Queued errata for NSP for The Linux Programming Interface

This page lists the errata for The Linux Programming Interface that have not yet been applied in applied to any print run. The table below includes production notes for the publisher. (If you want to see a complete list of all errata for the book, see the errata page.)

Note to editor: if you make changes that deviate in any way from what I've written below, please let me know of the changes, so that I can check them, and adjust the TLPI errata page appropriately. Also, please don't make any changes that would result in page reflow; if a change can't be made as I request in an erratum, let me know and I'll come up with an alternative.

Further note to editor: please send me the updated pages for review before sending them to the printer.

Last updated: 2026-05-25; last error report: 2026-05-25

Total errata to apply: 25

Page Fix Reported
29

At the start of the second paragraph under the heading "File ownership and permissions", change:

For the purpose of accessing a file,

to:

For the purpose of accessing a regular file,

Production notes:

Is there sufficient vertical space on the page to make this change?

2024-12-24

228

Near the bottom of the page (in Listing 12-1, sysinfo/procfs_pidmax.c), change:

        if (write(fd, argv[1], strlen(argv[1])) != strlen(argv[1]))
            fatal("write() failed");

to:

        if (write(fd, argv[1], strlen(argv[1])) != (ssize_t) strlen(argv[1]))
            fatal("write() failed");

2025-05-04

269

About a quarter of the way down this page (in Listing 14-1, filesys/t_mount.c), change:

        case 'f':
            for (j = 0; j < strlen(optarg); j++) {

to:

        case 'f':
            for (j = 0; j < (int) strlen(optarg); j++) {

2025-05-04

293

Towards the bottom of this page (in Listing 15-2, files/t_chown.c), change:

        if (uid == -1)
            fatal("No such user (%s)", argv[1]);

to:

        if ((uid_t) uid == -1)
            fatal("No such user (%s)", argv[1]);

2025-05-04

294

In the third line on this page (in Listing 15-2, files/t_chown.c), change:

        if (gid == -1)
            fatal("No such group (%s)", argv[2]);

to:

        if (gid == (gid_t) -1)
            fatal("No such group (%s)", argv[2]);

to:

2025-05-04

337

In Exercise 17.10, change:

The program should take two command-line arguments. The first argument is either of the letters u or g, indicating whether the second argument identifies a user or group.

to:

In addition to the pathname of a file, the program should take two further command-line arguments. The first of these arguments is either of the letters u or g, indicating whether the following argument identifies a user or group.

2024-12-24

469

There are two sets of related changes to make on this page.

In the second shell log on the page, change:

$ ./t_sigwaitinfo: finished delay
got signal: 42
    si_signo=42, si_code=-1 (SI_QUEUE), si_value=200
    si_pid=3840, si_uid=1000
got signal: 43
    si_signo=43, si_code=-1 (SI_QUEUE), si_value=100
    si_pid=3839, si_uid=1000

to:

$ ./t_sigwaitinfo: finished delay
got signal: 42 (Real-time signal 8)
    si_signo=42, si_code=-1 (SI_QUEUE), si_value=200
    si_pid=3840, si_uid=1000
got signal: 43 (Real-time signal 9)
    si_signo=43, si_code=-1 (SI_QUEUE), si_value=100
    si_pid=3839, si_uid=1000

In the last shell log on the page, change:

$ kill -USR1 3837                               Shell sends SIGUSR1 using kill()
$ got signal: 10                                Delivery of SIGUSR1

to:

$ kill -USR1 3837                               Shell sends SIGUSR1 using kill()
$ got signal: 10 (User defined signal 1)        Delivery of SIGUSR1

2025-02-09

510

Towards the bottom of this page (in Listing 23-8, timers/demo_timerfd.c), change:

    int maxExp, fd, secs, nanosecs;
    uint64_t numExp, totalExp;

to:

    int fd, secs, nanosecs;
    uint64_t numExp, totalExp, maxExp;

2025-05-04

759

About a quarter of the way down the page (in Listing 36-3, procres/rlimit_nproc.c), change:

    rl.rlim_cur = (argv[1][0] == 'i') ? RLIM_INFINITY :
                                getInt(argv[1], 0, "soft-limit");
    rl.rlim_max = (argc == 2) ? rl.rlim_cur :
                (argv[2][0] == 'i') ? RLIM_INFINITY :
                                getInt(argv[2], 0, "hard-limit");

to:

    rl.rlim_cur = (argv[1][0] == 'i') ? RLIM_INFINITY :
                                (rlim_t) getInt(argv[1], 0, "soft-limit");
    rl.rlim_max = (argc == 2) ? rl.rlim_cur :
                (argv[2][0] == 'i') ? RLIM_INFINITY :
                                (rlim_t) getInt(argv[2], 0, "hard-limit");

2025-05-04

831

In the middle of this page (in Listing 40-4, loginacct/view_lastlog.c), change:

        uid = userIdFromName(argv[j]);
        if (uid == -1) {
            printf("No such user: %s\n", argv[j]);
            continue;
         }

to:

        uid = userIdFromName(argv[j]);
        if (uid == (uid_t) -1) {
            printf("No such user: %s\n", argv[j]);
            continue;
         }

2025-05-04

897

Change the first line of this page (in Listing 44-3, pipes/pipe_sync.c):

        if (write(pfd[1], argv[1], strlen(argv[1])) != strlen(argv[1]))
            fatal("parent - partial/failed write");

to:

        if (write(pfd[1], argv[1], strlen(argv[1])) != 
		(ssize_t) strlen(argv[1]))
            fatal("parent - partial/failed write");

2025-05-04

973

Change the last line on this page (in Listing 47-3, svsem/svsem_mon.c):

    int semid, j;

to:

    int semid;
    unsigned int j;

2025-05-04

975

About a quarter of the way down the page (in Listing 47-4, svsem/svsem_setall.c), change:

    if (ds.sem_nsems != argc - 2)
        cmdLineErr("Set contains %ld semaphores, but %d values were supplied\n",
                (long) ds.sem_nsems, argc - 2);

to:

    if ((int) ds.sem_nsems != argc - 2)
        cmdLineErr("Set contains %ld semaphores, but %d values were supplied\n",
                (long) ds.sem_nsems, argc - 2);

2025-05-04

1173

About three quarters of the way down the page (in Listing 57-7, sockets/ud_ucase_cl.c), change:

        if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
                sizeof(struct sockaddr_un)) != msgLen)
            fatal("sendto");

