diff --git a/ALP-listings.tar.gz b/ALP-listings.tar.gz
new file mode 100644
index 0000000..6e66d84
Binary files /dev/null and b/ALP-listings.tar.gz differ
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..486449c
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..d38a84a
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,12 @@
+Open Publication License
+=========================
+Advanced Linux Programming is published under the [Open Publication
+License](http://www.opencontent.org/openpub/), Version 1, no options
+exercised. (Due to an oversight in final production, the copyright
+notice on the book is incorrect.) The full text may be downloaded from
+this site.
+
+GNU General Public License
+=========================
+Code samples in the book are covered by the [GNU General Public
+License](http://www.gnu.org/copyleft/gpl.html) and are also available.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9415436
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+# Default compiler options for C and C++. To build with other options,
+# provide a definition of CFLAGS when invoking make. For example,
+# invoke "make CFLAGS=-O2 all".
+CFLAGS = -g -Wall
+CXXFLAGS = $(CFLAGS)
+
+# Pass these variables to make subprocesses.
+export CFLAGS CXXFLAGS
+
+# The subdirectories in this directory.
+SUBDIRS = chapter-1 chapter-2 chapter-3 chapter-4 chapter-5 \
+ chapter-6 chapter-7 chapter-8 chapter-9 chapter-10 \
+ chapter-11 appendix-a appendix-b
+
+.PHONY: all clean $(SUBDIRS)
+
+# The default target: build the contents of each subdirectory.
+all: $(SUBDIRS)
+
+# For each subdirectory, invoke a make subprocess.
+$(SUBDIRS):
+ cd $@; $(MAKE)
+
+# Clean up build products in all subdirectories.
+clean:
+ for subdir in $(SUBDIRS); do \
+ (cd $${subdir}; $(MAKE) $@); \
+ done
diff --git a/README.md b/README.md
index f7ac329..f93e6aa 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,36 @@
-# advancedlinuxprogramming
\ No newline at end of file
+# Advanced Linux Programming
+
+## About This Repository
+
+Most of the content resides in the gh-pages branch. The master branch
+contains a README file and a LICENSE file.
+
+## About Advanced Linux Programming
+
+### Publication Information
+
+```
+Advanced Linux Programming
+by Mark Mitchell, Jeffrey Oldham, and Alex Samuel, of CodeSourcery LLC
+published by New Riders Publishing
+ISBN 0-7357-1043-0
+First Edition, June 2001
+```
+
+### From the Back Cover
+
+Advanced Linux Programming is intended for the programmer already
+familiar with the C programming language. Authors Alex Samuel, Jeffrey
+Oldham, and Mark Mitchell of CodeSourcery, LLC take a tutorial
+approach and teach the most important concepts and power features of
+the GNU/Linux system in application programs.
+
+If you're a developer already experienced with programming for the
+GNU/Linux system, are experienced with another UNIX-like system and
+are interested in developing GNU/Linux software, or want to make the
+transition for a non-UNIX environment and are already familiar with
+the general principles of writing good software, this book is for
+you. In addition, you will find that this book is equally applicable
+to C and C++ programming. Even those progamming in other languages
+will find this book useful since the C language APIs and conventions
+are the lingua franca of GNU/Linux.
diff --git a/about.html b/about.html
new file mode 100644
index 0000000..9ced7b2
--- /dev/null
+++ b/about.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+ About Advanced Linux Programming
+
+
+
+
+
+
+
+
About Advanced Linux Programming
+
+
Publication Information
+
+
Advanced Linux Programming
+by Mark Mitchell, Jeffrey Oldham, and Alex Samuel, of CodeSourcery LLC
+published by New Riders Publishing
+ISBN 0-7357-1043-0
+First Edition, June 2001
+
+
From the Back Cover
+
+
Advanced Linux Programming is intended for the
+programmer already familiar with the C programming language. Authors Alex
+Samuel, Jeffrey Oldham, and Mark Mitchell of CodeSourcery, LLC take a tutorial
+approach and teach the most important concepts and power features of the
+GNU/Linux system in application programs.
+
+
If you're a developer already experienced with programming for the GNU/Linux
+system, are experienced with another UNIX-like system and are interested in
+developing GNU/Linux software, or want to make the transition for a non-UNIX
+environment and are already familiar with the general principles of writing
+good software, this book is for you. In addition, you will find that this book
+is equally applicable to C and C++ programming. Even those progamming in
+other languages will find this book useful since the C language APIs and
+conventions are the lingua franca of GNU/Linux.
+"As Linux becomes a more mainstream player in the internet infrastructure
+market, there is a tremendous need for lucid programming texts that also convey
+some of the philosophy behind the Linux and GNU movements. This book does
+an incredible job of covering all that. I think it will be a standard against
+which other introductory programming texts for Linux (and with all due respect
+to Richard Stevens, possibly UNIX as well) are measured."
+
+
+
About CodeSourcery LLC
+
+
CodeSourcery, based in Granite Bay,
+California, brings top-notch people together to work on programming tools and
+other challenging technologies. A recognized leader in the development of the
+GNU C and C++ compilers, CodeSourcery also develops new UNIX development tools
+and contributes to the development of open-source software, in addition to
+contract software development and support services.
+Some web browsers have problems with inline PDF files. Try saving the
+file to your local filesystem before opening with a stand alone PDF
+viewer. If you still have problems viewing the file, make sure you
+have downloaded the entire file and the md5
+checksum matches.
+
+
+
+
+
Title
File
Filesize
md5 checksum
+
The Entire Advanced Linux Programming Book in One File
Download the full text of the book as
+
+PDF files
+.
+
+
+
The book is published under the
+Open Publication License,
+Version 1.0. Please consult the OPL for conditions on redistributing
+or modifying the book.
+
+
Download Code Listings
+
+
Download the code listings in this book as a gzipped tar file:
Extract the code samples with this GNU/Linux command:
+
+
+ $ tar zxf ALP-listings.tar.gz
+
+
+
If you're having trouble expanding the gzipped tar file, your web browser
+may be uncompressing it automatically during the download. If your
+browser downloads this file as ALP-listings.tar, you have an
+uncompressed tar file, so omit the z option when expanding it:
+
+ $ tar xf ALP-listings.tar
+
+
+
The code samples in this book are covered by version 2 of the
+GNU General Public License.
+Please consult the GPL for conditions on using, modifying, and redistributing
+the code in this book.
In Listing 1.1, add #include <stdlib.h> since atoi is used.
+
+
+
+ page 8
+
The first paragraph of Section 1.2.2 should refer to reciprocal.cpp,
+ not utilties.cpp.
+
+
+
+ page 31
+
In the third paragraph, the third sentence should read:
+
+ You should still always check for invalid input and produce sensible error
+ messages in response to such input.
+
+ The words "to such" are missing in the book as printed.
+
+
+
+
+ page 34
+
In the code, the comment for case ENOENT should
+ read PATH does not exist.
+
+
+
+
+ page 38
+
+ The first sentence in Section 2.3.2 should refer to an archive
+ rather than a archive.
+
+
+
+
+ page 38
+
In the last sentence of the text, omitting the sidebar, the
+ resulting object file is test1.o, not test.o.
+
+
+
+
+ page 39
+
In the first paragraph, the linker stops searching
+ directories.
+
+
+
+
+ page 41
+
In the paragraph beginning with "Static libraries", modify
+ "If decide to link" to "If you decide to link".
+
+
+
+
+ page 41
+
When linking statically, linking in the math library is
+ also required. Thus, the compilation line becomes
+ gcc -static -o tifftest tifftest.c -ltiff -ljpeg -lz -lm.
+
+
+
+
+ page 43
+
The indented line of code near the bottom of the page should refer to my_function, not foo.
+
+
+
+
+ page 48
+
In the first paragraph, the first technique has "considerable risks",
+ not "considerably risks".
+
+
+
+
+ page 53
+
The word "it" in the last sentence of the second paragraph
+ should instead be "is".
+ In particular, the sentence should read:
+
+ The default disposition for these signals is to terminate the process
+ and produce a core file.
+
+
+
+ page 57
+
The word "is" in the last sentence should instead be "it."
+ In particular, the sentence should read:
+
+ Instead, when a child process terminates, it becomes a zombie process.
+
+
+
+ page 60
+
The code in clean_up_child_process would not work correctly if there were more
+ than one child process. The Linux kernel will only call the signal handler once if two or more
+ child processes terminate at almost the same time. Therefore, if there is may be more than one child
+ process, the signal handler must repeatedly call waitpid (or one of the other
+ related functions) with the WNOHANG option until waitpid returns zero.
+
+
+
+ page 73
+
In the first paragraph, the second argument is for pthread_key_create, not
+ pthread_key_t. Thus, the pthread_key_create function takes two arguments:
+ a pointer to a pthread_key_t variable and a cleanup function.
+
+
+
+ page 98
+
The example code for calling shmget should use S_IWUSR, not
+ S_IWUSER. This write permission flag is spelled correctly throughout the
+ rest of the page. For a list of available flags, see the section 2 stat man page.
+
+
+
+ page 108
+
In Listing 5.6, the function used to parse the string
+ should be sscanf, not scanf.
+
+
+
+ page 110
+
The last sentence of section 5.4.1 should read:
+
+ Data written to the file descriptor write_fd can be read back from read_fd.
+
+
+ The identifiers write_fd and read_fd are
+ swapped in the text as printed.
+
+
+
+ page 117
+
In section 5.5.2, the list of system calls should mention
+ close, not closes.
+
+
+
+ page 120
+
In Listing 5.10, text should be checked for the
+ quit message before it is freed. The consequent of the
+ strcmp should be free (text); return 1. Its
+ alternative should be free (text). The standalone
+ free statement should be omitted.
+
+
+
+ page 121
+
In Listing 5.10, the client_name_len variable in
+ the do-loop should be initialized to
+ sizeof(client_name) before being passed to
+ accept.
+
+
+
+
+ page 121
+
In Listing 5.10, the call to bind on the ninth
+ line of this page should cast the second argument to a
+ struct sockaddr *. That is, the bind
+ call should be
+
In Listing 5.11, the call to connect on the sixth
+ line from the end should cast the second argument to a
+ struct sockaddr *. That is, the connect
+ call should be
+
In Listing 5.12, the call to connect on the second
+ line should cast the second argument to a
+ struct sockaddr *. That is, the connect
+ call should be
+
+ Note that the operator for the second half of the conditional should
+ be != rather than ==.
+
+
+
+
+ page 171
+
In the third paragraph, use F_SETLKW, not F_SETLCKW. This
+ LK abbreviation differs from the LCK abbreviation in F_RDLCK and
+ F_WRLCK.
+
+
+
+
+ page 174
+
The first sentence of the third paragraph of section 8.5
+ should end with "pointer to a struct rlimit", rather
+ than "pointer to a structrlimit" as printed. Note
+ the space between struct and rlimit.
+
+
+
+ page 181
+
The description of tv_nsec should read "tv_nsec,
+ an additional number of nanoseconds" rather than "tv_nsec,
+ an additional number of milliseconds."
+
+
+
+ page 183
+
The third parameter in the call to readlink should
+ be sizeof (target_path) - 1 to allow for the terminating
+ NUL character.
+
+
+
+ page 185
+
The file presented in Listing 8.11 should be named "itimer.c".
+
+
+
+ page 186
+
The sysinfo manual page describes struct
+ sysinfo, not structsysinfo.
+
+
+
+ page 188
+
The file presented in Listing 8.11 should end with a ".c", i.e.,
+ "print-uname.c".
+
+
+
+ page 191
+
The assembly instructions shown corresponding to the asm
+ should be:
+
+
+#APP
+ mycool_asm %ecx, %edx
+#NOAPP
+
+
+ reflecting the fact that foo and bar are
+ in separate registers.
+
+
+
+
+ page 206
+
In the beginning of 10.4.1, the root process impersonates
+ another user, not another process.
+
+
+
+ page 212
+
The prototype of the GNU extension getline
+ function differs from that presented. To use the GNU extension,
+ modify the code to
If you are a developer for the GNU/Linux system, this book will help you to:
+
+
+
Develop GNU/Linux software that works the way users expect it to.
+
Write more sophisticated programs with features such as multiprocessing,
+ multi-threading, interprocess communication, and interaction with hardware
+ devices.
+
Improve your programs by making them run faster, more reliably, and
+ more securely.
+
Understand the peculiarities of a GNU/Linux system, including its
+ limitations, special capabilities, and conventions.
+
+
+
Advanced Linux Programming is published under
+the Open Publication License, Version 1, no
+options exercised. (Due to an oversight in final
+production, the copyright notice on the book is incorrect.)
+The full text may be downloaded from this site. Code samples in the book
+are covered by the GNU General
+Public License and are also available.
+
+
diff --git a/listings/alp-header.png b/listings/alp-header.png
new file mode 100644
index 0000000..92506f4
Binary files /dev/null and b/listings/alp-header.png differ
diff --git a/listings/alp.css b/listings/alp.css
new file mode 100644
index 0000000..e1b916c
--- /dev/null
+++ b/listings/alp.css
@@ -0,0 +1,26 @@
+body {
+ margin-top: 8;
+ margin-left: 24;
+ margin-right: 8;
+ margin-bottom: 8;
+ color: black;
+ background: white url(red-edge.png);
+ background-repeat: repeat-y;
+ font-family: arial,sans-serif;
+}
+
+span.footnote {
+ font-size: small;
+}
+
+span.title {
+ font-style: italic;
+}
+
+p {
+ margin-left: 1em;
+}
+
+p.heading {
+ margin-left: 0;
+}
diff --git a/listings/appendix-a/Makefile b/listings/appendix-a/Makefile
new file mode 100644
index 0000000..e27375c
--- /dev/null
+++ b/listings/appendix-a/Makefile
@@ -0,0 +1,26 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS =
+LIBRARIES =
+PROGRAMS = calculator hello malloc-use
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o *.a $(PROGRAMS)
+
+# Additional dependencies.
+calculator.o stack.o number.o: \
+ CFLAGS += -pg
+
+calculator: LDFLAGS += -pg
+calculator: calculator.o stack.o number.o
+
diff --git a/listings/appendix-a/calculator.c b/listings/appendix-a/calculator.c
new file mode 100644
index 0000000..8d8f800
--- /dev/null
+++ b/listings/appendix-a/calculator.c
@@ -0,0 +1,100 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+/* Calculate using unary numbers. */
+
+/* Enter one-line expressions using reverse postfix notation, e.g.,
+ 602 7 5 - 3 * +
+ Nonnegative numbers are entered using decimal notation. The
+ operators "+", "-", and "*" are supported. The unary operators
+ "even" and "odd" return the number one iff its one operand is even
+ or odd, respectively. Spaces must separate all words. Negative
+ numbers are not supported. */
+
+#include
+#include
+#include
+#include
+#include "definitions.h"
+
+
+/* Apply the binary function with operands obtained from the stack,
+ pushing the answer on the stack. Return nonzero upon success. */
+
+int apply_binary_function (number (*function) (number, number),
+ Stack* stack)
+{
+ number operand1, operand2;
+ if (empty_stack (*stack))
+ return 0;
+ operand2 = pop_stack (stack);
+ if (empty_stack (*stack))
+ return 0;
+ operand1 = pop_stack (stack);
+ push_stack (stack, (*function) (operand1, operand2));
+ destroy_number (operand1);
+ destroy_number (operand2);
+ return 1;
+}
+
+/* Apply the unary function with an operand obtained from the stack,
+ pushing the answer on the stack. Return nonzero upon success. */
+
+int apply_unary_function (number (*function) (number),
+ Stack* stack)
+{
+ number operand;
+ if (empty_stack (*stack))
+ return 0;
+ operand = pop_stack (stack);
+ push_stack (stack, (*function) (operand));
+ destroy_number (operand);
+ return 1;
+}
+
+int main ()
+{
+ char command_line[1000];
+ char* command_to_parse;
+ char* token;
+ Stack number_stack = create_stack ();
+
+ while (1) {
+ printf ("Please enter a postfix expression:\n");
+ command_to_parse = fgets (command_line, sizeof (command_line), stdin);
+ if (command_to_parse == NULL)
+ return 0;
+
+ token = strtok (command_to_parse, " \t\n");
+ command_to_parse = 0;
+ while (token != 0) {
+ if (isdigit (token[0]))
+ push_stack (&number_stack, string_to_number (token));
+ else if (((strcmp (token, "+") == 0) &&
+ !apply_binary_function (&add, &number_stack)) ||
+ ((strcmp (token, "-") == 0) &&
+ !apply_binary_function (&subtract, &number_stack)) ||
+ ((strcmp (token, "*") == 0) &&
+ !apply_binary_function (&product, &number_stack)) ||
+ ((strcmp (token, "even") == 0) &&
+ !apply_unary_function (&even, &number_stack)) ||
+ ((strcmp (token, "odd") == 0) &&
+ !apply_unary_function (&odd, &number_stack)))
+ return 1;
+ token = strtok (command_to_parse, " \t\n");
+ }
+ if (empty_stack (number_stack))
+ return 1;
+ else {
+ number answer = pop_stack (&number_stack);
+ printf ("%u\n", number_to_unsigned_int (answer));
+ destroy_number (answer);
+ clear_stack (&number_stack);
+ }
+ }
+
+ return 0;
+}
diff --git a/listings/appendix-a/definitions.h b/listings/appendix-a/definitions.h
new file mode 100644
index 0000000..cf9928c
--- /dev/null
+++ b/listings/appendix-a/definitions.h
@@ -0,0 +1,45 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#ifndef DEFINITIONS_H
+#define DEFINITIONS_H 1
+
+/* Implement a number using a linked list. */
+struct LinkedListNumber
+{
+ struct LinkedListNumber*
+ one_less_;
+};
+typedef struct LinkedListNumber* number;
+
+/* Implement a stack of number's as a linked list. Use 0 to represent
+ an empty stack. */
+struct StackElement
+{
+ number element_;
+ struct StackElement* next_;
+};
+typedef struct StackElement* Stack;
+
+/* Operate on the stack of numbers. */
+Stack create_stack ();
+int empty_stack (Stack stack);
+number pop_stack (Stack* stack);
+void push_stack (Stack* stack, number n);
+void clear_stack (Stack* stack);
+
+/* Operations on numbers. */
+number make_zero ();
+void destroy_number (number n);
+number add (number n1, number n2);
+number subtract (number n1, number n2);
+number product (number n1, number n2);
+number even (number n);
+number odd (number n);
+number string_to_number (char* char_number);
+unsigned number_to_unsigned_int (number n);
+
+#endif /* DEFINITIONS_H */
diff --git a/listings/appendix-a/hello.c b/listings/appendix-a/hello.c
new file mode 100644
index 0000000..d79324f
--- /dev/null
+++ b/listings/appendix-a/hello.c
@@ -0,0 +1,13 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+int main ()
+{
+ printf ("Hello, world.\n");
+ return 0;
+}
diff --git a/listings/appendix-a/malloc-use.c b/listings/appendix-a/malloc-use.c
new file mode 100644
index 0000000..348e6f4
--- /dev/null
+++ b/listings/appendix-a/malloc-use.c
@@ -0,0 +1,138 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+/* Use C's dynamic memory allocation functions. */
+
+/* Invoke the program using one command-line argument specifying the
+ size of an array. This array consists of pointers to (possibly)
+ allocated arrays.
+
+ When the programming is running, select among the following
+ commands:
+
+ o allocate memory: a
+ o deallocate memory: d
+ o read from memory: r
+ o write to memory: w
+ o quit: q
+
+ The user is respond for obeying (or disobeying the rules on dynamic
+ memory use. */
+
+#ifdef MTRACE
+#include
+#endif /* MTRACE */
+#include
+#include
+#include
+
+/* Allocate memory with the specified size, returning nonzero upon
+ success. */
+
+void allocate (char** array, size_t size)
+{
+ *array = malloc (size);
+}
+
+/* Deallocate memory. */
+
+void deallocate (char** array)
+{
+ free ((void*) *array);
+}
+
+/* Read from a position in memory. */
+
+void read_from_memory (char* array, int position)
+{
+ volatile char character = array[position];
+}
+
+/* Write to a position in memory. */
+
+void write_to_memory (char* array, int position)
+{
+ array[position] = 'a';
+}
+
+int main (int argc, char* argv[])
+{
+ char** array;
+ unsigned array_size;
+ char command[32];
+ unsigned array_index;
+ char command_letter;
+ int size_or_position;
+ int error = 0;
+
+#ifdef MTRACE
+ mtrace ();
+#endif /* MTRACE */
+
+ if (argc != 2) {
+ fprintf (stderr, "%s: array-size\n", argv[0]);
+ return 1;
+ }
+
+ array_size = strtoul (argv[1], 0, 0);
+ array = (char **) calloc (array_size, sizeof (char *));
+ assert (array != 0);
+
+ /* Follow the user's commands. */
+ while (!error) {
+ printf ("Please enter a command: ");
+ command_letter = getchar ();
+ assert (command_letter != EOF);
+ switch (command_letter) {
+
+ case 'a':
+ fgets (command, sizeof (command), stdin);
+ if (sscanf (command, "%u %i", &array_index, &size_or_position) == 2
+ && array_index < array_size)
+ allocate (&(array[array_index]), size_or_position);
+ else
+ error = 1;
+ break;
+
+ case 'd':
+ fgets (command, sizeof (command), stdin);
+ if (sscanf (command, "%u", &array_index) == 1
+ && array_index < array_size)
+ deallocate (&(array[array_index]));
+ else
+ error = 1;
+ break;
+
+ case 'r':
+ fgets (command, sizeof (command), stdin);
+ if (sscanf (command, "%u %i", &array_index, &size_or_position) == 2
+ && array_index < array_size)
+ read_from_memory (array[array_index], size_or_position);
+ else
+ error = 1;
+ break;
+
+ case 'w':
+ fgets (command, sizeof (command), stdin);
+ if (sscanf (command, "%u %i", &array_index, &size_or_position) == 2
+ && array_index < array_size)
+ write_to_memory (array[array_index], size_or_position);
+ else
+ error = 1;
+ break;
+
+ case 'q':
+ free ((void *) array);
+ return 0;
+
+ default:
+ error = 1;
+ }
+ }
+
+ free ((void *) array);
+ return 1;
+}
diff --git a/listings/appendix-a/number.c b/listings/appendix-a/number.c
new file mode 100644
index 0000000..c414c4b
--- /dev/null
+++ b/listings/appendix-a/number.c
@@ -0,0 +1,154 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+/* Operate on unary numbers. */
+
+#include
+#include
+#include
+#include "definitions.h"
+
+/* Create a number representing zero. */
+
+number make_zero ()
+{
+ return 0;
+}
+
+/* Return nonzero if the number represents zero. */
+
+int zerop (number n)
+{
+ return n == 0;
+}
+
+/* Decrease a positive number by one. */
+
+number decrement_number (number n)
+{
+ number answer;
+ assert (!zerop (n));
+ answer = n->one_less_;
+ free (n);
+ return answer;
+}
+
+/* Add 1 to a number. */
+
+number add_one (number n)
+{
+ number answer = malloc (sizeof (struct LinkedListNumber));
+ answer->one_less_ = n;
+ return answer;
+}
+
+/* Destroying a number. */
+
+void destroy_number (number n)
+{
+ while (!zerop (n))
+ n = decrement_number (n);
+}
+
+/* Copy a number. This function is only needed because of memory
+ allocation. */
+
+number copy_number (number n)
+{
+ number answer = make_zero ();
+ while (!zerop (n)) {
+ answer = add_one (answer);
+ n = n->one_less_;
+ }
+ return answer;
+}
+
+/* Add two numbers. */
+
+number add (number n1, number n2)
+{
+ number answer = copy_number (n2);
+ number addend = n1;
+ while (!zerop (addend)) {
+ answer = add_one (answer);
+ addend = addend->one_less_;
+ }
+ return answer;
+}
+
+/* Subtract a number from another. */
+
+number subtract (number n1, number n2)
+{
+ number answer = copy_number (n1);
+ number subtrahend = n2;
+ while (!zerop (subtrahend)) {
+ assert (!zerop (answer));
+ answer = decrement_number (answer);
+ subtrahend = subtrahend->one_less_;
+ }
+ return answer;
+}
+
+/* Return the product of two numbers. */
+
+number product (number n1, number n2)
+{
+ number answer = make_zero ();
+ number multiplicand = n1;
+ while (!zerop (multiplicand)) {
+ number answer2 = add (answer, n2);
+ destroy_number (answer);
+ answer = answer2;
+ multiplicand = multiplicand->one_less_;
+ }
+ return answer;
+}
+
+/* Return nonzero if number is even. */
+
+number even (number n)
+{
+ if (zerop (n))
+ return add_one (make_zero ());
+ else
+ return odd (n->one_less_);
+}
+
+/* Return nonzero if number is odd. */
+
+number odd (number n)
+{
+ if (zerop (n))
+ return make_zero ();
+ else
+ return even (n->one_less_);
+}
+
+/* Convert a string representing a decimal integer into a "number". */
+
+number string_to_number (char * char_number)
+{
+ number answer = make_zero ();
+ int num = strtoul (char_number, (char **) 0, 0);
+ while (num != 0) {
+ answer = add_one (answer);
+ --num;
+ }
+ return answer;
+}
+
+/* Convert a "number" into an "unsigned int". */
+
+unsigned number_to_unsigned_int (number n)
+{
+ unsigned answer = 0;
+ while (!zerop (n)) {
+ n = n->one_less_;
+ ++answer;
+ }
+ return answer;
+}
diff --git a/listings/appendix-a/stack.c b/listings/appendix-a/stack.c
new file mode 100644
index 0000000..e2974b0
--- /dev/null
+++ b/listings/appendix-a/stack.c
@@ -0,0 +1,61 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+/* Provide a stack of "number"s. */
+
+#include
+#include
+#include "definitions.h"
+
+/* Create an empty stack. */
+
+Stack create_stack ()
+{
+ return 0;
+}
+
+/* Return nonzero if the stack is empty. */
+
+int empty_stack (Stack stack)
+{
+ return stack == 0;
+}
+
+/* Remove the number at the top of a non-empty stack. If the stack is
+ empty, abort. */
+
+number pop_stack (Stack* stack)
+{
+ number answer;
+ Stack rest_of_stack;
+
+ assert (!empty_stack (*stack));
+ answer = (*stack)->element_;
+ rest_of_stack = (*stack)->next_;
+ free (*stack);
+ *stack = rest_of_stack;
+ return answer;
+}
+
+/* Add a number to the beginning of a stack. */
+
+void push_stack (Stack* stack, number n)
+{
+ Stack new_stack = malloc (sizeof (struct StackElement));
+ new_stack->element_ = n;
+ new_stack->next_ = *stack;
+ *stack = new_stack;
+}
+
+/* Remove all the stack's elements. */
+
+void clear_stack (Stack* stack)
+{
+ while (!empty_stack (*stack)) {
+ number top = pop_stack (stack);
+ destroy_number (top);
+ }
+}
diff --git a/listings/appendix-b/Makefile b/listings/appendix-b/Makefile
new file mode 100644
index 0000000..e631518
--- /dev/null
+++ b/listings/appendix-b/Makefile
@@ -0,0 +1,18 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS = read-file.o write-all.o
+LIBRARIES =
+PROGRAMS = create-file hexdump listdir lseek-huge timestamp write-args
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o *.a $(PROGRAMS)
diff --git a/listings/appendix-b/create-file.c b/listings/appendix-b/create-file.c
new file mode 100644
index 0000000..cccb6c6
--- /dev/null
+++ b/listings/appendix-b/create-file.c
@@ -0,0 +1,29 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+int main (int argc, char* argv[])
+{
+ /* The path at which to create the new file. */
+ char* path = argv[1];
+ /* The permissions for the new file. */
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+
+ /* Create the file. */
+ int fd = open (path, O_WRONLY | O_EXCL | O_CREAT, mode);
+ if (fd == -1) {
+ /* An error occurred. Print an error message and bail. */
+ perror ("open");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/listings/appendix-b/hexdump.c b/listings/appendix-b/hexdump.c
new file mode 100644
index 0000000..a25868f
--- /dev/null
+++ b/listings/appendix-b/hexdump.c
@@ -0,0 +1,42 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+int main (int argc, char* argv[])
+{
+ unsigned char buffer[16];
+ size_t offset = 0;
+ size_t bytes_read;
+ int i;
+
+ /* Open the file for reading. */
+ int fd = open (argv[1], O_RDONLY);
+
+ /* Read from the file, one chunk at a time. Continue until read
+ "comes up short", i.e. reads less than we asked for. This
+ indicates that we've hit the end of the file. */
+ do {
+ /* Read the next lines's worth of bytes. */
+ bytes_read = read (fd, buffer, sizeof (buffer));
+ /* Print the offset in the file, followed by the bytes themselves. */
+ printf ("0x%06x : ", offset);
+ for (i = 0; i < bytes_read; ++i)
+ printf ("%02x ", buffer[i]);
+ printf ("\n");
+ /* Keep count of our position in the file. */
+ offset += bytes_read;
+ }
+ while (bytes_read == sizeof (buffer));
+
+ /* All done. */
+ close (fd);
+ return 0;
+}
diff --git a/listings/appendix-b/listdir.c b/listings/appendix-b/listdir.c
new file mode 100644
index 0000000..0ebe73c
--- /dev/null
+++ b/listings/appendix-b/listdir.c
@@ -0,0 +1,83 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Return a string that describes the type of the file system entry PATH. */
+
+const char* get_file_type (const char* path)
+{
+ struct stat st;
+ lstat (path, &st);
+ if (S_ISLNK (st.st_mode))
+ return "symbolic link";
+ else if (S_ISDIR (st.st_mode))
+ return "directory";
+ else if (S_ISCHR (st.st_mode))
+ return "character device";
+ else if (S_ISBLK (st.st_mode))
+ return "block device";
+ else if (S_ISFIFO (st.st_mode))
+ return "fifo";
+ else if (S_ISSOCK (st.st_mode))
+ return "socket";
+ else if (S_ISREG (st.st_mode))
+ return "regular file";
+ else
+ /* Unexpected. Each entry should be one of the types above. */
+ assert (0);
+}
+
+int main (int argc, char* argv[])
+{
+ char* dir_path;
+ DIR* dir;
+ struct dirent* entry;
+ char entry_path[PATH_MAX + 1];
+ size_t path_len;
+
+ if (argc >= 2)
+ /* If a directory was specified on the command line, use it. */
+ dir_path = argv[1];
+ else
+ /* Otherwise, use the current directory. */
+ dir_path = ".";
+ /* Copy the directory path into entry_path. */
+ strncpy (entry_path, dir_path, sizeof (entry_path));
+ path_len = strlen (dir_path);
+ /* If the directory path doesn't end with a slash, append a slash. */
+ if (entry_path[path_len - 1] != '/') {
+ entry_path[path_len] = '/';
+ entry_path[path_len + 1] = '\0';
+ ++path_len;
+ }
+
+ /* Start the listing operation of the directory specified on the
+ command line. */
+ dir = opendir (dir_path);
+ /* Loop over all directory entries. */
+ while ((entry = readdir (dir)) != NULL) {
+ const char* type;
+ /* Build the path to the directory entry by appending the entry
+ name to the path name. */
+ strncpy (entry_path + path_len, entry->d_name,
+ sizeof (entry_path) - path_len);
+ /* Determine the type of the entry. */
+ type = get_file_type (entry_path);
+ /* Print the type and path of the entry. */
+ printf ("%-18s: %s\n", type, entry_path);
+ }
+
+ /* All done. */
+ closedir (dir);
+ return 0;
+}
diff --git a/listings/appendix-b/lseek-huge.c b/listings/appendix-b/lseek-huge.c
new file mode 100644
index 0000000..353494f
--- /dev/null
+++ b/listings/appendix-b/lseek-huge.c
@@ -0,0 +1,31 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+int main (int argc, char* argv[])
+{
+ int zero = 0;
+ const int megabyte = 1024 * 1024;
+
+ char* filename = argv[1];
+ size_t length = (size_t) atoi (argv[2]) * megabyte;
+
+ /* Open a new file. */
+ int fd = open (filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ /* Jump to one byte short of where we want the file to end. */
+ lseek (fd, length - 1, SEEK_SET);
+ /* Write a single zero byte. */
+ write (fd, &zero, 1);
+ /* All done. */
+ close (fd);
+
+ return 0;
+}
diff --git a/listings/appendix-b/read-file.c b/listings/appendix-b/read-file.c
new file mode 100644
index 0000000..2d74a35
--- /dev/null
+++ b/listings/appendix-b/read-file.c
@@ -0,0 +1,46 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Read the contents of FILENAME into a newly-allocated buffer. The
+ size of the buffer is stored in *LENGTH. Returns the buffer, which
+ the caller must free. If FILENAME doesn't correspond to a regular
+ file, returns NULL. */
+
+char* read_file (const char* filename, size_t* length)
+{
+ int fd;
+ struct stat file_info;
+ char* buffer;
+
+ /* Open the file. */
+ fd = open (filename, O_RDONLY);
+
+ /* Get information about the file. */
+ fstat (fd, &file_info);
+ *length = file_info.st_size;
+ /* Make sure the file is an ordinary file. */
+ if (!S_ISREG (file_info.st_mode)) {
+ /* It's not, so give up. */
+ close (fd);
+ return NULL;
+ }
+
+ /* Allocate a buffer large enough to hold the file's contents. */
+ buffer = (char*) malloc (*length);
+ /* Read the file into the buffer. */
+ read (fd, buffer, *length);
+
+ /* Finish up. */
+ close (fd);
+ return buffer;
+}
diff --git a/listings/appendix-b/timestamp.c b/listings/appendix-b/timestamp.c
new file mode 100644
index 0000000..778a76e
--- /dev/null
+++ b/listings/appendix-b/timestamp.c
@@ -0,0 +1,39 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Return a character string representing the current date and time. */
+
+char* get_timestamp ()
+{
+ time_t now = time (NULL);
+ return asctime (localtime (&now));
+}
+
+int main (int argc, char* argv[])
+{
+ /* The file to which to append the timestamp. */
+ char* filename = argv[1];
+ /* Get the current timestamp. */
+ char* timestamp = get_timestamp ();
+ /* Open the file for writing. If it exists, append to it;
+ otherwise, create a new file. */
+ int fd = open (filename, O_WRONLY | O_CREAT | O_APPEND, 0666);
+ /* Compute the length of the timestamp string. */
+ size_t length = strlen (timestamp);
+ /* Write the timestamp to the file. */
+ write (fd, timestamp, length);
+ /* All done. */
+ close (fd);
+ return 0;
+}
diff --git a/listings/appendix-b/write-all.c b/listings/appendix-b/write-all.c
new file mode 100644
index 0000000..dd13c81
--- /dev/null
+++ b/listings/appendix-b/write-all.c
@@ -0,0 +1,29 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+/* Write all of COUNT bytes from BUFFER to file descriptor FD.
+ Returns -1 on error, or the number of bytes written. */
+
+ssize_t write_all (int fd, const void* buffer, size_t count)
+{
+ size_t left_to_write = count;
+ while (left_to_write > 0) {
+ size_t written = write (fd, buffer, count);
+ if (written == -1)
+ /* An error occurred; bail. */
+ return -1;
+ else
+ /* Keep count of how much more we need to write. */
+ left_to_write -= written;
+ }
+ /* We should have written no more than COUNT bytes! */
+ assert (left_to_write == 0);
+ /* The number of bytes written is exactly COUNT. */
+ return count;
+}
diff --git a/listings/appendix-b/write-args.c b/listings/appendix-b/write-args.c
new file mode 100644
index 0000000..392a5fe
--- /dev/null
+++ b/listings/appendix-b/write-args.c
@@ -0,0 +1,58 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+int main (int argc, char* argv[])
+{
+ int fd;
+ struct iovec* vec;
+ struct iovec* vec_next;
+ int i;
+ /* We'll need a "buffer" containing a newline character. Use an
+ ordinary char variable for this. */
+ char newline = '\n';
+ /* The first command-line argument is the output filename. */
+ char* filename = argv[1];
+ /* Skip past the first two elements of the argument list. Element
+ zero is the name of this program, and element one is the output
+ filename. */
+ argc -= 2;
+ argv += 2;
+
+ /* Allocate an array of iovec elements. We'll need two for each
+ element of the argument list, one for the text itself and one for
+ a newline. */
+ vec = (struct iovec*) malloc (2 * argc * sizeof (struct iovec));
+
+ /* Loop over the argument list, building the iovec entries. */
+ vec_next = vec;
+ for (i = 0; i < argc; ++i) {
+ /* The first element is the text of the argument itself. */
+ vec_next->iov_base = argv[i];
+ vec_next->iov_len = strlen (argv[i]);
+ ++vec_next;
+ /* The second element is a single newline character. It's OK for
+ multiple elements of the struct iovec array to point to the
+ same region of memory. */
+ vec_next->iov_base = &newline;
+ vec_next->iov_len = 1;
+ ++vec_next;
+ }
+
+ /* Write the arguments to a file. */
+ fd = open (filename, O_WRONLY | O_CREAT);
+ writev (fd, vec, 2 * argc);
+ close (fd);
+
+ free (vec);
+ return 0;
+}
diff --git a/listings/chapter-1/Makefile b/listings/chapter-1/Makefile
new file mode 100644
index 0000000..0e85e08
--- /dev/null
+++ b/listings/chapter-1/Makefile
@@ -0,0 +1,21 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS = reciprocal.o
+LIBRARIES =
+PROGRAMS = main
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o $(LIBRARIES) $(PROGRAMS)
+
+# Additional dependencies.
+main: reciprocal.o
diff --git a/listings/chapter-1/main.c b/listings/chapter-1/main.c
new file mode 100644
index 0000000..4f39c78
--- /dev/null
+++ b/listings/chapter-1/main.c
@@ -0,0 +1,18 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include "reciprocal.hpp"
+
+int main (int argc, char **argv)
+{
+ int i;
+
+ i = atoi (argv[1]);
+ printf ("The reciprocal of %d is %g\n", i, reciprocal (i));
+ return 0;
+}
diff --git a/listings/chapter-1/reciprocal.cpp b/listings/chapter-1/reciprocal.cpp
new file mode 100644
index 0000000..3c04eb1
--- /dev/null
+++ b/listings/chapter-1/reciprocal.cpp
@@ -0,0 +1,15 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include "reciprocal.hpp"
+
+double reciprocal (int i) {
+ // I should be non-zero.
+ assert (i != 0);
+ return 1.0/i;
+}
+
diff --git a/listings/chapter-1/reciprocal.hpp b/listings/chapter-1/reciprocal.hpp
new file mode 100644
index 0000000..e7a09cd
--- /dev/null
+++ b/listings/chapter-1/reciprocal.hpp
@@ -0,0 +1,15 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern double reciprocal (int i);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/listings/chapter-10/Makefile b/listings/chapter-10/Makefile
new file mode 100644
index 0000000..c193fe3
--- /dev/null
+++ b/listings/chapter-10/Makefile
@@ -0,0 +1,21 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS = grep-dictionary.o temp-file.o
+LIBRARIES =
+PROGRAMS = pam setuid-test simpleid stat-perm
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o *.a $(PROGRAMS)
+
+# Additional dependencies.
+pam: LDLIBS += -lpam -lpam_misc
diff --git a/listings/chapter-10/grep-dictionary.c b/listings/chapter-10/grep-dictionary.c
new file mode 100644
index 0000000..9270344
--- /dev/null
+++ b/listings/chapter-10/grep-dictionary.c
@@ -0,0 +1,34 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+/* Returns a non-zero value if and only if the WORD appears in
+ /usr/dict/words. */
+
+int grep_for_word (const char* word)
+{
+ size_t length;
+ char* buffer;
+ int exit_code;
+
+ /* Build up the string `grep -x WORD /usr/dict/words'. Allocate the
+ string dynamically to avoid buffer overruns. */
+ length =
+ strlen ("grep -x ") + strlen (word) + strlen (" /usr/dict/words") + 1;
+ buffer = (char*) malloc (length);
+ sprintf (buffer, "grep -x %s /usr/dict/words", word);
+
+ /* Run the command. */
+ exit_code = system (buffer);
+ /* Free the buffer. */
+ free (buffer);
+ /* If grep returned zero, then the word was present in the
+ dictionary. */
+ return exit_code == 0;
+}
+
diff --git a/listings/chapter-10/pam.c b/listings/chapter-10/pam.c
new file mode 100644
index 0000000..f331418
--- /dev/null
+++ b/listings/chapter-10/pam.c
@@ -0,0 +1,29 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+int main ()
+{
+ pam_handle_t* pamh;
+ struct pam_conv pamc;
+
+ /* Set up the PAM conversation. */
+ pamc.conv = &misc_conv;
+ pamc.appdata_ptr = NULL;
+ /* Start a new authentication session. */
+ pam_start ("su", getenv ("USER"), &pamc, &pamh);
+ /* Authenticate the user. */
+ if (pam_authenticate (pamh, 0) != PAM_SUCCESS)
+ fprintf (stderr, "Authentication failed!\n");
+ else
+ fprintf (stderr, "Authentication OK.\n");
+ /* All done. */
+ pam_end (pamh, 0);
+ return 0;
+}
diff --git a/listings/chapter-10/setuid-test.c b/listings/chapter-10/setuid-test.c
new file mode 100644
index 0000000..407fd7a
--- /dev/null
+++ b/listings/chapter-10/setuid-test.c
@@ -0,0 +1,15 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+int main ()
+{
+ printf ("uid=%d euid=%d\n", (int) getuid (), (int) geteuid ());
+ return 0;
+}
+
diff --git a/listings/chapter-10/simpleid.c b/listings/chapter-10/simpleid.c
new file mode 100644
index 0000000..f5da553
--- /dev/null
+++ b/listings/chapter-10/simpleid.c
@@ -0,0 +1,17 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+int main()
+{
+ uid_t uid = geteuid ();
+ gid_t gid = getegid ();
+ printf ("uid=%d gid=%d\n", uid, gid);
+ return 0;
+}
diff --git a/listings/chapter-10/stat-perm.c b/listings/chapter-10/stat-perm.c
new file mode 100644
index 0000000..5eae66b
--- /dev/null
+++ b/listings/chapter-10/stat-perm.c
@@ -0,0 +1,21 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+int main (int argc, char* argv[])
+{
+ const char* const filename = argv[1];
+ struct stat buf;
+ /* Get file information. */
+ stat (filename, &buf);
+ /* If the permissions are set such that the file's owner can write
+ to it, print a message. */
+ if (buf.st_mode & S_IWUSR)
+ printf ("Owning user can write `%s'.\n", filename);
+ return 0;
+}
diff --git a/listings/chapter-10/temp-file.c b/listings/chapter-10/temp-file.c
new file mode 100644
index 0000000..252f5a7
--- /dev/null
+++ b/listings/chapter-10/temp-file.c
@@ -0,0 +1,82 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+/* Returns the file descriptor for a newly created temporary file.
+ The temporary file will be readable and writable by the effective
+ user ID of the current process but will not be readable or writable
+ by anybody else.
+
+ Returns -1 if the temporary file could not be created. */
+
+int secure_temp_file ()
+{
+ /* This file descriptor points to /dev/random and allows us to get a
+ good source of random bits. */
+ static int random_fd = -1;
+ /* A random integer. */
+ unsigned int random;
+ /* A buffer, used to convert from a numeric to a string
+ representation of random. This buffer has fixed size, meaning
+ that we potentially have a buffer overrun bug if the integers on
+ this machine have a *lot* of bits. */
+ char filename[128];
+ /* The file descriptor for the new temporary file. */
+ int fd;
+ /* Information about the newly created file. */
+ struct stat stat_buf;
+
+ /* If we haven't opened /dev/random, do so now. (This is not
+ threadsafe.) */
+ if (random_fd == -1) {
+ /* Open /dev/random. Note that we're assuming that /dev/random
+ really is a source of random bits, not a file full of zeros
+ placed there by an attacker. */
+ random_fd = open ("/dev/random", O_RDONLY);
+ /* If we couldn't open /dev/random, give up. */
+ if (random_fd == -1)
+ return -1;
+ }
+
+ /* Read an integer from /dev/random. */
+ if (read (random_fd, &random, sizeof (random)) !=
+ sizeof (random))
+ return -1;
+ /* Create a filename out of the random number. */
+ sprintf (filename, "/tmp/%u", random);
+ /* Try to open the file. */
+ fd = open (filename,
+ /* Use O_EXECL, even though it doesn't work under NFS. */
+ O_RDWR | O_CREAT | O_EXCL,
+ /* Make sure nobody else can read or write the file. */
+ S_IRUSR | S_IWUSR);
+ if (fd == -1)
+ return -1;
+
+ /* Call lstat on the file, to make sure that it is not a symbolic
+ link. */
+ if (lstat (filename, &stat_buf) == -1)
+ return -1;
+ /* If the file is not a regular file, someone has tried to trick
+ us. */
+ if (!S_ISREG (stat_buf.st_mode))
+ return -1;
+ /* If we don't own the file, someone else might remove it, read it,
+ or change it while we're looking at it. */
+ if (stat_buf.st_uid != geteuid () || stat_buf.st_gid != getegid ())
+ return -1;
+ /* If there are any more permission bits set on the file,
+ something's fishy. */
+ if ((stat_buf.st_mode & ~(S_IRUSR | S_IWUSR)) != 0)
+ return -1;
+
+ return fd;
+}
diff --git a/listings/chapter-11/Makefile b/listings/chapter-11/Makefile
new file mode 100644
index 0000000..57e28ba
--- /dev/null
+++ b/listings/chapter-11/Makefile
@@ -0,0 +1,41 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+### Configuration. ####################################################
+
+# C source files for the server.
+SOURCES = server.c module.c common.c main.c
+# Object files corresponding to source files.
+OBJECTS = $(SOURCES:.c=.o)
+# Server module shared library files.
+MODULES = diskfree.so issue.so processes.so time.so
+
+### Rules. ############################################################
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: server $(MODULES)
+
+# Clean up build products.
+clean:
+ rm -f $(OBJECTS) $(MODULES) server
+
+# The main server program. Link with -Wl,-export-dyanamic so
+# dynamically loaded modules can bind symbols in the program. Link in
+# libdl, which contains calls for dynamic loading.
+server: $(OBJECTS)
+ $(CC) $(CFLAGS) -Wl,-export-dynamic -o $@ $^ -ldl
+
+# All object files in the server depend on server.h. But use the
+# default rule for building object files from source files.
+$(OBJECTS): server.h
+
+# Rule for building module shared libraries from the corresponding
+# source files. Compile -fPIC and generate a shared object file.
+$(MODULES): \
+%.so: %.c server.h
+ $(CC) $(CFLAGS) -fPIC -shared -o $@ $<
diff --git a/listings/chapter-11/common.c b/listings/chapter-11/common.c
new file mode 100644
index 0000000..a13f5ed
--- /dev/null
+++ b/listings/chapter-11/common.c
@@ -0,0 +1,92 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "server.h"
+
+const char* program_name;
+
+int verbose;
+
+void* xmalloc (size_t size)
+{
+ void* ptr = malloc (size);
+ /* Abort if the allocation failed. */
+ if (ptr == NULL)
+ abort ();
+ else
+ return ptr;
+}
+
+void* xrealloc (void* ptr, size_t size)
+{
+ ptr = realloc (ptr, size);
+ /* Abort if the allocation failed. */
+ if (ptr == NULL)
+ abort ();
+ else
+ return ptr;
+}
+
+char* xstrdup (const char* s)
+{
+ char* copy = strdup (s);
+ /* Abort if the allocation failed. */
+ if (copy == NULL)
+ abort ();
+ else
+ return copy;
+}
+
+void system_error (const char* operation)
+{
+ /* Generate an error message for errno. */
+ error (operation, strerror (errno));
+}
+
+void error (const char* cause, const char* message)
+{
+ /* Print an error message to stderr. */
+ fprintf (stderr, "%s: error: (%s) %s\n", program_name, cause, message);
+ /* End the program. */
+ exit (1);
+}
+
+char* get_self_executable_directory ()
+{
+ int rval;
+ char link_target[1024];
+ char* last_slash;
+ size_t result_length;
+ char* result;
+
+ /* Read the target of the symbolic link /proc/self/exe. */
+ rval = readlink ("/proc/self/exe", link_target, sizeof (link_target) - 1);
+ if (rval == -1)
+ /* The call to readlink failed, so bail. */
+ abort ();
+ else
+ /* NUL-terminate the target. */
+ link_target[rval] = '\0';
+ /* We want to trim the name of the executable file, to obtain the
+ directory that contains it. Find the rightmost slash. */
+ last_slash = strrchr (link_target, '/');
+ if (last_slash == NULL || last_slash == link_target)
+ /* Something stange is going on. */
+ abort ();
+ /* Allocate a buffer to hold the resulting path. */
+ result_length = last_slash - link_target;
+ result = (char*) xmalloc (result_length + 1);
+ /* Copy the result. */
+ strncpy (result, link_target, result_length);
+ result[result_length] = '\0';
+ return result;
+}
diff --git a/listings/chapter-11/diskfree.c b/listings/chapter-11/diskfree.c
new file mode 100644
index 0000000..3769c55
--- /dev/null
+++ b/listings/chapter-11/diskfree.c
@@ -0,0 +1,67 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "server.h"
+
+/* HTML source for the start of the page we generate. */
+
+static char* page_start =
+ "\n"
+ " \n"
+ "
\n";
+
+/* HTML source for the end of the page we generate. */
+
+static char* page_end =
+ "
\n"
+ " \n"
+ "\n";
+
+void module_generate (int fd)
+{
+ pid_t child_pid;
+ int rval;
+
+ /* Write the start of the page. */
+ write (fd, page_start, strlen (page_start));
+ /* Fork a child process. */
+ child_pid = fork ();
+ if (child_pid == 0) {
+ /* This is the child process. */
+ /* Set up an argumnet list for the invocation of df. */
+ char* argv[] = { "/bin/df", "-h", NULL };
+
+ /* Duplicate stdout and stderr to send data to the client socket. */
+ rval = dup2 (fd, STDOUT_FILENO);
+ if (rval == -1)
+ system_error ("dup2");
+ rval = dup2 (fd, STDERR_FILENO);
+ if (rval == -1)
+ system_error ("dup2");
+ /* Run df to show the free space on mounted file systems. */
+ execv (argv[0], argv);
+ /* A call to execv does not return unless an error occurred. */
+ system_error ("execv");
+ }
+ else if (child_pid > 0) {
+ /* This is the parent process. Wait for the child process to
+ finish. */
+ rval = waitpid (child_pid, NULL, 0);
+ if (rval == -1)
+ system_error ("waitpid");
+ }
+ else
+ /* The call to fork failed. */
+ system_error ("fork");
+ /* Write the end of the page. */
+ write (fd, page_end, strlen (page_end));
+}
diff --git a/listings/chapter-11/issue.c b/listings/chapter-11/issue.c
new file mode 100644
index 0000000..110c994
--- /dev/null
+++ b/listings/chapter-11/issue.c
@@ -0,0 +1,77 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "server.h"
+
+/* HTML source for the start of the page we generate. */
+
+static char* page_start =
+ "\n"
+ " \n"
+ "
\n";
+
+/* HTML source for the end of the page we generate. */
+
+static char* page_end =
+ "
\n"
+ " \n"
+ "\n";
+
+/* HTML source for the page indicating there was a problem opening
+ /proc/issue. */
+
+static char* error_page =
+ "\n"
+ " \n"
+ "
Error: Could not open /proc/issue.
\n"
+ " \n"
+ "\n";
+
+/* HTML source indicating an error. */
+
+static char* error_message = "Error reading /proc/issue.";
+
+void module_generate (int fd)
+{
+ int input_fd;
+ struct stat file_info;
+ int rval;
+
+ /* Open /etc/issue. */
+ input_fd = open ("/etc/issue", O_RDONLY);
+ if (input_fd == -1)
+ system_error ("open");
+ /* Obtain file information about it. */
+ rval = fstat (input_fd, &file_info);
+
+ if (rval == -1)
+ /* Either we couldn't open the file or we couldn't read from it. */
+ write (fd, error_page, strlen (error_page));
+ else {
+ int rval;
+ off_t offset = 0;
+
+ /* Write the start of the page. */
+ write (fd, page_start, strlen (page_start));
+ /* Copy from /proc/issue to the client socket. */
+ rval = sendfile (fd, input_fd, &offset, file_info.st_size);
+ if (rval == -1)
+ /* Something went wrong sending the contents of /proc/issue.
+ Write an error message. */
+ write (fd, error_message, strlen (error_message));
+ /* End the page. */
+ write (fd, page_end, strlen (page_end));
+ }
+
+ close (input_fd);
+}
diff --git a/listings/chapter-11/main.c b/listings/chapter-11/main.c
new file mode 100644
index 0000000..37b610e
--- /dev/null
+++ b/listings/chapter-11/main.c
@@ -0,0 +1,165 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "server.h"
+
+/* Description of long options for getopt_long. */
+
+static const struct option long_options[] = {
+ { "address", 1, NULL, 'a' },
+ { "help", 0, NULL, 'h' },
+ { "module-dir", 1, NULL, 'm' },
+ { "port", 1, NULL, 'p' },
+ { "verbose", 0, NULL, 'v' },
+};
+
+/* Description of short options for getopt_long. */
+
+static const char* const short_options = "a:hm:p:v";
+
+/* Usage summary text. */
+
+static const char* const usage_template =
+ "Usage: %s [ options ]\n"
+ " -a, --address ADDR Bind to local address (by default, bind\n"
+ " to all local addresses).\n"
+ " -h, --help Print this information.\n"
+ " -m, --module-dir DIR Load modules from specified directory\n"
+ " (by default, use executable directory).\n"
+ " -p, --port PORT Bind to specified port.\n"
+ " -v, --verbose Print verbose messages.\n";
+
+/* Print usage information and exit. If IS_ERROR is non-zero, write to
+ stderr and use an error exit code. Otherwise, write to stdout and
+ use a non-error termination code. Does not return. */
+
+static void print_usage (int is_error)
+{
+ fprintf (is_error ? stderr : stdout, usage_template, program_name);
+ exit (is_error ? 1 : 0);
+}
+
+int main (int argc, char* const argv[])
+{
+ struct in_addr local_address;
+ uint16_t port;
+ int next_option;
+
+ /* Store the program name, which we'll use in error messages. */
+ program_name = argv[0];
+
+ /* Set defaults for options. Bind the server to all local addresses,
+ and assign an unused port automatically. */
+ local_address.s_addr = INADDR_ANY;
+ port = 0;
+ /* Don't print verbose messages. */
+ verbose = 0;
+ /* Load modules from the directory containing this executable. */
+ module_dir = get_self_executable_directory ();
+ assert (module_dir != NULL);
+
+ /* Parse options. */
+ do {
+ next_option =
+ getopt_long (argc, argv, short_options, long_options, NULL);
+ switch (next_option) {
+ case 'a':
+ /* User specified -a or --address. */
+ {
+ struct hostent* local_host_name;
+
+ /* Look up the host name the user specified. */
+ local_host_name = gethostbyname (optarg);
+ if (local_host_name == NULL || local_host_name->h_length == 0)
+ /* Could not resolve the name. */
+ error (optarg, "invalid host name");
+ else
+ /* Host name is OK, so use it. */
+ local_address.s_addr =
+ *((int*) (local_host_name->h_addr_list[0]));
+ }
+ break;
+
+ case 'h':
+ /* User specified -h or --help. */
+ print_usage (0);
+
+ case 'm':
+ /* User specified -m or --module-dir. */
+ {
+ struct stat dir_info;
+
+ /* Check that it exists. */
+ if (access (optarg, F_OK) != 0)
+ error (optarg, "module directory does not exist");
+ /* Check that it is accessible. */
+ if (access (optarg, R_OK | X_OK) != 0)
+ error (optarg, "module directory is not accessible");
+ /* Make sure that it is a directory. */
+ if (stat (optarg, &dir_info) != 0 || !S_ISDIR (dir_info.st_mode))
+ error (optarg, "not a directory");
+ /* It looks OK, so use it. */
+ module_dir = strdup (optarg);
+ }
+ break;
+
+ case 'p':
+ /* User specified -p or --port. */
+ {
+ long value;
+ char* end;
+
+ value = strtol (optarg, &end, 10);
+ if (*end != '\0')
+ /* The user specified non-digits in the port number. */
+ print_usage (1);
+ /* The port number needs to be converted to network (big endian)
+ byte order. */
+ port = (uint16_t) htons (value);
+ }
+ break;
+
+ case 'v':
+ /* User specified -v or --verbose. */
+ verbose = 1;
+ break;
+
+ case '?':
+ /* User specified an nrecognized option. */
+ print_usage (1);
+
+ case -1:
+ /* Done with options. */
+ break;
+
+ default:
+ abort ();
+ }
+ } while (next_option != -1);
+
+ /* This program takes no additional arguments. Issue an error if the
+ user specified any. */
+ if (optind != argc)
+ print_usage (1);
+
+ /* Print the module directory, if we're running verbose. */
+ if (verbose)
+ printf ("modules will be loaded from %s\n", module_dir);
+
+ /* Run the server. */
+ server_run (local_address, port);
+
+ return 0;
+}
diff --git a/listings/chapter-11/module.c b/listings/chapter-11/module.c
new file mode 100644
index 0000000..cdce06a
--- /dev/null
+++ b/listings/chapter-11/module.c
@@ -0,0 +1,65 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+
+#include "server.h"
+
+char* module_dir;
+
+struct server_module* module_open (const char* module_name)
+{
+ char* module_path;
+ void* handle;
+ void (* module_generate) (int);
+ struct server_module* module;
+
+ /* Construct the full path of the module shared library we'll try to
+ load. */
+ module_path =
+ (char*) xmalloc (strlen (module_dir) + strlen (module_name) + 2);
+ sprintf (module_path, "%s/%s", module_dir, module_name);
+
+ /* Attempt to open MODULE_PATH as a shared library. */
+ handle = dlopen (module_path, RTLD_NOW);
+ free (module_path);
+ if (handle == NULL) {
+ /* Failed; either this path doesn't exist, or it isn't a shared
+ library. */
+ return NULL;
+ }
+
+ /* Resolve the module_generate symbol from the shared library. */
+ module_generate = (void (*) (int)) dlsym (handle, "module_generate");
+ /* Make sure the symbol was found. */
+ if (module_generate == NULL) {
+ /* The symbol is missing. While this is a shared library, it
+ probably isn't a server module. Close up and indicate failure. */
+ dlclose (handle);
+ return NULL;
+ }
+
+ /* Allocate and initialize a server_module object. */
+ module = (struct server_module*) xmalloc (sizeof (struct server_module));
+ module->handle = handle;
+ module->name = xstrdup (module_name);
+ module->generate_function = module_generate;
+ /* Return it, indicating success. */
+ return module;
+}
+
+void module_close (struct server_module* module)
+{
+ /* Close the shared library. */
+ dlclose (module->handle);
+ /* Deallocate the module name. */
+ free ((char*) module->name);
+ /* Deallocate the module object. */
+ free (module);
+}
diff --git a/listings/chapter-11/server.c b/listings/chapter-11/server.c
new file mode 100644
index 0000000..1a33200
--- /dev/null
+++ b/listings/chapter-11/server.c
@@ -0,0 +1,302 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "server.h"
+
+/* HTTP response and header for a successful request. */
+
+static char* ok_response =
+ "HTTP/1.0 200 OK\n"
+ "Content-type: text/html\n"
+ "\n";
+
+/* HTTP response, header, and body indicating that the we didn't
+ understand the request. */
+
+static char* bad_request_response =
+ "HTTP/1.0 400 Bad Request\n"
+ "Content-type: text/html\n"
+ "\n"
+ "\n"
+ " \n"
+ "
Bad Request
\n"
+ "
This server did not understand your request.
\n"
+ " \n"
+ "\n";
+
+/* HTTP response, header, and body template indicating that the
+ requested document was not found. */
+
+static char* not_found_response_template =
+ "HTTP/1.0 404 Not Found\n"
+ "Content-type: text/html\n"
+ "\n"
+ "\n"
+ " \n"
+ "
Not Found
\n"
+ "
The requested URL %s was not found on this server.
\n"
+ " \n"
+ "\n";
+
+/* HTTP response, header, and body template indicating that the
+ method was not understood. */
+
+static char* bad_method_response_template =
+ "HTTP/1.0 501 Method Not Implemented\n"
+ "Content-type: text/html\n"
+ "\n"
+ "\n"
+ " \n"
+ "
Method Not Implemented
\n"
+ "
The method %s is not implemented by this server.
\n"
+ " \n"
+ "\n";
+
+/* Handler for SIGCHLD, to clean up child processes that have
+ terminated. */
+
+static void clean_up_child_process (int signal_number)
+{
+ int status;
+ wait (&status);
+}
+
+/* Process an HTTP "GET" request for PAGE, and send the results to the
+ file descriptor CONNECTION_FD. */
+
+static void handle_get (int connection_fd, const char* page)
+{
+ struct server_module* module = NULL;
+
+ /* Make sure the requested page begins with a slash and does not
+ contain any additional slashes -- we don't support any
+ subdirectories. */
+ if (*page == '/' && strchr (page + 1, '/') == NULL) {
+ char module_file_name[64];
+
+ /* The page name looks OK. Construct the module name by appending
+ ".so" to the page name. */
+ snprintf (module_file_name, sizeof (module_file_name),
+ "%s.so", page + 1);
+ /* Try to open the module. */
+ module = module_open (module_file_name);
+ }
+
+ if (module == NULL) {
+ /* Either the requested page was malformed, or we couldn't open a
+ module with the indicated name. Either way, return the HTTP
+ response 404, Not Found. */
+ char response[1024];
+
+ /* Generate the response message. */
+ snprintf (response, sizeof (response), not_found_response_template, page);
+ /* Send it to the client. */
+ write (connection_fd, response, strlen (response));
+ }
+ else {
+ /* The requested module was loaded successfully. */
+
+ /* Send the HTTP response indicating success, and the HTTP header
+ for an HTML page. */
+ write (connection_fd, ok_response, strlen (ok_response));
+ /* Invoke the module, which will generate HTML output and send it
+ to the client file descriptor. */
+ (*module->generate_function) (connection_fd);
+ /* We're done with the module. */
+ module_close (module);
+ }
+}
+
+/* Handle a client connection on the file descriptor CONNECTION_FD. */
+
+static void handle_connection (int connection_fd)
+{
+ char buffer[256];
+ ssize_t bytes_read;
+
+ /* Read some data from the client. */
+ bytes_read = read (connection_fd, buffer, sizeof (buffer) - 1);
+ if (bytes_read > 0) {
+ char method[sizeof (buffer)];
+ char url[sizeof (buffer)];
+ char protocol[sizeof (buffer)];
+
+ /* Some data was read successfully. NUL-terminate the buffer so
+ we can use string operations on it. */
+ buffer[bytes_read] = '\0';
+ /* The first line the client sends is the HTTP request, which is
+ composed of a method, the requested page, and the protocol
+ version. */
+ sscanf (buffer, "%s %s %s", method, url, protocol);
+ /* The client may send various header information following the
+ request. For this HTTP implementation, we don't care about it.
+ However, we need to read any data the client tries to send. Keep
+ on reading data until we get to the end of the header, which is
+ delimited by a blank line. HTTP specifies CR/LF as the line
+ delimiter. */
+ while (strstr (buffer, "\r\n\r\n") == NULL)
+ bytes_read = read (connection_fd, buffer, sizeof (buffer));
+ /* Make sure the last read didn't fail. If it did, there's a
+ problem with the connection, so give up. */
+ if (bytes_read == -1) {
+ close (connection_fd);
+ return;
+ }
+ /* Check the protocol field. We understand HTTP versions 1.0 and
+ 1.1. */
+ if (strcmp (protocol, "HTTP/1.0") && strcmp (protocol, "HTTP/1.1")) {
+ /* We don't understand this protocol. Report a bad response. */
+ write (connection_fd, bad_request_response,
+ sizeof (bad_request_response));
+ }
+ else if (strcmp (method, "GET")) {
+ /* This server only implements the GET method. The client
+ specified some other method, so report the failure. */
+ char response[1024];
+
+ snprintf (response, sizeof (response),
+ bad_method_response_template, method);
+ write (connection_fd, response, strlen (response));
+ }
+ else
+ /* A valid request. Process it. */
+ handle_get (connection_fd, url);
+ }
+ else if (bytes_read == 0)
+ /* The client closed the connection before sending any data.
+ Nothing to do. */
+ ;
+ else
+ /* The call to read failed. */
+ system_error ("read");
+}
+
+
+void server_run (struct in_addr local_address, uint16_t port)
+{
+ struct sockaddr_in socket_address;
+ int rval;
+ struct sigaction sigchld_action;
+ int server_socket;
+
+ /* Install a handler for SIGCHLD that cleans up child processes that
+ have terminated. */
+ memset (&sigchld_action, 0, sizeof (sigchld_action));
+ sigchld_action.sa_handler = &clean_up_child_process;
+ sigaction (SIGCHLD, &sigchld_action, NULL);
+
+ /* Create a TCP socket. */
+ server_socket = socket (PF_INET, SOCK_STREAM, 0);
+ if (server_socket == -1)
+ system_error ("socket");
+ /* Construct a socket address structure for the local address on
+ which we want to listen for connections. */
+ memset (&socket_address, 0, sizeof (socket_address));
+ socket_address.sin_family = AF_INET;
+ socket_address.sin_port = port;
+ socket_address.sin_addr = local_address;
+ /* Bind the socket to that address. */
+ rval = bind (server_socket, &socket_address, sizeof (socket_address));
+ if (rval != 0)
+ system_error ("bind");
+ /* Instruct the socket to accept connections. */
+ rval = listen (server_socket, 10);
+ if (rval != 0)
+ system_error ("listen");
+
+ if (verbose) {
+ /* In verbose mode, display the local address and port number
+ we're listening on. */
+ socklen_t address_length;
+
+ /* Find the socket's local address. */
+ address_length = sizeof (socket_address);
+ rval = getsockname (server_socket, &socket_address, &address_length);
+ assert (rval == 0);
+ /* Print a message. The port number needs to be converted from
+ network byte order (big endian) to host byte order. */
+ printf ("server listening on %s:%d\n",
+ inet_ntoa (socket_address.sin_addr),
+ (int) ntohs (socket_address.sin_port));
+ }
+
+ /* Loop forever, handling connections. */
+ while (1) {
+ struct sockaddr_in remote_address;
+ socklen_t address_length;
+ int connection;
+ pid_t child_pid;
+
+ /* Accept a connection. This call blocks until a connection is
+ ready. */
+ address_length = sizeof (remote_address);
+ connection = accept (server_socket, &remote_address, &address_length);
+ if (connection == -1) {
+ /* The call to accept failed. */
+ if (errno == EINTR)
+ /* The call was interrupted by a signal. Try again. */
+ continue;
+ else
+ /* Something else went wrong. */
+ system_error ("accept");
+ }
+
+ /* We have a connection. Print a message if we're running in
+ verbose mode. */
+ if (verbose) {
+ socklen_t address_length;
+
+ /* Get the remote address of the connection. */
+ address_length = sizeof (socket_address);
+ rval = getpeername (connection, &socket_address, &address_length);
+ assert (rval == 0);
+ /* Print a message. */
+ printf ("connection accepted from %s\n",
+ inet_ntoa (socket_address.sin_addr));
+ }
+
+ /* Fork a child process to handle the connection. */
+ child_pid = fork ();
+ if (child_pid == 0) {
+ /* This is the child process. It shouldn't use stdin or stdout,
+ so close them. */
+ close (STDIN_FILENO);
+ close (STDOUT_FILENO);
+ /* Also this child process shouldn't do anything with the
+ listening socket. */
+ close (server_socket);
+ /* Handle a request from the connection. We have our own copy
+ of the connected socket descriptor. */
+ handle_connection (connection);
+ /* All done; close the connection socket, and end the child
+ process. */
+ close (connection);
+ exit (0);
+ }
+ else if (child_pid > 0) {
+ /* This is the parent process. The child process handles the
+ connection, so we don't need our copy of the connected socket
+ descriptor. Close it. Then continue with the loop and
+ accept another connection. */
+ close (connection);
+ }
+ else
+ /* Call to fork failed. */
+ system_error ("fork");
+ }
+}
diff --git a/listings/chapter-11/server.h b/listings/chapter-11/server.h
new file mode 100644
index 0000000..00763f7
--- /dev/null
+++ b/listings/chapter-11/server.h
@@ -0,0 +1,74 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#ifndef SERVER_H
+#define SERVER_H
+
+#include
+#include
+
+/*** Symbols defined in common.c. ************************************/
+
+/* The name of this program. */
+extern const char* program_name;
+
+/* If non-zero, print verbose messages. */
+extern int verbose;
+
+/* Like malloc, except aborts the program if allocation fails. */
+extern void* xmalloc (size_t size);
+
+/* Like realloc, except aborts the program if allocation fails. */
+extern void* xrealloc (void* ptr, size_t size);
+
+/* Like strdup, except aborts the program if allocation fails. */
+extern char* xstrdup (const char* s);
+
+/* Print an error message for a failed call OPERATION, using the value
+ of errno, and end the program. */
+extern void system_error (const char* operation);
+
+/* Print an error message for failure involving CAUSE, including a
+ descriptive MESSAGE, and end the program. */
+extern void error (const char* cause, const char* message);
+
+/* Return the directory containing the running program's executable.
+ The return value is a memory buffer which the caller must deallocate
+ using free. This function calls abort on failure. */
+extern char* get_self_executable_directory ();
+
+
+/*** Symbols defined in module.c **************************************/
+
+/* An instance of a loaded server module. */
+struct server_module {
+ /* The shared library handle corresponding to the loaded module. */
+ void* handle;
+ /* A name describing the module. */
+ const char* name;
+ /* The function which generates the HTML results for this module. */
+ void (* generate_function) (int);
+};
+
+/* The directory from which modules are loaded. */
+extern char* module_dir;
+
+/* Attempt to load a server module with the name MODULE_PATH. If a
+ server module exists with this path, loads the module and returns a
+ server_module structure representing it. Otherwise, returns NULL. */
+extern struct server_module* module_open (const char* module_path);
+
+/* Close a server module and deallocate the MODULE object. */
+extern void module_close (struct server_module* module);
+
+
+/*** Symbols defined in server.c. ************************************/
+
+/* Run the server on LOCAL_ADDRESS and PORT. */
+extern void server_run (struct in_addr local_address, uint16_t port);
+
+
+#endif /* SERVER_H */
diff --git a/listings/chapter-11/time.c b/listings/chapter-11/time.c
new file mode 100644
index 0000000..59dd736
--- /dev/null
+++ b/listings/chapter-11/time.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+
+#include "server.h"
+
+/* A template for the HTML page this module generates. */
+
+static char* page_template =
+ "\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "
The current time is %s.
\n"
+ " \n"
+ "\n";
+
+void module_generate (int fd)
+{
+ struct timeval tv;
+ struct tm* ptm;
+ char time_string[40];
+ FILE* fp;
+
+ /* Obtain the time of day, and convert it to a tm struct. */
+ gettimeofday (&tv, NULL);
+ ptm = localtime (&tv.tv_sec);
+ /* Format the date and time, down to a single second. */
+ strftime (time_string, sizeof (time_string), "%H:%M:%S", ptm);
+
+ /* Create a stream corresponding to the client socket file
+ descriptor. */
+ fp = fdopen (fd, "w");
+ assert (fp != NULL);
+ /* Generate the HTML output. */
+ fprintf (fp, page_template, time_string);
+ /* All done; flush the stream. */
+ fflush (fp);
+}
diff --git a/listings/chapter-2/Makefile b/listings/chapter-2/Makefile
new file mode 100644
index 0000000..21398c4
--- /dev/null
+++ b/listings/chapter-2/Makefile
@@ -0,0 +1,33 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001, 2004 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS = readfile.o temp_file.o test.o
+LIBRARIES = libtest.a libtest.so
+PROGRAMS = app arglist client getopt_long print-env tifftest
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o *.a $(PROGRAMS)
+
+# Additional dependencies.
+main: reciprocal.o
+
+libtest.a: test.o
+ ar cr $@ $?
+
+libtest.so: test.c
+ $(CC) $(CFLAGS) -fPIC -shared $< -o $@
+
+app: LDLIBS += -L. -ltest
+app: app.c libtest.a
+
+tifftest: CFLAGS += -static
+tifftest: LDLIBS += -ltiff -ljpeg -lz -lm
diff --git a/listings/chapter-2/app.c b/listings/chapter-2/app.c
new file mode 100644
index 0000000..c52acd7
--- /dev/null
+++ b/listings/chapter-2/app.c
@@ -0,0 +1,12 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+extern int f ();
+
+int main ()
+{
+ return f ();
+}
diff --git a/listings/chapter-2/arglist.c b/listings/chapter-2/arglist.c
new file mode 100644
index 0000000..e56f9fb
--- /dev/null
+++ b/listings/chapter-2/arglist.c
@@ -0,0 +1,24 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+int main (int argc, char* argv[])
+{
+ printf ("The name of this program is `%s'.\n", argv[0]);
+ printf ("This program was invoked with %d arguments.\n", argc - 1);
+
+ /* Were any command-line arguments specified? */
+ if (argc > 1) {
+ /* Yes, print them. */
+ int i;
+ printf ("The arguments are:\n");
+ for (i = 1; i < argc; ++i)
+ printf (" %s\n", argv[i]);
+ }
+
+ return 0;
+}
diff --git a/listings/chapter-2/client.c b/listings/chapter-2/client.c
new file mode 100644
index 0000000..68fbc70
--- /dev/null
+++ b/listings/chapter-2/client.c
@@ -0,0 +1,22 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+int main ()
+{
+ char* server_name = getenv ("SERVER_NAME");
+ if (server_name == NULL)
+ /* The SERVER_NAME environment variable was not set. Use the
+ default. */
+ server_name = "server.my-company.com";
+
+ printf ("accessing server %s\n", server_name);
+ /* Access the server here... */
+
+ return 0;
+}
diff --git a/listings/chapter-2/getopt_long.c b/listings/chapter-2/getopt_long.c
new file mode 100644
index 0000000..a607cb1
--- /dev/null
+++ b/listings/chapter-2/getopt_long.c
@@ -0,0 +1,100 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+/* The name of this program. */
+const char* program_name;
+
+/* Prints usage information for this program to STREAM (typically
+ stdout or stderr), and exit the program with EXIT_CODE. Does not
+ return. */
+
+void print_usage (FILE* stream, int exit_code)
+{
+ fprintf (stream, "Usage: %s options [ inputfile ... ]\n", program_name);
+ fprintf (stream,
+ " -h --help Display this usage information.\n"
+ " -o --output filename Write output to file.\n"
+ " -v --verbose Print verbose messages.\n");
+ exit (exit_code);
+}
+
+/* Main program entry point. ARGC conains number of argument list
+ elements; ARGV is an array of pointers to them. */
+
+int main (int argc, char* argv[])
+{
+ int next_option;
+
+ /* A string listing valid short options letters. */
+ const char* const short_options = "ho:v";
+ /* An array describing valid long options. */
+ const struct option long_options[] = {
+ { "help", 0, NULL, 'h' },
+ { "output", 1, NULL, 'o' },
+ { "verbose", 0, NULL, 'v' },
+ { NULL, 0, NULL, 0 } /* Required at end of array. */
+ };
+
+ /* The name of the file to receive program output, or NULL for
+ standard output. */
+ const char* output_filename = NULL;
+ /* Whether to display verbose messages. */
+ int verbose = 0;
+
+ /* Remember the name of the program, to incorporate in messages.
+ The name is stored in argv[0]. */
+ program_name = argv[0];
+
+ do {
+ next_option = getopt_long (argc, argv, short_options,
+ long_options, NULL);
+ switch (next_option)
+ {
+ case 'h': /* -h or --help */
+ /* User has requested usage information. Print it to standard
+ output, and exit with exit code zero (normal termination). */
+ print_usage (stdout, 0);
+
+ case 'o': /* -o or --output */
+ /* This option takes an argument, the name of the output file. */
+ output_filename = optarg;
+ break;
+
+ case 'v': /* -v or --verbose */
+ verbose = 1;
+ break;
+
+ case '?': /* The user specified an invalid option. */
+ /* Print usage information to standard error, and exit with exit
+ code one (indicating abonormal termination). */
+ print_usage (stderr, 1);
+
+ case -1: /* Done with options. */
+ break;
+
+ default: /* Something else: unexpected. */
+ abort ();
+ }
+ }
+ while (next_option != -1);
+
+ /* Done with options. OPTIND points to first non-option argument.
+ For demonstration purposes, print them if the verbose option was
+ specified. */
+ if (verbose) {
+ int i;
+ for (i = optind; i < argc; ++i)
+ printf ("Argument: %s\n", argv[i]);
+ }
+
+ /* The main program goes here. */
+
+ return 0;
+}
diff --git a/listings/chapter-2/print-env.c b/listings/chapter-2/print-env.c
new file mode 100644
index 0000000..3ac1caf
--- /dev/null
+++ b/listings/chapter-2/print-env.c
@@ -0,0 +1,18 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+/* The ENVIRON variable contains the environment. */
+extern char** environ;
+
+int main ()
+{
+ char** var;
+ for (var = environ; *var != NULL; ++var)
+ printf ("%s\n", *var);
+ return 0;
+}
diff --git a/listings/chapter-2/readfile.c b/listings/chapter-2/readfile.c
new file mode 100644
index 0000000..d021487
--- /dev/null
+++ b/listings/chapter-2/readfile.c
@@ -0,0 +1,41 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+char* read_from_file (const char* filename, size_t length)
+{
+ char* buffer;
+ int fd;
+ ssize_t bytes_read;
+
+ /* Allocate the buffer. */
+ buffer = (char*) malloc (length);
+ if (buffer == NULL)
+ return NULL;
+ /* Open the file. */
+ fd = open (filename, O_RDONLY);
+ if (fd == -1) {
+ /* open failed. Deallocate buffer before returning. */
+ free (buffer);
+ return NULL;
+ }
+ /* Read the data. */
+ bytes_read = read (fd, buffer, length);
+ if (bytes_read != length) {
+ /* read failed. Deallocate buffer and close fd before returning. */
+ free (buffer);
+ close (fd);
+ return NULL;
+ }
+ /* Everything's fine. Close the file and return the buffer. */
+ close (fd);
+ return buffer;
+}
diff --git a/listings/chapter-2/temp_file.c b/listings/chapter-2/temp_file.c
new file mode 100644
index 0000000..277bb34
--- /dev/null
+++ b/listings/chapter-2/temp_file.c
@@ -0,0 +1,57 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+/* A handle for a temporary file created with write_temp_file. In
+ this implementation, it's just a file descriptor. */
+typedef int temp_file_handle;
+
+/* Writes LENGTH bytes from BUFFER into a temporary file. The
+ temporary file is immediately unlinked. Returns a handle to the
+ temporary file. */
+
+temp_file_handle write_temp_file (char* buffer, size_t length)
+{
+ /* Create the filename and file. The XXXXXX will be replaced with
+ characters that make the filename unique. */
+ char temp_filename[] = "/tmp/temp_file.XXXXXX";
+ int fd = mkstemp (temp_filename);
+ /* Unlink the file immediately, so that it will be removed when the
+ file descriptor is closed. */
+ unlink (temp_filename);
+ /* Write the number of bytes to the file first. */
+ write (fd, &length, sizeof (length));
+ /* Now write the data itself. */
+ write (fd, buffer, length);
+ /* Use the file descriptor as the handle for the temporary file. */
+ return fd;
+}
+
+/* Reads the contents of a temporary file TEMP_FILE created with
+ write_temp_file. The return value is a newly-allocated buffer of
+ those contents, which the caller must deallocate with free.
+ *LENGTH is set to the size of the contents, in bytes. The
+ temporary file is removed. */
+
+char* read_temp_file (temp_file_handle temp_file, size_t* length)
+{
+ char* buffer;
+ /* The TEMP_FILE handle is a file descriptor to the temporary file. */
+ int fd = temp_file;
+ /* Rewind to the beginning of the file. */
+ lseek (fd, 0, SEEK_SET);
+ /* Read the size of the data in the temporary file. */
+ read (fd, length, sizeof (*length));
+ /* Allocate a buffer and read the data. */
+ buffer = (char*) malloc (*length);
+ read (fd, buffer, *length);
+ /* Close the file descriptor, which will cause the temporary file to
+ go away. */
+ close (fd);
+ return buffer;
+}
diff --git a/listings/chapter-2/test.c b/listings/chapter-2/test.c
new file mode 100644
index 0000000..52d6a82
--- /dev/null
+++ b/listings/chapter-2/test.c
@@ -0,0 +1,10 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+int f ()
+{
+ return 3;
+}
diff --git a/listings/chapter-2/tifftest.c b/listings/chapter-2/tifftest.c
new file mode 100644
index 0000000..f51e074
--- /dev/null
+++ b/listings/chapter-2/tifftest.c
@@ -0,0 +1,16 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+int main (int argc, char** argv)
+{
+ TIFF* tiff;
+ tiff = TIFFOpen (argv[1], "r");
+ TIFFClose (tiff);
+ return 0;
+}
diff --git a/listings/chapter-3/Makefile b/listings/chapter-3/Makefile
new file mode 100644
index 0000000..c3a1bc6
--- /dev/null
+++ b/listings/chapter-3/Makefile
@@ -0,0 +1,18 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS =
+LIBRARIES =
+PROGRAMS = fork-exec fork print-pid sigchld sigusr1 system zombie
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o *.a $(PROGRAMS)
diff --git a/listings/chapter-3/fork-exec.c b/listings/chapter-3/fork-exec.c
new file mode 100644
index 0000000..d86dc0f
--- /dev/null
+++ b/listings/chapter-3/fork-exec.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+
+/* Spawn a child process running a new program. PROGRAM is the name
+ of the program to run; the path will be searched for this program.
+ ARG_LIST is a NULL-terminated list of character strings to be
+ passed as the program's argument list. Returns the process id of
+ the spawned process. */
+
+int spawn (char* program, char** arg_list)
+{
+ pid_t child_pid;
+
+ /* Duplicate this process. */
+ child_pid = fork ();
+ if (child_pid != 0)
+ /* This is the parent process. */
+ return child_pid;
+ else {
+ /* Now execute PROGRAM, searching for it in the path. */
+ execvp (program, arg_list);
+ /* The execvp function returns only if an error occurs. */
+ fprintf (stderr, "an error occurred in execvp\n");
+ abort ();
+ }
+}
+
+int main ()
+{
+ /* The argument list to pass to the "ls" command. */
+ char* arg_list[] = {
+ "ls", /* argv[0], the name of the program. */
+ "-l",
+ "/",
+ NULL /* The argument list must end with a NULL. */
+ };
+
+ /* Spawn a child process running the "ls" command. Ignore the
+ returned child process id. */
+ spawn ("ls", arg_list);
+
+ printf ("done with main program\n");
+
+ return 0;
+}
diff --git a/listings/chapter-3/fork.c b/listings/chapter-3/fork.c
new file mode 100644
index 0000000..a9717d3
--- /dev/null
+++ b/listings/chapter-3/fork.c
@@ -0,0 +1,26 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+int main ()
+{
+ pid_t child_pid;
+
+ printf ("the main program process id is %d\n", (int) getpid ());
+
+ child_pid = fork ();
+ if (child_pid != 0) {
+ printf ("this is the parent process, with id %d\n", (int) getpid ());
+ printf ("the child's process id is %d\n", (int) child_pid);
+ }
+ else
+ printf ("this is the child process, with id %d\n", (int) getpid ());
+
+ return 0;
+}
diff --git a/listings/chapter-3/print-pid.c b/listings/chapter-3/print-pid.c
new file mode 100644
index 0000000..55585fe
--- /dev/null
+++ b/listings/chapter-3/print-pid.c
@@ -0,0 +1,15 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+int main ()
+{
+ printf ("The process id is %d\n", (int) getpid ());
+ printf ("The parent process id is %d\n", (int) getppid ());
+ return 0;
+}
diff --git a/listings/chapter-3/sigchld.c b/listings/chapter-3/sigchld.c
new file mode 100644
index 0000000..753e3b7
--- /dev/null
+++ b/listings/chapter-3/sigchld.c
@@ -0,0 +1,35 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+
+sig_atomic_t child_exit_status;
+
+void clean_up_child_process (int signal_number)
+{
+ /* Clean up the child process. */
+ int status;
+ wait (&status);
+ /* Store its exit status in a global variable. */
+ child_exit_status = status;
+}
+
+int main ()
+{
+ /* Handle SIGCHLD by calling clean_up_child_process. */
+ struct sigaction sigchld_action;
+ memset (&sigchld_action, 0, sizeof (sigchld_action));
+ sigchld_action.sa_handler = &clean_up_child_process;
+ sigaction (SIGCHLD, &sigchld_action, NULL);
+
+ /* Now do things, including forking a child process. */
+ /* ... */
+
+ return 0;
+}
diff --git a/listings/chapter-3/sigusr1.c b/listings/chapter-3/sigusr1.c
new file mode 100644
index 0000000..6a39834
--- /dev/null
+++ b/listings/chapter-3/sigusr1.c
@@ -0,0 +1,32 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+sig_atomic_t sigusr1_count = 0;
+
+void handler (int signal_number)
+{
+ ++sigusr1_count;
+}
+
+int main ()
+{
+ struct sigaction sa;
+ memset (&sa, 0, sizeof (sa));
+ sa.sa_handler = &handler;
+ sigaction (SIGUSR1, &sa, NULL);
+
+ /* Do some lengthy stuff here. */
+ /* ... */
+
+ printf ("SIGUSR1 was raised %d times\n", sigusr1_count);
+ return 0;
+}
diff --git a/listings/chapter-3/system.c b/listings/chapter-3/system.c
new file mode 100644
index 0000000..69e762c
--- /dev/null
+++ b/listings/chapter-3/system.c
@@ -0,0 +1,15 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+int main ()
+{
+ int return_value;
+ return_value = system ("ls -l /");
+ return return_value;
+}
+
diff --git a/listings/chapter-3/zombie.c b/listings/chapter-3/zombie.c
new file mode 100644
index 0000000..c0ec142
--- /dev/null
+++ b/listings/chapter-3/zombie.c
@@ -0,0 +1,26 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+int main ()
+{
+ pid_t child_pid;
+
+ /* Create a child process. */
+ child_pid = fork ();
+ if (child_pid > 0) {
+ /* This is the parent process. Sleep for a minute. */
+ sleep (60);
+ }
+ else {
+ /* This is the child process. Exit immediately. */
+ exit (0);
+ }
+ return 0;
+}
diff --git a/listings/chapter-4/Makefile b/listings/chapter-4/Makefile
new file mode 100644
index 0000000..f068b08
--- /dev/null
+++ b/listings/chapter-4/Makefile
@@ -0,0 +1,23 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS = cleanup.o condvar.o critical-section.o cxx-exit.o \
+ job-queue1.o job-queue2.o job-queue3.o spin-condvar.o
+LIBRARIES =
+PROGRAMS = detached primes thread-create thread-create2 \
+ thread-pid tsd
+
+# Link programs with the pthread library.
+LDLIBS += -lpthread
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o *.a $(PROGRAMS)
diff --git a/listings/chapter-4/cleanup.c b/listings/chapter-4/cleanup.c
new file mode 100644
index 0000000..b35ebb9
--- /dev/null
+++ b/listings/chapter-4/cleanup.c
@@ -0,0 +1,39 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+/* Allocate a temporary buffer. */
+
+void* allocate_buffer (size_t size)
+{
+ return malloc (size);
+}
+
+/* Deallocate a temporary buffer. */
+
+void deallocate_buffer (void* buffer)
+{
+ free (buffer);
+}
+
+void do_some_work ()
+{
+ /* Allocate a temporary buffer. */
+ void* temp_buffer = allocate_buffer (1024);
+ /* Register a cleanup handler for this buffer, to deallocate it in
+ case the thread exits or is cancelled. */
+ pthread_cleanup_push (deallocate_buffer, temp_buffer);
+
+ /* Do some work here that might call pthread_exit or might be
+ cancelled... */
+
+ /* Unregister the cleanup handler. Since we pass a non-zero value,
+ this actually performs the cleanup by calling
+ deallocate_buffer. */
+ pthread_cleanup_pop (1);
+}
diff --git a/listings/chapter-4/condvar.c b/listings/chapter-4/condvar.c
new file mode 100644
index 0000000..3c1ec7d
--- /dev/null
+++ b/listings/chapter-4/condvar.c
@@ -0,0 +1,62 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+extern void do_work ();
+
+int thread_flag;
+pthread_cond_t thread_flag_cv;
+pthread_mutex_t thread_flag_mutex;
+
+void initialize_flag ()
+{
+ /* Initialize the mutex and condition variable. */
+ pthread_mutex_init (&thread_flag_mutex, NULL);
+ pthread_cond_init (&thread_flag_cv, NULL);
+ /* Initialize the flag value. */
+ thread_flag = 0;
+}
+
+/* Calls do_work repeatedly while the thread flag is set; blocks if
+ the flag is clear. */
+
+void* thread_function (void* thread_arg)
+{
+ /* Loop infinitely. */
+ while (1) {
+ /* Lock the mutex before accessing the flag value. */
+ pthread_mutex_lock (&thread_flag_mutex);
+ while (!thread_flag)
+ /* The flag is clear. Wait for a signal on the condition
+ variable, indicating the flag value has changed. When the
+ signal arrives and this thread unblocks, loop and check the
+ flag again. */
+ pthread_cond_wait (&thread_flag_cv, &thread_flag_mutex);
+ /* When we've gotten here, we know the flag must be set. Unlock
+ the mutex. */
+ pthread_mutex_unlock (&thread_flag_mutex);
+ /* Do some work. */
+ do_work ();
+ }
+ return NULL;
+}
+
+/* Sets the value of the thread flag to FLAG_VALUE. */
+
+void set_thread_flag (int flag_value)
+{
+ /* Lock the mutex before accessing the flag value. */
+ pthread_mutex_lock (&thread_flag_mutex);
+ /* Set the flag value, and then signal in case thread_function is
+ blocked, waiting for the flag to become set. However,
+ thread_function can't actually check the flag until the mutex is
+ unlocked. */
+ thread_flag = flag_value;
+ pthread_cond_signal (&thread_flag_cv);
+ /* Unlock the mutex. */
+ pthread_mutex_unlock (&thread_flag_mutex);
+}
diff --git a/listings/chapter-4/critical-section.c b/listings/chapter-4/critical-section.c
new file mode 100644
index 0000000..6f90eed
--- /dev/null
+++ b/listings/chapter-4/critical-section.c
@@ -0,0 +1,36 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+/* An array of balances in accounts, indexed by account number. */
+
+float* account_balances;
+
+/* Transfer DOLLARS from account FROM_ACCT to account TO_ACCT. Return
+ 0 if the transaction succeeded, or 1 if the balance FROM_ACCT is
+ too small. */
+
+int process_transaction (int from_acct, int to_acct, float dollars)
+{
+ int old_cancel_state;
+
+ /* Check the balance in FROM_ACCT. */
+ if (account_balances[from_acct] < dollars)
+ return 1;
+
+ /* Begin critical section. */
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cancel_state);
+ /* Move the money. */
+ account_balances[to_acct] += dollars;
+ account_balances[from_acct] -= dollars;
+ /* End critical section. */
+ pthread_setcancelstate (old_cancel_state, NULL);
+
+ return 0;
+}
diff --git a/listings/chapter-4/cxx-exit.cpp b/listings/chapter-4/cxx-exit.cpp
new file mode 100644
index 0000000..a82d2f3
--- /dev/null
+++ b/listings/chapter-4/cxx-exit.cpp
@@ -0,0 +1,52 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+extern bool should_exit_thread_immediately ();
+
+class ThreadExitException
+{
+public:
+ /* Create an exception signalling thread exit with RETURN_VALUE. */
+ ThreadExitException (void* return_value)
+ : thread_return_value_ (return_value)
+ {
+ }
+
+ /* Actually exit the thread, using the return value provided in the
+ constructor. */
+ void* DoThreadExit ()
+ {
+ pthread_exit (thread_return_value_);
+ }
+
+private:
+ /* The return value that will be used when exiting the thread. */
+ void* thread_return_value_;
+};
+
+void do_some_work ()
+{
+ while (1) {
+ /* Do some useful things here... */
+
+ if (should_exit_thread_immediately ())
+ throw ThreadExitException (/* thread's return value = */ NULL);
+ }
+}
+
+void* thread_function (void*)
+{
+ try {
+ do_some_work ();
+ }
+ catch (ThreadExitException ex) {
+ /* Some function indicated that we should exit the thread. */
+ ex.DoThreadExit ();
+ }
+ return NULL;
+}
diff --git a/listings/chapter-4/detached.c b/listings/chapter-4/detached.c
new file mode 100644
index 0000000..5d93740
--- /dev/null
+++ b/listings/chapter-4/detached.c
@@ -0,0 +1,29 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+void* thread_function (void* thread_arg)
+{
+ /* Do work here... */
+ return NULL;
+}
+
+int main ()
+{
+ pthread_attr_t attr;
+ pthread_t thread;
+
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create (&thread, &attr, &thread_function, NULL);
+ pthread_attr_destroy (&attr);
+
+ /* Do work here... */
+
+ /* No need to join the second thread. */
+ return 0;
+}
diff --git a/listings/chapter-4/job-queue1.c b/listings/chapter-4/job-queue1.c
new file mode 100644
index 0000000..34af5ba
--- /dev/null
+++ b/listings/chapter-4/job-queue1.c
@@ -0,0 +1,36 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+struct job {
+ /* Link field for linked list. */
+ struct job* next;
+
+ /* Other fields describing work to be done... */
+};
+
+/* A linked list of pending jobs. */
+struct job* job_queue;
+
+extern void process_job (struct job*);
+
+/* Process queued jobs until the queue is empty. */
+
+void* thread_function (void* arg)
+{
+ while (job_queue != NULL) {
+ /* Get the next available job. */
+ struct job* next_job = job_queue;
+ /* Remove this job from the list. */
+ job_queue = job_queue->next;
+ /* Carry out the work. */
+ process_job (next_job);
+ /* Clean up. */
+ free (next_job);
+ }
+ return NULL;
+}
diff --git a/listings/chapter-4/job-queue2.c b/listings/chapter-4/job-queue2.c
new file mode 100644
index 0000000..a710006
--- /dev/null
+++ b/listings/chapter-4/job-queue2.c
@@ -0,0 +1,58 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+struct job {
+ /* Link field for linked list. */
+ struct job* next;
+
+ /* Other fields describing work to be done... */
+};
+
+/* A linked list of pending jobs. */
+struct job* job_queue;
+
+extern void process_job (struct job*);
+
+/* A mutex protecting job_queue. */
+pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Process queued jobs until the queue is empty. */
+
+void* thread_function (void* arg)
+{
+ while (1) {
+ struct job* next_job;
+
+ /* Lock the mutex on the job queue. */
+ pthread_mutex_lock (&job_queue_mutex);
+ /* Now it's safe to check if the queue is empty. */
+ if (job_queue == NULL)
+ next_job = NULL;
+ else {
+ /* Get the next available job. */
+ next_job = job_queue;
+ /* Remove this job from the list. */
+ job_queue = job_queue->next;
+ }
+ /* Unlock the mutex on the job queue, since we're done with the
+ queue for now. */
+ pthread_mutex_unlock (&job_queue_mutex);
+
+ /* Was the queue empty? If so, end the thread. */
+ if (next_job == NULL)
+ break;
+
+ /* Carry out the work. */
+ process_job (next_job);
+ /* Clean up. */
+ free (next_job);
+ }
+ return NULL;
+}
+
diff --git a/listings/chapter-4/job-queue3.c b/listings/chapter-4/job-queue3.c
new file mode 100644
index 0000000..e33008f
--- /dev/null
+++ b/listings/chapter-4/job-queue3.c
@@ -0,0 +1,94 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+struct job {
+ /* Link field for linked list. */
+ struct job* next;
+
+ /* Other fields describing work to be done... */
+};
+
+/* A linked list of pending jobs. */
+struct job* job_queue;
+
+extern void process_job (struct job*);
+
+/* A mutex protecting job_queue. */
+pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* A semaphore counting the number of jobs in the queue. */
+sem_t job_queue_count;
+
+/* Perform one-time initialization of the job queue. */
+
+void initialize_job_queue ()
+{
+ /* The queue is initially empty. */
+ job_queue = NULL;
+ /* Initialize the semaphore which counts jobs in the queue. Its
+ initial value should be zero. */
+ sem_init (&job_queue_count, 0, 0);
+}
+
+/* Process queued jobs until the queue is empty. */
+
+void* thread_function (void* arg)
+{
+ while (1) {
+ struct job* next_job;
+
+ /* Wait on the job queue semaphore. If its value is positive,
+ indicating that the queue is not empty, decrement the count by
+ one. If the queue is empty, block until a new job is enqueued. */
+ sem_wait (&job_queue_count);
+
+ /* Lock the mutex on the job queue. */
+ pthread_mutex_lock (&job_queue_mutex);
+ /* Because of the semaphore, we know the queue is not empty. Get
+ the next available job. */
+ next_job = job_queue;
+ /* Remove this job from the list. */
+ job_queue = job_queue->next;
+ /* Unlock the mutex on the job queue, since we're done with the
+ queue for now. */
+ pthread_mutex_unlock (&job_queue_mutex);
+
+ /* Carry out the work. */
+ process_job (next_job);
+ /* Clean up. */
+ free (next_job);
+ }
+ return NULL;
+}
+
+/* Add a new job to the front of the job queue. */
+
+void enqueue_job (/* Pass job-specific data here... */)
+{
+ struct job* new_job;
+
+ /* Allocate a new job object. */
+ new_job = (struct job*) malloc (sizeof (struct job));
+ /* Set the other fields of the job struct here... */
+
+ /* Lock the mutex on the job queue before accessing it. */
+ pthread_mutex_lock (&job_queue_mutex);
+ /* Place the new job at the head of the queue. */
+ new_job->next = job_queue;
+ job_queue = new_job;
+
+ /* Post to the semaphore to indicate another job is available. If
+ threads are blocked, waiting on the semaphore, one will become
+ unblocked so it can process the job. */
+ sem_post (&job_queue_count);
+
+ /* Unlock the job queue mutex. */
+ pthread_mutex_unlock (&job_queue_mutex);
+}
diff --git a/listings/chapter-4/primes.c b/listings/chapter-4/primes.c
new file mode 100644
index 0000000..0c82d2f
--- /dev/null
+++ b/listings/chapter-4/primes.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+/* Compute successive prime numbers (very inefficiently). Return the
+ Nth prime number, where N is the value pointed to by *ARG. */
+
+void* compute_prime (void* arg)
+{
+ int candidate = 2;
+ int n = *((int*) arg);
+
+ while (1) {
+ int factor;
+ int is_prime = 1;
+
+ /* Test primality by successive division. */
+ for (factor = 2; factor < candidate; ++factor)
+ if (candidate % factor == 0) {
+ is_prime = 0;
+ break;
+ }
+ /* Is this the prime number we're looking for? */
+ if (is_prime) {
+ if (--n == 0)
+ /* Return the desired prime number as the thread return value. */
+ return (void*) candidate;
+ }
+ ++candidate;
+ }
+ return NULL;
+}
+
+int main ()
+{
+ pthread_t thread;
+ int which_prime = 5000;
+ int prime;
+
+ /* Start the computing thread, up to the 5000th prime number. */
+ pthread_create (&thread, NULL, &compute_prime, &which_prime);
+ /* Do some other work here... */
+ /* Wait for the prime number thread to complete, and get the result. */
+ pthread_join (thread, (void*) &prime);
+ /* Print the largest prime it computed. */
+ printf("The %dth prime number is %d.\n", which_prime, prime);
+ return 0;
+}
diff --git a/listings/chapter-4/spin-condvar.c b/listings/chapter-4/spin-condvar.c
new file mode 100644
index 0000000..51330b1
--- /dev/null
+++ b/listings/chapter-4/spin-condvar.c
@@ -0,0 +1,48 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+
+extern void do_work ();
+
+int thread_flag;
+pthread_mutex_t thread_flag_mutex;
+
+void initialize_flag ()
+{
+ pthread_mutex_init (&thread_flag_mutex, NULL);
+ thread_flag = 0;
+}
+
+/* Calls do_work repeatedly while the thread flag is set; otherwise
+ spins. */
+
+void* thread_function (void* thread_arg)
+{
+ while (1) {
+ int flag_is_set;
+
+ /* Protect the flag with a mutex lock. */
+ pthread_mutex_lock (&thread_flag_mutex);
+ flag_is_set = thread_flag;
+ pthread_mutex_unlock (&thread_flag_mutex);
+
+ if (flag_is_set)
+ do_work ();
+ /* Else don't do anything. Just loop again. */
+ }
+ return NULL;
+}
+
+/* Sets the value of the thread flag to FLAG_VALUE. */
+
+void set_thread_flag (int flag_value)
+{
+ /* Protect the flag with a mutex lock. */
+ pthread_mutex_lock (&thread_flag_mutex);
+ thread_flag = flag_value;
+ pthread_mutex_unlock (&thread_flag_mutex);
+}
diff --git a/listings/chapter-4/thread-create.c b/listings/chapter-4/thread-create.c
new file mode 100644
index 0000000..08d18fe
--- /dev/null
+++ b/listings/chapter-4/thread-create.c
@@ -0,0 +1,31 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+/* Prints x's to stderr. The parameter is unused. Does not return. */
+
+void* print_xs (void* unused)
+{
+ while (1)
+ fputc ('x', stderr);
+ return NULL;
+}
+
+/* The main program. */
+
+int main ()
+{
+ pthread_t thread_id;
+ /* Create a new thread. The new thread will run the print_xs
+ function. */
+ pthread_create (&thread_id, NULL, &print_xs, NULL);
+ /* Print o's continuously to stderr. */
+ while (1)
+ fputc ('o', stderr);
+ return 0;
+}
diff --git a/listings/chapter-4/thread-create2.c b/listings/chapter-4/thread-create2.c
new file mode 100644
index 0000000..18965e8
--- /dev/null
+++ b/listings/chapter-4/thread-create2.c
@@ -0,0 +1,60 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+/* Parameters to print_function. */
+
+struct char_print_parms
+{
+ /* The character to print. */
+ char character;
+ /* The number of times to print it. */
+ int count;
+};
+
+/* Prints a number of characters to stderr, as given by PARAMETERS,
+ which is a pointer to a struct char_print_parms. */
+
+void* char_print (void* parameters)
+{
+ /* Cast the cookie pointer to the right type. */
+ struct char_print_parms* p = (struct char_print_parms*) parameters;
+ int i;
+
+ for (i = 0; i < p->count; ++i)
+ fputc (p->character, stderr);
+ return NULL;
+}
+
+/* The main program. */
+
+int main ()
+{
+ pthread_t thread1_id;
+ pthread_t thread2_id;
+ struct char_print_parms thread1_args;
+ struct char_print_parms thread2_args;
+
+ /* Create a new thread to print 30000 x's. */
+ thread1_args.character = 'x';
+ thread1_args.count = 30000;
+ pthread_create (&thread1_id, NULL, &char_print, &thread1_args);
+
+ /* Create a new thread to print 20000 o's. */
+ thread2_args.character = 'o';
+ thread2_args.count = 20000;
+ pthread_create (&thread2_id, NULL, &char_print, &thread2_args);
+
+ /* Make sure the first thread has finished. */
+ pthread_join (thread1_id, NULL);
+ /* Make sure the second thread has finished. */
+ pthread_join (thread2_id, NULL);
+
+ /* Now we can safely return. */
+ return 0;
+}
diff --git a/listings/chapter-4/thread-pid.c b/listings/chapter-4/thread-pid.c
new file mode 100644
index 0000000..6a56fda
--- /dev/null
+++ b/listings/chapter-4/thread-pid.c
@@ -0,0 +1,27 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+void* thread_function (void* arg)
+{
+ fprintf (stderr, "child thread pid is %d\n", (int) getpid ());
+ /* Spin forever. */
+ while (1);
+ return NULL;
+}
+
+int main ()
+{
+ pthread_t thread;
+ fprintf (stderr, "main thread pid is %d\n", (int) getpid ());
+ pthread_create (&thread, NULL, &thread_function, NULL);
+ /* Spin forever. */
+ while (1);
+ return 0;
+}
diff --git a/listings/chapter-4/tsd.c b/listings/chapter-4/tsd.c
new file mode 100644
index 0000000..048ecdb
--- /dev/null
+++ b/listings/chapter-4/tsd.c
@@ -0,0 +1,63 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+/* The key used to assocate a log file pointer with each thread. */
+static pthread_key_t thread_log_key;
+
+/* Write MESSAGE to the log file for the current thread. */
+
+void write_to_thread_log (const char* message)
+{
+ FILE* thread_log = (FILE*) pthread_getspecific (thread_log_key);
+ fprintf (thread_log, "%s\n", message);
+}
+
+/* Close the log file pointer THREAD_LOG. */
+
+void close_thread_log (void* thread_log)
+{
+ fclose ((FILE*) thread_log);
+}
+
+void* thread_function (void* args)
+{
+ char thread_log_filename[20];
+ FILE* thread_log;
+
+ /* Generate the filename for this thread's log file. */
+ sprintf (thread_log_filename, "thread%d.log", (int) pthread_self ());
+ /* Open the log file. */
+ thread_log = fopen (thread_log_filename, "w");
+ /* Store the file pointer in thread-specific data under thread_log_key. */
+ pthread_setspecific (thread_log_key, thread_log);
+
+ write_to_thread_log ("Thread starting.");
+ /* Do work here... */
+
+ return NULL;
+}
+
+int main ()
+{
+ int i;
+ pthread_t threads[5];
+
+ /* Create a key to associate thread log file pointers in
+ thread-specific data. Use close_thread_log to clean up the file
+ pointers. */
+ pthread_key_create (&thread_log_key, close_thread_log);
+ /* Create threads to do the work. */
+ for (i = 0; i < 5; ++i)
+ pthread_create (&(threads[i]), NULL, thread_function, NULL);
+ /* Wait for all threads to finish. */
+ for (i = 0; i < 5; ++i)
+ pthread_join (threads[i], NULL);
+ return 0;
+}
diff --git a/listings/chapter-5/Makefile b/listings/chapter-5/Makefile
new file mode 100644
index 0000000..562fd49
--- /dev/null
+++ b/listings/chapter-5/Makefile
@@ -0,0 +1,19 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS = sem_all_deall.o sem_init.o sem_pv.o
+LIBRARIES =
+PROGRAMS = dup2 mmap-read mmap-write pipe popen shm \
+ socket-client socket-inet socket-server
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o *.a $(PROGRAMS)
diff --git a/listings/chapter-5/dup2.c b/listings/chapter-5/dup2.c
new file mode 100644
index 0000000..fae038f
--- /dev/null
+++ b/listings/chapter-5/dup2.c
@@ -0,0 +1,51 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+
+int main ()
+{
+ int fds[2];
+ pid_t pid;
+
+ /* Create a pipe. File descriptors for the two ends of the pipe are
+ placed in fds. */
+ pipe (fds);
+ /* Fork a child process. */
+ pid = fork ();
+ if (pid == (pid_t) 0) {
+ /* This is the child process. Close our copy of the write end of
+ the file descriptor. */
+ close (fds[1]);
+ /* Connect the read end of the pipe to standard input. */
+ dup2 (fds[0], STDIN_FILENO);
+ /* Replace the child process with the "sort" program. */
+ execlp ("sort", "sort", 0);
+ }
+ else {
+ /* This is the parent process. */
+ FILE* stream;
+ /* Close our copy of the read end of the file descriptor. */
+ close (fds[0]);
+ /* Convert the write file descriptor to a FILE object, and write
+ to it. */
+ stream = fdopen (fds[1], "w");
+ fprintf (stream, "This is a test.\n");
+ fprintf (stream, "Hello, world.\n");
+ fprintf (stream, "My dog has fleas.\n");
+ fprintf (stream, "This program is great.\n");
+ fprintf (stream, "One fish, two fish.\n");
+ fflush (stream);
+ close (fds[1]);
+ /* Wait for the child process to finish. */
+ waitpid (pid, NULL, 0);
+ }
+
+ return 0;
+}
diff --git a/listings/chapter-5/mmap-read.c b/listings/chapter-5/mmap-read.c
new file mode 100644
index 0000000..ab73d07
--- /dev/null
+++ b/listings/chapter-5/mmap-read.c
@@ -0,0 +1,36 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#define FILE_LENGTH 0x100
+
+int main (int argc, char* const argv[])
+{
+ int fd;
+ void* file_memory;
+ int integer;
+
+ /* Open the file. */
+ fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);
+ /* Create the memory-mapping. */
+ file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ close (fd);
+
+ /* Read the integer, print it out, and double it. */
+ sscanf (file_memory, "%d", &integer);
+ printf ("value: %d\n", integer);
+ sprintf ((char*) file_memory, "%d\n", 2 * integer);
+ /* Release the memory (unnecessary since the program exits). */
+ munmap (file_memory, FILE_LENGTH);
+
+ return 0;
+}
diff --git a/listings/chapter-5/mmap-write.c b/listings/chapter-5/mmap-write.c
new file mode 100644
index 0000000..ef5d688
--- /dev/null
+++ b/listings/chapter-5/mmap-write.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#define FILE_LENGTH 0x100
+
+/* Return a uniformly random number in the range [low,high]. */
+
+int random_range (unsigned const low, unsigned const high)
+{
+ unsigned const range = high - low + 1;
+ return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));
+}
+
+int main (int argc, char* const argv[])
+{
+ int fd;
+ void* file_memory;
+
+ /* Seed the random number generator. */
+ srand (time (NULL));
+
+ /* Prepare a file large enough to hold an unsigned integer. */
+ fd = open (argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ lseek (fd, FILE_LENGTH+1, SEEK_SET);
+ write (fd, "", 1);
+ lseek (fd, 0, SEEK_SET);
+
+ /* Create the memory-mapping. */
+ file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);
+ close (fd);
+ /* Write a random integer to memory-mapped area. */
+ sprintf((char*) file_memory, "%d\n", random_range (-100, 100));
+ /* Release the memory (unnecessary since the program exits). */
+ munmap (file_memory, FILE_LENGTH);
+
+ return 0;
+}
diff --git a/listings/chapter-5/pipe.c b/listings/chapter-5/pipe.c
new file mode 100644
index 0000000..6c6b025
--- /dev/null
+++ b/listings/chapter-5/pipe.c
@@ -0,0 +1,72 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+/* Write COUNT copies of MESSAGE to STREAM, pausing for a second
+ between each. */
+
+void writer (const char* message, int count, FILE* stream)
+{
+ for (; count > 0; --count) {
+ /* Write the message to the stream, and send it off immediately. */
+ fprintf (stream, "%s\n", message);
+ fflush (stream);
+ /* Snooze a while. */
+ sleep (1);
+ }
+}
+
+/* Read random strings from the stream as long as possible. */
+
+void reader (FILE* stream)
+{
+ char buffer[1024];
+ /* Read until we hit the end of the stream. fgets reads until
+ either a newline or the end-of-file. */
+ while (!feof (stream)
+ && !ferror (stream)
+ && fgets (buffer, sizeof (buffer), stream) != NULL)
+ fputs (buffer, stdout);
+}
+
+int main ()
+{
+ int fds[2];
+ pid_t pid;
+
+ /* Create a pipe. File descriptors for the two ends of the pipe are
+ placed in fds. */
+ pipe (fds);
+ /* Fork a child process. */
+ pid = fork ();
+ if (pid == (pid_t) 0) {
+ FILE* stream;
+ /* This is the child process. Close our copy of the write end of
+ the file descriptor. */
+ close (fds[1]);
+ /* Convert the read file descriptor to a FILE object, and read
+ from it. */
+ stream = fdopen (fds[0], "r");
+ reader (stream);
+ close (fds[0]);
+ }
+ else {
+ /* This is the parent process. */
+ FILE* stream;
+ /* Close our copy of the read end of the file descriptor. */
+ close (fds[0]);
+ /* Convert the write file descriptor to a FILE object, and write
+ to it. */
+ stream = fdopen (fds[1], "w");
+ writer ("Hello, world.", 5, stream);
+ close (fds[1]);
+ }
+
+ return 0;
+}
diff --git a/listings/chapter-5/popen.c b/listings/chapter-5/popen.c
new file mode 100644
index 0000000..2f2eecd
--- /dev/null
+++ b/listings/chapter-5/popen.c
@@ -0,0 +1,19 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+
+int main ()
+{
+ FILE* stream = popen ("sort", "w");
+ fprintf (stream, "This is a test.\n");
+ fprintf (stream, "Hello, world.\n");
+ fprintf (stream, "My dog has fleas.\n");
+ fprintf (stream, "This program is great.\n");
+ fprintf (stream, "One fish, two fish.\n");
+ return pclose (stream);
+}
diff --git a/listings/chapter-5/sem_all_deall.c b/listings/chapter-5/sem_all_deall.c
new file mode 100644
index 0000000..0a42b3e
--- /dev/null
+++ b/listings/chapter-5/sem_all_deall.c
@@ -0,0 +1,34 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+/* We must define union semun ourselves. */
+
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short int *array;
+ struct seminfo *__buf;
+};
+
+/* Obtain a binary semaphore's ID, allocating if necessary. */
+
+int binary_semaphore_allocation (key_t key, int sem_flags)
+{
+ return semget (key, 1, sem_flags);
+}
+
+/* Deallocate a binary semaphore. All users must have finished their
+ use. Returns -1 on failure. */
+
+int binary_semaphore_deallocate (int semid)
+{
+ union semun ignored_argument;
+ return semctl (semid, 1, IPC_RMID, ignored_argument);
+}
diff --git a/listings/chapter-5/sem_init.c b/listings/chapter-5/sem_init.c
new file mode 100644
index 0000000..dcf851f
--- /dev/null
+++ b/listings/chapter-5/sem_init.c
@@ -0,0 +1,29 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+/* We must define union semun ourselves. */
+
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short int *array;
+ struct seminfo *__buf;
+};
+
+/* Initialize a binary semaphore with a value of one. */
+
+int binary_semaphore_initialize (int semid)
+{
+ union semun argument;
+ unsigned short values[1];
+ values[0] = 1;
+ argument.array = values;
+ return semctl (semid, 0, SETALL, argument);
+}
diff --git a/listings/chapter-5/sem_pv.c b/listings/chapter-5/sem_pv.c
new file mode 100644
index 0000000..f4d7560
--- /dev/null
+++ b/listings/chapter-5/sem_pv.c
@@ -0,0 +1,41 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+/* Wait on a binary semaphore. Block until the semaphore value is
+ positive, then decrement it by one. */
+
+int binary_semaphore_wait (int semid)
+{
+ struct sembuf operations[1];
+ /* Use the first (and only) semaphore. */
+ operations[0].sem_num = 0;
+ /* Decrement by 1. */
+ operations[0].sem_op = -1;
+ /* Permit undo'ing. */
+ operations[0].sem_flg = SEM_UNDO;
+
+ return semop (semid, operations, 1);
+}
+
+/* Post to a binary semaphore: increment its value by one. This
+ returns immediately. */
+
+int binary_semaphore_post (int semid)
+{
+ struct sembuf operations[1];
+ /* Use the first (and only) semaphore. */
+ operations[0].sem_num = 0;
+ /* Increment by 1. */
+ operations[0].sem_op = 1;
+ /* Permit undo'ing. */
+ operations[0].sem_flg = SEM_UNDO;
+
+ return semop (semid, operations, 1);
+}
diff --git a/listings/chapter-5/shm.c b/listings/chapter-5/shm.c
new file mode 100644
index 0000000..513b467
--- /dev/null
+++ b/listings/chapter-5/shm.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+
+int main ()
+{
+ int segment_id;
+ char* shared_memory;
+ struct shmid_ds shmbuffer;
+ int segment_size;
+ const int shared_segment_size = 0x6400;
+
+ /* Allocate a shared memory segment. */
+ segment_id = shmget (IPC_PRIVATE, shared_segment_size,
+ IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
+
+ /* Attach the shared memory segment. */
+ shared_memory = (char*) shmat (segment_id, 0, 0);
+ printf ("shared memory attached at address %p\n", shared_memory);
+ /* Determine the segment's size. */
+ shmctl (segment_id, IPC_STAT, &shmbuffer);
+ segment_size = shmbuffer.shm_segsz;
+ printf ("segment size: %d\n", segment_size);
+ /* Write a string to the shared memory segment. */
+ sprintf (shared_memory, "Hello, world.");
+ /* Deatch the shared memory segment. */
+ shmdt (shared_memory);
+
+ /* Reattach the shared memory segment, at a different address. */
+ shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);
+ printf ("shared memory reattached at address %p\n", shared_memory);
+ /* Print out the string from shared memory. */
+ printf ("%s\n", shared_memory);
+ /* Detach the shared memory segment. */
+ shmdt (shared_memory);
+
+ /* Deallocate the shared memory segment. */
+ shmctl (segment_id, IPC_RMID, 0);
+
+ return 0;
+}
diff --git a/listings/chapter-5/socket-client.c b/listings/chapter-5/socket-client.c
new file mode 100644
index 0000000..b145694
--- /dev/null
+++ b/listings/chapter-5/socket-client.c
@@ -0,0 +1,43 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+/* Write TEXT to the socket given by file descriptor SOCKET_FD. */
+
+void write_text (int socket_fd, const char* text)
+{
+ /* Write the number of bytes in the string, including
+ NUL-termination. */
+ int length = strlen (text) + 1;
+ write (socket_fd, &length, sizeof (length));
+ /* Write the string. */
+ write (socket_fd, text, length);
+}
+
+int main (int argc, char* const argv[])
+{
+ const char* const socket_name = argv[1];
+ const char* const message = argv[2];
+ int socket_fd;
+ struct sockaddr_un name;
+
+ /* Create the socket. */
+ socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);
+ /* Store the server's name in the socket address. */
+ name.sun_family = AF_LOCAL;
+ strcpy (name.sun_path, socket_name);
+ /* Connect the socket. */
+ connect (socket_fd, &name, SUN_LEN (&name));
+ /* Write the text on the command line to the socket. */
+ write_text (socket_fd, message);
+ close (socket_fd);
+ return 0;
+}
diff --git a/listings/chapter-5/socket-inet.c b/listings/chapter-5/socket-inet.c
new file mode 100644
index 0000000..255d1cf
--- /dev/null
+++ b/listings/chapter-5/socket-inet.c
@@ -0,0 +1,65 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Print the contents of the home page for the server's socket.
+ Return an indication of success. */
+
+void get_home_page (int socket_fd)
+{
+ char buffer[10000];
+ ssize_t number_characters_read;
+
+ /* Send the HTTP GET command for the home page. */
+ sprintf (buffer, "GET /\n");
+ write (socket_fd, buffer, strlen (buffer));
+ /* Read from the socket. read may not return all the data at one
+ time, so keep trying until we run out. */
+ while (1) {
+ number_characters_read = read (socket_fd, buffer, 10000);
+ if (number_characters_read == 0)
+ return;
+ /* Write the data to standard output. */
+ fwrite (buffer, sizeof (char), number_characters_read, stdout);
+ }
+}
+
+int main (int argc, char* const argv[])
+{
+ int socket_fd;
+ struct sockaddr_in name;
+ struct hostent* hostinfo;
+
+ /* Create the socket. */
+ socket_fd = socket (PF_INET, SOCK_STREAM, 0);
+ /* Store the server's name in the socket address. */
+ name.sin_family = AF_INET;
+ /* Convert from strings to numbers. */
+ hostinfo = gethostbyname (argv[1]);
+ if (hostinfo == NULL)
+ return 1;
+ else
+ name.sin_addr = *((struct in_addr *) hostinfo->h_addr);
+ /* Web servers use port 80. */
+ name.sin_port = htons (80);
+
+ /* Connect to the web server */
+ if (connect (socket_fd, &name, sizeof (struct sockaddr_in)) == -1) {
+ perror ("connect");
+ return 1;
+ }
+ /* Retrieve the server's home page. */
+ get_home_page (socket_fd);
+
+ return 0;
+}
diff --git a/listings/chapter-5/socket-server.c b/listings/chapter-5/socket-server.c
new file mode 100644
index 0000000..ead4239
--- /dev/null
+++ b/listings/chapter-5/socket-server.c
@@ -0,0 +1,78 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Read text from the socket and print it out. Continue until the
+ socket closes. Return non-zero if the client sent a "quit"
+ message, zero otherwise. */
+
+int server (int client_socket)
+{
+ while (1) {
+ int length;
+ char* text;
+
+ /* First, read the length of the text message from the socket. If
+ read returns zero, the client closed the connection. */
+ if (read (client_socket, &length, sizeof (length)) == 0)
+ return 0;
+ /* Allocate a buffer to hold the text. */
+ text = (char*) malloc (length);
+ /* Read the text itself, and print it. */
+ read (client_socket, text, length);
+ printf ("%s\n", text);
+ /* Free the buffer. */
+ free (text);
+ /* If the client sent the message "quit", we're all done. */
+ if (!strcmp (text, "quit"))
+ return 1;
+ }
+}
+
+int main (int argc, char* const argv[])
+{
+ const char* const socket_name = argv[1];
+ int socket_fd;
+ struct sockaddr_un name;
+ int client_sent_quit_message;
+
+ /* Create the socket. */
+ socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);
+ /* Indicate this is a server. */
+ name.sun_family = AF_LOCAL;
+ strcpy (name.sun_path, socket_name);
+ bind (socket_fd, &name, SUN_LEN (&name));
+ /* Listen for connections. */
+ listen (socket_fd, 5);
+
+ /* Repeatedly accept connections, spinning off one server() to deal
+ with each client. Continue until a client sends a "quit" message. */
+ do {
+ struct sockaddr_un client_name;
+ socklen_t client_name_len;
+ int client_socket_fd;
+
+ /* Accept a connection. */
+ client_socket_fd = accept (socket_fd, &client_name, &client_name_len);
+ /* Handle the connection. */
+ client_sent_quit_message = server (client_socket_fd);
+ /* Close our end of the connection. */
+ close (client_socket_fd);
+ }
+ while (!client_sent_quit_message);
+
+ /* Remove the socket file. */
+ close (socket_fd);
+ unlink (socket_name);
+
+ return 0;
+}
diff --git a/listings/chapter-6/Makefile b/listings/chapter-6/Makefile
new file mode 100644
index 0000000..508b3b6
--- /dev/null
+++ b/listings/chapter-6/Makefile
@@ -0,0 +1,18 @@
+########################################################################
+# Code listing from "Advanced Linux Programming," by CodeSourcery LLC #
+# Copyright (C) 2001 by New Riders Publishing #
+# See COPYRIGHT for license information. #
+########################################################################
+
+OBJECTS = random_number.o
+LIBRARIES =
+PROGRAMS = cdrom-eject
+
+.PHONY: all clean
+
+# Default target: build everything.
+all: $(OBJECTS) $(LIBRARIES) $(PROGRAMS)
+
+# Clean up build products.
+clean:
+ rm -f *.o *.a $(PROGRAMS)
diff --git a/listings/chapter-6/cdrom-eject.c b/listings/chapter-6/cdrom-eject.c
new file mode 100644
index 0000000..7537a32
--- /dev/null
+++ b/listings/chapter-6/cdrom-eject.c
@@ -0,0 +1,24 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+int main (int argc, char* argv[])
+{
+ /* Open a file descriptor to the device specified on the command line. */
+ int fd = open (argv[1], O_RDONLY);
+ /* Eject the CD-ROM. */
+ ioctl (fd, CDROMEJECT);
+ /* Close the file descriptor. */
+ close (fd);
+
+ return 0;
+}
diff --git a/listings/chapter-6/random_number.c b/listings/chapter-6/random_number.c
new file mode 100644
index 0000000..39993d2
--- /dev/null
+++ b/listings/chapter-6/random_number.c
@@ -0,0 +1,52 @@
+/***********************************************************************
+* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
+* Copyright (C) 2001 by New Riders Publishing *
+* See COPYRIGHT for license information. *
+***********************************************************************/
+
+#include
+#include
+#include
+#include