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.

+ +

Endorsement

+ +

By Adam Goodman, Publisher, +Linux Magazine:

+ +
+"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.

+ +
+ + + + +
+ Problems with this web site? + File an issue on github. + +
+ + + diff --git a/alp-folder/advanced-linux-programming.pdf b/alp-folder/advanced-linux-programming.pdf new file mode 100644 index 0000000..bc82674 Binary files /dev/null and b/alp-folder/advanced-linux-programming.pdf differ diff --git a/alp-folder/alp-apA-other-development-tools.pdf b/alp-folder/alp-apA-other-development-tools.pdf new file mode 100644 index 0000000..34287be Binary files /dev/null and b/alp-folder/alp-apA-other-development-tools.pdf differ diff --git a/alp-folder/alp-apB-low-level-io.pdf b/alp-folder/alp-apB-low-level-io.pdf new file mode 100644 index 0000000..09fdacd Binary files /dev/null and b/alp-folder/alp-apB-low-level-io.pdf differ diff --git a/alp-folder/alp-apC-signal-table.pdf b/alp-folder/alp-apC-signal-table.pdf new file mode 100644 index 0000000..18f62d8 Binary files /dev/null and b/alp-folder/alp-apC-signal-table.pdf differ diff --git a/alp-folder/alp-apD-online-resources.pdf b/alp-folder/alp-apD-online-resources.pdf new file mode 100644 index 0000000..c634085 Binary files /dev/null and b/alp-folder/alp-apD-online-resources.pdf differ diff --git a/alp-folder/alp-apE-open-publication-license.pdf b/alp-folder/alp-apE-open-publication-license.pdf new file mode 100644 index 0000000..1330254 Binary files /dev/null and b/alp-folder/alp-apE-open-publication-license.pdf differ diff --git a/alp-folder/alp-apF-gnu-public-license.pdf b/alp-folder/alp-apF-gnu-public-license.pdf new file mode 100644 index 0000000..08f5e4e Binary files /dev/null and b/alp-folder/alp-apF-gnu-public-license.pdf differ diff --git a/alp-folder/alp-ch01-advanced-unix-programming-with-linux.pdf b/alp-folder/alp-ch01-advanced-unix-programming-with-linux.pdf new file mode 100644 index 0000000..2662d6f Binary files /dev/null and b/alp-folder/alp-ch01-advanced-unix-programming-with-linux.pdf differ diff --git a/alp-folder/alp-ch02-writing-good-gnu-linux-software.pdf b/alp-folder/alp-ch02-writing-good-gnu-linux-software.pdf new file mode 100644 index 0000000..fe62388 Binary files /dev/null and b/alp-folder/alp-ch02-writing-good-gnu-linux-software.pdf differ diff --git a/alp-folder/alp-ch03-processes.pdf b/alp-folder/alp-ch03-processes.pdf new file mode 100644 index 0000000..0d53ca9 Binary files /dev/null and b/alp-folder/alp-ch03-processes.pdf differ diff --git a/alp-folder/alp-ch04-threads.pdf b/alp-folder/alp-ch04-threads.pdf new file mode 100644 index 0000000..0d8386d Binary files /dev/null and b/alp-folder/alp-ch04-threads.pdf differ diff --git a/alp-folder/alp-ch05-ipc.pdf b/alp-folder/alp-ch05-ipc.pdf new file mode 100644 index 0000000..e0088b4 Binary files /dev/null and b/alp-folder/alp-ch05-ipc.pdf differ diff --git a/alp-folder/alp-ch06-mastering-linux.pdf b/alp-folder/alp-ch06-mastering-linux.pdf new file mode 100644 index 0000000..60a44f6 Binary files /dev/null and b/alp-folder/alp-ch06-mastering-linux.pdf differ diff --git a/alp-folder/alp-ch07-proc-filesystem.pdf b/alp-folder/alp-ch07-proc-filesystem.pdf new file mode 100644 index 0000000..f1e98ca Binary files /dev/null and b/alp-folder/alp-ch07-proc-filesystem.pdf differ diff --git a/alp-folder/alp-ch08-linux-system-calls.pdf b/alp-folder/alp-ch08-linux-system-calls.pdf new file mode 100644 index 0000000..66428ec Binary files /dev/null and b/alp-folder/alp-ch08-linux-system-calls.pdf differ diff --git a/alp-folder/alp-ch09-inline-asm.pdf b/alp-folder/alp-ch09-inline-asm.pdf new file mode 100644 index 0000000..b7f069e Binary files /dev/null and b/alp-folder/alp-ch09-inline-asm.pdf differ diff --git a/alp-folder/alp-ch10-security.pdf b/alp-folder/alp-ch10-security.pdf new file mode 100644 index 0000000..bd0df1a Binary files /dev/null and b/alp-folder/alp-ch10-security.pdf differ diff --git a/alp-folder/alp-ch11-sample-application.pdf b/alp-folder/alp-ch11-sample-application.pdf new file mode 100644 index 0000000..85f4085 Binary files /dev/null and b/alp-folder/alp-ch11-sample-application.pdf differ diff --git a/alp-folder/alp-header.png b/alp-folder/alp-header.png new file mode 100644 index 0000000..92506f4 Binary files /dev/null and b/alp-folder/alp-header.png differ diff --git a/alp-folder/alp-index.pdf b/alp-folder/alp-index.pdf new file mode 100644 index 0000000..0f7a67a Binary files /dev/null and b/alp-folder/alp-index.pdf differ diff --git a/alp-folder/alp-title.png b/alp-folder/alp-title.png new file mode 100644 index 0000000..c7e45ba Binary files /dev/null and b/alp-folder/alp-title.png differ diff --git a/alp-folder/alp-toc.pdf b/alp-folder/alp-toc.pdf new file mode 100644 index 0000000..25e1fad Binary files /dev/null and b/alp-folder/alp-toc.pdf differ diff --git a/alp-folder/alp.css b/alp-folder/alp.css new file mode 100644 index 0000000..e1b916c --- /dev/null +++ b/alp-folder/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/alp-folder/index.html b/alp-folder/index.html new file mode 100644 index 0000000..d5de3b8 --- /dev/null +++ b/alp-folder/index.html @@ -0,0 +1,83 @@ + + + + + + + + + + Download Advanced Linux Programming + + + + +
+ + + +

