Advanced Programming in the Unix Environment
Author: W. Richard Stevens
Publisher: Addison Wesley Longman Inc.
Price: $63.43 US
Reviewer: David Bausum
Advanced Programming in the Unix Environment is not a new book; it was first published in 1992. However, it is the Unix programming book that convinced me that I could port a project of mine from DOS to Linux.
In 1992 I wrote a large program designed to work with the real-time stock market data feed provided by Data Broadcasting Corporation (see http://www.dbc.com/). The program is interactive, and it allows a user to display and print (in both textural and graphical modes) current and historical data about stocks, options and market indices. In the background, the program receives serial data (via satellite to a “black box” provided by DBC that connects to a PC's serial port), breaks the data into transactions, stores the transactions in a database and feeds the transactions to the display module based on user instructions. I wrote this program on a DOS system using Watcom's 32-bit compiler and utilizing most of the 16MB DOS can address.
Within a few years I began to find DOS's 16MB limit restrictive and began looking for a new working environment. About the same time I received a sample copy of Linux Journal. That particular issue (#14, June 1995) had the words “Intelligent Serial Boards” on its cover—those words got my attention. By then I had upgraded my program to work with a Digiboard, and I knew one requirement for a migration to a new OS would include being able to use it or another intelligent board. I subscribed to LJ and began to look for books relating to Linux/Unix.
When I began programming in the early eighties, I learned Basic and FORTRAN by reading what I call “no-name” books. By that I mean there was nothing memorable about either the books or their authors' style. By contrast I learned Cobol from McCracken and C from Kernighan and Ritchie. Anyone familiar with either book will recognize the difference between those books and “no-name” ones. I realized that if I hoped to port my DOS application to Linux, I needed to find a book which would do for Unix what the book by Kernighan and Ritchie does for C.
In the second half of 1995 and the first part of 1996 I kept running into references to Advanced Programming in the UNIX Environment by W. Richard Stevens. In the Spring of 1996 I ordered the book, and it has turned out to be everything I had hoped it would.
It is a big book—over 2 inches thick and more than 750 pages in length. It is hard cover, and it lies flat when open. It is an attractive book—both the cover and the general page layout. In the preface Stevens says he used troff and groff to format and prepare the camera-ready copy for the book. As one who has prepared copy for more than one book, I know that an attractive book does not just happen. It takes expertise and time, and Stevens's effort makes the reader's journey through the book more enjoyable.
The book discusses over 220 functions used by various Unix libraries. When a function is introduced, it is placed in a box with system include files required by the function, information about function returns and a function prototype. The book has over 10,000 lines of source code (all in C) and is filled with numerous small program examples. The code is available by FTP and was tested by Stevens on four flavors of Unix. The book has numerous tables which group together flags of a particular type or other information. It has numerous figures which show the relationships of the items under discussion. Where appropriate, it includes the output from an example and uses it to clarify or emphasize the current discussion item. It does these things within the context of the included Unix variants (listed below). Where necessary a topic is described for each variant. With a lesser writer the encyclopedic detail would become suffocating, but Stevens surrounds all of the above items with enough text to make a very readable book and an extremely valuable reference.
In the preface Stevens breaks the book into 6 parts and briefly describes each part. The following is a slightly different breakdown with longer descriptions.
Part 1 contains Chapters 1-6 (160 pages). The first two chapters provide a gentle introduction to Unix and a discussion of the included variants of Unix. They are SVR4 which dates to 1990, 4.3+BSD which refers to the state of BSD in early 1992 and POSIX.1 which dates to 1990. The remaining four chapters in this part (over 100 pages) discuss files, directories, access permissions, inodes, file I/O and special files such as the password file. This material duplicates Chapter 8, “The Unix System Interface”, in the Kernighan and Ritchie book, but it goes into much more detail and discusses many more topics.
Part 2 contains Chapters 7-9 (100 pages). These chapters deal with processes. Topics discussed include:
what happens when a process starts and when it stops
how to access program arguments and environment variables
process resource limits
process creation via forks and execs
process IDs and other properties
the relationship between a parent and a child process
Part 3 contains Chapters 10-12 (150 pages). At this stage we are about one third of the way through the book, and the going has not been too rough. That changes with this part. Chapter 10 deals with signals, Chapter 11 with terminal I/O and Chapter 12 with advanced terminal I/O. Once Stevens describes each of the over 30 signals available, he shows how signals in early versions of Unix were unreliable. Then, he describes functions introduced with POSIX.1 which make signals safe to use. Fortunately, these POSIX safe functions are available in Linux. His treatment of terminal I/O begins with an examination of the termio's structure which holds over 50 special flags (or switches), characters that are given special treatment during input and baud rates. He shows how to get and save these values. He describes canonical (i.e. line oriented) and noncanonical I/O. Again, I found his discussion highly applicable to Linux. Chapter 12 deals with various additions to the I/O system discussed in part 1 and in Chapter 11. Some of the topics included are nonblocking I/O, record locking, streams, multiplexing (via select or poll), asynchronous I/O and memory mapped I/O. The select function is available in Linux, but I don't think all of these topics are—yet.
Part 4 contains Chapters 13-15 (100 pages). Chapter 13 is a short chapter dealing with daemon processes. Chapters 14 and 15 deal with interprocess communication. That discussion begins with pipes and winds up 80 pages later with two examples of sets of functions used in client-server programs. Stevens treated part of Chapter 15 in much more detail in his 1990 book UNIX Network Programming (Prentice Hall).
Part 5 contains Chapters 16-18 (115 pages). At this stage we are two thirds of the way through the book, and the “advanced” in the title is beginning to show (to this DOS programmer). Each of the chapters in this part is devoted to developing a single program or library—a database program, a PostScript printer program and a modem dialer. I spent several days studying the printer program and learning how the logging facility used by the kernel and several daemons works.
Part 6 contains 1 chapter, 3 appendices, a bibliography and an index (120 pages). Chapter 19 deals with pseudo terminals. Appendix A is very valuable, providing a 20-page summary of all the functions introduced in the book. The material is arranged alphabetically and includes a function prototype, return values, required system include functions and a reference to the page which introduces the function. Appendix B provides source code used by many examples in the book. Appendix C provides solutions to some of the exercises which end each chapter. The index is quite complete (25 pages).
When I finish a book, I have several criteria for deciding if I can recommend it. Where does it now live: on my desk, in a pile of books near my desk or on a distant shelf? Was the book interesting in a general sort of way or did it change the way I think or act? Stevens's book lives on my desk, often open to a particular spot. Also, it has given me many ideas I am using in the port of my stock program to Linux. Three examples are serial I/O, coordinating multiple workers and error messages.
Chapter 11 made it relatively painless for me to get both standard serial ports and my Digiboard working under Linux. Chapter 10 gave me the idea of adding Unix signals and timers to the central work loop of my DOS program. This allows me to use the same program structure as the DOS program. In addition, it allows the program to sleep when it has no work and to awake when it does. Thus, it will be Linux “friendly”. Chapters 13 and 17 together with Appendix B showed me how to log errors in a special file. Using a single line, my program can call a function that writes to standard error, a program specific log file or both. The call uses a printf() format with a variable number of arguments, and it can either end the program or return to the calling function.
I have felt for many years that programming and construction are related. Migrating from DOS programming to Linux is like moving from wood-frame house construction to the construction of sky scrapers using concrete, steel and glass. Such a transition requires understanding new materials and how they interact. That is precisely the information provided by Stevens's book. He describes basic library calls, uses them in small code segments and pieces them together in several larger projects. I heartily recommend this book and hope your mileage will be as good as mine.
David Bausum received a Ph.D. in mathematics from Yale in 1974. Since the early 80's most of his energy has gone into software development and related activities. He coedited The Journal of Military History Cumulative Index: Vols 1-58, 1937-1994. He can be reached via e-mail at firstname.lastname@example.org.