http://invisible-island.net/
Copyright © 2005-2013,2014 by Thomas E. Dickey


Abstract

The book Solaris Systems Programming by Rich Teer borrows ideas, organization and content from Advanced Programming in the UNIX Environment by W. Richard Stevens. However that fact is not reflected in its bibliography. This summarizes my own observations as well as comments by others on the topic.

The works discussed here are:

Advanced Programming in the UNIX Environment. W. Richard Stevens. 1992. ISBN: 0-201-56317-7

and

Solaris Systems Programming. Rich Teer. 2005. ISBN: 0-201-75039-2

Introduction

To explain why/how I noticed this issue: there was a long newsgroup argument which I had been following for the past month (December 2004). There was a comment by one of the posters which said in rather strong terms that the latter book was required reading. While I may not agree with that, I thought it best to study the book to defend my opinion. I had noticed it in a nearby bookstore, but (on first glance) it was not something I needed (Stevens book is very good).

Going back to the book, I went to the section that I had looked at before; which discusses a section where I'm an expert (see my webpage). Two things were odd about the section: the phrasing of the final paragraph did not mesh well with the rest of the section. But more obvious was citing Goodheart, who's been out of print several years. Using an old reference like that for a new book – and then commenting that the whole topic is becoming obsolete seemed inconsistent.

I went to the bibliography to check Goodheart – 1991 (page 1154 of Teer). Reading down the bibliography, I noticed on page 1156 that Stevens was cited. But there is something odd about that citation. It mentions the three editions of Stevens UNIX Network Programming. I do not have that book; I am familiar with the material covered, and it was odd that Teer would cite three editions of that when it is not a focus of Teer's book. But Stevens Advanced Programming in the UNIX Environment is (except for the focus on Solaris) much the same type of book. Teer does not mention this book in his bibliography.

Next I looked at the preface and introduction. Teer mentions Stevens in one line (bottom of page xxxv), for inspiration. The introduction does not give any credits; those are all in the preface.

However, I was in the bookstore. Teer's book was on the top shelf; there was a copy of Stevens on the preceding bottom shelf. I picked that up, and opened it to the table of contents. To a first glance, it was the same table of contents as Teer's: there are differences, but more similarities than difference – most of the section titles in Teer are the same, or a word different from Stevens. The chapter ordering is mostly the same, making the similarity more striking.

I went to the section in Stevens which I had looked at in Teer. Starting at the bottom of page 504 (Teer), and comparing with section 11.13 in Stevens (top of page 360), I found the same ideas, much of the same wording transferred from Stevens to Teer.