Download Advanced Linux Programming

+ +

+Do not use a download accelerator to download these files. +

+ +

+To view and print the book, you will need a Portable Document Format +(PDF) viewer application, such as +

+

+ +

+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. +

+ +

+ +
TitleFileFilesizemd5 checksum +
The Entire Advanced Linux Programming Book in One Filepdf3866012 5e722dc5dfcde263ea06fa193e9f61b4 +
Front Matter and Table of Contentspdf1273361 fe0c601b919879e93d79d25a78818b5c +
Chapter 01 - Advanced Unix Programming with Linuxpdf2358355923f2a5d7fb4f941fe905fbe45be196 +
Chapter 02 - Writing Good GNU/Linux Softwarepdf280326 44c823c1240c7f70a6dc9dbfddbe03fa +
Chapter 03 - Processespdf241758 87b5d98ba5b5933cf2ad1dbcf37641aa +
Chapter 04 - Threadspdf292419 11f392b44c073498e9ec9b3f718e54e7 +
Chapter 05 - Interprocess Communicationpdf289853 0de9b56476a0e6e536fbac68e09b02d2 +
Chapter 06 - Mastering Linuxpdf268821ab8940fbcc40018d72bd2016e662afba +
Chapter 07 - The /proc File Systempdf258582b3fe701f67a37ad7ba7233bcdc3f5d90 +
Chapter 08 - Linux System Callspdf 261352 583182dc09bc8b3c3773ba6d0fc710f2 +
Chapter 09 - Inline Assembly Codepdf 204992 c226e58fc7bf544df477d8ae96b680ed +
Chapter 10 - Securitypdf 288441 fc340b97e9c7f3fc2f5fe4dd71132ffd +
Chapter 11 - A Sample GNU/Linux Applicationpdf29821550a205644e441ae26d2041567d131b82 +
Appendix A - Other Development Toolspdf 272377 09a9a79a3c3abe6869df3f1ab5b39b14 +
Appendix B - Low Level I/Opdf 252755 3eaa0f0bbd103e1cc7872663e227a14b +
Appendix C - Table of Signalspdf 177879 3b02a6abb38877580b743392b98c3290 +
Appendix D - Online Resourcespdf148074 372964ff1eb4f85aca3985736a06cc48 +
Appendix E - Open Publication License Version 1.0pdf176596 5b1ddb8d38b6a44b357345ba6c25010e +
Appendix F - The GNU General Public Licensepdf228793 e207c51489e6f3cfafba5b13bb5e3bd9 +
Indexpdf1253094 004eefcfc2c6dca9a21233e748b81f35 + +
+

