man7.org > tlpi > errata

Errata for The Linux Programming Interface

This page lists errata for The Linux Programming Interface. (For information about changes to the kernel-userspace and glibc APIs since TLPI was published, see the API changes page.)

In general, if you make an error report I'll list your name against the report, and even link to a home page or similar if you like. If you don't want your name to appear against the error report, please let me know at the time that you make the report.

You may also want to look at this frequently asked question.

Order errata list by: page number, print run, or report date

Last updated: 2012-05-26; last error report: 2012-05-25


This version of the errata page lists fixes according to the print run of the book in which they first appeared.

Below, the page number column uses the following coding for errors:

Color code Explanation
Typo A fix to a minor typographical or grammar error, or a replacement of an (obviously) incorrect word
Update This is a note on information that is new since the book was published (normally information relating to a kernel or glibc change); there won't be a change to the text
Code fix A significant fix to a piece of code
Minor code fix A minor fix to a piece of code; generally the problem and its solution should be obvious on an attentive reading of the text, or there is a syntax error in a code snippet that would be detected during compilation
Clarification A significant clarification to an explanation in the text
Minor clarification A minor clarification to an explanation in the text (the overall meaning of text isn't changed, but a minor detail is added or improved)
Technical fix A significant fix to a technical point explained in the text
Minor technical fix A minor fix to a technical point explained in the text (typically a correction to a minor or obvious technical error or imprecision in the text)

Use the following links to jump to:

To determine which printing of the book you have, look at the page containing the copyright notice (one of the pages right at the start of the book, before the table of contents). Near the top of the page, just below the copyright notice, is a line of numbers. The lowest ordinal number that you can see in this list indicates the print run that produced your copy of the book.

Fixes queued for the next print run

The following fixes and improvements will be applied in the next printing.

Page Fix Reported
44

In the list item "5" (toward the bottom of the page), change:

arch/i386/entry.S

to:

arch/x86/kernel/entry.S

Reported by Leif Dyvik.

2012-04-25

46

In the bottom left hand of Figure 3-1, under the heading "System call service routine", change:

arch/x86/kernel/process_32.c

to:

arch/x86/kernel/process.c

Explanation:

Erratum originally written on 2012-04-25; a small correction was made on 2012-05-25 after a note from Robert P. J. Day.

2012-05-25

61

In the second sentence of the first paragraph of Section 3.6.1, change:

Some of these standards are defined by standards bodies such The Open Group

to:

Some of these standards are defined by standards bodies such as The Open Group

Reported by Murray McAllister.

2012-04-30

230

At the end of the first small-font paragraph at the top of the page, change:

the Linux-specific /proc/hostname file

to:

the Linux-specific /proc/sys/kernel/hostname file

Reported by Ursache Vladimir

2012-04-26

230

At the end of the second small-font paragraph at the top of the page, change:

the Linux-specific /proc/domainname file

to:

the Linux-specific /proc/sys/kernel/domainname file

Reported by Ursache Vladimir

2012-04-26

441

Near the top of of this table, change the entry in the second column for the row SI_USER from:

A user process via kill() or raise()

to:

A user process via kill()

Explanation:

Once upon a time, raise() did produce an si_code of SI_USER, but modern glibc versions implement raise() raise using tgkill(), which yields an si_code of SI_TKILL. The simplest fix here is to remove mention of raise() in this table. I made some recent changes to the raise() man page to allow programmers to deduce the details.

2012-04-20

447

In the second-to-last bullet point on the page, change:

the use of signalfd() to receive a signal via file descriptor; and

to:

the use of signalfd() to receive a signal via a file descriptor; and

Reported by Murray McAllister.

2012-05-16

477

In the second sentence of the second paragraph of Section 22.14, change:

Asynchronous generation occurs when a signal is sent a process by the kernel

to:

Asynchronous generation occurs when a signal is sent to a process by the kernel

Reported by Murray McAllister.

2012-05-16

477

In the second line of the third paragraph from the bottom of the page, change:

suspend execution until a signal arrives, The atomicity of

to:

suspend execution until a signal arrives. The atomicity of

(i.e., change a comma to a period.)


Reported by Murray McAllister.

2012-05-16

516

In the second sentence of the second paragraph, change:

are initially exact duplicates of the corresponding parts the parent's memory

to:

are initially exact duplicates of the corresponding parts of the parent's memory

Reported by Murray McAllister.

2012-05-19

646

At the bottom of the page, add the following small-font note:

Chapter 32, which describes thread cancellation, notes that pthread_cond_wait() is a cancellation point. If a thread is canceled while blocked in a call to pthread_cond_wait(), then the mutex is relocked before the first cancellation cleanup handler is called. This means a cleanup handler can safely unlock the mutex (as is done, for example, in Listing 32-2).

Explanation:

Page 636 notes that it is an error to call pthread_mutex_unlock() on a mutex that is unlocked. Page 646 notes that pthread_cond_wait() unlocks its mutex before blocking. Chia Hao Lo pointed out that lacking any further details, the example in Listing 32-2 seemed to be at odds with those statements: if the thread is canceled while blocked in pthread_cond_wait(), wouldn't the cleanup handler then be unlocking a mutex that had already been unlocked by pthread_cond_wait()? The text added by the erratum resolves this question.

Reported by Chia Hao Lo.

2012-03-07

677

At the end of the first bullet point on this page (starting "If no command-line argument is supplied"), add the following text:

(When a pthread_cond_wait() call is canceled, the mutex is automatically relocked before the cleanup handler is invoked. This means the mutex can be safely unlocked in the cleanup handler.)

Explanation:

See the erratum for page 646.

Reported by Chia Hao Lo.

2012-03-07

801

In Table 39-1, in the entry for CAP_SYS_ADMIN, change:

employ CLONE_NEWNS flag with clone() and unshare();

to:

employ namespace-creation flags with clone() and unshare();

Explanation:

CLONE_NEWNS is just one of several namespace-creation flags whose operation is governed by CAP_SYS_ADMIN. (The others are CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWPID, and CLONE_NEWUTS.)

2012-03-03

1061

Change the one-sentence paragraph that precedes Section 51.2:

On Linux, programs employing the POSIX IPC mechanisms must be linked with the realtime library, librt, by specifying the –lrt option to the cc command.

to:

On Linux, programs employing POSIX message queues and shared memory must be linked with the realtime library, librt, using the cc –lrt option. Programs employing POSIX semaphores must be compiled using the cc –pthread option.

Explanation:

At the time of publication, cc –lrt was sufficient for all three POSIX IPC mechanisms, and for POSIX semaphores cc –pthread could alternatively be used. Some recent toolchain changes mean that now only cc –pthread can be used for POSIX semaphores.

2012-05-11

1214

In the definition of the addrinfo structure, change:

    size_t ai_addrlen;          /* Size of structure pointed to by ai_addr */

to:

    socklen_t ai_addrlen;       /* Size of structure pointed to by ai_addr */

2012-04-15

Notes

The following points are notes to the text, rather than fixes; there are no corresponding changes in the text of any print run.

Page Fix Reported
9

As a consequence of the (July 2011) renumbering of the Linux kernel series from 2.6.x to 3.x, the discussion of kernel numbering on this page is now out-of-date. However, all that has changed is that the numbering scheme has been simplified (replacing an invariant 2.6 with 3); the kernel development model remains unchanged. As Linus noted of the 3.0 release, there is otherwise nothing special about the release (i.e., no changes more significant than those in Linux 2.6.39 and each of the preceding 2.6.x releases).

In the bulleted list at the top of the page, each of the instances of 2.6.z could simply be replaced by 3.z and the description on this page would still be accurate for the current kernel development model.

2011-07-29

9

The small-font note at the bottom of the page states "At the time of writing, the 2.4 stable Linux kernel is still supported…" This has now ceased to be true: Willy Tarreau, the Linux 2.4 maintainer, notes that the 2.4 kernel series has now reached end-of-life.

2012-04-10

74

Since Linux 2.6.39, the open() system call supports a new file creation flag, O_PATH, that can be used to obtain a file descriptor with specific, limited uses. The returned file descriptor can be closed, duplicated, or passed via a UNIX domain socket (see Section 61.13.3); the file descriptor can't be read from or written to. O_PATH can be used to obtain file descriptors for symbolic links. O_PATH file descriptors are provided for use as the directory file descriptor argument in the *at() system calls (see Section 18.11).

2011-06-26

82

This note is also relevant for the discussion of file holes on page 83.

Linux 3.1 adds two new operations for the lseek() system call: SEEK_HOLE and SEEK_DATA. These operations can be used to determine the start and end of holes in a file. SEEK_HOLE seeks to the offset of the next file hole whose location is greater than or equal to the current file offset. SEEK_DATA seeks to the offset of the next non-hole region whose location is greater than or equal to the current file offset.

2011-07-29

83

Linux 2.6.38 added FALLOC_FL_PUNCH_HOLE, a new operation for the fallocate() system call. This operation creates a hole in a file in the byte range indicated by the system call's offset and len arguments. (The file data in the specified range is lost.) Among the file systems that already support this operation are XFS and (since Linux 3.0) ext4. Btrfs is capable of supporting the operation, and support is likely to be added in the future.

2011-06-30

224

In the first paragraph of this page, I refer to /proc as a "virtual file system". It would have been worth noting two points in relation to this term:

  • Some other sources use the term "pseudofilesystem" synonymously.
  • The Virtual File System described in Section 14,5, is a term used to refer to a specific component of the Linux kernel. This usage is unrelated to the term as used when describing the /proc file system.

However, there isn't sufficient space on the page to add this information.


Reported by Bill McConnaughey.

2011-07-18

241

Since Linux 2.6.39, the new syncfs() system call can be used to flush all kernel buffers containing updated file information for a specified file system (i.e., a per-file-system sync()). The file system is specified using a file descriptor that refers to an open file in the file system.

2011-06-26

301

The example shell session at the top of this page is technically correct, but could have been better chosen. As explained earlier in Section 15.4.5, the sticky bit no longer serves any purpose for regular (executable) files, but it does serve a purpose for directories. Therefore, a better example would have been to demonstrate manipulating the sticky bit of a directory, rather than a file.


Reported by Simon Durrant.

2011-08-23

348

This note relates to the shell session shown at the top of the page. Depending on factors including the file system type, the size of file created, and system scheduling decisions, you may not always see the behavior shown in this example. Specifically, by the time that the second df command is executed (via system()) the blocks of the closed file may not yet have been freed, so that the output of the second df shows no change in the amount of disk space used in the file system.

As a workaround, adding a sufficiently long sleep() call immediately after the close() call in dirs_links/t_unlink.c should ensure that the file blocks have been freed; in all cases that I tested (including very large file sizes), sleep(1) was sufficient to ensure that the file space was freed by the time of the second df command. Note that calling sync() after the close() call does not suffice to eliminate this behavior. Presumably, this is because sync() flushes dirty blocks in the buffer cache, whereas the file blocks in question here are being (asynchronously) deallocated by the kernel.


Reported by Yang Yang.

2011-12-04

365

Since Section 18.11 was written, some new AT_* flags have been added to various system calls mentioned in this section.

Linux 2.6.38 added the AT_NO_AUTOMOUNT flag for fstatat(). This flag can be used to prevent automounting of the terminal component of a pathname given to fstatat().

Linux 2.6.39 added the AT_EMPTY_PATH flag for linkat(), fchownat(), fstatat(), and name_to_handle_at(). (An explanation of the last of these system calls can be found on LWN.net.) This flag allows empty relative pathnames to be specified for these system calls, in which case the calls operate on the directory file descriptor.

2011-06-26

378

Linux 2.6.36 adds a new input flag for inotify, IN_EXCL_UNLINK, that prevents children of a watched directory from generating events for a directory after they have been unlinked from that directory. This flag would slot into Table 19-1, just below IN_DONT_FOLLOW. Further information can be found in the inotify(7) manual page.

2011-05-08

379

In the discussion of the IN_ATTRIB event in the first bullet point, it is worth noting that the "link count changed" case also includes deletion of a file. However, there isn't sufficient space on the page to add this information.


Reported by Bill McConnaughey.

2011-07-18

442

In Section 21.5, in the first paragraph following the numbered list, the error EINTR is described in parentheses as "Interrupted function". This text is the SUSv3 description of this error. However, glibc associates this error with a slightly different text: "Interrupted system call".


Reported by Junjiro Okajima.

2012-01-16

450

With respect to Table 22-1, Linux 3.0 added a new specifier, %E. This specifier is replaced by the pathname of the executable file, with slashes (/) substituted by exclamation marks (!). (The substitution is required because slashes can't form part of a filename—they delimit the filename components of a pathname.)


Reported by Junjiro Okajima.

2012-01-16

458

Although I refer to sigqueue() twice on this page (and once on page 477) as a system call, strictly speaking, it is a library function (layered on top of the Linux rt_sigqueueinfo(2) system call). In September 2011, I made changes to the Linux man pages to more accurately reflect that fact, documenting the underlying system call and moving the sigqueue() manual page from Section 2 (System Calls) to Section 3 (Library Functions).

2011-09-30

468

Ideally, the following information regarding portability should have been included at the bottom of this page:

On Linux, a blocked signal whose disposition is ignore is added to the process's set of pending signals if it is generated. However, according to SUSv3, an implementation may discard the signal in this case. (SUSv4 XSH 2.4.1: "If the action associated with a blocked signal is to ignore the signal and if that signal is generated for the process, it is unspecified whether the signal is discarded immediately upon generation or remains pending.") Thus, in addition to blocking the signal, a portable application that uses sigwaitinfo() to accept a signal must ensure that the signal is not ignored, by either installing a handler for the signal or ensuring that the signal's disposition is SIG_DFL (unless the default action is to ignore the signal).

However, there isn't sufficient space on the page to include this information.


Explanation:

This note was originally composed on 2011-12-08, but then expanded on 2012-02-14.

2012-02-14

491

Since Section 23.5 was written, some new clocks have been added to the POSIX clocks API.

Linux 2.6.39 adds CLOCK_BOOTTIME. This clock is the same as CLOCK_MONOTONIC, except that it includes time that the system has spent in suspended state. The new clock is intended for applications that want a monotonically increasing clock and also want to be aware of time the system has been suspended.

Linux 3.0 adds two clocks to the POSIX clocks API: CLOCK_BOOTTIME_ALARM and CLOCK_REALTIME_ALARM. These clocks behave identically to CLOCK_REALTIME and CLOCK_BOOTTIME, but the _ALARM suffixed clocks will wake the system if it is suspended. A new CAP_WAKE_ALARM capability governs the use of these clocks.

2011-06-26

492

Relevant to Section 23.5.2: since Linux 2.6.39, the new clock_adjtime() system call provides an interface to adjust the value of a POSIX clock (if that clock supports the interface) in the same manner as the adjtimex(2) system call.

2011-06-26

508

Since Linux 3.0, the timerfd_settime() system call supports a further flag, TFD_TIMER_CANCEL_ON_SET. If this flag is set for a CLOCK_REALTIME absolute (TFD_TIMER_ABSTIME) timer, then the timer is expired if the clock is reset.

2011-06-26

553

Section 26.2 discusses the traditional semantics for adoption of orphaned children by the init process. Linux 3.4 added the PR_SET_CHILD_SUBREAPER prctl() operation, which allows a "service manager" process to mark itself as a sort of 'sub-init', so that it adopts all orphaned processes created by the services it starts. All SIGCHLD signals will be delivered to the service manager. There is a corresponding PR_GET_CHILD_SUBREAPER prctl() operation.

2012-04-24

571

The last paragraph of the page should have noted that:

The fexecve() function is not specified in SUSv3, but is specified in SUSv4.

Explanation:

At various other places in the book (pages 15 and 426), I noted that SUSv4 specified fexecve(). That fact should also have been mentioned in Section 27.2.4. However, there isn't sufficient space on the page to add this sentence.

2010-12-31

628

In Section 29.7, I could have noted that calling pthread_detach() more than once on the same thread results in unspecified behavior.


Explanation:

It would have been desirable to note this point in the text. (It is noted in the pthread_detach() manual page that I wrote.) However, there isn't sufficient space on the page to add this sentence.

Reported by Jens Thoms Toerring.

2011-02-28

744

See the third bullet point at the top of the page. Starting with Linux 2.6.39, the limitation on modifying the SCHED_IDLE scheduling policy changes. An unprivileged SCHED_IDLE thread can now switch to another policy as long as its current nice value falls within the range permitted by the RLIMIT_NICE resource limit (see page 736).

2011-06-26

755

Linux 2.6.36 adds a new system call, prlimit(), that allows the caller to both set and retrieve its own resource limits (including retrieving the old limit at the same time as a new limit is set) and (with suitable permissions) perform the same task for other processes. See the manual page.

2011-05-08

760

The prlimit() system call mentioned in the notes for page 755 can be used to implement wrapper functions for getrlimit() and setrlimit() which work around the problem described in the paragraph at the top of this page. Reportedly, this has been done in glibc 2.13, but I have not yet tested to verify the change.

2011-05-08

792

The C11 standard (ratified by ISO on 8 Dec 2011), officially removes the dangerous function gets() from the language specification. From version 2.16, glibc does not expose the definition of gets() if the _ISOC11_SOURCE feature test macro is defined.

2012-01-18

801

Linux 2.6.38 adds a new capability, CAP_SYSLOG, used (instead of CAP_SYS_ADMIN) to govern privileged syslog(2) operations.

2011-05-08

801

Linux 3.0 adds a new CAP_WAKE_ALARM capability, which governs the use of the CLOCK_BOOTTIME_ALARM and CLOCK_REALTIME_ALARM clocks. (See also the note for page 491.)

2011-06-26

872

The last part of Section 42.3 discusses the use of objdump –t to display information from the symbol table of an executable, in order to see version tag dependencies.

Yang Yang notes that using objdump –T (which yields the same information for the cases discussed in the text, but in a slightly different form) may be preferable. The reason is that objdump –T obtains its information from the ELF dynamic symbol table (.dynsym), which is always present in a dynamically linked binary. By contrast, objdump –t obtains its information from the standard symbol table (.symtab), which is not present if the executable has been stripped.

The blog post Inside ELF Symbol Tables by Ali Bahrami provides a nice introduction to the two types of symbol tables.


Reported by Yang Yang.

2012-01-27

1055

To the first small-font note, about two thirds of the way down the page, it can be noted that Linux 2.6.38 added two new flags to the madvise() system call: MADV_HUGEPAGE and MADV_NOHUGEPAGE. These flags enable and disable an attribute on the memory region that indicates that it is important that the region be backed by huge pages. (Huge pages are briefly described on page 999.)

2011-06-26

1055

To the first small-font note, about two thirds of the way down the page, it can be noted that Linux 3.4 added two new flags to the madvise() system call: MADV_DONTDUMP and MADV_DODUMP. The MADV_DONTDUMP flag specifies that an address range should not be included in core dumps. The MADV_DODUMP flag reverses the effect of MADV_DONTDUMP.

2012-04-24

1284

The small-font note about one third of the way down the page states that a sendmmsg() system call is likely to be implemented in the future. This system call was added in Linux 3.0.

2011-06-26

Fixes and improvements in the third printing

The following fixes and improvements were applied in the third and later printings of the book.

Page Fix Reported
11

In the second paragraph, change:

which was subsequently adopted in 1990 as an International Standards Organization (ISO) standard

to:

which was subsequently adopted in 1990 as an International Organization for Standardization (ISO) standard

Explanation:

Although often referred to as the International Standards Organization, the correct title is International Organization for Standardization.

2011-08-04

38

In the last sentence of the first paragraph in Section 2.12, change:

However, each thread has it own stack…

to:

However, each thread has its own stack…

Reported by Jaewook Yu.

2011-04-09

73

Near the end of Listing 4-2, change:

    fd = open("w.log", O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
                       S_IRUSR | S_IWUSR);

to:

    fd = open("w.log", O_WRONLY | O_CREAT | O_APPEND,
                       S_IRUSR | S_IWUSR);

Explanation:

The code as originally given was technically correct, but the presence of O_TRUNC was superfluous for the purpose of the example, and its semantics were not explained in the accompanying comment.

Reported by Jessica T McKellar.

2011-05-26

74

In Table 4-3, move two rows to a different part of the table:

Flag Purpose SUS?
O_RDONLY Open for reading only v3
O_WRONLY Open for writing only v3
O_RDWR Open for reading and writing v3
O_CLOEXEC Set the close-on-exec flag (since Linux 2.6.23) v4
O_CREAT Create file if it doesn't already exist v3
O_DIRECT File I/O bypasses buffer cache  
O_DIRECTORY Fail if pathname is not a directory v4
O_EXCL With O_CREAT: create file exclusively v3
O_LARGEFILE Used on 32-bit systems to open large files  
O_NOATIME Don't update file last access time on read() (since Linux 2.6.8)  
O_NOCTTY Don't let pathname become the controlling terminal v3
O_NOFOLLOW Don't dereference symbolic links v4
O_TRUNC Truncate existing file to zero length v3
O_APPEND Writes are always appended to end of file v3
O_ASYNC Generate a signal when I/O is possible  
O_DSYNC Provide synchronized I/O data integrity (since Linux 2.6.33) v3
O_NONBLOCK Open in nonblocking mode v3
O_SYNC Make file writes synchronous v3

to give the following:

Flag Purpose SUS?
O_RDONLY Open for reading only v3
O_WRONLY Open for writing only v3
O_RDWR Open for reading and writing v3
O_CLOEXEC Set the close-on-exec flag (since Linux 2.6.23) v4
O_CREAT Create file if it doesn't already exist v3
O_DIRECTORY Fail if pathname is not a directory v4
O_EXCL With O_CREAT: create file exclusively v3
O_LARGEFILE Used on 32-bit systems to open large files  
O_NOCTTY Don't let pathname become the controlling terminal v3
O_NOFOLLOW Don't dereference symbolic links v4
O_TRUNC Truncate existing file to zero length v3
O_APPEND Writes are always appended to end of file v3
O_ASYNC Generate a signal when I/O is possible  
O_DIRECT File I/O bypasses buffer cache  
O_DSYNC Provide synchronized I/O data integrity (since Linux 2.6.33) v3
O_NOATIME Don't update file last access time on read() (since Linux 2.6.8)  
O_NONBLOCK Open in nonblocking mode v3
O_SYNC Make file writes synchronous v3

Explanation:

As noted on page 93, O_DIRECT and O_NOATIME are open file status flags that can be retrieved and modified using fcntl(). These flags were accidentally misplaced in the file creation flags section of Table 4-3.

Reported by Madhavan Kasthurirangan.

2011-09-04

93

In the prototype box for fcntl() at the top of the page, change:

Return on success depends on cmd, or –1 on error

to:

Return value on success depends on cmd; returns –1 on error

Explanation:

A minor wording improvement.

2011-06-16

97

About one third of the way down the page (in the paragraph starting "Assuming the normal situation"), change:

dup() will create the duplicate of descriptor 1 using file 3.

to:

dup() will create the duplicate of descriptor 1 using descriptor 3.

Reported by Simon Durrant.

2011-08-07

102

At the end of the paragraph second from the bottom of the page, add a sentence:

The preadv() and pwritev() system calls perform the same task as readv() and writev(), but perform the I/O at the file location specified by offset (like pread() and pwrite()). These system calls don't change the file offset.

Explanation:

The reader may have been able to draw this implication from the text (since it is explained that these system calls are like readv() and writev()), but it's better to make the point explicit.

Reported by Sun Jian.

2011-06-15

104

In the small-font at the top of the page, change:

The main difference was that a nonblocking write() on System V returned 0 if a write() could not be completed or if no input was available to satisfy a read().

to:

The main difference was that a nonblocking write() on System V returned 0 if a write() could not be completed and a nonblocking read() returned 0 if no input was available.

Reported by Sun Jian.

2011-06-15

104

In the first line of the small-font note towards the bottom of the page, change:

(e.g., Alpha, IA-64)

to:

(e.g., x86-64, Alpha, and IA-64)

Explanation:

It was an oversight to omit the most common 64-bit architecture here.

2011-12-11

110

In the first line of Exercise 5-1, change:

Modify the program in Listing 5-3

to:

If you have access to a 32-bit Linux system, modify the program in Listing 5-3

Explanation:

From Section 5.10, the reader can deduce that this exercise applies only to 32-bit systems. However, it is of course better to make that assumption explicit.

Reported by Sandipan Razzaque.

2011-12-11

136

In the last paragraph on this page, change:

When we compile the program in Listing 6-6 normally, we see the expected output:

to:

When we compile the program in Listing 6-6 without optimization, we see the expected output:

Explanation:

By default (i.e., "normally"), gcc compiles without optimization. This change makes that point more explicit.

Reported by Bill McConnaughey.

2011-06-28

141

In the paragraph below the prototype box for malloc(), change:

aligned on a byte boundary suitable for any type of C data structure.

to:

aligned on a byte boundary suitable for efficient access to any type of C data structure.

Explanation:

This change makes the intended idea behind the explanation clearer.

Reported by Sun Jian.

2011-04-07

142

Add a line at the top of Listing 7-1 (memalloc/free_and_sbrk.c):

#define _BSD_SOURCE
#include "tlpi_hdr.h"

#define MAX_ALLOCS 1000000

Explanation:

As noted on page 140, a feature test macro definition is needed for sbrk(). Without it, gcc complains ("implicit declaration of function 'sbrk'") when invoked with (for example) -std=c99.

I missed this problem because of the combination of two reasons: (1) the feature test macro requirements for sbrk() changed in the version of glibc (2.12) that was released not long before the book when to press (see the man page for details), and (2) there was a breakage in my main Makefile (now fixed in the latest version of the source code tarball).

Reported by Lei Yang.

2011-07-05

148

In the first line of the example code near the top of this page, change:

    struct { /* Some field definitions */ } myStruct;

to:

    struct myStruct { /* Some field definitions */ };

Reported by Sangman Lee.

2011-04-13

154

In the second bullet point, change:

In this case, the password field in /etc/passwd conventionally contains the letter x (although any nonempty character string may appear), and the encrypted password is instead stored in the shadow password file (Section 8.2).

to:

In this case, the password field in /etc/passwd contains the letter x, and the encrypted password is instead stored in the shadow password file (Section 8.2).

2012-02-08

166

In Exercise 8-1, completely replace the text:

8-1. When we execute the following code, we find that it displays the same number twice, even though the two users have different IDs in the password file. Why is this?
    printf("%ld %ld\n", (long) (getpwnam("avr")->pw_uid),
                        (long) (getpwnam("tsr")->pw_uid));

with the following text:

8-1. When we execute the following code, which attempts to display the usernames for two different user IDs, we find that it displays the same username twice. Why is this?
    printf("%s %s\n", getpwuid(uid1)->pw_name,
                      getpwuid(uid2)->pw_name);

Explanation:

The exercise was intended to demonstrate the nonreentrant nature of getpwnam() (and related functions, such as getpwuid()), but the experiment I proposed to do so was wrong. (And unfortunately it looks as though I didn't test this exact example.) As René Thomsen pointed out, the code of the original exercise wouldn't yield the results described in the text "since after each argument a copy of the value in the passwd structure for pw_uid is passed, and since this a direct value (not a reference) there should be no trouble [with] the next call overwriting this value, since it still has the copy."

The revised exercise correctly shows the point I wanted to make. A complete program that can be used to demonstrate the point is shown below.

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pwd.h>

int
main(int argc, char *argv[])
{
    if (argc != 3 || strcmp(argv[1], "--help") == 0) {
        fprintf(stderr, "Usage: %s uid1 uid2\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    printf("%s %s\n", getpwuid(atoi(argv[1]))->pw_name,
                      getpwuid(atoi(argv[2]))->pw_name);

    exit(EXIT_SUCCESS);
}

Reported by René Thomsen.

2011-07-14

179

About two thirds of the way down the page, change:

Alternatively, an application can make a call to getgroups() specifying gidtsetsize as 0.

to:

Alternatively, an application can make a call to getgroups() specifying gidsetsize as 0.

Reported by Simon Durrant.

2011-08-12

180

In the fifth line from the top of the page, change:

IDs by scanning /etc/groups

to:

IDs by scanning /etc/group

Reported by Yang Yang.

2011-11-30

186

At the end of the last paragraph on this page, add a sentence:

This argument is now obsolete and should always be specified as NULL. (SUSv4 marks gettimeofday() obsolete, presumably in favor of the POSIX clocks API described in Section 23.5.)

Explanation:

The fact that SUSv4 marks gettimeofday() obsolescent was noted in page 16, but it should also be mentioned here.

2011-08-12

187

At the end of the page, add a small-font note as follows:

SUSv4 marks ctime() and asctime() obsolete, because they do not return localized strings (and they are nonreentrant).

Explanation:

This point was noted on page 16, but it bears repeating here, where these functions are described in detail.

2011-08-12

217

Starting in the sixth line of the small-font note about one third of the way down the page, change:

which is the per-user limit on the number of processes that may created by this process

to:

which is the per-user limit on the number of processes that may be created by this process

Reported by Yongzhi Pan.

2011-09-20

241

In the fifth line from the top, change:

synchronized I/O data completion

to:

synchronized I/O data integrity completion

Reported by Junjiro Okajima.

2012-01-16

243

Two changes in the third paragraph.

In the fourth line, change:

synchronized I/O data integrity (like fdatasync())

to:

synchronized I/O data integrity completion (like fdatasync())

In the seventh and eighth lines, change:

synchronized I/O file integrity (like fsync())

to:

synchronized I/O file integrity completion (like fsync())

Reported by Junjiro Okajima.

2012-01-16

245

In the last sentence of the paragraph explaining POSIX_FADV_SEQUENTIAL, change:

to the twice the default size

to:

to twice the default size

Reported by Simon Durrant.

2011-08-23

252

In the second bullet point half-way down the page, change:

Examples of block devices include disks and tape drives.

to:

Disks are a common example of block devices.

Explanation:

Tapes are normally character devices.

Reported by Junjiro Okajima.

2012-01-16

258

In the "Key" box in the upper right hand corner of Figure 14-2, change:

2IPB = Double IBP

to:

2IPB = Double IPB

Reported by Yongzhi Pan.

2011-09-20

265

In the paragraph near the top of the page describing MS_BIND, change:

If this flag is specified, then the fstype, mountflags, and data arguments are ignored.

to:

If this flag is specified, then the fstype and data arguments are ignored, as are flags in mountflags other than MS_REC (described below).

2011-04-02

265

In the paragraph in the middle of the page describing MS_MOVE, change the last sentence:

When this flag is specified, the fstype, mountflags, and data arguments are ignored.

to:

When this flag is specified, the fstype and data arguments are ignored, as are the remaining flags in mountflags.

Reported by Sangman Lee.

2011-04-02

273

In the sentence immediately preceding Section 14.9.5, change:

we can simply create bind mounts for these directories (possibly mounted read-only) within the jail

to:

we can simply create bind mounts for these directories within the jail

Explanation:

It isn't possible to make read-only bind mounts to read-write directories. As noted on page 265, mountflags other than MS_REC are ignored when MS_BIND is specified.

Reported by Junjiro Okajima.

2012-01-16

278

In the third line from the bottom of the page, change:

(x000001, x000001, x0000002, and so on)

to:

(x000000, x000001, x0000002, and so on)

Reported by Junjiro Okajima.

2012-01-16

280

In the third line of the small-font note at the bottom of the page, change:

None of other fields

to:

None of the other fields

Reported by Simon Durrant.

2011-08-23

280

At the end of the small-font note at the bottom of the page (after the sentence beginnning "On Linux, lstat() returns…"), add the following sentence:

SUSv4 tightens the requirements on an implementation, requiring lstat() to return valid information in all fields of the stat structure except the permission bits of st_mode.

2011-09-30

286

In Table 15-2, in the entry for truncate(), change:

Same for ftruncate(); timestamps change only if file size changes

to:

Same for ftruncate()

Explanation:

The original text did not completely match Linux behavior, but the story here is complicated. On Linux, ftruncate() always changes the file timestamps, even if the file size is not changed. However, Linux truncate() only changes the timestamps if the file size changes. This more or less mirrors the specifications in SUSv3. SUSv3 makes no mention of file size changes when specifying that ftruncate() changes the file timestamps. By contrast, SUSv3 says for truncate() that if the file size is changed, the file timestamps are updated, implying that if the file size is unchanged, the timestamps should not be changed. A planned fix to SUSv4 would require that truncate() behave like ftruncate().

2012-02-14

287

In the sentence immediately preceding heading 15.2.1, change:

can be accessed using field names such st_atim.tv_nsec

to:

can be accessed using field names such as st_atim.tv_nsec

Reported by Yongzhi Pan.

2011-09-20

290

In the prototype box for futimens() at the bottom of the page change:

#include _GNU_SOURCE

to:

#define _GNU_SOURCE

Reported by Junjiro Okajima.

2012-01-16

297

Add some words to the last sentence in the small-font note at the top of the page:

To ensure that we are using an unadulterated ls, we can specify the full pathname of the command (/bin/ls) or precede the ls command with a backslash to prevent alias substitution.

Reported by Junjiro Okajima.

2012-01-16

306

In the first line on the page, change:

The various FL_* flags and their meanings are as follows:

to:

The various FS_* flags and their meanings are as follows:

Reported by Douglas Luu.

2011-11-12

313

In the first sentence of the paragraph that precedes the bulleted list in Section 16.2, change:

It is only possible to place user EAs on files and directories.

to:

It is only possible to place user EAs on regular files and directories.

Explanation:

From the bulleted list, the reader can deduce that this sentence is referring to regular files, but it's better to make that explicit.

Reported by Junjiro Okajima.

2012-01-16

331

In the second paragraph under the heading Retrieving entries from an in-memory ACL, change the last sentence:

Thus, we can loop through all of the entries in an ACL by specifying type as ACL_FIRST_ENTRY in the first call to acl_get_entry() and specifying type as ACL_NEXT_ENTRY in subsequent calls.

to:

Thus, we can loop through all of the entries in an ACL by specifying entry_id as ACL_FIRST_ENTRY in the first call to acl_get_entry() and specifying entry_id as ACL_NEXT_ENTRY in subsequent calls.

Reported by Yongzhi Pan.

2011-09-20

334

In the first sentence of the small-font note near the top of the page, change:

The acl_check() and acl_error() functions (the latter is a Linux extension)

to:

The acl_check() and acl_error() functions (both are Linux extensions)

Reported by Junjiro Okajima.

2012-01-16

336

About one third of the way down the page, change:

        /* Retrieve and display optional tag qualifier */

        if (tag == ACL_USER) {
            uidp = acl_get_qualifier(entry);
            if (uidp == NULL)
                errExit("acl_get_qualifier");

            name = groupNameFromId(*uidp);

to:

        /* Retrieve and display optional tag qualifier */

        if (tag == ACL_USER) {
            uidp = acl_get_qualifier(entry);
            if (uidp == NULL)
                errExit("acl_get_qualifier");

            name = userNameFromId(*uidp);

Reported by René Thomsen.

2011-08-11

381

In the third line of the paragraph near the top of the page that starts "The cookie field…", change:

and then an IN_MOVED_TO is

to:

and then an IN_MOVED_TO event is

2011-12-08

381

Add a sentence at the end of the paragraph near the top of the page that starts "The cookie field…":

These two events will have the same unique value in their cookie field, thus allowing the application to associate them. For all other types of event, the cookie field is set to 0.

Explanation:

This point was made implicitly in the program in Listing 19-1 (where the displayInotifyEvent() function contains the check if (i->cookie > 0)), but should of course have been made explicit in the text.

Reported by Yang Yang.

2011-12-06

381

In the third paragraph from the bottom of the page (starting "Using a larger buffer size"), change:

A read() from an inotify file descriptor returns the minimum of the number of events that are available and the number of events that will fit in the supplied buffer.

to:

A read() from an inotify file descriptor reads the minimum of the number of events that are available and the number of events that will fit in the supplied buffer.

Explanation:

This change is made to prevent the possible misinterpretation that the return value of read() is the number of items read. As shown in Figure 19-2, a read() from an inotify file descriptor returns the number of bytes read (as with a read() from other types of file descriptors).

Reported by Junjiro Okajima.

2012-01-16

392

In the third line of the paragraph describing SIGLOST, change:

if the NSF client fails

to:

if the NFS client fails

Reported by Suse Shi.

2011-04-22

404

In the paragraph just above the heading for Section 20-7, change:

This program takes two command-line arguments, a signal number and a process ID,

to:

This program takes two command-line arguments, a process ID and a signal number,

Explanation:

This makes the order of the arguments given in the text match the order of the arguments for Listing 20-3.

2011-05-18

405

In Listing 20-3 (signals/t_kill.c), change:

    if (argc != 3 || strcmp(argv[1], "--help") == 0)
        usageErr("%s sig-num pid\n", argv[0]);

to:

    if (argc != 3 || strcmp(argv[1], "--help") == 0)
        usageErr("%s pid sig-num\n", argv[0]);

Explanation:

See also the erratum on page 404.

Reported by Madhavan Kasthurirangan.

2011-05-18

407

In the first sentence below the prototype box for sigemptyset() and sigfillset(), change:

One of sigemptyset() or sigaddset() must be used to initialize a signal set.

to:

One of sigemptyset() or sigfillset() must be used to initialize a signal set.

Reported by Bill McConnaughey.

2011-07-18

408

In the last line of the prototype box at the top of the page, change:

Returns 1 if sig is empty, otherwise 0

to:

Returns 1 if set is empty, otherwise 0

Reported by Junjiro Okajima.

2012-01-16

428

In the first paragraph of Section 21.1.3, in the third line from end of the paragraph, change:

using the volatile attribute

to:

using the volatile keyword

Explanation:

Tightening up the terminology, so as to avoid possible confusion with the gcc attribute feature.

Reported by Yang Yang.

2011-12-09

457

In the second line of the last paragraph on this page, change:

that may be queued to a process

to:

that may be queued by a process

2011-12-12

458

Replace the first two paragraphs on this page:

On Linux, this call returns –1. The reason for this is that Linux employs a different model for limiting the number of realtime signals that may be queued to a process. In Linux versions up to and including 2.6.7, the kernel enforces a system-wide limit on the total number of realtime signals that may be queued to all processes. This limit can be viewed and (with privilege) changed via the Linux-specific /proc/sys/kernel/rtsig-max file. The default value in this file is 1024. The number of currently queued realtime signals can be found in the Linux-specific /proc/sys/kernel/rtsig-nr file.

Starting with Linux 2.6.8, this model was changed, and the aforementioned /proc interfaces were removed. Under the new model, the RLIMIT_SIGPENDING soft resource limit defines a limit on the number of signals that can be queued to all processes owned by a particular real user ID. We describe this limit further in Section 36.3.

with:

In systems with glibc versions before 2.4, this call returns –1. Since glibc 2.4, the return value depends on the kernel version. Before Linux 2.6.8, the call returns the value in the Linux-specific /proc/sys/kernel/rtsig-max file. This file defines a system-wide limit on the number of realtime signals that may be queued to all processes. The default value is 1024, but a privileged process can change it. The Linux-specific /proc/sys/kernel/rtsig-nr file shows the number of currently queued realtime signals.

Starting with Linux 2.6.8, these /proc files disappear. In their place, the RLIMIT_SIGPENDING resource limit (Section 36.3) limits the number of signals that can be queued to all processes owned by a particular real user ID. Since glibc 2.10, the sysconf() call returns the RLIMIT_SIGPENDING limit. (The SigQ field of the Linux-specific /proc/PID/status file displays the number of realtime signals pending for a process.)


Explanation:

Once upon a time, sysconf(_SC_SIGQUEUE_MAX) always returned –1. Although the other points in the text relating to the /proc files and the RLIMIT_SIGPENDING limit were all correct, I missed the fact that the glibc behavior changed, and to best capture the implications of that fact required reworking the entire text.

Reported by Yang Yang.

2011-12-12

460

In the second paragraph from the top of the page, change the second sentence:

This program takes up to four arguments, of which the first three are mandatory: a signal number, a target process ID, and an integer value to accompany the realtime signal.

to:

This program takes up to four arguments, of which the first three are mandatory: a target process ID, a signal number, and an integer value to accompany the realtime signal.

Explanation:

This change makes the order of the text match the order of the arguments in the program in Listing 22-2.

Reported by Sangman Lee.

2011-04-02

463

At the end of Listing 22-3 (signals/catch_rtsigs.c), change:

    while (!allDone)                    /* Wait for incoming signals */
        pause();
}

to:

    while (!allDone)                    /* Wait for incoming signals */
        pause();
 
    printf("Caught %d signals\n", sigCnt);
    exit(EXIT_SUCCESS);
}

Explanation:

These lines were accidentally deleted from the published version of the program. Without them, the line of output "Caught 6 signals" will not appear in the shell session shown on page 462.

Reported by Yang Yang.

2011-12-12

469

At the top of the page, insert a small-font note as follows:

According to SUSv3, calling sigwaitinfo() without blocking the signals in set results in undefined behavior.

2011-12-08

472

In the definition of the struct signalfd_siginfo structure, change:

    int32_t ssi_fd;        /* File descriptor (SIGPOLL/SIGIO) */
    uint32_t ssi_tid;      /* Kernel timer ID (POSIX timers) */
    uint32_t ssi_band;     /* Band event (SIGPOLL/SIGIO) */
    uint32_t ssi_tid;      /* (Kernel-internal) timer ID (POSIX timers) */
    uint32_t ssi_overrun;  /* Overrun count (POSIX timers) */

to:

    int32_t ssi_fd;        /* File descriptor (SIGPOLL/SIGIO) */
    uint32_t ssi_tid;      /* (Kernel-internal) timer ID (POSIX timers) */
    uint32_t ssi_band;     /* Band event (SIGPOLL/SIGIO) */
    uint32_t ssi_overrun;  /* Overrun count (POSIX timers) */

Explanation:

The definition of the ssi_tid field was accidentally duplicated, with two different accompanying comments. The fix removes the duplicate while retaining the slightly more detailed comment.

Reported by Sangman Lee.

2011-05-12

476

In the prototype box at the bottom of the page, change:

int sigmask(sig);

to:

int sigmask(int sig);

Reported by Junjiro Okajima.

2012-01-16

481

In the third paragraph, change:

When the timer reaches 0, the corresponding signal is sent to the process, and then, if the interval (it_interval) is nonzero, the timer value (it_value) is reloaded, and counting down toward 0 recommences.

to:

When the timer reaches 0, the corresponding signal is sent to the process, and then, if the interval (it_interval) is nonzero, the timer value (it_value) is reloaded with the interval value, and counting down toward 0 recommences.

Explanation:

This change helps avoid reader misunderstanding by reiterating a point already made (in different words) at the foot of page 480.

Reported by Sangman Lee.

2011-04-02

482

In the fourth line from the top of the page, change:

non-async-signal-functions

to:

non-async-signal-safe functions

Reported by Kiju Kim.

2012-02-15

491

About two thirds of the way down the page, in the paragraph beginning "The time value", change the last sentence in the paragraph:

The clock_getres() system call returns a pointer to a timespec structure containing the resolution of the clock specified in clockid.

to:

The clock_getres() system call returns, via the argument res, a pointer to a timespec structure containing the resolution of the clock specified in clockid.

Explanation:

The reader could probably deduce this information from the declaration in the preceding prototype box, but this change removes any ambiguity about whether the information is returned as the function result or via the argument res.

Reported by Bill McConnaughey.

2011-08-12

496

In the definition of the sigevent structure in the middle of the page, change:

        pid_t      _tid;      /* ID of thread to be signaled /

to:

        pid_t      _tid;      /* ID of thread to be signaled */

Reported by Junjiro Okajima.

2012-01-16

497

Add a sentence under the description of SIGEV_THREAD_ID; change:

(With SIGEV_SIGNAL notification, a signal is queued to the process as a whole, and, if there are multiple threads in the process, the signal will be delivered to an arbitrarily selected thread in the process.)

to:

(With SIGEV_SIGNAL notification, a signal is queued to the process as a whole, and, if there are multiple threads in the process, the signal will be delivered to an arbitrarily selected thread in the process. See Section 33.2 for a discussion of the interaction of threads and signals.)

2011-07-19

516

In the second paragraph from the bottom of the page, change:

that it inherits during the during the fork().

to:

that it inherits during the fork().

Reported by Bill McConnaughey.

2011-07-18

521

In the last line of the first bullet point at the top of the page, change:

virtual memory page frames

to:

physical memory page frames

Reported by Madhavan Kasthurirangan.

2011-09-04

530

In Exercise 24-3, change:

at a given moment in time

to:

at a given point in the program

Explanation:

The revised wording is more precise.

Reported by Bill McConnaughey.

2011-07-18

535

In the first normal-size paragraph at the top of the page, change:

2,147,482,647

to:

2,147,483,647

Reported by Junjiro Okajima.

2012-01-16

555

In Listing 26-4 (procexec/make_zombie.c), change:

    default:    /* Parent */
        sleep(3);               /* Give child a chance to start and exit */
        snprintf(cmd, CMD_SIZE, "ps | grep %s", basename(argv[0]));
        cmd[CMD_SIZE - 1] = '\0';       /* Ensure string is null-terminated */
        system(cmd);            /* View zombie child */

to:

    default:    /* Parent */
        sleep(3);               /* Give child a chance to start and exit */
        snprintf(cmd, CMD_SIZE, "ps | grep %s", basename(argv[0]));
        system(cmd);            /* View zombie child */

Explanation:

While writing a few code examples, it looks like I forgot that snprintf() always terminates its argument, even when it completely fills the buffer. (This was probably me confusing with the behavior of strncpy(). See page 793 of the book.)

Reported by Madhavan Kasthurirangan.

2011-09-02

565

In the explanation of ETXTBSY, change:

The file referred to by pathname is open for writing by another process

to:

The file referred to by pathname is open for writing by one or more processes

Explanation:

The ETXTBSY error could of course occur if the caller of execve() has itself opened pathname for writing.

Reported by Junjiro Okajima.

2012-01-16

572

In the fifth line of the first paragraph of the small-font note on this page, change:

(which is given as an argument to the script,

to:

(which is given as an argument to the interpreter,

Reported by Junjiro Okajima.

2012-01-16

572

In the fourth line of the second paragraph of the small-font note on this page, change:

(and these are passed as separate words to the script)

to:

(and these are passed as separate words to the interpreter)

Reported by Junjiro Okajima.

2012-01-16

580

In the third of the bullet points at the top of the page, change:

If all system calls succeed, then system() returns the termination status of the child shell used to execute command. (The termination status of a shell is the termination status of the last command it executes.)

to:

If all system calls succeed, then system() returns the termination status of the child shell used to execute command. The termination status of a shell is the exit status of the last command it executes; if that command is killed by a signal, most shells exit with the value 128+n, where n is the signal number. (If the child shell is itself killed by a signal, the termination status is as described in Section 26.1.3.)

Explanation:

There are two clarifications here. The first of these reiterates a point made in a small-font note near the top of page 532: when a command is terminated by a signal, the shell indicates that fact with a status of 128 plus the signal number.

The second, more significant fix (regarding what happens if the child shell is killed by a signal) results from Yang Yang's report. Yang Yang noted that on his Ubuntu system, the output in the last few lines of the shell session is different from that shown in the book. In the book, the following output is shown near the end of the shell session:

    $ fg
    ./t_system
    system() returned: status=0x000f (0,15)
    child killed by signal 15 (Terminated)
    

By contrast, Yang Yang obtained output of the form:

    $ fg
    ./t_system
    system() returned: status=0x8f00 (143,0)
    child exited, status=143
    

The differing output is a consequence of differences in the shells executed by system() on the two systems. A small-font note at the bottom of page 583 notes that some shells, when executing a simple command with sh -c, directly execute the command, rather than forking a new child shell to execute the command. On shells that perform this optimization, when system() is asked to execute the sleep 100 command, only a single process is created as a consequence of the call:

    system()    [process calls system("sleep 100")]
        |
    fork()
      :  \
      :   exec("sh")                  [Child process execs a shell]
      :     |
      :   exec("sleep")               [Child shell directly execs "sleep"]
      :     |
      :   [killed by SIGTERM]
      :  /
     waitpid(..., &status, ...)       [Sees "Killed by signal 15"]
    

By contrast, some shells don't perform this optimization, and the call to system() creates two processes, yielding the scenario shown in Figure 27-2 on page 584:

    system()    [process calls system("sleep 100")]
        |
    fork()
      :  \
      :   exec("sh")                  [Child process execs a shell]
      :     |
      :   fork()                      [Shell creates a new child]
      :     : \
      :     :  exec("sleep")          [New child execs "sleep"]
      :     :    |
      :     :  [killed by SIGTERM]
      :     : /
      :   waitpid(..., &status, ...)  [Sees "Killed by signal 15"]
      :     |
      :   exit(128+15)
      :  /
    waitpid(..., &status, ...)        [Sees "Exited normally, with status 143"]
    

The output in the book corresponds to the first of the scenarios described above. The shell executed by system() is bash, which does perform the optimization. In this case, the process running sleep is the child shell created by system(), and when that process is killed the status reported back by system() is as for a process killed by a signal.

The output for Yang Yang's case corresponds to the second scenario. The shell executed by system() is one that does not perform the optimization (dash, the default shell used to execute scripts on Ubuntu since version 6.10). In this case, the process running sleep is a child of the child shell created by system(). When that process is killed by a signal, the child shell observes the termination, and itself terminates with a status of the form 128+signum, which is in turn returned to the caller of system().

Reported by Yang Yang.

2011-12-23

601

In the second bullet point on this page, at the end of the first sentence ("If CHILD_SIG is nonzero…"), add a circled "5" as a reference to the corresponding line in Listing 28-3.


Reported by Junjiro Okajima.

2012-01-16

623

Inside the prototype box for pthread_exit(), change:

include <pthread.h>

to:

#include <pthread.h>

Reported by Fabien Galand.

2011-07-13

624

Inside the prototype boxes for pthread_self() and pthread_equal() (i.e., two changes!), change:

include <pthread.h>

to:

#include <pthread.h>

Reported by Fabien Galand.

2011-07-13

625

Inside the prototype box for pthread_join(), change:

include <pthread.h>

to:

#include <pthread.h>

Reported by Fabien Galand.

2011-07-13

632

Near the top of Listing 30-1 (threads/thread_incr.c), change:

static int glob = 0;

static void *                   /* Loop 'arg' times incrementing 'glob' */
threadFunc(void *arg)

to:

static volatile int glob = 0;   /* "volatile" prevents compiler optimizations
                                   of arithmetic operations on 'glob' */
static void *                   /* Loop 'arg' times incrementing 'glob' */
threadFunc(void *arg)

Explanation:

Making glob volatile means that the program more easily produces the "incorrect" output described on pages 633 and 634, even in the face of compiler optimization. Yang Yang's email report summarized the issue well, so I will just reproduce a lightly edited version of his comments:

I think failing to declare "glob" as volatile makes the program less "incorrect", because in this case, the output is determined by both the kernel's CPU scheduling decisions (as described on page 634) and the compiler's optimization decisions.

I've compiled Listing 30-1 with –O[0123] (GCC 4.5.2):

  1. –O2 and –O3 results in the same assembly code, which ably simplifies the entire loop to a single addition "glob += n". It's very hard to observe an incorrect output even with a huge n (overflow doesn't count), although the race condition does exist.
  2. –O1 uses a register to save the intermediate sum in each iteration, and writes the result into "glob" only once when the loop ends. Thus the output will be either n (more likely with a big n) or 2*n (more likely with a small n, as the first output on page 633).
  3. –O0 faithfully executes the load-increment-store routine (as if volatile were added), and its behavior matches both outputs on page 633.

With volatile, of course, the program's behavior will always be the same "incorrect" as in the text.

Reported by Yang Yang.

2011-12-25

635

In the sentence that immediately precedes Section 30.1.1, change:

In order to safely handle shared variables, all threads must cooperate in their use of a mutex, abiding by the locking rules it enforces.

to:

In order to safely handle shared variables, all threads must cooperate in their use of a mutex, abiding by its locking rules.

Explanation:

The use of the word "enforces" in the original text was a little confusing, suggesting a meaning that runs counter to the point that mutex locking is advisory.

Reported by Bill McConnaughey.

2011-07-18

638

In the second-to-last line on the page, remove the extra space between the words "early" and "futex".


Reported by Fabien Galand.

2011-11-26

644

In the seventh line of the second paragraph, change:

threads are designed to perform the exactly same task

to:

threads are designed to perform exactly the same task

Reported by Simon Durrant.

2011-09-26

649

This erratum makes changes on pages 649 and 650 to fix a single problem in Listing 30-4 (threads/thread_multijoin.c).

On page 649, in the second line from the bottom of the page, change:

    int idx = *((int *) arg);

to:

    int idx = (int) arg;

On page 650, about two thirds of the way down the page, change:

        s = pthread_create(&thread[idx].tid, NULL, threadFunc, &idx);

to:

        s = pthread_create(&thread[idx].tid, NULL, threadFunc, (void *) idx);

Explanation:

There was a race condition in the program. In the main program, the value &idx was passed as the final argument of the call to pthread_create(), which is located within a for loop indexed on idx. In the new thread, the passed pointer value was dereferenced to obtain the value for the local variable idx used within the thread. However, this will only succeed if the new thread dereferences the pointer before the main thread increments idx inside the for loop.

The changes given in the erratum correct the problem, and should generally work on any platform, but, as noted towards the bottom of page 622, casting an int back and forth to a pointer type is not strictly standards-conformant. A standards-conformant solution would be to apply a patch to the original program something like the following:

@@ -16,19 +16,22 @@
     TS_JOINED                   /* Thread terminated, and joined */
 };
 
-static struct {                 /* Info about each thread */
+struct tinfo {                  /* Info about each thread */
     pthread_t tid;              /* ID of this thread */
     enum tstate state;          /* Thread state (TS_* constants above) */
     int sleepTime;              /* Number seconds to live before terminating */
-} *thread;
+};
+
+static struct tinfo *thread;
 
 static void *                   /* Start function for thread */
 threadFunc(void *arg)
 {
-    int idx = *((int *) arg);
+    struct tinfo *tptr = arg;
+    int idx = tptr - thread;    /* Obtain index in 'thread' array */
     int s;
 
-    sleep(thread[idx].sleepTime);       /* Simulate doing some work */
+    sleep(tptr->sleepTime);     /* Simulate doing some work */
     printf("Thread %d terminating\n", idx);
 
     s = pthread_mutex_lock(&threadMutex);
@@ -36,7 +39,7 @@
         errExitEN(s, "pthread_mutex_lock");
 
     numUnjoined++;
-    thread[idx].state = TS_TERMINATED;
+    tptr->state = TS_TERMINATED;
 
     s = pthread_mutex_unlock(&threadMutex);
     if (s != 0)
@@ -65,7 +68,7 @@
     for (idx = 0; idx < argc - 1; idx++) {
         thread[idx].sleepTime = getInt(argv[idx + 1], GN_NONNEG, NULL);
         thread[idx].state = TS_ALIVE;
-        s = pthread_create(&thread[idx].tid, NULL, threadFunc, &idx);
+        s = pthread_create(&thread[idx].tid, NULL, threadFunc, &thread[idx]);
         if (s != 0)
             errExitEN(s, "pthread_create");
     }

Reported by Jacob Mandelson.

2011-04-02

656

In the second paragraph from the top of the page, change:

lock that mutex when the function is called, and unlock it when the mutex returns

to:

lock that mutex when the function is called, and unlock it when the function returns

Reported by Sun Jian.

2011-09-05

674

In the shell session towards the bottom of the page, change:

    $ ./t_pthread_cancel

to:

    $ ./thread_cancel

Reported by Yang Yang.

2011-12-28

704

In the last line of the prototype box for getsid() at the bottom of the page, change:

or (pid_t) –1 on error

to:

or –1 on error

Explanation:

Such a cast is not needed when the standards require the type to be a signed integer. SUSv3 and SUSv4 incorrectly documented a cast as being needed for getsid() and a few other functions. For some more details, see this mail thread and the follow-up Austin bug report.

2012-01-16

705

In the last line of the prototype box for setsid() at the top of the page, change:

or (pid_t) –1 on error

to:

or –1 on error

Explanation:

See the erratum for the getsid() prototype box on page 704.

2012-01-16

734

Change the last sentence on the page:

As a result, processes with low nice values receive less CPU than before, and processes with high nice values obtain a greater proportion of the CPU.

to:

As a result, processes with low priorities receive less CPU than before, and processes with high priorities obtain a greater proportion of the CPU.

Explanation:

This wording change is intended to prevent reader confusion over whether "low nice value" means a process that has a low priority (actually a high nice value) or processes whose nice value is a low number (meaning a high priority).

Reported by Bill McConnaughey.

2011-07-18

736

Change the third paragraph:

In Linux kernels before 2.6.12, an unprivileged process may use setpriority() only to (irreversibly) lower its own or another process's nice value. A privileged (CAP_SYS_NICE) process can use setpriority() to raise nice values.

to:

In Linux kernels before 2.6.12, an unprivileged process may use setpriority() only to (irreversibly) lower its own or another process's priority. A privileged (CAP_SYS_NICE) process can use setpriority() to raise priorities.

Explanation:

By rewording in terms of priorities, this wording change is intended to prevent reader confusion over whether lowering (raising) the nice value means adding a positive or negative number to the nice value. See also the erratum for page 734.

Reported by Junjiro Okajima.

2012-01-16

736

Change the initial sentences of the fourth paragraph:

Since kernel 2.6.12, Linux provides the RLIMIT_NICE resource limit, which permits unprivileged processes to increase nice values. An unprivileged process can raise its own nice value to the maximum specified by the formula 20 – rlim_cur, where rlim_cur is the current RLIMIT_NICE soft resource limit. As an example, if a process's RLIMIT_NICE soft limit is 25, then its nice value can be raised to –5.

to:

Since kernel 2.6.12, Linux provides the RLIMIT_NICE resource limit, which permits unprivileged processes to raise priorities. An unprivileged process can set its own nice value to the maximum specified by the formula 20 – rlim_cur, where rlim_cur is the current RLIMIT_NICE soft resource limit. As an example, if a process's RLIMIT_NICE soft limit is 25, then its nice value can be set to –5.

Explanation:

This wording change is intended to prevent reader confusion over whether lowering (raising) the nice value means adding a positive or negative number to the nice value. See also the erratum for page 734.

Reported by Junjiro Okajima.

2012-01-16

741

Change the last sentence of the second paragraph:

Thus, the lowest SCHED_RR priority would be specified as sched_get_priority_min(SCHED_FIFO), the next higher priority as sched_get_priority_min(SCHED_FIFO) + 1, and so on.

to:

Thus, the lowest SCHED_RR priority would be specified as sched_get_priority_min(SCHED_RR), the next higher priority as sched_get_priority_min(SCHED_RR) + 1, and so on.

Reported by Junjiro Okajima.

2012-01-16

750

In the code snippet near the top of the page, change:

    sched_setaffinity(pid, CPU_SETSIZE, &set);

to:

    sched_setaffinity(pid, sizeof(cpu_set_t), &set);

Explanation:

The setting of the second argument to sched_setaffinity() was correctly explained at the foot of page 749, and demonstrated in the example program, procpri/t_sched_setaffinity.c, provided in the source code distribution for the book, but unfortunately was shown incorrectly in this example. The fix above corrects the error. An alternative would have been to use the value CPU_SETSIZE / 8 as the second argument of the call.

Reported by Emmanuel Gras.

2011-10-14

774

In Listing 37-3, change:

static volatile sig_atomic_t hupReceived = 0;
                                    /* Set nonzero on receipt of SIGHUP */
 from
static void
sighupHandler(int sig)
{

to:

static volatile sig_atomic_t hupReceived = 0;
                                    /* Set nonzero on receipt of SIGHUP */

static void
sighupHandler(int sig)
{

Explanation:

This was a random piece of text that crept into the text during production; the problem didn't occur in the actual source code of the example program.

Reported by Simon Durrant.

2011-10-04

774

This change spans the code at the bottom of page 774 and top of page 775.

Change the lines:

        if (hupReceived) {              /* If we got SIGHUP... */
            logClose();
            logOpen(LOG_FILE);
            readConfigFile(CONFIG_FILE);
            hupReceived = 0;            /* Get ready for next SIGHUP */
        }

to:

        if (hupReceived) {              /* If we got SIGHUP... */
            hupReceived = 0;            /* Get ready for next SIGHUP */
            logClose();
            logOpen(LOG_FILE);
            readConfigFile(CONFIG_FILE);
        }

Explanation:

This fixes a race condition that occurs if two SIGHUP signals arrive in quick succession (i.e., there were two closely spaced attempts to reinitialize the daemon).

In the original ordering of the code, if the second SIGHUP signal was received just after (say) the call to readConfigFile(), then, because hupReceived is immediately reset to zero, the daemon would not be reinitialized a second time.

Reported by Yacine Belkadi.

2011-04-19

776

At the bottom of the page, after the small-font note beginning "Although syslog(2) and syslog(3) share the same name", add a further small-font paragraph:

Some modern implementations of syslogd, such as rsyslog and syslog-ng, dispense with the need for a separate klogd daemon by instead themselves reading directly from /proc/kmsg.

Reported by Przemysław Pawełczyk.

2011-06-12

814

Change the bullet point about half way down the page:

Since Linux 2.6.24, file capabilities can be disabled if the kernel is built without the CONFIG_SECURITY_FILE_CAPABILITIES option.

to:

In Linux kernel versions 2.6.24 through to 2.6.32, file capabilities can be disabled if the kernel is built without the CONFIG_SECURITY_FILE_CAPABILITIES option.

2011-09-17

827

In the prototype box at the top of the page, change:

void updwtmpx(char *wtmpx_file, struct utmpx *ut);

to:

void updwtmpx(const char *wtmpx_file, const struct utmpx *ut);

Reported by Yang Yang.

2012-01-23

857

Change the first sentence under the heading Further information:

Various information related to static and shared libraries can be found in the ar(1), gcc(1), ld(1), ldconfig(8), ld.so(8), dlopen(3), and objdump(1) manual pages and in the info documentation for ld and readelf.

to:

Various information related to static and shared libraries can be found in the ar(1), gcc(1), ld(1), ldconfig(8), ld.so(8), dlopen(3), readelf(1), and objdump(1) manual pages and in the info documentation for ld.

Explanation:

The readelf documentation is available via info, but it's actually a manual page, and so is best listed as such here.

Reported by Yang Yang.

2012-01-27

879

In the fourth line from the bottom of the page, change:

The data exchanged via pipes, FIFOs, and datagram sockets

to:

The data exchanged via pipes, FIFOs, and stream sockets

Reported by Yang Yang.

2012-01-28

885

In the first bullet point at the top of the page, change:

The System V IPC facilities are connectionless. These facilities provide no notion of a handle (like a file descriptor) referring to an open IPC object. In later chapters, we'll sometimes talk of "opening" a System V IPC object, but this is really just shorthand to describe the process of obtaining a handle to refer to the object.

to:

The System V IPC facilities are connectionless. These facilities provide no notion of a handle (like a file descriptor) referring to an open IPC object. In later chapters, we'll sometimes talk of "opening" a System V IPC object, but this is really just shorthand to describe the process of obtaining an identifier that refers to the object.

Explanation:

The original text is a little confusing, since it talks of "obtaining a handle to refer to the object", whereas the preceding sentence says that there is "no notion … of a handle referring to an open IPC object". The reader can probably deduce the intended sense (that there is no notion of something like an open file handle) from the rest of the chapter, and the point is made quite clear in Section 45.1, but the wording here could be better.

Reported by Yang Yang.

2012-01-28

904

In Listing 44-5 (pipes/popen_glob.c), at the bottom of the page, change:

        /* Build and execute command to glob 'pat' */

        snprintf(popenCmd, PCMD_BUF_SIZE, POPEN_FMT, pat);
        popenCmd[PCMD_BUF_SIZE - 1] = '\0';     /* Ensure string is
                                                   null-terminated */
        fp = popen(popenCmd, "r");

to:

        /* Build and execute command to glob 'pat' */

        snprintf(popenCmd, PCMD_BUF_SIZE, POPEN_FMT, pat);

        fp = popen(popenCmd, "r");

Explanation:

See the erratum for page 555.

2011-09-02

907

About one third of the way down the page (three lines above the mkfifo() prototype box), change:

and ls –F appends an the pipe symbol (|) to the FIFO pathname.

to:

and ls –F appends a pipe symbol (|) to the FIFO pathname.

Reported by Fabien Galand.

2011-11-26

916

In the first line of the second bullet point at the top of the page, change:

If the FIFO is being opened FIFO for writing,

to:

If the FIFO is being opened for writing,

Reported by Yang Yang.

2012-02-02

1008

In the shell session output at the top of the page, change:

$ ./svshm_create -p 102400
9633796
$ ./svshm_create -p 3276800
9666565
$ ./svshm_create -p 102400
1015817
$ ./svshm_create -p 3276800
1048586

to:

$ ./svshm_create -p 102400
9633796
$ ./svshm_create -p 3276800
9666565

Explanation:

By accident, two superfluous invocations of the svshm_create program were included in the shell session output. These superfluous invocations do no harm (the remainder of the shell session output is still correct), but they are unnecessary and thus confusing.

Reported by Fabien Galand.

2011-11-26

1040

In the second paragraph of Section 49.10 (i.e., nearly two thirds of the way down the page), change:

when explaining why it usually preferable to specify

to:

when explaining why it is usually preferable to specify

Reported by Fabien Galand.

2011-11-26

1042

In the code snippet about half way down the page, change:

remap_file_pages(addr, ps, 0, 2, 0);
                         /* Maps page 0 of file into page 2 of region */
remap_file_pages(addr + 2 * ps, ps, 0, 0, 0);
                         /* Maps page 2 of file into page 0 of region */

to:

remap_file_pages(addr, ps, 0, 2, 0);
                         /* Maps page 2 of file into page 0 of region */
remap_file_pages(addr + 2 * ps, ps, 0, 0, 0);
                         /* Maps page 0 of file into page 2 of region */

Reported by Madhavan Kasthurirangan.

2011-09-18

1049

In the third line of the second-to-last paragraph (beginning "The munlock() system call…"), change:

in the same way as for munlock().

to:

in the same way as for mlock().

Reported by Simon Durrant.

2011-12-13

1079

In the last line of the paragraph describing, SIGEV_NONE, change:

when a new messages arrives on an empty queue.

to:

when a new message arrives on an empty queue.

Reported by Bill McConnaughey.

2011-07-18

1141

A bit more than half way down the page, change:

    $ ls -li /dev/sda7 | awk '$6 == "3," && $7 == 10'

to:

    $ ls -li /dev | awk '$6 == "3," && $7 == 7'

Explanation:

Initial report by Corentin Chary (2011-08-23). My initial errata improved after a note from Gerald Demitre (2012-01-14).

Reported by Corentin Chary and Gerald Demitre

2012-01-14

1161

At the start of the third paragraph, change:

The src_addr and addrlen arguments to accept()

to:

The remaining arguments to accept()

Reported by Simon Durrant.

2011-12-13

1189

In the second paragraph on this page, change:

The range of IANA registered ports is 1024 to 41951.

to:

The range of IANA registered ports is 1024 to 49151.

Explanation:

A typo…

Reported by Yang Firo.

2011-05-04

1190

In the right-hand "TCP endpoint" box in Figure 58-8, the boxes labeled "send buffer" and "receive buffer" should be reversed, so that "receive buffer" is at the top and "send buffer" is at the bottom.


Reported by Yongzhi Pan.

2012-01-15

1203

In the first line of the first paragraph, change:

The sin_family field is set to AF_INET6.

to:

The sin6_family field is set to AF_INET6.

Reported by Simon Durrant.

2012-01-02

1214

At the end of the ninth line from the bottom of the page, change:

The in_addr field

to:

The ai_addr field

Reported by Simon Durrant.

2012-01-02

1230

In Listing 59-9 (sockets/inet_sockets.c), near the end of the listing, change:

    if (getnameinfo(addr, addrlen, host, NI_MAXHOST,
                    service, NI_MAXSERV, NI_NUMERICSERV) == 0)
        snprintf(addrStr, addrStrLen, "(%s, %s)", host, service);
    else
        snprintf(addrStr, addrStrLen, "(?UNKNOWN?)");

    addrStr[addrStrLen - 1] = '\0';     /* Ensure result is null-terminated */
    return addrStr;

to:

    if (getnameinfo(addr, addrlen, host, NI_MAXHOST,
                    service, NI_MAXSERV, NI_NUMERICSERV) == 0)
        snprintf(addrStr, addrStrLen, "(%s, %s)", host, service);
    else
        snprintf(addrStr, addrStrLen, "(?UNKNOWN?)");

    return addrStr;

Explanation:

See the erratum for page 555.

2011-09-02

1235

In the last line of the first paragraph in Section 59.14, change:

In the case,

to:

In this case,

Reported by Simon Durrant.

2012-01-02

1261

In the small-font note near the bottom of the page, change:

Performance benefits could also be obtained if sendfile() could be used to transfer bytes between two regular files. On Linux 2.4 and earlier, out_fd could refer to a regular file. Some reworking of the underlying implementation meant that this possibility disappeared in the 2.6 kernel. However, this feature may be reinstated in a future kernel version

to:

Performance benefits could also be obtained if sendfile() could be used to transfer bytes between two regular files. On Linux 2.4 and earlier, out_fd could refer to a regular file. Some reworking of the underlying implementation meant that this possibility disappeared in the 2.6 kernel. Some later changes restored this feature in Linux 2.6.33.

2011-09-11

1337

In the first sentence after the poll() prototype box, change:

The fds argument and the pollfd array (nfds) specify the file descriptors that poll() is to monitor.

to:

The pollfd array (fds) and the nfds argument specify the file descriptors that poll() is to monitor.

Reported by Simon Durrant.

2012-01-02

1349

Just over half way down the page, change:

        if (gotSigio) {                 /* Is input available? */

            /* Read all available input until error (probably EAGAIN)
               or EOF (not actually possible in cbreak mode) or a
               hash (#) character is read */

            while (read(STDIN_FILENO, &ch, 1) > 0 && !done) {
                printf("cnt=%d; read %c\n", cnt, ch);
                done = ch == '#';
            }
 
            gotSigio = 0;
        }

to:

        if (gotSigio) {                 /* Is input available? */
            gotSigio = 0;

            /* Read all available input until error (probably EAGAIN)
               or EOF (not actually possible in cbreak mode) or a
               hash (#) character is read */

            while (read(STDIN_FILENO, &ch, 1) > 0 && !done) {
                printf("cnt=%d; read %c\n", cnt, ch);
                done = ch == '#';
            }
        }

Explanation:

This fixes a race condition that occurs if two SIGIO signals arrive in quick succession.

The race condition in the original code is as follows. Suppose that some input has been supplied to the program, a SIGIO signal has been generated, and we have just returned from the signal handler and have entered the block of code shown in the erratum. If further input arrived and a second SIGIO signal was received just after the while loop terminated, then, because gotSigio is immediately reset to zero, the program would not read the new input (until the delivery of a further SIGIO signal).

Reported by Yacine Belkadi.

2011-04-19

1355

In the fourth line from the top of the page, change:

The F_GETOWN_EX operation is the converse of the F_GETOWN_EX operation.

to:

The F_GETOWN_EX operation is the converse of the F_SETOWN_EX operation.

Reported by Bill McConnaughey.

2011-07-18

1361

In the shell session in the middle of this page, change:

$ fg
./epoll_input p q
About to epoll_wait()
Ready: 2
  fd=4; events: EPOLLIN 
    read 4 bytes: ppp

  fd=5; events: EPOLLIN EPOLLHUP 
    read 4 bytes: qqq

    closing fd 5
About to epoll_wait()

to:

$ fg
./epoll_input p q
About to epoll_wait()
Ready: 2
  fd=4; events: EPOLLIN 
    read 4 bytes: ppp

  fd=5; events: EPOLLIN EPOLLHUP 
    read 4 bytes: qqq

About to epoll_wait()
Ready: 1
  fd=5; events: EPOLLHUP
    closing fd 5
About to epoll_wait()

Explanation:

The shell output originally shown was produced by an earlier version of the program that contained a small bug. The bug was fixed, but I overlooked to refresh the shell session demonstrating the use of the program.

Reported by Pedro Dominguez.

2011-04-28

1361

Change the second to last paragraph on the page:

The two blank lines in the above output are the newlines that were read by the instances of cat, written to the FIFOs, and then read and echoed by our monitoring program.

to:

The two blank lines in the above output are the newlines that were read by the instances of cat, written to the FIFOs, and then read and echoed by our program.

Explanation:

This isn't an error fix at all. The change (which shortens the paragraph by one line) was made solely to create enough vertical space on the page to accommodate the previous change (which added three lines to the page).

2011-04-28

1366

In the code snippet a bit more than half way down the page, change:

    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev) == -1)

to:

    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)

Reported by tjuer.

2011-12-16

1418

At the end of the last paragraph on this page, add a sentence:

This file can be viewed using zcat(1) and searched using zgrep(1). The /proc/config.z file is itself only available if the kernel was configured with the CONFIG_IKCONFIG and CONFIG_IKCONFIG_PROC configuration options enabled.

Reported by Bill McConnaughey.

2011-07-18

1426

In the solution for Exercise 8-1, change:

8-1. The two getpwnam() calls are executed before the printf() output string is constructed, and—since getpwnam() returns its result in a statically allocated buffer—the second call overwrites the result returned by the first call.

to:

8-1. The two getpwuid() calls are executed before the printf() output string is constructed, and—since getpwuid() returns its pw_name result in a statically allocated buffer—the second call overwrites the result returned by the first call.

Explanation:

See the erratum for Exercise 8-1 on page 166.

Reported by René Thomsen.

2011-07-14

1439

Under the bibliography entry for "Gont, F. 2008", change the URL:

http://www.cpni.gov.uk/Docs/InternetProtocol.pdf

to:

http://www.gont.com.ar/papers/InternetProtocol.pdf

Reported by Kiju Kim.

2012-01-20

1439

Under the bibliography entry for "Gont, F. 2009 (a)", change the URL:

http://www.cpni.gov.uk/Docs/tn-03-09-security-assessment-TCP.pdf

to:

http://www.gont.com.ar/papers/tn-03-09-security-assessment-TCP.pdf

Reported by Kiju Kim.

2012-01-20

1440

Under the bibliography entry for "Hallyn, S. 2007", change the URL:

http://www.ibm.com/developerworks/library/l-posixcap.html

to:

http://www.ibm.com/developerworks/library/l-posixcap/index.html

Reported by Kiju Kim.

2012-01-20

1440

In the small-font note under the bibliography entry for "Josey, A. (ed.). 2004", change:

A newer version of this guide (published in 2010) for version 4 of the specification can be ordered online at http://www.opengroup.org/bookstore/catalog/.

to:

A newer version of this guide (published in 2010) for version 4 of the specification can be found at http://www.unix.org/version4/theguide.html.

Reported by Kiju Kim.

2012-01-20

1440

Under the bibliography entry for "Kent, A., and Mogul, J.C. 1987", change the URL:

http://www.acm.org/sigcomm/ccr/archive/1995/jan95/ccr-9501-mogulf1.pdf

to:

http://ccr.sigcomm.org/archive/1995/jan95/ccr-9501-mogulf1.html

Reported by Kiju Kim.

2012-01-20

1441

Under the bibliography entry for "Lu, H.J. 1995" replace the URL:

http://www.trunix.org/programlama/os/elf-hl/Documentation/elf/elf.html

to:

This paper can be found online at a variety of locations.

Explanation:

There is currently a version at http://l4u-00.jinr.ru/usoft/WWW/www_debian.org/Documentation/elf/elf.html, but I'm not sure how stable that location is.

Reported by Kiju Kim.

2012-01-20

1444

Under the bibliography entry for "Stone, J., and Partridge, C. 2000", change the URL:

http://www.acm.org/sigcomm/sigcomm2000/conf/abstract/9-1.htm

to:

http://dl.acm.org/citation.cfm?doid=347059.347561

Reported by Kiju Kim.

2012-01-20

1469

Change the index entry:

International Standards Organization (ISO), 11

to:

International Organization for Standardization (ISO), 11

Explanation:

See the erratum for page 11.

2011-08-04

1470

Change the index entry:

ISO (International Standards Organization), 11

to:

ISO (International Organization for Standardization), 11

Explanation:

See the erratum for page 11.

2011-08-04

Fixes and improvements in the second printing

The following fixes and improvements were applied in the second and later printings of the book.

Page Fix Reported
xli

Under the heading "Web site and source code of example programs", change:

http://www.man7.org/tlpi/.

to:

http://man7.org/tlpi/.

2011-01-08

xli

Under the heading "Feedback", following the sentence:

Book bugs and general suggestions about how the explanations in the book can be improved are also welcome.

add the sentence:

(A current list of errata can be found at http://man7.org/tlpi/errata/.)

2011-01-08

15

In the paragraph just above the heading "Legacy features", change:

When using interfaces that are unspecified or weakly specified, we have few guarantees when porting applications to other UNIX implementations.

to:

When using interfaces that are unspecified or weakly specified, we have few guarantees when porting applications to other UNIX implementations, and portable applications should avoid relying on the behavior of a specific implementation.

Explanation:

The added text simply emphasizes a point that was already implied.

2011-02-28

16

On the fourth line from the bottom of the page, remove the superfluous right parenthesis following "mid-1990s".


Reported by Justin Pryzby.

2010-12-28

32

In the fourth paragraph, change:

the operation performed execve()

to:

the operation performed by execve()

Reported by Sun Jian.

2011-02-25

48

In the fourth line, change:

(in #ifdef statements)

to:

(in #if statements)

Reported by Richard Moore.

2011-01-26

57

In the first line of text below the example program, change:

The file enames.c.inc

to:

The file ename.c.inc

Reported by Kiju Kim.

2011-02-13

57

In the third line of the second normal-size font paragraph on the page (i.e., a bit more than half way down the page), change:

names separate by a slash.

to:

names separated by a slash.

Reported by Subu Rama.

2010-12-03

67

A bit more than half way down the page, immediately following the heading "Using macros that may not be present on all implementations" change:

In some cases, a macro may be not be defined...

to:

In some cases, a macro may not be defined...

Reported by the multitalented Markus Boje.

2010-11-22

75

In the first bullet point at the top of the page, change:

They can be retrieved using the fcntl() F_GETFL operation (Section 5.3).

to:

Only one of these values should be specified in flags. The access mode can be retrieved using the fcntl() F_GETFL operation (Section 5.3).

Explanation:

This is just a clarification that reiterates a point made on page 72.

Suggested from a conversation with Krzysztof Żelechowski.

2010-12-16

75

In the third line of the O_CLOEXEC paragraph at the bottom of the page, change:

additional fcntl() F_SETFD and F_SETFD operations

to:

additional fcntl() F_GETFD and F_SETFD operations

Reported by Subu Rama.

2010-11-30

83

In the middle of the last paragraph (small-font note), change:

This allows an application to be sure that a later write() to the file won't fail because disk space is exhausted (which could otherwise occur if a hole in the file was filled in, or some other application consumed space on the disk).

to:

This allows an application to be sure that a later write() to the file won't fail because disk space is exhausted (which could otherwise occur if a hole in the file was filled in, or some other application consumed space on the disk before the full extent of the file was written).

Explanation:

The parenthetical clause describes two reasons why the write() might fail. The added words simply clarify the second reason a little.

Reported by Kiju Kim.

2011-03-19

99

In the paragraph at the bottom of the page, change:

The integer count specifies

to:

The integer iovcnt specifies

Reported by Subu Rama.

2010-11-30

110

(Exercise 5-3) In the first sentence of the last paragraph of the page, change:

This file should open

to:

This program should open

Reported by Justin Pryzby.

2010-12-28

111

In Exercise 5-6, change the line:

    write(fd2, "world", 6);

to:

    write(fd2, " world", 6);

(i.e., add a space before world).


Reported by John Wiersba. (I initially wrote up this erratum incorrectly; fixed on 2010-12-07, after a note from Geoff Clare.)

2010-11-30

115

In the last paragraph of Section 6.2, change:

the Ppid field

to:

the PPid field

(i.e., make the second "P" upper case).


Reported by Subu Rama.

2010-12-20

118

About one third of the way down the page, change:

    extern char etext, edata, end;
            /* For example, &etext gives the address of the end
               of the program text / start of initialized data */

to:

    extern char etext, edata, end;
            /* For example, &etext gives the address of the next byte past
               the end of the program text / start of initialized data */

Explanation:

The original wording was intended (the details are explained in the text), but the rewording is more precise and avoids possibilities for confusion.

Reported by Sun Jian.

2011-02-16

155

In the last paragraph of Section 8.2, change the sentence:

SUSv3 doesn't specify shadow passwords, and not all UNIX implementations provide this feature.

to:

SUSv3 doesn't specify shadow passwords. Not all UNIX implementations provide this feature, and on implementations where it is provided the details of file locations and APIs vary.

Explanation:

It's worth emphasizing that even on systems where shadow passwords are provided, the details are unstandardized and therefore vary across systems.

Reported by John Wiersba.

2010-12-13

156

In the bullet point for Encrypted password ID about one third of the way down the page, change:

the passwd command

to:

the gpasswd command

Reported by Justin Pryzby.

2010-12-28

156

In the bullet point for Group ID about half way down the page, change the sentence:

There is normally one group defined with the group ID 0, named root (like the /etc/passwd record with user ID of 0).

to:

There is normally one group defined with the group ID 0, named root (like the /etc/passwd record with user ID of 0, but unlike the user ID 0, this group has no special privileges).

Explanation:

The added detail prevents possible misunderstandings about the significance of GID 0.

Reported by John Wiersba.

2010-12-13

180

In the third paragraph, change:

Instead, it defines the initial real user ID, effective user ID, and saved set-user-ID of the login shell.

to:

Instead, it defines the initial real group ID, effective group ID, and saved set-group-ID of the login shell.

Reported by Justin Pryzby.

2011-01-03

181

In the first bullet point of the page, change:

The setegid() implementation also changes the saved set-group-ID if the effective user ID is set to a value other than that of the current real user ID.

to:

The setegid() implementation also changes the saved set-group-ID if the effective group ID is set to a value other than that of the current real group ID.

Reported by Justin Pryzby.

2011-01-03

187

In the third line of the small-font note about two thirds of the way down the page, change:

4.3BSD added the more precise

to:

4.2BSD added the more precise

2010-12-26

199

In the final paragraph, change the opening piece of the first sentence:

The std and dst components are strings identifying the standard and DST timezones;

to:

The std and dst components are strings that define names for the standard and DST timezones;

Explanation:

This is a clarification to remove the ambiguity of the word "identifying" (does "identifying" mean "defining a name for" or "selecting"?).

Suggested from a conversation with Subu Rama.

2010-12-20

200

About a quarter of the way down the page, add a closing quote at the end of the first code snippet, so that it reads:

    TZ="CET-1:00:00CEST-2:00:00,M3.5.0,M10.5.0"

Reported by Subu Rama.

2010-12-20

204

In the last line of the page, change "4.3BSD" to "4.2BSD".


Reported by Roger M. Levasseur.

2010-12-26

262

In Figure 14-4, the arrow pointing from Mount points to the windows icon should point instead to the C icon.


Reported by Dave Walker.

2010-11-28

276

In the first sentence of the bullet point at the bottom of the page, change:

For most file Linux systems

to:

For most Linux file systems

Reported by Subu Rama.

2011-01-04

280

Near the end of the small-font note at the bottom of the page, change:

(On all major contemporary UNIX implementations, symbolic links are implemented as i-nodes.)

to:

(On all major contemporary UNIX implementations, symbolic links are implemented as i-nodes. See Section 18.2 for further details.)

Explanation:

Adding this forward reference to the relevant section is helpful for the reader.

Reported by Justin Pryzby.

2010-12-28

307

In the last line of the paragraph for FS_NOTAIL_FL, change:

mount -notail

to:

mount -o notail

Reported by Justin Pryzby.

2010-12-28

324

In the first bullet point, about half way down the page, change:

Simply modifying the ACL_GROUP_OBJ and ACL_USER_OBJ entries

to:

Simply modifying the ACL_GROUP_OBJ and ACL_OTHER entries

Reported by Jorge Merlino.

2011-03-08

353

Below the prototype box for readdir() (about half way down the page), change:

Each call to readdir() reads the next directory from the directory stream

to:

Each call to readdir() reads the next directory entry from the directory stream

Reported by Subu Rama.

2011-01-12

354

In the second line, change:

stat() on the pathname

to:

lstat() (or stat(), if a symbolic link should be dereferenced) on the pathname

Suggested by a report by Justin Pryzby.

2010-12-28

354

At the end of the small-font note near the top of the page, add a sentence:

Although not specified in SUSv3, scandir() is provided on most UNIX implementations. SUSv4 added a specification for scandir().

Reported by Geoff Clare.

2010-12-31

360

Near the top of the page, change:

The fourth argument to func, ftwbuf, is pointer to a structure defined as follows:

to:

The fourth argument to func, ftwbuf, is a pointer to a structure defined as follows:

Reported by Subu Rama.

2011-01-12

378

Two changes associated with the description of inotify_rm_watch().

1. In the prototype box at the top of the page, change the line:

int inotify_rm_watch(int fd, uint32_t wd);

to:

int inotify_rm_watch(int fd, int wd);

2. In the paragraph below the prototype box, remove the sentence:

(The uint32_t data type is an unsigned 32-bit integer.)

Explanation:

The calling signature of this function changed in glibc 2.10.

2010-10-25

387

Change the opening sentence on this page:

This chapter and next two chapters discuss signals.

to:

This chapter and the next two chapters discuss signals.

2011-01-03

387

In the fourth bullet point, change:

the use of a process signal mask

to:

the use of the process signal mask

Explanation:

Each process has a single signal mask, so using the definite article "the" is better than the indefinite article "a".

2011-01-03

408

In the prototype box at the top of the page, change the line:

int sigandset(sigset_t *set, sigset_t *left, sigset_t *right);

to:

int sigandset(sigset_t *dest, sigset_t *left, sigset_t *right);

Reported by Matias Virsu.

2010-12-22

419

Change the text of Exercise 20-4:

Implement siginterrupt() using sigaction().

to:

Implement the siginterrupt() function described in Section 21.5 using sigaction().

Explanation:

This exercise should have been at the end of Chapter 21. However, as an exercise in the use of sigaction(), it works fine in Chapter 20 as well.

Reported by Subu Rama.

2011-01-14

431

In the shell session about one quarter of the way down the page, change the second line:

    $ ./sigmask_siglongjmp x

to:

    $ ./sigmask_siglongjmp

Explanation:

The "x" argument is superfluous (it was used in an earlier version of the program).

Reported by Subu Rama.

2011-01-14

439

Near the top of the page, in the paragraph under si_code, change:

as shown in Table 21-1.

to:

as shown in Table 21-2.

Reported by Subu Rama.

2011-01-14

468

In the prototype box, change:

Returns number of delivered signal on success

to:

Returns signal number on success

Explanation:

The new wording is a little more concise, and avoids the possible misreading "number of delivered signals".

2011-01-03

468

At the end of the second-to-last paragraph, change:

(see Exercise 22-3.)

to:

(see Exercise 22-3)

2011-01-04

471

In the prototype box near the top of the page, change:

Returns number of delivered signal on success

to:

Returns signal number on success

Explanation:

The new wording is a little more concise, and avoids the possible misreading "number of delivered signals".

2011-01-03

477

In the first line of Section 22.14, change:

This file contains

to:

Core dumps contain

Explanation:

This is a rewording that clarifies the text a little.

Reported by Justin Pryzby.

2010-12-28

480

In the paragraph in the middle of the page beginning "The default disposition", change:

we must to establish

to:

we must establish

Reported by Eric Arora.

2011-01-05

480

In the sixth line from the bottom of the page, change:

the timer is expires

to:

the timer expires

Reported by Eric Arora.

2011-01-05

483

This fix applies to a segment of code that spans the bottom of page 483 and the top of page 484. The change moves a block of code to a location lower down in the program (but otherwise leaves the lines of code unchanged). Change:

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = sigalrmHandler;
    if (sigaction(SIGALRM, &sa, NULL) == -1)
        errExit("sigaction");

    /* Exit after 3 signals, or on first signal if interval is 0 */

    maxSigs = (itv.it_interval.tv_sec == 0 &&
                itv.it_interval.tv_usec == 0) ? 1 : 3;

    displayTimes("START:", FALSE);

    /* Set timer from the command-line arguments */

    itv.it_value.tv_sec = (argc > 1) ? getLong(argv[1], 0, "secs") : 2;
    itv.it_value.tv_usec = (argc > 2) ? getLong(argv[2], 0, "usecs") : 0;
    itv.it_interval.tv_sec = (argc > 3) ? getLong(argv[3], 0, "int-secs") : 0;
    itv.it_interval.tv_usec = (argc > 4) ? getLong(argv[4], 0, "int-usecs") : 0;

    if (setitimer(ITIMER_REAL, &itv, 0) == -1)
        errExit("setitimer");

to:

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = sigalrmHandler;
    if (sigaction(SIGALRM, &sa, NULL) == -1)
        errExit("sigaction");

    /* Set timer from the command-line arguments */

    itv.it_value.tv_sec = (argc > 1) ? getLong(argv[1], 0, "secs") : 2;
    itv.it_value.tv_usec = (argc > 2) ? getLong(argv[2], 0, "usecs") : 0;
    itv.it_interval.tv_sec = (argc > 3) ? getLong(argv[3], 0, "int-secs") : 0;
    itv.it_interval.tv_usec = (argc > 4) ? getLong(argv[4], 0, "int-usecs") : 0;

    /* Exit after 3 signals, or on first signal if interval is 0 */

    maxSigs = (itv.it_interval.tv_sec == 0 &&
                itv.it_interval.tv_usec == 0) ? 1 : 3;

    displayTimes("START:", FALSE);
    if (setitimer(ITIMER_REAL, &itv, 0) == -1)
        errExit("setitimer"); 

Explanation:

The initialization of itv produces a value used in the initialization of maxSigs. Therefore the initializations must be in that order. (When I originally wrote the program the initializations were in the correct order, but during the production phase of the book I accidentally made a change that introduced the error.)

Reported by Subu Rama.

2011-01-17

538

In the second bullet point, half way down the page, change:

in an application that creates child processes, typically only one of the processes (most often the parent) should terminate via exit(), while the other processes should terminate via _exit().

to:

in an application that creates child processes that don't exec new programs, typically only one of the processes (most often the parent) should terminate via exit(), while the other processes should terminate via _exit().

Explanation:

This change clarifies the intended meaning of the explanation by adding an important detail.

Suggested by a conversation with Justin Pryzby.

2011-01-03

574

In the last line of the small-font note at the top of the page (starting "The Linux 2.2 kernel…"), change:

would show just the value echo.

to:

would show just the value necho.

Reported by Subu Rama.

2011-01-27

585

In the second-to-last line of the first bulleted paragraph on the page, change:

executable it if it is

to:

able to be executed if it is

Explanation:

There are two fixes here. One rewords a slightly cumbersome double use of the word executable, and the other removes a superfluous word, it.

Reported by Justin Pryzby.

2010-12-28

617

In the last line of the page, change:

case of a multithreaded processes

to:

case of a multithreaded process

Reported by Subu Rama.

2011-01-27

618

In the second paragraph of the page (starting "The threads in a process"), change the second sentence:

On a multiprocessor system, multiple threads can execute parallel.

to:

On a multiprocessor system, multiple threads can execute in parallel.

Reported by Eric Arora.

2011-01-05

618

In the second paragraph of the page (starting "The threads in a process"), change:

(Although it sometimes useful

to:

(Although it is sometimes useful

Reported by Subu Rama.

2011-01-27

621

In the code segment at the bottom of the page, change:

    pthread_t *thread;

to:

    pthread_t thread;

Reported by Subu Rama.

2011-02-17

624

In the sentence just above the box containing the prototype for pthread_equal(), change:

The pthread_equal() function allows us check

to:

The pthread_equal() function allows us to check

Reported by Jens Thoms Toerring.

2011-02-27

642

In the fourth line from the top of the page, change:

    s = pthread_mutex_init(mtx, &mtxAttr);

to:

    s = pthread_mutex_init(&mtx, &mtxAttr);

Reported by Gary Hu.

2011-01-05

668

About half way down the page, change:

    static __thread buf[MAX_ERROR_LEN];

to:

    static __thread char buf[MAX_ERROR_LEN];

Reported by Sangman Lee.

2011-03-09

702

In the middle of the page, change this entire paragraph:

If the pid and pgid arguments specify the same process (i.e., pgid is 0 or matches the process ID of the process specified by pid), then a new process group is created, and the specified process is made the leader of the new group (i.e., the process group ID of the process is made the same as its process ID). If the two arguments specify different values (i.e., pgid is not 0 and doesn't match the process ID of the process specified by pid), then setpgid() is being used to move a process between process groups.

to:

If setpgid() changes the process group ID of the target process (the process specified by pid) to be the same as its process ID, then the target process is made the leader of a new process group whose ID is the same as the process ID. If setpgid() changes the process group ID of the target process to a value different from its process ID, then the target process is moved to the existing process group specified by pgid. If setpgid() leaves the process group ID of the target process unchanged, then the call has no effect on the target process.

Explanation:

The original text was correct, but (1) was more complex than is needed to explain the behavior of setpgid(), and (2) didn't clearly explain the behavior if the process group ID was unchanged. The new text rectifies both of these problems.

Reported by Jonathan Nieder.

2011-02-16

708

In the second line of Section 34.5, change:

Within a session, only one process can be in the foreground

to:

Within a session, only one process group can be in the foreground

Reported by Justin Pryzby.

2010-12-28

730

Two changes in the first paragraph of Section 34.8.

1. Change:

(which is the same as the process group ID of the process group leader)

to:

(which is the same as the process ID of the process group leader)

2. Change:

(which is the same as the ID of the session leader)

to:

(which is the same as the process ID of the session leader)

The first of these changes was suggested by Justin Pryzby.

2011-01-03

740

In the first and third bullet points (i.e., two changes) in Section 35.2.2, change:

as described for the SCHED_FIFO policy above

to:

as described for the SCHED_RR policy above

Reported by Sangman Lee.

2011-03-11

760

In the second line of the small-font note about a third of the way down the page, change:

limits larger that

to:

limits larger than

Reported by Justin Pryzby.

2010-12-28

769

In the third line from the bottom of the page, change:

becomeDaeomon()

to:

becomeDaemon()

Reported by Justin Pryzby.

2010-12-28

780

In the code snippet at the top of the page, change the line:

   syslog(LOG_ERROR, "Bad argument: %s", argv[1]);

to:

   syslog(LOG_ERR, "Bad argument: %s", argv[1]);

Reported by Greg Olin.

2010-12-06

785

In the code segment at the bottom of the page, change two instances of:

    if (setuid(getuid() == -1)

to:

    if (setuid(getuid()) == -1)

Reported by Sangman Lee.

2011-03-16

786

In the fourth line of text, change:

is insufficient to change the set-user-ID identifier.

to:

is insufficient to change the saved set-user-ID.

Explanation:

The text as originally given was intended and the meaning is probably clear, but Przemysław commented on this wording and suggested the change, and I agree that it's better (and more consistent with the wordings I use elsewhere).

Reported by Przemysław Pawełczyk.

2010-11-28

786

Add a sentence to the end of the third paragraph:

SUSv3 doesn't specify this feature, but many other implementations behave the same way as Linux. SUSv4 does specify this feature.

Explanation:

SUSv4 added a specification for this behavior, and I noted the difference between SUSv3 and SUSv4 on page 176, but failed to do the same on this page.

Reported by Geoff Clare.

2010-12-07

822

In the second line of the second bullet point (in the middle of the page), change:

then getutxent() finds the next

to:

then getutxid() finds the next

Reported by Sangman Lee.

2011-03-16

849

Change the shell command in line 9:

    # ls -l libdemo* | awk '{print $1, $$9, $10, $11}'

to:

    # ls -l libdemo* | awk '{print $1, $9, $10, $11}'

Reported by Zerksis Umrigar.

2010-12-25

895

In the seventh line from the bottom of the page, change:

The parent then closes the read end of the pipe (10)

to:

The parent then closes the write end of the pipe (10)

Reported by Sangman Lee.

2011-03-16

1017

In the first line of the small-font note at the bottom of the page, change:

and one is that is

to:

and one that is

Reported by Justin Pryzby.

2010-12-28

1083

In the second of the three bullet points in the middle of the page, change:

timer notifications

to:

message notifications

Reported by Subu Rama.

2011-02-17

1102

In the second of the three bullet points in the middle of the page, change:

    /* Initialize a thread-shared mutex with the value 1 */

to:

    /* Initialize a semaphore with the value 1 */

Reported by Subu Rama.

2011-02-17

1119

In the third line from the bottom of the page, change:

the value into operation

to:

the value LOCK_NB into operation

Reported by Justin Pryzby.

2010-12-28

1176

In the first paragraph, change the entire sentences:

The remaining bytes of the sun_path field then define the abstract name for the socket. These bytes are interpreted in their entirety, rather than as a null-terminated string.

to:

The name of the abstract socket is then defined by the remaining bytes (including any null bytes) in sun_path up to the length defined for the size of the address structure (i.e., addrlen – sizeof(sa_family_t)).

Explanation:

This change fixes a factual mistake (found as a consequence of a man-pages bug report by Lennart Poettering).

2010-10-25

1176

Two changes to the example code in Listing 57-8 (sockets/us_abstract_bind.c).

1. Change the lines:

   strncpy(&addr.sun_path[1], "xyz", sizeof(addr.sun_path) - 2);
   /* Abstract name is "xyz" followed by null bytes */

to:

   str = "xyz";         /* Abstract name is "\0xyz" */
   strncpy(&addr.sun_path[1], str, strlen(str));

2. Change the line:

           sizeof(struct sockaddr_un)) == -1)

to:

           sizeof(sa_family_t) + strlen(str) + 1) == -1)

Explanation:

The program as originally provided was correct (i.e., the resulting abstract socket name is valid), but changing the code better reflects the spirit of the changed explanatory text (see the previous erratum).

2010-10-25

1192

In the eighth line of the paragraph headed Flow control, change:

which allows unacknowledged segments containing a total of up N

to:

which allows unacknowledged segments containing a total of up to N

Reported by Subu Rama.

2011-02-17

1218

In the last sentence of the paragraph somewhat more than half way down the page starting "The resulting host and service names…", change:

define one of the feature text macros

to:

define one of the feature test macros

Reported by Subu Rama.

2011-02-17

1247

In the fifth and sixth lines of the third paragraph (beginning "One of the simplest approaches…"), change:

Successive requests to the DNS server to resolve the domain name return these IP addresses in a different order, in a round-robin fashion.

to:

Successive requests to the DNS server to resolve the domain name return these IP addresses in round-robin order.

Explanation:

This rewording is simpler and clearer.

2011-01-06

1247

In the fourth paragraph (beginning "Round-robin DNS has the advantage…"), change the second and third sentences:

However, it does present some problems. One of these is the caching performed by remote DNS servers, which means that future requests from clients on a particular host (or set of hosts) bypass the round-robin DNS server and are always handled by the same server.

to:

However, it does have some shortcomings. A DNS server performing iterative resolution may cache its results (see Section 59.8), with the result that future queries on the domain name return the same IP address, instead of the round-robin sequence generated by the authoritative DNS server.

Explanation:

This rewording clarifies the intended meaning a little and provides a helpful cross reference.

Suggested from a conversation with Justin Pryzby.

2010-12-28

1247

In the second and third lines of Section 60.5, change:

a large number server processes

to:

a large number of server processes

Reported by Justin Pryzby.

2010-12-28

1260

About two thirds of the way down the page, change the paragraph:

Of the above flags, only MSG_OOB is specified by SUSv3. MSG_DONTWAIT appears on a few other UNIX implementations, and MSG_NOSIGNAL and MSG_MORE are Linux-specific.

to:

Of the above flags, only MSG_OOB is specified by SUSv3. SUSv4 adds a specification for MSG_NOSIGNAL. MSG_DONTWAIT is not standardized, but appears on a few other UNIX implementations. MSG_MORE is Linux-specific.

Explanation:

I overlooked the fact that SUSv4 added a specification for MSG_NOSIGNAL.

2010-12-31

1262

In the example code at the bottom of the page, change the two lines that read:

    setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, sizeof(optval));

to:

    setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval));

Reported by Przemysław Pawełczyk.

2010-11-28

1276

In the fourth line of Section 61.8, change:

all kinds of TCP/IP packets

to:

all kinds of network packets

Explanation:

Using the term "TCP/IP" in this context is slightly confusing; better to use the more generic term "network".

Reported by Justin Pryzby.

2010-12-28

1327

Change the last sentence on the page:

POSIX AIO is described in [Gallmeister, 1995] and [Robbins & Robbins, 2003].

to:

POSIX AIO is described in [Gallmeister, 1995], [Robbins & Robbins, 2003], and the aio(7) manual page.

Explanation:

After TLPI went to press, I wrote manual pages for the POSIX AIO API.

2011-01-06

1356

Below the prototype box for epoll_create(), change:

(Since Linux 2.6.8, the size argument is ignored, because…

to:

(Since Linux 2.6.8, the size argument must be greater than zero but is otherwise ignored, because…

Explanation:

This fix was found as a consequence of a man-pages bug report by Joern Heissler.

2010-12-03

1358

Change the second-to-last line of Listing 63-4:

    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev) == -1)

to:

    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)

Reported by Sangman Lee.

2011-03-07

1406

In the second paragraph of the small-font note two thirds of the way down the page (beginning "SUSv3 specifies..."), change:

that consist of one of more

to:

that consist of one or more

Reported by Subu Rama.

2011-01-04

1503

In the entry for "uint32_t data type", remove the page reference "378".


Explanation:

This change is required because of the changes on page 378.

2010-10-25


(C) 2011 Michael Kerrisk,   mtk AT man7.org