|
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 toward 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 went 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 of the page,
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
(i.e., prior to performing the read…
to:
synchronized I/O data integrity completion
(i.e., prior to performing the read…
In the seventh and eighth lines,
change:
synchronized I/O file integrity
(i.e., prior to performing the read…
to:
synchronized I/O file integrity completion
(i.e., prior to performing the read…
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 beginning
"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):
-
–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.
-
–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).
-
–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.
Because it is a common misunderstanding,
it's perhaps worth pointing out that it is not generally necessary
to employ the
volatile
qualifier on global variables in multithreaded programs.
For further information on this point, see, for example,
various Stack Overflow questions:
When to use volatile with multi threading?,
Should ALL global variables be volatile-qualified?,
and
Is 'volatile' needed in this multi-threaded C++ code?.
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 toward 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");
}
2012-10-15 follow-up: Ideally, instead of using
int
in the modified code, it would have been preferable to use
uintptr_t:
uintptr_t idx = (uintptr_t) arg;
The problem with using
int
is that the cast generates a compiler warning
("cast from pointer to integer of different size")
when compiling on 64-bit systems.
However, using
uintptr_t
would have required more substantial changes to the code:
an adjustment to the format specifier used in the
printf()
call in
threadFunc(),
and a corresponding
change to the declaration of
idx
in
main().
But, there's not much point in trying to make a perfect solution here,
since the correct fix is really something like the longer patch above.
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 toward 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
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
(daemons/daemon_SIGHUP.c),
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
|
In the second bullet point in Section 39.10,
change:
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:
The
remaining
arguments
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.gz
file is itself only available if the kernel was configured with the
CONFIG_IKCONFIG
and
CONFIG_IKCONFIG_PROC
configuration options enabled.
Explanation:
In print run 7, a fix was made to remedy a minor error that
occurred when applying this erratum:
/proc/config.z was changed to
/proc/config.gz.
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
https://www.linux.co.cr/free-unix-os/review/acrobat/950517.pdf,
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
|