to:

        if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
                sizeof(struct sockaddr_un)) != (ssize_t) msgLen)
            fatal("sendto");

2025-05-04

1209

A bit more than half way down the page (in Listing 59-4, sockets/i6d_ucase_cl.c), change:

        if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
                    sizeof(struct sockaddr_in6)) != msgLen)
            fatal("sendto");

to:

        if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
                    sizeof(struct sockaddr_in6)) != (ssize_t) msgLen)
            fatal("sendto");

2025-05-04

1222

In the second-to-last line of this page (in Listing 59-6, sockets/is_seqnum_sv.c), change:

        if (write(cfd, seqNumStr, strlen(seqNumStr)) != strlen(seqNumStr))
            fprintf(stderr, "Error on write");

to:

        if (write(cfd, seqNumStr, strlen(seqNumStr)) != 
                (ssize_t) strlen(seqNumStr))
            fprintf(stderr, "Error on write");

Production notes:

If there is insufficient vertical space on the page to make this change, let me know, and I'll make an additional change to create some space.

2025-05-04

1224

At the bottom of this page (in Listing 59-7, sockets/is_seqnum_cl.c), change:

        if (connect(cfd, rp->ai_addr, rp->ai_addrlen) != -1)
            break;                              /* Success */

to:

        if (connect(cfd, rp->ai_addr, rp->ai_addrlen) == 0)
            break;                              /* Success */

2025-04-12

1225

About a quarter of the way down the page (in Listing 59-7, sockets/is_seqnum_cl.c), change:

    if (write(cfd, reqLenStr, strlen(reqLenStr)) !=  strlen(reqLenStr))
        fatal("Partial/failed write (reqLenStr)");

to:

    if (write(cfd, reqLenStr, strlen(reqLenStr)) != 
            (ssize_t) strlen(reqLenStr))
        fatal("Partial/failed write (reqLenStr)");

2025-05-04

1228

Toward the bottom of this page (in Listing 59-9, sockets/inet_sockets.c), change:

        if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
            break;                      /* Success */

to:

        if (connect(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
            break;                      /* Success */

2025-04-12

1242

About halfway down this page (in Listing 60-3, sockets/id_echo_cl.c), change:

        if (write(sfd, argv[j], len) != len)
            fatal("partial/failed write");

to:

        if (write(sfd, argv[j], len) != (ssize_t) len)
            fatal("partial/failed write");

2025-05-04

1308

In the first sentence on this page, change:

The precise operation and interaction of the MIN and TIME parameters depends on whether they each have nonzero values.

to:

The precise operation and interaction of the MIN and TIME parameters depend on whether they each have nonzero values.

2025-09-10

1308

In the second sentence of the paragraph following the heading MIN > 0, TIME > 0 (read with interbyte timeout), change:

The read() returns when either the lesser of MIN bytes and the number of bytes requested has been read, or when the time between receiving successive bytes exceeds TIME tenths of a second.

to:

The read() returns either after reading the smaller of MIN bytes and the number of bytes requested, or when the interval between receiving successive bytes exceeds TIME tenths of a second.

2025-09-10

1316

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

XYZ             Type XYZ and Control-Z

to:

xyz             Type XYZ and Control-Z

2025-09-10

1318

In the second sentence of the small-font note somewhat more than half-way down the page, change:

For file I/O, flushing means forcing the output to be transferred either user-space memory to the buffer cache...

to:

For file I/O, flushing means forcing the output to be transferred either from user-space memory to the buffer cache...

2025-09-10

1430

In the solution for Exercise 27-1, change:

The execvp() function

to:

The execlp() function

2025-02-04