+
+ + + + +
+ Problems with this web site? + File an issue on github. + +
+ + + + diff --git a/alp.css b/alp.css new file mode 100644 index 0000000..34bf286 --- /dev/null +++ b/alp.css @@ -0,0 +1,26 @@ +body { + margin-top: 8; + margin-left: 24; + margin-right: 8; + margin-bottom: 8; + color: black; + background: white url(images/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/csl-logo.png b/csl-logo.png new file mode 100644 index 0000000..d3b6021 Binary files /dev/null and b/csl-logo.png differ diff --git a/downloads.html b/downloads.html new file mode 100644 index 0000000..6d7b352 --- /dev/null +++ b/downloads.html @@ -0,0 +1,79 @@ + + + + + + + + Downloads for Advanced Linux Programming + + + + +
+ + + +

Download Advanced Linux Programming

+ +

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:

+ + ++ + + + + + + +
filemd5bytes
ALP-listings.tar.gzf31cc72cd3e9e2f46adb304b2ef04ea247675
+ +

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.

+ +

Browse Code Listings

+ +

You may also browse the code listings on-line.

+ +
+ + + + +
+ Problems with this web site? + File an issue on github. + +
+ + diff --git a/errata.html b/errata.html new file mode 100644 index 0000000..2d2d7e0 --- /dev/null +++ b/errata.html @@ -0,0 +1,424 @@ + + + + + + + + Advanced Linux Programming + + + + +
+ + + +

Reporting an Error

+ +

Should you find an error in Advanced Linux +Programming that is not already listed here, +please send mail to +alp-errata@advancedlinuxprogramming.com.

+ +

Errata for Advanced Linux Programming

+ +
    + +
  • + page iv (publication information) + +

    Due to an oversight in production, an incorrect copyright notice + was included. The copyright notice should read:

    + +
    + Advanced Linux Programming +

    + FIRST EDITION: June, 2001 +

    + Copyright © 2001 by New Riders Publishing. This material may be + distributed only subject to the terms and conditions set forth in the Open + Publication License, Version 1, no options exercised. (The latest version of this license + is available at http://www.opencontent.org/openpub/). +
    +
  • + +
  • + page xx + +

    The term "GNU/Linux" is misspelled as "GNU/Liux."

    +
  • + +
  • + page 6 +

    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 +

    + bind (socket_fd, (struct sockaddr *) &name, SUN_LEN (&name)). +

    +

    Similarly, on the nineteenth line, the second argument of + accept should be cast: +

    + accept (socket_fd, (struct sockaddr *) &client_name, &client_name_len) +
    +

    +
  • + +
  • + page 122 +

    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 +

    + connect (socket_fd, (struct sockaddr *) &name, SUN_LEN (&name)). +

    +

    +
  • + +
  • + page 125 +

    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 +

    + connect (socket_fd, (struct sockaddr *) &name, sizeof (struct sockaddr_in)). +

    +

    +
  • + +
  • + page 130 +

    The third line of the first full paragraph should omit the word "cause". +

    +
  • + +
  • + page 132 +

    The sixth line of the first full paragraph should refer + to "the character device", not the "the block device". +

    +
  • + +
  • + page 133 +

    In the first footnote, the Windows device name should be LPT1, + not LRP1. +

  • + +
  • + page 133 +

    In the second footnote, the ASCII code for a carriage return should be 13, not 14.

    +
  • + +
  • + page 149 +

    The check for whether or not the read failed should be:

    +
    + if (bytes_read == 0 || bytes_read != sizeof (buffer)) +
    +

    + 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

    +
    + char *username = NULL;
    + size_t username_length = 0;
    + ssize_t characters_read = getline (&username, &username_length, stdin);
    + 
    +

    If the call fails, characters_read will be -1. + Otherwise, username will point to a malloc-allocated + buffer with username_length characters.

    +
  • + +
  • + page 224 +

    The third parameter in the call to readlink should + be sizeof (link_target) - 1 to allow for the terminating + NUL character.

    +
  • + +
  • + page 231 +

    The third parameter in the first call to write should + be strlen (bad_request_response).

    +
  • + +
  • + page 241 +

    The error_page string should note a failure to + open /etc/issue, not /proc/issue.

    +
  • + +
  • + page 245 +

    The comment above the get_group_name function should + say "deallocate with free", not "allocate with + free".

    +
  • + +
  • + page 286 +

    The first line inside the while loop is incorrect. It should + read: +

    +size_t written = write (fd, buffer + count - left_to_write, + left_to_write); +
    +

    +
  • + +
+ +
+ + + + +
+ Problems with this web site? + File an issue on github. + +
+ + diff --git a/images/alp-header.png b/images/alp-header.png new file mode 100644 index 0000000..92506f4 Binary files /dev/null and b/images/alp-header.png differ diff --git a/images/alp-title.png b/images/alp-title.png new file mode 100644 index 0000000..c7e45ba Binary files /dev/null and b/images/alp-title.png differ diff --git a/images/csl-logo.png b/images/csl-logo.png new file mode 100644 index 0000000..d3b6021 Binary files /dev/null and b/images/csl-logo.png differ diff --git a/images/red-edge.png b/images/red-edge.png new file mode 100644 index 0000000..73133b9 Binary files /dev/null and b/images/red-edge.png differ diff --git a/images/ruins.png b/images/ruins.png new file mode 100644 index 0000000..a7e3fc3 Binary files /dev/null and b/images/ruins.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..295f337 --- /dev/null +++ b/index.html @@ -0,0 +1,94 @@ + + + + + + + + + + Advanced Linux Programming + + + + + + + + + + + + +
Advanced Linux Programming +
+ +

This is the official home page for Advanced Linux +Programming by CodeSourcery +LLC, published by New Riders Publishing.

+ +

Overview

+ +

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.

+ +

On This Web Site

+ + + +

Translations

+ +
+
French
+
A partial translation into French is available at + http://www.advancedlinuxprogramming-fr.org/. +
+
+ +
+ + + + + + +
+ www.newriders.com + + www.codesourcery.com +
+ +
+
+Problems with this web site? + File an issue on github. + + +
+ + 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 +#include + +/* Return a random integer between MIN and MAX, inclusive. Obtain + randomness from /dev/random. */ + +int random_number (int min, int max) +{ + /* Store a file descriptor opened to /dev/random in a static + variable. That way, we don't need to open the file every time + this function is called. */ + static int dev_random_fd = -1; + + char* next_random_byte; + int bytes_to_read; + unsigned random_value; + + /* Make sure MAX is greater than MIN. */ + assert (max > min); + + /* If this is the first time this function is called, open a file + descriptor to /dev/random. */ + if (dev_random_fd == -1) { + dev_random_fd = open ("/dev/random", O_RDONLY); + assert (dev_random_fd != -1); + } + + /* Read enough random bytes to fill an integer variable. */ + next_random_byte = (char*) &random_value; + bytes_to_read = sizeof (random_value); + /* Loop until we've read enough bytes. Since /dev/random is filled + from user-generated actions, the read may block, and may only + return a single random byte at a time. */ + do { + int bytes_read; + bytes_read = read (dev_random_fd, next_random_byte, bytes_to_read); + bytes_to_read -= bytes_read; + next_random_byte += bytes_read; + } while (bytes_to_read > 0); + + /* Compute a random number in the correct range. */ + return min + (random_value % (max - min + 1)); +} diff --git a/listings/chapter-7/Makefile b/listings/chapter-7/Makefile new file mode 100644 index 0000000..5720f1a --- /dev/null +++ b/listings/chapter-7/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 = +LIBRARIES = +PROGRAMS = clock-speed get-exe-path get-pid open-and-spin \ + print-arg-list print-environment print-uptime + +.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-7/clock-speed.c b/listings/chapter-7/clock-speed.c new file mode 100644 index 0000000..b64da3e --- /dev/null +++ b/listings/chapter-7/clock-speed.c @@ -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. * +***********************************************************************/ + +#include +#include + +/* Returns the clock speed of the system's CPU in MHz, as reported by + /proc/cpuinfo. On a multiprocessor machine, returns the speed of + the first CPU. On error returns zero. */ + +float get_cpu_clock_speed () +{ + FILE* fp; + char buffer[1024]; + size_t bytes_read; + char* match; + float clock_speed; + + /* Read the entire contents of /proc/cpuinfo into the buffer. */ + fp = fopen ("/proc/cpuinfo", "r"); + bytes_read = fread (buffer, 1, sizeof (buffer), fp); + fclose (fp); + /* Bail if read failed or if buffer isn't big enough. */ + if (bytes_read == 0 || bytes_read == sizeof (buffer)) + return 0; + /* NUL-terminate the text. */ + buffer[bytes_read] = '\0'; + /* Locate the line that starts with "cpu MHz". */ + match = strstr (buffer, "cpu MHz"); + if (match == NULL) + return 0; + /* Parse the line to extrace the clock speed. */ + sscanf (match, "cpu MHz : %f", &clock_speed); + return clock_speed; +} + + +int main () +{ + printf ("CPU clock speed: %4.0f MHz\n", get_cpu_clock_speed ()); + return 0; +} diff --git a/listings/chapter-7/get-exe-path.c b/listings/chapter-7/get-exe-path.c new file mode 100644 index 0000000..efee55d --- /dev/null +++ b/listings/chapter-7/get-exe-path.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 + +/* Finds the path containing the currently-running program executable. + The path is placed into BUFFER, which is of length LEN. Returns + the number of characters in the path, or -1 on error. */ + +size_t get_executable_path (char* buffer, size_t len) +{ + char* path_end; + /* Read the target of /proc/self/exe. */ + if (readlink ("/proc/self/exe", buffer, len) <= 0) + return -1; + /* Find the last occurence of a forward slash, the path separator. */ + path_end = strrchr (buffer, '/'); + if (path_end == NULL) + return -1; + /* Advance to the character past the last slash. */ + ++path_end; + /* Obtain the directory containing the program by truncating the + path after the last slash. */ + *path_end = '\0'; + /* The length of the path is the number of characters up through the + last slash. */ + return (size_t) (path_end - buffer); +} + +int main () +{ + char path[PATH_MAX]; + get_executable_path (path, sizeof (path)); + printf ("this program is in the directory %s\n", path); + return 0; +} diff --git a/listings/chapter-7/get-pid.c b/listings/chapter-7/get-pid.c new file mode 100644 index 0000000..6547c5a --- /dev/null +++ b/listings/chapter-7/get-pid.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 + +/* Returns the process id of the calling processes, as determined from + the /proc/self symlink. */ + +pid_t get_pid_from_proc_self () +{ + char target[32]; + int pid; + /* Read the target of the symbolic link. */ + readlink ("/proc/self", target, sizeof (target)); + /* The target is a directory named for the process id. */ + sscanf (target, "%d", &pid); + return (pid_t) pid; +} + +int main () +{ + printf ("/proc/self reports process id %d\n", + (int) get_pid_from_proc_self ()); + printf ("getpid() reports process id %d\n", (int) getpid ()); + return 0; +} diff --git a/listings/chapter-7/open-and-spin.c b/listings/chapter-7/open-and-spin.c new file mode 100644 index 0000000..88f5242 --- /dev/null +++ b/listings/chapter-7/open-and-spin.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 +#include +#include +#include + +int main (int argc, char* argv[]) +{ + const char* const filename = argv[1]; + int fd = open (filename, O_RDONLY); + printf ("in process %d, file descriptor %d is open to %s\n", + (int) getpid (), (int) fd, filename); + while (1); + return 0; +} diff --git a/listings/chapter-7/print-arg-list.c b/listings/chapter-7/print-arg-list.c new file mode 100644 index 0000000..2c81059 --- /dev/null +++ b/listings/chapter-7/print-arg-list.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 +#include +#include + +/* Prints the argument list, one argument to a line, of the process + given by PID. */ + +void print_process_arg_list (pid_t pid) +{ + int fd; + char filename[24]; + char arg_list[1024]; + size_t length; + char* next_arg; + + /* Generate the name of the cmdline file for the process. */ + snprintf (filename, sizeof (filename), "/proc/%d/cmdline", (int) pid); + /* Read the contents of the file. */ + fd = open (filename, O_RDONLY); + length = read (fd, arg_list, sizeof (arg_list)); + close (fd); + /* read does not NUL-terminate the buffer, so do it here. */ + arg_list[length] = '\0'; + + /* Loop over arguments. Arguments are separated by NULs. */ + next_arg = arg_list; + while (next_arg < arg_list + length) { + /* Print the argument. Each is NUL-terminated, so just treat it + like an ordinary string. */ + printf ("%s\n", next_arg); + /* Advance to the next argument. Since each argument is + NUL-terminated, strlen counts the length of the next argument, + not the entire argument list. */ + next_arg += strlen (next_arg) + 1; + } +} + +int main (int argc, char* argv[]) +{ + pid_t pid = (pid_t) atoi (argv[1]); + print_process_arg_list (pid); + return 0; +} diff --git a/listings/chapter-7/print-environment.c b/listings/chapter-7/print-environment.c new file mode 100644 index 0000000..2851bbd --- /dev/null +++ b/listings/chapter-7/print-environment.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 +#include +#include + +/* Prints the environment, one environment variable to a line, of the + process given by PID. */ + +void print_process_environment (pid_t pid) +{ + int fd; + char filename[24]; + char environment[8192]; + size_t length; + char* next_var; + + /* Generate the name of the environ file for the process. */ + snprintf (filename, sizeof (filename), "/proc/%d/environ", (int) pid); + /* Read the contents of the file. */ + fd = open (filename, O_RDONLY); + length = read (fd, environment, sizeof (environment)); + close (fd); + /* read does not NUL-terminate the buffer, so do it here. */ + environment[length] = '\0'; + + /* Loop over variables. Variables are separated by NULs. */ + next_var = environment; + while (next_var < environment + length) { + /* Print the variable. Each is NUL-terminated, so just treat it + like an ordinary string. */ + printf ("%s\n", next_var); + /* Advance to the next variable. Since each variable is + NUL-terminated, strlen counts the length of the next variable, + not the entire variable list. */ + next_var += strlen (next_var) + 1; + } +} + +int main (int argc, char* argv[]) +{ + pid_t pid = (pid_t) atoi (argv[1]); + print_process_environment (pid); + return 0; +} diff --git a/listings/chapter-7/print-uptime.c b/listings/chapter-7/print-uptime.c new file mode 100644 index 0000000..175cb12 --- /dev/null +++ b/listings/chapter-7/print-uptime.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 + +/* Summarize a duration of time to standard output. TIME is the + amount of time, in seconds, and LABEL is a short descriptive label. */ + +void print_time (char* label, long time) +{ + /* Conversion constants. */ + const long minute = 60; + const long hour = minute * 60; + const long day = hour * 24; + /* Produce output. */ + printf ("%s: %ld days, %ld:%02ld:%02ld\n", label, time / day, + (time % day) / hour, (time % hour) / minute, time % minute); +} + +int main () +{ + FILE* fp; + double uptime, idle_time; + /* Read the system uptime and accumulated idle time from /proc/uptime. */ + fp = fopen ("/proc/uptime", "r"); + fscanf (fp, "%lf %lf\n", &uptime, &idle_time); + fclose (fp); + /* Summarize it. */ + print_time ("uptime ", (long) uptime); + print_time ("idle time", (long) idle_time); + return 0; +} diff --git a/listings/chapter-8/Makefile b/listings/chapter-8/Makefile new file mode 100644 index 0000000..d82cb75 --- /dev/null +++ b/listings/chapter-8/Makefile @@ -0,0 +1,20 @@ +######################################################################## +# Code listing from "Advanced Linux Programming," by CodeSourcery LLC # +# Copyright (C) 2001 by New Riders Publishing # +# See COPYRIGHT for license information. # +######################################################################## + +OBJECTS = better_sleep.o print-cpu-times.o print-time.o \ + write_journal_entry.o +LIBRARIES = +PROGRAMS = check-access copy itimer limit-cpu lock-file mprotect \ + print-symlink print-uname sysinfo + +.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-8/better_sleep.c b/listings/chapter-8/better_sleep.c new file mode 100644 index 0000000..efc3e32 --- /dev/null +++ b/listings/chapter-8/better_sleep.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 + +int better_sleep (double sleep_time) +{ + struct timespec tv; + /* Construct the timespec from the number of whole seconds... */ + tv.tv_sec = (time_t) sleep_time; + /* ... and the remainder in nanoseconds. */ + tv.tv_nsec = (long) ((sleep_time - tv.tv_sec) * 1e+9); + + while (1) + { + /* Sleep for the time specified in tv. If interrupted by a + signal, place the remaining time left to sleep back into tv. */ + int rval = nanosleep (&tv, &tv); + if (rval == 0) + /* Completed the entire sleep time; all done. */ + return 0; + else if (errno == EINTR) + /* Interruped by a signal. Try again. */ + continue; + else + /* Some other error; bail out. */ + return rval; + } + return 0; +} diff --git a/listings/chapter-8/check-access.c b/listings/chapter-8/check-access.c new file mode 100644 index 0000000..7751cd7 --- /dev/null +++ b/listings/chapter-8/check-access.c @@ -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. * +***********************************************************************/ + +#include +#include +#include + +int main (int argc, char* argv[]) +{ + char* path = argv[1]; + int rval; + + /* Check file existence. */ + rval = access (path, F_OK); + if (rval == 0) + printf ("%s exists\n", path); + else { + if (errno == ENOENT) + printf ("%s does not exist\n", path); + else if (errno == EACCES) + printf ("%s is not accessible\n", path); + return 0; + } + + /* Check read access. */ + rval = access (path, R_OK); + if (rval == 0) + printf ("%s is readable\n", path); + else + printf ("%s is not readable (access denied)\n", path); + + /* Check write access. */ + rval = access (path, W_OK); + if (rval == 0) + printf ("%s is writable\n", path); + else if (errno == EACCES) + printf ("%s is not writable (access denied)\n", path); + else if (errno == EROFS) + printf ("%s is not writable (read-only filesystem)\n", path); + + return 0; +} diff --git a/listings/chapter-8/copy.c b/listings/chapter-8/copy.c new file mode 100644 index 0000000..988e3ef --- /dev/null +++ b/listings/chapter-8/copy.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 +#include + +int main (int argc, char* argv[]) +{ + int read_fd; + int write_fd; + struct stat stat_buf; + off_t offset = 0; + + /* Open the input file. */ + read_fd = open (argv[1], O_RDONLY); + /* Stat the input file to obtain its size. */ + fstat (read_fd, &stat_buf); + /* Open the ouput file for writing, with the same permissions as the + source file. */ + write_fd = open (argv[2], O_WRONLY | O_CREAT, stat_buf.st_mode); + /* Blast the bytes from one file to the other. */ + sendfile (write_fd, read_fd, &offset, stat_buf.st_size); + /* Close up. */ + close (read_fd); + close (write_fd); + + return 0; +} diff --git a/listings/chapter-8/itimer.c b/listings/chapter-8/itimer.c new file mode 100644 index 0000000..cc94b08 --- /dev/null +++ b/listings/chapter-8/itimer.c @@ -0,0 +1,40 @@ +/*********************************************************************** +* 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 + +void timer_handler (int signum) +{ + static int count = 0; + printf ("timer expired %d times\n", ++count); +} + +int main () +{ + struct sigaction sa; + struct itimerval timer; + + /* Install timer_handler as the signal handler for SIGVTALRM. */ + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = &timer_handler; + sigaction (SIGVTALRM, &sa, NULL); + + /* Configure the timer to expire after 250 msec... */ + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = 250000; + /* ... and every 250 msec after that. */ + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 250000; + /* Start a virtual timer. It counts down whenever this process is + executing. */ + setitimer (ITIMER_VIRTUAL, &timer, NULL); + + /* Do busy work. */ + while (1); +} diff --git a/listings/chapter-8/limit-cpu.c b/listings/chapter-8/limit-cpu.c new file mode 100644 index 0000000..2eb962c --- /dev/null +++ b/listings/chapter-8/limit-cpu.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 + +int main () +{ + struct rlimit rl; + + /* Obtain the current limits. */ + getrlimit (RLIMIT_CPU, &rl); + /* Set a CPU limit of one second. */ + rl.rlim_cur = 1; + setrlimit (RLIMIT_CPU, &rl); + /* Do busy work. */ + while (1); + + return 0; +} diff --git a/listings/chapter-8/lock-file.c b/listings/chapter-8/lock-file.c new file mode 100644 index 0000000..b977fac --- /dev/null +++ b/listings/chapter-8/lock-file.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 + +int main (int argc, char* argv[]) +{ + char* file = argv[1]; + int fd; + struct flock lock; + + printf ("opening %s\n", file); + /* Open a file descriptor to the file. */ + fd = open (file, O_WRONLY); + printf ("locking\n"); + /* Initialize the flock structure. */ + memset (&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + /* Place a write lock on the file. */ + fcntl (fd, F_SETLKW, &lock); + + printf ("locked; hit enter to unlock... "); + /* Wait for the user to hit enter. */ + getchar (); + + printf ("unlocking\n"); + /* Release the lock. */ + lock.l_type = F_UNLCK; + fcntl (fd, F_SETLKW, &lock); + + close (fd); + return 0; +} diff --git a/listings/chapter-8/mprotect.c b/listings/chapter-8/mprotect.c new file mode 100644 index 0000000..9a75958 --- /dev/null +++ b/listings/chapter-8/mprotect.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 +#include +#include +#include +#include + +static int alloc_size; +static char* memory; + +void segv_handler (int signal_number) +{ + printf ("memory accessed!\n"); + mprotect (memory, alloc_size, PROT_READ | PROT_WRITE); +} + +int main () +{ + int fd; + struct sigaction sa; + + /* Install segv_handler as the handler for SIGSEGV. */ + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = &segv_handler; + sigaction (SIGSEGV, &sa, NULL); + + /* Allocate one page of memory by mapping /dev/zero. Map the memory + as write-only, intially. */ + alloc_size = getpagesize (); + fd = open ("/dev/zero", O_RDONLY); + memory = mmap (NULL, alloc_size, PROT_WRITE, MAP_PRIVATE, fd, 0); + close (fd); + /* Write to the page to obtain a private copy. */ + memory[0] = 0; + /* Make the the memory unwritable. */ + mprotect (memory, alloc_size, PROT_NONE); + + /* Write to the allocated memory region. */ + memory[0] = 1; + + /* All done; unmap the memory. */ + printf ("all done\n"); + munmap (memory, alloc_size); + return 0; +} diff --git a/listings/chapter-8/print-cpu-times.c b/listings/chapter-8/print-cpu-times.c new file mode 100644 index 0000000..d5bf313 --- /dev/null +++ b/listings/chapter-8/print-cpu-times.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 +#include +#include + +void print_cpu_time() +{ + struct rusage usage; + getrusage (RUSAGE_SELF, &usage); + printf ("CPU time: %ld.%06ld sec user, %ld.%06ld sec system\n", + usage.ru_utime.tv_sec, usage.ru_utime.tv_usec, + usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); +} diff --git a/listings/chapter-8/print-symlink.c b/listings/chapter-8/print-symlink.c new file mode 100644 index 0000000..a6d714d --- /dev/null +++ b/listings/chapter-8/print-symlink.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 + +int main (int argc, char* argv[]) +{ + char target_path[256]; + char* link_path = argv[1]; + + /* Attempt to read the target of the symbolic link. */ + int len = readlink (link_path, target_path, sizeof (target_path) - 1); + + if (len == -1) { + /* The call failed. */ + if (errno == EINVAL) + /* It's not a symbolic link; report that. */ + fprintf (stderr, "%s is not a symbolic link\n", link_path); + else + /* Some other problem occurred; print the generic message. */ + perror ("readlink"); + return 1; + } + else { + /* NUL-terminate the target path. */ + target_path[len] = '\0'; + /* Print it. */ + printf ("%s\n", target_path); + return 0; + } +} diff --git a/listings/chapter-8/print-time.c b/listings/chapter-8/print-time.c new file mode 100644 index 0000000..8adff5b --- /dev/null +++ b/listings/chapter-8/print-time.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 + +void print_time () +{ + struct timeval tv; + struct tm* ptm; + char time_string[40]; + long milliseconds; + + /* 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), "%Y-%m-%d %H:%M:%S", ptm); + /* Compute milliseconds from microseconds. */ + milliseconds = tv.tv_usec / 1000; + /* Print the formatted time, in seconds, followed by a decimal point + and the milliseconds. */ + printf ("%s.%03ld\n", time_string, milliseconds); +} diff --git a/listings/chapter-8/print-uname.c b/listings/chapter-8/print-uname.c new file mode 100644 index 0000000..a70bb67 --- /dev/null +++ b/listings/chapter-8/print-uname.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 + +int main () +{ + struct utsname u; + uname (&u); + printf ("%s release %s (version %s) on %s\n", u.sysname, u.release, + u.version, u.machine); + return 0; +} diff --git a/listings/chapter-8/sysinfo.c b/listings/chapter-8/sysinfo.c new file mode 100644 index 0000000..91057cc --- /dev/null +++ b/listings/chapter-8/sysinfo.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 + +int main () +{ + /* Conversion constants. */ + const long minute = 60; + const long hour = minute * 60; + const long day = hour * 24; + const double megabyte = 1024 * 1024; + /* Obtain system statistics. */ + struct sysinfo si; + sysinfo (&si); + /* Summarize intersting values. */ + printf ("system uptime : %ld days, %ld:%02ld:%02ld\n", + si.uptime / day, (si.uptime % day) / hour, + (si.uptime % hour) / minute, si.uptime % minute); + printf ("total RAM : %5.1f MB\n", si.totalram / megabyte); + printf ("free RAM : %5.1f MB\n", si.freeram / megabyte); + printf ("process count : %d\n", si.procs); + + return 0; +} diff --git a/listings/chapter-8/write_journal_entry.c b/listings/chapter-8/write_journal_entry.c new file mode 100644 index 0000000..4998597 --- /dev/null +++ b/listings/chapter-8/write_journal_entry.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 +#include +#include +#include + +const char* journal_filename = "journal.log"; + +void write_journal_entry (char* entry) +{ + int fd = open (journal_filename, O_WRONLY | O_CREAT | O_APPEND, 0660); + write (fd, entry, strlen (entry)); + write (fd, "\n", 1); + fsync (fd); + close (fd); +} diff --git a/listings/chapter-9/Makefile b/listings/chapter-9/Makefile new file mode 100644 index 0000000..1a6406c --- /dev/null +++ b/listings/chapter-9/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 = bit-pos-asm bit-pos-loop + +.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-9/bit-pos-asm.c b/listings/chapter-9/bit-pos-asm.c new file mode 100644 index 0000000..5470e43 --- /dev/null +++ b/listings/chapter-9/bit-pos-asm.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 + +int main (int argc, char* argv[]) +{ + long max = atoi (argv[1]); + long number; + unsigned position; + volatile unsigned result; + + /* Repeat the operation for a large number of values. */ + for (number = 1; number <= max; ++number) { + /* Compute the position of the most significant set bit using the + bsrl assembly instruction. */ + asm ("bsrl %1, %0" : "=r" (position) : "r" (number)); + result = position; + } + + return 0; +} diff --git a/listings/chapter-9/bit-pos-loop.c b/listings/chapter-9/bit-pos-loop.c new file mode 100644 index 0000000..d491d38 --- /dev/null +++ b/listings/chapter-9/bit-pos-loop.c @@ -0,0 +1,30 @@ +/*********************************************************************** +* 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[]) +{ + long max = atoi (argv[1]); + long number; + long i; + unsigned position; + volatile unsigned result; + + /* Repeat the operation for a large number of values. */ + for (number = 1; number <= max; ++number) { + /* Repeatedly shift the number to the right, until the result is + zero. Keeep count of the number of shifts this requires. */ + for (i = (number >> 1), position = 0; i != 0; ++position) + i >>= 1; + /* The position of the most significant set bit is the number of + shifts we needed after the first one. */ + result = position; + } + + return 0; +} diff --git a/listings/index.html b/listings/index.html new file mode 100644 index 0000000..0ee8800 --- /dev/null +++ b/listings/index.html @@ -0,0 +1,213 @@ + + + + + + + + + + + Advanced Linux Programming listings + + + +
+ + + +

Code Listings from Advanced Linux Programming

+ + + + +
+ + + + +
+ Problems with this web site? + File an issue on github. + +
+ diff --git a/listings/red-edge.png b/listings/red-edge.png new file mode 100644 index 0000000..73133b9 Binary files /dev/null and b/listings/red-edge.png differ diff --git a/nr-logo.png b/nr-logo.png new file mode 100644 index 0000000..10367c4 Binary files /dev/null and b/nr-logo.png differ diff --git a/red-edge.png b/red-edge.png new file mode 100644 index 0000000..73133b9 Binary files /dev/null and b/red-edge.png differ diff --git a/resources.html b/resources.html new file mode 100644 index 0000000..c085cd6 --- /dev/null +++ b/resources.html @@ -0,0 +1,121 @@ + + + + + + + + Advanced Linux Programming Resources + + + + +
+ + + +

Resources for Advanced Linux Programming

+ +

Here are some places to visit on the Internet to learn more about +programming for the GNU/Linux system.

+ +

General information

+ +
    + +
  • www.advancedlinuxprogramming.com + is this book's home on the Internet. Here, you can download the full + text of this book and program source code, find links to other online + resources, and get more information about programming + GNU/Linux.

  • + +
  • www.tldp.org + is the home of the Linux Documentation Project. This site is a + repository for a wealth of documentation, FAQ lists, HOWTOs, and other + documentation about GNU/Linux systems and software.

  • + +
+ +

Information about GNU/Linux software

+ +
    + +
  • www.gnu.org is the + home of the GNU Project. From this site, you can download a + staggering array of sophisticated free software applications. Among + them is the GNU C library, which is part of every GNU/Linux system and + contains many of the functions described in this book. The GNU + Project site also provides information about how you can contribute to + the development of the GNU/Linux system, by writing code or + documentation, by using free software, and by spreading the free + software message.

  • + +
  • www.kernel.org is + the primary site for distribution of the Linux kernel source code. + For the trickiest and most technically detailed questions about how + Linux works, the source code is the best place to look. See also the + Documentation directory for explanation of the kernel + internals.

  • + +
  • www.linuxhq.com + also distributes Linux kernel sources, patches, and related + information.

  • + +
  • gcc.gnu.org is the + home of the GNU Compiler Collection (GCC). GCC is the primary + compiler used on GNU/Linux systems, and includes compilers for C, C++, + Objective C, Java, Chill, and Fortran.

  • + +
  • www.gnome.org and www.kde.org are the homes of + the two most popular GNU/Linux windowing environments, Gnome and KDE. + If you plan to write an application with a graphical user interface, + you should familiarize yourself with either or both.

  • + +
+ +

Other sites

+ +
    + +
  • developer.intel.com + provides information about Intel processor architectures, including + the x86 (IA32) architecture. If you are developing for x86 Linux and + use inline assembly instructions, the technical manuals available here + will be very useful.

  • + +
  • developer.amd.com + provides similar information about AMD's line of microprocessors and + their special features.

  • + +
  • freshmeat.net + is an index of open source software, generally for GNU/Linux. This + site is one of the best places to stay abreast of the newest releases + of GNU/Linux software, from core system components to more obscure, + specialized applications.

  • + +
  • www.linuxsecurity.com + contains information, techniques, and links to software related to + GNU/Linux security. The site is of interest to users, system + administrators, and developers.

  • + +
+ + +
+ + + + +
+ Problems with this web site? + File an issue on github. + +
+ + diff --git a/ruins.png b/ruins.png new file mode 100644 index 0000000..a7e3fc3 Binary files /dev/null and b/ruins.png differ