Seeing the two sections, and the table of contents, I selected another section (don't recall which), and noticing that they also were similar, decided to buy Teer's book so that I could discuss it further.

On the newsgroup, I asked:

        Speaking of which - since you're determined to force it upon everyone's
        attention:

        Since that borrows (more than a small amount) upon

                "Advanced Programming in the UNIX Environment",
                W. Richard Stevens, 1993

        why does its bibliography only mention Steven's 3 editions
        of "Unix Network Programming"?

His response (in part – both quotes via google, though I have copies saved via my newsreader):

        My book doesn't "borrow" from APUE, certainly not to the extent
        that you seem to be implying.  Both my book and APUE cover a
        similar subject (one might argue that SSP is in fact a superset
        of APUE), and I admire Rich Stevens' writing style--a style that
        in the sincerest form of flattery, I've attempted to immitate
        (I'll take your words as a sign that I was somewhat successful
        in that attempt).  It shouldn't be too surprising, then, that
        the two books appear to be at least superficially similar.

        > why does its bibliography only mention Steven's 3 editions of
        > "Unix Network Programming"?

        Because my book doesn't make reference to Rich Stevens' other
        books.  If it did, a suitable reference would be in the
        bibliography.

That was clear enough. But my dictionary says

plagiarism act of stealing and using as one's own the ideas or the expression of the ideas of another.

I started comparing the two books side-by-side, and in a half hour found that most of the sections I compared had borrowed (rewording, but retaining most of the original). Not all sections in Teer's book borrow from Stevens, but my initial impression (having spent a few hours on this) was that if Stevens had something to say that was relevant to Teer's book, it can be found paraphrased there. There are also a number of instances where it is not paraphrased, but used without change.

Examples

Chapter 12 - Terminal I/O

Here is the example I noticed first. It is from Teer (bottom of page 504 to middle of 505). Close study indicates several problems with grammar and word choice. I have emphasized a few of the ones that I see. Compare to Stevens (second paragraph of page 360, to the end of section 11.13):


Compare Stevens p360 to Teer p504
Stevens Teer

The routines that support the termcap file were then extracted from the vi editor and placed into a separate curses library. Lots of features were added to make this library usable for any program that wanted to manipulate the screen.

The functions that vi used to handle the termcap file were removed and placed into a separate curses library. Many features were added to this library to make it useful for any program that wanted to perform device-independent screen manipulation.

The termcap scheme was not perfect. As more and more terminals were added to the data file, it took longer to scan the file looking for a specific terminal. The data file also used two-character names to identify the different terminal attributes. These deficiencies led to development of the terminfo scheme and its associated curses library. The terminal descriptions in terminfo are basically compiled versions of a textual description and can be located faster at run time. terminfo appeared with SVR4 and has been in all System V releases since then.

One of the problems with the termcap scheme is that was implemented as a plain text file. This file had to be searched linearly when a terminal's capabilities were being looked up. Also, termcap uses two character names to identify a terminal's characteristics. To work around these deficiencies, the terminfo scheme and its associated curses library were developed. The terminfo facility uses a compiled version of the textual terminal descriptions. This makes searching them much faster.

A description of terminfo and the curses library is provided by Goodheart [1991]. Strang, Mui and O'Reilly [1991] provide a description of termcap and terminfo.

A detailed discussion of curses programming is beyond the scope of this text. Interested readers are referred to [Goodheart 1991] for a description of terminfo and the curses library, or [Strang 1986], which describes the original Berkeley version of the curses library. For a description of the termcap and terminfo files, see [Strang, Mui, and O'Reilly 1991].

Neither termcap nor terminfo, by itself, addresses the problems we've been looking at in this chapter -- changing the terminal's mode, changing one of the terminal special characters, handling the window size, and so on. What they do provide is a way to perform typical operations (clear the screen, move the cursor) on a wide variety of terminals. On the other hand, curses does help with some of the details that we've addressed in this chapter. Functions are provided by curses to set raw mode, set cbreak mode, turn echo on and off, and the like. But curses is designed for character-based dumb terminals, while the trend today is toward pixel-based graphics terminals.

Neither termcap nor terminfo by themselves address the problems we've discussed in this chapter (i.e., changing the terminal's mode, changing the special characters, handling the screen size, etc.). But they do provide a way to perform typical operations, like clearing the screen or moving the cursor, on a wide variety of terminals. The curses library does, however, provide some functions that help us handle some of the details we've talked about in this chapter, like setting raw or cbreak mode, enabling or disabling echoing, and so on.

Given the wide use of GUI-based workstations these days, the character-oriented curses style of screen programming is becoming deprecated in favour of graphical applications using the X Window System or written in Java.


CHAPTER BY CHAPTER

One might argue that was coincidence, an isolated example. To deal with that, it is necessary to review the whole book. Here are (briefly) the findings from that review. But it is a long list, thus relegated to an appendix.

Comparing Figures

At first glance, perhaps different. But look again. The layout of Teer's figure is the same as Stevens'. Some information (Solaris-specific) is added, but most of the difference lies in the fact that Teer's copy is larger.

Compare Stevens figure 6.4 to Teer figure 6.1
Stevens Teer
Stevens Figure 6.4 Teer Figure 6.1

To avoid breaking up the flow of discussion, other figures can be found here.

Good Reviews

Searching for "Solaris Systems Programming" with google, the first hit (other than Rich Teer's webpage) is the advertisement on amazon.com. The page lists five (5) reviews. Four (4) are favourable. But reconsider them:

The remaining review is unfavorable. In short, it notes that the book is of mediocre quality. Talking to Gunnar Ritter about this, I find that he has much more to say about that aspect than I am likely to. Rather than dissect Rich Teer's mistakes in rewording Richard Stevens' text, I have included Gunnar Ritter's comments as an appendix.

Pre-Publication Review

Several technical reviewers are cited in the acknowledgements. One may ask why none of them brought up this problem. Some of my associates have offered these possible explanations:

The preface notes that one person actually read the whole manuscript.

Informal Review

See this newsgroup thread for a discussion of the borrowing from Steven's book. Some of the newsgroup readers have both books, and their remarks are insightful:

As noted by Henry Townsend, Rich Teer more than once referred to the book that he was working on as an updated version of Stevens' book. Google finds 20 references; a few are quoted here to show that they are consistent:

Analysis

Teer states repeatedly that he is an admirer of Richard Stevens. Oddly enough, google finds little newsgroup discussion where both Stevens and Teer participated, so that one may gauge their interaction. (A reader of this page found one instance, where Teer does comment about his plans, but it is only Teer adding to one of Stevens's remarks). Since Teer is said to have been a technical reviewer for Stevens' network programming book, presumably there was private correspondence. But that would be irrelevant to this analysis.

The comments which google finds suggest that Rich Teer started his book in late 2000, more than a year after Stevens died. According to Teer's resume, he was working on the book from early 2001 to the end of summer 2004 (he says three and a half years).

The one line in the acknowledgements crediting Stevens reads

Special thanks to W. Richard Stevens for his inspiration and encouragement when this book was just a twinkle in the author's eyes.

At first glance, that might be taken to imply that Teer had discussed his plans for a book with Stevens. However the available evidence suggests that (aside from intentions) the real planning of the book came later.

The book is laid out as if Teer used Stevens' book as an outline. Consistent with that, Teer paraphrased Stevens introductory discussion on several topics. That much warrants an entry in the bibliography.

But Teer also imitates/copies figures from Stevens' book, imitates/adapts/copies programs from Stevens book. Townsend tries to argue that copying the programs is fair use, but see this newsgroup thread, in particular:

I was thinking about the same thing in May 1998 so I asked Mr. Stevens 
about the copying policy. The question was about sources in UNIX 
network programming -- 2nd edition and especially about the writen 
function in Figure 3.15, page 78

and

The reply from the editor was: 

  You have Prentice Hall's permission to use this code snippet as long 
  as you cite your source, do not use this for commercial purposes, 
  and have read and understand the disclaimer in the book. The 
  software is provided on as "as is" basis and without warranty of any 
  kind, expressed or implied, including without limitation any 
  warranty of merchantability or fitness for a particular purpose. In 
  no event shall the author or Prentice Hall be liable for any 
  damanges of any kind as is stated in the disclaimer.

Adapting the programs for use in another book is commercial use, of course.
Adapting them without credit is plagiarism.

Teer states more than once that he is imitating Stevens style. That is nonsense. Teer is imitating the organization and content of Stevens book.

Recommendations

What should be done?

That depends on the context, of course. Beyond the dictionary definition, plagiarism is a topic that is interesting to many people.

For an academic environment, here is a good overview of the topic. Other online references such as this and this are simpler, aimed at persuading students to not infringe. Much attention is given to copying of content from online sources. But:

For a professional, similar constraints apply. However see this, for the applicable text:

4. Uncredited improper paraphrasing of pages or paragraphs (by changing a few words or phrases or rearranging the original sentence order). Calls for a written apology to avoid suspension of publication privileges and a possible violation notice in the later articles bibliographic record.

It is not clear if that applies to Teer either, though several of his newsgroup postings use the term "professional". But this page for the publisher certainly does.

To whom should Teer apologize? Apparently the publisher (who acts in two roles), and Stevens' family (who would be getting royalties from Stevens books) are the injured parties. People who buy the books also have been defrauded.

Specifically:

Credits

Gunnar Ritter provided much detail to substantiate my impression that the book is not well researched. He has also provided useful feedback on this webpage.

Ian Clarke served as a second opinion, making the same arguments and observations that I would.

Several of my associates have offered opinions on this topic (which generally conform to mine). I have noted those as supporting discussion. Since their comments were made via private email and because the comments are short, I have not listed their names.

Appendix A: Other Examples

As indicated in Appendix C, there are many examples from which to choose. Showing all of them would be excessive (for several reasons: time, space, etc.). This is a review, so the selection is small.

Section 1.8 User Identification

Not coincidentally, this is the same section number in both books. Later sections differ by chapter number; borrowed portions still tend to have the same section number within chapters.


Compare Stevens p16 to Teer p22
Stevens Teer

The user ID from our entry in the password file is a numeric value that identifies us to the system. This user ID is assigned by the system administrator when our login name is assigned and we cannot change it. It is normally assigned so that every user has a unique user ID. We'll see how the user ID is utilized by the kernel to check if we have the appropriate permissions to perform certain operations.

We call the user whose user ID is 0 either root or the superuser. The entry in the password file normally has a login name of root and we refer to the special privileges of this user as superuser privileges. As we'll see in Chapter 4, if a process has superuser privileges, most file permission checks are bypassed. Some operating system functions are restricted to only the superuser. The superuser has free reign over the system.

A user ID (UID) is a number associated with our user name that identifies us to the operating system. This number is usually unique for each user, but is sometimes overloaded so that the same user ID is associated with several user names. Our user ID and user name are usually assigned to us by the system administrator. Several user names and user IDs are reserved by Solaris (they are already in /etc/passwd when we install the OS); the most important of these is the user root, which has a user ID of 0. Processes running with a user ID of 0 bypass most file system permissions checks and a number of privileged operations are restricted to these processes. Because of its elevated privilege status, the root user is also known as the superuser.

Section 5.2 File Streams, Data Types and Constants

Same concepts, same order of presentation. Teer does move one sentence to a different paragraph.


Compare Stevens p121 to Teer p159
Stevens Teer

In Chapter 3 all the I/O routines centered around file descriptors. When a file is opened a file descriptor is returned, and that descriptor is then used for all subsequent I/O operations. With the standard I/O library the discussion centers around streams. (Do not confuse the standard I/O term stream with the STREAMS I/O system that is part of System V.) When we open or create a file with the standard I/O library we say that we have associated a stream with the file.

The functions we described in Chapter 4 operate on file descriptors. A successful open of a file returns a file descriptor, which is then used in all subsequent operations on that file. The functions we describe in this chapter operate on file streams. We should be careful not to confuse the term file stream with the STREAMS I/O subsystem (details on STREAMS programming can be found in [Rago 1993]).

When we open a stream, the standard I/O function fopen returns a pointer to a FILE object. This object is normally a structure that contains all the information required by the standard I/O library to manage the stream: the file descriptor used for actual I/O, a pointer to a buffer for the stream, the size of the buffer, a count of the number of characters currently in the buffer, an error flag and the like.

When we open a file using functions provided by the standard I/O library, we say that we have associated a stream with that file. A successful open returns a pointer to a FILE object. A FILE object is a structure that contains all the information required to manage the stream, including the next character in the buffer, the number of characters available in the buffer, a pointer to the buffer, various flags (e.g., end of file and error), and the file descriptor used for the actual I/O.

Application software should never need to examine a FILE object. To reference the stream we pass its FILE pointer as an argument to each standard I/O function. Throughout this text we'll refer to a pointer to a FILE object, the type FILE* as a file pointer.

The member of the FILE object are private to the implementation and may change from one release of Solaris to another. Hence, FILE objects should be treated as opaque objects, that is, applications should not directly manipulate the structure members. Instead, we pass a pointer to a FILE object (i.e., a FILE*) to one of the functions in the standard I/O library; in this text we refer to the object we pass as a file pointer.

Chapter 10 Exercises

At first, I did not pay much attention to the exercises. But Teer uses Stevens' material in that area as well.


Compare Stevens p118 to Teer p416
Stevens Teer

4.3 What happens if the file mode creation mask is set to 777 (octal)? Verify the results using your shell's umask command.

10.2 What happens if you set your file creation mask to 0777? Use the umask command to verify the results.

4.5 Run Program 4.3 after creating the files foo and bar. What happens?

10.3 What happens if we rerun Program 10.4 after creating the files foo and bar?

4.6 In Section 4.12, we said that a file size of 0 is valid for a regular file. We also said that the st_size field is defined for directories and symbolic links. Should we ever see a file size of 0 for a directory or a symbolic link?

10.4 In Section 10.12, we stated that the st_size member is valid for regular files, symbolic links, and directories; we also said that regular files can have a length of 0. Is it possible for a directory or symbolic link to ever have a length of 0?

4.7 Write a utility like cp(1) that copies a file containing holes, without writing the bytes of 0 to the output file.

10.5 Write a version of cp that is sparse-file aware (i.e., 0 bytes should not be written to the output file).

4.14 How can you set only one of the two time values with the utime function?

10.6 How can we use the utime function to modify only one of the two time values it sets?

Appendix B: Other Figures

As indicated in Appendix C, there are many examples from which to choose. Here are a few which are representative of the whole.

The main difference between these two is that Teer added the superblock which Stevens mentions in the paragraph preceding figure 4.8. Labeling, layout (including the choice of crossing arrows) are copied.

Compare Stevens figure 4.8 to Teer figure 10.7
Stevens Teer
Stevens Figure 4.8 Teer Figure 10.7

The same comments apply here.

Compare Stevens figure 4.9 to Teer figure 10.8
Stevens Teer
Stevens Figure 4.9 Teer Figure 10.8

For this pair, there are minor changes in labeling, but they are still the same picture.

Compare Stevens figure 11.5 to Teer figure 12.5
Stevens Teer
Stevens Figure 11.5 Teer Figure 12.5

Tables are treated as figures in both books. So there is no need for a separate section on tables. Here is an example.

Compare Stevens figure 4.13 to Teer figure 10.10
Stevens Teer
Stevens Figure 4.13 Teer Figure 10.10

Appendix C: Chapter by Chapter

The chapter numbers on the left margin are from Teer. Most of the chapter and section titles that correspond to Stevens use the same words for the titles.

Not all of the information from Stevens is used in Teer's paraphrasing. Generally any comments regarding older systems are discarded, e.g., BSD 4.3, and where Solaris does the same as SVR4, the text is reworded to discard the reference to SVR4, etc., and describe Solaris' behavior.

Sections noted as "ok" are those where Teer has provided enough material from other sources that there is no noticeable relationship to Stevens.


1 – Introduction

Start by comparing Teer 1.3 and Stevens 1.3. At this point, they have parallel structure, but little paraphrasing. That changes. There is some, e.g., bottom of Teer p7 matches 3rd paragraph of "Filename" on Stevens p3.

Teer program 1.1 is Stevens program 1.1 (some minor changes, but at first glance a copy). The discussion for program 1.1 paraphrases Stevens, adds some new material, but is based on Stevens.

Stevens "Working Directory", p6 becomes Teer "Current Directory", p11. Stevens "Home Directory", p6 becomes Teer "Home Directory", p12, noting that the rewording regarding "placed" is not well-chosen.

Stevens section 1.4 becomes Teer 1.5. Reworded notes on file descriptor in Teer are misleading, since as Stevens notes, file descriptors are used by the kernel, provided by the process.

Compare Stevens top of p7 with Teer top of p13.
Teer program 1.2 is Stevens program 1.2 (same comment).
Teer program 1.3 is Stevens program 1.3 (same comment).

Teer section 1.6 does not resemble Stevens 1.5, except for the two programs which are adapted from Stevens.

Teer 1.7 expands on Stevens 1.7, but is less focused, since it introduces some elements of the sample programs which have already been displayed.

Stevens section 1.8 becomes Teer 1.8 (more words, same order of presentation, some paraphrasing). Teer program 1.7 is Stevens program 1.6 (same comment).

Stevens section 1.9 becomes Teer 1.9 (more words, same order of presentation, some paraphrasing).
Teer program 1.8 is Stevens program 1.7 (Teer expands it by using sigset rather than signal, sigset is much newer of course).

Stevens section 1.10 becomes Teer 1.10 (more words, same order of presentation, some paraphrasing).

Teer section 1.11 does not resemble Stevens 1.11.

Exercises (Teer p43, Stevens p23): the first two are paraphrased from Stevens.

2 – Solaris

This does not contain material from Stevens.

3 – Utility Functions

This has some overlap in content, but is not directly borrowed from Stevens.

4 – Basic File I/O

See Stevens chapter 3.

The sections are named similarly (same order of presentation), though Teer has added Solaris-specific functions.

Stevens figure 3.1 is redone as Teer figure 4.2.

The example on Stevens p61 is paraphrased in Teer p139 by changing err_sys to err_msg and "< 0" to "== -1". The accompanying description is also paraphrased from Stevens.

5 – Standard I/O Library

See Stevens chapter 5.

Introduction (5.1) is adapted from Stevens.

First 3 paragraphs of 5.2 are adapted from Stevens.

5.3 corresponds to Stevens, but is more wordy.

Stevens section 5.4 is adapted as Teer 5.11.

Stevens section 5.5, 5.6, 5.7, 5.9 are rewritten as Teer 5.4, 5.6 (little paraphrasing).

Stevens section 5.10 corresponds to Teer 5.9 (ok).

Stevens section 5.11 corresponds to Teer 5.8 (ok).

Stevens section 5.8, 5.12 corresponds to Teer 5.12 (ok: has referred to Stevens but has rewritten/expanded).

6 – Date and Time Operations

See Stevens section 6.9.

Stevens figure 6.4 is slightly modified to form Teer figure 6.1

7 – Users and Groups

See Stevens section 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 8.10, 8.14.

This covers the same material as Stevens but does not appear to paraphrase or borrow content.

8 – System Information and Resource Limits

This does not contain material from Stevens.

9 – Secure C Programming

This does not contain material from Stevens.

10 – Files and Directories

See Stevens chapter 4.

Teer 10.1 paraphrases Stevens 4.1 except for last sentence.

Teer 10.2 is new.

Teer 10.3 parallels Stevens 4.2 (does not paraphrase); oddly Teer usually orders functions alphabetically (as in the section title), but the synopsis puts them in reverse alphabetic order here. Most of the content of 10.3 is copied/adapted from Solaris manual pages (which by the way do not appear in the bibliography).

Teer 10.4 paraphrases Stevens 4.3 (some material added, but where they overlap, order, etc., are from Stevens).

Teer 10.5 paraphrases Stevens 4.4 (same comment – second half of this section is rewritten, but borrows ideas in the same order as presented in Stevens).

Stevens section 4.10 corresponds to Teer 10.6 (ok).

Stevens section 4.5 corresponds to Teer 10.7 (ok – some small pieces paraphrased, but the ordering and examples differ).

Stevens section 4.7 corresponds to Teer 10.8 (ok – same comment).

Stevens section 4.8 corresponds to Teer 10.9 (ok – same comment – Stevens example is adapted though).

Stevens section 4.9 corresponds to Teer 10.10 (ok – same comment—Stevens example is adapted though).

Stevens section 4.11 corresponds to Teer 10.11 (ok – see comment for 10.3).

Stevens section 4.12 corresponds to Teer 10.12 (same order of ideas, but not simple paraphrase).

Stevens section 4.13 corresponds to Teer 10.13 (paraphrasing).

Stevens section 4.14 corresponds to Teer 10.14 (paraphrasing in several places, e.g., compare Stevens p94 to Teer p376).

Stevens figure 4.8 is copied in Teer as figure 10.7.

Stevens section 4.15 corresponds to Teer 10.15, 10.16 (paraphrasing in several places, example is adapted).
Stevens figure 4.9 is copied in Teer as figure 10.8.

Stevens section 4.16 corresponds to Teer 10.17 (paraphrasing, some copying, example is adapted).

Stevens section 4.17 corresponds to Teer 10.19 (ok – rewritten).

Stevens section 4.18 corresponds to Teer 10.20 (different text, but same ordering of the items – not alphabetic).
Stevens figure 4.13 is extended in Teer as figure 10.10.

Stevens section 4.19 corresponds to Teer 10.21 (ok – rewritten).

Stevens section 4.20 corresponds to Teer 10.22 (ok – rewritten, though not well done: example now contains a coding error).

Stevens section 4.21 corresponds to Teer 10.23 (ok – rewritten).

Stevens section 4.22 corresponds to Teer 10.24 (first paragraph paraphrased, example 4.8 is adapted as 10.14 in Teer, synopsis blocks are copied, last paragraph paraphrased – the point of the second example which is not obvious from the code, and which is not necessary to this section).

Stevens section 4.23 corresponds to Teer 10.26 (the example on Teer p409 is adapted with minor changes from Stevens p11, otherwise the text is different – Stevens is clear, Teer not).

Stevens section 4.24 corresponds to Teer 10.27 (the synopsis block is copied from Stevens, but the text is different).

Stevens exercises on p118 are a source for Teer exercises p416 (4.3 10.2, 4.5 10.3, 4.6 10.4, 4.7 10.5, 4.14 10.6).
Exercise 10.1 which has no counterpart in Stevens is poorly chosen.

11 – Working with File Systems

This does not contain material from Stevens.

12 – Terminal I/O

See Stevens chapter 11.

Stevens section 11.1 corresponds to Teer 12.1 (paraphrased, with additions by Teer).

Stevens section 11.2 corresponds to Teer 12.2 (paraphrased, with additions by Teer).
Stevens figure 11.1 is Teer 12.1 (rotated by 90 degrees).
Stevens figure 11.2 is Teer 12.2 (minor changes).
Stevens figure 11.3 is Teer 12.3 (extended by new columns but same purpose).
Stevens figure 11.4 is Teer 12.4 (same structure, minor changes).
Stevens figure 11.5 is Teer 12.5 (same structure, minor changes).

Stevens section 11.3 corresponds to Teer 12.3 (paraphrased, with additions by Teer).
Stevens figure 11.6 is Teer 12.6 (some columns different but same purpose).

Stevens section 11.4 corresponds to Teer 12.4 (paraphrased, the synopsis block is copied from Stevens).
Stevens program 11.2 corresponds to Teer 12.2 (Teer does add some functionality to steven's example).

Stevens section 11.5 and 11.6 corresponds to Teer 12.5 (paraphrased, with additions by Teer).

Stevens section 11.7 corresponds to Teer 12.6 (paraphrased).

Stevens section 11.8 corresponds to Teer 12.7 (ok – no direct borrowing).

Stevens section 11.9 corresponds to Teer 12.8 (ok – no direct borrowing, e.g., example program is for ttyname_r rather than ttyname).

Stevens section 11.10 corresponds to Teer 12.9 (paraphrases, adapts the example program by removing the signal handling stating that signals haven't been discussed yet, although the index gives several counterexamples, and also adds some useless text about encryption which is dealt with superficially in Teer's book).

Stevens section 11.11 corresponds to Teer 12.10 (paraphrases, incorrectly uses the term "intercharacter" to replace Stevens' "interbyte").

Stevens figure 11.7 is Teer figure 12.8 (one word changed, but that makes the description incorrect).

Stevens program 11.10 is adapted as Teer program 12.7.

Stevens program 11.11 is adapted as Teer program 12.8.

Stevens section 11.12 corresponds to Teer 12.11 (paraphrases, except comment about SVR4 and BSD is replaced by comment about X).
Stevens program 11.12 is adapted as Teer program 12.9.

Stevens section 11.13 corresponds to Teer 12.12 (paraphrases, except section title is – for a change – modified). Note especially that the references are copied from Stevens, including Goodheart which has been out of print since the mid-90's. It was topical for Stevens to use it; it is evidence that Teer copied this section. That, and the poorly constructed replacement for the last sentence in the section prompted me to look closely at the bibliography.

Stevens section 11.14 corresponds to Teer 12.13 (paraphrases).

Stevens exercise 11.1 is Teer 12.2.
Stevens exercise 11.3 is Teer 12.1.

13 – Advanced I/O

See Stevens chapter 12.

Stevens 12.2 corresponds to Teer 13.2, (paraphrased, omitting the historical notes as usual).

Stevens 12.3 corresponds to Teer 13.3, 13.4, 13.6, 13.7 (paraphrased). Teer's rewording of definition for record locking is poor. Teer omits historical notes from Stevens which are relevant even to Solaris.

Teer 13.4 gives an incorrect prototype for fcntl in the synopsis; the Solaris-specific discussion of the 3rd parameter is poor. Teer program 13.2 copies Stevens 12.2, renamed and removed comments. Teer program 13.3 copies Stevens 12.3, renamed and add a struct in the wrong place, making it useless.

Teer 13.5 discusses lockf (not in Stevens).

Teer 13.6 copies the dining philosophers example from another source than Stevens (but I don't see anything suitable in Teer's bibliography). Here is an interesting reference which shows where to start looking. However Teer program 13.4 is adapted from Stevens 12.4.

Teer 13.7 is adapted from Stevens p373. Teer omits content from Stevens p374 to top of 378.

The first part of Teer 13.8 (p521) is adapted from Stevens p378-379. Notes on performance and program 13.5 do not appear in Stevens.

Teer 13.9 corresponds to Stevens 12.4 p383-384 (but is a disordered rewrite). Program 13.6 is adapted from Stevens 12.9.

Teer 13.10 corresponds to Stevens 12.4 p385-386 (but is a disordered rewrite).

Teer 13.11 corresponds to Stevens 12.4 p386-387 (but is a disordered rewrite). Figure 13.7 is adapted from Stevens 12.10 (changes "yes or no" to "don't care").

Teer 13.12 corresponds to Stevens 12.4 p392 (but is a disordered rewrite).

Teer 13.13 corresponds to Stevens pp 387-391, but is actually paraphrased from Solaris manpages, e.g., streamio (7i). Teer program 13.8 is adapted from Stevens program 12.10.

Teer 13.14 corresponds to Stevens pp 391-394. Teer reorders this, putting the discussion of read before write. However (contrary to Teer's usual practice), the options listed are in the same non-alphabetic order as Stevens. And the streamio manpage does not list some of those listed by Stevens, e.g., SNDPIPE.

Teer 13.15 paraphrases Stevens 12.5. The talkd program in Teer corresponds to the modem dialer in Stevens. Noting that renaming, Teer figures 13.9 and 13.10 are adapted from Stevens 12.11 and 12.12.

Teer 13.16 corresponds to Stevens 12.5.1 (but is a disordered rewrite). Some parts are paraphrased (cf: Teer p541 with Stevens p397 and Teer p542 with Stevens p399-400).


My own review stops at this point, in the middle of chapter 13. Reviewing takes time. I have incorporated comments from Gunnar Ritter and Ian Clarke for the remaining chapters.


14 – Environment of a Unix Process

See Stevens chapter 7.

15 – Process Control

See Stevens chapter 8.

Ian Clarke comments on this chapter.

16 – Process Relationships

See Stevens chapter 9.

Ian Clarke comments on this chapter.

17 – Signals

See Stevens chapter 10.

18 – Daemon Processes

See Stevens chapter 13.

19 – Interprocess Communication Using Pipes and FIFOs

See Stevens chapter 14.

20 – System V Interprocess Communication Facility

See Stevens chapter 14.

21 – Advanced Interprocess Communication

See Stevens chapter 15.

22 – Doors

Gunnar Ritter notes:

As Ian Clarke has mentioned, the chapter on doors (22, page 951 etc.) is derived from volume 2 of Stevens "UNIX Network Programming, Second Edition: Interprocess Communications" (Prentice-Hall, 1999), chapter 15, page 355 etc. This is again plagiarism in my opinion because Teer does not explicitly mention his source for the derived parts; I don't think just having it in the bibliography is enough for all of the following:

and lists several instances:

Teer 22.1, pages 951-953 are from Stevens 15.1, pages 355-357.
Teer figure 22.1 is Stevens fig. 15.1.
Teer pages 954-955 are from Stevens pages 363-364.
Teer page 956 is from Stevens pages 362-363.
Teer pages 960-961 are from Stevens pages 367-369.
Teer pages 962-965 are from Stevens pages 375-379.
Teer pages 977-978 are from Stevens page 384.
Teer pages 979-980 are from Stevens page 386.
Teer pages 983-985 are from Stevens pages 388-390.
Teer pages 985-986 are from Stevens pages 390-391.
Teer page 986 last paragraph is from Stevens page 395.
Teer page 992 is from Stevens pages 397-398.
Teer exercise 22.1, page 993 is Stevens 15.4, page 398.
Same comment applies to 22.2 (derived from Stevens exercise 15.6), 22.3 (derived from Stevens exercise 15.8), 22.4 (derived from Stevens exercise 15.9).

concluding with

So Teer has really plagiarized from two books of Stevens.

23 – Pseudo Terminals

See Stevens chapter 19.

Ian Clarke comments:

I had a look at that chapter (chap. 23): most of the diagrams are the same or very similar (and in the same order), there are a number of rather similar looking paragraphs and a general order of presentation that is very similar to Stevens (chap. 19). Most notably, the main example program of the chapter (pty.c) is the same program (with some modification) as Stevens wrote.

Appendix A – Internationalization and Localization Primer

Appendix B – BSD Source Compatibility

Appendix C – Function Summary

Appendix D – Miscellaneous Source Code

See Stevens Appendix B.

Appendix E – Solutions to Selected Exercises

See Stevens Appendix C.

First two exercises from chapter 1 are copied from Stevens.

Appendix D: Bad Reviews

Here are Gunnar Ritter's comments. Except as noted, I have made only minor changes to present them on this webpage.

Although Teer does not mark the material he has borrowed from Stevens, the first sentence of the publisher's book description which is also printed on the back cover is "In the tradition of W. Richard Stevens' Advanced Programming in the UNIX Environment, this book offers comprehensive, practical guidance for systems programmers." From Teer's preface, the reader learns "Despite the word 'Solaris' in the title, this book is suitable for programmers of any UNIX or UNIX-like operating system (that being said, some of the features we describe are specific to Solaris)" (page xxxi, Teer's emphasis).

This claim is important for the buyer and reader. Many people are writing programs for Unix-like environments today. But Solaris is only one of the Unix-like environments available, and, according to many reports, it might not even be the prevalent one of them. So many people are interested in learning Unix programming but are not using a Solaris system. Moreover, it is common to keep programs portable between the various Unix-like environments because the effort of doing so is not too high, but the gain of programs that run on e.g. Linux, Solaris, and BSD is. This applies to both Open Source and commercial programming. Thus even if somebody learns programming on a Solaris system, chances are high that he wants to write portable programs, or is even required to do so by his employer.

From the second sentence cited above, it is clear that Teer claims that his book is useful for learning how to write portable programs. And from the first sentence, it is clear that this is to be done in the tradition of Steven's APUE. Now Stevens had pursued a very elaborate but successful way of ensuring portability: He had actually tested his example programs on a variety of then-contemporary Unix systems, as described on page xvii of his preface. In contrast, Teer tested his programs only on the Solaris platform, as described on page xxxv of his preface, and much of his sample code actually cannot be compiled e.g. on Linux or BSD systems. This would certainly have been excusable if such code had been marked, i.e. if there had been a set of portable base examples and another set of examples that introduce special Solaris functionality. But there is no such distinction in Teer's book. As far as the examples are concerned, a Linux or BSD user of today can thus just as well use Stevens' book as Teer's; some of the examples do work with both books, and for those that do not, the reader has to determine the reason on his own.

Teer's main method of providing portability information is the function availability table following page 1104. The table covers all versions of Solaris from 2.5 to 9, and a number of standards, all of them from the 80s and 90s, and all based on the C standard from 1989 and the POSIX.1 standard from 1990. These are the very standards on which Stevens' book was based; Teer explicitly dispenses with information about the recent C standard from 1999 and the recent POSIX.1 standard from 2001 because they were still not supported by Sun with Solaris 9 (they are supported from Solaris 10 on, though). As far as standards-based programming is concerned, Teer's book has thus not much more to offer than Stevens'.

Moreover, Teer's method of presenting the standards is impractical. For every interface he learns, Teer's reader has to consult the table if he is interested in its portability. Stevens presents such information in-line. Still worse, Teer's table provides only a function summary; it lacks any information about defined constants, structure fields etc., and Teer gives such information only sporadically within the text (e.g. for the flags for open() on page 127). Thus even if a function is contained in the table, the reader often cannot determine if the way it is called conforms to the standard. The listing of deficiencies in Teer's book below gives some prominent cases.

It must thus be concluded that, unless one sticks with writing programs for Solaris only, Teer's book is inferior to Stevens'. The fact that it was published eleven years later is nearly irrelevant in this respect.

The following table lists some individual deficiencies of the book, most of them concerning portability, but also some generic inconsistencies. Page numbers are from Teer.


Detailed Criticism
Page Comments
8 Teer introduces MAXNAMELEN here (why not the POSIX constant NAME_MAX?) but later writes on page 283

If we want our code to work with s5fs and UFS, we can't rely on compile time limits, and must use run time limits.

This is inconsistent.

33 long double occupies 96 bits on Solaris/i386 with Sun C, not 128.
99 Teer says

Note that the alloca function is very machine-, compiler-, and system dependent; its use is strongly discouraged.

This comes straight from the WARNINGS section of malloc(3C), which reads

The alloca() function is machine-, compiler-, and most of all, system-dependent. Its use is strongly discouraged.

Stevens' position "implementations exist for a wide variety of systems" (page 171) makes much more sense. In particular, alloca() is available for all known compilers on all Solaris platforms. It is odd that Teer takes such a strict position concerning portability at this single point.

175-176 The printf conversions %wc and %ws are proprietary to SVR4 derivatives but Teer does not mention this anywhere. This is particularly bad because the lack of portability will only be noticed at run time on most platforms later.
184-185 Teer does not explain why fgetpos() and fsetpos() are available and why they are of little use on Unix. Stevens did (page 136). This is not helpful to a novice who might ask "Now should I use fseek() or fsetpos()?".
268-269 The description of utmp/utmpx and wtmp/wtmpx only applies to Solaris, without any remark about the various portability constraints in this area. This culminates with

In fact, because the utmpx and wtmpx functions also update the utmp and wtmp files on older versions of Solaris, there's never a need to call the old functions.

(i.e., getutent() etc.). But on many other platforms, these functions do not even exist. Cf. Stevens page 153; the situation is not any better today.

276 Teer says that the nodename field of struct utsname contains

the NUL-terminated name of the machine as it is known on the network (i.e., its hostname).

Stevens remarked on page 154

POSIX.1 warns that the nodename element may not be adequate to reference the host on a communications network. This function is from System V, and in older days the nodename element was adequate for referencing the host on a UUCP network.

which is still relevant today and still causes a lot of confusion for novices. Teer mentions the possible lack of domain information only for sysinfo(SI_HOSTNAME, ...) on page 277.

325 Teer describes the /proc filesystem but does not even mention that its structure is totally different on other platforms. An actual description of other structures may well be outside the scope of the book, but it would not have hurt if he had just made a remark about that.
334-335 Teer describes getloadavg() but does not mention that the constants such as LOADAVG_1MIN and the <sys/loadavg.h> header are Solaris specific. (The call is otherwise portable to BSD at least.) Stevens had probably written a portable wrapper function for this because the information can be retrieved on nearly any platform in some way.
337 Teer claims that

there isn't much an application can do to defend itself against DoS attacks.

But on pages 864-865 he devotes an entire section to Denial of Service Attacks and makes at least some notes on how to avoid them. He never mentions algorithmic complexity attacks which are definitively relevant for application programming. The chapter on Secure C Programming thus is not only incomplete, it is even inconsistent with the rest of the book.

344-346 Teer devotes three pages and a complete sample program on how to break out of a chroot jail. The example is horribly stupid though because all what is necessary for the programm to defend from this particular "attack" is to insert a chdir("/"); after the first call to chroot(). What Teer presents is thus a weakness in his sample code, not a weakness in the chroot call. What is worse is that there are actual ways to break out on Solaris that are not much more difficult to perform and against which there is no way to defend if root privilegues can be obtained inside the chroot, most prominently mounting /proc and using /proc/1/cwd to break out, or using /dev/mem to access the kernel structures directly. But the reader does not learn about the real dangers from Teer's book.
357 Teer does not mention that the st_fstype field of struct stat is only available on SVR4 derivatives, and that the block size for the st_blocks field depends on the implementation (cf. Stevens page 80).
363 In the note in small type, Teer apparently describes the effects of the sticky bit on directories but does not mention what his description applies to.
512 Mentioning that mandatory locking is nonportable would not have hurt.
556 Teer describes sendfile() but does not describe that the particular interface originates from Linux. No history notes, no portability notes.
564-565 Teer does not mention the portability constraints concerning anonymous mappings.
644 The WNOWAIT constant is not in POSIX but the reader cannot learn this from Teer's book.
687 Teer does not mention that the way to obtain a controlling terminal is implementation-specific (cf. Stevens page 246).
719 Teer describes sigset() as "the signal function's reliable counterpart" but does not describe the various portability constraints of it. BSD systems generally did not provide it until very recently (except for very old code that had been left out since 4.3BSD); on Linux with GNU libc or uClibc, one must define _GNU_SOURCE or _XOPEN_SOURCE to get its prototype; Linux with diet libc, libc5 or older does not provide it at all. All would have been fine if Teer had provided his own implementation of it (and the related functions) using the portable sigaction() interface; but he did not. Teer frankly admits that he does not know about all of this on page 746 where he writes

the signal handling functions we've discussed so far are adequate for most needs (unless POSIX compliance is a requirement), and [that] they are likely to be found on older systems.

It is clearly not in Stevens' tradition to speculate about portability instead of making the required tests.

720 Teer claims that

when porting programs that use signal from BSD, it is usually sufficient to add the line

#define signal sigset

on the top of the program. The only case where we can't do this is when we are working with SIGCHLD.

This is wrong because BSD signal() does restart system calls but System V sigset() does not, so some code will mysteriously fail to work if one follows Teer's advice blindly. Moreover, SUSv2 (and so Solaris) even provides a function named bsd_signal() that is explicitly required to restart signals and would fit much better for this purpose, but Teer does not mention it anywhere.

753-754 Some of the flags for sa_flags in struct sigaction are from POSIX, some are from SUSv2, and some are Solaris-specific, but the reader does not learn this from Teer's book.
952 Teer writes that

A preliminary version of the doors API is being developed for Linux; details can be found at http://www.rampant.org/doors.

But this project is not being actively developed anymore; its last update was on January 5, 2003 for Linux 2.4.18, more than one and a half year before the publication of Teer's book. Now Teer does provide a portability hint as an exception here, and then it can easily lead the reader to the wrong assumption that anybody was actively developing an implementation of doors for Linux.

1045 The chapter An Internationalization and Localization Primer has almost nothing about multibyte character encodings. It even leads the reader to a wrong direction here:

Use standard codesets, for example, ISO Latin-1.

But one does not use hard-coded international character sets with the C/Unix/Solaris locale mechanism. On page 1046, Teer writes that

Internationalization and localization is a large and complicated subject. We've only had the briefest of looks at it in this appendix.

But Teer in fact omits one of the most intricate consequences of internationalization and misleads his reader instead, which is not acceptable even in a short summary.

1104-1115 Teer's Function Availability table contains a "POSIX" column that "refers to the 1996 edition of POSIX 1003.1". What Teer does not mention is that this edition provides a couple of implementation options. He has arbitrarily chosen these options for composing his table; functions available with the _POSIX_THREAD_SAFE_FUNCTIONS option such as getc_unlocked() and getpwnam_r() are marked in the POSIX column, but fsync() from _POSIX_FSYNC or mmap() and ftruncate() from _POSIX_MAPPED_FILES are not, even though Solaris offers all three options.

Appendix E: News-Group Discussions

Here is a list of the subsequent discussions in newsgroups about the Solaris Systems Programming book.