diff -Naur ../glibc-2.1.3/ChangeLog glibc-2.1.3/ChangeLog --- ../glibc-2.1.3/ChangeLog 2000-02-24 18:05:16.000000000 -0800 +++ glibc-2.1.3/ChangeLog 2000-02-29 13:15:05.000000000 -0800 @@ -1,3 +1,16 @@ +2000-02-28 David S. Miller + + * sysdeps/unix/sysv/linux/sparc/getsysstats.c: New file. + +2000-02-24 Ulrich Drepper + + * locale/C-ctype.c (_nl_C_LC_CTYPE): Move comma to correct place + for big endian machines. + +2000-02-24 Andreas Jaeger + + * locale/programs/ld-ctype.c (ctype_output): Add missing &. + 2000-02-24 Ulrich Drepper * locale/C-ctype.c: Add table pointer for both endianesses. @@ -42,6 +55,10 @@ conditions so as not to clobber the final '\0' when there is only one element in the vector. +2000-02-23 Cristian Gafton + + * locale/programs/ld-ctype.c (CTYPE_DATA): Make sure we keep the alignment + 2000-02-22 Ulrich Drepper * libio/stdio.h: Define macros stdin, stdout, and stderr. @@ -230,6 +247,11 @@ Rebel-NetWinder to platform table so _ioperm platform lookup via /proc/cpuinfo works on later version NetWinders. +2000-02-14 Cristian Gafton + + * timezone/aliases: New file + * timezone/Makefile (tzlinks): Add aliases + 2000-02-13 Ulrich Drepper * sysdeps/i386/fpu/s_cosf.S: Domain of opcode is not large enough @@ -406,6 +428,12 @@ * sysdeps/unix/sysv/linux/arm/mmap64.S: Correct check for ENOSYS. +2000-02-01 Cristian Gafton + + * misc/syslog.c (closelog): reset LogType to SOCK_DGRAM + (openlog_internal): retry with SOCK_DGRAM if we are in SOCK_STREAM + mode and we get a connection refused. + 2000-01-25 Ulrich Drepper * sysdeps/unix/sysv/linux/i386/Dist: Add sys/io.h. diff -Naur ../glibc-2.1.3/Makeconfig glibc-2.1.3/Makeconfig --- ../glibc-2.1.3/Makeconfig 1999-11-29 11:19:20.000000000 -0800 +++ glibc-2.1.3/Makeconfig 2000-01-10 14:11:06.000000000 -0800 @@ -789,7 +789,8 @@ $(patsubst $<,/dev/null,$^) > $@-tmp mv -f $@-tmp $@ -all-Depend-files = $(wildcard $(..)*/Depend) +all-Depend-files = $(wildcard $(patsubst %,$(..)%/Depend,$(add-ons))) + $(common-objpfx)sysd-sorted: $(..)scripts/gen-sorted.awk $(all-Depend-files) \ $(common-objpfx)sysd-dirs $(..)Makeconfig { { dirs='$(patsubst $(..)%/Depend,$(..)%,$(filter %/Depend,$^))';\ diff -Naur ../glibc-2.1.3/Makefile.in glibc-2.1.3/Makefile.in --- ../glibc-2.1.3/Makefile.in 1998-02-26 06:51:55.000000000 -0800 +++ glibc-2.1.3/Makefile.in 1998-03-12 12:17:58.000000000 -0800 @@ -1,4 +1,4 @@ -# Generated from $Id: Makefile.in,v 1.6 1998/02/26 14:51:55 drepper Exp $. +# Generated from $Id: Makefile.in,v 1.1.1.1 1998/03/12 20:17:58 gafton Exp $. srcdir = @srcdir@ diff -Naur ../glibc-2.1.3/README-alpha glibc-2.1.3/README-alpha --- ../glibc-2.1.3/README-alpha 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/README-alpha 1999-06-16 15:30:43.000000000 -0700 @@ -0,0 +1,287 @@ + GNU libc SNAPSHOT SYSTEM + (general info) + Updated 1997-9-26 + +WHAT ARE GNU libc SNAPSHOTS +--------------------------- + +Snapshots are an "image" of the main glibc development tree, captured at a +particular random instant in time. When you use the snapshots, you should be +able to maintain a local copy of libc that is no more than one day older than +the official source tree used by the libc maintainers. + +The primary purpose of providing snapshots is to widen the group of motivated +developers that would like to help test, debug, and enhance glibc, by providing +you with access to the "latest and greatest" source. This has several +advantages, and several disadvantages. + + First the advantages: + + o Once we have a large base of motivated testers using the snapshots, + this should provide good coverage across all currently supported + glibc hosts and targets. If a new bug is introduced in glibc due to + fixing another bug or ongoing development, it should become + obvious much more quickly and get fixed before the next general + net release. This should help to reduce the chances of glibc being + released to the general public with a major bug that went unnoticed + during the release cycle testing because they are machine dependent. + We hope to greatly improve glibc's stability and reliability by + involving more people and more execution environments in the + prerelease testing. + + o With access to the latest source, any diffs that you send to fix + bugs or add new features should be much easier for the glibc team + to merge into the official source base (after suitable review + of course). This encourages us to merge your changes quicker, + while they are still "fresh". + + o Once your diffs are merged, you can obtain a new copy of glibc + containing your changes almost immediately. Thus you do not + have to maintain local copies of your changes for any longer + than it takes to get them merged into the official source base. + This encourages you to send in changes quicker. + + And the disadvantages: + + o The snapshot you get will be largely untested and of unknown quality. + It may fail to configure or compile. It may have serious bugs. + You should always keep a copy of the last known working version + before updating to the current snapshot, or at least be able to + regenerate a working version if the latest snapshot is unusable + in your environment for some reason. + + If a production version of glibc has a bug and a snapshot has the fix, + and you care about stability, you should put only the fix for that + particular problem into your production version. Of course, if you + are eager to test glibc, you can use the snapshot versions in your + daily work, but users who have not been consulted about whether they + feel like testing glibc should generally have something which is at + least as bug free as the last released version. + + o Providing timely response to your questions, bug reports, and + submitted patches will require the glibc development team to allocate + time from an already thin time budget. Please try to help us make + this time as productive as possible. See the section below about + how to submit changes. + + +WHO SHOULD TRY THE SNAPSHOTS +---------------------------- + +Remember, these are snapshots not tested versions. So if you use +these versions you should be able to + + o make sure your system stays usable + + o locate and hopefully fix problems + + o to port glibc to a new target yourself + +You should not use the snapshots if + + o your system is needed in a production environment which needs + stability + + o you expect us to fix your problems since you somehow depend on them. + You must be willing to fix the problems yourself, we don't want to + see "I have problems, fix this" messages. + + +HOW TO GET THE SNAPSHOTS +------------------------ + +At the moment we provide a full snapshot weekly (every sunday), so +that users getting a snapshot for the first time, or updating after +a long period of not updating, can get the latest version in a single +operation. Along with the full snapshot, we will provide incremental +diffs on a nearly daily basis (whenever code changes). Each daily +diff will be relative to the source tree after applying all previous +daily diffs. The daily diffs are for people who have relatively low +bandwidth ftp or uucp connections. + +The files will be available via anonymous ftp from alpha.gnu.org, in +directory /gnu/libc and on linux.kernel.org in /pub/software/libs/glibc. The +directories should look something like: + + libc-970921.tar.gz + libc-970917-970922.diff.gz + libc-970922-970925.diff.gz + . + . + . + +Please note that the snapshots on alpha.gnu.org and on +linux.kernel.org are not always in sync. Patches to some files might +appear a day a diff earlier or later on alpha than on kernel. +Use always alpha or always kernel but don't mix them. + +There are sometimes additionally test releases of the add-ons available in +these directories. If a new version of an add-on is available it is normally +required for the corresponding snapshot so always pay attention for these. + +Note that we provide GNU gzip compressed files only. You can ftp gzip +from ftp.gnu.org in directory pub/gnu. + +In some cases the dates for diffs and snapshots do not match like in the +example above. The full release is for 970921 but the patch is for +970917-970922. This only means that nothing changed between 970917 and 970922 +and that you have to use this patch on top of the 970921 snapshot since the +patch is made on 970922. + +Also, as the gcc developers did with their gcc snapshot system, even though we +will make the snapshots available on a publically accessible ftp area, we ask +that recipients not widely publicise their availability. The motivation for +this request is not to hoard them, but to avoid the situation where the +general glibc user base naively attempts to use the snapshots, has trouble with +them, complains publically, and the reputation of glibc declines because of a +perception of instability or lack of quality control. + + +GLIBC TEST SUITE +---------------- + +A test suite is distributed as an integral part of the snapshots. A simple +"make check" in your build directory is sufficient to run the tests. glibc +should pass all tests and if any fails, please report it. A failure might not +originate from a bug in glibc but also from bugs in the tools, e.g. with gcc +2.7.2.x the math tests fail some of the tests because of compiler bugs. + +Note that the test suite is still in its infancy. The tests themselves only +cover a small portion of libc features, and where tests do exist for a feature +they are not exhaustive. New tests are welcome. + + +GETTING HELP, GLIBC DISCUSSIONS, etc +------------------------------------ + +People who want to help with glibc and who test out snapshots +regularly should get on the libc-alpha@sourceware.cygnus.com mailing +list by sending an email to libc-alpha-subscribe@sourceware.cygnus.com. +This list is meant (as the name suggests) for the discussion of test +releases and also reports for them. People who are on this list are +welcome to post questions of general interest. + +People who are not only willing to test the snapshots but instead +really want to help developing glibc should contact +libc-hacker-subscribe@sourceware.cygnus.com.org to be put on the developers +mailing list. This list is really only meant for developers. No +questions about installation problems or other simple topics are +wanted nor will they be answered. + +Do *not* send any questions about the snapshots or patches specific to the +snapshots to bug-glibc@gnu.org. Nobody there will have any idea what +you are talking about and it will just cause confusion. + + +BUG REPORTS +----------- + +Send bug reports directly to Ulrich Drepper . Please +do *not* use the glibcbug script for reporting bugs in the snapshots. +glibcbug should only be used for problems with the official released versions. +We don't like bug reports in the bug database because otherwise the impression +of instability or lack of quality control of glibc as a whole might manifest +in people's mind. + +Note that since no testing is done on the snapshots, and snapshots may even be +made when glibc is in an inconsistent state, it may not be unusual for an +occasional snapshot to have a very obvious bug, such as failure to compile on +*any* machine. It is likely that such bugs will be fixed by the next +snapshot, so it really isn't necessary to report them unless they persist for +a couple of days. + +Missing files should always be reported, since they usually mean there is a +problem with the snapshot-generating process and we won't know about them +unless someone tells us. + +Bugs which are non-obvious, such as failure to compile on only a specific +machine, a new machine dependent or obscure bug (particularly one not detected +by the testsuite), etc should be reported when you discover them, or have a +suggested patch to fix them. + + +FORMAT FOR PATCHES +------------------ + +If you have a fix for a bug, or an enhancement to submit, send your patch to +Ulrich Drepper . Here are some simple guidelines for +submitting patches: + + o Use "unified diffs" for patches. A typical command for generating + context diffs is "diff -ru glibc-old glibc-patched". + + o Use the "minimalist approach" for patches. That is, each patch + should address only one particular bug, new feature, etc. Do not + save up many unrelated changes and submit them all in one big + patch, since in general, the larger the patch the more difficult + it is for us to decide if the patch is either correct or + desirable. And if we find something about the patch that needs + to be corrected before it can be installed, we would have to reject + the entire patch, which might contain changes which otherwise would + be accepted if submitted separately. + + o Submit a sample ChangeLog entry with your patch. See the existing + glibc ChangeLog for examples of what a ChangeLog entry should look + like. The emacs command ^X4A will create a ChangeLog entry header + for you. + + +BUILDING SNAPSHOTS +------------------ + +The `best' way to build glibc is to use an extra directory, e.g.: +tar xzf libc-970921.tar.gz +mkdir build-glibc +cd build-glibc +../libc-970921/configure ... + +In this way you can easily clean up (since `make clean' doesn't work at +the moment) and rebuild glibc. + + +NECESSARY TOOLS +--------------- + +For the recommended versions of gcc, binutils, make, texinfo, gettext, +autoconf and other tools which might be especially needed when using patches, +please read the file INSTALL. + + +HOW CAN YOU HELP +---------------- + +It helps already a lot if you just install glibc on your system and try to +solve any problems. You might want to look at the file `PROJECTS' and help +with one of those projects, fix some bugs (see `BUGS' or the bug database), +port to an unsupported platform, ... + + +FURTHER DOCUMENTATION +--------------------- + +A lot of questions are answered in the FAQ. The files `INSTALL', `README' and +`NOTES' contain the most important documentation. Furthermore glibc has its +own 700+ pages info documentation, ... + + + +And finally a word of caution: The libc is one of the most fundamental parts +of your system - and these snapshots are untested and come without any +guarantee or warranty. You might be lucky and everything works or you might +crash your system. If you install a glibc snapshot as primary library, you +should have a backup somewhere. + +On many systems it is also a problem to replace the libc while the system is +running. In the worst case on broken OSes some systems crash. On better +systems you can move the old libc aside but removing it will cause problems +since there are still processes using this libc image and so you might have to +check the filesystem to get rid of the libc data. One good alternative (which +is also safer) is to use a chroot'ed environment. + +Thanks for your help and support. + +Thanks to Fred Fish from Cygnus for the original version of this text +(for GDB). + + +Ulrich Drepper diff -Naur ../glibc-2.1.3/README.template glibc-2.1.3/README.template --- ../glibc-2.1.3/README.template 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/README.template 1999-07-28 15:46:07.000000000 -0700 @@ -0,0 +1,96 @@ +This directory contains the version VERSION release of the GNU C Library. +Many bugs have been fixed since the last release. +Some bugs surely remain. + +As of this release, the GNU C library is known to run on the following +configurations: + + *-*-gnu GNU Hurd + i[3456]86-*-linux-gnu Linux-2.x on Intel + m68k-*-linux-gnu Linux-2.x on Motorola 680x0 + alpha-*-linux-gnu Linux-2.x on DEC Alpha + powerpc-*-linux-gnu Linux and MkLinux on PowerPC systems + sparc-*-linux-gnu Linux-2.x on SPARC + sparc64-*-linux-gnu Linux-2.x on UltraSPARC + arm-*-none ARM standalone systems + arm-*-linux Linux-2.x on ARM + arm-*-linuxaout Linux-2.x on ARM using a.out binaries + + +Former releases of this library (version 1.09.1 and perhaps earlier +versions) used to run on the following configurations: + + alpha-dec-osf1 + i[3456]86-*-bsd4.3 + i[3456]86-*-isc2.2 + i[3456]86-*-isc3 + i[3456]86-*-sco3.2 + i[3456]86-*-sco3.2v4 + i[3456]86-*-sysv + i[3456]86-*-sysv4 + i[3456]86-force_cpu386-none + i[3456]86-sequent-bsd + i960-nindy960-none + m68k-hp-bsd4.3 + m68k-mvme135-none + m68k-mvme136-none + m68k-sony-newsos3 + m68k-sony-newsos4 + m68k-sun-sunos4 + mips-dec-ultrix4 + mips-sgi-irix4 + sparc-sun-solaris2 + sparc-sun-sunos4 + +Since no one has volunteered to test and fix the above configurations, +these are not supported at the moment. It's expected that these don't +work anymore. Porting the library is not hard. If you are interested +in doing a port, please contact the glibc maintainers by sending +electronic mail to . + +The GNU C library now includes Michael Glad's Ultra Fast Crypt, which +provides the Unix `crypt' function, plus some other entry points. +Because of the United States export restriction on DES +implementations, we are distributing this code separately from the +rest of the C library. There is an extra distribution tar file just +for crypt; it is called `glibc-crypt-VERSION.tar.gz'. You can just +unpack the crypt distribution along with the rest of the C library and +build; you can also build the library without getting crypt. Users +outside the USA can get the crypt distribution via anonymous FTP from +ftp.gwdg.de [134.76.11.100] in the directory pub/linux/glibc, or +another archive site outside the USA. Archive maintainers are +encouraged to copy this distribution to their archives outside the +USA. Please get it from ftp.gwdg.de; transferring this distribution +from ftp.gnu.org (or any other site in the USA) to a site outside the +USA is in violation of US export laws. + +Beside the separate crypt tar file there are some more add-ons which can be +used together with GNU libc. They are designed in a way to ease the +installation by integrating them in the libc source tree. Simply get the +add-ons you need and use the --enable-add-ons option of the `configure' +script to tell where the add-ons are found. Please read the FAQ file for +more details. + +See the file INSTALL to find out how to configure, build, install, and port +the GNU C library. You might also consider reading the WWW pages for the +GNU libc at http://www.gnu.org/software/libc/libc.html. + +The GNU C Library is completely documented by the Texinfo manual found +in the `manual/' subdirectory. The manual is still being updated and +contains some known errors and omissions; we regret that we do not +have the resources to work on the manual as much as we would like. +Please send comments on the manual to , and +not to the library bug-reporting address. + +The file NOTES contains a description of the feature-test macros used +in the GNU C library, explaining how you can tell the library what +facilities you want it to make available. + +We prefer to get bug reports sent using the `glibcbug' shell script which +is installed together with the rest of the GNU libc to . +Simply run this shell script and fill in the information. Nevertheless +you can still send bug reports to as normal electronic +mails. + +The GNU C Library is free software. See the file COPYING.LIB for copying +conditions. diff -Naur ../glibc-2.1.3/Versions.def glibc-2.1.3/Versions.def --- ../glibc-2.1.3/Versions.def 1999-11-15 16:24:57.000000000 -0800 +++ glibc-2.1.3/Versions.def 1999-12-27 08:16:06.000000000 -0800 @@ -31,6 +31,7 @@ libnsl { GLIBC_2.0 GLIBC_2.1 GLIBC_2.0 + GLIBC_2.1.2 GLIBC_2.1 } libnss_compat { GLIBC_2.0 diff -Naur ../glibc-2.1.3/c_stubs/Banner glibc-2.1.3/c_stubs/Banner --- ../glibc-2.1.3/c_stubs/Banner 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/c_stubs/Banner 2000-02-25 16:35:04.000000000 -0800 @@ -0,0 +1 @@ +The C stubs add-on version 2.1.2. diff -Naur ../glibc-2.1.3/c_stubs/COPYING.LIB glibc-2.1.3/c_stubs/COPYING.LIB --- ../glibc-2.1.3/c_stubs/COPYING.LIB 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/c_stubs/COPYING.LIB 2000-02-25 16:35:05.000000000 -0800 @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 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. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff -Naur ../glibc-2.1.3/c_stubs/ChangeLog glibc-2.1.3/c_stubs/ChangeLog --- ../glibc-2.1.3/c_stubs/ChangeLog 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/c_stubs/ChangeLog 2000-02-27 11:35:23.000000000 -0800 @@ -0,0 +1,32 @@ +2000-02-27 Cristian Gafton + + * gconv_stubs.c: Return __gconv_OK for: + __gconv_transform_ascii_internal + __gconv_transform_ucs2little_internal + __gconv_transform_utf16_internal + __gconv_transform_utf8_internal + __gconv_transform_ucs2_internal + +2000-02-25 Cristian Gafton + + * gconv_stubs.c: add __c_stubs_is_compiled_in so we can detect when + the library is linked in. + +Wed Dec 8 13:47:25 1999 Ivan Brunello + + * Makefile (extra-objs): Changed stubs.o to gconv_stubs.o. + +Sun Dec 5 11:32:17 1999 H.J. Lu + + * gconv_stubs.c: Renamed from stubs.c. + Support glibc 2.1.x. + +Mon Aug 23 16:42:05 1999 H.J. Lu + + * Banner: New. + * COPYING.LIB: Likewise. + * Makefile: Likewise. + * README: Likewise. + * configure: Likewise. + * stubs.c: Likewise. + * test-stdio.c: Likewise. diff -Naur ../glibc-2.1.3/c_stubs/Makefile glibc-2.1.3/c_stubs/Makefile --- ../glibc-2.1.3/c_stubs/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/c_stubs/Makefile 2000-02-25 16:35:05.000000000 -0800 @@ -0,0 +1,46 @@ +# Copyright (C) 1999 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# The GNU C Library 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 +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public +# License along with the GNU C Library; see the file COPYING.LIB. If not, +# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# +# Sub-makefile for the C stub add-on library. +# +subdir := c_stubs + +tests-static := test-stdio +tests := $(tests-static) + +libc_stubs-objs := gconv_stubs.o + +install-lib := libc_stubs.a +non-lib.a := libc_stubs.a + +extra-objs := gconv_stubs.o libc_stubs.a + +include ../Makeconfig + +CPPFLAGS += -I../iconv + +include ../Rules + +$(objpfx)libc_stubs.a: $(addprefix $(objpfx), $(libc_stubs-objs)) + -rm -f $@ + $(LD) -r -o $@ $^ + +lib: $(objpfx)libc_stubs.a + +$(objpfx)test-stdio: $(objpfx)libc_stubs.a diff -Naur ../glibc-2.1.3/c_stubs/README glibc-2.1.3/c_stubs/README --- ../glibc-2.1.3/c_stubs/README 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/c_stubs/README 2000-02-25 16:35:05.000000000 -0800 @@ -0,0 +1,8 @@ +This is a stub add-on library for the GNU C library version 2.1.2 and +above. It is used to create the smaller static binaries by stubbing +out the gconv related functions. The resulting binaries may not have +all the functionalities. + +H.J. Lu +hjl@gnu.org +12/05/1999 diff -Naur ../glibc-2.1.3/c_stubs/configure glibc-2.1.3/c_stubs/configure --- ../glibc-2.1.3/c_stubs/configure 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/c_stubs/configure 2000-02-25 16:35:05.000000000 -0800 @@ -0,0 +1,2 @@ +# This is only to keep the GNU C library configure mechanism happy. +exit 0 diff -Naur ../glibc-2.1.3/c_stubs/gconv_stubs.c glibc-2.1.3/c_stubs/gconv_stubs.c --- ../glibc-2.1.3/c_stubs/gconv_stubs.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/c_stubs/gconv_stubs.c 2000-02-27 11:35:23.000000000 -0800 @@ -0,0 +1,83 @@ +/* Provide gconv stub functions for the minimum static binaries. + Copyright (C) 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include + +/* hack for self identification */ +int __c_stubs_is_compiled_in; + +/* Don't drag in the dynamic linker. */ +void *__libc_stack_end; + +int +__gconv_OK () +{ +#if __GLIBC__ > 2 || __GLIBC_MINOR__ > 1 + return __GCONV_OK; +#else + return GCONV_OK; +#endif +} + +int +__gconv_NOCONV () +{ +#if __GLIBC__ > 2 || __GLIBC_MINOR__ > 1 + return __GCONV_NOCONV; +#else + return GCONV_NOCONV; +#endif +} + +strong_alias (__gconv_OK, + __gconv_close_transform); + +strong_alias (__gconv_NOCONV, + __gconv); +strong_alias (__gconv_NOCONV, + __gconv_find_transform); +strong_alias (__gconv_NOCONV, + __gconv_open); + +/* These transformations should not fail in normal conditions */ +strong_alias (__gconv_OK, + __gconv_transform_ascii_internal); +strong_alias (__gconv_OK, + __gconv_transform_ucs2little_internal); +strong_alias (__gconv_OK, + __gconv_transform_utf16_internal); +strong_alias (__gconv_OK, + __gconv_transform_utf8_internal); +strong_alias (__gconv_OK, + __gconv_transform_ucs2_internal); + +/* We can assume no conversion for these ones */ +strong_alias (__gconv_NOCONV, + __gconv_transform_internal_ascii); +strong_alias (__gconv_NOCONV, + __gconv_transform_internal_ucs2); +strong_alias (__gconv_NOCONV, + __gconv_transform_internal_ucs2little); +strong_alias (__gconv_NOCONV, + __gconv_transform_internal_ucs4); +strong_alias (__gconv_NOCONV, + __gconv_transform_internal_utf16); +strong_alias (__gconv_NOCONV, + __gconv_transform_internal_utf8); diff -Naur ../glibc-2.1.3/c_stubs/test-stdio.c glibc-2.1.3/c_stubs/test-stdio.c --- ../glibc-2.1.3/c_stubs/test-stdio.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/c_stubs/test-stdio.c 2000-02-25 16:35:05.000000000 -0800 @@ -0,0 +1,8 @@ +#include + +int +main () +{ + printf ("Hello world\n"); + return 0; +} diff -Naur ../glibc-2.1.3/config-name.in glibc-2.1.3/config-name.in --- ../glibc-2.1.3/config-name.in 1994-12-08 01:12:33.000000000 -0800 +++ glibc-2.1.3/config-name.in 1998-02-07 12:00:39.000000000 -0800 @@ -1,5 +1,5 @@ /* @configure_input@ -*- C -*- - Generated from $Id: config-name.in,v 1.1 1994/12/08 09:12:33 roland Exp $. + Generated from $Id: config-name.in,v 1.1.1.1 1998/02/07 20:00:39 gafton Exp $. This is used only by the generic `uname' function for systems with no real `uname' call. If this data is not correct, it does not matter much. */ diff -Naur ../glibc-2.1.3/config.make.in glibc-2.1.3/config.make.in --- ../glibc-2.1.3/config.make.in 2000-02-11 15:49:41.000000000 -0800 +++ glibc-2.1.3/config.make.in 2000-02-14 12:05:50.000000000 -0800 @@ -1,5 +1,5 @@ # @configure_input@ -# From $Id: config.make.in,v 1.61.2.2 2000/02/11 20:45:02 drepper Exp $. +# From $Id: config.make.in,v 1.1.1.2 2000/02/14 20:05:50 gafton Exp $. # Don't edit this file. Put configuration parameters in configparms instead. version = @VERSION@ diff -Naur ../glibc-2.1.3/db2/include/queue.h glibc-2.1.3/db2/include/queue.h --- ../glibc-2.1.3/db2/include/queue.h 1998-06-09 08:03:53.000000000 -0700 +++ glibc-2.1.3/db2/include/queue.h 1998-07-09 11:45:13.000000000 -0700 @@ -1,4 +1,4 @@ -/* BSDI $Id: queue.h,v 1.3 1998/06/09 15:03:53 drepper Exp $ */ +/* BSDI $Id: queue.h,v 1.1.1.1 1998/07/09 18:45:13 gafton Exp $ */ /* * Copyright (c) 1991, 1993 diff -Naur ../glibc-2.1.3/elf/rtld.c glibc-2.1.3/elf/rtld.c --- ../glibc-2.1.3/elf/rtld.c 2000-02-22 23:02:47.000000000 -0800 +++ glibc-2.1.3/elf/rtld.c 2000-02-23 14:48:17.000000000 -0800 @@ -758,6 +758,60 @@ __munmap (file, file_size); } + + /* + * Modifications by Red Hat Software + * + * Deal with the broken binaries from the non-versioned ages of glibc. + * If a binary does not have version information enebled, we assume that + * it is a glibc 2.0 binary andwe load a compatibility library to try to + * overcome binary incompatibilities. + * Blame: gafton@redhat.com + */ +#define LIB_NOVERSION "/lib/libNoVersion.so.1" + + if (_dl_loaded->l_info[DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (DT_VERNEED)] == NULL) { + struct link_map *new_map = NULL; + struct stat test_st; + int test_fd; + int can_load; + + HP_TIMING_NOW (start); + +/* _dl_sysdep_message("Loading compatibility library... ", NULL); */ + + can_load = 1; + test_fd = __open (LIB_NOVERSION, O_RDONLY); + if (test_fd < 0) { + can_load = 0; +/* _dl_sysdep_message(" Can't find " LIB_NOVERSION "\n", NULL); */ + } else { + if (__fxstat (_STAT_VER, test_fd, &test_st) < 0 || test_st.st_size == 0) { + can_load = 0; +/* _dl_sysdep_message(" Can't stat " LIB_NOVERSION "\n", NULL); */ + } + } + + if (test_fd >= 0) /* open did no fail.. */ + __close(test_fd); /* avoid fd leaks */ + + if (can_load != 0) { + new_map = _dl_map_object (_dl_loaded, LIB_NOVERSION, + 1, lt_library, 0); + if (new_map->l_opencount == 1) { + /* It is no duplicate. */ + ++npreloads; +/* _dl_sysdep_message(" DONE\n", NULL); */ + } else { +/* _dl_sysdep_message(" FAILED\n", NULL); */ + } + } + + HP_TIMING_NOW (stop); + HP_TIMING_DIFF (diff, start, stop); + HP_TIMING_ACCUM_NT (load_time, diff); + } + if (npreloads != 0) { /* Set up PRELOADS with a vector of the preloaded libraries. */ diff -Naur ../glibc-2.1.3/glibc-2.1.spec glibc-2.1.3/glibc-2.1.spec --- ../glibc-2.1.3/glibc-2.1.spec 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-2.1.spec 2000-02-29 13:27:37.000000000 -0800 @@ -0,0 +1,305 @@ +Summary: The GNU libc libraries. +Name: glibc +Version: 2.1.3 +Release: 15 +Copyright: LGPL +Group: System Environment/Libraries +Source: %{name}-%{version}.tar.gz +# Other sources are available at: +# http://www.ozemail.com.au/~geoffk/glibc-crypt/glibc-crypt-2.1.tar.gz +# In the source tarball the file diff-CYGNUS-to-REDHAT.patch contains all +# diffs applied by Red Hat to the current CVS version of glibc +Buildroot: /var/tmp/glibc-%{PACKAGE_VERSION}-root +Obsoletes: zoneinfo, libc-static, libc-devel, libc-profile, libc-headers, +Obsoletes: linuxthreads, gencat, locale +Autoreq: false +%ifarch alpha +Provides: ld.so.2 +%else +%endif +%ifarch sparc +Obsoletes: libc +%endif + +%description +The glibc package contains standard libraries which are used by +multiple programs on the system. In order to save disk space and +memory, as well as to make upgrading easier, common system code is +kept in one place and shared between programs. This particular package +contains the most important sets of shared libraries: the standard C +library and the standard math library. Without these two libraries, a +Linux system will not function. The glibc package also contains +national language (locale) support and timezone databases. + +%package devel +Summary: Header and object files for development using standard C libraries. +Group: Development/Libraries +Conflicts: texinfo < 3.11 +Prereq: /sbin/install-info +Obsoletes: libc-debug, libc-headers, libc-devel, linuxthreads-devel +Obsoletes: glibc-debug +Prereq: kernel-headers +Requires: kernel-headers >= 2.2.1 +Autoreq: true + +%description devel +The glibc-devel package contains the header and object files necessary +for developing programs which use the standard C libraries (which are +used by nearly all programs). If you are developing programs which +will use the standard C libraries, your system needs to have these +standard header and object files available in order to create the +executables. + +Install glibc-devel if you are going to develop programs which will +use the standard C libraries. + +%package profile +Summary: The GNU libc libraries, including support for gprof profiling. +Group: Development/Libraries +Obsoletes: libc-profile +Autoreq: true + +%description profile +The glibc-profile package includes the GNU libc libraries and support +for profiling using the gprof program. Profiling is analyzing a +program's functions to see how much CPU time they use and determining +which functions are calling other functions during execution. To use +gprof to profile a program, your program needs to use the GNU libc +libraries included in glibc-profile (instead of the standard GNU libc +libraries included in the glibc package). + +If you are going to use the gprof program to profile a program, you'll +need to install the glibc-profile program. + +%package -n nscd +Summary: A Name Service Caching Daemon (nscd). +Group: System Environment/Daemons +Conflicts: kernel < 2.2.0 +Prereq: /sbin/chkconfig +Autoreq: true + +%description -n nscd +Nscd caches name service lookups and can dramatically improve +performance with NIS+, and may help with DNS as well. Note that you +can't use nscd with 2.0 kernels because of bugs in the kernel-side +thread support. Unfortunately, nscd happens to hit these bugs +particularly hard. + +Install nscd if you need a name service lookup caching daemon, and +you're not using a version 2.0 kernel. + +%prep +%setup -q + +%ifarch armv4l +rm -rf glibc-compat +%endif + +find . -type f -size 0 -o -name "*.orig" -exec rm -f {} \; + +%build +rm -rf build-$RPM_ARCH-linux +mkdir build-$RPM_ARCH-linux ; cd build-$RPM_ARCH-linux +%ifarch i586 i686 +BuildFlags="-mpentium -D__USE_STRING_INLINES -fstrict-aliasing -mcpu=%{_target_cpu}" +%endif +%ifarch sparcv9 +BuildFlags="-mv8 -mtune=ultrasparc" +%endif +CC=egcs CFLAGS="$BuildFlags -g -O3" ../configure --prefix=/usr \ + --enable-add-ons=yes --without-cvs \ + %{_target_cpu}-redhat-linux +make -r CFLAGS="$BuildFlags -g -O3" PARALLELMFLAGS=-s + +%install +rm -rf $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT +make install_root=$RPM_BUILD_ROOT install -C build-$RPM_ARCH-linux +cd build-$RPM_ARCH-linux && \ + make install_root=$RPM_BUILD_ROOT install-locales -C ../localedata objdir=`pwd` && \ + cd .. + +# compatibility hack: this locale has vanished from glibc, but some other +# programs are still using it. Normally we would handle it in the %pre +# section but with glibc that is simply not an option +mkdir -p $RPM_BUILD_ROOT/usr/share/locale/ru_RU/LC_MESSAGES + +# Remove the files we don't want to distribute +rm -f $RPM_BUILD_ROOT/usr/lib/libNoVersion* + +# the man pages for the linuxthreads require special attention +make -C linuxthreads/man +mkdir -p $RPM_BUILD_ROOT/usr/man/man3 +install -m 0644 linuxthreads/man/*.3thr $RPM_BUILD_ROOT/usr/man/man3 +gzip -9nvf $RPM_BUILD_ROOT/usr/man/man3/* + +gzip -9nvf $RPM_BUILD_ROOT/usr/info/libc* + +ln -sf libbsd-compat.a $RPM_BUILD_ROOT/usr/lib/libbsd.a + +install -m 644 redhat/nsswitch.conf $RPM_BUILD_ROOT/etc/nsswitch.conf + +# Take care of setuids +# -- new security review sez that this shouldn't be needed anymore +#chmod 755 $RPM_BUILD_ROOT/usr/libexec/pt_chown + +# This is for ncsd - in glibc 2.1 +install -m 644 nscd/nscd.conf $RPM_BUILD_ROOT/etc +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d +install -m 755 nscd/nscd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/nscd + +# The database support +mkdir -p $RPM_BUILD_ROOT/var/db +install -m 644 nss/db-Makefile $RPM_BUILD_ROOT/var/db/Makefile + +# Strip binaries +strip $RPM_BUILD_ROOT/sbin/* || : +strip $RPM_BUILD_ROOT/usr/bin/* || : +strip $RPM_BUILD_ROOT/usr/sbin/* || : + +# BUILD THE FILE LIST +find $RPM_BUILD_ROOT -type f -or -type l | + sed -e 's|.*/etc|%config &|' > rpm.filelist.in +for n in /usr/share /usr/include; do + find ${RPM_BUILD_ROOT}${n} -type d | \ + grep -v '^/usr/share$' | \ + sed "s/^/%dir /" >> rpm.filelist.in +done + +# primary filelist +sed "s|$RPM_BUILD_ROOT||" < rpm.filelist.in | + grep -v '/etc/localtime' | \ + grep -v '/etc/nsswitch.conf' | \ + sort > rpm.filelist + +grep '/usr/lib/lib.*_p\.a' < rpm.filelist > profile.filelist +egrep "(/usr/include)|(/usr/info)" < rpm.filelist | + grep -v /usr/info/dir > devel.filelist + +mv rpm.filelist rpm.filelist.full +grep -v '/usr/lib/lib.*_p.a' rpm.filelist.full | + egrep -v "(/usr/include)|(/usr/info)" > rpm.filelist + +grep '/usr/lib/lib.*\.a' < rpm.filelist >> devel.filelist +grep '/usr/lib/.*\.o' < rpm.filelist >> devel.filelist +grep '/usr/lib/lib.*\.so' < rpm.filelist >> devel.filelist +grep '/usr/man/man' < rpm.filelist >> devel.filelist + +mv rpm.filelist rpm.filelist.full +grep -v '/usr/lib/lib.*\.a' < rpm.filelist.full | + grep -v '/usr/lib/.*\.o' | + grep -v '/usr/lib/lib.*\.so'| + grep -v '/usr/man/man' | + grep -v 'nscd' > rpm.filelist + +# /etc/localtime - we're proud of our timezone +rm -f $RPM_BUILD_ROOT/etc/localtime +cp -f $RPM_BUILD_ROOT/usr/share/zoneinfo/US/Eastern $RPM_BUILD_ROOT/etc/localtime +#ln -sf ../usr/share/zoneinfo/US/Eastern $RPM_BUILD_ROOT/etc/localtime + +# the last bit: more documentation +rm -rf documentation +mkdir documentation +cp linuxthreads/ChangeLog documentation/ChangeLog.threads +cp linuxthreads/Changes documentation/Changes.threads +cp linuxthreads/README documentation/README.threads +cp linuxthreads/FAQ.html documentation/FAQ-threads.html +cp -r linuxthreads/Examples documentation/examples.threads +cp crypt/README documentation/README.crypt +cp db2/README documentation/README.db2 +cp db2/mutex/README documentation/README.db2.mutex +cp timezone/README documentation/README.timezone +cp ChangeLog* documentation +gzip -9 documentation/ChangeLog* + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%post devel +/sbin/install-info /usr/info/libc.info.gz /usr/info/dir + +%pre devel +# this used to be a link and it is causing nightmares now +if [ -L /usr/include/scsi ] ; then + rm -f /usr/include/scsi +fi + +%preun devel +if [ "$1" = 0 ]; then + /sbin/install-info --delete /usr/info/libc.info.gz /usr/info/dir +fi + +%post -n nscd +/sbin/chkconfig --add nscd + +%preun -n nscd +if [ $1 = 0 ] ; then + /sbin/chkconfig --del nscd +fi + +%clean +rm -rf "$RPM_BUILD_ROOT" +rm -f *.filelist* + +%files -f rpm.filelist +%defattr(-,root,root) +%config(noreplace) /etc/localtime +%config(noreplace) /etc/nsswitch.conf +%doc README NEWS INSTALL FAQ BUGS NOTES PROJECTS +%doc documentation/* README.template README.libm +%doc login/README.utmpd hesiod/README.hesiod +%dir /var/db + +%ifnarch sparcv9 i586 i686 +%files -f devel.filelist devel +%defattr(-,root,root) + +%files -f profile.filelist profile +%defattr(-,root,root) + +%files -n nscd +%defattr(-,root,root) +%config /etc/nscd.conf +/etc/rc.d/init.d/nscd +/usr/sbin/nscd +%endif + +%define date %(echo `LC_ALL="C" date +"%a %b %d %Y"`) + +%changelog +* %{date} Cristian Gafton +- fix c_stubs add-on to work around various assert()s in glibc +- add Davem's patch for _NPROCESSORS_ONLN on Sparc + +* Fri Feb 25 2000 Cristian Gafton +- add the c_stubs add-on +- sparc patch from davem + +* Thu Feb 24 2000 Cristian Gafton +- fix locale problems on 64 bit arches + +* Tue Feb 22 2000 Cristian Gafton +- cygnus sync up for fixes to nscd + +* Thu Feb 17 2000 Cristian Gafton +- updated to include new China timezones +- sync up with the locale changes from Cygnus + +* Tue Feb 01 2000 Cristian Gafton +- updated from cygnus branch +- fix syslog so that it will continuously try to fallback from SOK_DGRAM to + SOCK_STREAM and backwards + +* Mon Jan 31 2000 Cristian Gafton +- update from cygnus branch +- compress man pages for the linuxthreads stuff + +* Fri Jan 21 2000 Cristian Gafton +- add Jakub's patch so we back out even more + +* Thu Jan 20 2000 Cristian Gafton +- back out the setrlimit changes (well, sort of) + +* Mon Jan 03 2000 Cristian Gafton +- make release from CVS server directly now diff -Naur ../glibc-2.1.3/glibc-compat/.cvsignore glibc-2.1.3/glibc-compat/.cvsignore --- ../glibc-2.1.3/glibc-compat/.cvsignore 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/.cvsignore 2000-01-03 18:17:33.000000000 -0800 @@ -0,0 +1 @@ +glibc-compat*.tar.gz diff -Naur ../glibc-2.1.3/glibc-compat/Banner glibc-2.1.3/glibc-compat/Banner --- ../glibc-2.1.3/glibc-compat/Banner 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/Banner 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1 @@ +Glibc-2.0 compatibility add-on by Cristian Gafton diff -Naur ../glibc-2.1.3/glibc-compat/ChangeLog glibc-2.1.3/glibc-compat/ChangeLog --- ../glibc-2.1.3/glibc-compat/ChangeLog 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/ChangeLog 2000-02-23 17:59:39.000000000 -0800 @@ -0,0 +1,24 @@ +2000-02-23 Cristian Gafton + + * stubs.c (__setfpucw): Avoid using _FPU_SETCW on platform that do not have it + +1999-07-08 Cristian Gafton + + * stubs.c (__setfpucw): New function + * Makefile: Use -include, not include + (archive): New target. + + +1999-04-09 Andreas Jaeger + * glibc-compat/Makefile: Add rules to link libnss_*.so.1 to libnss1_*.so.2. + +1998-11-18 Cristian Gafton + + * shlib-versions: added alpha versions + + * Makefile (services): Added libnss_dns + +1998-11-16 Cristian Gafton + + * makedist (archive): remove old tar file just in case + diff -Naur ../glibc-2.1.3/glibc-compat/Depend glibc-2.1.3/glibc-compat/Depend --- ../glibc-2.1.3/glibc-compat/Depend 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/Depend 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,3 @@ +resolv +nss +nis diff -Naur ../glibc-2.1.3/glibc-compat/Makefile glibc-2.1.3/glibc-compat/Makefile --- ../glibc-2.1.3/glibc-compat/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/Makefile 2000-01-06 09:33:12.000000000 -0800 @@ -0,0 +1,152 @@ +# Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +# This is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# The GNU C Library 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 +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public +# License along with the GNU C Library; see the file COPYING.LIB. If not, +# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# $Id: Makefile,v 1.2 2000/01/06 17:33:12 gafton Exp $ + +subdir := glibc-compat + +distribute := nss-nis.h + +# This is the trivial part which goes into libc itself. +routines = + +# These are the databases that go through nss dispatch. +# Caution: if you add a database here, you must add its real name +# in databases.def, too. +databases = proto service hosts network grp pwd rpc ethers \ + spwd netgrp alias + +# Specify rules for the nss_* modules. We have some services. +services := files nis compat dns db + +extra-libs := $(services:%=libnss1_%) libNoVersion +# These libraries will be built in the `others' pass rather than +# the `lib' pass, because they depend on libc.so being built already. +extra-libs-others = $(extra-libs) + +# The sources are found in the appropriate subdir. +subdir-dirs = $(services:%=nss_%) +vpath %.c $(subdir-dirs) + +libnss1_files-routines := $(addprefix files-,$(databases)) +libnss1_db-routines := $(addprefix db-,$(filter-out hosts network,$(databases))) +libnss1_compat-routines := $(addprefix compat-,grp pwd spwd) +libnss1_nis-routines := $(addprefix nis-,$(databases)) +libnss1_dns-routines := $(addprefix dns-, host network) + +libcompat-routines := $(addprefix old, fileops iofdopen iopopen stdfiles \ + iofclose iofopen pclose tmpfile) +libNoVersion-routines := stubs + +generated += $(filter-out db-alias.c db-netgrp.c, \ + $(addsuffix .c,$(libnss1_db-routines))) + +libnss1_files-inhibit-o = $(filter-out .os,$(object-suffixes)) +libnss1_db-inhibit-o = $(filter-out .os,$(object-suffixes)) +libnss1_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) +libnss1_nis-inhibit-o = $(filter-out .os,$(object-suffixes)) +libnss1_dns-inhibit-o = $(filter-out .os,$(object-suffixes)) + +-include ../Rules + +# Force the soname to be libnss_*.so.1 for compatibility. +LDFLAGS-nss1_files.so = -Wl,-soname=lib$(libprefix)nss_files.so$($(@F)-version) +LDFLAGS-nss1_db.so = -Wl,-soname=lib$(libprefix)nss_db.so$($(@F)-version) +LDFLAGS-nss1_nis.so = -Wl,-soname=lib$(libprefix)nss_nis.so$($(@F)-version) +LDFLAGS-nss1_compat.so = -Wl,-soname=lib$(libprefix)nss_compat.so$($(@F)-version) +LDFLAGS-nss1_dns.so = -Wl,-soname=lib$(libprefix)nss_dns.so$($(@F)-version) + +-include ../Makeconfig + +ifeq (yes,$(build-shared)) +install-others += $(inst_slibdir)/libnss_files.so$(libnss1_files.so-version) \ + $(inst_slibdir)/libnss_db.so$(libnss1_db.so-version) \ + $(inst_slibdir)/libnss_nis.so$(libnss1_nis.so-version) \ + $(inst_slibdir)/libnss_compat.so$(libnss1_compat.so-version) \ + $(inst_slibdir)/libnss_dns.so$(libnss1_dns.so-version) +endif + +$(inst_slibdir)/libnss_files.so$(libnss1_files.so-version): $(inst_slibdir)/libnss1_files-$(version).so $(+force) + rm -f $@ + $(LN_S) $(') > $@.new + mv -f $@.new $@ + +$(objpfx)libnss1_compat.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \ + $(objpfx)libnss1_files.so +$(objpfx)libnss1_nis.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \ + $(objpfx)libnss1_files.so + +# The DNS NSS modules needs the resolver. +#$(objpfx)libnss1_dns.so: $(filter-out $(common-objpfx)resolv/stamp.os, \ +# $(wildcard $(common-objpfx)resolv/*.os)) \ +# $(common-objpfx)libc.so +$(objpfx)libnss1_dns.so: $(common-objpfx)resolv/libresolv.so $(common-objpfx)libc.so + +# Depend on libc.so so a DT_NEEDED is generated in the shared objects. +# This ensures they will load libc.so for needed symbols if loaded by +# a statically-linked program that hasn't already loaded it. +$(objpfx)libnss1_compat.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \ + $(objpfx)libnss1_files.so $(common-objpfx)libc.so +$(objpfx)libnss1_db.so: $(common-objpfx)db2/libdb.so $(objpfx)libnss1_files.so\ + $(common-objpfx)libc.so +$(objpfx)libnss1_dns.so: $(common-objpfx)resolv/libresolv.so \ + $(common-objpfx)libc.so +$(objpfs)libnss1_files.so: $(common-objpfx)libc.so +$(objpfx)libnss1_nis.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \ + $(objpfx)libnss1_files.so $(common-objpfx)libc.so + + +# +# This is needed to build the separate tarball +# +pkgNAME = $(subdir) +pkgVERSION = 2.1.2 +pkgCVSTAG = $(pkgNAME)_$(subst .,-,$(pkgVERSION)) + +archive: + @rm -f *.tar.gz *~ + cvs tag -F $(pkgCVSTAG) . + @rm -rf /tmp/$(pkgNAME)-$(pkgVERSION) /tmp/$(pkgNAME) $(pkgNAME)-$(pkgVERSION).tar.gz + @cd /tmp; cvs export -r$(pkgCVSTAG) $(pkgNAME) + @pkgDIR=$$PWD; cd /tmp; tar cvzf $$pkgDIR/$(pkgNAME)-$(pkgVERSION).tar.gz $(pkgNAME) + @rm -rf /tmp/$(pkgNAME) + @echo "The archive is in $(pkgNAME)-$(pkgVERSION).tar.gz" diff -Naur ../glibc-2.1.3/glibc-compat/Versions glibc-2.1.3/glibc-compat/Versions --- ../glibc-2.1.3/glibc-compat/Versions 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/Versions 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,106 @@ +libnss1_db { + GLIBC_2.0 { + _nss_db_endaliasent; _nss_db_endetherent; _nss_db_endgrent; + _nss_db_endnetgrent; _nss_db_endprotoent; _nss_db_endpwent; + _nss_db_endrpcent; _nss_db_endservent; _nss_db_endspent; + _nss_db_getaliasbyname_r; _nss_db_getaliasent_r; _nss_db_getetherent_r; + _nss_db_getgrent_r; _nss_db_getgrgid_r; _nss_db_getgrnam_r; + _nss_db_gethostton_r; _nss_db_getnetgrent_r; _nss_db_getntohost_r; + _nss_db_getprotobyname_r; _nss_db_getprotobynumber_r; + _nss_db_getprotoent_r; _nss_db_getpwent_r; _nss_db_getpwnam_r; + _nss_db_getpwuid_r; _nss_db_getrpcbyname_r; _nss_db_getrpcbynumber_r; + _nss_db_getrpcent_r; _nss_db_getservbyname_r; _nss_db_getservbyport_r; + _nss_db_getservent_r; _nss_db_getspent_r; _nss_db_getspnam_r; + _nss_db_setaliasent; _nss_db_setetherent; _nss_db_setgrent; + _nss_db_setnetgrent; _nss_db_setprotoent; _nss_db_setpwent; + _nss_db_setrpcent; _nss_db_setservent; _nss_db_setspent; + } +} + +libnss1_dns { + GLIBC_2.0 { + _nss_dns_gethostbyaddr_r; _nss_dns_gethostbyname2_r; + _nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r; + _nss_dns_getnetbyname_r; + } +} + +libnss1_files { + GLIBC_2.0 { + _nss_files_setaliasent; _nss_files_endaliasent; + _nss_files_getaliasbyname_r; _nss_files_getaliasent_r; + + _nss_files_setetherent; _nss_files_endetherent; + _nss_files_getetherent_r; _nss_files_parse_etherent; + + _nss_files_setgrent; _nss_files_endgrent; + _nss_files_getgrent_r; _nss_files_getgrgid_r; _nss_files_getgrnam_r; + + _nss_files_sethostent; _nss_files_endhostent; + _nss_files_gethostbyaddr_r; _nss_files_gethostbyname2_r; _nss_files_gethostbyname_r; + _nss_files_gethostent_r; _nss_files_gethostton_r; + + _nss_files_setnetent; _nss_files_endnetent; + _nss_files_getnetbyaddr_r; _nss_files_getnetbyname_r; + _nss_files_getnetent_r; _nss_files_getntohost_r; + _nss_files_parse_netent; + + _nss_files_setnetgrent; _nss_files_endnetgrent; _nss_files_getnetgrent_r; + + _nss_files_setprotoent; _nss_files_endprotoent; + _nss_files_getprotobyname_r; _nss_files_getprotobynumber_r; + _nss_files_getprotoent_r; _nss_files_parse_protoent; + + _nss_files_setpwent; _nss_files_endpwent; + _nss_files_getpwent_r; _nss_files_getpwnam_r; _nss_files_getpwuid_r; + + _nss_files_setrpcent; _nss_files_endrpcent; + _nss_files_getrpcbyname_r; _nss_files_getrpcbynumber_r; + _nss_files_getrpcent_r; + _nss_files_parse_rpcent; + + _nss_files_setservent; _nss_files_endservent; + _nss_files_getservbyname_r; _nss_files_getservbyport_r; + _nss_files_getservent_r; + _nss_files_parse_servent; + + _nss_files_setspent; _nss_files_endspent; + _nss_files_getspent_r; _nss_files_getspnam_r; + + _nss_netgroup_parseline; + } +} + +libnss1_compat { + GLIBC_2.0 { + _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent; + _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r; + _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r; + _nss_compat_getspent_r; _nss_compat_getspnam_r; _nss_compat_initgroups; + _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent; + } +} + +libnss1_nis { + GLIBC_2.0 { + _nss_nis_endaliasent; _nss_nis_endetherent; _nss_nis_endgrent; + _nss_nis_endhostent; _nss_nis_endnetent; _nss_nis_endnetgrent; + _nss_nis_endprotoent; _nss_nis_endpwent; _nss_nis_endrpcent; + _nss_nis_endservent; _nss_nis_endspent; _nss_nis_getaliasbyname_r; + _nss_nis_getaliasent_r; _nss_nis_getetherent_r; _nss_nis_getgrent_r; + _nss_nis_getgrgid_r; _nss_nis_getgrnam_r; _nss_nis_gethostbyaddr_r; + _nss_nis_gethostbyname2_r; _nss_nis_gethostbyname_r; _nss_nis_gethostent_r; + _nss_nis_gethostton_r; _nss_nis_getnetbyaddr_r; _nss_nis_getnetbyname_r; + _nss_nis_getnetent_r; _nss_nis_getnetgrent_r; _nss_nis_getntohost_r; + _nss_nis_getprotobyname_r; _nss_nis_getprotobynumber_r; + _nss_nis_getprotoent_r; _nss_nis_getpublickey; _nss_nis_getpwent_r; + _nss_nis_getpwnam_r; _nss_nis_getpwuid_r; _nss_nis_getrpcbyname_r; + _nss_nis_getrpcbynumber_r; _nss_nis_getrpcent_r; _nss_nis_getsecretkey; + _nss_nis_getservbyname_r; _nss_nis_getservbyport_r; _nss_nis_getservent_r; + _nss_nis_getspent_r; _nss_nis_getspnam_r; _nss_nis_initgroups; + _nss_nis_netname2user; _nss_nis_setaliasent; _nss_nis_setetherent; + _nss_nis_setgrent; _nss_nis_sethostent; _nss_nis_setnetent; + _nss_nis_setnetgrent; _nss_nis_setprotoent; _nss_nis_setpwent; + _nss_nis_setrpcent; _nss_nis_setservent; _nss_nis_setspent; + } +} diff -Naur ../glibc-2.1.3/glibc-compat/Versions.def glibc-2.1.3/glibc-compat/Versions.def --- ../glibc-2.1.3/glibc-compat/Versions.def 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/Versions.def 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,15 @@ +libnss1_files { + GLIBC_2.0 +} +libnss1_db { + GLIBC_2.0 +} +libnss1_dns { + GLIBC_2.0 +} +libnss1_nis { + GLIBC_2.0 +} +libnss1_compat { + GLIBC_2.0 +} diff -Naur ../glibc-2.1.3/glibc-compat/configure glibc-2.1.3/glibc-compat/configure --- ../glibc-2.1.3/glibc-compat/configure 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/configure 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,28 @@ +#! /bin/sh +# +# We need a configure script only when compiling as part of GNU C library. +# Here we have to generate one of the files we need while compiling. +# +# The only problem is that no users of the package might thing they have to +# run configure themself and find it irritating when nothing happens. +# +# So we try here to find out whether we are called from the glibc configure +# or by a user. If the later is true show a gentle message. +# +saw_srcdir=no +srcdir= +saw_cache_file=no +# We use a simple heuristic which might fail: if we see the argument the +# glibc configure passes we assume it's glibc who calls us. +for opt in $*; do + case $opt in + --srcdir=*) saw_srcdir=yes + srcdir=`echo "$opt" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; + --cache-file=*) saw_cache_file=yes ;; + *) ;; + esac +done + +echo "Configure stage for glibc 2.0 add-on" + +exit 0 diff -Naur ../glibc-2.1.3/glibc-compat/nss-nis.h glibc-2.1.3/glibc-compat/nss-nis.h --- ../glibc-2.1.3/glibc-compat/nss-nis.h 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss-nis.h 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,58 @@ +/* Copyright (C) 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _NIS_NSS_NIS_H +#define _NIS_NSS_NIS_H 1 + +#include + +#include "nsswitch.h" + + +/* Convert YP error number to NSS error number. */ +static enum nss_status yperr2nss_tab[] = +{ + [YPERR_SUCCESS] = NSS_STATUS_SUCCESS, + [YPERR_BADARGS] = NSS_STATUS_UNAVAIL, + [YPERR_RPC] = NSS_STATUS_UNAVAIL, + [YPERR_DOMAIN] = NSS_STATUS_UNAVAIL, + [YPERR_MAP] = NSS_STATUS_UNAVAIL, + [YPERR_KEY] = NSS_STATUS_NOTFOUND, + [YPERR_YPERR] = NSS_STATUS_UNAVAIL, + [YPERR_RESRC] = NSS_STATUS_TRYAGAIN, + [YPERR_NOMORE] = NSS_STATUS_NOTFOUND, + [YPERR_PMAP] = NSS_STATUS_UNAVAIL, + [YPERR_YPBIND] = NSS_STATUS_UNAVAIL, + [YPERR_YPSERV] = NSS_STATUS_UNAVAIL, + [YPERR_NODOM] = NSS_STATUS_UNAVAIL, + [YPERR_BADDB] = NSS_STATUS_UNAVAIL, + [YPERR_VERS] = NSS_STATUS_UNAVAIL, + [YPERR_ACCESS] = NSS_STATUS_UNAVAIL, + [YPERR_BUSY] = NSS_STATUS_TRYAGAIN +}; +#define YPERR_COUNT (sizeof (yperr2nss_tab) / sizeof (yperr2nss_tab[0])) + +static inline enum nss_status +yperr2nss (int errval) +{ + if ((unsigned int) errval > YPERR_COUNT) + return NSS_STATUS_UNAVAIL; + return yperr2nss_tab[errval]; +} + +#endif /* nis/nss-nis.h */ diff -Naur ../glibc-2.1.3/glibc-compat/nss_compat/compat-grp.c glibc-2.1.3/glibc-compat/nss_compat/compat-grp.c --- ../glibc-2.1.3/glibc-compat/nss_compat/compat-grp.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_compat/compat-grp.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,769 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Structure for remembering -group members ... */ +#define BLACKLIST_INITIAL_SIZE 512 +#define BLACKLIST_INCREMENT 256 +struct blacklist_t + { + char *data; + int current; + int size; + }; + +struct ent_t + { + bool_t nis; + bool_t nis_first; + char *oldkey; + int oldkeylen; + FILE *stream; + struct blacklist_t blacklist; +}; +typedef struct ent_t ent_t; + +static ent_t ext_ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; + +/* Protect global state against multiple changers. */ +__libc_lock_define_initialized (static, lock) + +/* Prototypes for local functions. */ +static void blacklist_store_name (const char *, ent_t *); +static int in_blacklist (const char *, int, ent_t *); + +static enum nss_status +internal_setgrent (ent_t *ent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->nis = ent->nis_first = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + if (ent->stream == NULL) + { + ent->stream = fopen ("/etc/group", "r"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (ent->stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (ent->stream); + ent->stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (ent->stream); + + return status; +} + + +enum nss_status +_nss_compat_setgrent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_setgrent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_endgrent (ent_t *ent) +{ + if (ent->stream != NULL) + { + fclose (ent->stream); + ent->stream = NULL; + } + + ent->nis = ent->nis_first = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_endgrent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_endgrent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + +static enum nss_status +getgrent_next_nis (struct group *result, ent_t *ent, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain; + char *outkey, *outval; + int outkeylen, outvallen, parse_res; + char *p; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_NOTFOUND; + } + + do + { + char *save_oldkey; + int save_oldlen; + bool_t save_nis_first; + + if (ent->nis_first) + { + if (yp_first (domain, "group.byname", &outkey, &outkeylen, + &outval, &outvallen) != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_UNAVAIL; + } + save_oldkey = ent->oldkey; + save_oldlen = ent->oldkeylen; + save_nis_first = TRUE; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + ent->nis_first = FALSE; + } + else + { + if (yp_next (domain, "group.byname", ent->oldkey, ent->oldkeylen, + &outkey, &outkeylen, &outval, &outvallen) + != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_NOTFOUND; + } + + save_oldkey = ent->oldkey; + save_oldlen = ent->oldkeylen; + save_nis_first = FALSE; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + } + + /* Copy the found data to our buffer */ + p = strncpy (buffer, outval, buflen); + + /* ...and free the data. */ + free (outval); + + while (isspace (*p)) + ++p; + + if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1) + { + free (ent->oldkey); + ent->oldkey = save_oldkey; + ent->oldkeylen = save_oldlen; + ent->nis_first = save_nis_first; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + if (!save_nis_first) + free (save_oldkey); + } + + if (parse_res && + in_blacklist (result->gr_name, strlen (result->gr_name), ent)) + parse_res = 0; /* if result->gr_name in blacklist,search next entry */ + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +/* This function handle the +group entrys in /etc/group */ +static enum nss_status +getgrnam_plusgroup (const char *name, struct group *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + char *domain, *outval, *p; + int outvallen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + + if (yp_match (domain, "group.byname", name, strlen (name), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, outval, + buflen < (size_t) outvallen ? buflen : (size_t) outvallen); + free (outval); + while (isspace (*p)) + p++; + if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + else + return NSS_STATUS_RETURN; +} + +static enum nss_status +getgrent_next_file (struct group *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_grent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (result->gr_name[0] != '+' && result->gr_name[0] != '-') + /* This is a real entry. */ + break; + + /* -group */ + if (result->gr_name[0] == '-' && result->gr_name[1] != '\0' + && result->gr_name[1] != '@') + { + blacklist_store_name (&result->gr_name[1], ent); + continue; + } + + /* +group */ + if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' + && result->gr_name[1] != '@') + { + enum nss_status status; + + /* Store the group in the blacklist for the "+" at the end of + /etc/group */ + blacklist_store_name (&result->gr_name[1], ent); + status = getgrnam_plusgroup (&result->gr_name[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ + || status == NSS_STATUS_NOTFOUND) /* No group in NIS */ + continue; + else + { + if (status == NSS_STATUS_TRYAGAIN) + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + return status; + } + } + + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + ent->nis = TRUE; + ent->nis_first = TRUE; + + return getgrent_next_nis (result, ent, buffer, buflen); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer, + size_t buflen) +{ + if (ent->nis) + { + return getgrent_next_nis (gr, ent, buffer, buflen); + } + else + return getgrent_next_file (gr, ent, buffer, buflen); +} + +enum nss_status +_nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the setgrent function was not called before. */ + if (ext_ent.stream == NULL) + status = internal_setgrent (&ext_ent); + + if (status == NSS_STATUS_SUCCESS) + status = internal_getgrent_r (grp, &ext_ent, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +/* Searches in /etc/group and the NIS/NIS+ map for a special group */ +static enum nss_status +internal_getgrnam_r (const char *name, struct group *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_grent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->gr_name[0] != '+' && result->gr_name[0] != '-') + { + if (strcmp (result->gr_name, name) == 0) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -group */ + if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') + { + if (strcmp (&result->gr_name[1], name) == 0) + return NSS_STATUS_NOTFOUND; + else + continue; + } + + /* +group */ + if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') + { + if (strcmp (name, &result->gr_name[1]) == 0) + { + enum nss_status status; + + status = getgrnam_plusgroup (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) + /* We couldn't parse the entry */ + continue; + else + return status; + } + } + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + enum nss_status status; + + status = getgrnam_plusgroup (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) + /* We couldn't parse the entry */ + continue; + else + return status; + } + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getgrnam_r (const char *name, struct group *grp, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; + enum nss_status status; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + __libc_lock_lock (lock); + + status = internal_setgrent (&ent); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getgrnam_r (name, grp, &ent, buffer, buflen); + + internal_endgrent (&ent); + + return status; +} + +/* This function handle the + entry in /etc/group */ +static enum nss_status +getgrgid_plusgroup (gid_t gid, struct group *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + char buf[1024]; + char *domain, *outval, *p; + int outvallen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + + snprintf (buf, sizeof (buf), "%d", gid); + + if (yp_match (domain, "group.bygid", buf, strlen (buf), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + p = strncpy (buffer, outval, + buflen < (size_t) outvallen ? buflen : (size_t) outvallen); + free (outval); + while (isspace (*p)) + p++; + if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + else + return NSS_STATUS_RETURN; +} + +/* Searches in /etc/group and the NIS/NIS+ map for a special group id */ +static enum nss_status +internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_grent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->gr_name[0] != '+' && result->gr_name[0] != '-') + { + if (result->gr_gid == gid) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -group */ + if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') + { + blacklist_store_name (&result->gr_name[1], ent); + continue; + } + + /* +group */ + if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') + { + enum nss_status status; + + /* Store the group in the blacklist for the "+" at the end of + /etc/group */ + blacklist_store_name (&result->gr_name[1], ent); + status = getgrnam_plusgroup (&result->gr_name[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid) + break; + else + continue; + } + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + enum nss_status status; + + status = getgrgid_plusgroup (gid, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getgrgid_r (gid_t gid, struct group *grp, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setgrent (&ent); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getgrgid_r (gid, grp, &ent, buffer, buflen); + + internal_endgrent (&ent); + + return status; +} + + +/* Support routines for remembering -@netgroup and -user entries. + The names are stored in a single string with `|' as separator. */ +static void +blacklist_store_name (const char *name, ent_t *ent) +{ + int namelen = strlen (name); + char *tmp; + + /* first call, setup cache */ + if (ent->blacklist.size == 0) + { + ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); + ent->blacklist.data = malloc (ent->blacklist.size); + if (ent->blacklist.data == NULL) + return; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + ent->blacklist.current = 1; + } + else + { + if (in_blacklist (name, namelen, ent)) + return; /* no duplicates */ + + if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) + { + ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); + tmp = realloc (ent->blacklist.data, ent->blacklist.size); + if (tmp == NULL) + { + free (ent->blacklist.data); + ent->blacklist.size = 0; + return; + } + ent->blacklist.data = tmp; + } + } + + tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); + *tmp++ = '|'; + *tmp = '\0'; + ent->blacklist.current += namelen + 1; + + return; +} + +/* returns TRUE if ent->blacklist contains name, else FALSE */ +static bool_t +in_blacklist (const char *name, int namelen, ent_t *ent) +{ + char buf[namelen + 3]; + char *cp; + + if (ent->blacklist.data == NULL) + return FALSE; + + buf[0] = '|'; + cp = stpcpy (&buf[1], name); + *cp++= '|'; + *cp = '\0'; + return strstr (ent->blacklist.data, buf) != NULL; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_compat/compat-pwd.c glibc-2.1.3/glibc-compat/nss_compat/compat-pwd.c --- ../glibc-2.1.3/glibc-compat/nss_compat/compat-pwd.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_compat/compat-pwd.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,1199 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netgroup.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME pwent +#define STRUCTURE passwd +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Structure for remembering -@netgroup and -user members ... */ +#define BLACKLIST_INITIAL_SIZE 512 +#define BLACKLIST_INCREMENT 256 +struct blacklist_t + { + char *data; + int current; + int size; + }; + +struct ent_t + { + bool_t netgroup; + bool_t nis; + bool_t first; + char *oldkey; + int oldkeylen; + FILE *stream; + struct blacklist_t blacklist; + struct passwd pwd; + struct __netgrent netgrdata; + }; +typedef struct ent_t ent_t; + +static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, NULL, NULL, NULL}}; + +/* Protect global state against multiple changers. */ +__libc_lock_define_initialized (static, lock) + +/* Prototypes for local functions. */ +static void blacklist_store_name (const char *, ent_t *); +static int in_blacklist (const char *, int, ent_t *); + +static void +give_pwd_free (struct passwd *pwd) +{ + if (pwd->pw_name != NULL) + free (pwd->pw_name); + if (pwd->pw_passwd != NULL) + free (pwd->pw_passwd); + if (pwd->pw_gecos != NULL) + free (pwd->pw_gecos); + if (pwd->pw_dir != NULL) + free (pwd->pw_dir); + if (pwd->pw_shell != NULL) + free (pwd->pw_shell); + + memset (pwd, '\0', sizeof (struct passwd)); +} + +static size_t +pwd_need_buflen (struct passwd *pwd) +{ + size_t len = 0; + + if (pwd->pw_passwd != NULL) + len += strlen (pwd->pw_passwd) + 1; + + if (pwd->pw_gecos != NULL) + len += strlen (pwd->pw_gecos) + 1; + + if (pwd->pw_dir != NULL) + len += strlen (pwd->pw_dir) + 1; + + if (pwd->pw_shell != NULL) + len += strlen (pwd->pw_shell) + 1; + + return len; +} + +static void +copy_pwd_changes (struct passwd *dest, struct passwd *src, + char *buffer, size_t buflen) +{ + if (src->pw_passwd != NULL && strlen (src->pw_passwd)) + { + if (buffer == NULL) + dest->pw_passwd = strdup (src->pw_passwd); + else if (dest->pw_passwd && + strlen (dest->pw_passwd) >= strlen (src->pw_passwd)) + strcpy (dest->pw_passwd, src->pw_passwd); + else + { + dest->pw_passwd = buffer; + strcpy (dest->pw_passwd, src->pw_passwd); + buffer += strlen (dest->pw_passwd) + 1; + buflen = buflen - (strlen (dest->pw_passwd) + 1); + } + } + + if (src->pw_gecos != NULL && strlen (src->pw_gecos)) + { + if (buffer == NULL) + dest->pw_gecos = strdup (src->pw_gecos); + else if (dest->pw_gecos && + strlen (dest->pw_gecos) >= strlen (src->pw_gecos)) + strcpy (dest->pw_gecos, src->pw_gecos); + else + { + dest->pw_gecos = buffer; + strcpy (dest->pw_gecos, src->pw_gecos); + buffer += strlen (dest->pw_gecos) + 1; + buflen = buflen - (strlen (dest->pw_gecos) + 1); + } + } + if (src->pw_dir != NULL && strlen (src->pw_dir)) + { + if (buffer == NULL) + dest->pw_dir = strdup (src->pw_dir); + else if (dest->pw_dir && + strlen (dest->pw_dir) >= strlen (src->pw_dir)) + strcpy (dest->pw_dir, src->pw_dir); + else + { + dest->pw_dir = buffer; + strcpy (dest->pw_dir, src->pw_dir); + buffer += strlen (dest->pw_dir) + 1; + buflen = buflen - (strlen (dest->pw_dir) + 1); + } + } + + if (src->pw_shell != NULL && strlen (src->pw_shell)) + { + if (buffer == NULL) + dest->pw_shell = strdup (src->pw_shell); + else if (dest->pw_shell && + strlen (dest->pw_shell) >= strlen (src->pw_shell)) + strcpy (dest->pw_shell, src->pw_shell); + else + { + dest->pw_shell = buffer; + strcpy (dest->pw_shell, src->pw_shell); + buffer += strlen (dest->pw_shell) + 1; + buflen = buflen - (strlen (dest->pw_shell) + 1); + } + } +} + +static enum nss_status +internal_setpwent (ent_t *ent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->nis = ent->first = ent->netgroup = 0; + + /* If something was left over free it. */ + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + if (ent->stream == NULL) + { + ent->stream = fopen ("/etc/passwd", "r"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (ent->stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (ent->stream); + ent->stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (ent->stream); + + give_pwd_free (&ent->pwd); + + return status; +} + + +enum nss_status +_nss_compat_setpwent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_setpwent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_endpwent (ent_t *ent) +{ + if (ent->stream != NULL) + { + fclose (ent->stream); + ent->stream = NULL; + } + + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + ent->nis = ent->first = ent->netgroup = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + give_pwd_free (&ent->pwd); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_endpwent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_endpwent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + +static enum nss_status +getpwent_next_nis_netgr (const char *name, struct passwd *result, ent_t *ent, + char *group, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *ypdomain, *host, *user, *domain, *outval, *p, *p2; + int status, outvallen; + size_t p2len; + + if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS) + { + ent->netgroup = 0; + ent->first = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + if (ent->first == TRUE) + { + memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); + ent->first = FALSE; + } + + while (1) + { + char *saved_cursor; + int parse_res; + + saved_cursor = ent->netgrdata.cursor; + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen, + &errno); + if (status != 1) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_RETURN; + } + + if (user == NULL || user[0] == '-') + continue; + + if (domain != NULL && strcmp (ypdomain, domain) != 0) + continue; + + /* If name != NULL, we are called from getpwnam */ + if (name != NULL) + if (strcmp (user, name) != 0) + continue; + + if (yp_match (ypdomain, "passwd.byname", user, + strlen (user), &outval, &outvallen) + != YPERR_SUCCESS) + continue; + + p2len = pwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + p = strncpy (buffer, outval, buflen); + while (isspace (*p)) + p++; + free (outval); + if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1) + { + ent->netgrdata.cursor = saved_cursor; + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + { + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (result->pw_name, ent); + copy_pwd_changes (result, &ent->pwd, p2, p2len); + break; + } + } + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain, *outkey, *outval, *p, *p2; + int outkeylen, outvallen, parse_res; + size_t p2len; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + { + ent->nis = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + p2len = pwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + do + { + bool_t saved_first; + char *saved_oldkey; + int saved_oldlen; + + if (ent->first) + { + if (yp_first (domain, "passwd.byname", &outkey, &outkeylen, + &outval, &outvallen) != YPERR_SUCCESS) + { + ent->nis = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + saved_first = TRUE; + saved_oldkey = ent->oldkey; + saved_oldlen = ent->oldkeylen; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + ent->first = FALSE; + } + else + { + if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen, + &outkey, &outkeylen, &outval, &outvallen) + != YPERR_SUCCESS) + { + ent->nis = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_NOTFOUND; + } + + saved_first = FALSE; + saved_oldkey = ent->oldkey; + saved_oldlen = ent->oldkeylen; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + } + + /* Copy the found data to our buffer */ + p = strncpy (buffer, outval, buflen); + + /* ...and free the data. */ + free (outval); + + while (isspace (*p)) + ++p; + if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1) + { + free (ent->oldkey); + ent->oldkey = saved_oldkey; + ent->oldkeylen = saved_oldlen; + ent->first = saved_first; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + if (!saved_first) + free (saved_oldkey); + } + if (parse_res && + in_blacklist (result->pw_name, strlen (result->pw_name), ent)) + parse_res = 0; + } + while (!parse_res); + + copy_pwd_changes (result, &ent->pwd, p2, p2len); + + return NSS_STATUS_SUCCESS; +} + +/* This function handle the +user entrys in /etc/passwd */ +static enum nss_status +getpwnam_plususer (const char *name, struct passwd *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + struct passwd pwd; + int parse_res; + char *p; + size_t plen; + char *domain, *outval, *ptr; + int outvallen; + + memset (&pwd, '\0', sizeof (struct passwd)); + + copy_pwd_changes (&pwd, result, NULL, 0); + + plen = pwd_need_buflen (&pwd); + if (plen > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + + if (yp_match (domain, "passwd.byname", name, strlen (name), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ? + buflen : (size_t) outvallen); + buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0'; + free (outval); + while (isspace (*ptr)) + ptr++; + if ((parse_res = _nss_files_parse_pwent (ptr, result, data, buflen)) + == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res > 0) + { + copy_pwd_changes (result, &pwd, p, plen); + give_pwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + } + else + { + /* Give buffer the old len back */ + buflen += plen; + give_pwd_free (&pwd); + } + return NSS_STATUS_RETURN; +} + +/* get the next user from NIS+ (+ entry) */ +static enum nss_status +getpwent_next_file (struct passwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_pwent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (result->pw_name[0] != '+' && result->pw_name[0] != '-') + /* This is a real entry. */ + break; + + /* -@netgroup */ + if (result->pw_name[0] == '-' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->pw_name[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + blacklist_store_name (user, ent); + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + int status; + + ent->netgroup = TRUE; + ent->first = TRUE; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + status = getpwent_next_nis_netgr (NULL, result, ent, + &result->pw_name[2], + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + else + return status; + } + + /* -user */ + if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + blacklist_store_name (&result->pw_name[1], ent); + continue; + } + + /* +user */ + if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + enum nss_status status; + + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (&result->pw_name[1], ent); + status = getpwnam_plususer (&result->pw_name[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + continue; + else + return status; + } + + /* +:... */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') + { + ent->nis = TRUE; + ent->first = TRUE; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + return getpwent_next_nis (result, ent, buffer, buflen); + } + } + + return NSS_STATUS_SUCCESS; +} + + +/* get the next user from NIS (+ entry) */ +static enum nss_status +internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer, + size_t buflen) +{ + if (ent->netgroup) + { + int status; + + /* We are searching members in a netgroup */ + /* Since this is not the first call, we don't need the group name */ + status = getpwent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen); + if (status == NSS_STATUS_RETURN) + return getpwent_next_file (pw, ent, buffer, buflen); + else + return status; + } + else + if (ent->nis) + { + return getpwent_next_nis (pw, ent, buffer, buflen); + } + else + return getpwent_next_file (pw, ent, buffer, buflen); +} + +enum nss_status +_nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the setpwent function was not called before. */ + if (ext_ent.stream == NULL) + status = internal_setpwent (&ext_ent); + + if (status == NSS_STATUS_SUCCESS) + status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ +static enum nss_status +internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_pwent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->pw_name[0] != '+' && result->pw_name[0] != '-') + { + if (strcmp (result->pw_name, name) == 0) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -@netgroup */ + if (result->pw_name[0] == '-' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->pw_name[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + if (strcmp (user, name) == 0) + return NSS_STATUS_NOTFOUND; + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf[strlen (result->pw_name)]; + int status; + + strcpy (buf, &result->pw_name[2]); + ent->netgroup = TRUE; + ent->first = TRUE; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + do + { + status = getpwent_next_nis_netgr (name, result, ent, buf, + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + + if (status == NSS_STATUS_SUCCESS && + strcmp (result->pw_name, name) == 0) + return NSS_STATUS_SUCCESS; + } while (status == NSS_STATUS_SUCCESS); + continue; + } + + /* -user */ + if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + if (strcmp (&result->pw_name[1], name) == 0) + return NSS_STATUS_NOTFOUND; + else + continue; + } + + /* +user */ + if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + if (strcmp (name, &result->pw_name[1]) == 0) + { + enum nss_status status; + + status = getpwnam_plususer (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) + /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + + /* +:... */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') + { + enum nss_status status; + + status = getpwnam_plususer (name, result, buffer, buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getpwnam_r (const char *name, struct passwd *pwd, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, NULL, NULL, NULL}}; + enum nss_status status; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + status = internal_setpwent (&ent); + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getpwnam_r (name, pwd, &ent, buffer, buflen); + + internal_endpwent (&ent); + + return status; +} + +/* This function handle the + entry in /etc/passwd for getpwuid */ +static enum nss_status +getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + struct passwd pwd; + int parse_res; + char *p; + size_t plen; + char buf[1024]; + char *domain, *outval, *ptr; + int outvallen; + + memset (&pwd, '\0', sizeof (struct passwd)); + + copy_pwd_changes (&pwd, result, NULL, 0); + + plen = pwd_need_buflen (&pwd); + if (plen > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + + sprintf (buf, "%d", uid); + if (yp_match (domain, "passwd.byuid", buf, strlen (buf), + &outval, &outvallen) + != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ? + buflen : (size_t) outvallen); + buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0'; + free (outval); + while (isspace (*ptr)) + ptr++; + if ((parse_res = _nss_files_parse_pwent (ptr, result, data, buflen)) + == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res > 0) + { + copy_pwd_changes (result, &pwd, p, plen); + give_pwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + } + else + { + /* Give buffer the old len back */ + buflen += plen; + give_pwd_free (&pwd); + } + return NSS_STATUS_RETURN; +} + +/* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */ +static enum nss_status +internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_pwent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->pw_name[0] != '+' && result->pw_name[0] != '-') + { + if (result->pw_uid == uid) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -@netgroup */ + if (result->pw_name[0] == '-' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->pw_name[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + blacklist_store_name (user, ent); + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf[strlen (result->pw_name)]; + int status; + + strcpy (buf, &result->pw_name[2]); + ent->netgroup = TRUE; + ent->first = TRUE; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + do + { + status = getpwent_next_nis_netgr (NULL, result, ent, buf, + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + + if (status == NSS_STATUS_SUCCESS && uid == result->pw_uid) + return NSS_STATUS_SUCCESS; + } while (status == NSS_STATUS_SUCCESS); + continue; + } + + /* -user */ + if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + blacklist_store_name (&result->pw_name[1], ent); + continue; + } + + /* +user */ + if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + enum nss_status status; + + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (&result->pw_name[1], ent); + status = getpwnam_plususer (&result->pw_name[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS && result->pw_uid == uid) + break; + else + continue; + } + + /* +:... */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') + { + enum nss_status status; + + status = getpwuid_plususer (uid, result, buffer, buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + { + if (status == NSS_STATUS_TRYAGAIN) + /* The parser ran out of space */ + fsetpos (ent->stream, &pos); + return status; + } + } + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, NULL, NULL, NULL}}; + enum nss_status status; + + status = internal_setpwent (&ent); + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen); + + internal_endpwent (&ent); + + return status; +} + + +/* Support routines for remembering -@netgroup and -user entries. + The names are stored in a single string with `|' as separator. */ +static void +blacklist_store_name (const char *name, ent_t *ent) +{ + int namelen = strlen (name); + char *tmp; + + /* first call, setup cache */ + if (ent->blacklist.size == 0) + { + ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); + ent->blacklist.data = malloc (ent->blacklist.size); + if (ent->blacklist.data == NULL) + return; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + ent->blacklist.current = 1; + } + else + { + if (in_blacklist (name, namelen, ent)) + return; /* no duplicates */ + + if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) + { + ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); + tmp = realloc (ent->blacklist.data, ent->blacklist.size); + if (tmp == NULL) + { + free (ent->blacklist.data); + ent->blacklist.size = 0; + return; + } + ent->blacklist.data = tmp; + } + } + + tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); + *tmp++ = '|'; + *tmp = '\0'; + ent->blacklist.current += namelen + 1; + + return; +} + +/* returns TRUE if ent->blacklist contains name, else FALSE */ +static bool_t +in_blacklist (const char *name, int namelen, ent_t *ent) +{ + char buf[namelen + 3]; + char *cp; + + if (ent->blacklist.data == NULL) + return FALSE; + + buf[0] = '|'; + cp = stpcpy (&buf[1], name); + *cp++= '|'; + *cp = '\0'; + return strstr (ent->blacklist.data, buf) != NULL; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_compat/compat-spwd.c glibc-2.1.3/glibc-compat/nss_compat/compat-spwd.c --- ../glibc-2.1.3/glibc-compat/nss_compat/compat-spwd.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_compat/compat-spwd.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,915 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netgroup.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME spent +#define STRUCTURE spwd +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Structure for remembering -@netgroup and -user members ... */ +#define BLACKLIST_INITIAL_SIZE 512 +#define BLACKLIST_INCREMENT 256 +struct blacklist_t + { + char *data; + int current; + int size; + }; + +struct ent_t + { + bool_t netgroup; + bool_t nis; + bool_t first; + char *oldkey; + int oldkeylen; + FILE *stream; + struct blacklist_t blacklist; + struct spwd pwd; + struct __netgrent netgrdata; + }; +typedef struct ent_t ent_t; + +static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; + +/* Protect global state against multiple changers. */ +__libc_lock_define_initialized (static, lock) + +/* Prototypes for local functions. */ +static void blacklist_store_name (const char *, ent_t *); +static int in_blacklist (const char *, int, ent_t *); + +static void +give_spwd_free (struct spwd *pwd) +{ + if (pwd->sp_namp != NULL) + free (pwd->sp_namp); + if (pwd->sp_pwdp != NULL) + free (pwd->sp_pwdp); + + memset (pwd, '\0', sizeof (struct spwd)); +} + +static int +spwd_need_buflen (struct spwd *pwd) +{ + int len = 0; + + if (pwd->sp_pwdp != NULL) + len += strlen (pwd->sp_pwdp) + 1; + + return len; +} + +static void +copy_spwd_changes (struct spwd *dest, struct spwd *src, + char *buffer, size_t buflen) +{ + if (src->sp_pwdp != NULL && strlen (src->sp_pwdp)) + { + if (buffer == NULL) + dest->sp_pwdp = strdup (src->sp_pwdp); + else if (dest->sp_pwdp && + strlen (dest->sp_pwdp) >= strlen (src->sp_pwdp)) + strcpy (dest->sp_pwdp, src->sp_pwdp); + else + { + dest->sp_pwdp = buffer; + strcpy (dest->sp_pwdp, src->sp_pwdp); + buffer += strlen (dest->sp_pwdp) + 1; + buflen = buflen - (strlen (dest->sp_pwdp) + 1); + } + } + if (src->sp_lstchg != 0) + dest->sp_lstchg = src->sp_lstchg; + if (src->sp_min != 0) + dest->sp_min = src->sp_min; + if (src->sp_max != 0) + dest->sp_max = src->sp_max; + if (src->sp_warn != 0) + dest->sp_warn = src->sp_warn; + if (src->sp_inact != 0) + dest->sp_inact = src->sp_inact; + if (src->sp_expire != 0) + dest->sp_expire = src->sp_expire; + if (src->sp_flag != 0) + dest->sp_flag = src->sp_flag; +} + +static enum nss_status +internal_setspent (ent_t *ent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->nis = ent->first = ent->netgroup = 0; + + /* If something was left over free it. */ + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + if (ent->stream == NULL) + { + ent->stream = fopen ("/etc/shadow", "r"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (ent->stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (ent->stream); + ent->stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (ent->stream); + + give_spwd_free (&ent->pwd); + + return status; +} + + +enum nss_status +_nss_compat_setspent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_setspent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_endspent (ent_t *ent) +{ + if (ent->stream != NULL) + { + fclose (ent->stream); + ent->stream = NULL; + } + + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + ent->nis = ent->first = ent->netgroup = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + give_spwd_free (&ent->pwd); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_endspent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_endspent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +getspent_next_nis_netgr (const char *name, struct spwd *result, ent_t *ent, + char *group, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *ypdomain, *host, *user, *domain, *outval, *p, *p2; + int status, outvallen; + size_t p2len; + + if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS) + { + ent->netgroup = 0; + ent->first = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + if (ent->first == TRUE) + { + bzero (&ent->netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); + ent->first = FALSE; + } + + while (1) + { + char *saved_cursor; + int parse_res; + + saved_cursor = ent->netgrdata.cursor; + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen, + &errno); + if (status != 1) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_RETURN; + } + + if (user == NULL || user[0] == '-') + continue; + + if (domain != NULL && strcmp (ypdomain, domain) != 0) + continue; + + /* If name != NULL, we are called from getpwnam */ + if (name != NULL) + if (strcmp (user, name) != 0) + continue; + + if (yp_match (ypdomain, "shadow.byname", user, + strlen (user), &outval, &outvallen) + != YPERR_SUCCESS) + continue; + + p2len = spwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + p = strncpy (buffer, outval, buflen); + while (isspace (*p)) + p++; + free (outval); + if ((parse_res = _nss_files_parse_spent (p, result, data, buflen)) == -1) + { + ent->netgrdata.cursor = saved_cursor; + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + { + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (result->sp_namp, ent); + copy_spwd_changes (result, &ent->pwd, p2, p2len); + break; + } + } + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getspent_next_nis (struct spwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain, *outkey, *outval, *p, *p2; + int outkeylen, outvallen, parse_res; + size_t p2len; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + { + ent->nis = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + p2len = spwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + do + { + bool_t saved_first; + char *saved_oldkey; + int saved_oldlen; + + if (ent->first) + { + if (yp_first (domain, "shadow.byname", &outkey, &outkeylen, + &outval, &outvallen) != YPERR_SUCCESS) + { + ent->nis = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + saved_first = TRUE; + saved_oldkey = ent->oldkey; + saved_oldlen = ent->oldkeylen; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + ent->first = FALSE; + } + else + { + if (yp_next (domain, "shadow.byname", ent->oldkey, ent->oldkeylen, + &outkey, &outkeylen, &outval, &outvallen) + != YPERR_SUCCESS) + { + ent->nis = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_NOTFOUND; + } + + saved_first = FALSE; + saved_oldkey = ent->oldkey; + saved_oldlen = ent->oldkeylen; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + } + + /* Copy the found data to our buffer */ + p = strncpy (buffer, outval, buflen); + + /* ...and free the data. */ + free (outval); + + while (isspace (*p)) + ++p; + if ((parse_res = _nss_files_parse_spent (p, result, data, buflen)) == -1) + { + free (ent->oldkey); + ent->oldkey = saved_oldkey; + ent->oldkeylen = saved_oldlen; + ent->first = saved_first; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + if (!saved_first) + free (saved_oldkey); + } + if (parse_res && + in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) + parse_res = 0; + } + while (!parse_res); + + copy_spwd_changes (result, &ent->pwd, p2, p2len); + + return NSS_STATUS_SUCCESS; +} + +/* This function handle the +user entrys in /etc/shadow */ +static enum nss_status +getspnam_plususer (const char *name, struct spwd *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + struct spwd pwd; + int parse_res; + char *p; + size_t plen; + char *domain, *outval, *ptr; + int outvallen; + + + memset (&pwd, '\0', sizeof (struct spwd)); + + copy_spwd_changes (&pwd, result, NULL, 0); + + plen = spwd_need_buflen (&pwd); + if (plen > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + + if (yp_match (domain, "shadow.byname", name, strlen (name), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ? + buflen : (size_t) outvallen); + buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0'; + free (outval); + while (isspace (*ptr)) + ptr++; + if ((parse_res = _nss_files_parse_spent (ptr, result, data, buflen)) == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + { + copy_spwd_changes (result, &pwd, p, plen); + give_spwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + } + else + { + /* Give buffer the old len back */ + buflen += plen; + give_spwd_free (&pwd); + } + return NSS_STATUS_RETURN; +} + +static enum nss_status +getspent_next_file (struct spwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + || !(parse_res = _nss_files_parse_spent (p, result, data, + buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') + /* This is a real entry. */ + break; + + /* -@netgroup */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->sp_namp[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + blacklist_store_name (user, ent); + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + int status; + + ent->netgroup = TRUE; + ent->first = TRUE; + copy_spwd_changes (&ent->pwd, result, NULL, 0); + + status = getspent_next_nis_netgr (NULL, result, ent, + &result->sp_namp[2], + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + else + return status; + } + + /* -user */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' + && result->sp_namp[1] != '@') + { + blacklist_store_name (&result->sp_namp[1], ent); + continue; + } + + /* +user */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' + && result->sp_namp[1] != '@') + { + enum nss_status status; + + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (&result->sp_namp[1], ent); + status = getspnam_plususer (&result->sp_namp[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ + || status == NSS_STATUS_NOTFOUND) /* entry doesn't exist */ + continue; + else + { + if (status == NSS_STATUS_TRYAGAIN) + fsetpos (ent->stream, &pos); + return status; + } + } + + /* +:... */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') + { + ent->nis = TRUE; + ent->first = TRUE; + copy_spwd_changes (&ent->pwd, result, NULL, 0); + + return getspent_next_nis (result, ent, buffer, buflen); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_getspent_r (struct spwd *pw, ent_t *ent, + char *buffer, size_t buflen) +{ + if (ent->netgroup) + { + int status; + + /* We are searching members in a netgroup */ + /* Since this is not the first call, we don't need the group name */ + status = getspent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen); + if (status == NSS_STATUS_RETURN) + return getspent_next_file (pw, ent, buffer, buflen); + else + return status; + } + else + if (ent->nis) + { + return getspent_next_nis (pw, ent, buffer, buflen); + } + else + return getspent_next_file (pw, ent, buffer, buflen); +} + +enum nss_status +_nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + if (ext_ent.stream == NULL) + status = internal_setspent (&ext_ent); + + if (status == NSS_STATUS_SUCCESS) + status = internal_getspent_r (pwd, &ext_ent, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ +static enum nss_status +internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_spent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') + { + if (strcmp (result->sp_namp, name) == 0) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -@netgroup */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->sp_namp[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + if (strcmp (user, name) == 0) + return NSS_STATUS_NOTFOUND; + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + char buf[strlen (result->sp_namp)]; + int status; + + strcpy (buf, &result->sp_namp[2]); + ent->netgroup = TRUE; + ent->first = TRUE; + copy_spwd_changes (&ent->pwd, result, NULL, 0); + + do + { + status = getspent_next_nis_netgr (name, result, ent, buf, + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + + if (status == NSS_STATUS_SUCCESS && + strcmp (result->sp_namp, name) == 0) + return NSS_STATUS_SUCCESS; + } while (status == NSS_STATUS_SUCCESS); + continue; + } + + /* -user */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' + && result->sp_namp[1] != '@') + { + if (strcmp (&result->sp_namp[1], name) == 0) + return NSS_STATUS_NOTFOUND; + else + continue; + } + + /* +user */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' + && result->sp_namp[1] != '@') + { + if (strcmp (name, &result->sp_namp[1]) == 0) + { + enum nss_status status; + + status = getspnam_plususer (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) + /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + + /* +:... */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') + { + enum nss_status status; + + status = getspnam_plususer (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getspnam_r (const char *name, struct spwd *pwd, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; + enum nss_status status; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + status = internal_setspent (&ent); + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getspnam_r (name, pwd, &ent, buffer, buflen); + + internal_endspent (&ent); + + return status; +} + +/* Support routines for remembering -@netgroup and -user entries. + The names are stored in a single string with `|' as separator. */ +static void +blacklist_store_name (const char *name, ent_t *ent) +{ + int namelen = strlen (name); + char *tmp; + + /* first call, setup cache */ + if (ent->blacklist.size == 0) + { + ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); + ent->blacklist.data = malloc (ent->blacklist.size); + if (ent->blacklist.data == NULL) + return; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + ent->blacklist.current = 1; + } + else + { + if (in_blacklist (name, namelen, ent)) + return; /* no duplicates */ + + if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) + { + ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); + tmp = realloc (ent->blacklist.data, ent->blacklist.size); + if (tmp == NULL) + { + free (ent->blacklist.data); + ent->blacklist.size = 0; + return; + } + ent->blacklist.data = tmp; + } + } + + tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); + *tmp++ = '|'; + *tmp = '\0'; + ent->blacklist.current += namelen + 1; + + return; +} + +/* Returns TRUE if ent->blacklist contains name, else FALSE. */ +static bool_t +in_blacklist (const char *name, int namelen, ent_t *ent) +{ + char buf[namelen + 3]; + char *cp; + + if (ent->blacklist.data == NULL) + return FALSE; + + buf[0] = '|'; + cp = stpcpy (&buf[1], name); + *cp++= '|'; + *cp = '\0'; + return strstr (ent->blacklist.data, buf) != NULL; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_db/db-XXX.c glibc-2.1.3/glibc-compat/nss_db/db-XXX.c --- ../glibc-2.1.3/glibc-compat/nss_db/db-XXX.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_db/db-XXX.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,288 @@ +/* Common code for DB-based databases in nss_db module. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include "nsswitch.h" + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- database file name, ("hosts", "passwd") + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. +*/ + +#define ENTNAME_r CONCAT(ENTNAME,_r) + +#include +#define DBFILE _PATH_VARDB DATABASE ".db" + +#ifdef NEED_H_ERRNO +#define H_ERRNO_PROTO , int *herrnop +#define H_ERRNO_ARG , herrnop +#define H_ERRNO_SET(val) (*herrnop = (val)) +#else +#define H_ERRNO_PROTO +#define H_ERRNO_ARG +#define H_ERRNO_SET(val) ((void) 0) +#endif + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared handle open on the database. */ + +static DB *db; +static int keep_db; +static unsigned int entidx; /* Index for `getENTNAME'. */ + +/* Open database file if not already opened. */ +static enum nss_status +internal_setent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (db == NULL) + { + db = dbopen (DBFILE, O_RDONLY, 0, DB_BTREE, NULL); + + if (db == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl ((*db->fd) (db), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl ((*db->fd) (db), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + (*db->close) (db); + db = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + + /* Remember STAYOPEN flag. */ + if (db != NULL) + keep_db |= stayopen; + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +CONCAT(_nss_db_set,ENTNAME) (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (stayopen); + + /* Reset the sequential index. */ + entidx = 0; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (void) +{ + if (db != NULL) + { + (*db->close) (db); + db = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +CONCAT(_nss_db_end,ENTNAME) (void) +{ + __libc_lock_lock (lock); + + internal_endent (); + + /* Reset STAYOPEN flag. */ + keep_db = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* Do a database lookup for KEY. */ +static enum nss_status +lookup (const DBT *key, struct STRUCTURE *result, + void *buffer, int buflen H_ERRNO_PROTO) +{ + char *p; + enum nss_status status; + int err; + DBT value; + + /* Open the database. */ + status = internal_setent (keep_db); + if (status != NSS_STATUS_SUCCESS) + { + H_ERRNO_SET (NETDB_INTERNAL); + return status; + } + + /* Succeed iff it matches a value that parses correctly. */ + err = (*db->get) (db, key, &value, 0); + if (err < 0) + { + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_UNAVAIL; + } + else if (err != 0) + { + H_ERRNO_SET (HOST_NOT_FOUND); + status = NSS_STATUS_NOTFOUND; + } + else + { + /* Copy the result to a safe place. */ + p = (char *) memcpy (buffer, value.data, value.size); + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + + err = parse_line (p, result, buffer, buflen); + + if (err == 0) + { + /* If the key begins with '0' we are trying to get the next + entry. We want to ignore unparsable lines in this case. */ + if (((char *) key->data)[0] == '0') + { + /* Super magical return value. We need to tell our caller + that it should continue looping. This value cannot + happen in other cases. */ + status = NSS_STATUS_RETURN; + } + else + { + H_ERRNO_SET (HOST_NOT_FOUND); + status = NSS_STATUS_NOTFOUND; + } + } + else if (err < 0) + { + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_TRYAGAIN; + } + else + status = NSS_STATUS_SUCCESS; + } + + if (! keep_db) + internal_endent (); + + return status; +} + + +/* Macro for defining lookup functions for this DB-based database. + + NAME is the name of the lookup; e.g. `pwnam'. + + KEYPATTERN gives `printf' args to construct a key string; + e.g. `(".%s", name)'. + + KEYSIZE gives the allocation size of a buffer to construct it in; + e.g. `1 + strlen (name)'. + + PROTO describes the arguments for the lookup key; + e.g. `const char *name'. + + BREAK_IF_MATCH is ignored, but used by ../nss_files/files-XXX.c. */ + +#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \ +enum nss_status \ +_nss_db_get##name##_r (proto, \ + struct STRUCTURE *result, \ + char *buffer, size_t buflen H_ERRNO_PROTO) \ +{ \ + DBT key; \ + enum nss_status status; \ + const size_t size = (keysize) + 1; \ + key.data = __alloca (size); \ + key.size = KEYPRINTF keypattern; \ + __libc_lock_lock (lock); \ + status = lookup (&key, result, buffer, buflen H_ERRNO_ARG); \ + __libc_lock_unlock (lock); \ + return status; \ +} + +#define KEYPRINTF(pattern, args...) snprintf (key.data, size, pattern ,##args) + + + + +/* Return the next entry from the database file, doing locking. */ +enum nss_status +CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, + char *buffer, size_t buflen H_ERRNO_PROTO) +{ + /* Return next entry in host file. */ + enum nss_status status; + char buf[20]; + DBT key; + + __libc_lock_lock (lock); + /* Loop until we find a valid entry or hit EOF. See above for the + special meaning of the status value. */ + do + { + key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++); + status = lookup (&key, result, buffer, buflen H_ERRNO_ARG); + if (status == NSS_STATUS_TRYAGAIN +#ifdef NEED_H_ERRNO + && *herrnop == NETDB_INTERNAL +#endif + && errno == ERANGE) + /* Give the user a chance to get the same entry with a larger + buffer. */ + --entidx; + } + while (status == NSS_STATUS_RETURN); + __libc_lock_unlock (lock); + + return status; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_db/db-alias.c glibc-2.1.3/glibc-compat/nss_db/db-alias.c --- ../glibc-2.1.3/glibc-compat/nss_db/db-alias.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_db/db-alias.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,255 @@ +/* Mail alias file parser in nss_db module. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nsswitch.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared handle open on the database. */ + +static DB *db; +static int keep_db; +static unsigned int entidx; /* Index for `getaliasent_r'. */ + +/* Open database file if not already opened. */ +static enum nss_status +internal_setent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (db == NULL) + { + db = dbopen (_PATH_VARDB "aliases.db", O_RDONLY, 0, DB_BTREE, NULL); + + if (db == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl ((*db->fd) (db), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl ((*db->fd) (db), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + (*db->close) (db); + db = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + + /* Remember STAYOPEN flag. */ + if (db != NULL) + keep_db |= stayopen; + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_db_setaliasent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (stayopen); + + /* Reset the sequential index. */ + entidx = 0; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (void) +{ + if (db != NULL) + { + (*db->close) (db); + db = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_db_endaliasent (void) +{ + __libc_lock_lock (lock); + + internal_endent (); + + /* Reset STAYOPEN flag. */ + keep_db = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* We provide the parse function here. The parser in libnss_files + cannot be used. The generation of the db file already resolved all + :include: statements so we simply have to parse the list and store + the result. */ +static enum nss_status +lookup (const DBT *key, struct aliasent *result, char *buffer, + size_t buflen) +{ + enum nss_status status; + DBT value; + + /* Open the database. */ + status = internal_setent (keep_db); + if (status != NSS_STATUS_SUCCESS) + return status; + + if ((*db->get) (db, key, &value, 0) == 0) + { + const char *src = value.data; + + result->alias_members_len = 0; + + /* We now have to fill the BUFFER with all the information. */ + if (buflen < key->size + 1) + { + no_more_room: + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (status == NSS_STATUS_SUCCESS) + { + char *cp; + size_t cnt; + + buffer = stpncpy (buffer, key->data, key->size) + 1; + buflen -= key->size + 1; + + while (*src != '\0') + { + const char *end, *upto; + while (isspace (*src)) + ++src; + + end = strchr (src, ','); + if (end == NULL) + end = strchr (src, '\0'); + for (upto = end; upto > src && isspace (upto[-1]); --upto); + + if (upto != src) + { + if ((upto - src) + __alignof__ (char *) > buflen) + goto no_more_room; + buffer = stpncpy (buffer, src, upto - src) + 1; + buflen -= (upto - src) + __alignof (char *); + ++result->alias_members_len; + } + src = end + (*end != '\0'); + } + + /* Now prepare the return. Provide string pointers for the + currently selected aliases. */ + + /* Adjust the pointer so it is aligned for storing pointers. */ + buffer += __alignof__ (char *) - 1; + buffer -= ((buffer - (char *) 0) % __alignof__ (char *)); + result->alias_members = (char **) buffer; + + /* Compute addresses of alias entry strings. */ + cp = result->alias_name; + for (cnt = 0; cnt < result->alias_members_len; ++cnt) + { + cp = strchr (cp, '\0') + 1; + result->alias_members[cnt] = cp; + } + + status = (result->alias_members_len == 0 + ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS); + } + } + else + status = NSS_STATUS_NOTFOUND; + + if (! keep_db) + internal_endent (); + + return status; +} + +enum nss_status +_nss_db_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen) +{ + /* Return next entry in alias file. */ + enum nss_status status; + char buf[20]; + DBT key; + + __libc_lock_lock (lock); + key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++); + status = lookup (&key, result, buffer, buflen); + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_db_getaliasbyname_r (const char *name, struct aliasent *result, + char *buffer, size_t buflen) +{ + DBT key; + enum nss_status status; + + key.size = 1 + strlen (name); + + key.data = __alloca (key.size); + ((char *) key.data)[0] = '.'; + memcpy (&((char *) key.data)[1], name, key.size - 1); + + __libc_lock_lock (lock); + status = lookup (&key, result, buffer, buflen); + __libc_lock_unlock (lock); + + return status; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_db/db-netgrp.c glibc-2.1.3/glibc-compat/nss_db/db-netgrp.c --- ../glibc-2.1.3/glibc-compat/nss_db/db-netgrp.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_db/db-netgrp.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,129 @@ +/* Netgroup file parser in nss_db modules. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include "nsswitch.h" +#include "netgroup.h" + + +#define DBFILE _PATH_VARDB "netgroup.db" + + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared handle open on the database. */ +static DB *db; +static char *entry; +static char *cursor; + +enum nss_status +_nss_db_setnetgrent (const char *group) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Make sure the data base file is open. */ + if (db == NULL) + { + db = dbopen (DBFILE, O_RDONLY, 0, DB_BTREE, NULL); + + if (db == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl ((*db->fd) (db), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl ((*db->fd) (db), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + (*db->close) (db); + db = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + + if (status == NSS_STATUS_SUCCESS) + { + DBT key = { data: (void *) group, size: strlen (group) }; + DBT value; + + if ((*db->get) (db, &key, &value, 0) != 0) + status = NSS_STATUS_NOTFOUND; + else + cursor = entry = value.data; + } + + __libc_lock_unlock (lock); + + return status; + +} + + +enum nss_status +_nss_db_endnetgrent (void) +{ + __libc_lock_lock (lock); + + if (db != NULL) + { + (*db->close) (db); + db = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +extern enum nss_status _nss_netgroup_parseline (char **cursor, + struct __netgrent *result, + char *buffer, int buflen); + +enum nss_status +_nss_db_getnetgrent_r (struct __netgrent *result, char *buffer, int buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = _nss_netgroup_parseline (&cursor, result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_dns/dns-host.c glibc-2.1.3/glibc-compat/nss_dns/dns-host.c --- ../glibc-2.1.3/glibc-compat/nss_dns/dns-host.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_dns/dns-host.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,602 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Extended from original form by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Parts of this file are plain copies of the file `gethtnamadr.c' from + the bind package and it has the following copyright. */ + +/* + * ++Copyright++ 1985, 1988, 1993 + * - + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nsswitch.h" + +/* Get implementation for some internal functions. */ +#include "../resolv/mapv4v6addr.h" +#include "../resolv/mapv4v6hostent.h" + +/* Maximum number of aliases we allow. */ +#define MAX_NR_ALIASES 48 +#define MAX_NR_ADDRS 48 + +#if PACKETSZ > 1024 +# define MAXPACKET PACKETSZ +#else +# define MAXPACKET 1024 +#endif +/* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */ +#ifdef MAXHOSTNAMELEN +# undef MAXHOSTNAMELEN +#endif +#define MAXHOSTNAMELEN 256 + +static const char AskedForGot[] = "\ +gethostby*.getanswer: asked for \"%s\", got \"%s\""; + + +/* We need this time later. */ +typedef union querybuf +{ + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + + +static enum nss_status getanswer_r (const querybuf *answer, int anslen, + const char *qname, int qtype, + struct hostent *result, char *buffer, + size_t buflen, int *h_errnop); + +enum nss_status +_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *h_errnop) +{ + querybuf host_buffer; + int size, type, n; + const char *cp; + + switch (af) { + case AF_INET: + size = INADDRSZ; + type = T_A; + break; + case AF_INET6: + size = IN6ADDRSZ; + type = T_AAAA; + break; + default: + *h_errnop = NETDB_INTERNAL; + __set_errno (EAFNOSUPPORT); + return NSS_STATUS_UNAVAIL; + } + + result->h_addrtype = af; + result->h_length = size; + + /* + * if there aren't any dots, it could be a user-level alias. + * this is also done in res_query() since we are not the only + * function that looks up host names. + */ + if (strchr (name, '.') == NULL && (cp = __hostalias (name)) != NULL) + name = cp; + + n = res_search (name, C_IN, type, host_buffer.buf, sizeof (host_buffer.buf)); + if (n < 0) + { + *h_errnop = h_errno; + return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + + return getanswer_r (&host_buffer, n, name, type, result, buffer, buflen, + h_errnop); +} + + +enum nss_status +_nss_dns_gethostbyname_r (const char *name, struct hostent *result, + char *buffer, size_t buflen, int *h_errnop) +{ + enum nss_status status = NSS_STATUS_NOTFOUND; + + if (_res.options & RES_USE_INET6) + status = _nss_dns_gethostbyname2_r (name, AF_INET6, result, buffer, + buflen, h_errnop); + if (status == NSS_STATUS_NOTFOUND) + status = _nss_dns_gethostbyname2_r (name, AF_INET, result, buffer, + buflen, h_errnop); + + return status; +} + + +enum nss_status +_nss_dns_gethostbyaddr_r (const char *addr, int len, int af, + struct hostent *result, char *buffer, size_t buflen, + int *h_errnop) +{ + static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; + static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; + const u_char *uaddr = (const u_char *)addr; + struct host_data + { + char *aliases[MAX_NR_ALIASES]; + unsigned char host_addr[16]; /* IPv4 or IPv6 */ + char *h_addr_ptrs[MAX_NR_ADDRS + 1]; + char linebuffer[0]; + } *host_data = (struct host_data *) buffer; + querybuf host_buffer; + char qbuf[MAXDNAME+1], *qp; + int size, n, status; + + if (af == AF_INET6 && len == IN6ADDRSZ && + (memcmp (uaddr, mapped, sizeof mapped) == 0 + || memcmp (uaddr, tunnelled, sizeof tunnelled) == 0)) + { + /* Unmap. */ + addr += sizeof mapped; + uaddr += sizeof mapped; + af = AF_INET; + len = INADDRSZ; + } + + switch (af) + { + case AF_INET: + size = INADDRSZ; + break; + case AF_INET6: + size = IN6ADDRSZ; + break; + default: + __set_errno (EAFNOSUPPORT); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + if (size != len) + { + __set_errno (EAFNOSUPPORT); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + switch (af) + { + case AF_INET: + sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff), + (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff)); + break; + case AF_INET6: + qp = qbuf; + for (n = IN6ADDRSZ - 1; n >= 0; n--) + qp += sprintf (qp, "%x.%x.", uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf); + strcpy(qp, "ip6.int"); + break; + default: + /* Cannot happen. */ + } + + n = res_query (qbuf, C_IN, T_PTR, (u_char *)host_buffer.buf, + sizeof host_buffer); + if (n < 0) + { + *h_errnop = h_errno; + return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + + status = getanswer_r (&host_buffer, n, qbuf, T_PTR, result, buffer, buflen, + h_errnop); + if (status != NSS_STATUS_SUCCESS) + { + *h_errnop = h_errno; + return status; + } + +#ifdef SUNSECURITY + This is not implemented because it is not possible to use the current + source from bind in a multi-threaded program. +#endif + + result->h_addrtype = af; + result->h_length = len; + memcpy (host_data->host_addr, addr, len); + host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; + host_data->h_addr_ptrs[1] = NULL; + if (af == AF_INET && (_res.options & RES_USE_INET6)) + { + map_v4v6_address ((char *) host_data->host_addr, + (char *) host_data->host_addr); + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, + struct hostent *result, char *buffer, size_t buflen, + int *h_errnop) +{ + struct host_data + { + char *aliases[MAX_NR_ALIASES]; + unsigned char host_addr[16]; /* IPv4 or IPv6 */ + char *h_addr_ptrs[MAX_NR_ADDRS + 1]; + char linebuffer[0]; + } *host_data = (struct host_data *) buffer; + int linebuflen = buflen - offsetof (struct host_data, linebuffer); + register const HEADER *hp; + const u_char *end_of_message, *cp; + int n, ancount, qdcount; + int haveanswer, had_error; + char *bp, **ap, **hap; + char tbuf[MAXDNAME]; + const char *tname; + int (*name_ok) __P ((const char *)); + + tname = qname; + result->h_name = NULL; + end_of_message = answer->buf + anslen; + switch (qtype) + { + case T_A: + case T_AAAA: + name_ok = res_hnok; + break; + case T_PTR: + name_ok = res_dnok; + break; + default: + return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */ + } + + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + bp = host_data->linebuffer; + ancount = ntohs (hp->ancount); + qdcount = ntohs (hp->qdcount); + cp = answer->buf + HFIXEDSZ; + if (qdcount != 1) + { + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + + n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + if (n < 0 || (*name_ok) (bp) == 0) + { + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + cp += n + QFIXEDSZ; + + if (qtype == T_A || qtype == T_AAAA) + { + /* res_send() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = strlen (bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) + { + __set_h_errno (NO_RECOVERY); + return NSS_STATUS_TRYAGAIN; + } + result->h_name = bp; + bp += n; + linebuflen -= n; + /* The qname can be abbreviated, but h_name is now absolute. */ + qname = result->h_name; + } + + ap = host_data->aliases; + *ap = NULL; + result->h_aliases = host_data->aliases; + hap = host_data->h_addr_ptrs; + *hap = NULL; + result->h_addr_list = host_data->h_addr_ptrs; + haveanswer = 0; + had_error = 0; + + while (ancount-- > 0 && cp < end_of_message && had_error == 0) + { + int type, class; + + n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + if (n < 0 || (*name_ok) (bp) == 0) + { + ++had_error; + continue; + } + cp += n; /* name */ + type = _getshort (cp); + cp += INT16SZ; /* type */ + class = _getshort(cp); + cp += INT16SZ + INT32SZ; /* class, TTL */ + n = _getshort(cp); + cp += INT16SZ; /* len */ + if (class != C_IN) + { + /* XXX - debug? syslog? */ + cp += n; + continue; /* XXX - had_error++ ? */ + } + + if ((qtype ==T_A || qtype == T_AAAA) && type == T_CNAME) + { + if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1]) + continue; + n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf); + if (n < 0 || (*name_ok) (tbuf) == 0) + { + ++had_error; + continue; + } + cp += n; + /* Store alias. */ + *ap++ = bp; + n = strlen (bp) + 1; /* For the \0. */ + if (n >= MAXHOSTNAMELEN) + { + ++had_error; + continue; + } + bp += n; + linebuflen -= n; + /* Get canonical name. */ + n = strlen (tbuf) + 1; /* For the \0. */ + if ((size_t) n > buflen || n >= MAXHOSTNAMELEN) + { + ++had_error; + continue; + } + strcpy (bp, tbuf); /* Cannot overflow. */ + result->h_name = bp; + bp += n; + linebuflen -= n; + continue; + } + + if (qtype == T_PTR && type == T_CNAME) + { + n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf); + if (n < 0 || res_dnok (tbuf) == 0) + { + ++had_error; + continue; + } + cp += n; + /* Get canonical name. */ + n = strlen (tbuf) + 1; /* For the \0. */ + if ((size_t) n > buflen || n >= MAXHOSTNAMELEN) + { + ++had_error; + continue; + } + strcpy (bp, tbuf); /* Cannot overflow. */ + tname = bp; + bp += n; + linebuflen -= n; + continue; + } + if (type != qtype) + { + syslog (LOG_NOTICE | LOG_AUTH, + "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", + qname, p_class (C_IN), p_type (qtype), p_type (type)); + cp += n; + continue; /* XXX - had_error++ ? */ + } + + switch (type) + { + case T_PTR: + if (strcasecmp (tname, bp) != 0) + { + syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + if (n < 0 || res_hnok (bp) == 0) + { + ++had_error; + break; + } +#if MULTI_PTRS_ARE_ALIASES + cp += n; + if (haveanswer == 0) + result->h_name = bp; + else if (ap < &host_data->aliases[MAXALIASES-1]) + *ap++ = bp; + else + n = -1; + if (n != -1) + { + n = strlen (bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) + { + ++had_error; + break; + } + bp += n; + linebuflen -= n; + } + break; +#else + result->h_name = bp; + if (_res.options & RES_USE_INET6) + { + n = strlen (bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) + { + ++had_error; + break; + } + bp += n; + linebuflen -= n; + map_v4v6_hostent (result, &bp, &linebuflen); + } + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +#endif + case T_A: + case T_AAAA: + if (strcasecmp (result->h_name, bp) != 0) + { + syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + if (n != result->h_length) + { + cp += n; + continue; + } + if (!haveanswer) + { + register int nn; + + result->h_name = bp; + nn = strlen (bp) + 1; /* for the \0 */ + bp += nn; + linebuflen -= nn; + } + + bp += sizeof (align) - ((u_long) bp % sizeof (align)); + + if (n >= linebuflen) + { + ++had_error; + continue; + } + if (hap >= &host_data->h_addr_ptrs[MAX_NR_ADDRS-1]) + { + cp += n; + continue; + } + memcpy (*hap++ = bp, cp, n); + bp += n; + cp += n; + linebuflen -= n; + break; + default: + abort (); + } + if (had_error == 0) + ++haveanswer; + } + + if (haveanswer > 0) + { + *ap = NULL; + *hap = NULL; +#if defined(RESOLVSORT) + /* + * Note: we sort even if host can take only one address + * in its return structures - should give it the "best" + * address in that case, not some random one + */ + if (_res.nsort && haveanswer > 1 && qtype == T_A) + addrsort (host_data->h_addr_ptrs, haveanswer); +#endif /*RESOLVSORT*/ + + if (result->h_name == NULL) + { + n = strlen (qname) + 1; /* For the \0. */ + if (n > linebuflen || n >= MAXHOSTNAMELEN) + goto no_recovery; + strcpy (bp, qname); /* Cannot overflow. */ + result->h_name = bp; + bp += n; + linebuflen -= n; + } + + if (_res.options & RES_USE_INET6) + map_v4v6_hostent (result, &bp, &linebuflen); + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; + } + no_recovery: + *h_errnop = NO_RECOVERY; + return NSS_STATUS_TRYAGAIN; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_dns/dns-network.c glibc-2.1.3/glibc-compat/nss_dns/dns-network.c --- ../glibc-2.1.3/glibc-compat/nss_dns/dns-network.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_dns/dns-network.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,345 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Extended from original form by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Parts of this file are plain copies of the file `getnetnamadr.c' from + the bind package and it has the following copyright. */ + +/* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro + * Dep. Matematica Universidade de Coimbra, Portugal, Europe + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "nsswitch.h" +#include + +/* Maximum number of aliases we allow. */ +#define MAX_NR_ALIASES 48 + + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + + +typedef enum +{ + BYADDR, + BYNAME +} lookup_method; + + +/* We need this time later. */ +typedef union querybuf +{ + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + + +/* Prototypes for local functions. */ +static enum nss_status getanswer_r (const querybuf *answer, int anslen, + struct netent *result, char *buffer, + size_t buflen, lookup_method net_i); + + +enum nss_status +_nss_dns_getnetbyname_r (const char *name, struct netent *result, + char *buffer, size_t buflen) +{ + /* Return entry for network with NAME. */ + querybuf net_buffer; + int anslen; + char *qbuf; + + qbuf = strdupa (name); + anslen = res_search (qbuf, C_IN, T_PTR, (u_char *) &net_buffer, + sizeof (querybuf)); + if (anslen < 0) + /* Nothing found. */ + return (errno == ECONNREFUSED + || errno == EPFNOSUPPORT + || errno == EAFNOSUPPORT) + ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + + return getanswer_r (&net_buffer, anslen, result, buffer, buflen, BYNAME); +} + + +enum nss_status +_nss_dns_getnetbyaddr_r (long net, int type, struct netent *result, + char *buffer, size_t buflen) +{ + /* Return entry for network with NAME. */ + enum nss_status status; + querybuf net_buffer; + unsigned int net_bytes[4]; + char qbuf[MAXDNAME]; + int cnt, anslen; + u_int32_t net2; + + /* No net address lookup for IPv6 yet. */ + if (type != AF_INET) + return NSS_STATUS_UNAVAIL; + + net2 = (u_int32_t) net; + for (cnt = 4; net2 != 0; net2 >>= 8) + net_bytes[--cnt] = net2 & 0xff; + + switch (cnt) + { + case 3: + /* Class A network. */ + sprintf (qbuf, "0.0.0.%u.in-addr.arpa", net_bytes[3]); + break; + case 2: + /* Class B network. */ + sprintf (qbuf, "0.0.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2]); + break; + case 1: + /* Class C network. */ + sprintf (qbuf, "0.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2], + net_bytes[1]); + break; + case 0: + /* Class D - E network. */ + sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2], + net_bytes[1], net_bytes[0]); + break; + } + + anslen = res_query (qbuf, C_IN, T_PTR, (u_char *) &net_buffer, + sizeof (querybuf)); + if (anslen < 0) + /* Nothing found. */ + return (errno == ECONNREFUSED + || errno == EPFNOSUPPORT + || errno == EAFNOSUPPORT) + ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + + status = getanswer_r (&net_buffer, anslen, result, buffer, buflen, BYADDR); + if (status == NSS_STATUS_SUCCESS) + { + /* Strip trailing zeros. */ + unsigned int u_net = net; /* Maybe net should be unsigned? */ + + while ((u_net & 0xff) == 0 && u_net != 0) + u_net >>= 8; + result->n_net = u_net; + } + + return status; +} + + +#undef offsetof +#define offsetof(Type, Member) ((size_t) &((Type *) NULL)->Member) + +static enum nss_status +getanswer_r (const querybuf *answer, int anslen, struct netent *result, + char *buffer, size_t buflen, lookup_method net_i) +{ + /* + * Find first satisfactory answer + * + * answer --> +------------+ ( MESSAGE ) + * | Header | + * +------------+ + * | Question | the question for the name server + * +------------+ + * | Answer | RRs answering the question + * +------------+ + * | Authority | RRs pointing toward an authority + * | Additional | RRs holding additional information + * +------------+ + */ + struct net_data + { + char *aliases[MAX_NR_ALIASES]; + char linebuffer[0]; + } *net_data = (struct net_data *) buffer; + int linebuflen = buflen - offsetof (struct net_data, linebuffer); + const char *end_of_message = &answer->buf[anslen]; + const HEADER *header_pointer = &answer->hdr; + /* #/records in the answer section. */ + int answer_count = ntohs (header_pointer->ancount); + /* #/entries in the question section. */ + int question_count = ntohs (header_pointer->qdcount); + char *bp = net_data->linebuffer; + const char *cp = &answer->buf[HFIXEDSZ]; + char **alias_pointer; + int have_answer; + char *ans; + + if (question_count == 0) + { + /* FIXME: the Sun version uses for host name lookup an additional + parameter for pointing to h_errno. this is missing here. + OSF/1 has a per-thread h_errno variable. */ + if (header_pointer->aa != 0) + { + __set_h_errno (HOST_NOT_FOUND); + return NSS_STATUS_NOTFOUND; + } + else + { + __set_h_errno (TRY_AGAIN); + return NSS_STATUS_TRYAGAIN; + } + } + + /* Skip the question part. */ + while (question_count-- > 0) + cp += __dn_skipname (cp, end_of_message) + QFIXEDSZ; + + alias_pointer = result->n_aliases = &net_data->aliases[0]; + *alias_pointer = NULL; + have_answer = 0; + ans = NULL; + + while (--answer_count >= 0 && cp < end_of_message) + { + int n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + int type, class; + + if (n < 0 || res_dnok (bp) == 0) + break; + cp += n; + ans = strdupa (bp); + GETSHORT (type, cp); + GETSHORT (class, cp); + cp += INT32SZ; /* TTL */ + GETSHORT (n, cp); + + if (class == C_IN && type == T_PTR) + { + n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + if (n < 0 || !res_hnok (bp)) + { + /* XXX What does this mean? The original form from bind + returns NULL. Incrementing cp has no effect in any case. + What should I return here. ??? */ + cp += n; + return NSS_STATUS_UNAVAIL; + } + cp += n; + *alias_pointer++ = bp; + bp += strlen (bp) + 1; + result->n_addrtype = class == C_IN ? AF_INET : AF_UNSPEC; + ++have_answer; + } + } + + if (have_answer) + { + char *tmp; + int len; + char *in, *cp, *rp, *wp; + int cnt, first_flag; + + *alias_pointer = NULL; + switch (net_i) + { + case BYADDR: + result->n_name = result->n_aliases[0]; + result->n_net = 0L; + break; + case BYNAME: + len = strlen (result->n_aliases[0]); + tmp = (char *) alloca (len + 1); + tmp[len] = 0; + wp = &tmp[len - 1]; + + rp = in = result->n_aliases[0]; + result->n_name = ans; + + first_flag = 1; + for (cnt = 0; cnt < 4; ++cnt) + { + char *startp; + + startp = rp; + while (*rp != '.') + ++rp; + if (rp - startp > 1 || *startp != '0' || !first_flag) + { + first_flag = 0; + if (cnt > 0) + *wp-- = '.'; + cp = rp; + while (cp > startp) + *wp-- = *--cp; + } + in = rp + 1; + } + + result->n_net = inet_network (wp); + break; + } + + ++result->n_aliases; + return NSS_STATUS_SUCCESS; + } + + __set_h_errno (TRY_AGAIN); + return NSS_STATUS_TRYAGAIN; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-XXX.c glibc-2.1.3/glibc-compat/nss_files/files-XXX.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-XXX.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-XXX.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,311 @@ +/* Common code for file-based databases in nss_files module. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include "nsswitch.h" + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- string of the database file's name ("hosts", "passwd"). + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. + + Also see files-parse.c. +*/ + +#define ENTNAME_r CONCAT(ENTNAME,_r) + +#define DATAFILE "/etc/" DATABASE + +#ifdef NEED_H_ERRNO +# include +# define H_ERRNO_PROTO , int *herrnop +# define H_ERRNO_ARG , herrnop +# define H_ERRNO_SET(val) (*herrnop = (val)) +#else +# define H_ERRNO_PROTO +# define H_ERRNO_ARG +# define H_ERRNO_SET(val) ((void) 0) +#endif + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared stream open on the database file. */ + +static FILE *stream; +static fpos_t position; +static enum { none, getent, getby } last_use; +static int keep_stream; + +/* Open database file if not already opened. */ +static enum nss_status +internal_setent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (stream == NULL) + { + stream = fopen (DATAFILE, "r"); + + if (stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (stream); + + /* Remember STAYOPEN flag. */ + if (stream != NULL) + keep_stream |= stayopen; + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +CONCAT(_nss_files_set,ENTNAME) (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (stayopen); + + if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) + { + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + + last_use = getent; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (void) +{ + if (stream != NULL) + { + fclose (stream); + stream = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +CONCAT(_nss_files_end,ENTNAME) (void) +{ + __libc_lock_lock (lock); + + internal_endent (); + + /* Reset STAYOPEN flag. */ + keep_stream = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* Parsing the database file into `struct STRUCTURE' data structures. */ + +static enum nss_status +internal_getent (struct STRUCTURE *result, + char *buffer, int buflen H_ERRNO_PROTO) +{ + char *p; + struct parser_data *data = (void *) buffer; + int linebuflen = buffer + buflen - data->linebuffer; + int parse_result; + + if (buflen < (int) sizeof *data + 1) + { + __set_errno (ERANGE); + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } + + do + { + /* Terminate the line so that we can test for overflow. */ + data->linebuffer[linebuflen - 1] = '\xff'; + + p = fgets (data->linebuffer, linebuflen, stream); + if (p == NULL && feof (stream)) + { + /* End of file or read error. */ + __set_errno (ENOENT); + H_ERRNO_SET (HOST_NOT_FOUND); + return NSS_STATUS_NOTFOUND; + } + else if (p == NULL || data->linebuffer[linebuflen - 1] != '\xff') + { + /* The line is too long. Give the user the opportunity to + enlarge the buffer. */ + __set_errno (ERANGE); + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to get the next + line of the file to parse. */ + || ! (parse_result = parse_line (p, result, data, buflen))); + + /* Filled in RESULT with the next entry from the database file. */ + return parse_result == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_SUCCESS; +} + + +/* Return the next entry from the database file, doing locking. */ +enum nss_status +CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, + char *buffer, size_t buflen H_ERRNO_PROTO) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the set*ent function was not called before. */ + if (stream == NULL) + { + status = internal_setent (0); + + if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) + { + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + + if (status == NSS_STATUS_SUCCESS) + { + /* If the last use was not by the getent function we need the + position the stream. */ + if (last_use != getent) + { + if (fsetpos (stream, &position) < 0) + status = NSS_STATUS_UNAVAIL; + else + last_use = getent; + } + + if (status == NSS_STATUS_SUCCESS) + { + status = internal_getent (result, buffer, buflen H_ERRNO_ARG); + + /* Remember this position if we were successful. If the + operation failed we give the user a chance to repeat the + operation (perhaps the buffer was too small). */ + if (status == NSS_STATUS_SUCCESS) + fgetpos (stream, &position); + else + /* We must make sure we reposition the stream the next call. */ + last_use = none; + } + } + + __libc_lock_unlock (lock); + + return status; +} + +/* Macro for defining lookup functions for this file-based database. + + NAME is the name of the lookup; e.g. `hostbyname'. + + KEYSIZE and KEYPATTERN are ignored here but used by ../nss_db/db-XXX.c. + + PROTO describes the arguments for the lookup key; + e.g. `const char *hostname'. + + BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result' + to the lookup key arguments and does `break;' if they match. */ + +#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \ +enum nss_status \ +_nss_files_get##name##_r (proto, \ + struct STRUCTURE *result, \ + char *buffer, size_t buflen H_ERRNO_PROTO) \ +{ \ + enum nss_status status; \ + \ + __libc_lock_lock (lock); \ + \ + /* Reset file pointer to beginning or open file. */ \ + status = internal_setent (keep_stream); \ + \ + if (status == NSS_STATUS_SUCCESS) \ + { \ + /* Tell getent function that we have repositioned the file pointer. */ \ + last_use = getby; \ + \ + while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG)) \ + == NSS_STATUS_SUCCESS) \ + { break_if_match } \ + \ + if (! keep_stream) \ + internal_endent (); \ + } \ + \ + __libc_lock_unlock (lock); \ + \ + return status; \ +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-alias.c glibc-2.1.3/glibc-compat/nss_files/files-alias.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-alias.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-alias.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,451 @@ +/* Mail alias file parser in nss_files module. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nsswitch.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared stream open on the database file. */ + +static FILE *stream; +static fpos_t position; +static enum { none, getent, getby } last_use; + + +static enum nss_status +internal_setent (void) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (stream == NULL) + { + stream = fopen ("/etc/aliases", "r"); + + if (stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (stream); + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_files_setaliasent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (); + + if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) + { + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + + last_use = getent; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (void) +{ + if (stream != NULL) + { + fclose (stream); + stream = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_files_endaliasent (void) +{ + __libc_lock_lock (lock); + + internal_endent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* Parsing the database file into `struct aliasent' data structures. */ +static enum nss_status +get_next_alias (const char *match, struct aliasent *result, + char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_NOTFOUND; + int ignore = 0; + + result->alias_members_len = 0; + + while (1) + { + /* Now we are ready to process the input. We have to read a + line and all its continuations and construct the array of + string pointers. This pointers and the names itself have to + be placed in BUFFER. */ + char *first_unused = buffer; + size_t room_left = buflen - (buflen % __alignof__ (char *)); + char *line; + + /* Read the first line. It must contain the alias name and + possibly some alias names. */ + first_unused[room_left - 1] = '\xff'; + line = fgets (first_unused, room_left, stream); + if (line == NULL && feof (stream)) + /* Nothing to read. */ + break; + else if (line == NULL || first_unused[room_left - 1] != '\xff') + { + /* The line is too long for our buffer. */ + no_more_room: + __set_errno (ERANGE); + status = NSS_STATUS_TRYAGAIN; + break; + } + else + { + char *cp; + + /* If we are in IGNORE mode and the first character in the + line is a white space we ignore the line and start + reading the next. */ + if (ignore && isspace (*first_unused)) + continue; + + /* Terminate the line for any case. */ + cp = strpbrk (first_unused, "#\n"); + if (cp != NULL) + *cp = '\0'; + + /* Skip leading blanks. */ + while (isspace (*line)) + ++line; + + result->alias_name = first_unused; + while (*line != '\0' && *line != ':') + *first_unused++ = *line++; + if (*line == '\0' || result->alias_name == first_unused) + /* No valid name. Ignore the line. */ + continue; + + *first_unused++ = '\0'; + if (room_left < (size_t) (first_unused - result->alias_name)) + goto no_more_room; + room_left -= first_unused - result->alias_name; + ++line; + + /* When we search for a specific alias we can avoid all the + difficult parts and compare now with the name we are + looking for. If it does not match we simply ignore all + lines until the next line containing the start of a new + alias is found. */ + ignore = (match != NULL + && __strcasecmp (result->alias_name, match) != 0); + + while (! ignore) + { + while (isspace (*line)) + ++line; + + cp = first_unused; + while (*line != '\0' && *line != ',') + *first_unused++ = *line++; + + if (first_unused != cp) + { + /* OK, we can have a regular entry or an include + request. */ + if (*line != '\0') + ++line; + *first_unused++ = '\0'; + + if (strncmp (cp, ":include:", 9) != 0) + { + if (room_left < (first_unused - cp) + sizeof (char *)) + goto no_more_room; + room_left -= (first_unused - cp) + sizeof (char *); + + ++result->alias_members_len; + } + else + { + /* Oh well, we have to read the addressed file. */ + FILE *listfile; + char *old_line = NULL; + + first_unused = cp; + + listfile = fopen (&cp[9], "r"); + /* If the file does not exist we simply ignore + the statement. */ + if (listfile != NULL + && (old_line = strdup (line)) != NULL) + { + while (! feof (listfile)) + { + first_unused[room_left - 1] = '\xff'; + line = fgets (first_unused, room_left, listfile); + if (line == NULL && feof (listfile)) + break; + if (line == NULL + || first_unused[room_left - 1] != '\xff') + { + free (old_line); + goto no_more_room; + } + + /* Parse the line. */ + cp = strpbrk (line, "#\n"); + if (cp != NULL) + *cp = '\0'; + + do + { + while (isspace (*line)) + ++line; + + cp = first_unused; + while (*line != '\0' && *line != ',') + *first_unused++ = *line++; + + if (*line != '\0') + ++line; + + if (first_unused != cp) + { + *first_unused++ = '\0'; + if (room_left < ((first_unused - cp) + + __alignof__ (char *))) + { + free (old_line); + goto no_more_room; + } + room_left -= ((first_unused - cp) + + __alignof__ (char *)); + ++result->alias_members_len; + } + } + while (*line != '\0'); + } + fclose (listfile); + + first_unused[room_left - 1] = '\0'; + strncpy (first_unused, old_line, room_left); + + if (old_line != NULL) + free (old_line); + + if (first_unused[room_left - 1] != '\0') + goto no_more_room; + } + } + } + + if (*line == '\0') + { + /* Get the next line. But we must be careful. We + must not read the whole line at once since it + might belong to the current alias. Simply read + the first character. If it is a white space we + have a continuation line. Otherwise it is the + beginning of a new alias and we can push back the + just read character. */ + int ch; + + ch = fgetc (stream); + if (ch == EOF || ch == '\n' || !isspace (ch)) + { + size_t cnt; + + /* Now prepare the return. Provide string + pointers for the currently selected aliases. */ + if (ch != EOF) + ungetc (ch, stream); + + /* Adjust the pointer so it is aligned for + storing pointers. */ + first_unused += __alignof__ (char *) - 1; + first_unused -= ((first_unused - (char *) 0) + % __alignof__ (char *)); + result->alias_members = (char **) first_unused; + + /* Compute addresses of alias entry strings. */ + cp = result->alias_name; + for (cnt = 0; cnt < result->alias_members_len; ++cnt) + { + cp = strchr (cp, '\0') + 1; + result->alias_members[cnt] = cp; + } + + status = (result->alias_members_len == 0 + ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS); + break; + } + + /* The just read character is a white space and so + can be ignored. */ + first_unused[room_left - 1] = '\xff'; + line = fgets (first_unused, room_left, stream); + if (line == NULL && feof (stream)) + break; + if (line == NULL || first_unused[room_left - 1] != '\xff') + goto no_more_room; + cp = strpbrk (line, "#\n"); + if (cp != NULL) + *cp = '\0'; + } + } + } + + if (status != NSS_STATUS_NOTFOUND) + /* We read something. In any case break here. */ + break; + } + + return status; +} + + +enum nss_status +_nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the set*ent function was not called before. */ + if (stream == NULL) + status = internal_setent (); + + if (status == NSS_STATUS_SUCCESS) + { + /* If the last use was not by the getent function we need the + position the stream. */ + if (last_use != getent) + { + if (fsetpos (stream, &position) < 0) + status = NSS_STATUS_UNAVAIL; + else + last_use = getent; + } + + if (status == NSS_STATUS_SUCCESS) + { + result->alias_local = 1; + + /* Read lines until we get a definite result. */ + do + status = get_next_alias (NULL, result, buffer, buflen); + while (status == NSS_STATUS_RETURN); + + /* If we successfully read an entry remember this position. */ + if (status == NSS_STATUS_SUCCESS) + fgetpos (stream, &position); + else + last_use = none; + } + } + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_files_getaliasbyname_r (const char *name, struct aliasent *result, + char *buffer, size_t buflen) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + __libc_lock_lock (lock); + + /* Open the stream or rest it. */ + status = internal_setent (); + last_use = getby; + + if (status == NSS_STATUS_SUCCESS) + { + result->alias_local = 1; + + /* Read lines until we get a definite result. */ + do + status = get_next_alias (name, result, buffer, buflen); + while (status == NSS_STATUS_RETURN); + } + + internal_endent (); + + __libc_lock_unlock (lock); + + return status; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-ethers.c glibc-2.1.3/glibc-compat/nss_files/files-ethers.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-ethers.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-ethers.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,75 @@ +/* Copyright (C) 1996 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include + +/* Because the `ethers' lookup does not fit so well in the scheme so + we define a dummy struct here which helps us to use the available + functions. */ +struct etherent +{ + const char *e_name; + struct ether_addr e_addr; +}; +struct etherent_data {}; + +#define ENTNAME etherent +#define DATABASE "ethers" +#include "files-parse.c" +LINE_PARSER +("#", + /* Read the ethernet address: 6 x 8bit hexadecimal number. */ + { + size_t cnt; + + for (cnt = 0; cnt < 6; ++cnt) + { + unsigned int number; + + if (cnt < 5) + INT_FIELD (number, ISCOLON , 0, 16, (unsigned int)) + else + INT_FIELD (number, isspace, 0, 16, (unsigned int)) + + if (number > 0xff) + return 0; + result->e_addr.ether_addr_octet[cnt] = number; + } + }; + STRING_FIELD (result->e_name, isspace, 1); + ) + + +#include GENERIC + +DB_LOOKUP (hostton, 1 + strlen (name), (".%s", name), + { + if (strcmp (result->e_name, name) == 0) + break; + }, const char *name) + +DB_LOOKUP (ntohost, 18, ("=%x:%x:%x:%x:%x:%x", + addr->ether_addr_octet[0], addr->ether_addr_octet[1], + addr->ether_addr_octet[2], addr->ether_addr_octet[3], + addr->ether_addr_octet[4], addr->ether_addr_octet[5]), + { + if (memcmp (&result->e_addr, addr, + sizeof (struct ether_addr)) == 0) + break; + }, struct ether_addr *addr) diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-grp.c glibc-2.1.3/glibc-compat/nss_files/files-grp.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-grp.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-grp.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,45 @@ +/* Group file parser in nss_files module. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include + +#define STRUCTURE group +#define ENTNAME grent +#define DATABASE "group" +struct grent_data {}; + +/* Our parser function is already defined in fgetgrent.c, so use that. + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (grnam, 1 + strlen (name), (".%s", name), + { + if (name[0] != '-' && name[0] != '+' + && ! strcmp (name, result->gr_name)) + break; + }, const char *name) + +DB_LOOKUP (grgid, 20, ("=%lu", (unsigned long int) gid), + { + if (result->gr_gid == gid && result->gr_name[0] != '+' + && result->gr_name[0] != '-') + break; + }, gid_t gid) diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-hosts.c glibc-2.1.3/glibc-compat/nss_files/files-hosts.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-hosts.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-hosts.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,107 @@ +/* Hosts file parser in nss_files module. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include + + +/* Get implementation for some internal functions. */ +#include "../resolv/mapv4v6addr.h" + + +#define ENTNAME hostent +#define DATABASE "hosts" +#define NEED_H_ERRNO + +#define ENTDATA hostent_data +struct hostent_data + { + unsigned char host_addr[16]; /* IPv4 or IPv6 address. */ + char *h_addr_ptrs[2]; /* Points to that and null terminator. */ + }; + +#define TRAILING_LIST_MEMBER h_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (addr, isspace, 1); + + /* Parse address. */ + if (inet_pton (AF_INET, addr, entdata->host_addr) > 0) + { + if (_res.options & RES_USE_INET6) + { + map_v4v6_address ((char *) entdata->host_addr, + (char *) entdata->host_addr); + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + { + result->h_addrtype = AF_INET; + result->h_length = INADDRSZ; + } + } + else if (inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + { + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + /* Illegal address: ignore line. */ + return 0; + + /* Store a pointer to the address in the expected form. */ + entdata->h_addr_ptrs[0] = entdata->host_addr; + entdata->h_addr_ptrs[1] = NULL; + result->h_addr_list = entdata->h_addr_ptrs; + + STRING_FIELD (result->h_name, isspace, 1); + }) + +#include "files-XXX.c" + +DB_LOOKUP (hostbyname, ,, + { + if (result->h_addrtype != ((_res.options & RES_USE_INET6) + ? AF_INET6 : AF_INET)) + continue; + LOOKUP_NAME_CASE (h_name, h_aliases) + }, const char *name) + +DB_LOOKUP (hostbyname2, ,, + { + if (result->h_addrtype != af) + continue; + LOOKUP_NAME_CASE (h_name, h_aliases) + }, const char *name, int af) + +DB_LOOKUP (hostbyaddr, ,, + { + if (result->h_addrtype == type && result->h_length == len && + ! memcmp (addr, result->h_addr_list[0], len)) + break; + }, const char *addr, int len, int type) diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-netgrp.c glibc-2.1.3/glibc-compat/nss_files/files-netgrp.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-netgrp.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-netgrp.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,268 @@ +/* Netgroup file parser in nss_files modules. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include "nsswitch.h" +#include "netgroup.h" + +#define DATAFILE "/etc/netgroup" + + +#define EXPAND(needed) \ + do \ + { \ + size_t old_cursor = result->cursor - result->data; \ + \ + result->data_size += 512 > 2 * needed ? 512 : 2 * needed; \ + result->data = realloc (result->data, result->data_size); \ + \ + if (result->data == NULL) \ + { \ + status = NSS_STATUS_UNAVAIL; \ + goto the_end; \ + } \ + \ + result->cursor = result->data + old_cursor; \ + } \ + while (0) + + +enum nss_status +_nss_files_setnetgrent (const char *group, struct __netgrent *result) +{ + FILE *fp; + enum nss_status status; + + if (group[0] == '\0') + return NSS_STATUS_UNAVAIL; + + /* Find the netgroups file and open it. */ + fp = fopen (DATAFILE, "r"); + if (fp == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* Read the file line by line and try to find the description + GROUP. We must take care for long lines. */ + char *line = NULL; + size_t line_len = 0; + const ssize_t group_len = strlen (group); + + status = NSS_STATUS_NOTFOUND; + result->cursor = result->data; + + while (!feof (fp)) + { + ssize_t curlen = getline (&line, &line_len, fp); + int found; + + if (curlen < 0) + { + status = NSS_STATUS_NOTFOUND; + break; + } + + found = (curlen > group_len && strncmp (line, group, group_len) == 0 + && isspace (line[group_len])); + + /* Read the whole line (including continuation) and store it + if FOUND in nonzero. Otherwise we don't need it. */ + if (found) + { + /* Store the data from the first line. */ + EXPAND (curlen - group_len); + memcpy (result->cursor, &line[group_len + 1], + curlen - group_len); + result->cursor += (curlen - group_len) - 1; + } + + while (line[curlen - 1] == '\n' && line[curlen - 2] == '\\') + { + /* Yes, we have a continuation line. */ + if (found) + /* Remove these characters from the stored line. */ + result->cursor -= 2; + + /* Get next line. */ + curlen = getline (&line, &line_len, fp); + if (curlen <= 0) + break; + + if (found) + { + /* Make sure we have enough room. */ + EXPAND (1 + curlen + 1); + + /* Add separator in case next line starts immediately. */ + *result->cursor++ = ' '; + + /* Copy new line. */ + memcpy (result->cursor, line, curlen + 1); + result->cursor += curlen; + } + } + + if (found) + { + /* Now we have read the line. */ + status = NSS_STATUS_SUCCESS; + result->cursor = result->data; + result->first = 1; + break; + } + } + + the_end: + /* We don't need the file and the line buffer anymore. */ + free (line); + fclose (fp); + } + + return status; +} + + +int +_nss_files_endnetgrent (struct __netgrent *result) +{ + /* Free allocated memory for data if some is present. */ + if (result->data != NULL) + { + free (result->data); + result->data = NULL; + result->data_size = 0; + result->cursor = NULL; + } + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_netgroup_parseline (char **cursor, struct __netgrent *result, + char *buffer, int buflen) +{ + enum nss_status status; + const char *host, *user, *domain; + char *cp = *cursor; + + /* Some sanity checks. */ + if (cp == NULL) + return NSS_STATUS_NOTFOUND; + + /* First skip leading spaces. */ + while (isspace (*cp)) + ++cp; + + if (*cp != '(') + { + /* We have a list of other netgroups. */ + char *name = cp; + + while (*cp != '\0' && ! isspace (*cp)) + ++cp; + + if (name != cp) + { + /* It is another netgroup name. */ + int last = *cp == '\0'; + + result->type = group_val; + result->val.group = name; + *cp = '\0'; + if (! last) + ++cp; + *cursor = cp; + result->first = 0; + + return NSS_STATUS_SUCCESS; + } + + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + } + + /* Match host name. */ + host = ++cp; + while (*cp != ',') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + + /* Match user name. */ + user = ++cp; + while (*cp != ',') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + + /* Match domain name. */ + domain = ++cp; + while (*cp != ')') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + ++cp; + + + /* When we got here we have found an entry. Before we can copy it + to the private buffer we have to make sure it is big enough. */ + if (cp - host > buflen) + { + __set_errno (ERANGE); + status = NSS_STATUS_UNAVAIL; + } + else + { + memcpy (buffer, host, cp - host); + result->type = triple_val; + + buffer[(user - host) - 1] = '\0'; + result->val.triple.host = *host == ',' ? NULL : buffer; + + buffer[(domain - host) - 1] = '\0'; + result->val.triple.user = *user == ',' ? NULL : buffer + (user - host); + + buffer[(cp - host) - 1] = '\0'; + result->val.triple.domain = + *domain == ')' ? NULL : buffer + (domain - host); + + status = NSS_STATUS_SUCCESS; + + /* Remember where we stopped reading. */ + *cursor = cp; + + result->first = 0; + } + + return status; +} + + +enum nss_status +_nss_files_getnetgrent_r (struct __netgrent *result, char *buffer, int buflen) +{ + enum nss_status status; + + status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen); + + return status; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-network.c glibc-2.1.3/glibc-compat/nss_files/files-network.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-network.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-network.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,56 @@ +/* Networks file parser in nss_files module. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include + +#define ENTNAME netent +#define DATABASE "networks" + +struct netent_data {}; + +#define TRAILING_LIST_MEMBER n_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (result->n_name, isspace, 1); + + STRING_FIELD (addr, isspace, 1); + result->n_net = inet_network (addr); + result->n_addrtype = AF_INET; + + }) + +#include "files-XXX.c" + +DB_LOOKUP (netbyname, ,, + LOOKUP_NAME_CASE (n_name, n_aliases), + const char *name) + +DB_LOOKUP (netbyaddr, ,, + { + if (result->n_addrtype == type && result->n_net == net) + /* Bingo! */ + break; + }, unsigned long int net, int type) diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-parse.c glibc-2.1.3/glibc-compat/nss_files/files-parse.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-parse.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-parse.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,251 @@ +/* Common code for file-based database parsers in nss_files module. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- string of the database file's name ("hosts", "passwd"). + + ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store + things pointed to by the resultant `struct STRUCTURE'. + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. + + Also see files-XXX.c. */ + +#define CONCAT(a,b) CONCAT1(a,b) +#define CONCAT1(a,b) a##b + +#ifndef STRUCTURE +# define STRUCTURE ENTNAME +#endif + + +struct parser_data + { +#ifdef ENTDATA + struct ENTDATA entdata; +# define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata; +#else +# define ENTDATA_DECL(data) +#endif + char linebuffer[0]; + }; + +#ifdef ENTDATA +/* The function can't be exported, because the entdata structure + is defined only in files-foo.c. */ +# define parser_stclass static inline +#else +/* Export the line parser function so it can be used in nss_db. */ +# define parser_stclass /* Global */ +# define parse_line CONCAT(_nss_files_parse_,ENTNAME) +#endif + + +#ifdef EXTERN_PARSER + +/* The parser is defined in a different module. */ +extern int parse_line (char *line, struct STRUCTURE *result, + struct parser_data *data, size_t datalen); + +# define LINE_PARSER(EOLSET, BODY) /* Do nothing */ + +#else + +/* Define a line parsing function. */ + +# define LINE_PARSER(EOLSET, BODY) \ +parser_stclass int \ +parse_line (char *line, struct STRUCTURE *result, \ + struct parser_data *data, size_t datalen) \ +{ \ + ENTDATA_DECL (data) \ + char *p = strpbrk (line, EOLSET "\n"); \ + if (p != NULL) \ + *p = '\0'; \ + BODY; \ + TRAILING_LIST_PARSER; \ + return 1; \ +} + + +# define STRING_FIELD(variable, terminator_p, swallow) \ + { \ + variable = line; \ + while (*line != '\0' && !terminator_p (*line)) \ + ++line; \ + if (*line != '\0') \ + { \ + *line = '\0'; \ + do \ + ++line; \ + while (swallow && terminator_p (*line)); \ + } \ + } + +# define INT_FIELD(variable, terminator_p, swallow, base, convert) \ + { \ + char *endp; \ + variable = convert (strtoul (line, &endp, base)); \ + if (endp == line) \ + return 0; \ + else if (terminator_p (*endp)) \ + do \ + ++endp; \ + while (swallow && terminator_p (*endp)); \ + else if (*endp != '\0') \ + return 0; \ + line = endp; \ + } + +# define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default) \ + { \ + char *endp; \ + if (*line == '\0') \ + /* We expect some more input, so don't allow the string to end here. */ \ + return 0; \ + variable = convert (strtoul (line, &endp, base)); \ + if (endp == line) \ + variable = default; \ + if (terminator_p (*endp)) \ + do \ + ++endp; \ + while (swallow && terminator_p (*endp)); \ + else if (*endp != '\0') \ + return 0; \ + line = endp; \ + } + +# define ISCOLON(c) ((c) == ':') + + +# ifndef TRAILING_LIST_MEMBER +# define TRAILING_LIST_PARSER /* Nothing to do. */ +# else + +# define TRAILING_LIST_PARSER \ +{ \ + char **list = parse_list (line, data, datalen); \ + if (list) \ + result->TRAILING_LIST_MEMBER = list; \ + else \ + return -1; /* -1 indicates we ran out of space. */ \ +} + +static inline char ** +parse_list (char *line, struct parser_data *data, size_t datalen) +{ + char *eol, **list, **p; + + if (line >= data->linebuffer && line < (char *) data + datalen) + /* Find the end of the line buffer, we will use the space in DATA after + it for storing the vector of pointers. */ + eol = strchr (line, '\0') + 1; + else + /* LINE does not point within DATA->linebuffer, so that space is + not being used for scratch space right now. We can use all of + it for the pointer vector storage. */ + eol = data->linebuffer; + /* Adjust the pointer so it is aligned for storing pointers. */ + eol += __alignof__ (char *) - 1; + eol -= (eol - (char *) 0) % __alignof__ (char *); + /* We will start the storage here for the vector of pointers. */ + list = (char **) eol; + + p = list; + while (1) + { + char *elt; + + if ((size_t) ((char *) &p[1] - (char *) data) > datalen) + { + /* We cannot fit another pointer in the buffer. */ + __set_errno (ERANGE); + return NULL; + } + if (*line == '\0') + break; + + /* Skip leading white space. This might not be portable but useful. */ + while (isspace (*line)) + ++line; + + elt = line; + while (1) + { + if (*line == '\0' || TRAILING_LIST_SEPARATOR_P (*line)) + { + /* End of the next entry. */ + if (line > elt) + /* We really found some data. */ + *p++ = elt; + + /* Terminate string if necessary. */ + if (*line != '\0') + *line++ = '\0'; + break; + } + ++line; + } + } + *p = NULL; + + return list; +} + +# endif /* TRAILING_LIST_MEMBER */ +#endif /* EXTERN_PARSER */ + + +#define LOOKUP_NAME(nameelt, aliaselt) \ +{ \ + char **ap; \ + if (! strcmp (name, result->nameelt)) \ + break; \ + for (ap = result->aliaselt; *ap; ++ap) \ + if (! strcmp (name, *ap)) \ + break; \ + if (*ap) \ + break; \ +} + +#define LOOKUP_NAME_CASE(nameelt, aliaselt) \ +{ \ + char **ap; \ + if (! __strcasecmp (name, result->nameelt)) \ + break; \ + for (ap = result->aliaselt; *ap; ++ap) \ + if (! __strcasecmp (name, *ap)) \ + break; \ + if (*ap) \ + break; \ +} + + +/* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead. */ +#ifndef GENERIC +# define GENERIC "files-XXX.c" +#endif diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-proto.c glibc-2.1.3/glibc-compat/nss_files/files-proto.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-proto.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-proto.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,47 @@ +/* Protocols file parser in nss_files module. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include + + +#define ENTNAME protoent +#define DATABASE "protocols" + +struct protoent_data {}; + +#define TRAILING_LIST_MEMBER p_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + STRING_FIELD (result->p_name, isspace, 1); + INT_FIELD (result->p_proto, isspace, 1, 10,); + ) + +#include GENERIC + +DB_LOOKUP (protobyname, 1 + strlen (name), (".%s", name), + LOOKUP_NAME (p_name, p_aliases), + const char *name) + +DB_LOOKUP (protobynumber, 20, ("=%d", proto), + { + if (result->p_proto == proto) + break; + }, int proto) diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-pwd.c glibc-2.1.3/glibc-compat/nss_files/files-pwd.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-pwd.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-pwd.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,45 @@ +/* User file parser in nss_files module. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include + +#define STRUCTURE passwd +#define ENTNAME pwent +#define DATABASE "passwd" +struct pwent_data {}; + +/* Our parser function is already defined in fgetpwent_r.c, so use that + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (pwnam, 1 + strlen (name), (".%s", name), + { + if (name[0] != '+' && name[0] != '-' + && ! strcmp (name, result->pw_name)) + break; + }, const char *name) + +DB_LOOKUP (pwuid, 20, ("=%lu", (unsigned long int) uid), + { + if (result->pw_uid == uid && result->pw_name[0] != '+' + && result->pw_name[0] != '-') + break; + }, uid_t uid) diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-rpc.c glibc-2.1.3/glibc-compat/nss_files/files-rpc.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-rpc.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-rpc.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,47 @@ +/* SunRPC program number file parser in nss_files module. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include + + +#define ENTNAME rpcent +#define DATABASE "rpc" + +struct rpcent_data {}; + +#define TRAILING_LIST_MEMBER r_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + STRING_FIELD (result->r_name, isspace, 1); + INT_FIELD (result->r_number, isspace, 1, 10,); + ) + +#include GENERIC + +DB_LOOKUP (rpcbyname, 1 + strlen (name), (".%s", name), + LOOKUP_NAME (r_name, r_aliases), + const char *name) + +DB_LOOKUP (rpcbynumber, 20, ("=%d", number), + { + if (result->r_number == number) + break; + }, int number) diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-service.c glibc-2.1.3/glibc-compat/nss_files/files-service.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-service.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-service.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,60 @@ +/* Services file parser in nss_files module. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include + + +#define ENTNAME servent +#define DATABASE "services" + +struct servent_data {}; + +#define TRAILING_LIST_MEMBER s_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +#define ISSLASH(c) ((c) == '/') +LINE_PARSER +("#", + STRING_FIELD (result->s_name, isspace, 1); + INT_FIELD (result->s_port, ISSLASH, 10, 0, htons); + STRING_FIELD (result->s_proto, isspace, 1); + ) + +#include GENERIC + +DB_LOOKUP (servbyname, 2 + strlen (name) + (proto ? strlen (proto) : 0), + (".%s/%s", name, proto ?: ""), + { + /* Must match both protocol (if specified) and name. */ + if (proto != NULL && strcmp (result->s_proto, proto)) + continue; + LOOKUP_NAME (s_name, s_aliases) + }, + const char *name, const char *proto) + +DB_LOOKUP (servbyport, 21 + (proto ? strlen (proto) : 0), + ("=%d/%s", ntohs (port), proto ?: ""), + { + /* Must match both port and protocol. */ + if (result->s_port == port + && (proto == NULL + || strcmp (result->s_proto, proto) == 0)) + break; + }, int port, const char *proto) diff -Naur ../glibc-2.1.3/glibc-compat/nss_files/files-spwd.c glibc-2.1.3/glibc-compat/nss_files/files-spwd.c --- ../glibc-2.1.3/glibc-compat/nss_files/files-spwd.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_files/files-spwd.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,38 @@ +/* User file parser in nss_files module. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include + +#define STRUCTURE spwd +#define ENTNAME spent +#define DATABASE "shadow" +struct spent_data {}; + +/* Our parser function is already defined in sgetspent_r.c, so use that + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (spnam, 1 + strlen (name), (".%s", name), + { + if (name[0] != '+' && name[0] != '-' + && ! strcmp (name, result->sp_namp)) + break; + }, const char *name) diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-alias.c glibc-2.1.3/glibc-compat/nss_nis/nis-alias.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-alias.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-alias.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,278 @@ +/* Copyright (C) 1996, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +static int +_nss_nis_parse_aliasent (const char *key, char *alias, struct aliasent *result, + char *buffer, size_t buflen) +{ + char *first_unused = buffer + strlen (alias) + 1; + size_t room_left = + buflen - (buflen % __alignof__ (char *)) - strlen (alias) - 2; + char *line; + char *cp; + + result->alias_members_len = 0; + *first_unused = '\0'; + first_unused++; + strcpy (first_unused, key); + + if (first_unused[room_left - 1] != '\0') + { + /* The line is too long for our buffer. */ + no_more_room: + __set_errno (ERANGE); + return -1; + } + + result->alias_name = first_unused; + + /* Terminate the line for any case. */ + cp = strpbrk (alias, "#\n"); + if (cp != NULL) + *cp = '\0'; + + first_unused += strlen (result->alias_name) + 1; + /* Adjust the pointer so it is aligned for + storing pointers. */ + first_unused += __alignof__ (char *) - 1; + first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); + result->alias_members = (char **) first_unused; + + line = alias; + + while (*line != '\0') + { + /* Skip leading blanks. */ + while (isspace (*line)) + line++; + + if (*line == '\0') + break; + + if (room_left < sizeof (char *)) + goto no_more_room; + room_left -= sizeof (char *); + result->alias_members[result->alias_members_len] = line; + + while (*line != '\0' && *line != ',') + line++; + + if (line != result->alias_members[result->alias_members_len]) + { + *line = '\0'; + line++; + result->alias_members_len++; + } + } + return result->alias_members_len == 0 ? 0 : 1; +} + +enum nss_status +_nss_nis_setaliasent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endaliasent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getaliasent_r (struct aliasent *alias, char *buffer, + size_t buflen) +{ + char *domain; + char *result; + int len; + char *outkey; + int keylen; + char *p; + int parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + alias->alias_local = 0; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + + if (new_start) + retval = yperr2nss (yp_first (domain, "mail.aliases", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "mail.aliases", oldkey, + oldkeylen, &outkey, &keylen, + &result, &len)); + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, buflen); + if (parse_res == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getaliasent_r (struct aliasent *alias, char *buffer, size_t buflen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getaliasent_r (alias, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias, + char *buffer, size_t buflen) +{ + enum nss_status retval; + int parse_res; + char *domain; + char *result; + int len; + char *p; + size_t namlen = strlen (name); + char name2[namlen + 1]; + int i; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Convert name to lowercase. */ + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + retval = yperr2nss (yp_match (domain, "mail.aliases", name, namlen, + &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + alias->alias_local = 0; + parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + else + return NSS_STATUS_SUCCESS; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-ethers.c glibc-2.1.3/glibc-compat/nss_nis/nis-ethers.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-ethers.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-ethers.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,299 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +struct ether +{ + const char *e_name; + struct ether_addr e_addr; +}; + +/* Get the declaration of the parser function. */ +#define ENTNAME etherent +#define STRUCTURE ether +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +struct response +{ + char *val; + struct response *next; +}; + +static struct response *start = NULL; +static struct response *next = NULL; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (start == NULL) + { + start = malloc (sizeof (struct response)); + next = start; + } + else + { + next->next = malloc (sizeof (struct response)); + next = next->next; + } + next->next = NULL; + next->val = malloc (invallen + 1); + strncpy (next->val, inval, invallen); + next->val[invallen] = '\0'; + } + + return 0; +} + +enum nss_status +internal_nis_setetherent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + yp_get_default_domain (&domainname); + + while (start != NULL) + { + if (start->val != NULL) + free (start->val); + next = start; + start = start->next; + free (next); + } + start = NULL; + + ypcb.foreach = saveit; + ypcb.data = NULL; + status = yperr2nss (yp_all (domainname, "ethers.byname", &ypcb)); + next = start; + + return status; +} + +enum nss_status +_nss_nis_setetherent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_nis_setetherent (); + + __libc_lock_unlock (lock); + + return result; +} + +enum nss_status +_nss_nis_endetherent (void) +{ + __libc_lock_lock (lock); + + while (start != NULL) + { + if (start->val != NULL) + free (start->val); + next = start; + start = start->next; + free (next); + } + start = NULL; + next = NULL; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getetherent_r (struct ether *eth, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + + if (start == NULL) + internal_nis_setetherent (); + + /* Get the next entry until we found a correct one. */ + do + { + char *p; + + if (next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, next->val, buflen); + next = next->next; + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_etherent (p, eth, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getetherent_r (struct ether *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getetherent_r (result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_gethostton_r (const char *name, struct ether *eth, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + retval = yperr2nss (yp_match (domain, "ethers.byname", name, + strlen (name), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_etherent (p, eth, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getntohost_r (struct ether_addr *addr, struct ether *eth, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, nlen, parse_res; + char buf[33]; + + if (addr == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%x:%x:%x:%x:%x:%x", + (int) addr->ether_addr_octet[0], + (int) addr->ether_addr_octet[1], + (int) addr->ether_addr_octet[2], + (int) addr->ether_addr_octet[3], + (int) addr->ether_addr_octet[4], + (int) addr->ether_addr_octet[5]); + + retval = yperr2nss (yp_match (domain, "ethers.byaddr", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_etherent (p, eth, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-grp.c glibc-2.1.3/glibc-compat/nss_nis/nis-grp.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-grp.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-grp.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,249 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_setgrent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endgrent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain, *result, *outkey; + int len, keylen, parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *p; + + if (new_start) + retval = yperr2nss (yp_first (domain, "group.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "group.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_grent (p, grp, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getgrent_r (struct group *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getgrent_r (result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getgrnam_r (const char *name, struct group *grp, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + retval = yperr2nss (yp_match (domain, "group.byname", name, + strlen (name), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_grent (p, grp, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getgrgid_r (gid_t gid, struct group *grp, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, nlen, parse_res; + char buf[32]; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%d", gid); + + retval = yperr2nss (yp_match (domain, "group.bygid", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_grent (p, grp, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-hosts.c glibc-2.1.3/glibc-compat/nss_nis/nis-hosts.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-hosts.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-hosts.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,417 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get implementation for some internal functions. */ +#include "../../resolv/mapv4v6addr.h" +#include "../../resolv/mapv4v6hostent.h" + +#define ENTNAME hostent +#define DATABASE "hosts" +#define NEED_H_ERRNO + +#define ENTDATA hostent_data +struct hostent_data + { + unsigned char host_addr[16]; /* IPv4 or IPv6 address. */ + char *h_addr_ptrs[2]; /* Points to that and null terminator. */ + }; + +#define TRAILING_LIST_MEMBER h_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "../nss_files/files-parse.c" +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (addr, isspace, 1); + + /* Parse address. */ + if ((_res.options & RES_USE_INET6) + && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + { + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + if (inet_pton (AF_INET, addr, entdata->host_addr) > 0) + { + if (_res.options & RES_USE_INET6) + { + map_v4v6_address ((char *) entdata->host_addr, + (char *) entdata->host_addr); + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + { + result->h_addrtype = AF_INET; + result->h_length = INADDRSZ; + } + } + else + /* Illegal address: ignore line. */ + return 0; + + /* Store a pointer to the address in the expected form. */ + entdata->h_addr_ptrs[0] = entdata->host_addr; + entdata->h_addr_ptrs[1] = NULL; + result->h_addr_list = entdata->h_addr_ptrs; + + /* If we need the host entry in IPv6 form change it now. */ + if (_res.options & RES_USE_INET6) + { + char *bufptr = data->linebuffer; + size_t buflen = (char *) data + datalen - bufptr; + int ibuflen = buflen; /* Use this for machines with size_t > int. */ + map_v4v6_hostent (result, &bufptr, &ibuflen); + buflen = ibuflen; + } + + STRING_FIELD (result->h_name, isspace, 1); + } +) + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_sethostent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endhostent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_gethostent_r (struct hostent *host, char *buffer, + size_t buflen, int *h_errnop) +{ + char *domain; + char *result; + int len, parse_res; + char *outkey; + int keylen; + struct parser_data *data = (void *) buffer; + size_t linebuflen = buffer + buflen - data->linebuffer; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1) + { + __set_errno (ERANGE); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *p; + + if (new_start) + retval = yperr2nss (yp_first (domain, "hosts.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "hosts.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + switch (retval) + { + case NSS_STATUS_TRYAGAIN: + __set_errno (EAGAIN); + *h_errnop = TRY_AGAIN; + break; + case NSS_STATUS_NOTFOUND: + *h_errnop = HOST_NOT_FOUND; + break; + default: + *h_errnop = NO_RECOVERY; + break; + } + return retval; + } + + if ((size_t) (len + 1) > linebuflen) + { + free (result); + *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = parse_line (p, host, data, buflen); + if (parse_res == -1 && errno == ERANGE) + { + *h_errnop = NETDB_INTERNAL;; + return NSS_STATUS_TRYAGAIN; + } + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + +int +_nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen, + int *h_errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_gethostent_r (host, buffer, buflen, h_errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *h_errnop) +{ + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + struct parser_data *data = (void *) buffer; + size_t linebuflen = buffer + buflen - data->linebuffer; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1) + { + *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + /* Convert name to lowercase. */ + size_t namelen = strlen (name); + char name2[namelen + 1]; + int i; + + for (i = 0; i < namelen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + retval = yperr2nss (yp_match (domain, "hosts.byname", name2, + namelen, &result, &len)); + + } + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *h_errnop = TRY_AGAIN; + __set_errno (EAGAIN); + } + if (retval == NSS_STATUS_NOTFOUND) + *h_errnop = HOST_NOT_FOUND; + return retval; + } + + if ((size_t) (len + 1) > linebuflen) + { + free (result); + *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = parse_line (p, host, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res == 0 || host->h_addrtype != af) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_gethostbyname_r (const char *name, struct hostent *host, + char *buffer, size_t buflen, int *h_errnop) +{ + if (_res.options & RES_USE_INET6) + { + enum nss_status status; + + status = _nss_nis_gethostbyname2_r (name, AF_INET6, host, buffer, buflen, + h_errnop); + if (status == NSS_STATUS_SUCCESS) + return status; + } + + return _nss_nis_gethostbyname2_r (name, AF_INET, host, buffer, buflen, + h_errnop); +} + +enum nss_status +_nss_nis_gethostbyaddr_r (char *addr, int addrlen, int type, + struct hostent *host, char *buffer, size_t buflen, + int *h_errnop) +{ + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + char *buf; + struct parser_data *data = (void *) buffer; + size_t linebuflen = buffer + buflen - data->linebuffer; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1) + { + __set_errno (ERANGE); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + buf = inet_ntoa (*(struct in_addr *) addr); + + retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf, + strlen (buf), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *h_errnop = TRY_AGAIN; + __set_errno (EAGAIN); + } + if (retval == NSS_STATUS_NOTFOUND) + *h_errnop = HOST_NOT_FOUND; + return retval; + } + + if ((size_t) (len + 1) > linebuflen) + { + free (result); + __set_errno (ERANGE); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = parse_line (p, host, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else if (parse_res == 0) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-netgrp.c glibc-2.1.3/glibc-compat/nss_nis/nis-netgrp.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-netgrp.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-netgrp.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,128 @@ +/* Copyright (C) 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +static char *data = NULL; +static size_t data_size = 0; +static char *cursor = NULL;; + +extern enum nss_status +_nss_netgroup_parseline (char **cursor, struct __netgrent *result, + char *buffer, size_t buflen); + +enum nss_status +_nss_nis_setnetgrent (char *group) +{ + char *domain; + char *result; + int len, group_len; + enum nss_status status; + + status = NSS_STATUS_SUCCESS; + + if (group[0] == '\0') + return NSS_STATUS_UNAVAIL; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + __libc_lock_lock (lock); + + if (data != NULL) + { + free (data); + data = NULL; + data_size = 0; + cursor = NULL; + } + + group_len = strlen (group); + + status = yperr2nss (yp_match (domain, "netgroup", group, group_len, + &result, &len)); + if (status == NSS_STATUS_SUCCESS) + { + if (len > 0) + { + data = malloc (len + 1); + data_size = len; + cursor = strncpy (data, result, len + 1); + data[len] = '\0'; + free (result); + } + else + status = NSS_STATUS_NOTFOUND; + } + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_nis_endnetgrent (void) +{ + __libc_lock_lock (lock); + + if (data != NULL) + { + free (data); + data = NULL; + data_size = 0; + cursor = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen) +{ + enum nss_status status; + + if (cursor == NULL) + return NSS_STATUS_NOTFOUND; + + __libc_lock_lock (lock); + + status = _nss_netgroup_parseline (&cursor, result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-network.c glibc-2.1.3/glibc-compat/nss_nis/nis-network.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-network.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-network.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,318 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME netent +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_setnetent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endnetent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, + int *herrnop) +{ + struct parser_data *data = (void *) buffer; + char *domain, *result, *outkey; + int len, keylen, parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *p; + + if (new_start) + retval = yperr2nss (yp_first (domain, "networks.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "networks.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = NETDB_INTERNAL; + __set_errno (EAGAIN); + } + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_netent (p, net, data, buflen); + if (parse_res == -1 && errno == ERANGE) + { + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, + int *herrnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getnetent_r (net, buffer, buflen, herrnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getnetbyname_r (const char *name, struct netent *net, + char *buffer, size_t buflen, int *herrnop) +{ + enum nss_status retval; + struct parser_data *data = (void *) buffer; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1) + { + *herrnop = NETDB_INTERNAL; + __set_errno(ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + char name2[namlen + 1]; + int i; + + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + retval = yperr2nss (yp_match (domain, "networks.byname", name2, + namlen, &result, &len)); + } + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + __set_errno (EAGAIN); + *herrnop = NETDB_INTERNAL; + } + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_netent (p, net, data, buflen); + + if (parse_res <= 0) + { + *herrnop = NETDB_INTERNAL; + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetbyaddr_r (unsigned long addr, int type, struct netent *net, + char *buffer, size_t buflen, int *herrnop) +{ + struct parser_data *data = (void *) buffer; + char *domain; + char *result; + int len; + char buf[256]; + int blen; + struct in_addr in; + char *p; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + in = inet_makeaddr (addr, 0); + strcpy (buf, inet_ntoa (in)); + blen = strlen (buf); + + while (1) + { + enum nss_status retval; + int parse_res; + + retval = yperr2nss (yp_match (domain, "networks.byaddr", buf, + strlen (buf), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_NOTFOUND) + { + if (buf[blen - 2] == '.' && buf[blen - 1] == '0') + { + /* Try again, but with trailing dot(s) + removed (one by one) */ + buf[blen - 2] = '\0'; + blen -= 2; + continue; + } + else + return NSS_STATUS_NOTFOUND; + } + else + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_netent (p, net, data, buflen); + + + if (parse_res <= 0) + { + *herrnop = NETDB_INTERNAL; + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; + } +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-proto.c glibc-2.1.3/glibc-compat/nss_nis/nis-proto.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-proto.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-proto.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,280 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME protoent +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +__libc_lock_define_initialized (static, lock) + +struct response +{ + char *val; + struct response *next; +}; + +static struct response *start = NULL; +static struct response *next = NULL; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (start == NULL) + { + start = malloc (sizeof (struct response)); + next = start; + } + else + { + next->next = malloc (sizeof (struct response)); + next = next->next; + } + next->next = NULL; + next->val = malloc (invallen + 1); + strncpy (next->val, inval, invallen); + next->val[invallen] = '\0'; + } + + return 0; +} + +enum nss_status +internal_nis_setprotoent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + yp_get_default_domain (&domainname); + + while (start != NULL) + { + if (start->val != NULL) + free (start->val); + next = start; + start = start->next; + free (next); + } + start = NULL; + + ypcb.foreach = saveit; + ypcb.data = NULL; + status = yperr2nss (yp_all (domainname, "protocols.bynumber", &ypcb)); + next = start; + + return status; +} + +enum nss_status +_nss_nis_setprotoent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setprotoent (); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_endprotoent (void) +{ + __libc_lock_lock (lock); + + while (start != NULL) + { + if (start->val != NULL) + free (start->val); + next = start; + start = start->next; + free (next); + } + start = NULL; + next = NULL; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getprotoent_r (struct protoent *proto, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + + if (start == NULL) + internal_nis_setprotoent (); + + /* Get the next entry until we found a correct one. */ + do + { + char *p; + + if (next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, next->val, buflen); + next = next->next; + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_protoent (p, proto, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getprotoent_r (struct protoent *proto, char *buffer, size_t buflen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getprotoent_r (proto, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getprotobyname_r (const char *name, struct protoent *proto, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + retval = yperr2nss (yp_match (domain, "protocols.byname", name, + strlen (name), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_protoent (p, proto, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getprotobynumber_r (int number, struct protoent *proto, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, nlen, parse_res; + char buf[32]; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%d", number); + + retval = yperr2nss (yp_match (domain, "protocols.bynumber", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_protoent (p, proto, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-pwd.c glibc-2.1.3/glibc-compat/nss_nis/nis-pwd.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-pwd.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-pwd.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,407 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME pwent +#define STRUCTURE passwd +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_setpwent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endpwent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain; + int parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *result, *outkey, *result2, *p; + int len, keylen, len2; + size_t namelen; + + if (new_start) + retval = yperr2nss (yp_first (domain, "passwd.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "passwd.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + /* Check for adjunct style secret passwords. They can be + recognized by a password starting with "##". */ + p = strchr (result, ':'); + if (p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && (namelen = p - result, + yp_match (domain, "passwd.adjunct.byname", result, namelen, + &result2, &len2)) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct entry. Merge encrypted + password therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp, *tmp; + size_t restlen; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + restlen = len - (p - result); + if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + { + free (result2); + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + memcpy (buffer, result, namelen); + tmp = buffer + namelen; + *tmp++ = ':'; + memcpy (tmp, encrypted, endp - encrypted); + tmp += endp - encrypted; + memcpy (tmp, p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_pwent (p, pwd, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getpwent_r (result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getpwnam_r (const char *name, struct passwd *pwd, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *result2, *p; + int len, len2, parse_res; + size_t namelen; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + namelen = strlen (name); + + retval = yperr2nss (yp_match (domain, "passwd.byname", name, + namelen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + /* Check for adjunct style secret passwords. They can be recognized + by a password starting with "##". */ + p = strchr (result, ':'); + if (p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && (namelen = p - result, + yp_match (domain, "passwd.adjunct.byname", name, namelen, + &result2, &len2)) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct entry. Merge encrypted password + therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp, *tmp; + size_t restlen; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + restlen = len - (p - result); + if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + { + free (result2); + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + memcpy (buffer, name, namelen); + tmp = buffer + namelen; + *tmp++ = ':'; + memcpy (tmp, encrypted, endp - encrypted); + tmp += endp - encrypted; + memcpy (tmp, p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_pwent (p, pwd, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p, *result2; + int len, nlen, parse_res, len2; + char buf[32]; + size_t namelen; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%d", uid); + + retval = yperr2nss (yp_match (domain, "passwd.byuid", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + /* Check for adjunct style secret passwords. They can be recognized + by a password starting with "##". */ + p = strchr (result, ':'); + if (p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && (namelen = p - result, + yp_match (domain, "passwd.adjunct.byname", result, namelen, + &result2, &len2)) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct entry. Merge encrypted password + therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp, *tmp; + size_t restlen; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + restlen = len - (p - result); + if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + { + free (result2); + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + memcpy (buffer, result, namelen); + tmp = buffer + namelen; + *tmp++ = ':'; + memcpy (tmp, encrypted, endp - encrypted); + tmp += endp - encrypted; + memcpy (tmp, p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_pwent (p, pwd, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-rpc.c glibc-2.1.3/glibc-compat/nss_nis/nis-rpc.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-rpc.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-rpc.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,295 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME rpcent +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +__libc_lock_define_initialized (static, lock) + +struct response_t +{ + char *val; + struct response_t *next; +}; + +struct intern_t +{ + struct response_t *start; + struct response_t *next; +}; +typedef struct intern_t intern_t; + +static intern_t intern = {NULL, NULL}; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + intern_t *intern = (intern_t *)indata; + + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (intern->start == NULL) + { + intern->start = malloc (sizeof (struct response_t)); + intern->next = intern->start; + } + else + { + intern->next->next = malloc (sizeof (struct response_t)); + intern->next = intern->next->next; + } + intern->next->next = NULL; + intern->next->val = malloc (invallen + 1); + strncpy (intern->next->val, inval, invallen); + intern->next->val[invallen] = '\0'; + } + + return 0; +} + +static enum nss_status +internal_nis_setrpcent (intern_t *intern) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + while (intern->start != NULL) + { + if (intern->start->val != NULL) + free (intern->start->val); + intern->next = intern->start; + intern->start = intern->start->next; + free (intern->next); + } + intern->start = NULL; + + ypcb.foreach = saveit; + ypcb.data = (char *)intern; + status = yperr2nss (yp_all(domainname, "rpc.bynumber", &ypcb)); + intern->next = intern->start; + + return status; +} + +enum nss_status +_nss_nis_setrpcent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setrpcent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_endrpcent (intern_t *intern) +{ + while (intern->start != NULL) + { + if (intern->start->val != NULL) + free (intern->start->val); + intern->next = intern->start; + intern->start = intern->start->next; + free (intern->next); + } + intern->start = NULL; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endrpcent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_endrpcent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen, + intern_t *data) +{ + struct parser_data *pdata = (void *) buffer; + int parse_res; + char *p; + + if (data->start == NULL) + internal_nis_setrpcent (data); + + /* Get the next entry until we found a correct one. */ + do + { + if (data->next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, data->next->val, buflen); + data->next = data->next->next; + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getrpcent_r (rpc, buffer, buflen, &intern); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc, + char *buffer, size_t buflen) +{ + intern_t data = {NULL, NULL}; + enum nss_status status; + int found; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + status = internal_nis_setrpcent (&data); + if (status != NSS_STATUS_SUCCESS) + return status; + + found = 0; + while (!found && + ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, &data)) + == NSS_STATUS_SUCCESS)) + { + if (strcmp (rpc->r_name, name) == 0) + found = 1; + else + { + int i = 0; + + while (rpc->r_aliases[i] != NULL) + { + if (strcmp (rpc->r_aliases[i], name) == 0) + { + found = 1; + break; + } + else + ++i; + } + } + } + + internal_nis_endrpcent (&data); + + if (!found && status == NSS_STATUS_SUCCESS) + return NSS_STATUS_NOTFOUND; + else + return status; +} + +enum nss_status +_nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, nlen, parse_res; + char buf[32]; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%d", number); + + retval = yperr2nss (yp_match (domain, "rpc.bynumber", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_rpcent (p, rpc, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-service.c glibc-2.1.3/glibc-compat/nss_nis/nis-service.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-service.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-service.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,280 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME servent +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +__libc_lock_define_initialized (static, lock) + +struct response_t +{ + char *val; + struct response_t *next; +}; + +struct intern_t +{ + struct response_t *start; + struct response_t *next; +}; +typedef struct intern_t intern_t; + +static intern_t intern = { NULL, NULL }; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + intern_t *intern = (intern_t *) indata; + + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (intern->start == NULL) + { + intern->start = malloc (sizeof (struct response_t)); + intern->next = intern->start; + } + else + { + intern->next->next = malloc (sizeof (struct response_t)); + intern->next = intern->next->next; + } + intern->next->next = NULL; + intern->next->val = malloc (invallen + 1); + strncpy (intern->next->val, inval, invallen); + intern->next->val[invallen] = '\0'; + } + + return 0; +} + +static enum nss_status +internal_nis_setservent (intern_t *intern) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + while (intern->start != NULL) + { + if (intern->start->val != NULL) + free (intern->start->val); + intern->next = intern->start; + intern->start = intern->start->next; + free (intern->next); + } + intern->start = NULL; + + ypcb.foreach = saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); + intern->next = intern->start; + + return status; +} +enum nss_status +_nss_nis_setservent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setservent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_endservent (intern_t * intern) +{ + while (intern->start != NULL) + { + if (intern->start->val != NULL) + free (intern->start->val); + intern->next = intern->start; + intern->start = intern->start->next; + free (intern->next); + } + intern->start = NULL; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endservent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_endservent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_getservent_r (struct servent *serv, char *buffer, + size_t buflen, intern_t *data) +{ + struct parser_data *pdata = (void *) buffer; + int parse_res; + char *p; + + if (data->start == NULL) + internal_nis_setservent (data); + + /* Get the next entry until we found a correct one. */ + do + { + if (data->next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, data->next->val, buflen); + data->next = data->next->next; + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_servent (p, serv, pdata, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getservent_r (serv, buffer, buflen, &intern); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getservbyname_r (const char *name, char *protocol, + struct servent *serv, char *buffer, size_t buflen) +{ + intern_t data = { NULL, NULL }; + enum nss_status status; + int found; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + status = internal_nis_setservent (&data); + if (status != NSS_STATUS_SUCCESS) + return status; + + found = 0; + while (!found && + ((status = internal_nis_getservent_r (serv, buffer, buflen, &data)) + == NSS_STATUS_SUCCESS)) + { + if (protocol == NULL || strcmp (serv->s_proto, protocol) == 0) + { + char **cp; + + if (strcmp (serv->s_name, name) == 0) + found = 1; + else + for (cp = serv->s_aliases; *cp; cp++) + if (strcmp (name, *cp) == 0) + found = 1; + } + } + + internal_nis_endservent (&data); + + if (!found && status == NSS_STATUS_SUCCESS) + return NSS_STATUS_NOTFOUND; + else + return status; +} + +enum nss_status +_nss_nis_getservbyport_r (int port, char *protocol, struct servent *serv, + char *buffer, size_t buflen) +{ + intern_t data = { NULL, NULL }; + enum nss_status status; + int found; + + if (protocol == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + status = internal_nis_setservent (&data); + if (status != NSS_STATUS_SUCCESS) + return status; + + found = 0; + while (!found && + ((status = internal_nis_getservent_r (serv, buffer, buflen, &data)) + == NSS_STATUS_SUCCESS)) + { + if (htons (serv->s_port) == port) + { + if (strcmp (serv->s_proto, protocol) == 0) + { + found = 1; + } + } + } + + internal_nis_endservent (&data); + + if (!found && status == NSS_STATUS_SUCCESS) + return NSS_STATUS_NOTFOUND; + else + return status; +} diff -Naur ../glibc-2.1.3/glibc-compat/nss_nis/nis-spwd.c glibc-2.1.3/glibc-compat/nss_nis/nis-spwd.c --- ../glibc-2.1.3/glibc-compat/nss_nis/nis-spwd.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/nss_nis/nis-spwd.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,201 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME spent +#define STRUCTURE spwd +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_setspent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endspent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain, *result, *outkey; + int len, keylen, parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *p; + + if (new_start) + retval = yperr2nss (yp_first (domain, "shadow.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "shadow.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_spent (p, sp, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getspent_r (struct spwd *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getspent_r (result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getspnam_r (const char *name, struct spwd *sp, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + retval = yperr2nss (yp_match (domain, "shadow.byname", name, + strlen (name), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_spent (p, sp, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff -Naur ../glibc-2.1.3/glibc-compat/oldfileops.c glibc-2.1.3/glibc-compat/oldfileops.c --- ../glibc-2.1.3/glibc-compat/oldfileops.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/oldfileops.c 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,774 @@ +/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + Written by Per Bothner . + + This library 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, or (at + your option) any later version. + + This library 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 library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +/* This is a compatibility file. If we don't build the libc with + versioning don't compile this file. */ + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" +#include +#include +#include +#include +#include +#ifndef errno +extern int errno; +#endif +#ifndef __set_errno +# define __set_errno(Val) errno = (Val) +#endif + + +#ifdef _LIBC +# define open(Name, Flags, Prot) __open (Name, Flags, Prot) +# define close(FD) __close (FD) +# define lseek(FD, Offset, Whence) __lseek (FD, Offset, Whence) +# define read(FD, Buf, NBytes) __read (FD, Buf, NBytes) +# define write(FD, Buf, NBytes) __write (FD, Buf, NBytes) +#endif + +/* An fstream can be in at most one of put mode, get mode, or putback mode. + Putback mode is a variant of get mode. + + In a filebuf, there is only one current position, instead of two + separate get and put pointers. In get mode, the current position + is that of gptr(); in put mode that of pptr(). + + The position in the buffer that corresponds to the position + in external file system is normally _IO_read_end, except in putback + mode, when it is _IO_save_end. + If the field _fb._offset is >= 0, it gives the offset in + the file as a whole corresponding to eGptr(). (?) + + PUT MODE: + If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end, + and _IO_read_base are equal to each other. These are usually equal + to _IO_buf_base, though not necessarily if we have switched from + get mode to put mode. (The reason is to maintain the invariant + that _IO_read_end corresponds to the external file position.) + _IO_write_base is non-NULL and usually equal to _IO_base_base. + We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode. + The un-flushed character are those between _IO_write_base and _IO_write_ptr. + + GET MODE: + If a filebuf is in get or putback mode, eback() != egptr(). + In get mode, the unread characters are between gptr() and egptr(). + The OS file position corresponds to that of egptr(). + + PUTBACK MODE: + Putback mode is used to remember "excess" characters that have + been sputbackc'd in a separate putback buffer. + In putback mode, the get buffer points to the special putback buffer. + The unread characters are the characters between gptr() and egptr() + in the putback buffer, as well as the area between save_gptr() + and save_egptr(), which point into the original reserve buffer. + (The pointers save_gptr() and save_egptr() are the values + of gptr() and egptr() at the time putback mode was entered.) + The OS position corresponds to that of save_egptr(). + + LINE BUFFERED OUTPUT: + During line buffered output, _IO_write_base==base() && epptr()==base(). + However, ptr() may be anywhere between base() and ebuf(). + This forces a call to filebuf::overflow(int C) on every put. + If there is more space in the buffer, and C is not a '\n', + then C is inserted, and pptr() incremented. + + UNBUFFERED STREAMS: + If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer. +*/ + +#define CLOSED_FILEBUF_FLAGS \ + (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET) + + +void +_IO_old_file_init (fp) + _IO_FILE *fp; +{ + /* POSIX.1 allows another file handle to be used to change the position + of our file descriptor. Hence we actually don't know the actual + position before we do the first fseek (and until a following fflush). */ + fp->_old_offset = _IO_pos_BAD; + fp->_IO_file_flags |= CLOSED_FILEBUF_FLAGS; + + _IO_link_in(fp); + fp->_vtable_offset = ((int) sizeof (struct _IO_FILE) + - (int) sizeof (struct _IO_FILE_complete)); + fp->_fileno = -1; +} + +int +_IO_old_file_close_it (fp) + _IO_FILE *fp; +{ + int write_status, close_status; + if (!_IO_file_is_open (fp)) + return EOF; + + write_status = _IO_old_do_flush (fp); + + _IO_unsave_markers(fp); + + close_status = _IO_SYSCLOSE (fp); + + /* Free buffer. */ + _IO_setb (fp, NULL, NULL, 0); + _IO_setg (fp, NULL, NULL, NULL); + _IO_setp (fp, NULL, NULL); + + _IO_un_link (fp); + fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS; + fp->_fileno = EOF; + fp->_old_offset = _IO_pos_BAD; + + return close_status ? close_status : write_status; +} + +void +_IO_old_file_finish (fp, dummy) + _IO_FILE *fp; + int dummy; +{ + if (_IO_file_is_open (fp)) + { + _IO_old_do_flush (fp); + if (!(fp->_flags & _IO_DELETE_DONT_CLOSE)) + _IO_SYSCLOSE (fp); + } + _IO_default_finish (fp, 0); +} + +_IO_FILE * +_IO_old_file_fopen (fp, filename, mode) + _IO_FILE *fp; + const char *filename; + const char *mode; +{ + int oflags = 0, omode; + int read_write, fdesc; + int oprot = 0666; + if (_IO_file_is_open (fp)) + return 0; + switch (*mode++) + { + case 'r': + omode = O_RDONLY; + read_write = _IO_NO_WRITES; + break; + case 'w': + omode = O_WRONLY; + oflags = O_CREAT|O_TRUNC; + read_write = _IO_NO_READS; + break; + case 'a': + omode = O_WRONLY; + oflags = O_CREAT|O_APPEND; + read_write = _IO_NO_READS|_IO_IS_APPENDING; + break; + default: + __set_errno (EINVAL); + return NULL; + } + if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+')) + { + omode = O_RDWR; + read_write &= _IO_IS_APPENDING; + } + fdesc = open (filename, omode|oflags, oprot); + if (fdesc < 0) + return NULL; + fp->_fileno = fdesc; + _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); + if (read_write & _IO_IS_APPENDING) + if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT) + == _IO_pos_BAD && errno != ESPIPE) + return NULL; + _IO_link_in (fp); + return fp; +} + +_IO_FILE * +_IO_old_file_attach (fp, fd) + _IO_FILE *fp; + int fd; +{ + if (_IO_file_is_open (fp)) + return NULL; + fp->_fileno = fd; + fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES); + fp->_flags |= _IO_DELETE_DONT_CLOSE; + /* Get the current position of the file. */ + /* We have to do that since that may be junk. */ + fp->_old_offset = _IO_pos_BAD; + if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT) + == _IO_pos_BAD && errno != ESPIPE) + return NULL; + return fp; +} + +_IO_FILE * +_IO_old_file_setbuf (fp, p, len) + _IO_FILE *fp; + char *p; + _IO_ssize_t len; +{ + if (_IO_default_setbuf (fp, p, len) == NULL) + return NULL; + + fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end + = fp->_IO_buf_base; + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + + return fp; +} + +static int old_do_write __P ((_IO_FILE *, const char *, _IO_size_t)); + +/* Write TO_DO bytes from DATA to FP. + Then mark FP as having empty buffers. */ + +int +_IO_old_do_write (fp, data, to_do) + _IO_FILE *fp; + const char *data; + _IO_size_t to_do; +{ + return (to_do == 0 || old_do_write (fp, data, to_do) == to_do) + ? 0 : EOF; +} + +static +int +old_do_write (fp, data, to_do) + _IO_FILE *fp; + const char *data; + _IO_size_t to_do; +{ + _IO_size_t count; + if (fp->_flags & _IO_IS_APPENDING) + /* On a system without a proper O_APPEND implementation, + you would need to sys_seek(0, SEEK_END) here, but is + is not needed nor desirable for Unix- or Posix-like systems. + Instead, just indicate that offset (before and after) is + unpredictable. */ + fp->_old_offset = _IO_pos_BAD; + else if (fp->_IO_read_end != fp->_IO_write_base) + { + _IO_pos_t new_pos + = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1); + if (new_pos == _IO_pos_BAD) + return 0; + fp->_old_offset = new_pos; + } + count = _IO_SYSWRITE (fp, data, to_do); + if (fp->_cur_column && count) + fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1; + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base; + fp->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) + ? fp->_IO_buf_base : fp->_IO_buf_end); + return count; +} + +int +_IO_old_file_underflow (fp) + _IO_FILE *fp; +{ + _IO_ssize_t count; +#if 0 + /* SysV does not make this test; take it out for compatibility */ + if (fp->_flags & _IO_EOF_SEEN) + return (EOF); +#endif + + if (fp->_flags & _IO_NO_READS) + { + __set_errno (EBADF); + return EOF; + } + if (fp->_IO_read_ptr < fp->_IO_read_end) + return *(unsigned char *) fp->_IO_read_ptr; + + if (fp->_IO_buf_base == NULL) + _IO_doallocbuf (fp); + + /* Flush all line buffered files before reading. */ + /* FIXME This can/should be moved to genops ?? */ + if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) + _IO_flush_all_linebuffered (); + + _IO_switch_to_get_mode (fp); + + /* This is very tricky. We have to adjust those + pointers before we call _IO_SYSREAD () since + we may longjump () out while waiting for + input. Those pointers may be screwed up. H.J. */ + fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base; + fp->_IO_read_end = fp->_IO_buf_base; + fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end + = fp->_IO_buf_base; + + count = _IO_SYSREAD (fp, fp->_IO_buf_base, + fp->_IO_buf_end - fp->_IO_buf_base); + if (count <= 0) + { + if (count == 0) + fp->_flags |= _IO_EOF_SEEN; + else + fp->_flags |= _IO_ERR_SEEN, count = 0; + } + fp->_IO_read_end += count; + if (count == 0) + return EOF; + if (fp->_old_offset != _IO_pos_BAD) + _IO_pos_adjust (fp->_old_offset, count); + return *(unsigned char *) fp->_IO_read_ptr; +} + +int +_IO_old_file_overflow (f, ch) + _IO_FILE *f; + int ch; +{ + if (f->_flags & _IO_NO_WRITES) /* SET ERROR */ + { + f->_flags |= _IO_ERR_SEEN; + __set_errno (EBADF); + return EOF; + } + /* If currently reading or no buffer allocated. */ + if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0) + { + /* Allocate a buffer if needed. */ + if (f->_IO_write_base == 0) + { + _IO_doallocbuf (f); + _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); + } + /* Otherwise must be currently reading. + If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end, + logically slide the buffer forwards one block (by setting the + read pointers to all point at the beginning of the block). This + makes room for subsequent output. + Otherwise, set the read pointers to _IO_read_end (leaving that + alone, so it can continue to correspond to the external position). */ + if (f->_IO_read_ptr == f->_IO_buf_end) + f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base; + f->_IO_write_ptr = f->_IO_read_ptr; + f->_IO_write_base = f->_IO_write_ptr; + f->_IO_write_end = f->_IO_buf_end; + f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end; + + if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) + f->_IO_write_end = f->_IO_write_ptr; + f->_flags |= _IO_CURRENTLY_PUTTING; + } + if (ch == EOF) + return _IO_old_do_flush (f); + if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */ + if (_IO_old_do_flush (f) == EOF) + return EOF; + *f->_IO_write_ptr++ = ch; + if ((f->_flags & _IO_UNBUFFERED) + || ((f->_flags & _IO_LINE_BUF) && ch == '\n')) + if (_IO_old_do_flush (f) == EOF) + return EOF; + return (unsigned char) ch; +} + +int +_IO_old_file_sync (fp) + _IO_FILE *fp; +{ + _IO_size_t delta; + int retval = 0; + + _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp); + _IO_flockfile (fp); + /* char* ptr = cur_ptr(); */ + if (fp->_IO_write_ptr > fp->_IO_write_base) + if (_IO_old_do_flush(fp)) return EOF; + delta = fp->_IO_read_ptr - fp->_IO_read_end; + if (delta != 0) + { +#ifdef TODO + if (_IO_in_backup (fp)) + delta -= eGptr () - Gbase (); +#endif + _IO_off_t new_pos = _IO_SYSSEEK (fp, delta, 1); + if (new_pos != (_IO_off_t) EOF) + fp->_IO_read_end = fp->_IO_read_ptr; +#ifdef ESPIPE + else if (errno == ESPIPE) + ; /* Ignore error from unseekable devices. */ +#endif + else + retval = EOF; + } + if (retval != EOF) + fp->_old_offset = _IO_pos_BAD; + /* FIXME: Cleanup - can this be shared? */ + /* setg(base(), ptr, ptr); */ + _IO_funlockfile (fp); + _IO_cleanup_region_end (0); + return retval; +} + +_IO_fpos64_t +_IO_old_file_seekoff (fp, offset, dir, mode) + _IO_FILE *fp; + _IO_off64_t offset; + int dir; + int mode; +{ + _IO_pos_t result; + _IO_off64_t delta, new_offset; + long count; + /* POSIX.1 8.2.3.7 says that after a call the fflush() the file + offset of the underlying file must be exact. */ + int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end + && fp->_IO_write_base == fp->_IO_write_ptr); + + if (mode == 0) + dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ + + /* Flush unwritten characters. + (This may do an unneeded write if we seek within the buffer. + But to be able to switch to reading, we would need to set + egptr to ptr. That can't be done in the current design, + which assumes file_ptr() is eGptr. Anyway, since we probably + end up flushing when we close(), it doesn't make much difference.) + FIXME: simulate mem-papped files. */ + + if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp)) + if (_IO_switch_to_get_mode (fp)) + return EOF; + + if (fp->_IO_buf_base == NULL) + { + _IO_doallocbuf (fp); + _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + } + + switch (dir) + { + case _IO_seek_cur: + /* Adjust for read-ahead (bytes is buffer). */ + offset -= fp->_IO_read_end - fp->_IO_read_ptr; + if (fp->_old_offset == _IO_pos_BAD) + goto dumb; + /* Make offset absolute, assuming current pointer is file_ptr(). */ + offset += _IO_pos_as_off (fp->_old_offset); + + dir = _IO_seek_set; + break; + case _IO_seek_set: + break; + case _IO_seek_end: + { + struct _G_stat64 st; + if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode)) + { + offset += st.st_size; + dir = _IO_seek_set; + } + else + goto dumb; + } + } + /* At this point, dir==_IO_seek_set. */ + + /* If destination is within current buffer, optimize: */ + if (fp->_old_offset != _IO_pos_BAD && fp->_IO_read_base != NULL + && !_IO_in_backup (fp)) + { + /* Offset relative to start of main get area. */ + _IO_pos_t rel_offset = (offset - fp->_old_offset + + (fp->_IO_read_end - fp->_IO_read_base)); + if (rel_offset >= 0) + { +#if 0 + if (_IO_in_backup (fp)) + _IO_switch_to_main_get_area (fp); +#endif + if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base) + { + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset, + fp->_IO_read_end); + _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); + goto resync; + } +#ifdef TODO + /* If we have streammarkers, seek forward by reading ahead. */ + if (_IO_have_markers (fp)) + { + int to_skip = rel_offset + - (fp->_IO_read_ptr - fp->_IO_read_base); + if (ignore (to_skip) != to_skip) + goto dumb; + goto resync; + } +#endif + } +#ifdef TODO + if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ()) + { + if (!_IO_in_backup (fp)) + _IO_switch_to_backup_area (fp); + gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr); + goto resync; + } +#endif + } + +#ifdef TODO + _IO_unsave_markers (fp); +#endif + + if (fp->_flags & _IO_NO_READS) + goto dumb; + + /* Try to seek to a block boundary, to improve kernel page management. */ + new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1); + delta = offset - new_offset; + if (delta > fp->_IO_buf_end - fp->_IO_buf_base) + { + new_offset = offset; + delta = 0; + } + result = _IO_SYSSEEK (fp, new_offset, 0); + if (result < 0) + return EOF; + if (delta == 0) + count = 0; + else + { + count = _IO_SYSREAD (fp, fp->_IO_buf_base, + (must_be_exact + ? delta : fp->_IO_buf_end - fp->_IO_buf_base)); + if (count < delta) + { + /* We weren't allowed to read, but try to seek the remainder. */ + offset = count == EOF ? delta : delta-count; + dir = _IO_seek_cur; + goto dumb; + } + } + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta, + fp->_IO_buf_base + count); + _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); + fp->_old_offset = result + count; + _IO_mask_flags (fp, 0, _IO_EOF_SEEN); + return offset; + dumb: + + _IO_unsave_markers (fp); + result = _IO_SYSSEEK (fp, offset, dir); + if (result != EOF) + { + _IO_mask_flags (fp, 0, _IO_EOF_SEEN); + fp->_old_offset = result; + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); + } + return result; + +resync: + /* We need to do it since it is possible that the file offset in + the kernel may be changed behind our back. It may happen when + we fopen a file and then do a fork. One process may access the + the file and the kernel file offset will be changed. */ + if (fp->_old_offset >= 0) + _IO_SYSSEEK (fp, fp->_old_offset, 0); + + return offset; +} + +_IO_ssize_t +_IO_old_file_write (f, data, n) + _IO_FILE *f; + const void *data; + _IO_ssize_t n; +{ + _IO_ssize_t to_do = n; + while (to_do > 0) + { + _IO_ssize_t count = write (f->_fileno, data, to_do); + if (count == EOF) + { + f->_flags |= _IO_ERR_SEEN; + break; + } + to_do -= count; + data = (void *) ((char *) data + count); + } + n -= to_do; + if (f->_old_offset >= 0) + f->_old_offset += n; + return n; +} + +_IO_size_t +_IO_old_file_xsputn (f, data, n) + _IO_FILE *f; + const void *data; + _IO_size_t n; +{ + register const char *s = (char *) data; + _IO_size_t to_do = n; + int must_flush = 0; + _IO_size_t count; + + if (n <= 0) + return 0; + /* This is an optimized implementation. + If the amount to be written straddles a block boundary + (or the filebuf is unbuffered), use sys_write directly. */ + + /* First figure out how much space is available in the buffer. */ + count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */ + if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) + { + count = f->_IO_buf_end - f->_IO_write_ptr; + if (count >= n) + { + register const char *p; + for (p = s + n; p > s; ) + { + if (*--p == '\n') + { + count = p - s + 1; + must_flush = 1; + break; + } + } + } + } + /* Then fill the buffer. */ + if (count > 0) + { + if (count > to_do) + count = to_do; + if (count > 20) + { + memcpy (f->_IO_write_ptr, s, count); + s += count; + } + else + { + register char *p = f->_IO_write_ptr; + register int i = (int) count; + while (--i >= 0) + *p++ = *s++; + } + f->_IO_write_ptr += count; + to_do -= count; + } + if (to_do + must_flush > 0) + { + _IO_size_t block_size, do_write; + /* Next flush the (full) buffer. */ + if (__overflow (f, EOF) == EOF) + return n - to_do; + + /* Try to maintain alignment: write a whole number of blocks. + dont_write is what gets left over. */ + block_size = f->_IO_buf_end - f->_IO_buf_base; + do_write = to_do - (block_size >= 128 ? to_do % block_size : 0); + + if (do_write) + { + count = old_do_write (f, s, do_write); + to_do -= count; + if (count < do_write) + return n - to_do; + } + + /* Now write out the remainder. Normally, this will fit in the + buffer, but it's somewhat messier for line-buffered files, + so we let _IO_default_xsputn handle the general case. */ + if (to_do) + to_do -= _IO_default_xsputn (f, s+do_write, to_do); + } + return n - to_do; +} + + +struct _IO_jump_t _IO_old_file_jumps = +{ + JUMP_INIT_DUMMY, + JUMP_INIT(finish, _IO_old_file_finish), + JUMP_INIT(overflow, _IO_old_file_overflow), + JUMP_INIT(underflow, _IO_old_file_underflow), + JUMP_INIT(uflow, _IO_default_uflow), + JUMP_INIT(pbackfail, _IO_default_pbackfail), + JUMP_INIT(xsputn, _IO_old_file_xsputn), + JUMP_INIT(xsgetn, _IO_default_xsgetn), + JUMP_INIT(seekoff, _IO_old_file_seekoff), + JUMP_INIT(seekpos, _IO_default_seekpos), + JUMP_INIT(setbuf, _IO_old_file_setbuf), + JUMP_INIT(sync, _IO_old_file_sync), + JUMP_INIT(doallocate, _IO_file_doallocate), + JUMP_INIT(read, _IO_file_read), + JUMP_INIT(write, _IO_old_file_write), + JUMP_INIT(seek, _IO_file_seek), + JUMP_INIT(close, _IO_file_close), + JUMP_INIT(stat, _IO_file_stat) +}; + +#ifdef SHARED +symbol_version (_IO_old_do_write, _IO_do_write, GLIBC_2.0); +symbol_version (_IO_old_file_attach, _IO_file_attach, GLIBC_2.0); +symbol_version (_IO_old_file_close_it, _IO_file_close_it, GLIBC_2.0); +symbol_version (_IO_old_file_finish, _IO_file_finish, GLIBC_2.0); +symbol_version (_IO_old_file_fopen, _IO_file_fopen, GLIBC_2.0); +symbol_version (_IO_old_file_init, _IO_file_init, GLIBC_2.0); +symbol_version (_IO_old_file_setbuf, _IO_file_setbuf, GLIBC_2.0); +symbol_version (_IO_old_file_sync, _IO_file_sync, GLIBC_2.0); +symbol_version (_IO_old_file_overflow, _IO_file_overflow, GLIBC_2.0); +symbol_version (_IO_old_file_seekoff, _IO_file_seekoff, GLIBC_2.0); +symbol_version (_IO_old_file_underflow, _IO_file_underflow, GLIBC_2.0); +symbol_version (_IO_old_file_write, _IO_file_write, GLIBC_2.0); +symbol_version (_IO_old_file_xsputn, _IO_file_xsputn, GLIBC_2.0); +#else +strong_alias (_IO_old_do_write, _IO_do_write); +strong_alias (_IO_old_file_attach, _IO_file_attach); +strong_alias (_IO_old_file_close_it, _IO_file_close_it); +strong_alias (_IO_old_file_finish, _IO_file_finish); +strong_alias (_IO_old_file_fopen, _IO_file_fopen); +strong_alias (_IO_old_file_init, _IO_file_init); +strong_alias (_IO_old_file_setbuf, _IO_file_setbuf); +strong_alias (_IO_old_file_sync, _IO_file_sync); +strong_alias (_IO_old_file_overflow, _IO_file_overflow); +strong_alias (_IO_old_file_seekoff, _IO_file_seekoff); +strong_alias (_IO_old_file_underflow, _IO_file_underflow); +strong_alias (_IO_old_file_write, _IO_file_write); +strong_alias (_IO_old_file_xsputn, _IO_file_xsputn); +#endif diff -Naur ../glibc-2.1.3/glibc-compat/oldiofclose.c glibc-2.1.3/glibc-compat/oldiofclose.c --- ../glibc-2.1.3/glibc-compat/oldiofclose.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/oldiofclose.c 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,60 @@ +/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library 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, or (at + your option) any later version. + + This library 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 library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" +#ifdef __STDC__ +#include +#endif + +int +_IO_old_fclose (fp) + _IO_FILE *fp; +{ + int status; + + CHECK_FILE(fp, EOF); + + _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp); + _IO_flockfile (fp); + if (fp->_IO_file_flags & _IO_IS_FILEBUF) + status = _IO_old_file_close_it (fp); + else + status = fp->_flags & _IO_ERR_SEEN ? -1 : 0; + _IO_FINISH (fp); + _IO_funlockfile (fp); + _IO_cleanup_region_end (0); + if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr) + { + fp->_IO_file_flags = 0; + free(fp); + } + + return status; +} + +strong_alias (_IO_old_fclose, __old_fclose) +symbol_version (_IO_old_fclose, _IO_fclose, GLIBC_2.0); +symbol_version (__old_fclose, fclose, GLIBC_2.0); diff -Naur ../glibc-2.1.3/glibc-compat/oldiofdopen.c glibc-2.1.3/glibc-compat/oldiofdopen.c --- ../glibc-2.1.3/glibc-compat/oldiofdopen.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/oldiofdopen.c 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,140 @@ +/* Copyright (C) 1993, 1994, 1997 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library 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, or (at + your option) any later version. + + This library 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 library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#ifdef __STDC__ +# include +#endif +#include "libioP.h" +#include + +#ifndef _IO_fcntl +# define _IO_fcntl __fcntl +#endif + +_IO_FILE * +_IO_old_fdopen (fd, mode) + int fd; + const char *mode; +{ + int read_write; + int posix_mode = 0; + struct locked_FILE + { + struct _IO_FILE_plus fp; +#ifdef _IO_MTSAFE_IO + _IO_lock_t lock; +#endif + } *new_f; + int fd_flags; + + switch (*mode++) + { + case 'r': + read_write = _IO_NO_WRITES; + break; + case 'w': + read_write = _IO_NO_READS; + break; + case 'a': + posix_mode = O_APPEND; + read_write = _IO_NO_READS|_IO_IS_APPENDING; + break; + default: + MAYBE_SET_EINVAL; + return NULL; + } + if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+')) + read_write &= _IO_IS_APPENDING; +#ifdef F_GETFL + fd_flags = _IO_fcntl (fd, F_GETFL); +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) +#endif + if (fd_flags == -1 + || ((fd_flags & O_ACCMODE) == O_RDONLY && !(read_write & _IO_NO_WRITES)) + || ((fd_flags & O_ACCMODE) == O_WRONLY && !(read_write & _IO_NO_READS))) + return NULL; + + /* The May 93 draft of P1003.4/D14.1 (redesignated as 1003.1b) + [System Application Program Interface (API) Amendment 1: + Realtime Extensions], Rationale B.8.3.3 + Open a Stream on a File Descriptor says: + + Although not explicitly required by POSIX.1, a good + implementation of append ("a") mode would cause the + O_APPEND flag to be set. + + (Historical implementations [such as Solaris2] do a one-time + seek in fdopen.) + + However, we do not turn O_APPEND off if the mode is "w" (even + though that would seem consistent) because that would be more + likely to break historical programs. + */ + if ((posix_mode & O_APPEND) && !(fd_flags & O_APPEND)) + { +#ifdef F_SETFL + if (_IO_fcntl (fd, F_SETFL, fd_flags | O_APPEND) == -1) +#endif + return NULL; + } +#endif + + new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); + if (new_f == NULL) + return NULL; +#ifdef _IO_MTSAFE_IO + new_f->fp.file._lock = &new_f->lock; +#endif + _IO_init (&new_f->fp.file, 0); + _IO_JUMPS (&new_f->fp) = &_IO_old_file_jumps; + _IO_old_file_init (&new_f->fp.file); +#if !_IO_UNIFIED_JUMPTABLES + new_f->fp.vtable = NULL; +#endif + if (_IO_old_file_attach (&new_f->fp.file, fd) == NULL) + { + _IO_un_link (&new_f->fp.file); + free (new_f); + return NULL; + } + new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE; + + new_f->fp.file._IO_file_flags = + _IO_mask_flags (&new_f->fp.file, read_write, + _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); + + return (_IO_FILE *) &new_f->fp; +} + +#ifdef SHARED +strong_alias (_IO_old_fdopen, __old_fdopen) +symbol_version (_IO_old_fdopen, _IO_fdopen, GLIBC_2.0); +symbol_version (__old_fdopen, fdopen, GLIBC_2.0); +#else +strong_alias (_IO_old_fdopen, _IO_fdopen); +strong_alias (__old_fdopen, fdopen); +#endif diff -Naur ../glibc-2.1.3/glibc-compat/oldiofopen.c glibc-2.1.3/glibc-compat/oldiofopen.c --- ../glibc-2.1.3/glibc-compat/oldiofopen.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/oldiofopen.c 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,71 @@ +/* Copyright (C) 1993, 1997 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library 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, or (at + your option) any later version. + + This library 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 library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" +#ifdef __STDC__ +#include +#endif + + +_IO_FILE * +_IO_old_fopen (filename, mode) + const char *filename; + const char *mode; +{ + struct locked_FILE + { + struct _IO_FILE_plus fp; +#ifdef _IO_MTSAFE_IO + _IO_lock_t lock; +#endif + } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); + + if (new_f == NULL) + return NULL; +#ifdef _IO_MTSAFE_IO + new_f->fp.file._lock = &new_f->lock; +#endif + _IO_init (&new_f->fp.file, 0); + _IO_JUMPS (&new_f->fp.file) = &_IO_old_file_jumps; + _IO_old_file_init (&new_f->fp.file); +#if !_IO_UNIFIED_JUMPTABLES + new_f->fp.vtable = NULL; +#endif + if (_IO_old_file_fopen (&new_f->fp.file, filename, mode) != NULL) + return (_IO_FILE *) &new_f->fp; + _IO_un_link (&new_f->fp.file); + free (new_f); + return NULL; +} + +#ifdef SHARED +strong_alias (_IO_old_fopen, __old_fopen) +symbol_version (_IO_old_fopen, _IO_fopen, GLIBC_2.0); +symbol_version (__old_fopen, fopen, GLIBC_2.0); +#else +strong_alias (_IO_old_fopen, _IO_fopen); +strong_alias (__old_fopen, fopen); +#endif diff -Naur ../glibc-2.1.3/glibc-compat/oldiopopen.c glibc-2.1.3/glibc-compat/oldiopopen.c --- ../glibc-2.1.3/glibc-compat/oldiopopen.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/oldiopopen.c 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,289 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + Written by Per Bothner . + + This library 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, or (at + your option) any later version. + + This library 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 library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include "libioP.h" +#if _IO_HAVE_SYS_WAIT +#include +#include +#ifdef __STDC__ +#include +#endif +#ifdef _LIBC +# include +#endif +#include +#include + +#ifndef _IO_fork +#ifdef _LIBC +#define _IO_fork __vfork +#else +#define _IO_fork vfork /* defined in libiberty, if needed */ +#endif +extern _IO_pid_t _IO_fork __P ((void)); +#endif + +#endif /* _IO_HAVE_SYS_WAIT */ + +#ifndef _IO_pipe +#ifdef _LIBC +#define _IO_pipe __pipe +#else +#define _IO_pipe pipe +#endif +extern int _IO_pipe __P ((int des[2])); +#endif + +#ifndef _IO_dup2 +#ifdef _LIBC +#define _IO_dup2 __dup2 +#else +#define _IO_dup2 dup2 +#endif +extern int _IO_dup2 __P ((int fd, int fd2)); +#endif + +#ifndef _IO_waitpid +#ifdef _LIBC +#define _IO_waitpid __waitpid +#else +#define _IO_waitpid waitpid +#endif +#endif + +#ifndef _IO_execl +#define _IO_execl execl +#endif +#ifndef _IO__exit +#define _IO__exit _exit +#endif + +#ifndef _IO_close +#ifdef _LIBC +#define _IO_close __close +#else +#define _IO_close close +#endif +#endif + +struct _IO_proc_file +{ + struct _IO_FILE_plus file; + /* Following fields must match those in class procbuf (procbuf.h) */ + _IO_pid_t pid; + struct _IO_proc_file *next; +}; +typedef struct _IO_proc_file _IO_proc_file; + +static struct _IO_proc_file *old_proc_file_chain = NULL; + +_IO_FILE * +_IO_old_proc_open (fp, command, mode) + _IO_FILE *fp; + const char *command; + const char *mode; +{ +#if _IO_HAVE_SYS_WAIT + volatile int read_or_write; + volatile int parent_end, child_end; + int pipe_fds[2]; + _IO_pid_t child_pid; + if (_IO_file_is_open (fp)) + return NULL; + if (_IO_pipe (pipe_fds) < 0) + return NULL; + if (mode[0] == 'r' && mode[1] == '\0') + { + parent_end = pipe_fds[0]; + child_end = pipe_fds[1]; + read_or_write = _IO_NO_WRITES; + } + else if (mode[0] == 'w' && mode[1] == '\0') + { + parent_end = pipe_fds[1]; + child_end = pipe_fds[0]; + read_or_write = _IO_NO_READS; + } + else + { + __set_errno (EINVAL); + return NULL; + } + ((_IO_proc_file *) fp)->pid = child_pid = _IO_fork (); + if (child_pid == 0) + { + int child_std_end = mode[0] == 'r' ? 1 : 0; + _IO_close (parent_end); + if (child_end != child_std_end) + { + _IO_dup2 (child_end, child_std_end); + _IO_close (child_end); + } + /* POSIX.2: "popen() shall ensure that any streams from previous + popen() calls that remain open in the parent process are closed + in the new child process." */ + while (old_proc_file_chain) + { + _IO_close (_IO_fileno ((_IO_FILE *) old_proc_file_chain)); + old_proc_file_chain = old_proc_file_chain->next; + } + + _IO_execl ("/bin/sh", "sh", "-c", command, (char *) 0); + _IO__exit (127); + } + _IO_close (child_end); + if (child_pid < 0) + { + _IO_close (parent_end); + return NULL; + } + _IO_fileno (fp) = parent_end; + + /* Link into old_proc_file_chain. */ + ((_IO_proc_file *) fp)->next = old_proc_file_chain; + old_proc_file_chain = (_IO_proc_file *) fp; + + _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES); + return fp; +#else /* !_IO_HAVE_SYS_WAIT */ + return NULL; +#endif +} + +_IO_FILE * +_IO_old_popen (command, mode) + const char *command; + const char *mode; +{ + struct locked_FILE + { + struct _IO_proc_file fpx; +#ifdef _IO_MTSAFE_IO + _IO_lock_t lock; +#endif + } *new_f; + _IO_FILE *fp; + + new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); + if (new_f == NULL) + return NULL; +#ifdef _IO_MTSAFE_IO + new_f->fpx.file.file._lock = &new_f->lock; +#endif + fp = &new_f->fpx.file.file; + _IO_init (fp, 0); + _IO_JUMPS (fp) = &_IO_old_proc_jumps; + _IO_old_file_init (fp); +#if !_IO_UNIFIED_JUMPTABLES + new_f->fpx.file.vtable = NULL; +#endif + if (_IO_old_proc_open (fp, command, mode) != NULL) + return fp; + _IO_un_link (fp); + free (new_f); + return NULL; +} + +int +_IO_old_proc_close (fp) + _IO_FILE *fp; +{ + /* This is not name-space clean. FIXME! */ +#if _IO_HAVE_SYS_WAIT + int wstatus; + _IO_proc_file **ptr = &old_proc_file_chain; + _IO_pid_t wait_pid; + int status = -1; + + /* Unlink from old_proc_file_chain. */ + for ( ; *ptr != NULL; ptr = &(*ptr)->next) + { + if (*ptr == (_IO_proc_file *) fp) + { + *ptr = (*ptr)->next; + status = 0; + break; + } + } + + if (status < 0 || _IO_close (_IO_fileno(fp)) < 0) + return -1; + /* POSIX.2 Rationale: "Some historical implementations either block + or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting + for the child process to terminate. Since this behavior is not + described in POSIX.2, such implementations are not conforming." */ + do + { + wait_pid = _IO_waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0); + } + while (wait_pid == -1 && errno == EINTR); + if (wait_pid == -1) + return -1; + return wstatus; +#else /* !_IO_HAVE_SYS_WAIT */ + return -1; +#endif +} + +struct _IO_jump_t _IO_old_proc_jumps = { + JUMP_INIT_DUMMY, + JUMP_INIT(finish, _IO_old_file_finish), + JUMP_INIT(overflow, _IO_old_file_overflow), + JUMP_INIT(underflow, _IO_old_file_underflow), + JUMP_INIT(uflow, _IO_default_uflow), + JUMP_INIT(pbackfail, _IO_default_pbackfail), + JUMP_INIT(xsputn, _IO_old_file_xsputn), + JUMP_INIT(xsgetn, _IO_default_xsgetn), + JUMP_INIT(seekoff, _IO_old_file_seekoff), + JUMP_INIT(seekpos, _IO_default_seekpos), + JUMP_INIT(setbuf, _IO_old_file_setbuf), + JUMP_INIT(sync, _IO_old_file_sync), + JUMP_INIT(doallocate, _IO_file_doallocate), + JUMP_INIT(read, _IO_file_read), + JUMP_INIT(write, _IO_old_file_write), + JUMP_INIT(seek, _IO_file_seek), + JUMP_INIT(close, _IO_old_proc_close), + JUMP_INIT(stat, _IO_file_stat), + JUMP_INIT(showmanyc, _IO_default_showmanyc), + JUMP_INIT(imbue, _IO_default_imbue) +}; + +#ifdef SHARED +strong_alias (_IO_old_popen, __old_popen) +symbol_version (_IO_old_popen, _IO_popen, GLIBC_2.0); +symbol_version (__old_popen, popen, GLIBC_2.0); +symbol_version (_IO_old_proc_open, _IO_proc_open, GLIBC_2.0); +symbol_version (_IO_old_proc_close, _IO_proc_close, GLIBC_2.0); +#else +strong_alias (_IO_old_popen, _IO_popen); +strong_alias (__old_popen, popen); +strong_alias (_IO_old_proc_open, _IO_proc_open); +strong_alias (_IO_old_proc_close, _IO_proc_close); +#endif diff -Naur ../glibc-2.1.3/glibc-compat/oldpclose.c glibc-2.1.3/glibc-compat/oldpclose.c --- ../glibc-2.1.3/glibc-compat/oldpclose.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/oldpclose.c 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,48 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library 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, or (at + your option) any later version. + + This library 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 library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" +#include "stdio.h" +#include + +int +__old_pclose (fp) + FILE *fp; +{ +#if 0 + /* Does not actually test that stream was created by popen(). Instead, + it depends on the filebuf::sys_close() virtual to Do The Right Thing. */ + if (fp is not a proc_file) + return -1; +#endif + return _IO_old_fclose (fp); +} + +#ifdef SHARED +symbol_version (__old_pclose, pclose, GLIBC_2.0); +#else +strong_alias (__old_pclose, pclose); +#endif diff -Naur ../glibc-2.1.3/glibc-compat/oldstdfiles.c glibc-2.1.3/glibc-compat/oldstdfiles.c --- ../glibc-2.1.3/glibc-compat/oldstdfiles.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/oldstdfiles.c 2000-01-03 17:07:07.000000000 -0800 @@ -0,0 +1,97 @@ +/* Copyright (C) 1993, 1994, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library 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, or (at + your option) any later version. + + This library 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 library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + + +/* This file provides definitions of _IO_stdin, _IO_stdout, and _IO_stderr + for C code. Compare stdstreams.cc. + (The difference is that here the vtable field is set to 0, + so the objects defined are not valid C++ objects. On the other + hand, we don't need a C++ compiler to build this file.) */ + +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" + +#ifdef _IO_MTSAFE_IO +#define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \ + static _IO_lock_t _IO_stdfile_##FD##_lock = _IO_lock_initializer; \ + struct _IO_FILE_plus NAME \ + = {FILEBUF_LITERAL(CHAIN, FLAGS, FD), &_IO_old_file_jumps}; +#else +#define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \ + struct _IO_FILE_plus NAME \ + = {FILEBUF_LITERAL(CHAIN, FLAGS, FD), &_IO_old_file_jumps}; +#endif + +DEF_STDFILE(_IO_stdin_, 0, 0, _IO_NO_WRITES); +DEF_STDFILE(_IO_stdout_, 1, &_IO_stdin_.file, _IO_NO_READS); +DEF_STDFILE(_IO_stderr_, 2, &_IO_stdout_.file, + _IO_NO_READS+_IO_UNBUFFERED); + +#if defined __GNUC__ && __GNUC__ >= 2 + +#include + +extern const int _IO_stdin_used; +weak_extern (_IO_stdin_used); + +#undef stdin +#undef stdout +#undef stderr + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +#ifdef SHARED +extern +#endif +FILE *_IO_list_all; + +static void _IO_check_libio __P ((void)) __attribute__ ((constructor)); + +/* This function determines which shared C library the application + was linked against. We then set up the stdin/stdout/stderr and + _IO_list_all accordingly. */ + +static void +_IO_check_libio () +{ +#ifdef SHARED + if (&_IO_stdin_used == NULL) +#endif + { + /* We are using the old one. */ + _IO_stdin = stdin = &_IO_stdin_.file; + _IO_stdout = stdout = &_IO_stdout_.file; + _IO_stderr = stderr = _IO_list_all = &_IO_stderr_.file; + _IO_stdin->_vtable_offset = _IO_stdout->_vtable_offset = + _IO_stderr->_vtable_offset = stdin->_vtable_offset = + stdout->_vtable_offset = stderr->_vtable_offset = + ((int) sizeof (struct _IO_FILE) + - (int) sizeof (struct _IO_FILE_complete)); + } +} + +#endif diff -Naur ../glibc-2.1.3/glibc-compat/oldtmpfile.c glibc-2.1.3/glibc-compat/oldtmpfile.c --- ../glibc-2.1.3/glibc-compat/oldtmpfile.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/oldtmpfile.c 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,55 @@ +/* Copyright (C) 1991, 1993, 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define _IO_USE_OLD_IO_FILE +#include +#include +#include + +/* This returns a new stream opened on a temporary file (generated + by tmpnam). The file is opened with mode "w+b" (binary read/write). + If we couldn't generate a unique filename or the file couldn't + be opened, NULL is returned. */ +FILE * +__old_tmpfile (void) +{ + char buf[FILENAME_MAX]; + int fd; + FILE *f; + + if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0)) + return NULL; + fd = __gen_tempname (buf, 1, 0); + if (fd < 0) + return NULL; + + /* Note that this relies on the Unix semantics that + a file is not really removed until it is closed. */ + (void) remove (buf); + + if ((f = _IO_old_fdopen (fd, "w+b")) == NULL) + __close (fd); + + return f; +} + +#ifdef SHARED +symbol_version (__old_tmpfile, tmpfile, GLIBC_2.0); +#else +strong_alias (__old_tmpfile, tmpfile); +#endif diff -Naur ../glibc-2.1.3/glibc-compat/rpcsvc/yp.h glibc-2.1.3/glibc-compat/rpcsvc/yp.h --- ../glibc-2.1.3/glibc-compat/rpcsvc/yp.h 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/rpcsvc/yp.h 2000-01-03 18:17:33.000000000 -0800 @@ -0,0 +1,621 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#ifndef __RPCSVC_YP_H__ +#define __RPCSVC_YP_H__ + +#include + +#define YPMAXRECORD 1024 +#define YPMAXDOMAIN 64 +#define YPMAXMAP 64 +#define YPMAXPEER 64 + +enum ypstat { + YP_TRUE = 1, + YP_NOMORE = 2, + YP_FALSE = 0, + YP_NOMAP = -1, + YP_NODOM = -2, + YP_NOKEY = -3, + YP_BADOP = -4, + YP_BADDB = -5, + YP_YPERR = -6, + YP_BADARGS = -7, + YP_VERS = -8, +}; +typedef enum ypstat ypstat; +#ifdef __cplusplus +extern "C" bool_t xdr_ypstat(XDR *, ypstat*); +#elif __STDC__ +extern bool_t xdr_ypstat(XDR *, ypstat*); +#else /* Old Style C */ +bool_t xdr_ypstat(); +#endif /* Old Style C */ + + +enum ypxfrstat { + YPXFR_SUCC = 1, + YPXFR_AGE = 2, + YPXFR_NOMAP = -1, + YPXFR_NODOM = -2, + YPXFR_RSRC = -3, + YPXFR_RPC = -4, + YPXFR_MADDR = -5, + YPXFR_YPERR = -6, + YPXFR_BADARGS = -7, + YPXFR_DBM = -8, + YPXFR_FILE = -9, + YPXFR_SKEW = -10, + YPXFR_CLEAR = -11, + YPXFR_FORCE = -12, + YPXFR_XFRERR = -13, + YPXFR_REFUSED = -14, +}; +typedef enum ypxfrstat ypxfrstat; +#ifdef __cplusplus +extern "C" bool_t xdr_ypxfrstat(XDR *, ypxfrstat*); +#elif __STDC__ +extern bool_t xdr_ypxfrstat(XDR *, ypxfrstat*); +#else /* Old Style C */ +bool_t xdr_ypxfrstat(); +#endif /* Old Style C */ + + +typedef char *domainname; +#ifdef __cplusplus +extern "C" bool_t xdr_domainname(XDR *, domainname*); +#elif __STDC__ +extern bool_t xdr_domainname(XDR *, domainname*); +#else /* Old Style C */ +bool_t xdr_domainname(); +#endif /* Old Style C */ + + +typedef char *mapname; +#ifdef __cplusplus +extern "C" bool_t xdr_mapname(XDR *, mapname*); +#elif __STDC__ +extern bool_t xdr_mapname(XDR *, mapname*); +#else /* Old Style C */ +bool_t xdr_mapname(); +#endif /* Old Style C */ + + +typedef char *peername; +#ifdef __cplusplus +extern "C" bool_t xdr_peername(XDR *, peername*); +#elif __STDC__ +extern bool_t xdr_peername(XDR *, peername*); +#else /* Old Style C */ +bool_t xdr_peername(); +#endif /* Old Style C */ + + +typedef struct { + u_int keydat_len; + char *keydat_val; +} keydat; +#ifdef __cplusplus +extern "C" bool_t xdr_keydat(XDR *, keydat*); +#elif __STDC__ +extern bool_t xdr_keydat(XDR *, keydat*); +#else /* Old Style C */ +bool_t xdr_keydat(); +#endif /* Old Style C */ + + +typedef struct { + u_int valdat_len; + char *valdat_val; +} valdat; +#ifdef __cplusplus +extern "C" bool_t xdr_valdat(XDR *, valdat*); +#elif __STDC__ +extern bool_t xdr_valdat(XDR *, valdat*); +#else /* Old Style C */ +bool_t xdr_valdat(); +#endif /* Old Style C */ + + +struct ypmap_parms { + domainname domain; + mapname map; + u_int ordernum; + peername peer; +}; +typedef struct ypmap_parms ypmap_parms; +#ifdef __cplusplus +extern "C" bool_t xdr_ypmap_parms(XDR *, ypmap_parms*); +#elif __STDC__ +extern bool_t xdr_ypmap_parms(XDR *, ypmap_parms*); +#else /* Old Style C */ +bool_t xdr_ypmap_parms(); +#endif /* Old Style C */ + + +struct ypreq_key { + domainname domain; + mapname map; + keydat key; +}; +typedef struct ypreq_key ypreq_key; +#ifdef __cplusplus +extern "C" bool_t xdr_ypreq_key(XDR *, ypreq_key*); +#elif __STDC__ +extern bool_t xdr_ypreq_key(XDR *, ypreq_key*); +#else /* Old Style C */ +bool_t xdr_ypreq_key(); +#endif /* Old Style C */ + + +struct ypreq_nokey { + domainname domain; + mapname map; +}; +typedef struct ypreq_nokey ypreq_nokey; +#ifdef __cplusplus +extern "C" bool_t xdr_ypreq_nokey(XDR *, ypreq_nokey*); +#elif __STDC__ +extern bool_t xdr_ypreq_nokey(XDR *, ypreq_nokey*); +#else /* Old Style C */ +bool_t xdr_ypreq_nokey(); +#endif /* Old Style C */ + + +struct ypreq_xfr { + ypmap_parms map_parms; + u_int transid; + u_int prog; + u_int port; +}; +typedef struct ypreq_xfr ypreq_xfr; +#ifdef __cplusplus +extern "C" bool_t xdr_ypreq_xfr(XDR *, ypreq_xfr*); +#elif __STDC__ +extern bool_t xdr_ypreq_xfr(XDR *, ypreq_xfr*); +#else /* Old Style C */ +bool_t xdr_ypreq_xfr(); +#endif /* Old Style C */ + + +struct ypresp_val { + ypstat stat; + valdat val; +}; +typedef struct ypresp_val ypresp_val; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_val(XDR *, ypresp_val*); +#elif __STDC__ +extern bool_t xdr_ypresp_val(XDR *, ypresp_val*); +#else /* Old Style C */ +bool_t xdr_ypresp_val(); +#endif /* Old Style C */ + + +struct ypresp_key_val { + ypstat stat; +#ifdef STUPID_SUN_BUG + /* This is the form as distributed by Sun. But even the Sun NIS + servers expect the values in the other order. So their + implementation somehow must change the order internally. We + don't want to follow this bad example since the user should be + able to use rpcgen on this file. */ + keydat key; + valdat val; +#else + valdat val; + keydat key; +#endif +}; +typedef struct ypresp_key_val ypresp_key_val; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_key_val(XDR *, ypresp_key_val*); +#elif __STDC__ +extern bool_t xdr_ypresp_key_val(XDR *, ypresp_key_val*); +#else /* Old Style C */ +bool_t xdr_ypresp_key_val(); +#endif /* Old Style C */ + + +struct ypresp_master { + ypstat stat; + peername peer; +}; +typedef struct ypresp_master ypresp_master; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_master(XDR *, ypresp_master*); +#elif __STDC__ +extern bool_t xdr_ypresp_master(XDR *, ypresp_master*); +#else /* Old Style C */ +bool_t xdr_ypresp_master(); +#endif /* Old Style C */ + + +struct ypresp_order { + ypstat stat; + u_int ordernum; +}; +typedef struct ypresp_order ypresp_order; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_order(XDR *, ypresp_order*); +#elif __STDC__ +extern bool_t xdr_ypresp_order(XDR *, ypresp_order*); +#else /* Old Style C */ +bool_t xdr_ypresp_order(); +#endif /* Old Style C */ + + +struct ypresp_all { + bool_t more; + union { + ypresp_key_val val; + } ypresp_all_u; +}; +typedef struct ypresp_all ypresp_all; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_all(XDR *, ypresp_all*); +#elif __STDC__ +extern bool_t xdr_ypresp_all(XDR *, ypresp_all*); +#else /* Old Style C */ +bool_t xdr_ypresp_all(); +#endif /* Old Style C */ + + +struct ypresp_xfr { + u_int transid; + ypxfrstat xfrstat; +}; +typedef struct ypresp_xfr ypresp_xfr; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_xfr(XDR *, ypresp_xfr*); +#elif __STDC__ +extern bool_t xdr_ypresp_xfr(XDR *, ypresp_xfr*); +#else /* Old Style C */ +bool_t xdr_ypresp_xfr(); +#endif /* Old Style C */ + + +struct ypmaplist { + mapname map; + struct ypmaplist *next; +}; +typedef struct ypmaplist ypmaplist; +#ifdef __cplusplus +extern "C" bool_t xdr_ypmaplist(XDR *, ypmaplist*); +#elif __STDC__ +extern bool_t xdr_ypmaplist(XDR *, ypmaplist*); +#else /* Old Style C */ +bool_t xdr_ypmaplist(); +#endif /* Old Style C */ + + +struct ypresp_maplist { + ypstat stat; + ypmaplist *maps; +}; +typedef struct ypresp_maplist ypresp_maplist; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_maplist(XDR *, ypresp_maplist*); +#elif __STDC__ +extern bool_t xdr_ypresp_maplist(XDR *, ypresp_maplist*); +#else /* Old Style C */ +bool_t xdr_ypresp_maplist(); +#endif /* Old Style C */ + + +enum yppush_status { + YPPUSH_SUCC = 1, + YPPUSH_AGE = 2, + YPPUSH_NOMAP = -1, + YPPUSH_NODOM = -2, + YPPUSH_RSRC = -3, + YPPUSH_RPC = -4, + YPPUSH_MADDR = -5, + YPPUSH_YPERR = -6, + YPPUSH_BADARGS = -7, + YPPUSH_DBM = -8, + YPPUSH_FILE = -9, + YPPUSH_SKEW = -10, + YPPUSH_CLEAR = -11, + YPPUSH_FORCE = -12, + YPPUSH_XFRERR = -13, + YPPUSH_REFUSED = -14, +}; +typedef enum yppush_status yppush_status; +#ifdef __cplusplus +extern "C" bool_t xdr_yppush_status(XDR *, yppush_status*); +#elif __STDC__ +extern bool_t xdr_yppush_status(XDR *, yppush_status*); +#else /* Old Style C */ +bool_t xdr_yppush_status(); +#endif /* Old Style C */ + + +struct yppushresp_xfr { + u_int transid; + yppush_status status; +}; +typedef struct yppushresp_xfr yppushresp_xfr; +#ifdef __cplusplus +extern "C" bool_t xdr_yppushresp_xfr(XDR *, yppushresp_xfr*); +#elif __STDC__ +extern bool_t xdr_yppushresp_xfr(XDR *, yppushresp_xfr*); +#else /* Old Style C */ +bool_t xdr_yppushresp_xfr(); +#endif /* Old Style C */ + + +enum ypbind_resptype { + YPBIND_SUCC_VAL = 1, + YPBIND_FAIL_VAL = 2, +}; +typedef enum ypbind_resptype ypbind_resptype; +#ifdef __cplusplus +extern "C" bool_t xdr_ypbind_resptype(XDR *, ypbind_resptype*); +#elif __STDC__ +extern bool_t xdr_ypbind_resptype(XDR *, ypbind_resptype*); +#else /* Old Style C */ +bool_t xdr_ypbind_resptype(); +#endif /* Old Style C */ + + +struct ypbind_binding { + char ypbind_binding_addr[4]; + char ypbind_binding_port[2]; +}; +typedef struct ypbind_binding ypbind_binding; +#ifdef __cplusplus +extern "C" bool_t xdr_ypbind_binding(XDR *, ypbind_binding*); +#elif __STDC__ +extern bool_t xdr_ypbind_binding(XDR *, ypbind_binding*); +#else /* Old Style C */ +bool_t xdr_ypbind_binding(); +#endif /* Old Style C */ + + +struct ypbind_resp { + ypbind_resptype ypbind_status; + union { + u_int ypbind_error; + ypbind_binding ypbind_bindinfo; + } ypbind_resp_u; +}; +typedef struct ypbind_resp ypbind_resp; +#ifdef __cplusplus +extern "C" bool_t xdr_ypbind_resp(XDR *, ypbind_resp*); +#elif __STDC__ +extern bool_t xdr_ypbind_resp(XDR *, ypbind_resp*); +#else /* Old Style C */ +bool_t xdr_ypbind_resp(); +#endif /* Old Style C */ + +#define YPBIND_ERR_ERR 1 +#define YPBIND_ERR_NOSERV 2 +#define YPBIND_ERR_RESC 3 + +struct ypbind_setdom { + domainname ypsetdom_domain; + ypbind_binding ypsetdom_binding; + u_int ypsetdom_vers; +}; +typedef struct ypbind_setdom ypbind_setdom; +#ifdef __cplusplus +extern "C" bool_t xdr_ypbind_setdom(XDR *, ypbind_setdom*); +#elif __STDC__ +extern bool_t xdr_ypbind_setdom(XDR *, ypbind_setdom*); +#else /* Old Style C */ +bool_t xdr_ypbind_setdom(); +#endif /* Old Style C */ + + +#define YPPROG ((u_long)100004) +#define YPVERS ((u_long)2) + +#ifdef __cplusplus +#define YPPROC_NULL ((u_long)0) +extern "C" void * ypproc_null_2(void *, CLIENT *); +extern "C" void * ypproc_null_2_svc(void *, struct svc_req *); +#define YPPROC_DOMAIN ((u_long)1) +extern "C" bool_t * ypproc_domain_2(domainname *, CLIENT *); +extern "C" bool_t * ypproc_domain_2_svc(domainname *, struct svc_req *); +#define YPPROC_DOMAIN_NONACK ((u_long)2) +extern "C" bool_t * ypproc_domain_nonack_2(domainname *, CLIENT *); +extern "C" bool_t * ypproc_domain_nonack_2_svc(domainname *, struct svc_req *); +#define YPPROC_MATCH ((u_long)3) +extern "C" ypresp_val * ypproc_match_2(ypreq_key *, CLIENT *); +extern "C" ypresp_val * ypproc_match_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_FIRST ((u_long)4) +extern "C" ypresp_key_val * ypproc_first_2(ypreq_key *, CLIENT *); +extern "C" ypresp_key_val * ypproc_first_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_NEXT ((u_long)5) +extern "C" ypresp_key_val * ypproc_next_2(ypreq_key *, CLIENT *); +extern "C" ypresp_key_val * ypproc_next_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_XFR ((u_long)6) +extern "C" ypresp_xfr * ypproc_xfr_2(ypreq_xfr *, CLIENT *); +extern "C" ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *, struct svc_req *); +#define YPPROC_CLEAR ((u_long)7) +extern "C" void * ypproc_clear_2(void *, CLIENT *); +extern "C" void * ypproc_clear_2_svc(void *, struct svc_req *); +#define YPPROC_ALL ((u_long)8) +extern "C" ypresp_all * ypproc_all_2(ypreq_nokey *, CLIENT *); +extern "C" ypresp_all * ypproc_all_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_MASTER ((u_long)9) +extern "C" ypresp_master * ypproc_master_2(ypreq_nokey *, CLIENT *); +extern "C" ypresp_master * ypproc_master_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_ORDER ((u_long)10) +extern "C" ypresp_order * ypproc_order_2(ypreq_nokey *, CLIENT *); +extern "C" ypresp_order * ypproc_order_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_MAPLIST ((u_long)11) +extern "C" ypresp_maplist * ypproc_maplist_2(domainname *, CLIENT *); +extern "C" ypresp_maplist * ypproc_maplist_2_svc(domainname *, struct svc_req *); + +#elif __STDC__ +#define YPPROC_NULL ((u_long)0) +extern void * ypproc_null_2(void *, CLIENT *); +extern void * ypproc_null_2_svc(void *, struct svc_req *); +#define YPPROC_DOMAIN ((u_long)1) +extern bool_t * ypproc_domain_2(domainname *, CLIENT *); +extern bool_t * ypproc_domain_2_svc(domainname *, struct svc_req *); +#define YPPROC_DOMAIN_NONACK ((u_long)2) +extern bool_t * ypproc_domain_nonack_2(domainname *, CLIENT *); +extern bool_t * ypproc_domain_nonack_2_svc(domainname *, struct svc_req *); +#define YPPROC_MATCH ((u_long)3) +extern ypresp_val * ypproc_match_2(ypreq_key *, CLIENT *); +extern ypresp_val * ypproc_match_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_FIRST ((u_long)4) +extern ypresp_key_val * ypproc_first_2(ypreq_key *, CLIENT *); +extern ypresp_key_val * ypproc_first_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_NEXT ((u_long)5) +extern ypresp_key_val * ypproc_next_2(ypreq_key *, CLIENT *); +extern ypresp_key_val * ypproc_next_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_XFR ((u_long)6) +extern ypresp_xfr * ypproc_xfr_2(ypreq_xfr *, CLIENT *); +extern ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *, struct svc_req *); +#define YPPROC_CLEAR ((u_long)7) +extern void * ypproc_clear_2(void *, CLIENT *); +extern void * ypproc_clear_2_svc(void *, struct svc_req *); +#define YPPROC_ALL ((u_long)8) +extern ypresp_all * ypproc_all_2(ypreq_nokey *, CLIENT *); +extern ypresp_all * ypproc_all_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_MASTER ((u_long)9) +extern ypresp_master * ypproc_master_2(ypreq_nokey *, CLIENT *); +extern ypresp_master * ypproc_master_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_ORDER ((u_long)10) +extern ypresp_order * ypproc_order_2(ypreq_nokey *, CLIENT *); +extern ypresp_order * ypproc_order_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_MAPLIST ((u_long)11) +extern ypresp_maplist * ypproc_maplist_2(domainname *, CLIENT *); +extern ypresp_maplist * ypproc_maplist_2_svc(domainname *, struct svc_req *); + +#else /* Old Style C */ +#define YPPROC_NULL ((u_long)0) +extern void * ypproc_null_2(); +extern void * ypproc_null_2_svc(); +#define YPPROC_DOMAIN ((u_long)1) +extern bool_t * ypproc_domain_2(); +extern bool_t * ypproc_domain_2_svc(); +#define YPPROC_DOMAIN_NONACK ((u_long)2) +extern bool_t * ypproc_domain_nonack_2(); +extern bool_t * ypproc_domain_nonack_2_svc(); +#define YPPROC_MATCH ((u_long)3) +extern ypresp_val * ypproc_match_2(); +extern ypresp_val * ypproc_match_2_svc(); +#define YPPROC_FIRST ((u_long)4) +extern ypresp_key_val * ypproc_first_2(); +extern ypresp_key_val * ypproc_first_2_svc(); +#define YPPROC_NEXT ((u_long)5) +extern ypresp_key_val * ypproc_next_2(); +extern ypresp_key_val * ypproc_next_2_svc(); +#define YPPROC_XFR ((u_long)6) +extern ypresp_xfr * ypproc_xfr_2(); +extern ypresp_xfr * ypproc_xfr_2_svc(); +#define YPPROC_CLEAR ((u_long)7) +extern void * ypproc_clear_2(); +extern void * ypproc_clear_2_svc(); +#define YPPROC_ALL ((u_long)8) +extern ypresp_all * ypproc_all_2(); +extern ypresp_all * ypproc_all_2_svc(); +#define YPPROC_MASTER ((u_long)9) +extern ypresp_master * ypproc_master_2(); +extern ypresp_master * ypproc_master_2_svc(); +#define YPPROC_ORDER ((u_long)10) +extern ypresp_order * ypproc_order_2(); +extern ypresp_order * ypproc_order_2_svc(); +#define YPPROC_MAPLIST ((u_long)11) +extern ypresp_maplist * ypproc_maplist_2(); +extern ypresp_maplist * ypproc_maplist_2_svc(); +#endif /* Old Style C */ + +#define YPPUSH_XFRRESPPROG ((u_long)0x40000000) +#define YPPUSH_XFRRESPVERS ((u_long)1) + +#ifdef __cplusplus +#define YPPUSHPROC_NULL ((u_long)0) +extern "C" void * yppushproc_null_1(void *, CLIENT *); +extern "C" void * yppushproc_null_1_svc(void *, struct svc_req *); +#define YPPUSHPROC_XFRRESP ((u_long)1) +extern "C" void * yppushproc_xfrresp_1(yppushresp_xfr *, CLIENT *); +extern "C" void * yppushproc_xfrresp_1_svc(yppushresp_xfr *, struct svc_req *); + +#elif __STDC__ +#define YPPUSHPROC_NULL ((u_long)0) +extern void * yppushproc_null_1(void *, CLIENT *); +extern void * yppushproc_null_1_svc(void *, struct svc_req *); +#define YPPUSHPROC_XFRRESP ((u_long)1) +extern void * yppushproc_xfrresp_1(yppushresp_xfr *, CLIENT *); +extern void * yppushproc_xfrresp_1_svc(yppushresp_xfr *, struct svc_req *); + +#else /* Old Style C */ +#define YPPUSHPROC_NULL ((u_long)0) +extern void * yppushproc_null_1(); +extern void * yppushproc_null_1_svc(); +#define YPPUSHPROC_XFRRESP ((u_long)1) +extern void * yppushproc_xfrresp_1(); +extern void * yppushproc_xfrresp_1_svc(); +#endif /* Old Style C */ + +#define YPBINDPROG ((u_long)100007) +#define YPBINDVERS ((u_long)2) + +#ifdef __cplusplus +#define YPBINDPROC_NULL ((u_long)0) +extern "C" void * ypbindproc_null_2(void *, CLIENT *); +extern "C" void * ypbindproc_null_2_svc(void *, struct svc_req *); +#define YPBINDPROC_DOMAIN ((u_long)1) +extern "C" ypbind_resp * ypbindproc_domain_2(domainname *, CLIENT *); +extern "C" ypbind_resp * ypbindproc_domain_2_svc(domainname *, struct svc_req *); +#define YPBINDPROC_SETDOM ((u_long)2) +extern "C" void * ypbindproc_setdom_2(ypbind_setdom *, CLIENT *); +extern "C" void * ypbindproc_setdom_2_svc(ypbind_setdom *, struct svc_req *); + +#elif __STDC__ +#define YPBINDPROC_NULL ((u_long)0) +extern void * ypbindproc_null_2(void *, CLIENT *); +extern void * ypbindproc_null_2_svc(void *, struct svc_req *); +#define YPBINDPROC_DOMAIN ((u_long)1) +extern ypbind_resp * ypbindproc_domain_2(domainname *, CLIENT *); +extern ypbind_resp * ypbindproc_domain_2_svc(domainname *, struct svc_req *); +#define YPBINDPROC_SETDOM ((u_long)2) +extern void * ypbindproc_setdom_2(ypbind_setdom *, CLIENT *); +extern void * ypbindproc_setdom_2_svc(ypbind_setdom *, struct svc_req *); + +#else /* Old Style C */ +#define YPBINDPROC_NULL ((u_long)0) +extern void * ypbindproc_null_2(); +extern void * ypbindproc_null_2_svc(); +#define YPBINDPROC_DOMAIN ((u_long)1) +extern ypbind_resp * ypbindproc_domain_2(); +extern ypbind_resp * ypbindproc_domain_2_svc(); +#define YPBINDPROC_SETDOM ((u_long)2) +extern void * ypbindproc_setdom_2(); +extern void * ypbindproc_setdom_2_svc(); +#endif /* Old Style C */ + +#endif /* !__RPCSVC_YP_H__ */ diff -Naur ../glibc-2.1.3/glibc-compat/rpcsvc/ypclnt.h glibc-2.1.3/glibc-compat/rpcsvc/ypclnt.h --- ../glibc-2.1.3/glibc-compat/rpcsvc/ypclnt.h 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/rpcsvc/ypclnt.h 2000-01-03 18:17:33.000000000 -0800 @@ -0,0 +1,90 @@ +/* +** Copyright (c) 1996 Thorsten Kukuk, Germany +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This library 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 +** Library General Public License for more details. +** +** You should have received a copy of the GNU Library General Public +** License along with this library; if not, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Author: Thorsten Kukuk +** +*/ + +#ifndef __RPCSVC_YPCLNT_H__ +#define __RPCSVC_YPCLNT_H__ + +#include + +/* some defines */ +#define YPERR_SUCCESS 0 /* There is no error */ +#define YPERR_BADARGS 1 /* Args to function are bad */ +#define YPERR_RPC 2 /* RPC failure */ +#define YPERR_DOMAIN 3 /* Can't bind to a server with this domain */ +#define YPERR_MAP 4 /* No such map in server's domain */ +#define YPERR_KEY 5 /* No such key in map */ +#define YPERR_YPERR 6 /* Internal yp server or client error */ +#define YPERR_RESRC 7 /* Local resource allocation failure */ +#define YPERR_NOMORE 8 /* No more records in map database */ +#define YPERR_PMAP 9 /* Can't communicate with portmapper */ +#define YPERR_YPBIND 10 /* Can't communicate with ypbind */ +#define YPERR_YPSERV 11 /* Can't communicate with ypserv */ +#define YPERR_NODOM 12 /* Local domain name not set */ +#define YPERR_BADDB 13 /* yp data base is bad */ +#define YPERR_VERS 14 /* YP version mismatch */ +#define YPERR_ACCESS 15 /* Access violation */ +#define YPERR_BUSY 16 /* Database is busy */ + +/* Types of update operations */ +#define YPOP_CHANGE 1 /* change, do not add */ +#define YPOP_INSERT 2 /* add, do not change */ +#define YPOP_DELETE 3 /* delete this entry */ +#define YPOP_STORE 4 /* add, or change */ + +__BEGIN_DECLS + +/* struct ypall_callback * is the arg which must be passed to yp_all */ +struct ypall_callback + { + int (*foreach) __P ((int __status, char *__key, int __keylen, + char *__val, int __vallen, char *__data)); + char *data; + }; + +/* External NIS client function references. */ +extern int yp_bind __P ((__const char *)); +extern void yp_unbind __P ((__const char *)); +extern int yp_get_default_domain __P ((char **)); +extern int yp_match __P ((__const char *, __const char *, __const char *, + __const int, char **, int *)); +extern int yp_first __P ((__const char *, __const char *, char **, + int *, char **, int *)); +extern int yp_next __P ((__const char *, __const char *, __const char *, + __const int, char **, int *, char **, int *)); +extern int yp_master __P ((__const char *, __const char *, char **)); +extern int yp_order __P ((__const char *, __const char *, unsigned int *)); +extern int yp_all __P ((__const char *, __const char *, + __const struct ypall_callback *)); +extern __const char *yperr_string __P ((__const int)); +extern __const char *ypbinderr_string __P ((__const int)); +extern int ypprot_err __P ((__const int)); +extern int yp_update __P ((char *, char *, unsigned, char *, + int, char *, int)); +#if 0 +extern int yp_maplist __P ((__const char *, struct ypmaplist **)); +#endif + +/* Exist only under BSD and Linux systems */ +extern int __yp_check __P ((char **)); + +__END_DECLS + +#endif /* __RPCSVC_YPCLNT_H__ */ diff -Naur ../glibc-2.1.3/glibc-compat/shlib-versions glibc-2.1.3/glibc-compat/shlib-versions --- ../glibc-2.1.3/glibc-compat/shlib-versions 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/shlib-versions 2000-01-03 17:07:08.000000000 -0800 @@ -0,0 +1,19 @@ +# Interface revision of the compat nss_* modules. +# +# This must match NSS_SHLIB_REVISION in nss/nsswitch.h, +# which determines the library names used for service +# names given in /etc/nsswitch.conf. +alpha-.*-linux.* libnss1_files=1.1 +alpha-.*-linux.* libnss1_dns=1.1 +alpha-.*-linux.* libnss1_db=1.1 +alpha-.*-linux.* libnss1_compat=1.1 +alpha-.*-linux.* libnss1_nis=1.1 +.*-.*-.* libnss1_files=1 +.*-.*-.* libnss1_db=1 +.*-.*-.* libnss1_dns=1 +.*-.*-.* libnss1_compat=1 +.*-.*-.* libnss1_nis=1 + +# The libNoVersion revision number +.*-.*-.* libNoVersion=1 + diff -Naur ../glibc-2.1.3/glibc-compat/stubs.c glibc-2.1.3/glibc-compat/stubs.c --- ../glibc-2.1.3/glibc-compat/stubs.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/glibc-compat/stubs.c 2000-02-23 17:59:39.000000000 -0800 @@ -0,0 +1,54 @@ +/* + * STAT stuff that breaks Applix + */ + +#include + +/* 1 of 3: _xstat */ +int +_xstat (int vers, const char *name, struct stat *buf) +{ + return __xstat (vers, name, buf); +} + +/* 2 of 3: _fxstat */ +int +_fxstat (int vers, int fd, struct stat *buf) +{ + return __fxstat (vers, fd, buf); +} + +/* 3 of 3: _lxstat */ +int +_lxstat (int vers, const char *name, struct stat *buf) +{ + return __lxstat (vers, name, buf); +} + + +/* + * __setjmp stuff that breaks again Applix + */ +#include + +int __setjmp(jmp_buf env) +{ + return _setjmp(env); +} + + +/* + * __setfpucw break several math packages that ahve not heard of + * the standard _FPU_SETCW() way of setting the control word for the FPU + */ +#include +void __setfpucw(fpu_control_t cw) +{ + +#if defined(_FPU_SETCW) + _FPU_SETCW(cw); +#endif /* _FPU_SETCW */ + + /* others are a no-op. Why doesn't alpha has something like this? */ +} + diff -Naur ../glibc-2.1.3/hesiod/hesiod.c glibc-2.1.3/hesiod/hesiod.c --- ../glibc-2.1.3/hesiod/hesiod.c 1998-05-25 01:40:13.000000000 -0700 +++ glibc-2.1.3/hesiod/hesiod.c 1998-07-09 11:46:28.000000000 -0700 @@ -41,7 +41,7 @@ * it uses res_send() and accesses _res. */ -static const char rcsid[] = "$Id: hesiod.c,v 1.5 1998/05/25 08:40:13 drepper Exp $"; +static const char rcsid[] = "$Id: hesiod.c,v 1.1.1.1 1998/07/09 18:46:28 gafton Exp $"; #include #include diff -Naur ../glibc-2.1.3/hesiod/hesiod.h glibc-2.1.3/hesiod/hesiod.h --- ../glibc-2.1.3/hesiod/hesiod.h 1997-09-15 17:16:33.000000000 -0700 +++ glibc-2.1.3/hesiod/hesiod.h 1998-02-07 12:04:52.000000000 -0800 @@ -1,4 +1,4 @@ -/* $Id: hesiod.h,v 1.1 1997/09/16 00:16:33 drepper Exp $ */ +/* $Id: hesiod.h,v 1.1.1.1 1998/02/07 20:04:52 gafton Exp $ */ /* * Copyright (c) 1996 by Internet Software Consortium. diff -Naur ../glibc-2.1.3/hesiod/hesiod_p.h glibc-2.1.3/hesiod/hesiod_p.h --- ../glibc-2.1.3/hesiod/hesiod_p.h 1997-09-15 17:16:33.000000000 -0700 +++ glibc-2.1.3/hesiod/hesiod_p.h 1998-02-07 12:04:52.000000000 -0800 @@ -16,7 +16,7 @@ */ /* - * $Id: hesiod_p.h,v 1.1 1997/09/16 00:16:33 drepper Exp $ + * $Id: hesiod_p.h,v 1.1.1.1 1998/02/07 20:04:52 gafton Exp $ */ /* diff -Naur ../glibc-2.1.3/hurd/hurdmalloc.c glibc-2.1.3/hurd/hurdmalloc.c --- ../glibc-2.1.3/hurd/hurdmalloc.c 1996-12-19 17:32:01.000000000 -0800 +++ glibc-2.1.3/hurd/hurdmalloc.c 1998-02-07 12:05:05.000000000 -0800 @@ -37,6 +37,9 @@ /* * HISTORY * $Log: hurdmalloc.c,v $ + * Revision 1.1.1.1 1998/02/07 20:05:05 gafton + * import from sourceware + * * Revision 1.13 1996/12/20 01:32:01 drepper * Update from main archive 961219 * diff -Naur ../glibc-2.1.3/include/nlist.h glibc-2.1.3/include/nlist.h --- ../glibc-2.1.3/include/nlist.h 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/include/nlist.h 1998-02-07 12:07:02.000000000 -0800 @@ -0,0 +1 @@ +#include diff -Naur ../glibc-2.1.3/linuxthreads/Banner glibc-2.1.3/linuxthreads/Banner --- ../glibc-2.1.3/linuxthreads/Banner 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/Banner 1998-08-28 03:07:16.000000000 -0700 @@ -0,0 +1 @@ +linuxthreads-0.8 by Xavier Leroy diff -Naur ../glibc-2.1.3/linuxthreads/ChangeLog glibc-2.1.3/linuxthreads/ChangeLog --- ../glibc-2.1.3/linuxthreads/ChangeLog 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/ChangeLog 2000-02-23 13:17:31.000000000 -0800 @@ -0,0 +1,1257 @@ +2000-02-22 Ulrich Drepper + + * semaphore.h (SEM_FAILED): Use 0 not NULL. + +2000-02-14 Ulrich Drepper + + * condvar.c (pthread_cond_timedwait_relative_old): Tight loop with + nanosleep does not work either. Get absolute time inside the + loop. + (pthread_cond_timedwait_relative_new): Likewise. + Patch by Kaz Kylheku . + +2000-02-13 Ulrich Drepper + + * condvar.c (pthread_cond_timedwait_relative_old): Undo last patch + but keep the code around. A bug in the kernel prevent us from + using the code. + (pthread_cond_timedwait_relative_new): Likewise. + (PR libc/1597 and libc/1598). + +2000-02-01 Kaz Kylheku + + * condvar.c (pthread_cond_timedwait_relative_old): Do tight + loop around nanosleep calls instead of around most of the function + (pthread_cond_timedwait_relative_new): Likewise. + body. Got rid of backwards goto and one local. + +2000-01-31 Ulrich Drepper + + * condvar.c (pthread_cond_timedwait_relative_old): Recompute time + before every nanosleep call to account for time spent in the rest + of the function. + (pthread_cond_timedwait_relative_new): Likewise. + Patch by khendricks@ivey.uwo.ca (PR libc/1564). + +2000-01-29 Ulrich Drepper + + * condvar.c (pthread_cond_timedwait_relative_old): Get remaining time + from nanosleep call so that in case we restart we only wait for the + remaining time. + (pthread_cond_timedwait_relative_new): Likewise. + Patch by khendricks@ivey.uwo.ca (PR libc/1561). + +2000-01-18 Ulrich Drepper + + * manager.c (pthread_allocate_stack): Compute guard page address + correctly. Patch by HJ Lu. + +2000-01-12 Ulrich Drepper + + * internals.h (pthread_readlock_info): New structure. + (_pthread_descr_struct): Add p_readlock_list, p_readlock_free, and + p_untracked_readlock_count. + * pthread.c (__pthread_initial_thread, pthread_manager_thread): + Add initializers for new fields. + * manager.c (pthread_free): Free read/write lock lists. + * queue.h (queue_is_empty): New function. + * rwlock.c: Implement requirements about when readers should get + locks assigned. + * sysdeps/pthread/pthread.h + (PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP): New definition. + * sysdeps/pthread/bits/pthreadtypes.h (struct _pthread_rwlock_t): + Define this name as well. + Patches by Kaz Kylheku . + +2000-01-06 Andreas Jaeger + + * pthread.c: Remove extra initializer. + +2000-01-05 Ulrich Drepper + + * pthread.c (__pthread_initial_thread, pthread_manager_thread): + Adjust initializers for struct _pthread_descr_struct change. + * internals.h (struct _pthread_descr_struct): Move new elements to + the end. + +2000-01-03 Kaz Kylheku + + Redesigned how cancellation unblocks a thread from internal + cancellation points (sem_wait, pthread_join, + pthread_cond_{wait,timedwait}). + Cancellation won't eat a signal in any of these functions + (*required* by POSIX and Single Unix Spec!). + * condvar.c: Spontaneous wakeup on pthread_cond_timedwait won't eat a + simultaneous condition variable signal (not required by POSIX + or Single Unix Spec, but nice). + * spinlock.c: __pthread_lock queues back any received restarts + that don't belong to it instead of assuming ownership of lock + upon any restart; fastlock can no longer be acquired by two threads + simultaneously. + * restart.h: Restarts queue even on kernels that don't have + queued real time signals (2.0, early 2.1), thanks to atomic counter, + avoiding a rare race condition in pthread_cond_timedwait. + +1999-12-28 Ulrich Drepper + + * sysdeps/alpha/pt-machine.h: Move stack_pointer definition to the + beginning. + + * manager.c (__pthread_start): Add one more cast to assignment of + arg to prevent warning on 64bit machines. + +1999-12-21 Ulrich Drepper + + * manager.c (pthread_handle_create): Set p_pid of new thread + before calling the callback function to report a new thread. + +1999-12-20 Andreas Jaeger + + * pthread.c (pthread_initialize): Move getrlimit call after + setting of errno. + +1999-12-01 Ulrich Drepper + + * sysdeps/i386/pt-machine.h: Move stack_pointer definition to the + beginning. + * sysdeps/i386/i686/pt-machine.h: Likewise. + Patches by Alan Modra . + +1999-11-23 Ulrich Drepper + + * manager.c (pthread_start_thread_event): Initialize p_pid already + here. + +1999-11-22 Ulrich Drepper + + * internals.h: Add prototype for __pthread_manager_event. + * manager.c (__pthread_manager_event): New function. + (pthread_start_thread_event): Correct computation of self. + Use INIT_THREAD_SELF. + * pthread.c (__pthread_manager_thread): Initialize p_lock. + (__pthread_initialize_manager): Respect event flags also for creation + of the manager thread. + +1999-11-08 Ulrich Drepper + + * pthread.c (__pthread_initialize_manager): Initialize + __pthread_manager_thread.p_tid. + +1999-11-02 Ulrich Drepper + + * internals.h: Declare __pthread_last_event. + * manager.c: Define __pthread_last_event. + (pthread_handle_create): Set __pthread_last_event. + (pthread_exited): Likewise. + * join.c (pthread_exit): Likewise. + + * Makefile (libpthread-routines): Add events. + * events.c: New file. + * internals.h: Protect against multiple inclusion. + Include thread_dbP.h header. + (struct _pthread_descr_struct): Add new fields p_report_events and + p_eventbuf. + Declare event reporting functions. + * join.c (pthread_exit): Signal event if this is wanted. + * manager.c (__pthread_threads_events): New variable. + (pthread_handle_create): Take new parameters with event information. + Signal TD_CREATE event if wanted. + (__pthread_manager): Adjust pthread_handle_create call. + (pthread_start_thread_event): New function. Block until manager is + finished and then call pthread_start_thread. + (pthread_exited): Signal TD_REAP event if wanted. + +1999-10-26 Ulrich Drepper + + * restart.h (suspend_with_cancellation): Rewrite as a macro. + + * condvar.c (pthread_cond_timedwait_relative): Don't mark as inline. + +1999-10-21 Xavier Leroy + + * linuxthreads/pthread.c: For i386, wrap pthread_handle_sigrestart + and pthread_handle_sigcancel with functions that restore + %gs from the signal context. For each signal handling function, + two wrappers are required, one for a non-RT signal and one for + a RT signal. + * linuxthreads/signal.c: For i386, add code to restore %gs + from the signal context in pthread_sighandler and + pthread_sighandler_rt. + +1999-10-09 Andreas Jaeger + + * internals.h: Add __new_sem_post to get prototype in + manager.c; include semaphore.h for needed types. + +1999-10-08 Ulrich Drepper + + * manager.c (__pthread_manager) [REQ_POST]: Use __new_sem_post + directly instead of calling sem_post which should not be necessary + but is faster and might help in some case to work around problems. + +1999-09-25 Ulrich Drepper + + * condvar.c (pthread_cond_timedwait_relative): Never return with + EINTR. Patch by Andreas Schwab. + +1999-09-19 Ulrich Drepper + + * signals.c (sigaction): Correct last patch. Don't select + pthread_sighandler_rt based on the signal number but instead of + the SA_SIGINFO flag. + +1999-09-23 Ulrich Drepper + + * specific.c: Move definitions of struct pthread_key_struct and + destr_function to ... + * internals.h: ...here. + +1999-09-03 Andreas Schwab + + * ptfork.c (__fork): Renamed from fork and use __libc_fork. Add + fork as weak alias. + (__vfork): New function, alias vfork. + * Versions: Export __fork, vfork, and __vfork in libpthread. + +1999-08-23 Andreas Schwab + + * signals.c (pthread_sighandler): Add SIGCONTEXT_EXTRA_ARGS to + call to signal handler. + +1999-08-20 Ulrich Drepper + + * pthread.c (__pthread_reset_main_thread): Undo last change. + (__pthread_kill_other_threads_np): Reset signal handlers for the + signals we used in the thread implementation here. + +1999-08-19 Ulrich Drepper + + * pthread.c (__pthread_reset_main_thread): Reset signal handlers + for the signals we used in the thread implementation [PR libc/1234]. + + * Versions: Export __pthread_kill_other_threads_np from libpthread + for GLIBC_2.1.2. + + * signals.c: Pass sigcontext through wrapper to the user function. + +1999-08-01 Ulrich Drepper + + * Versions [ld.so] (GLIBC_2.0): Export __libc_internal_tsd_get and + __libc_internal_tsd_set. + +1999-07-29 Andreas Jaeger + + * manager.c: Remove inclusion of since it's not + needed anymore. + +1999-07-16 Andreas Jaeger + + * internals.h: Align _pthread_descr_struct to 32 bytes. + Reported by Tim Hockin , close PR libc/1206. + +1999-07-09 Ulrich Drepper + + * manager.c (pthread_handle_create): Free mmap region after stack + if clone failed. Patch by Kaz Kylheku . + +1999-07-09 Cristian Gafton + + * Makefile (libpthread-routines): Add oldsemaphore routine. + * Versions: Add sem_destroy, sem_getvalue, sem_init, sem_post, + sem_trywait, and sem_wait to GLIBC_2.1. + * oldsemaphore.c: New file. + * semaphore.c: Add default_symbol_versions for the changed functions. + (__new_sem_init): Rename from sem_init. + (__new_sem_post): Rename from sem_post. + (__new_sem_wait): Rename from sem_wait. + (__new_sem_trywait): Rename from sem_trywait. + (__new_sem_getvalue): Rename from sem_getvalue. + (__new_sem_destroy): Rename from sem_destroy. + +1999-06-23 Robey Pointer + + * internals.h: Added p_nextlock entry to separate queueing for a + lock from queueing for a CV (sometimes a thread queues on a lock + to serialize removing itself from a CV queue). + * pthread.c: Added p_nextlock to initializers. + * spinlock.c: Changed to use p_nextlock instead of p_nextwaiting. + +1999-05-23 Andreas Jaeger + + * man/pthread_cond_init.man: Correct example. + Reported by Tomas Berndtsson . + + * linuxthreads.texi (Condition Variables): Likewise. + +1999-05-18 Jakub Jelinek + + * sysdeps/sparc/sparc64/pt-machine.h (__compare_and_swap): Use + casx not cas, also successful casx returns the old value in rd + and not the new value. + +1999-05-16 Xavier Leroy + + * manager.c: If pthread_create() is given a NULL attribute + and the thread manager runs with a realtime policy, set the + scheduling policy of the newly created thread back to SCHED_OTHER. + * manager.c: If the PTHREAD_INHERIT_SCHED attribute is given, + initialize the schedpolicy field of new_thread->p_start_args + to that of the calling thread. + +1999-04-29 Ulrich Drepper + + * sysdeps/sparc/sparc64/pt-machine.h (__compare_and_swap): cas + instruction does not allow memory element to use offset. + +1999-04-28 Ulrich Drepper + + * manager.c (pthread_allocate_stack): Optimize initialization of new + thread descriptor. + + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_define_initialized): + Don't use initializer since it is all zeroes. + (__libc_once_define): Likewise. + +1999-04-16 Andreas Jaeger + + * sysdeps/arm/Implies: Removed since cmpxchg/no-cmpxchg + doesn't exist anymore. + * sysdeps/i386/Implies: Likewise. + * sysdeps/m68k/Implies: Likewise. + * sysdeps/mips/Implies: Likewise. + * sysdeps/powerpc/Implies: Likewise. + * sysdeps/sparc/sparc32/Implies: Likewise. + * sysdeps/sparc/sparc64/Implies: Likewise. + +1999-04-15 Ulrich Drepper + + * sysdeps/alpha/bits/semaphore.h: Removed. + * sysdeps/powerpc/bits/semaphore.h: Removed. + * sysdeps/pthread/cmpxchg/bits/semaphore.h: Removed. + * sysdeps/pthread/no-cmpxchg/bits/semaphore.h: Removed. + * Makefile (headers): Remove bits/semaphore.h. + + * semaphore.h: Define _pthread_descr if necessary. + Don't include limits.h. Define SEM_VALUE_MAX directly. + Define SEM_FAILED. + (sem_t): Protect element names with leading __. + Add declarations for sem_close, sem_open, and sem_unlink. + * semaphore.c: Adjust all functions for new element names. + Define sem_close, sem_open, and sem_unlink. + * Versions (libthread): Add sem_close, sem_open, and sem_unlink for + GLIBC_2.1.1. + * sysdeps/pthread/bits/pthreadtypes.h: Define _pthread_descr only if + necessary. + +1999-03-16 H.J. Lu + + * specific.c (pthread_key_delete): Check th->p_terminated to see + if the thread is running. + + * Versions (__libc_internal_tsd_get, __libc_internal_tsd_set): + Added to GLIBC_2.0 for libc.so. + +1999-02-12 H.J. Lu + + * Versions (__libc_current_sigrtmin, __libc_current_sigrtmax, + __libc_allocate_rtsig): Added to GLIBC_2.1. + + * internals.h (DEFAULT_SIG_RESTART): Removed. + (DEFAULT_SIG_CANCEL): Removed. + + * pthread.c (init_rtsigs, __libc_current_sigrtmin, + __libc_current_sigrtmax, __libc_allocate_rtsig): New functions. + (__pthread_sig_restart, __pthread_sig_cancel, + __pthread_sig_debug): Initialized. + (pthread_initialize): Call init_rtsigs () to initialize + real-time signals. + +1999-02-03 H.J. Lu + + * manager.c (__pthread_manager): Do block __pthread_sig_debug. + Don't restart the thread which sent REQ_DEBUG. + (pthread_start_thread): Check if __pthread_sig_debug > 0 + before debugging. + + * pthread.c (__pthread_initialize_manager): Suspend ourself + after sending __pthread_sig_debug to gdb instead of + __pthread_sig_cancel. + +1999-01-24 H.J. Lu + + * manager.c (__pthread_manager): Delete __pthread_sig_debug + from mask if __pthread_sig_debug > 0. + (pthread_handle_create): Increment __pthread_handles_num. + + * manager.c (pthread_handle_create): Don't pass CLONE_PTRACE to clone. + * pthread.c (__pthread_initialize_manager): Likewise. + + * pthread.c (pthread_initialize): Use __libc_allocate_rtsig (1) + instead of __libc_allocate_rtsig (2). + (__pthread_initialize_manager): Send __pthread_sig_debug to gdb + instead of __pthread_sig_cancel. + (pthread_handle_sigdebug): Fix comments. + +1999-01-21 Ulrich Drepper + + * manager.c (pthread_allocate_stack): Set + __pthread_nonstandard_stacks if user-specified stack is used. + +1999-01-16 Ulrich Drepper + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Add _LFS_ASYNCHRONOUS_IO, + _LFS_LARGEFILE, _LFS64_LARGEFILE, and _LFS64_STDIO from Unix98. + +1999-01-07 Xavier Leroy + + * pthread.c: Use a third signal __pthread_sig_debug distinct + from __pthread_sig_cancel to notify gdb when a thread is + created + * manager.c: Likewise. + * internals.h: Likewise. + * signals.c: The implementation of sigwait(s) assumed that + all signals in s have signal handlers already attached. + This is not required by the standard, so make it work + also if some of the signals have no handlers. + +1999-01-05 Andreas Schwab + + * linuxthreads.texi: Remove pointers from first @node. Move old + @node spec inside comment. + +1998-12-31 Ulrich Drepper + + * sysdeps/pthread/bits/stdio-lock.h: Define _IO_lock_lock and + _IO_lock_unlock. + +1998-12-29 Ulrich Drepper + + * semaphore.c (sem_trywait): Don't forget to unlock the semaphore + lock. Patch by Bernd Schmidt . + +1998-12-21 Ulrich Drepper + + * manager.c: Threads now send __pthread_sig_cancel on termination. + Change clone call and signal masks. + * thread.c (pthread_handle_sigrestart): Remove special code for + manager. + (pthread_handle_sigcancel): In manager thread call + __pthread_manager_sighandler. + * sysdeps/i386/pt-machine.h (__compare_and_swap): Add memory clobber. + * sysdeps/i386/i686/pt-machine.h: Likewise. + Patches by Xavier Leroy. + +1998-12-14 Ulrich Drepper + + * spinlock.c (__pthread_unlock): Don't crash if called for an + untaken mutex. Reported by Ruslan V. Brushkoff . + + * Examples/ex6.c: Unbuffer stdout and reduce sleep time to reduce + overall runtime. + +1998-12-13 Ulrich Drepper + + * Examples/ex3.c: Wait until all threads are started before + searching for the number to avoid race condition on very fast + systems. + +1998-12-08 Andreas Jaeger + + * sysdeps/pthread/pthread.h: Remove __pthread_setcanceltype + declaration since it's not needed. + + * sysdeps/pthread/pthread.h: Move internal functions to ... + * internals.h: ...here. + +1998-12-02 H.J. Lu + + * pthread.c (__pthread_sig_restart): Initiliaze to 0 if + SIGRTMIN is defined. + (__pthread_sig_cancel): Likewise. + +1998-12-01 Andreas Jaeger + + * wrapsyscall.c: Include for msync, + for system and for tcdrain prototype. + Correct msync declaration. + +1998-11-29 Roland McGrath + + * sysdeps/pthread/bits/libc-tsd.h (__libc_tsd_define, __libc_tsd_get, + __libc_tsd_set): New macros for new interface. + * no-tsd.c: New file, provide uninitialized defns of + __libc_internal_tsd_get and __libc_internal_tsd_set. + * Makefile (routines): Add no-tsd. + +1998-10-12 Roland McGrath + + * internals.h: Include , not . + * sysdeps/pthread/bits/libc-lock.h (__libc_internal_tsd_get, + __libc_internal_tsd_set): Move decls to ... + * sysdeps/pthread/bits/libc-tsd.h: New file for __libc_internal_tsd_* + declarations. + + * sysdeps/pthread/bits/libc-lock.h (__libc_internal_tsd_get, + __libc_internal_tsd_set): Make these pointers to functions, not + functions; remove #pragma weak decls for them. + * specific.c (__libc_internal_tsd_get, __libc_internal_tsd_set): + Define static functions and initialized pointers to them. + +1998-11-18 Ulrich Drepper + + * Makefile (CFLAGS-mutex.c): Define as -D__NO_WEAK_PTHREAD_ALIASES. + (CFLAGS-specific.c): Likewise. + (CFLAGS-pthread.c): Likewise. + (CFLAGS-ptfork.c): Likewise. + (CFLAGS-cancel.c): Likewise. + * sysdeps/pthread/bits/libc-lock.h: Don't mark __pthread_* functions + as weak references if __NO_WEAK_PTHREAD_ALIASES is defined. + + * mutex.c (pthread_mutex_init): Define as strong symbol. + (pthread_mutex_destroy): Likewise. + (pthread_mutex_trylock): Likewise. + (pthread_mutex_lock): Likewise. + (pthread_mutex_unlock): Likewise. + (pthread_mutexattr_init): Likewise. + (pthread_mutexattr_destroy): Likewise. + (pthread_once): Likewise. + * ptfork.c (pthread_atfork): Likewise. + * specific.c (pthread_key_create): Likewise. + (pthread_setspecific): Likewise. + (pthread_getspecific): Likewise. + +1998-11-15 Andreas Schwab + + * linuxthreads.texi: Fix punctuation after xref. + +1998-11-10 H.J. Lu + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Undefine NR_OPEN + if it is defined in . + +1998-10-29 14:28 Ulrich Drepper + + * spinlock.h (__pthread_trylock): Define inline. + (__pthread_lock): Add extra parameter to declaration. Declare + using internal_function. + (__pthread_unlock): Declare using internal_function. + * spinlock.c (__pthread_lock): Add new parameter. Use it instead + of local variable self. Avoid recomputing self. Define using + internal_function. + (__pthread_trylock): Remove. + (__pthread_unlock): Define using internal_function. + * cancel.c: Adjust for __pthread_lock interface change. Use already + computed self value is possible. + * condvar.c: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * rwlock.c: Likewise. + * semaphore.c: Likewise. + * signals.c: Likewise. + +1998-10-27 13:46 Ulrich Drepper + + * sysdeps/pthread/pthread.h (struct _pthread_cleanup_buffer): Prepend + __ to field names of the struct. + * sysdeps/pthread/bits/pthreadtypes.h (struct _pthread_fastlock): + Likewise. + (pthread_attr_t): Likewise. + (pthread_cond_t): Likewise. + (pthread_condattr_t): Likewise. + (pthread_mutex_t): Likewise. + (pthread_mutexattr_t): Likewise. + (pthread_rwlock_t): Likewise. + (pthread_rwlockattr_t): Likewise. + * attr.c: Adjust for pthread.h and pthreadtypes.h change. + * cancel.c: Likewise. + * condvar.c: Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * ptlongjmp.c: Likewise. + * rwlock.c: Likewise. + * spinlock.c: Likewise. + +1998-10-09 Ulrich Drepper + + * sysdeps/i386/pt-machine.h (get_eflags, set_eflags): Mark these + also with PT_EI. + + * sysdeps/i386/i686/pt-machine.h: Remove unused inline + definitions. + + * Makefile (libpthread-routines): Add pt-machine. + * pt-machine.c: New file. + * sysdeps/alpha/pt-machine.h: Define PT_EI as extern inline is not + yet defined. Use PT_EI in extern inline definitions. + * sysdeps/arm/pt-machine.h: Likewise. + * sysdeps/i386/pt-machine.h: Likewise. + * sysdeps/i386/i686/pt-machine.h: Likewise. + * sysdeps/m68k/pt-machine.h: Likewise. + * sysdeps/mips/pt-machine.h: Likewise. + * sysdeps/powerpc/pt-machine.h: Likewise. + * sysdeps/sparc/sparc32/pt-machine.h: Likewise. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +1998-10-02 Andreas Jaeger + + * semaphore.h: Include so that _pthread_descr + is declared. + +1998-09-15 David S. Miller + + * sysdeps/sparc/sparc32/pt-machine.h (INIT_THREAD_SELF): Add nr + argument. + * sysdeps/sparc/sparc64/pt-machine.h (INIT_THREAD_SELF): Likewise. + +1998-09-12 14:24 -0400 Zack Weinberg + + * linuxthreads/sysdeps/unix/sysv/linux/bits/sigthread.h: Add + multiple inclusion guard. + +1998-09-02 11:08 Andreas Schwab + + * signals.c (sigaction): Check that sig is less than NSIG to avoid + array index overflow. + +1998-09-06 10:56 Ulrich Drepper + + * sysdeps/pthread/semaphore.h: New file. + +1998-09-06 09:08 Ulrich Drepper + + * sysdeps/pthread/bits/libc-lock.h (enum __libc_tsd_key_t): Add + _LIBC_TSD_KEY_DL_ERROR. + +1998-08-31 Ulrich Drepper + + * sysdeps/i386/i686/pt-machine.h (testandset): Add memory clobber. + * sysdeps/i386/pt-machine.h: Likewise. + Suggested by Roland McGrath. + +1998-08-28 13:58 Ulrich Drepper + + * internals.h: Also define THREAD_GETMEM_NC and THREAD_SETMEM_NC to + access thread data with non-constant offsets. + * specific.c: Use THREAD_GETMEM_NC and THREAD_SETMEM_NC where + necessary. + + * sysdeps/i386/useldt.h: Fix typo. Add THREAD_GETMEM_NC and + THREAD_SETMEM_NC definitions. + + * sysdeps/sparc/sparc32/pt-machine.h: Define THREAD_GETMEM_NC and + THREAD_SETMEM_NC. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +1998-08-26 15:46 Ulrich Drepper + + * internals.h: Define THREAD_GETMEM and THREAD_SETMEM to default if + not already defined. + (struct _pthread_descr_struct): Add p_self and p_nr field. + * manager.c (__pthread_handles): Define second element to point + to manager thread. + (__pthread_handles_num): Initialize to 2. + (__pthread_manager): Use INIT_THREAD_SELF with two arguments. + (pthread_start_thread): Likewise. + (pthread_handle_create): Start search for free slot at entry 2. + Initialize new fields p_self and p_nr. + Call __clone with CLONE_PTRACE if available. + (pthread_free): Call FREE_THREAD_SELF if available. + * pthread.c (__pthread_initial_thread): Initialize new fields. + (__pthread_manager_thread): Likewise. + (__pthread_initialize_manager): Call __clone with CLONE_PTRACE. + + * cancel.c: Use THREAD_GETMEM and THREAD_SETMEM to access the + elements of the thread descriptor. + * condvar.c: Likewise. + * errno.c: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * pthread.c: Likewise. + * ptlongjmp.c: Likewise. + * semaphore.c: Likewise. + * signals.c: Likewise. + * specific.c: Likewise. + * spinlock.c: Likewise. + + * sysdeps/alpha/pt-machine.h (INIT_THREAD_SELF): Add extra parameter. + + * sysdeps/i386/useldt.h: New file. + * sysdeps/i386/i686/pt-machine.h: Show how to use this file. + + * sysdeps/sparc/sparc32/pt-machine.h: Define THREAD_GETMEM and + THREAD_SETMEM using __thread_self. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +1998-08-24 Geoff Keating + + * spinlock.c (__pthread_lock): Reset p_nextwaiting to NULL if it + turned out that we didn't need to queue after all. + +1998-08-22 Geoff Keating + + * sysdeps/powerpc/pt-machine.h: Remove testandset, it's not used + and wastes space; correct types. + +1998-08-08 11:18 H.J. Lu + + * signals.c (sigaction): Handle NULL argument. + +1998-08-04 Ulrich Drepper + + * sysdeps/unix/sysv/linux/bits/sigthread.h: Use __sigset_t instead + of sigset_t. + +1998-08-02 Andreas Schwab + + * Makefile (linuxthreads-version): Extract correct number from + Banner. + +1998-07-29 Xavier Leroy + + * Banner: Bump version number to 0.8 + * FAQ.html: Many updates, in particular w.r.t. debugging. + * manager.c: Support for non-default stacksize for + LinuxThreads-allocated stacks; + don't use guard pages for stacks with default size, rely on + rlimit(RLIMIT_STACK) instead (it's cheaper). + * attr.c: Likewise. + * cancel.c: Use __pthread_sig_cancel and __pthread_sig_restart + everywhere instead of PTHREAD_SIG_CANCEL and PTHREAD_SIG_RESTART. + * condvar.c: Likewise. + * internals.h: Likewise. + * restart.h: Likewise. + * signals.c: Likewise. + * pthread.c: Likewise; set rlimit(RLIMIT_STACK) as we need it. + +1998-07-23 Andreas Schwab + + * weaks.c: Define pthread_mutexattr_[sg]ettype instead of + __pthread_mutexattr_[sg]ettype. Add more weak aliases. + * Versions: Put __pthread_mutexattr_settype under version + GLIBC_2.0. Don't export __pthread_mutexattr_setkind_np and + __pthread_mutexattr_gettype. + +1998-07-23 Andreas Schwab + + * sysdeps/pthread/bits/libc-lock.h: Make + __pthread_mutexattr_settype weak. Don't make + __pthread_mutexattr_setkind_np weak. + +1998-07-16 10:52 Ulrich Drepper + + * manager.c (pthread_handle_create): Check whether sched_setscheduler + call can succeed here. + + * mutex.c: Define __pthread_mutexattr_settype and make + __pthread_mutexattr_setkind_np an alias. + Likewise for __pthread_mutexattr_gettype. + +1998-07-15 11:00 -0400 Zack Weinberg + + * attr.c (pthread_attr_setschedpolicy): Don't check whether caller + is root. + +1998-07-14 19:38 Ulrich Drepper + + * sysdeps/pthread/bits/libc-lock.h: Define __libc_cleanup_end. + +1998-07-11 Andreas Jaeger + + * Examples/ex6.c: Include for usleep. + +1998-06-13 11:04 Andreas Schwab + + * Examples/ex4.c (main): Use exit, not pthread_exit. + +1998-07-09 13:39 Ulrich Drepper + + * Versions: Add __pthread_mutexattr_gettype and + __pthread_mutexattr_settype. + * lockfile.c: Use __pthread_mutexattr_settype instead of + __pthread_mutexattr_setkind_np. + * mutex.c: Define __pthread_mutexattr_gettype and + __pthread_mutexattr_settype. + * weak.c: Likewise. + * sysdeps/pthread/pthread.h: Declare __pthread_mutexattr_gettype and + __pthread_mutexattr_settype. + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_init_recursive): + Use __pthread_mutexattr_settype. + +1998-07-08 22:26 Ulrich Drepper + + * Versions: Add pthread_mutexattr_gettype, pthread_mutexattr_settype. + * mutex.c: Define weak alias pthread_mutexattr_gettype and + pthread_mutexattr_settype. + * sysdeps/pthread/pthread.h: Declare these functions. + Move pthread_sigmask and pthread_kill declaration in separate header. + * sysdeps/unix/sysv/linux/bits/sigthread.h: New file. + +1998-07-07 15:20 Ulrich Drepper + + * Makefile: Add rules to compile and run tests. + * Examples/ex1.c: Little changes to fix warnings. + * Examples/ex2.c: Likewise. + * Examples/ex3.c: Likewise. + * Examples/ex4.c: Likewise. + * Examples/ex5.c: Likewise. + * Examples/ex6.c: New file. + +1998-07-05 11:54 Ulrich Drepper + + * Versions: Add pthread_attr_init to GLIBC_2.1 version in libc. + +1998-07-01 Andreas Jaeger + + * attr.c: Include . + +1998-06-30 11:47 Ulrich Drepper + + * attr.c: Include errno.h. Use memcpy to copy sched_param. + * internals.h: Include limits.h. + * manager.c: Use memcpy to copy sched_param. + * ptfork.c: Include errno.h. + * pthread.c: Likewise. + * semaphore.c: Likewise. + * specific.c: Likewise. + * spinlock.h: Likewise. + * sysdeps/pthread/pthread.h: Include only allowed headers. Move + type definition to ... + * sysdeps/pthread/bits/pthreadtypes.h: ...here. New file. + +1998-06-29 12:34 Ulrich Drepper + + * sysdeps/pthread/pthread.h: Use __PMT not __P for function pointers. + + * sysdeps/pthread/pthread.h: Define various PTHREAD_* symbols also + as macros as demanded in POSIX.1, Annex C. + +1998-06-29 12:29 Ulrich Drepper + + * internals.h (struct pthread_request): For free use pthread_t + instead of pthread_descr. + * join.c (pthread_join): Pass thread_id, not th to manager. + (pthread_detach): Likewise. + * manager.c (__pthread_manager): Except thread ID in FREE_REQ case. + (pthread_exited): Remove detached queue code. + (pthread_handle_free): Expect thread ID parameter and use it to + validate the thread decsriptor. Don't use detached queue. + Patches by Xavier Leroy. + +1998-06-27 Andreas Schwab + + * libpthread.map: Export accept, longjmp, sigaction, siglongjmp, + _IO_flockfile, _IO_ftrylockfile, _IO_funlockfile, + __pthread_atfork, __pthread_key_create, __pthread_once. + * internals.h: Doc fix. + * pthread.c (__pthread_initialize): Define again. + +1998-06-26 Ulrich Drepper + + * manager.c (pthread_exited): If thread is not detached put it on + special list. + (pthread_handle_free): If thread is not on list with living threads + search on list with detached threads. + + * sysdeps/pthread/pthread.h (PTHREAD_RWLOCK_INITIALIZER): Correct + for new definition of pthread_rwlock_t. + + * spinlock.c: Correct test whether to compile + __pthread_compare_and_swap or not. + +1998-06-25 19:27 Ulrich Drepper + + * attr.c: Finish user stack support. Change locking code to be safe + in situations with different priorities. + * cancel.c: Likewise. + * condvar.c: Likewise. + * internals.h: Likewise. + * join.c: Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * ptlongjmp.c: Likewise. + * queue.h: Likewise. + * rwlock.c: Likewise. + * semaphore.c: Likewise. + * semaphore.h: Likewise. + * signals.c: Likewise. + * spinlock.c: Likewise. + * spinlock.h: Likewise. + * sysdeps/pthread/pthread.h: Likewise. + Patches by Xavier Leroy. + + * sysdeps/i386/i686/pt-machine.h: New file. + +1998-06-25 Ulrich Drepper + + * sysdeps/pthread/pthread.h: Make [sg]et_stacksize and + [sg]et_stackaddr prototypes always available. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_THREAD_ATTR_STACKSIZE and _POSIX_THREAD_ATTR_STACKADDR. + +1998-06-24 Ulrich Drepper + + * manager.c (pthread_free): Undo patch from 980430. + Reported by David Wragg . + +1998-06-09 15:07 Ulrich Drepper + + * manager.c: Define __pthread_manager_adjust_prio and use it to + increase priority when needed. + * internals.h: Add prototype for __pthread_manager_adjust_prio. + * mutex.c: Optimize mutexes to wake up only one thread. + * pthread.c: Move PID of manager for global variable in structure + element. + Patches by Xavier Leroy. + +1998-06-07 13:47 Ulrich Drepper + + * sysdeps/pthread/bits/libc-lock.h: Optimize cleanup handlers a bit. + +1998-06-03 Andreas Jaeger + + * attr.c: Correct typo. + +1998-05-01 Ulrich Drepper + + * manager.c (pthread_free): Unmap guard before the stack. + Patch by Matthias Urlichs. + +1998-04-30 Ulrich Drepper + + * manager.c (pthread_free): Detect already free child. + Patch by Xavier Leroy, reported by Matthias Urlichs. + +1998-04-23 Andreas Schwab + + * Makefile (linuxthreads-version): Renamed back from + libpthread-version. + +1998-04-21 Ulrich Drepper + + * ptlongjmp.c: Add prototypes for __libc_siglongjmp and + __libc_longjmp. + +1998-04-20 14:55 Ulrich Drepper + + * Makefile (libpthread-routines): Add ptlongjmp and spinlock. + * internals.h: Add definitions for new spinlock implementation. + * ptlongjmp.c: New file. + * spinlock.c: New file. + * spinlock.h (acquire): Don't reschedule using __sched_yield, use + new function __pthread_acquire to prevent deadlocks with thread + with different priorities. + Patches by Xavier Leroy . + +1998-03-16 Andreas Schwab + + * manager.c (__pthread_manager): Reduce first argument to select + to include just the needed file descriptor. + +1998-03-17 00:06 Ulrich Drepper + + * manager.c: Fix last patch which caused core dumps. + + * pthread.c: Correctly handle missing SIGRTMIN. + +1998-03-15 Andreas Schwab + + * libpthread.map: Add __libc_internal_tsd_get and + __libc_internal_tsd_set. Add missing cancelable functions. Export + libc internal versions of the cancelable functions. + +1998-03-13 16:51 Ulrich Drepper + + * weaks.c: Define pthread_attr_init as GLIBC_2.0 and GLIBC_2.1. + +1998-03-13 00:46 Ulrich Drepper + + * attr.c: Implement pthread_attr_[gs]etguardsize, + pthread_attr_[gs]setstackaddr, pthread_attr_[gs]etstacksize. + Change pthread_attr_init to have two interfaces. + * internals.h (struct _pthread_descr_struct): Add new fields for + above functions. + * libpthread.map: Add names in GLIBC_2.1 section. + * manager.c (pthread_handle_create): Implement guardsize and + user stack. + (pthread_free): Likewise. + * pthread.c (pthread_create): Add new interface for changed + pthread_attr_t. + * sysdeps/pthread/pthread.h: Add prototypes for new functions. + * sysdeps/unix/sysv/linux/bits/local_lim.h: Add definition of + PTHREAD_STACK_MIN. + +1998-03-11 00:42 Wolfram Gloger + + * manager.c: Enable resetting of the thread scheduling policy + to SCHED_OTHER when the parent thread has a different one. + +1998-02-01 13:51 Ulrich Drepper + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_ASYNCHRONOUS_IO. + + * sysdeps/pthread/pthread.h: Define bits for Unix98 variants of + mutexes. + * mutex.c: Implement new mutex types. + + * internals.h: Include . + + * libpthread.map: Add __erno_location and __h_errno_location. + + * errno.c: Return pointer to variable actually in use. This might + not be the one in the thread structure. + * internals.h (struct _pthread_descr_struct): Add new fields p_errnop + and p_h_errnop. + * manager.c (__pthread_manager): Set p_errnop and p_h_errnop member + of manager thread structure. + (pthread_handle_create): Set p_errnop and p_h_errnop members for new + thread. + * pthread.c: Adapt initializer for thread structures. + (__pthread_initial_thread): Set p_errnop and p_h_errnop member. + (__pthread_reset_main_thread): Reset p_errnop and p_h_errnop of + current thread to global variables. + +1998-01-31 17:27 Ulrich Drepper + + * rwlock.c: New file. + * Makefile (libpthread-routines): Add rwlock. + * sysdeps/pthread/pthread.h: Define data structures and declare + functions. + * libpthread.map: Add new functions. + +1997-12-18 13:50 Philip Blundell + + * sysdeps/arm/pt-machine.h: New file; add ARM support. + * sysdeps/arm/Implies: likewise. + * README: Document it. + +1997-12-13 Andreas Schwab + + * signals.c: Remove unneeded initializer for sigwaited, saving a + warning. + +1997-04-11 01:18 Andreas Schwab + + * semaphore.c (sem_init): Set sem_spinlock only if available. + +1997-12-04 01:48 Ulrich Drepper + + * mutex.c: Implement PTHREAD_MUTEX_CHECKERROR. + * sysdeps/pthread/pthread.h: Define PTHREAD_MUTEX_CHECKERROR. + + * Makefile: Update from LinuxThreads 0.7. + * internals.h. Likewise. + * manager.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * signals.c: Likewise. + * specific.c: Likewise. + * Examples/ex3.c: Likewise. + +1997-11-20 18:13 Ulrich Drepper + + * pthread.c (__pthread_reset_main_thread): Close pipe only if still + open. + +1997-10-29 05:38 Ulrich Drepper + + * wrapsyscall.c: Add socket functions which are also cancelation + points. + +1997-10-19 21:40 Wolfram Gloger + + * specific.c (__libc_internal_tsd_set, __libc_internal_tsd_get): + New functions for fast thread specific data within libc. + + * internals.h: Add new array p_libc_specific to struct + _pthread_descr_struct. + + * sysdeps/pthread/bits/libc-lock.h: Declare new functions. + +1997-10-13 05:39 Ulrich Drepper + + * semaphore.h: Add __BEGIN_DECLS/__END_DECLS. + Reported by Ralf Corsepius . + +1997-08-29 03:05 Ulrich Drepper + + * internals.h (struct _pthread_descr_struct): Add definitions for + two-level specific key handling. + * manager.c (pthread_handle_create): Initialize specific memory array. + * specific.c: Implement two-level key handling. + * weaks.c: Don't provide dummy key handling. + * sysdeps/pthread/bits/libc-lock.h: Typedef __libc_lock_t (no #define). + Add definition of __libc_key_t. + * sysdeps/unix/sysv/linux/bits/local_lim.h: Define PTHREAD_KEYS_MAX + as 1024. + Add definition of _POSIX_THREAD_DESTRUCTOR_ITERATIONS and + PTHREAD_DESTRUCTOR_ITERATIONS. + + * manager.c (pthread_handle_create): Compare mmap result with + MAP_FAILED. + + * ptfork.c: Rename to __pthread_atfork and make old name a weak alias. + * sysdeps/pthread/bits/pthread.h: Add prototype for __pthread_atfork. + +1997-08-22 19:04 Richard Henderson + + sysdeps/sparc -> sysdeps/sparc/sparc32 + sysdeps/sparc64 -> sysdeps/sparc/sparc64 + + * internals.h: Change definition of THREAD_SELF to be an expression, + not a statement that did a return. + * sysdeps/alpha/pt-machine.h (THREAD_SELF): Update accordingly. + * sysdeps/sparc/sparc32/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF): + Follow Solaris and use a "system reserved" register (%g6) to hold + the thread descriptor. + * sysdeps/sparc/sparc64/pt-machine.h: Likewise. + +1997-08-03 00:09 Ulrich Drepper + + * mutex.c: Correct pthread_once. Patch by Xavier Leroy. + * sysdeps/pthread/pthread.h: Add prototype for __pthread_once. + * sysdeps/pthread/bits/pthread.h: Add macros for __libc_once. + + * semaphore.c: Include spinlock.h only when needed. + + * specific.c (__pthread_setsepcific, __pthread_getspecific): Reject + keys for entries not in use. + + * weaks.c: Implement key handling functions for real. + +1997-06-29 01:04 Richard Henderson + + Initial sparc64-linux support: + * linuxthreads/sysdeps/sparc64/Implies: New file. + * linuxthreads/sysdeps/sparc64/pt-machine.h: Likewise. + +1997-06-29 00:48 Ulrich Drepper + + * semaphore.c: Include spinlock.h at correct place. + Patch by HJ Lu. + +1997-06-13 10:06 Richard Henderson + + The Great Bit File Move: + * sysdeps/alpha/semaphorebits.h: -> .../bits/semaphore.h. + * sysdeps/powerpc/semaphorebits.h: Likewise. + * sysdeps/pthread/cmpxchg/semaphorebits.h: Likewise. + * sysdeps/pthread/no-cmpxchg/semaphorebits.h: Likewise. + * sysdeps/pthread/libc-lock.h: -> bits/ + * sysdeps/pthread/stdio-lock.h: Likewise. + * sysdeps/unix/sysv/linux/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/posix_opt.h: Likewise. + * semaphore.h: Likewise. + * sysdeps/pthread/pthread.h: Likewise. + + * lockfile.c: -> . + * semaphore.h: Likewise. + + * Makefile: (headers): foo.h -> bits/foo.h. + * sysdeps/pthread/Makefile: Likewise. + +1997-04-11 01:18 Andreas Schwab + + * semaphore.c (sem_init): Set sem_spinlock only if available. + + * sysdeps/m68k/pt-machine.h (testandset, __compare_and_swap): Fix + asm constraints. + +1997-04-09 03:00 Ulrich Drepper + + Update from LinuxThreads 0.6. + + * attr.c (pthread_attr_getdetachstate): Use __sched_get_priority_max + and __sched_get_priority_min instead of names without `__'. + + * manager.c: Rewrite large parts to implement opaque pthread_t. + + * cancel.c: Adapt for opaque pthread_t type. + * condvar.c: Likewise. + * errno.c: Likewise. + * join.c: Likewise. + * mutex.c: Likewise. + * pthread.c: Likewise. + * signals.c: Likewise. + * specific.c: Likewise. + * restart.h: Likewise. + * queue.h: Likewise. + * Examples/ex3.c: Likewise. + * Examples/ex4.c: Likewise. + * sysdeps/pthread/pthread.h: Likewise. + + * pthread.c: Accumulate time for all threads in thread manager. + + * semaphore.c: Implement fallback implementation for architectures + sometimes missing compare-exchange operations. + + * cancel.c (pthread_cancel): Validate handle argument. + * join.c (pthread_join): Likewise. + (pthread_detach): Likewise. + * signals.c (pthread_kill): Likewise. + + * spinlock.h (acquire): Use __sched_yield not sched_yield. + + * queue.h (enqueue): Enqueue thread according to priority. + + * internals.c (struct pthread_start_args): New struct for passing + args to cloning function. + (struct _pthread): Rename to _pthread_descr_struct and adapt for + opaque pthread_t. + + * Examples/Makefile (clean): Pass -f option to rm. + + * sysdeps/i386/pt-machine.h: Add check for compare-exchange instruction + and define TEST_FOR_COMPARE_AND_SWAP. + * sysdeps/i386/i486/pt-machine.h: Removed. + + * sysdeps/unix/sysv/linux/local_lim.h (PTHREAD_THREADS_MAX): Increase + to 1024. + +1997-04-04 16:38 Ulrich Drepper + + * restart.h (suspend): Clear p_signal before suspending. + (suspend_with_cancellation): Likewise. + Patch by Xavier Leroy . + + * weaks.c: Make __pthread_key_create return 1. + * sysdeps/pthread/libc-lock.h: Define __libc_key_create, + __libc_getspecific, __libc_setspecific, and __libc_key_t. + * sysdeps/pthread/stdio-lock.h: Don't care for implementation not + using libio. + +1997-03-19 15:13 Miguel de Icaza + + * sysdeps/sparc/pt-machine (RELEASE): Fix. + +1997-03-01 07:55 Geoff Keating + + * sysdeps/powerpc/Implies: Added. + * sysdeps/powerpc/pt-machine.h: Added. + * sysdeps/powerpc/semaphorebits.h: Added. + +1997-01-22 01:22 Ulrich Drepper + + * linuxtheads/pthread.c (__pthread_initial_thread): Correct + initializer. + (__pthread_manager_thread): Likewise. + Reported by Andreas Jaeger. + +1997-01-18 22:15 Richard Henderson + + Since sigset_t no longer fits in a register, we can't pass in the + thread's initial mask so easily. Take this opportunity to simplify + the clone implementation by only accepting a single void* argument. + + * linuxthreads/manager.c (__pthread_manager): Put thread vitals + in the thread struct instead of as arguments through clone. + (pthread_start_thread): Look for them there. + * linuxthreads/internals.h (struct _pthread): Add p_initial_fn, + p_initial_fn_arg, p_initial_mask. Fix __pthread_manager proto. + * linuxthreads/pthread.c (pthread_initialize_manager): Revise + clone invocation. diff -Naur ../glibc-2.1.3/linuxthreads/Changes glibc-2.1.3/linuxthreads/Changes --- ../glibc-2.1.3/linuxthreads/Changes 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/Changes 1998-08-28 03:07:17.000000000 -0700 @@ -0,0 +1,73 @@ +Release 0.7: +- Destructors for thread-specific data now conform to the POSIX semantics + (call destructors again if non-NULL TSD remains after a round of + destruction). +- Implemented thread-specific data as a sparse array, allows more TSD keys + and smaller thread descriptors (Ulrich Drepper). +- Added "error checking" mutexes. +- Protect against multiple sigwait() on the same signals. +- Simplified implementation of semaphores when compare_and_swap is + not available. +- Fixed bug in fork() where stdin was closed if fork() was called before + the first pthread_create(). +- Fixed bug in the gethostby*_r functions (bad result if null bytes + in addresses). +- Typos in manual pages corrected. +- First cut at a PowerPC port (not working yet, runs into problems + with gcc and with the C library). + +Release 0.6: +- Validation of thread identifiers: no more crashes when operating on + a thread that has exited (based on Pavel Krauz's ideas). +- Added fallback implementation of semaphores for the 386 and the + Sparc. +- Fixed a bug in signal handling causing false restarts of suspended + threads. +- Fixed a bug in realtime scheduling causing all threads to have + default scheduling on Ix86 with libc5. +- With realtime scheduling, unlocking a mutex now restarts the + highest priority thread waiting on the mutex, not the + first-suspended thread (Richard Neitzel). +- Timing a process now returns cumulative times for all threads, not + just times for the initial thread (suggested by Wolfram Gloger). +- Cleaned up name space (internal defs prefixed by __, weak aliases + for non-portable extensions). +- MIPS port (contributed by Ralf Baechle). + +Release 0.5: +- Signal-safe semaphores a la POSIX 1003.1b added. +- Locking bug in pthread_mutex_trylock over recursive mutexes fixed. +- Race conditions in thread cancellation fixed. +- Sparc port (contributed by Miguel de Icaza). +- Support for getpwnam_r and getpwuid_r. +- Added pthread_kill_other_threads_np to be used in conjunction with + exec*(). + +Release 0.4: +- Manual pages for all functions. +- Synchronization bug causing accumulation of zombie processes fixed. +- Race condition in pthread_cond_timedwait fixed. +- Recursive mutexes are back by popular demand. +- Partial support for realtime scheduling (initiated by Richard Neitzel). +- pthread.h cleaned up a lot: now C++ compatible, added missing "const" + qualifiers, added short documentation, put to GNU libc standards + for name space pollution (Ulrich Drepper). +- Motorola 68k port (contributed by Andreas Schwab). +- Interaction with fork(2) cleaned up a lot. + +Release 0.3: +- Thread creation and reclaimation now performed by a centralized + "thread manager" thread. +- Removed recursive mutexes to make regular mutexes more efficient. +- Now available as a shared library (contributed by Richard Henderson). +- Alpha port (contributed by Richard Henderson). +- Fixed many small discrepancies with Posix 1003.1c. +- Put under the LGPL instead of the GPL. + +Release 0.2: +- Reentrant libc functions (adapted from libc 5.3.9 by Peeter Joot) +- pthread_cond_wait did not reacquire the mutex correctly on return +- More efficient pthread_cond_broadcast + +Release 0.1: +- First public release diff -Naur ../glibc-2.1.3/linuxthreads/Examples/Makefile glibc-2.1.3/linuxthreads/Examples/Makefile --- ../glibc-2.1.3/linuxthreads/Examples/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/Examples/Makefile 1998-08-28 03:07:19.000000000 -0700 @@ -0,0 +1,15 @@ +CC=gcc +CFLAGS=-g -O -Wall -I.. -D_REENTRANT +LIBPTHREAD=../libpthread.a + +PROGS=ex1 ex2 ex3 ex4 ex5 proxy + +all: $(PROGS) + +.c: + $(CC) $(CFLAGS) -o $* $*.c $(LIBPTHREAD) + +$(PROGS): + +clean: + rm -f $(PROGS) diff -Naur ../glibc-2.1.3/linuxthreads/Examples/ex1.c glibc-2.1.3/linuxthreads/Examples/ex1.c --- ../glibc-2.1.3/linuxthreads/Examples/ex1.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/Examples/ex1.c 1998-08-28 03:07:19.000000000 -0700 @@ -0,0 +1,35 @@ +/* Creates two threads, one printing 10000 "a"s, the other printing + 10000 "b"s. + Illustrates: thread creation, thread joining. */ + +#include +#include +#include +#include "pthread.h" + +void * process(void * arg) +{ + int i; + fprintf(stderr, "Starting process %s\n", (char *) arg); + for (i = 0; i < 10000; i++) { + write(1, (char *) arg, 1); + } + return NULL; +} + +int main(void) +{ + int retcode; + pthread_t th_a, th_b; + void * retval; + + retcode = pthread_create(&th_a, NULL, process, (void *) "a"); + if (retcode != 0) fprintf(stderr, "create a failed %d\n", retcode); + retcode = pthread_create(&th_b, NULL, process, (void *) "b"); + if (retcode != 0) fprintf(stderr, "create b failed %d\n", retcode); + retcode = pthread_join(th_a, &retval); + if (retcode != 0) fprintf(stderr, "join a failed %d\n", retcode); + retcode = pthread_join(th_b, &retval); + if (retcode != 0) fprintf(stderr, "join b failed %d\n", retcode); + return 0; +} diff -Naur ../glibc-2.1.3/linuxthreads/Examples/ex2.c glibc-2.1.3/linuxthreads/Examples/ex2.c --- ../glibc-2.1.3/linuxthreads/Examples/ex2.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/Examples/ex2.c 1998-08-28 03:07:19.000000000 -0700 @@ -0,0 +1,113 @@ +/* The classic producer-consumer example. + Illustrates mutexes and conditions. + All integers between 0 and 9999 should be printed exactly twice, + once to the right of the arrow and once to the left. */ + +#include +#include "pthread.h" + +#define BUFFER_SIZE 16 + +/* Circular buffer of integers. */ + +struct prodcons { + int buffer[BUFFER_SIZE]; /* the actual data */ + pthread_mutex_t lock; /* mutex ensuring exclusive access to buffer */ + int readpos, writepos; /* positions for reading and writing */ + pthread_cond_t notempty; /* signaled when buffer is not empty */ + pthread_cond_t notfull; /* signaled when buffer is not full */ +}; + +/* Initialize a buffer */ + +void init(struct prodcons * b) +{ + pthread_mutex_init(&b->lock, NULL); + pthread_cond_init(&b->notempty, NULL); + pthread_cond_init(&b->notfull, NULL); + b->readpos = 0; + b->writepos = 0; +} + +/* Store an integer in the buffer */ + +void put(struct prodcons * b, int data) +{ + pthread_mutex_lock(&b->lock); + /* Wait until buffer is not full */ + while ((b->writepos + 1) % BUFFER_SIZE == b->readpos) { + pthread_cond_wait(&b->notfull, &b->lock); + /* pthread_cond_wait reacquired b->lock before returning */ + } + /* Write the data and advance write pointer */ + b->buffer[b->writepos] = data; + b->writepos++; + if (b->writepos >= BUFFER_SIZE) b->writepos = 0; + /* Signal that the buffer is now not empty */ + pthread_cond_signal(&b->notempty); + pthread_mutex_unlock(&b->lock); +} + +/* Read and remove an integer from the buffer */ + +int get(struct prodcons * b) +{ + int data; + pthread_mutex_lock(&b->lock); + /* Wait until buffer is not empty */ + while (b->writepos == b->readpos) { + pthread_cond_wait(&b->notempty, &b->lock); + } + /* Read the data and advance read pointer */ + data = b->buffer[b->readpos]; + b->readpos++; + if (b->readpos >= BUFFER_SIZE) b->readpos = 0; + /* Signal that the buffer is now not full */ + pthread_cond_signal(&b->notfull); + pthread_mutex_unlock(&b->lock); + return data; +} + +/* A test program: one thread inserts integers from 1 to 10000, + the other reads them and prints them. */ + +#define OVER (-1) + +struct prodcons buffer; + +void * producer(void * data) +{ + int n; + for (n = 0; n < 10000; n++) { + printf("%d --->\n", n); + put(&buffer, n); + } + put(&buffer, OVER); + return NULL; +} + +void * consumer(void * data) +{ + int d; + while (1) { + d = get(&buffer); + if (d == OVER) break; + printf("---> %d\n", d); + } + return NULL; +} + +int main(void) +{ + pthread_t th_a, th_b; + void * retval; + + init(&buffer); + /* Create the threads */ + pthread_create(&th_a, NULL, producer, 0); + pthread_create(&th_b, NULL, consumer, 0); + /* Wait until producer and consumer finish. */ + pthread_join(th_a, &retval); + pthread_join(th_b, &retval); + return 0; +} diff -Naur ../glibc-2.1.3/linuxthreads/Examples/ex3.c glibc-2.1.3/linuxthreads/Examples/ex3.c --- ../glibc-2.1.3/linuxthreads/Examples/ex3.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/Examples/ex3.c 1998-12-14 08:09:39.000000000 -0800 @@ -0,0 +1,152 @@ +/* Multi-thread searching. + Illustrates: thread cancellation, cleanup handlers. */ + +#include +#include +#include +#include +#include +#include + +/* Defines the number of searching threads */ +#define NUM_THREADS 5 + +/* Function prototypes */ +void *search(void *); +void print_it(void *); + +/* Global variables */ +pthread_t threads[NUM_THREADS]; +pthread_mutex_t lock; +int tries; +volatile int started; + +int main(int argc, char ** argv) +{ + int i; + int pid; + + /* create a number to search for */ + pid = getpid(); + printf("Searching for the number = %d...\n", pid); + + /* Initialize the mutex lock */ + pthread_mutex_init(&lock, NULL); + + /* Create the searching threads */ + for (started=0; started +#include +#include +#include +#include + +/* This is a typical example of a library function that uses + static variables to accumulate results between calls. + Here, it just returns the concatenation of all string arguments + that were given to it. */ + +#if 0 + +char * str_accumulate(char * s) +{ + static char accu[1024] = { 0 }; + strcat(accu, s); + return accu; +} + +#endif + +/* Of course, this cannot be used in a multi-threaded program + because all threads store "accu" at the same location. + So, we'll use thread-specific data to have a different "accu" + for each thread. */ + +/* Key identifying the thread-specific data */ +static pthread_key_t str_key; +/* "Once" variable ensuring that the key for str_alloc will be allocated + exactly once. */ +static pthread_once_t str_alloc_key_once = PTHREAD_ONCE_INIT; + +/* Forward functions */ +static void str_alloc_key(void); +static void str_alloc_destroy_accu(void * accu); + +/* Thread-safe version of str_accumulate */ + +char * str_accumulate(const char * s) +{ + char * accu; + + /* Make sure the key is allocated */ + pthread_once(&str_alloc_key_once, str_alloc_key); + /* Get the thread-specific data associated with the key */ + accu = (char *) pthread_getspecific(str_key); + /* It's initially NULL, meaning that we must allocate the buffer first. */ + if (accu == NULL) { + accu = malloc(1024); + if (accu == NULL) return NULL; + accu[0] = 0; + /* Store the buffer pointer in the thread-specific data. */ + pthread_setspecific(str_key, (void *) accu); + printf("Thread %lx: allocating buffer at %p\n", pthread_self(), accu); + } + /* Now we can use accu just as in the non thread-safe code. */ + strcat(accu, s); + return accu; +} + +/* Function to allocate the key for str_alloc thread-specific data. */ + +static void str_alloc_key(void) +{ + pthread_key_create(&str_key, str_alloc_destroy_accu); + printf("Thread %lx: allocated key %d\n", pthread_self(), str_key); +} + +/* Function to free the buffer when the thread exits. */ +/* Called only when the thread-specific data is not NULL. */ + +static void str_alloc_destroy_accu(void * accu) +{ + printf("Thread %lx: freeing buffer at %p\n", pthread_self(), accu); + free(accu); +} + +/* Test program */ + +void * process(void * arg) +{ + char * res; + res = str_accumulate("Result of "); + res = str_accumulate((char *) arg); + res = str_accumulate(" thread"); + printf("Thread %lx: \"%s\"\n", pthread_self(), res); + return NULL; +} + +int main(int argc, char ** argv) +{ + char * res; + pthread_t th1, th2; + + res = str_accumulate("Result of "); + pthread_create(&th1, NULL, process, (void *) "first"); + pthread_create(&th2, NULL, process, (void *) "second"); + res = str_accumulate("initial thread"); + printf("Thread %lx: \"%s\"\n", pthread_self(), res); + pthread_join(th1, NULL); + pthread_join(th2, NULL); + exit(0); +} diff -Naur ../glibc-2.1.3/linuxthreads/Examples/ex5.c glibc-2.1.3/linuxthreads/Examples/ex5.c --- ../glibc-2.1.3/linuxthreads/Examples/ex5.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/Examples/ex5.c 1998-08-28 03:07:19.000000000 -0700 @@ -0,0 +1,102 @@ +/* The classic producer-consumer example, implemented with semaphores. + All integers between 0 and 9999 should be printed exactly twice, + once to the right of the arrow and once to the left. */ + +#include +#include "pthread.h" +#include "semaphore.h" + +#define BUFFER_SIZE 16 + +/* Circular buffer of integers. */ + +struct prodcons { + int buffer[BUFFER_SIZE]; /* the actual data */ + int readpos, writepos; /* positions for reading and writing */ + sem_t sem_read; /* number of elements available for reading */ + sem_t sem_write; /* number of locations available for writing */ +}; + +/* Initialize a buffer */ + +void init(struct prodcons * b) +{ + sem_init(&b->sem_write, 0, BUFFER_SIZE - 1); + sem_init(&b->sem_read, 0, 0); + b->readpos = 0; + b->writepos = 0; +} + +/* Store an integer in the buffer */ + +void put(struct prodcons * b, int data) +{ + /* Wait until buffer is not full */ + sem_wait(&b->sem_write); + /* Write the data and advance write pointer */ + b->buffer[b->writepos] = data; + b->writepos++; + if (b->writepos >= BUFFER_SIZE) b->writepos = 0; + /* Signal that the buffer contains one more element for reading */ + sem_post(&b->sem_read); +} + +/* Read and remove an integer from the buffer */ + +int get(struct prodcons * b) +{ + int data; + /* Wait until buffer is not empty */ + sem_wait(&b->sem_read); + /* Read the data and advance read pointer */ + data = b->buffer[b->readpos]; + b->readpos++; + if (b->readpos >= BUFFER_SIZE) b->readpos = 0; + /* Signal that the buffer has now one more location for writing */ + sem_post(&b->sem_write); + return data; +} + +/* A test program: one thread inserts integers from 1 to 10000, + the other reads them and prints them. */ + +#define OVER (-1) + +struct prodcons buffer; + +void * producer(void * data) +{ + int n; + for (n = 0; n < 10000; n++) { + printf("%d --->\n", n); + put(&buffer, n); + } + put(&buffer, OVER); + return NULL; +} + +void * consumer(void * data) +{ + int d; + while (1) { + d = get(&buffer); + if (d == OVER) break; + printf("---> %d\n", d); + } + return NULL; +} + +int main(void) +{ + pthread_t th_a, th_b; + void * retval; + + init(&buffer); + /* Create the threads */ + pthread_create(&th_a, NULL, producer, 0); + pthread_create(&th_b, NULL, consumer, 0); + /* Wait until producer and consumer finish. */ + pthread_join(th_a, &retval); + pthread_join(th_b, &retval); + return 0; +} diff -Naur ../glibc-2.1.3/linuxthreads/Examples/ex6.c glibc-2.1.3/linuxthreads/Examples/ex6.c --- ../glibc-2.1.3/linuxthreads/Examples/ex6.c 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/Examples/ex6.c 1998-12-14 14:24:16.000000000 -0800 @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +void * +test_thread (void *v_param) +{ + return NULL; +} + +int +main (void) +{ + unsigned long count; + + setvbuf (stdout, NULL, _IONBF, 0); + + for (count = 0; count < 2000; ++count) + { + pthread_t thread; + int status; + + status = pthread_create (&thread, NULL, test_thread, NULL); + if (status != 0) + { + printf ("status = %d, count = %lu: %s\n", status, count, + strerror (errno)); + return 1; + } + else + { + printf ("count = %lu\n", count); + } + /* pthread_detach (thread); */ + pthread_join (thread, NULL); + usleep (10); + } + return 0; +} diff -Naur ../glibc-2.1.3/linuxthreads/FAQ.html glibc-2.1.3/linuxthreads/FAQ.html --- ../glibc-2.1.3/linuxthreads/FAQ.html 1969-12-31 16:00:00.000000000 -0800 +++ glibc-2.1.3/linuxthreads/FAQ.html 2000-02-01 14:11:26.000000000 -0800 @@ -0,0 +1,1039 @@ + + +LinuxThreads Frequently Asked Questions + + +

LinuxThreads Frequently Asked Questions
+ (with answers)

+

[For LinuxThreads version 0.8]

+ +

+ +A. The big picture
+B. Getting more information
+C. Issues related to the C library
+D. Problems, weird behaviors, potential bugs
+E. Missing functions, wrong types, etc
+F. C++ issues
+G. Debugging LinuxThreads programs
+H. Compiling multithreaded code; errno madness
+I. X-Windows and other libraries
+J. Signals and threads
+K. Internals of LinuxThreads

+ +


+

+ +

A. The big picture

+ +

A.1: What is LinuxThreads?

+ +LinuxThreads is a Linux library for multi-threaded programming. +It implements the Posix 1003.1c API (Application Programming +Interface) for threads. It runs on any Linux system with kernel 2.0.0 +or more recent, and a suitable C library (see section C). +

+ +

A.2: What are threads?

+ +A thread is a sequential flow of control through a program. +Multi-threaded programming is, thus, a form of parallel programming +where several threads of control are executing concurrently in the +program. All threads execute in the same memory space, and can +therefore work concurrently on shared data.

+ +Multi-threaded programming differs from Unix-style multi-processing in +that all threads share the same memory space (and a few other system +resources, such as file descriptors), instead of running in their own +memory space as is the case with Unix processes.

+ +Threads are useful for two reasons. First, they allow a program to +exploit multi-processor machines: the threads can run in parallel on +several processors, allowing a single program to divide its work +between several processors, thus running faster than a single-threaded +program, which runs on only one processor at a time. Second, some +programs are best expressed as several threads of control that +communicate together, rather than as one big monolithic sequential +program. Examples include server programs, overlapping asynchronous +I/O, and graphical user interfaces.

+ +

A.3: What is POSIX 1003.1c?

+ +It's an API for multi-threaded programming standardized by IEEE as +part of the POSIX standards. Most Unix vendors have endorsed the +POSIX 1003.1c standard. Implementations of the 1003.1c API are +already available under Sun Solaris 2.5, Digital Unix 4.0, +Silicon Graphics IRIX 6, and should soon be available from other +vendors such as IBM and HP. More generally, the 1003.1c API is +replacing relatively quickly the proprietary threads library that were +developed previously under Unix, such as Mach cthreads, Solaris +threads, and IRIX sprocs. Thus, multithreaded programs using the +1003.1c API are likely to run unchanged on a wide variety of Unix +platforms.

+ +

A.4: What is the status of LinuxThreads?

+ +LinuxThreads implements almost all of Posix 1003.1c, as well as a few +extensions. The only part of LinuxThreads that does not conform yet +to Posix is signal handling (see section J). Apart +from the signal stuff, all the Posix 1003.1c base functionality, +as well as a number of optional extensions, are provided and conform +to the standard (to the best of my knowledge). +The signal stuff is hard to get right, at least without special kernel +support, and while I'm definitely looking at ways to implement the +Posix behavior for signals, this might take a long time before it's +completed.

+ +

A.5: How stable is LinuxThreads?

+ +The basic functionality (thread creation and termination, mutexes, +conditions, semaphores) is very stable. Several industrial-strength +programs, such as the AOL multithreaded Web server, use LinuxThreads +and seem quite happy about it. There used to be some rough edges in +the LinuxThreads / C library interface with libc 5, but glibc 2 +fixes all of those problems and is now the standard C library on major +Linux distributions (see section C).

+ +


+

+ +

B. Getting more information

+ +

B.1: What are good books and other sources of +information on POSIX threads?

+ +The FAQ for comp.programming.threads lists several books: +http://www.serpentine.com/~bos/threads-faq/.

+ +There are also some online tutorials. Follow the links from the +LinuxThreads web page: +http://pauillac.inria.fr/~xleroy/linuxthreads.

+ +

B.2: I'd like to be informed of future developments on +LinuxThreads. Is there a mailing list for this purpose?

+ +I post LinuxThreads-related announcements on the newsgroup +comp.os.linux.announce, +and also on the mailing list +linux-threads@magenet.com. +You can subscribe to the latter by writing +majordomo@magenet.com.

+ +

B.3: What are good places for discussing +LinuxThreads?

+ +For questions about programming with POSIX threads in general, use +the newsgroup +comp.programming.threads. +Be sure you read the +FAQ +for this group before you post.

+ +For Linux-specific questions, use +comp.os.linux.development.apps +and comp.os.linux.development.kernel. +The latter is especially appropriate for questions relative to the +interface between the kernel and LinuxThreads.

+ +

B.4: How should I report a possible bug in +LinuxThreads?

+ +If you're using glibc 2, the best way by far is to use the +glibcbug script to mail a bug report to the glibc +maintainers.

+ +If you're using an older libc, or don't have the glibcbug +script on your machine, then e-mail me directly +(Xavier.Leroy@inria.fr).

+ +In both cases, before sending the bug report, make sure that it is not +addressed already in this FAQ. Also, try to send a short program that +reproduces the weird behavior you observed.

+ +

B.5: I'd like to read the POSIX 1003.1c standard. Is +it available online?

+ +Unfortunately, no. POSIX standards are copyrighted by IEEE, and +IEEE does not distribute them freely. You can buy paper copies from +IEEE, but the price is fairly high ($120 or so). If you disagree with +this policy and you're an IEEE member, be sure to let them know.

+ +On the other hand, you probably don't want to read the standard. It's +very hard to read, written in standard-ese, and targeted to +implementors who already know threads inside-out. A good book on +POSIX threads provides the same information in a much more readable form. +I can personally recommend Dave Butenhof's book, Programming +with POSIX threads (Addison-Wesley). Butenhof was part of the +POSIX committee and also designed the Digital Unix implementations of +POSIX threads, and it shows.

+ +Another good source of information is the X/Open Group Single Unix +specification which is available both +on-line +and as a +book and CD/ROM. +That specification includes pretty much all the POSIX standards, +including 1003.1c, with some extensions and clarifications.

+ +


+

+ +

C. Issues related to the C library

+ +

C.1: Which version of the C library should I use +with LinuxThreads?

+ +The best choice by far is glibc 2, a.k.a. libc 6. It offers very good +support for multi-threading, and LinuxThreads has been closely +integrated with glibc 2. The glibc 2 distribution contains the +sources of a specially adapted version of LinuxThreads.

+ +glibc 2 comes preinstalled as the default C library on several Linux +distributions, such as RedHat 5 and up, and Debian 2. +Those distributions include the version of LinuxThreads matching +glibc 2.

+ +

C.2: My system has libc 5 preinstalled, not glibc +2. Can I still use LinuxThreads?

+ +Yes, but you're likely to run into some problems, as libc 5 only +offers minimal support for threads and contains some bugs that affect +multithreaded programs.

+ +The versions of libc 5 that work best with LinuxThreads are +libc 5.2.18 on the one hand, and libc 5.4.12 or later on the other hand. +Avoid 5.3.12 and 5.4.7: these have problems with the per-thread errno +variable.

+ +

C.3: So, should I switch to glibc 2, or stay with a +recent libc 5?

+ +I'd recommend you switch to glibc 2. Even for single-threaded +programs, glibc 2 is more solid and more standard-conformant than libc +5. And the shortcomings of libc 5 almost preclude any serious +multi-threaded programming.

+ +Switching an already installed +system from libc 5 to glibc 2 is not completely straightforward. +See the Glibc2 +HOWTO for more information. Much easier is (re-)installing a +Linux distribution based on glibc 2, such as RedHat 6.

+ +

C.4: Where can I find glibc 2 and the version of +LinuxThreads that goes with it?

+ +On prep.ai.mit.edu and its many, many mirrors around the world. +See http://www.gnu.org/order/ftp.html +for a list of mirrors.

+ +

C.5: Where can I find libc 5 and the version of +LinuxThreads that goes with it?

+ +For libc 5, see ftp://sunsite.unc.edu/pub/Linux/devel/GCC/.

+ +For the libc 5 version of LinuxThreads, see +ftp://ftp.inria.fr/INRIA/Projects/cristal/Xavier.Leroy/linuxthreads/.

+ +

C.6: How can I recompile the glibc 2 version of the +LinuxThreads sources?

+ +You must transfer the whole glibc sources, then drop the LinuxThreads +sources in the linuxthreads/ subdirectory, then recompile +glibc as a whole. There are now too many inter-dependencies between +LinuxThreads and glibc 2 to allow separate re-compilation of LinuxThreads. +

+ +

C.7: What is the correspondence between LinuxThreads +version numbers, libc version numbers, and RedHat version +numbers?

+ +Here is a summary. (Information on Linux distributions other than +RedHat are welcome.)

+ + + + + + + +
LinuxThreads C library RedHat
0.7, 0.71 (for libc 5) libc 5.x RH 4.2
0.7, 0.71 (for glibc 2) glibc 2.0.x RH 5.x
0.8 glibc 2.1.1 RH 6.0
0.8 glibc 2.1.2 not yet released
+

+ +


+

+ +

D. Problems, weird behaviors, potential bugs

+ +

D.1: When I compile LinuxThreads, I run into problems in +file libc_r/dirent.c

+ +You probably mean: +
+        libc_r/dirent.c:94: structure has no member named `dd_lock'
+
+I haven't actually seen this problem, but several users reported it. +My understanding is that something is wrong in the include files of +your Linux installation (/usr/include/*). Make sure +you're using a supported version of the libc 5 library. (See question C.2).

+ +

D.2: When I compile LinuxThreads, I run into problems with +/usr/include/sched.h: there are several occurrences of +_p that the C compiler does not understand

+ +Yes, /usr/include/sched.h that comes with libc 5.3.12 is broken. +Replace it with the sched.h file contained in the +LinuxThreads distribution. But really you should not be using libc +5.3.12 with LinuxThreads! (See question C.1.)

+ +

D.3: My program does fdopen() on a file +descriptor opened on a pipe. When I link it with LinuxThreads, +fdopen() always returns NULL!

+ +You're using one of the buggy versions of libc (5.3.12, 5.4.7., etc). +See question C.1 above.

+ +

D.4: My program creates a lot of threads, and after +a while pthread_create() no longer returns!

+ +This is known bug in the version of LinuxThreads that comes with glibc +2.1.1. An upgrade to 2.1.2 is recommended.

+ +

D.5: When I'm running a program that creates N +threads, top or ps +display N+2 processes that are running my program. What do all these +processes correspond to?

+ +Due to the general "one process per thread" model, there's one process +for the initial thread and N processes for the threads it created +using pthread_create. That leaves one process +unaccounted for. That extra process corresponds to the "thread +manager" thread, a thread created internally by LinuxThreads to handle +thread creation and thread termination. This extra thread is asleep +most of the time. + +

D.6: Scheduling seems to be very unfair when there +is strong contention on a mutex: instead of giving the mutex to each +thread in turn, it seems that it's almost always the same thread that +gets the mutex. Isn't this completely broken behavior?

+ +That behavior has mostly disappeared in recent releases of +LinuxThreads (version 0.8 and up). It was fairly common in older +releases, though. + +What happens in LinuxThreads 0.7 and before is the following: when a +thread unlocks a mutex, all other threads that were waiting on the +mutex are sent a signal which makes them runnable. However, the +kernel scheduler may or may not restart them immediately. If the +thread that unlocked the mutex tries to lock it again immediately +afterwards, it is likely that it will succeed, because the threads +haven't yet restarted. This results in an apparently very unfair +behavior, when the same thread repeatedly locks and unlocks the mutex, +while other threads can't lock the mutex.

+ +In LinuxThreads 0.8 and up, pthread_unlock restarts only +one waiting thread, and pre-assign the mutex to that thread. Hence, +if the thread that unlocked the mutex tries to lock it again +immediately, it will block until other waiting threads have had a +chance to lock and unlock the mutex. This results in much fairer +scheduling.

+ +Notice however that even the old "unfair" behavior is perfectly +acceptable with respect to the POSIX standard: for the default +scheduling policy, POSIX makes no guarantees of fairness, such as "the +thread waiting for the mutex for the longest time always acquires it +first". Properly written multithreaded code avoids that kind of heavy +contention on mutexes, and does not run into fairness problems. If +you need scheduling guarantees, you should consider using the +real-time scheduling policies SCHED_RR and +SCHED_FIFO, which have precisely defined scheduling +behaviors.

+ +

D.7: I have a simple test program with two threads +that do nothing but printf() in tight loops, and from the +printout it seems that only one thread is running, the other doesn't +print anything!

+ +Again, this behavior is characteristic of old releases of LinuxThreads +(0.7 and before); more recent versions (0.8 and up) should not exhibit +this behavior.

+ +The reason for this behavior is explained in +question D.6 above: printf() performs +locking on stdout, and thus your two threads contend very +heavily for the mutex associated with stdout. But if you +do some real work between two calls to printf(), you'll +see that scheduling becomes much smoother.

+ +

D.8: I've looked at <pthread.h> +and there seems to be a gross error in the pthread_cleanup_push +macro: it opens a block with { but does not close it! +Surely you forgot a } at the end of the macro, right? +

+ +Nope. That's the way it should be. The closing brace is provided by +the pthread_cleanup_pop macro. The POSIX standard +requires pthread_cleanup_push and +pthread_cleanup_pop to be used in matching pairs, at the +same level of brace nesting. This allows +pthread_cleanup_push to open a block in order to +stack-allocate some data structure, and +pthread_cleanup_pop to close that block. It's ugly, but +it's the standard way of implementing cleanup handlers.

+ +

D.9: I tried to use real-time threads and my program +loops like crazy and freezes the whole machine!

+ +Versions of LinuxThreads prior to 0.8 are susceptible to ``livelocks'' +(one thread loops, consuming 100% of the CPU time) in conjunction with +real-time scheduling. Since real-time threads and processes have +higher priority than normal Linux processes, all other processes on +the machine, including the shell, the X server, etc, cannot run and +the machine appears frozen.

+ +The problem is fixed in LinuxThreads 0.8.

+ +

D.10: My application needs to create thousands of +threads, or maybe even more. Can I do this with +LinuxThreads?

+ +No. You're going to run into several hard limits: +
    +
  • Each thread, from the kernel's standpoint, is one process. Stock +Linux kernels are limited to at most 512 processes for the super-user, +and half this number for regular users. This can be changed by +changing NR_TASKS in include/linux/tasks.h +and recompiling the kernel. On the x86 processors at least, +architectural constraints seem to limit NR_TASKS to 4090 +at most. +
  • LinuxThreads contains a table of all active threads. This table +has room for 1024 threads at most. To increase this limit, you must +change PTHREAD_THREADS_MAX in the LinuxThreads sources +and recompile. +
  • By default, each thread reserves 2M of virtual memory space for +its stack. This space is just reserved; actual memory is allocated +for the stack on demand. But still, on a 32-bit processor, the total +virtual memory space available for the stacks is on the order of 1G, +meaning that more than 500 threads will have a hard time fitting in. +You can overcome this limitation by moving to a 64-bit platform, or by +allocating smaller stacks yourself using the setstackaddr +attribute. +
  • Finally, the Linux kernel contains many algorithms that run in +time proportional to the number of process table entries. Increasing +this number drastically will slow down the kernel operations +noticeably. +
+(Other POSIX threads libraries have similar limitations, by the way.) +For all those reasons, you'd better restructure your application so +that it doesn't need more than, say, 100 threads. For instance, +in the case of a multithreaded server, instead of creating a new +thread for each connection, maintain a fixed-size pool of worker +threads that pick incoming connection requests from a queue.

+ +


+

+ +

E. Missing functions, wrong types, etc

+ +

E.1: Where is pthread_yield() ? How +comes LinuxThreads does not implement it?

+ +Because it's not part of the (final) POSIX 1003.1c standard. +Several drafts of the standard contained pthread_yield(), +but then the POSIX guys discovered it was redundant with +sched_yield() and dropped it. So, just use +sched_yield() instead. + +

E.2: I've found some type errors in +<pthread.h>. +For instance, the second argument to pthread_create() +should be a pthread_attr_t, not a +pthread_attr_t *. Also, didn't you forget to declare +pthread_attr_default?

+ +No, I didn't. What you're describing is draft 4 of the POSIX +standard, which is used in OSF DCE threads. LinuxThreads conforms to the +final standard. Even though the functions have the same names as in +draft 4 and DCE, their calling conventions are slightly different. In +particular, attributes are passed by reference, not by value, and +default attributes are denoted by the NULL pointer. Since draft 4/DCE +will eventually disappear, you'd better port your program to use the +standard interface.

+ +

E.3: I'm porting an application from Solaris and I +have to rename all thread functions from thr_blah to +pthread_blah. This is very annoying. Why did you change +all the function names?

+ +POSIX did it. The thr_* functions correspond to Solaris +threads, an older thread interface that you'll find only under +Solaris. The pthread_* functions correspond to POSIX +threads, an international standard available for many, many platforms. +Even Solaris 2.5 and later support the POSIX threads interface. So, +do yourself a favor and rewrite your code to use POSIX threads: this +way, it will run unchanged under Linux, Solaris, and quite a lot of +other platforms.

+ +

E.4: How can I suspend and resume a thread from +another thread? Solaris has the thr_suspend() and +thr_resume() functions to do that; why don't you?

+ +The POSIX standard provides no mechanism by which a thread A can +suspend the execution of another thread B, without cooperation from B. +The only way to implement a suspend/restart mechanism is to have B +check periodically some global variable for a suspend request +and then suspend itself on a condition variable, which another thread +can signal later to restart B.

+ +Notice that thr_suspend() is inherently dangerous and +prone to race conditions. For one thing, there is no control on where +the target thread stops: it can very well be stopped in the middle of +a critical section, while holding mutexes. Also, there is no +guarantee on when the target thread will actually stop. For these +reasons, you'd be much better off using mutexes and conditions +instead. The only situations that really require the ability to +suspend a thread are debuggers and some kind of garbage collectors.

+ +If you really must suspend a thread in LinuxThreads, you can send it a +SIGSTOP signal with pthread_kill. Send +SIGCONT for restarting it. +Beware, this is specific to LinuxThreads and entirely non-portable. +Indeed, a truly conforming POSIX threads implementation will stop all +threads when one thread receives the SIGSTOP signal! +One day, LinuxThreads will implement that behavior, and the +non-portable hack with SIGSTOP won't work anymore.

+ +

E.5: Does LinuxThreads implement +pthread_attr_setstacksize() and +pthread_attr_setstackaddr()?

+ +These optional functions are provided in recent versions of +LinuxThreads (0.8 and up). Earlier releases did not provide these +optional components of the POSIX standard.

+ +Even if pthread_attr_setstacksize() and +pthread_attr_setstackaddr() are now provided, we still +recommend that you do not use them unless you really have strong +reasons for doing so. The default stack allocation strategy for +LinuxThreads is nearly optimal: stacks start small (4k) and +automatically grow on demand to a fairly large limit (2M). +Moreover, there is no portable way to estimate the stack requirements +of a thread, so setting the stack size yourself makes your program +less reliable and non-portable.

+ +

E.6: LinuxThreads does not support the +PTHREAD_SCOPE_PROCESS value of the "contentionscope" +attribute. Why?

+ +With a "one-to-one" model, as in LinuxThreads (one kernel execution +context per thread), there is only one scheduler for all processes and +all threads on the system. So, there is no way to obtain the behavior of +PTHREAD_SCOPE_PROCESS. + +

E.7: LinuxThreads does not implement process-shared +mutexes, conditions, and semaphores. Why?

+ +This is another optional component of the POSIX standard. Portable +applications should test _POSIX_THREAD_PROCESS_SHARED +before using this facility. +

+The goal of this extension is to allow different processes (with +different address spaces) to synchronize through mutexes, conditions +or semaphores allocated in shared memory (either SVR4 shared memory +segments or mmap()ed files). +

+The reason why this does not work in LinuxThreads is that mutexes, +conditions, and semaphores are not self-contained: their waiting +queues contain pointers to linked lists of thread descriptors, and +these pointers are meaningful only in one address space. +

+Matt Messier and I spent a significant amount of time trying to design a +suitable mechanism for sharing waiting queues between processes. We +came up with several solutions that combined two of the following +three desirable features, but none that combines all three: +

    +
  • allow sharing between processes having different UIDs +
  • supports cancellation +
  • supports pthread_cond_timedwait +
+We concluded that kernel support is required to share mutexes, +conditions and semaphores between processes. That's one place where +Linus Torvalds's intuition that "all we need in the kernel is +clone()" fails. +

+Until suitable kernel support is available, you'd better use +traditional interprocess communications to synchronize different +processes: System V semaphores and message queues, or pipes, or sockets. +

+ +


+

+ +

F. C++ issues

+ +

F.1: Are there C++ wrappers for LinuxThreads?

+ +Douglas Schmidt's ACE library contains, among a lot of other +things, C++ wrappers for LinuxThreads and quite a number of other +thread libraries. Check out +http://www.cs.wustl.edu/~schmidt/ACE.html

+ +

F.2: I'm trying to use LinuxThreads from a C++ +program, and the compiler complains about the third argument to +pthread_create() !

+ +You're probably trying to pass a class member function or some +other C++ thing as third argument to pthread_create(). +Recall that pthread_create() is a C function, and it must +be passed a C function as third argument.

+ +

F.3: I'm trying to use LinuxThreads in conjunction +with libg++, and I'm having all sorts of trouble.

+ +>From what I understand, thread support in libg++ is completely broken, +especially with respect to locking of iostreams. H.J.Lu wrote: +
+If you want to use thread, I can only suggest egcs and glibc. You +can find egcs at +http://www.cygnus.com/egcs. +egcs has libsdtc++, which is MT safe under glibc 2. If you really +want to use the libg++, I have a libg++ add-on for egcs. +
+
+

+ +

G. Debugging LinuxThreads programs

+ +

G.1: Can I debug LinuxThreads program using gdb?

+ +Yes, but not with the stock gdb 4.17. You need a specially patched +version of gdb 4.17 developed by Eric Paire and colleages at The Open +Group, Grenoble. The patches against gdb 4.17 are available at +http://www.gr.opengroup.org/java/jdk/linux/debug.htm. +Precompiled binaries of the patched gdb are available in RedHat's RPM +format at http://odin.appliedtheory.com/.

+ +Some Linux distributions provide an already-patched version of gdb; +others don't. For instance, the gdb in RedHat 5.2 is thread-aware, +but apparently not the one in RedHat 6.0. Just ask (politely) the +makers of your Linux distributions to please make sure that they apply +the correct patches to gdb.

+ +

G.2: Does it work with post-mortem debugging?

+ +Not very well. Generally, the core file does not correspond to the +thread that crashed. The reason is that the kernel will not dump core +for a process that shares its memory with other processes, such as the +other threads of your program. So, the thread that crashes silently +disappears without generating a core file. Then, all other threads of +your program die on the same signal that killed the crashing thread. +(This is required behavior according to the POSIX standard.) The last +one that dies is no longer sharing its memory with anyone else, so the +kernel generates a core file for that thread. Unfortunately, that's +not the thread you are interested in. + +

G.3: Any other ways to debug multithreaded programs, then?

+ +Assertions and printf() are your best friends. Try to debug +sequential parts in a single-threaded program first. Then, put +printf() statements all over the place to get execution traces. +Also, check invariants often with the assert() macro. In truth, +there is no other effective way (save for a full formal proof of your +program) to track down concurrency bugs. Debuggers are not really +effective for subtle concurrency problems, because they disrupt +program execution too much.

+ +


+

+ +

H. Compiling multithreaded code; errno madness

+ +

H.1: You say all multithreaded code must be compiled +with _REENTRANT defined. What difference does it make?

+ +It affects include files in three ways: +
    +
  • The include files define prototypes for the reentrant variants of +some of the standard library functions, +e.g. gethostbyname_r() as a reentrant equivalent to +gethostbyname().

    + +

  • If _REENTRANT is defined, some +<stdio.h> functions are no longer defined as macros, +e.g. getc() and putc(). In a multithreaded +program, stdio functions require additional locking, which the macros +don't perform, so we must call functions instead.

    + +

  • More importantly, <errno.h> redefines errno when +_REENTRANT is +defined, so that errno refers to the thread-specific errno location +rather than the global errno variable. This is achieved by the +following #define in <errno.h>: +
    +        #define errno (*(__errno_location()))
    +
    +which causes each reference to errno to call the +__errno_location() function for obtaining the location +where error codes are stored. libc provides a default definition of +__errno_location() that always returns +&errno (the address of the global errno variable). Thus, +for programs not linked with LinuxThreads, defining +_REENTRANT makes no difference w.r.t. errno processing. +But LinuxThreads redefines __errno_location() to return a +location in the thread descriptor reserved for holding the current +value of errno for the calling thread. Thus, each thread operates on +a different errno location. +
+

+ +

H.2: Why is it so important that each thread has its +own errno variable?

+ +If all threads were to store error codes in the same, global errno +variable, then the value of errno after a system call or library +function returns would be unpredictable: between the time a system +call stores its error code in the global errno and your code inspects +errno to see which error occurred, another thread might have stored +another error code in the same errno location.

+ +

H.3: What happens if I link LinuxThreads with code +not compiled with -D_REENTRANT?

+ +Lots of trouble. If the code uses getc() or +putc(), it will perform I/O without proper interlocking +of the stdio buffers; this can cause lost output, duplicate output, or +just crash other stdio functions. If the code consults errno, it will +get back the wrong error code. The following code fragment is a +typical example: +
+        do {
+          r = read(fd, buf, n);
+          if (r == -1) {
+            if (errno == EINTR)   /* an error we can handle */
+              continue;
+            else {                /* other errors are fatal */
+              perror("read failed");
+              exit(100);
+            }
+          }
+        } while (...);
+
+Assume this code is not compiled with -D_REENTRANT, and +linked with LinuxThreads. At run-time, read() is +interrupted. Since the C library was compiled with +-D_REENTRANT, read() stores its error code +in the location pointed to by __errno_location(), which +is the thread-local errno variable. Then, the code above sees that +read() returns -1 and looks up errno. Since +_REENTRANT is not defined, the reference to errno +accesses the global errno variable, which is most likely 0. Hence the +code concludes that it cannot handle the error and stops.

+ +

H.4: With LinuxThreads, I can no longer use the signals +SIGUSR1 and SIGUSR2 in my programs! Why?

+ +The short answer is: because the Linux kernel you're using does not +support realtime signals.

+ +LinuxThreads needs two signals for its internal operation. +One is used to suspend and restart threads blocked on mutex, condition +or semaphore operations. The other is used for thread +cancellation.

+ +On ``old'' kernels (2.0 and early 2.1 kernels), there are only 32 +signals available and the kernel reserves all of them but two: +SIGUSR1 and SIGUSR2. So, LinuxThreads has +no choice but use those two signals.

+ +On recent kernels (2.2 and up), more than 32 signals are provided in +the form of realtime signals. When run on one of those kernels, +LinuxThreads uses two reserved realtime signals for its internal +operation, thus leaving SIGUSR1 and SIGUSR2 +free for user code. (This works only with glibc, not with libc 5.)

+ +

H.5: Is the stack of one thread visible from the +other threads? Can I pass a pointer into my stack to other threads? +

+ +Yes, you can -- if you're very careful. The stacks are indeed visible +from all threads in the system. Some non-POSIX thread libraries seem +to map the stacks for all threads at the same virtual addresses and +change the memory mapping when they switch from one thread to +another. But this is not the case for LinuxThreads, as it would make +context switching between threads more expensive, and at any rate +might not conform to the POSIX standard.

+ +So, you can take the address of an "auto" variable and pass it to +other threads via shared data structures. However, you need to make +absolutely sure that the function doing this will not return as long +as other threads need to access this address. It's the usual mistake +of returning the address of an "auto" variable, only made much worse +because of concurrency. It's much, much safer to systematically +heap-allocate all shared data structures.

+ +


+

+ +

I. X-Windows and other libraries

+ +

I.1: My program uses both Xlib and LinuxThreads. +It stops very early with an "Xlib: unknown 0 error" message. What +does this mean?

+ +That's a prime example of the errno problem described in question H.2. The binaries for Xlib you're using have not been +compiled with -D_REENTRANT. It happens Xlib contains a +piece of code very much like the one in question H.2. So, your Xlib fetches the error code from the +wrong errno location and concludes that an error it cannot handle +occurred.

+ +

I.2: So, what can I do to build a multithreaded X +Windows client?

+ +The best solution is to use X libraries that have been compiled with +multithreading options set. Linux distributions that come with glibc +2 as the main C library generally provide thread-safe X libraries. +At least, that seems to be the case for RedHat 5 and later.

+ +You can try to recompile yourself the X libraries with multithreading +options set. They contain optional support for multithreading; it's +just that the binaries provided by your Linux distribution were built +without this support. See the file README.Xfree3.3 in +the LinuxThreads distribution for patches and info on how to compile +thread-safe X libraries from the Xfree3.3 distribution. The Xfree3.3 +sources are readily available in most Linux distributions, e.g. as a +source RPM for RedHat. Be warned, however, that X Windows is a huge +system, and recompiling even just the libraries takes a lot of time +and disk space.

+ +Another, less involving solution is to call X functions only from the +main thread of your program. Even if all threads have their own errno +location, the main thread uses the global errno variable for its errno +location. Thus, code not compiled with -D_REENTRANT +still "sees" the right error values if it executes in the main thread +only.

+ +

This is a lot of work. Don't you have precompiled +thread-safe X libraries that you could distribute?

+ +No, I don't. Sorry. But consider installing a Linux distribution +that comes with thread-safe X libraries, such as RedHat 6.

+ +

I.3: Can I use library FOO in a multithreaded +program?

+ +Most libraries cannot be used "as is" in a multithreaded program. +For one thing, they are not necessarily thread-safe: calling +simultaneously two functions of the library from two threads might not +work, due to internal use of global variables and the like. Second, +the libraries must have been compiled with -D_REENTRANT to avoid +the errno problems explained in question H.2. +

+ +

I.4: What if I make sure that only one thread calls +functions in these libraries?

+ +This avoids problems with the library not being thread-safe. But +you're still vulnerable to errno problems. At the very least, a +recompile of the library with -D_REENTRANT is needed. +

+ +

I.5: What if I make sure that only the main thread +calls functions in these libraries?

+ +That might actually work. As explained in question I.1, +the main thread uses the global errno variable, and can therefore +execute code not compiled with -D_REENTRANT.

+ +

I.6: SVGAlib doesn't work with LinuxThreads. Why? +

+ +Because both LinuxThreads and SVGAlib use the signals +SIGUSR1 and