2004, 2005 by Marc J. Rochkind. All rights reserved. Portions marked "Open Source" may be copied under license.



The following table summarizes errors, or alleged errors, that have come to my attention mostly via emails from readers. I've identified the contributor in the Credit column; if that's blank, it means I get the credit. (Double credit really, since I made the original mistake, too.)

The Comment column contains a description of the error and its resolution. If anything there is italicized, I'm quoting the person in the Credit column.

I haven't worked out the actual textual correction to the book in some cases, so the Correction column may be blank. Also, in some cases I haven't verified that the contribution is correct, so be cautious about taking anything here as fact unless it's something in the Correction column. (Although if Geoff Clare said it, it's most likely true.)

If the error affects Example source, the file(s) involved are listed in the File column. If that column is blank, it may mean that I haven't yet identified changes to the source files, not that no changes are needed.

In other words, please treat this page as a work-in-progress.

(I'm trying to think what was going on with me while I was writing page 287, which has 5 errors.)

Section Page File Comment Credit Correction
1.4.2 34   ... the EC_FLUSH macro, in ec.h, is defined taking one argument that seems to me not be used.

There was an earlier implementation that did use the argument, to further identify the source of the error. I decided that wasn't necessary, but left the argument in. Perhaps this is a good idea, but I should have at least provided an explanation.

Fabio De Francesco p. 36, end of 3rd bullet, add: "(The argument isn't used.)"
1.6 56   I said there was disagreement "among the various standards about whether the 'va' macros" go in stdio.h or stdarg.h. Geoff Clare writes:

The problem you had is entirely gcc's fault.

When you compile with gcc it uses its own <stdarg.h> header, but the normal Solaris <stdio.h> header. SUS requires that these both define va_list, so they need to cooperate such that if they are both included then the one that is included second does not try to redefine va_list. Solaris's <stdarg.h> does cooperate properly with <stdio.h> in this respect, but gcc's own <stdarg.h> does not.

There is no "disagreement" between the standards. The SUS requirement for va_list to be defined by <stdio.h> is simply an extension to Standard C. Nor is Solaris any different from the other SUS-compliant systems here. They all define va_list in both <stdarg.h> and <stdio.h> (when the appropriate FTM is defined). The only difference is the internal mechanism those headers use to cooperate with each other.

Geoff Clare 1st para.: delete the words "among the various standards" and insert the words "gcc on" before "Solaris".
2.12 98   Misspelled "kernel." Spelled correctly on the previous and next lines, and in the same sentence in 1985 edition! Haris Memic "kernal" should be "kernel."
2.15 113   Michael Kerrisk has different results for writev. See the post on the AUP Forum. Michael Kerrisk Reference to Michael's post added to footnote 12.
Ex. 2.5 121   "an Bseek" should be "a Bseek" Michael Kerrisk Change "an" to "a".
3.4.1 145       Replace the word "we've" on the first line with "I've".
3.5.1 149  
At page 149 in the first itemized paragraph, you showed some example
using /dev/ad0s1g and root file system, but I think that the
'/dev/ad0s1g' should be changed to '/dev/ad0s1m', and I think
that this modification more fits to your original intention.
Byung-Joon Lee Replace "g" with "m".
3.6.2 166   fchdir synopsis: "directorby" Michael Kerrisk Change it to "directory by".
3.6.5 178 aupls.c I wrote the correction in the column to the right, but Geoff Claire disagrees. I haven't checked into this yet.

I think the program behaves more sensibly without this change.

As far as I can tell the only difference it makes is what happens when you pass the name of a non-directory file as the argument to aupls (and -d is not used). The original program would output the details for that file. With the above change it ignores the file.

I realise that the intention is for the argument to be a directory (as indicated in the "usage" message), but the program needs to do something reasonable if a non-directory is specified. The original behaviour was fine. A reasonable alternative would be to give an error message saying that the specified file is not a directory. Just ignoring it does not seem reasonable to me.

Geoff Clare In function do_entry, the line

if (stat_only || !is_dir) {

should be

if (stat_only) {

3.7 181   In table 3.3 on page 181 the "Changed by" entries for st_atime and st_ctime should be the other way round. (st_atime can be changed by utime(); st_ctime is only changed by side-effect.) Geoff Clare Change as indicated.
3.7.2 183   In synopsis header, "ichown". Michael Kerrisk Change to "lchown".
4.3.1 227   Description of TOSTOP: "clocked" Michael Kerrisk Change to "blocked".
4.5.10 243   On page 243 you suggest changing character size and parity settings in c_cflag for raw mode. This may work fine with a terminal emulator, but if there is real hardware involved these are hardware settings that need to match the terminal device. Changing them could cause data corruption. Also when changing c_cflag settings, tcsetattr() can fail with EINVAL to indicate that the requested settings are not supported. I would recommend that you remove the parts that mess with CSIZE/CS8 and PARENB. (Clearing INPCK is fine.) Geoff Clare  
4.7 248   You say on page 248 that the name /dev/tty wasn't a requirement prior to SUS2. That's not true - it was also in SUS1 and XPG4. Geoff Clare 1st para.: Insert "always" after "wasn't" and delete the words "prior to SUS2".
4.10.1 261 ptutil.c On page 261 the O_NOCTTY flag is used in the posix_openpt() call but it is missing from the open() of /dev/ptmx. Geoff Clare Add "| O_NOCTTY" to the 2nd arg of open.
4.10.1 264-265   Now the fun one - STREAMS ptys (page 264/265). SUS2 requires that STREAMS ptys work correctly if you just open the slave device obtained from ptsname(). There is no need to push any modules on a UNIX98 system. Or more precisely, there is no need when a standards-conforming environment is used on a UNIX98 system. Solaris does conform to UNIX98 but it provides both conforming and non-conforming environments. If your code is compiled with Sun's c89 compiler, the pty will end up with two instances of the ptem and ldterm modules on the STREAM, causing havoc (e.g. double echoing of typed characters). To avoid this problem you need to use I_FIND to check whether each module is already on the STREAM before you I_PUSH it. Geoff Clare  
4.10.2 274 record.c     On p. 274, 4th line from the bottom: The ec_neg1 test should be ec_false. (See the comment on the 3rd line from the top on p. 37.)
5.2 282   2nd bullet: "a =" Michael Kerrisk Change to "an =".
5.*, 6.* 285 and other places   You have calls to execl() with just NULL as the last argument. It needs to be (char *)NULL or (char *)0. ... The reason the cast is needed is because NULL is allowed to be defined as plain 0, and execl() is a variadic function so the compiler has no way of knowing it should convert the 0 to a pointer instead of passing it as an int. Geoff Clare "NULL" changed to "(char *)NULL" in these places: synopses for execl, execlp, and execle on p. 285, 288, and 289, and in Appendix D; example code on p. 286, 287 (2 places), 368, 372, 374 (2 places), 375 (2 places), 391, 393, 396, and 401.
5.3 287   "fd < open_max - 1" should be "fd < open_max" Geoff Clare " - 1" removed in 2 places.
5.3 287   The first F_SETFD should be F_GETFD Geoff Clare  
5.3 289   On page 289 you say about execlp() and execvp() executing shell scripts that "It's up to the implementation as to what shell it uses." SUS and POSIX require that the script is executed as if by a standards-conforming "sh" utility. Note that this is another case where Solaris provides both standards-conforming and non-conforming behaviours. If a program compiled with Sun's c89 compiler calls execlp() then the shell used is /usr/xpg4/bin/sh (or I think it was /bin/ksh on older versions of Solaris). With plain cc (or gcc) it is /bin/sh. Geoff Clare 2nd para. from the bottom: Add the words ", but it must be standards-conforming" after the last word in the sentence ("uses").
5.3 290   "On nearly all systems, the work to deal with the #! line is done by execvp, not by the shell itself". Perhaps there are some systems which do handle it inside the exec library functions, but I believe most systems handle #! inside the kernel itself. Geoff Clare No change.
5.8 308   In display_status() you should only use WTERMSIG if WIFSIGNALED is true. If WIFSTOPPED is true you should use WSTOPSIG to get the signal number. Geoff Clare  
5.12 318   You say that when superuser calls setuid() or setgid() the call "sets both the real and saved values". It sets the effective value as well. Geoff Clare Change synopses titles to add ", effective," after "real" on p. 318 and in Appendix D.
5.15 320   When nice() returns -1, to tell whether it was an error you have to set errno to zero before the call and if it returns -1 then check if errno is non-zero (just like sysconf() and pathconf()). Geoff Clare Change footnote 13 to read: "Finally fixed in the latest version of [SUS2002]. You can set errno to zero before the call and then test it afterwards."
5.16 324   2nd para. from bottom: "member" Michael Kerrisk Change to "members".
5.17.3 336   Incorrect reference to "pthread_func" Greg King p. 336, 3rd line from top: change "pthread_func" to "thread_func".
5.17.5 348   You can't use your ec_*() error handling macros inside a pthread_cleanup_push/pthread_cleanup_pop block. SUS3 says "The effect of the use of return, break, continue, and goto to prematurely leave a code block described by a pair of pthread_cleanup_push() and pthread_cleanup_pop() functions calls is undefined." Geoff Clare  
5.18.2 354   The waitpid() call has &e->ue_result as the second argument, which is a pointer to ssize_t but waitpid() takes a pointer to int. Geoff Clare  
6.2.1 362-363   After the fpathconf() call you should only examine errno if fpathconf() returned -1. I.e. the "if (errno != 0)" at the top of page 363 should be "if (v == -1 && errno != 0)". Geoff Clare Code at top of p. 363 changed to:

if (v == -1)
    if (errno != 0)
        printf("No limit for PIPE_BUF\n");
    printf("PIPE_BUF = %ld\n", v);

6.2 371   You say "the standard says nothing about what file descriptors pipe will use". It does actually require that they are the two lowest available. However, this doesn't help as far as the point you are making is concerned, since the standard doesn't say they have to be in order. I.e. if 0 and 1 are closed then pipe(pfd) is allowed to set pfd[0] = 1 and pfd[1] = 0. Geoff Clare At top of p. 371, replace "what file descriptors pipe will use" with "which end is which".
7.4.2 429     Jim Fathman First sentence of last paragraph: Insert the word "no" before "conflicts."
  449   On page 449, the declarations for mq_timedsend and mq_timedreceive seem to have
been copied and pasted from their non-timed equivalents on page 448. They have
the extra timespec parameter, but no separating comma after priority or
Paul Floyd Add the comma.
7.7.2 452   The second snprintf() uses %d for a pid_t argument. It needs to cast the pid to long and use %ld. Geoff Clare  
7.7.2 453   The line


should be

    if (mq_unlink(mqname) == -1)

so that errno is only examined if mq_unlink() failed.

Geoff Clare  
7.7.3 456   Non-support of POSIX Message Queues: Since you wrote the book, support for POSIX Message queues has been added (Linux 2.6.6, May 2004). Michael Kerrisk  
7.9.1 461-462   You say it's okay to pass an int, pointer to struct semid_ds or an array of unsigned shorts as the fourth semctl() argument instead of passing a union semun. It isn't okay, because semctl() is a variable-argument function whose prototype only specifies the types of the first three arguments. Geoff Clare p. 461: Delete the start of the sentence on the last line beginning "Actually, you ...".

p. 462: Delete the rest of that sentence (1st two lines): "type int ... directly.".
7.10.1 472   The unlink() should be sem_unlink(). Geoff Clare In the function SimpleSemRemove, change "unlink" to "sem_unlink".
7.10.2 475   Non-support of POSIX Process Shared Semaphores: Well, actually, even at the time you were writing, this support did exist in Linux 2.6.  It was added during the 2.5 development series.  Of course that would have been easy to miss if one wasn't closely following Linux development. Michael Kerrisk 2nd para. from bottom, 2nd line: Change "they" to "some versions".
7.11.3 485   flockfile() doesn't set file locks! It "locks" a FILE object in the same sense that pthread_mutex_lock() locks a mutex. I.e. it prevents other threads (in the same process) from accessing that stdio stream until the owning thread unlocks it. Its purpose is to allow a sequence of getc() or putc() calls to be replaced with one flockfile() then the corresponding sequence of getc_unlocked() or putc_unlocked() calls then a funlockfile(), thus eliminating all the intermediate unlock+lock operations done internally by getc() or putc(). Geoff Clare Delete entire 1st para. on p. 485.
7.14.1 505   In "The call, sem_open" it should be shm_open. Geoff Clare In 1st para., change it to "shm_open".
8.8.4 591 ndb.c ... the printed port numbers came out wrong because display_servent() doesn't convert s_port to host byte order. I.e. the s->s_port printf argument should be ntohs(s->s_port). Geoff Clare "s->s_port" changed to "ntohs(s->s_port)" and outputted ports changed as follows:

change 5120 to 20
change 5120 to 20
change 5376 to 21
change 5376 to 21
change 5632 to 22
change 5632 to 22
change 5888 to 23
change 5888 to 23
change 6400 to 25
change 6400 to 25
change 6912 to 27
change 6912 to 27
change 7424 to 29
change 7424 to 29
change 7936 to 31
change 7936 to 31

7.14.3 515   Non-support of POSIX Shared Memories: You say Linux doesn't support POSIX Shared Memory.  This is wrong: Linux has supported POSIX Shared Memory since kernel 2.4 (glibc 2.2 or later required) -- around the start of 2001.  Michael Kerrisk Last para. of 7.14.3: Insert "some versions of" before the word "Linux".
8.9.5 596   "For inet_pron" Geoff Clare In 2nd. para from bottom, change it to "inet_pton".
  635   ... the comment /* non-zero to set, zero to clear */ for the siginterrupt() "on" argument is the wrong way round. Non-zero means system calls will be interrupted, which is equivalent to SA_RESTART being clear. Geoff Clare Change the argument name to "flag". Swap "set" and "clear" in the comment.
9.5.1 639   3rd para.: The convention of si_code <= 0 for signals from a process and si_code > 0 for signals from the kernel is only followed on some systems. It isn't required by the standard and shouldn't be relied on in portable code. (An example of a system which doesn't follow the convention is HP-UX, where SI_USER and SI_QUEUE are negative but SI_TIMER, SI_ASYNCIO and SI_MESGQ are positive.) Geoff Clare Change "If" to "Usually, if".
9.5.5 646   "much as pselect adds a time-out to select". ... select already had a time-out; pselect adds a signal mask. Geoff Clare Delete the phrase ", much as ... select"
Ref. 704   [STE2003] has a copyright date of 2004. Michael Kerrisk Change 2003 at end of entry to 2004. Leave "[Ste2003]" unchanged.

You can register your email address to get notified when there are new errata.