diff options
author | tjr <tjr@FreeBSD.org> | 2005-10-01 04:37:08 +0000 |
---|---|---|
committer | tjr <tjr@FreeBSD.org> | 2005-10-01 04:37:08 +0000 |
commit | c36d8046bb9e942d877c8e9414f17fc3b88be160 (patch) | |
tree | 2fe4e8cc881bec8eb4702a6ce75c06c7d8667738 /contrib | |
parent | 22bb48addfe7a42ef866f6f9cb16473f00eae5b5 (diff) | |
download | FreeBSD-src-c36d8046bb9e942d877c8e9414f17fc3b88be160.zip FreeBSD-src-c36d8046bb9e942d877c8e9414f17fc3b88be160.tar.gz |
Import GNU cpio 2.6 (trimmed)
Diffstat (limited to 'contrib')
84 files changed, 19558 insertions, 10 deletions
diff --git a/contrib/cpio/ABOUT-NLS b/contrib/cpio/ABOUT-NLS new file mode 100644 index 0000000..8e16152 --- /dev/null +++ b/contrib/cpio/ABOUT-NLS @@ -0,0 +1,705 @@ +Notes on the Free Translation Project +************************************* + +Free software is going international! The Free Translation Project is +a way to get maintainers of free software, translators, and users all +together, so that will gradually become able to speak many languages. +A few packages already provide translations for their messages. + + If you found this `ABOUT-NLS' file inside a distribution, you may +assume that the distributed package does use GNU `gettext' internally, +itself available at your nearest GNU archive site. But you do _not_ +need to install GNU `gettext' prior to configuring, installing or using +this package with messages translated. + + Installers will find here some useful hints. These notes also +explain how users should proceed for getting the programs to use the +available translations. They tell how people wanting to contribute and +work at translations should contact the appropriate team. + + When reporting bugs in the `intl/' directory or bugs which may be +related to internationalization, you should tell about the version of +`gettext' which is used. The information can be found in the +`intl/VERSION' file, in internationalized packages. + +Quick configuration advice +========================== + +If you want to exploit the full power of internationalization, you +should configure it using + + ./configure --with-included-gettext + +to force usage of internationalizing routines provided within this +package, despite the existence of internationalizing capabilities in the +operating system where this package is being installed. So far, only +the `gettext' implementation in the GNU C library version 2 provides as +many features (such as locale alias, message inheritance, automatic +charset conversion or plural form handling) as the implementation here. +It is also not possible to offer this additional functionality on top +of a `catgets' implementation. Future versions of GNU `gettext' will +very likely convey even more functionality. So it might be a good idea +to change to GNU `gettext' as soon as possible. + + So you need _not_ provide this option if you are using GNU libc 2 or +you have installed a recent copy of the GNU gettext package with the +included `libintl'. + +INSTALL Matters +=============== + +Some packages are "localizable" when properly installed; the programs +they contain can be made to speak your own native language. Most such +packages use GNU `gettext'. Other packages have their own ways to +internationalization, predating GNU `gettext'. + + By default, this package will be installed to allow translation of +messages. It will automatically detect whether the system already +provides the GNU `gettext' functions. If not, the GNU `gettext' own +library will be used. This library is wholly contained within this +package, usually in the `intl/' subdirectory, so prior installation of +the GNU `gettext' package is _not_ required. Installers may use +special options at configuration time for changing the default +behaviour. The commands: + + ./configure --with-included-gettext + ./configure --disable-nls + +will respectively bypass any pre-existing `gettext' to use the +internationalizing routines provided within this package, or else, +_totally_ disable translation of messages. + + When you already have GNU `gettext' installed on your system and run +configure without an option for your new package, `configure' will +probably detect the previously built and installed `libintl.a' file and +will decide to use this. This might be not what is desirable. You +should use the more recent version of the GNU `gettext' library. I.e. +if the file `intl/VERSION' shows that the library which comes with this +package is more recent, you should use + + ./configure --with-included-gettext + +to prevent auto-detection. + + The configuration process will not test for the `catgets' function +and therefore it will not be used. The reason is that even an +emulation of `gettext' on top of `catgets' could not provide all the +extensions of the GNU `gettext' library. + + Internationalized packages have usually many `po/LL.po' files, where +LL gives an ISO 639 two-letter code identifying the language. Unless +translations have been forbidden at `configure' time by using the +`--disable-nls' switch, all available translations are installed +together with the package. However, the environment variable `LINGUAS' +may be set, prior to configuration, to limit the installed set. +`LINGUAS' should then contain a space separated list of two-letter +codes, stating which languages are allowed. + +Using This Package +================== + +As a user, if your language has been installed for this package, you +only have to set the `LANG' environment variable to the appropriate +`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, +and `CC' is an ISO 3166 two-letter country code. For example, let's +suppose that you speak German and live in Germany. At the shell +prompt, merely execute `setenv LANG de_DE' (in `csh'), +`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). +This can be done from your `.login' or `.profile' file, once and for +all. + + You might think that the country code specification is redundant. +But in fact, some languages have dialects in different countries. For +example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The +country code serves to distinguish the dialects. + + The locale naming convention of `LL_CC', with `LL' denoting the +language and `CC' denoting the country, is the one use on systems based +on GNU libc. On other systems, some variations of this scheme are +used, such as `LL' or `LL_CC.ENCODING'. You can get the list of +locales supported by your system for your country by running the command +`locale -a | grep '^LL''. + + Not all programs have translations for all languages. By default, an +English message is shown in place of a nonexistent translation. If you +understand other languages, you can set up a priority list of languages. +This is done through a different environment variable, called +`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' +for the purpose of message handling, but you still need to have `LANG' +set to the primary language; this is required by other parts of the +system libraries. For example, some Swedish users who would rather +read translations in German than English for when Swedish is not +available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. + + In the `LANGUAGE' environment variable, but not in the `LANG' +environment variable, `LL_CC' combinations can be abbreviated as `LL' +to denote the language's main dialect. For example, `de' is equivalent +to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' +(Portuguese as spoken in Portugal) in this context. + +Translating Teams +================= + +For the Free Translation Project to be a success, we need interested +people who like their own language and write it well, and who are also +able to synergize with other translators speaking the same language. +Each translation team has its own mailing list. The up-to-date list of +teams can be found at the Free Translation Project's homepage, +`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams" +area. + + If you'd like to volunteer to _work_ at translating messages, you +should become a member of the translating team for your own language. +The subscribing address is _not_ the same as the list itself, it has +`-request' appended. For example, speakers of Swedish can send a +message to `sv-request@li.org', having this message body: + + subscribe + + Keep in mind that team members are expected to participate +_actively_ in translations, or at solving translational difficulties, +rather than merely lurking around. If your team does not exist yet and +you want to start one, or if you are unsure about what to do or how to +get started, please write to `translation@iro.umontreal.ca' to reach the +coordinator for all translator teams. + + The English team is special. It works at improving and uniformizing +the terminology in use. Proven linguistic skill are praised more than +programming skill, here. + +Available Packages +================== + +Languages are not equally supported in all packages. The following +matrix shows the current state of internationalization, as of November +2003. The matrix shows, in regard of each package, for which languages +PO files have been submitted to translation coordination, with a +translation percentage of at least 50%. + + Ready PO files am az be bg ca cs da de el en en_GB eo es + +-------------------------------------------+ + a2ps | [] [] [] [] | + aegis | () | + ant-phone | () | + anubis | | + ap-utils | | + bash | [] [] [] [] | + batchelor | | + bfd | [] [] | + binutils | [] [] | + bison | [] [] [] | + bluez-pin | [] [] | + clisp | [] [] [] | + clisp | | + coreutils | [] [] [] [] | + cpio | [] [] [] | + darkstat | [] () [] | + diffutils | [] [] [] [] [] [] [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] | + error | [] [] [] [] [] | + fetchmail | [] () [] [] [] [] | + fileutils | [] [] [] | + findutils | [] [] [] [] [] [] [] | + flex | [] [] [] [] | + fslint | | + gas | [] | + gawk | [] [] [] [] | + gbiff | [] | + gcal | [] | + gcc | [] [] | + gettext | [] [] [] [] [] | + gettext-examples | [] [] [] | + gettext-runtime | [] [] [] [] [] | + gettext-tools | [] [] [] | + gimp-print | [] [] [] [] [] | + gliv | | + glunarclock | [] [] [] | + gnubiff | [] | + gnucash | [] () [] [] | + gnucash-glossary | [] () [] | + gnupg | [] () [] [] [] [] | + gpe-aerial | [] | + gpe-beam | [] [] | + gpe-calendar | [] [] | + gpe-clock | [] [] | + gpe-conf | [] [] | + gpe-contacts | [] [] | + gpe-edit | [] | + gpe-go | [] | + gpe-login | [] [] | + gpe-ownerinfo | [] [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] | + gpe-taskmanager | [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | [] [] | + gphoto2 | [] [] [] [] | + gprof | [] [] [] | + gpsdrive | () () () | + gramadoir | [] | + grep | [] [] [] [] [] [] | + gretl | [] | + gtick | () | + hello | [] [] [] [] [] [] | + id-utils | [] [] | + indent | [] [] [] [] | + jpilot | [] [] [] | + jtag | | + jwhois | [] | + kbd | [] [] [] [] [] | + latrine | () | + ld | [] [] | + libc | [] [] [] [] [] [] | + libgpewidget | [] [] | + libiconv | [] [] [] [] [] | + lifelines | [] () | + lilypond | [] | + lingoteach | | + lingoteach_lessons | () () | + lynx | [] [] [] [] | + m4 | [] [] [] [] | + mailutils | [] [] | + make | [] [] [] | + man-db | [] () [] [] () | + minicom | [] [] [] | + mysecretdiary | [] [] [] | + nano | [] () [] [] [] | + nano_1_0 | [] () [] [] [] | + opcodes | [] | + parted | [] [] [] [] [] | + ptx | [] [] [] [] [] | + python | | + radius | | + recode | [] [] [] [] [] [] [] | + screem | | + scrollkeeper | [] [] [] [] [] [] | + sed | [] [] [] [] [] | + sh-utils | [] [] [] | + shared-mime-info | | + sharutils | [] [] [] [] [] [] | + sketch | [] () [] | + soundtracker | [] [] [] | + sp | [] | + tar | [] [] [] [] | + texinfo | [] [] [] | + textutils | [] [] [] [] | + tin | () () | + tuxpaint | [] [] [] [] [] [] [] | + util-linux | [] [] [] [] [] | + vorbis-tools | [] [] [] [] | + wastesedge | () | + wdiff | [] [] [] [] | + wget | [] [] [] [] [] [] | + xchat | [] [] [] [] | + xfree86_xkb_xml | [] | + xpad | [] | + +-------------------------------------------+ + am az be bg ca cs da de el en en_GB eo es + 0 1 8 3 37 37 54 73 15 1 5 12 62 + + et fa fi fr ga gl he hr hu id is it ja + +----------------------------------------+ + a2ps | [] [] [] () | + aegis | | + ant-phone | | + anubis | [] | + ap-utils | [] | + bash | [] [] | + batchelor | [] | + bfd | [] | + binutils | [] [] | + bison | [] [] [] [] | + bluez-pin | [] [] [] [] [] | + clisp | [] | + clisp | | + coreutils | [] [] [] [] [] [] | + cpio | [] [] [] | + darkstat | () [] [] [] | + diffutils | [] [] [] [] [] [] [] | + e2fsprogs | | + enscript | [] [] | + error | [] [] [] [] | + fetchmail | [] | + fileutils | [] [] [] [] [] [] | + findutils | [] [] [] [] [] [] [] [] [] [] | + flex | [] [] | + fslint | | + gas | [] | + gawk | [] [] [] | + gbiff | | + gcal | [] | + gcc | [] | + gettext | [] [] | + gettext-examples | [] [] | + gettext-runtime | [] [] [] [] | + gettext-tools | [] [] | + gimp-print | [] [] | + gliv | () | + glunarclock | [] [] [] [] [] | + gnubiff | | + gnucash | () [] | + gnucash-glossary | [] | + gnupg | [] [] [] [] [] [] [] | + gpe-aerial | [] | + gpe-beam | [] | + gpe-calendar | [] [] [] | + gpe-clock | [] | + gpe-conf | [] | + gpe-contacts | [] [] | + gpe-edit | [] [] | + gpe-go | [] | + gpe-login | [] [] | + gpe-ownerinfo | [] [] [] | + gpe-sketchbook | [] | + gpe-su | [] | + gpe-taskmanager | [] | + gpe-timesheet | [] [] [] | + gpe-today | [] [] | + gpe-todo | [] [] | + gphoto2 | [] [] [] | + gprof | [] [] | + gpsdrive | () [] () () | + gramadoir | [] | + grep | [] [] [] [] [] [] [] [] [] [] [] | + gretl | [] | + gtick | [] [] | + hello | [] [] [] [] [] [] [] [] [] [] [] [] | + id-utils | [] [] [] [] | + indent | [] [] [] [] [] [] [] [] [] | + jpilot | [] () | + jtag | | + jwhois | [] [] [] [] | + kbd | [] | + latrine | | + ld | [] | + libc | [] [] [] [] [] | + libgpewidget | [] [] [] [] | + libiconv | [] [] [] [] [] [] [] [] [] | + lifelines | () | + lilypond | [] | + lingoteach | [] [] | + lingoteach_lessons | | + lynx | [] [] [] [] | + m4 | [] [] [] [] | + mailutils | | + make | [] [] [] [] [] | + man-db | () () | + minicom | [] [] [] [] | + mysecretdiary | [] [] | + nano | [] [] [] [] | + nano_1_0 | [] [] [] [] | + opcodes | [] | + parted | [] [] [] | + ptx | [] [] [] [] [] [] [] | + python | | + radius | | + recode | [] [] [] [] [] [] | + screem | | + scrollkeeper | [] | + sed | [] [] [] [] [] [] [] [] [] | + sh-utils | [] [] [] [] [] [] [] | + shared-mime-info | [] | + sharutils | [] [] [] [] [] | + sketch | [] | + soundtracker | [] [] [] [] | + sp | [] () | + tar | [] [] [] [] [] [] [] [] [] | + texinfo | [] [] [] [] | + textutils | [] [] [] [] [] | + tin | [] () | + tuxpaint | [] [] [] [] [] [] [] [] | + util-linux | [] [] [] [] () [] | + vorbis-tools | [] | + wastesedge | () | + wdiff | [] [] [] [] [] [] | + wget | [] [] [] [] [] [] [] | + xchat | [] [] [] | + xfree86_xkb_xml | | + xpad | [] | + +----------------------------------------+ + et fa fi fr ga gl he hr hu id is it ja + 21 1 24 84 24 24 8 10 38 31 1 22 33 + + ko lg lt lv ms nb nl nn no pl pt pt_BR ro + +-------------------------------------------+ + a2ps | () [] [] () () [] [] | + aegis | () () | + ant-phone | [] [] | + anubis | [] [] [] [] [] | + ap-utils | [] () [] | + bash | [] [] | + batchelor | [] | + bfd | [] | + binutils | | + bison | [] [] [] [] | + bluez-pin | [] [] [] | + clisp | [] | + clisp | | + coreutils | [] | + cpio | [] [] [] [] [] | + darkstat | [] [] [] [] | + diffutils | [] [] [] [] | + e2fsprogs | [] | + enscript | [] [] [] | + error | [] [] [] | + fetchmail | [] [] () | + fileutils | [] | + findutils | [] [] [] [] [] | + flex | [] [] [] [] | + fslint | [] [] | + gas | | + gawk | [] [] [] | + gbiff | [] [] | + gcal | | + gcc | | + gettext | [] [] [] | + gettext-examples | [] [] | + gettext-runtime | [] [] [] | + gettext-tools | [] [] [] | + gimp-print | [] | + gliv | [] [] [] | + glunarclock | [] [] [] | + gnubiff | | + gnucash | [] [] () | + gnucash-glossary | [] [] | + gnupg | [] | + gpe-aerial | [] [] [] | + gpe-beam | [] [] [] | + gpe-calendar | [] [] [] | + gpe-clock | [] [] [] | + gpe-conf | [] [] [] | + gpe-contacts | [] [] [] | + gpe-edit | [] [] [] | + gpe-go | [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] [] | + gpe-sketchbook | [] [] [] | + gpe-su | [] [] [] | + gpe-taskmanager | [] [] [] | + gpe-timesheet | [] [] [] | + gpe-today | [] [] [] | + gpe-todo | [] [] [] | + gphoto2 | [] | + gprof | [] [] | + gpsdrive | () () () [] | + gramadoir | [] | + grep | [] [] [] [] | + gretl | | + gtick | [] [] | + hello | [] [] [] [] [] [] [] [] [] [] | + id-utils | [] [] [] | + indent | [] [] [] | + jpilot | () () | + jtag | | + jwhois | [] [] [] [] | + kbd | [] [] [] | + latrine | [] | + ld | | + libc | [] [] [] [] [] | + libgpewidget | [] [] [] | + libiconv | [] [] [] [] | + lifelines | | + lilypond | | + lingoteach | | + lingoteach_lessons | | + lynx | [] [] | + m4 | [] [] [] [] | + mailutils | [] | + make | [] [] [] [] | + man-db | [] | + minicom | [] [] [] | + mysecretdiary | [] [] [] | + nano | [] [] [] [] | + nano_1_0 | [] [] [] [] [] | + opcodes | [] [] | + parted | [] [] [] [] | + ptx | [] [] [] [] [] [] [] | + python | | + radius | [] | + recode | [] [] [] | + screem | | + scrollkeeper | [] [] [] [] | + sed | [] [] [] | + sh-utils | [] | + shared-mime-info | [] | + sharutils | [] | + sketch | [] [] | + soundtracker | | + sp | | + tar | [] [] [] [] [] [] | + texinfo | [] [] [] | + textutils | [] [] | + tin | | + tuxpaint | [] [] [] [] [] [] [] [] [] | + util-linux | [] [] | + vorbis-tools | [] [] | + wastesedge | | + wdiff | [] [] [] [] | + wget | [] [] | + xchat | [] [] | + xfree86_xkb_xml | [] | + xpad | [] [] | + +-------------------------------------------+ + ko lg lt lv ms nb nl nn no pl pt pt_BR ro + 11 0 1 2 12 10 60 4 4 38 23 34 74 + + ru sk sl sr sv ta tr uk vi wa zh_CN zh_TW + +-------------------------------------------+ + a2ps | [] [] [] [] [] | 16 + aegis | () | 0 + ant-phone | | 2 + anubis | [] [] [] | 9 + ap-utils | () | 3 + bash | [] | 9 + batchelor | | 2 + bfd | [] [] | 6 + binutils | [] [] [] | 7 + bison | [] [] [] | 14 + bluez-pin | [] [] [] | 13 + clisp | | 5 + clisp | | 0 + coreutils | [] [] [] [] [] | 16 + cpio | [] [] [] | 14 + darkstat | [] [] [] () () | 12 + diffutils | [] [] [] [] | 22 + e2fsprogs | [] [] | 5 + enscript | [] [] [] | 12 + error | [] [] [] | 15 + fetchmail | [] [] [] | 11 + fileutils | [] [] [] [] [] [] | 16 + findutils | [] [] [] [] [] [] [] | 29 + flex | [] [] [] | 13 + fslint | | 2 + gas | [] | 3 + gawk | [] [] | 12 + gbiff | | 3 + gcal | [] [] | 4 + gcc | [] | 4 + gettext | [] [] [] [] [] [] | 16 + gettext-examples | [] [] | 9 + gettext-runtime | [] [] [] [] [] [] [] [] [] | 21 + gettext-tools | [] [] [] [] [] [] | 14 + gimp-print | [] [] | 10 + gliv | | 3 + glunarclock | [] [] [] [] | 15 + gnubiff | | 1 + gnucash | [] [] [] | 9 + gnucash-glossary | [] [] [] | 8 + gnupg | [] [] [] [] | 17 + gpe-aerial | [] [] | 7 + gpe-beam | [] [] | 8 + gpe-calendar | [] [] [] [] [] | 13 + gpe-clock | [] [] [] | 9 + gpe-conf | [] [] [] | 9 + gpe-contacts | [] [] [] [] | 11 + gpe-edit | [] [] [] [] [] | 11 + gpe-go | [] | 5 + gpe-login | [] [] [] [] [] | 12 + gpe-ownerinfo | [] [] [] [] | 12 + gpe-sketchbook | [] [] [] | 9 + gpe-su | [] [] [] | 9 + gpe-taskmanager | [] [] [] | 9 + gpe-timesheet | [] [] [] [] | 11 + gpe-today | [] [] [] [] [] | 12 + gpe-todo | [] [] [] [] [] | 12 + gphoto2 | [] [] [] | 11 + gprof | [] [] | 9 + gpsdrive | [] [] | 4 + gramadoir | | 3 + grep | [] [] [] [] [] | 26 + gretl | | 2 + gtick | [] | 5 + hello | [] [] [] [] [] | 33 + id-utils | [] [] [] | 12 + indent | [] [] [] [] [] | 21 + jpilot | [] [] [] [] [] | 9 + jtag | [] | 1 + jwhois | () () [] [] | 11 + kbd | [] [] | 11 + latrine | | 1 + ld | [] [] | 5 + libc | [] [] [] [] | 20 + libgpewidget | [] [] [] | 12 + libiconv | [] [] [] [] [] [] [] [] [] | 27 + lifelines | [] | 2 + lilypond | [] | 3 + lingoteach | | 2 + lingoteach_lessons | () | 0 + lynx | [] [] [] [] | 14 + m4 | [] [] [] | 15 + mailutils | [] | 4 + make | [] [] [] [] | 16 + man-db | [] | 5 + minicom | [] | 11 + mysecretdiary | [] [] | 10 + nano | [] [] [] [] [] | 17 + nano_1_0 | [] [] [] [] | 17 + opcodes | [] [] | 6 + parted | [] [] [] | 15 + ptx | [] [] [] | 22 + python | | 0 + radius | [] | 2 + recode | [] [] [] [] | 20 + screem | [] [] | 2 + scrollkeeper | [] [] [] [] | 15 + sed | [] [] [] [] [] [] | 23 + sh-utils | [] [] [] | 14 + shared-mime-info | [] [] | 4 + sharutils | [] [] [] [] [] | 17 + sketch | [] | 6 + soundtracker | [] [] | 9 + sp | [] | 3 + tar | [] [] [] [] [] | 24 + texinfo | [] [] [] [] | 14 + textutils | [] [] [] [] [] | 16 + tin | | 1 + tuxpaint | [] [] [] [] [] | 29 + util-linux | [] [] [] | 15 + vorbis-tools | [] | 8 + wastesedge | | 0 + wdiff | [] [] [] [] | 18 + wget | [] [] [] [] [] [] [] [] | 23 + xchat | [] [] [] [] [] | 14 + xfree86_xkb_xml | [] [] [] [] | 6 + xpad | | 4 + +-------------------------------------------+ + 51 teams ru sk sl sr sv ta tr uk vi wa zh_CN zh_TW + 117 domains 58 41 16 16 78 0 53 12 1 10 21 22 1230 + + Some counters in the preceding matrix are higher than the number of +visible blocks let us expect. This is because a few extra PO files are +used for implementing regional variants of languages, or language +dialects. + + For a PO file in the matrix above to be effective, the package to +which it applies should also have been internationalized and +distributed as such by its maintainer. There might be an observable +lag between the mere existence a PO file and its wide availability in a +distribution. + + If November 2003 seems to be old, you may fetch a more recent copy +of this `ABOUT-NLS' file on most GNU archive sites. The most +up-to-date matrix with full percentage details can be found at +`http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'. + +Using `gettext' in new packages +=============================== + +If you are writing a freely available program and want to +internationalize it you are welcome to use GNU `gettext' in your +package. Of course you have to respect the GNU Library General Public +License which covers the use of the GNU `gettext' library. This means +in particular that even non-free programs can use `libintl' as a shared +library, whereas only free software can use `libintl' as a static +library or use modified versions of `libintl'. + + Once the sources are changed appropriately and the setup can handle +the use of `gettext' the only thing missing are the translations. The +Free Translation Project is also available for packages which are not +developed inside the GNU project. Therefore the information given above +applies also for every other Free Software Project. Contact +`translation@iro.umontreal.ca' to make the `.pot' files available to +the translation teams. + diff --git a/contrib/cpio/AUTHORS b/contrib/cpio/AUTHORS new file mode 100644 index 0000000..980c8f3 --- /dev/null +++ b/contrib/cpio/AUTHORS @@ -0,0 +1,6 @@ +Authors of GNU cpio + +Phil Nelson <phil@cs.wwu.edu> +David MacKenzie <djm@gnu.ai.mit.edu> +John Oleynick <juo@klinzhai.rutgers.edu> +Sergey Poznyakoff <gray@mirddin.farlep.net>
\ No newline at end of file diff --git a/contrib/cpio/COPYING b/contrib/cpio/COPYING index a43ea21..d60c31a 100644 --- a/contrib/cpio/COPYING +++ b/contrib/cpio/COPYING @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 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. @@ -279,7 +279,7 @@ POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - Appendix: How to Apply These Terms to Your New Programs + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -291,7 +291,7 @@ 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. <one line to give the program's name and a brief idea of what it does.> - Copyright (C) 19yy <name of author> + Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -305,14 +305,15 @@ the "copyright" line and a pointer to where the full notice is found. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/contrib/cpio/ChangeLog b/contrib/cpio/ChangeLog index eaf14a9..695be81 100644 --- a/contrib/cpio/ChangeLog +++ b/contrib/cpio/ChangeLog @@ -1,3 +1,433 @@ +2004-12-20 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + Released version 2.6. Sources up to this point are tagged + release_2_6. + + * configure.ac: Raised version number to 2.6 + * NEWS: Likewise + * bootstrap (update_po): Give -r to wget. Always remove index.html + Ignore alloca-opt module (it duplicates alloca) + +2004-11-23 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * src/main.c (enum cpio_options): Bugfix: Initialize first enum + value to 256. + * bootstrap: Add unlocked-io + * headers/argp.h: Removed + * headers/getopt.h: Removed + * headers/Makefile.am: Updated + +2004-10-14 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * src/copyout.c: Add trailing slash to directory names in + ustar format. + * src/makepath.c: Removed redeclaration of error(). + * src/tar.c: Fixed deviations from POSIX.1-1988: + Properly split long file names. Fill in octal fields with zeros, + not spaces. Save only protection modes, not the whole mode. + + * NEWS: Updated + +2004-09-08 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * NEWS: Updated + * TODO: Updated + * bootstrap: Install po files by default + * po/LINGUAS: Removed. File is generated automatically + * po/.cvsignore: Updated + * src/copyin.c: Implemented --to-stdout option + * src/copyout.c: Display the annoying 'truncating inode number' + message only if the user wishes it. + * src/extern.h: Added new globals. + * src/global.c: Likewise. + + * src/main.c: Added support for --to-stdout and --warning options + * src/tar.c (read_in_tar_header): Use warn_junk_bytes() + * src/util.c (create_all_directories): Use dir_name. + + * configure.ac: Added support for the test suite + * Makefile.am: Likewise + + * tests: New directory + * tests/.cvsignore: New file + * tests/Makefile.am: New file + * tests/testsuite.at: New file + * tests/inout.at: New file + * tests/version.at: New file + * tests/atlocal.in: New file + +2004-09-07 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * src/main.c (process_args): Bugfix. Allow extra arguments + in copy_in mode. + * src/util.c (write_nuls_to_file): Use buffered I/O. All + callers changed. Thanks Matthew Braithwaite <mab@cnet.com> + for noticing. + Bugfix: extra_bytes was mistakenly used instead of blocks. + * THANKS: Added Matthew Braithwaite. + +2004-09-06 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + Started merging with tar into paxutils. Sources before + this point are tagged alpha-2_50_90. + + * bootstrap: New file + * autogen.sh: Removed + * Makefile.am: Updated + * NEWS: Updated + * README-alpha: Updated + * configure.ac: Updated + * doc/cpio.1: Updated + * po/POTFILES.in: Updated + + * src/Makefile.am: Updated + * src/error.c: Removed + * src/dirname.c: Likewise + * src/xmalloc.c: Likewise + * src/stripslash.c: Likewise + * src/xstrdup.c + * src/gettext.h: Likewise + * src/system.h: Likewise + * src/rmt.h: Likewise + * src/getopt.c: Likewise + * src/getopt1.c: Likewise + * src/bcopy.c: Likewise + * src/fnmatch.c: Likewise + * src/mkdir.c: Likewise + * src/strdup.c: Likewise + * src/argp-ba.c: Likewise + * src/argp-eexst.c: Likewise + * src/argp-fmtstream.c: Likewise + * src/argp-fs-xinl.c: Likewise + * src/argp-help.c: Likewise + * src/argp-parse.c: Likewise + * src/argp-pv.c: Likewise + * src/argp-pvh.c: Likewise + * src/argp-xinl.c: Likewise + * src/pin.c: Likewise + * src/alloca.c: Likewise + * src/argmatch.c: Likewise + * src/rmt.c: Likewise + * src/rtapelib.c: Likewise + * src/strerror.c: Likewise + + * src/copyin.c: Switched to ANSI C (sigh) + * src/copyout.c: Likewise + * src/copypass.c: Likewise + * src/defer.c: Likewise + * src/defer.h: Likewise + * src/dstring.c: Likewise + * src/dstring.h: Likewise + * src/extern.h: Likewise + * src/filemode.c: Likewise + * src/global.c: Likewise + * src/idcache.c: Likewise + * src/main.c: Likewise + * src/makepath.c: Likewise + * src/mt.c: Likewise + * src/tar.c: Likewise + * src/userspec.c: Likewise + * src/util.c: Likewise + + * lib: New directory + * lib/Makefile.tmpl: New file + * lib/bcopy.c: Moved from ../src + * lib/mkdir.c: Likewise. + * lib/strdup.c: Likewise. + * lib/strerror.c: Likewise. + +2004-08-30 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * Makefile.am: Added headers to SUBDIRS. + * configure.ac: Check for AC_SYS_LARGEFILE. + Use AC_CONFIG_LINKS to provide for fnmatch.h and getopt.h on + the systems where these are missing + Check for argp and replace it if necessary. + * src/Makefile.am: Updated + * src/fnmatch.h: Moved to headers/ + * src/getopt.h: Likewise. + * src/main.c: Option parsing rewritten using argp. Improved + option consistency checking. + * src/rmt.c: Include getopt.h + + * src/argp-ba.c: New file + * src/argp-eexst.c: New file + * src/argp-fmtstream.c: New file + * src/argp-fs-xinl.c: New file + * src/argp-help.c: New file + * src/argp-parse.c: New file + * src/argp-pv.c: New file + * src/argp-pvh.c: New file + * src/argp-xinl.c: New file + * src/pin.c: New file + + * headers: New directory + * headers/Makefile.am: New file + * headers/getopt.h: New file + * headers/argp.h: New file + * headers/fnmatch.h: New file + * headers/.cvsignore: New file + +2004-03-02 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * src/util.c (copy_files_disk_to_disk): Bugfix. If a file + grew n bytes in copy-pass mode, these n bytes got prepended + to the contents of all subsequent files. Fix provided by + Holger Fleischmann <holger_fleischmann@mra.man.de> + * THANKS: Added Holger Fleischmann. + +2004-02-27 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * src/makepath.c: Remove unneded typedefs + + * src/copyin.c: Remove __MSDOS__ conditionals + * src/copyout.c: Likewise + * src/copypass.c: Likewise + * src/main.c: Likewise + * src/tar.c: Likewise + * src/util.c: Likewise + +2004-02-27 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + Changed from flat to deep package layout. Added the framework + for NLS support. + + * .cvsignore: Updated + * Makefile.am: Updated + * configure.ac: Updated + * NEWS: Updated + * README-alpha: Updated + * THANKS: Updated + + * autogen.sh: New file + + * alloca.c: Moved to src + * argmatch.c: Likewise + * bcopy.c: Likewise + * dstring.h: Likewise + * copyin.c: Likewise + * copyout.c: Likewise + * copypass.c: Likewise + * cpio.h: Likewise + * cpiohdr.h: Likewise + * defer.c: Likewise + * defer.h: Likewise + * dirname.c: Likewise + * dstring.c: Likewise + * dstring.h: Likewise + * error.c: Likewise + * extern.h: Likewise + * filemode.c: Likewise + * filetypes.h: Likewise + * fnmatch.c: Likewise + * fnmatch.h: Likewise + * getopt.c: Likewise + * getopt.h: Likewise + * getopt1.c: Likewise + * global.c: Likewise + * idcache.c: Likewise + * main.c: Likewise + * makepath.c: Likewise + * mkdir.c: Likewise + * mt.c: Likewise + * rmt.c: Likewise + * rmt.h: Likewise + * rtapelib.c: Likewise + * safe-stat.h: Likewise + * strdup.c: Likewise + * strerror.c: Likewise + * stripslash.c: Likewise + * system.h: Likewise + * tar.c: Likewise + * tar.h: Likewise + * tarhdr.h: Likewise + * userspec.c: Likewise + * util.c: Likewise + * xmalloc.c: Likewise + * xstrdup.c: Likewise + + * cpio.1: Moved to doc + * cpio.texi: Likewise + * mt.1: Likewise + + * src: New directory + * src/.cvsignore: New file + * src/Makefile.am: Likewise + * src/alloca.c: Likewise + * src/argmatch.c: Likewise + * src/bcopy.c: Likewise + * src/copyin.c: Likewise + * src/copyout.c: Likewise + * src/copypass.c: Likewise + * src/cpio.h: Likewise + * src/cpiohdr.h: Likewise + * src/defer.c: Likewise + * src/defer.h: Likewise + * src/dirname.c: Likewise + * src/dstring.c: Likewise + * src/dstring.h: Likewise + * src/error.c: Likewise + * src/extern.h: Likewise + * src/filemode.c: Likewise + * src/filetypes.h: Likewise + * src/fnmatch.c: Likewise + * src/fnmatch.h: Likewise + * src/getopt.c: Likewise + * src/getopt.h: Likewise + * src/getopt1.c: Likewise + * src/gettext.h: Likewise + * src/global.c: Likewise + * src/idcache.c: Likewise + * src/main.c: Likewise + * src/makepath.c: Likewise + * src/mkdir.c: Likewise + * src/mt.c: Likewise + * src/rmt.c: Likewise + * src/rmt.h: Likewise + * src/rtapelib.c: Likewise + * src/safe-stat.h: Likewise + * src/strdup.c: Likewise + * src/strerror.c: Likewise + * src/stripslash.c: Likewise + * src/system.h: Likewise + * src/tar.c: Likewise + * src/tar.h: Likewise + * src/tarhdr.h: Likewise + * src/userspec.c: Likewise + * src/util.c: Likewise + * src/xmalloc.c: Likewise + * src/xstrdup.c: Likewise + + * doc: New directory + * doc/.cvsignore: New file + * doc/Makefile.am: New file + * doc/cpio.1: New file + * doc/cpio.info: New file + * doc/cpio.texi: New file + * doc/mt.1: New file + + * po: New directory + * po/.cvsignore: New file + * po/LINGUAS: New file + * po/Makevars: New file + * po/POTFILES.in: New file + +2003-11-28 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * configure.ac: Added various checks + * Makefile.am (rmt_LDADD): Added. + * error.c: Updated + * rmt.c: Removed useless private_errstring + * system.h: Updated + * userspec.c: Changed the way of handling declared vs. undeclared + system calls. + * strerror.c: New file. Borrowed from GNU Radius. + + * copyin.c: Removed kludgy declaration of delayed_seek_count. + * copypass.c: Likewise + * extern.h: Declare delayed_seek_count. + * mkdir.c: Fixed handling of undeclared errno + * mt.c: Likewise + * util.c: Likewise + * rtapelib.c: Likewise + +2003-11-28 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * TODO: New file + + * README-alpha: New file + * Makefile.am: Require at least version 1.7.1 + * configure.ac: Check for locale.h + * main.c (main): Call setlocale. Thanks + Mitsuru Chinen <mchinen@yamato.ibm.com> for the patch. + * THANKS: Updated + +2003-11-21 Sergey Poznyakoff <gray@Mirddin.farlep.net> + + * configure.ac: Added to the repository + * Makefile.am: Likewise + * NEWS: Likewise + * README: Likewise + * AUTHORS: Likewise + * .cvsignore: Likewise + + * configure.in: Removed + * Makefile.in: Removed + * makefile.pc: Removed + * configure: Removed + + * alloca.c: Added to the repository + * argmatch.c: Likewise + * bcopy.c: Likewise + * cpio.h: Likewise + * cpiohdr.h: Likewise + * defer.c: Likewise + * defer.h: Likewise + * dirname.c: Likewise + * dstring.c: Likewise + * dstring.h: Likewise + * error.c: Likewise + * filemode.c: Likewise + * filetypes.h: Likewise + * fnmatch.c: Likewise + * fnmatch.h: Likewise + * getopt.c: Likewise + * getopt.h: Likewise + * getopt1.c: Likewise + * idcache.c: Likewise + * mkdir.c: Likewise + * rmt.h: Likewise + * rtapelib.c: Likewise + * safe-stat.h: Likewise + * strdup.c: Likewise + * stripslash.c: Likewise + * tar.c: Likewise + * tar.h: Likewise + * tarhdr.h: Likewise + * xmalloc.c: Likewise + * xstrdup.c: Likewise + + * makepath.c: Updated + * mt.c: Likewise. + * rmt.c: Likewise. + * util.c: Likewise. + * copyin.c: Likewise. + * copyout.c: Likewise. + * copypass.c: Likewise. + * global.c: Likewise. + * main.c: Likewise. + +Thu Jun 13 20:14:48 2002 John Oleynick (juo@gnu.org) + * copyin.c: Strip leading / on absolute filenames after + comparing to the list of files specified on the command line + (instead of before). Problem reported by Jeff Holt. + * Version 2.5 released. + +Thu Jun 13 00:20:30 2002 John Oleynick (juo@gnu.org) + * Makefile.in: Fixed problem of looking in srcdir for info files. + Bug reported by Mike Castle. + * cpio.texi: Fixed typo. Problem reported by Fabrice Bauzac. + +Sun Jan 13 18:45:02 2002 John Oleynick (juo@gnu.org) + * copyin.c: Fixed a problem skipping files with multiple links + in a newc or CRC format archive. If the file with the shared copy + of the data was skipped, but other links were not skipped, the + other links were created as empty files. Bug reported by + Hendrik-Jan Thomassen. + +Thu Dec 6 20:05:10 2001 John Oleynick (juo@gnu.org) + * mt.c, mt.1: Merged Debian --rsh-command option and -V fix. + * copyout.c, copypass.c, util.c, extern.h: Modified to warn + if a file grows or its mtime is changed while it is being + copied. + +Wed Dec 6 00:02:04 2001 John Oleynick (juo@gnu.org) + * Many files: Updated FSF's address in copyright notices. + +Wed Aug 29 23:57:05 2001 John Oleynick (juo@gnu.org) + * Many files: Numerous fixes from Debian, Red Hat and SuSE + GNU/Linux distributions. + Tue Jan 16 19:03:05 1996 John Oleynick (juo@wombat.gnu.ai.mit.edu) * util.c: An I/O error reading a file would cause the last byte of the next file to be corrupted in the archive. Thanks to a @@ -962,7 +1392,6 @@ Sat Dec 2 13:22:37 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) (usage): Mention long options in message. Local Variables: -mode: indented-text -left-margin: 8 +mode: change-log version-control: never End: diff --git a/contrib/cpio/INSTALL b/contrib/cpio/INSTALL new file mode 100644 index 0000000..095b1eb --- /dev/null +++ b/contrib/cpio/INSTALL @@ -0,0 +1,231 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PREFIX', the package will +use PREFIX as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/contrib/cpio/NEWS b/contrib/cpio/NEWS index 5da98da..b7dc861 100644 --- a/contrib/cpio/NEWS +++ b/contrib/cpio/NEWS @@ -1,3 +1,44 @@ +GNU cpio NEWS -- history of user-visible changes. 2004-12-20 +Copyright (C) 2003, 2004 Free Software Foundation, Inc. +See the end of file for copying conditions. + +Please send cpio bug reports to <bug-cpio@gnu.org>. + +Version 2.6 + +* Added NLS support + +* Improved configure script + +* Improved invocation consistency checking and help output + +* Printing warning about truncation of inode numbers is suppressed by +default. See below. + +* New option --warning (-W) controls the level of output warnings: + + -Wnone Disables all warnings + -Wtruncate Enable warning about truncation of the inode number + -Wall Enables all warnings + + To disable a particular warning, prefix its name with 'no-', just + like in gcc. + +* New option --to-stdout extracts files to standard output. + +* The output of `cpio --help' is largely improved. + +* Bugfixes: +** If a file grew n bytes in copy-pass mode, these n bytes got prepended +to the contents of all subsequent files. +** Padding the archive with zero bytes upon truncation of the file being +archived was broken. + + +Major changes in version 2.5: + +* bug fixes from Debian, Red Hat, and SuSE GNU/Linux Distribution patches +* --rsh-command option Major changes in version 2.4: @@ -62,3 +103,23 @@ Some options have changed meaning in 2.0, for SVR4 compatibility: Version 2.0 also fixes several bugs in the handling of files with multiple links and of multi-volume archives on floppy disks. + +---------------------------------------------------------------------- +Copyright information: + +Copyright (C) 2003, 2004 Free Software Foundation, Inc. + + Permission is granted to anyone to make or distribute verbatim copies + of this document as received, in any medium, provided that the + copyright notice and this permission notice are preserved, + thus giving the recipient permission to redistribute in turn. + + Permission is granted to distribute modified versions + of this document, or of portions of it, + under the above conditions, provided also that they + carry prominent notices stating who last changed them. + +Local variables: +mode: outline +paragraph-separate: "[ ]*$" +end: diff --git a/contrib/cpio/README b/contrib/cpio/README index 8206e97..fafff13 100644 --- a/contrib/cpio/README +++ b/contrib/cpio/README @@ -9,7 +9,8 @@ operations, respectively. See the file INSTALL for compilation and installation instructions for Unix. -For non-Unix systems: +For non-Unix systems [ Note: The non-Unix makefiles have not been tested + for this release ] makefile.pc is a makefile for Turbo C or C++ or Borland C++ on MS-DOS. @@ -67,5 +68,4 @@ than 100 characters. That's why it's not an official part of GNU tar. *stdp = 1; if (wantug) { -Mail suggestions and bug reports for GNU cpio to -bug-gnu-utils@prep.ai.mit.edu. +Mail suggestions and bug reports for GNU cpio to bug-cpio@gnu.org. diff --git a/contrib/cpio/THANKS b/contrib/cpio/THANKS new file mode 100644 index 0000000..bef8514 --- /dev/null +++ b/contrib/cpio/THANKS @@ -0,0 +1,14 @@ +GNU cpio THANKS file + +GNU cpio has originally been written by Phil Nelson <phil@cs.wwu.edu> +and David MacKenzie <djm@gnu.ai.mit.edu>. It was further modified +by John Oleynick <juo@gnu.org> and Sergey Poznyakoff <gray@gnu.org> +who currently maintains it. + +The following is a list of people who contributed to GNU cpio by +reporting problems, suggesting various improvements or submitting actual +code. Help us keep it complete and exempt of errors. + +Matthew Braithwaite <mab@cnet.com> +Mitsuru Chinen <mchinen@yamato.ibm.com> +Holger Fleischmann <holger_fleischmann@mra.man.de>
\ No newline at end of file diff --git a/contrib/cpio/TODO b/contrib/cpio/TODO new file mode 100644 index 0000000..5ba1030 --- /dev/null +++ b/contrib/cpio/TODO @@ -0,0 +1,356 @@ +Following is the list of cpio-related reports to bug-gnu-utils. +Many of them appear to be fixed, but quite a number of them is +probably still waiting for being handled. The list is sorted +in reverse chronological order. + + 4. copyin.c cpio probably questions/rfc (score: 35) + Author: Grzegorz Jaskiewicz <gj@pointblue.com.pl> + Date: Tue, 24 Jun 2003 17:12:45 +0100 + Hi! I am currently working on module that (in GNU software) + will be able to read/write cpio format (only ascii). Thus i am + separating some of cpio structures into libcpio. I've been + going through cop + /archive/html/bug-gnu-utils/2003-06/msg00422.html (5,430 bytes) + + 5. RE: Problem when building on HP-UX 11i(11.11) (score: 4) + Author: "Leon Strydom" <leon.strydom@tasima.co.za> + Date: Thu, 13 Mar 2003 09:10:02 +0200 + Hi Bob, I got it to compile, thanks. The reason why I had to + try GNU-Tar is because of the 2GB file size limit problems: + Here are the errors I got: With TAR(hp-ux 11i tar): CMD: tar + cvf backup.tar /a + /archive/html/bug-gnu-utils/2003-03/msg00106.html (5,191 bytes) + + 6. cpio - large file support (score: 35) + Author: "Keith Ansell" <keitha@edp.fastfreenet.com> + Date: Tue, 4 Mar 2003 16:24:37 -0000 + Can you help. I need to archive a large database, this will + create a cpio file greater than 2 Gigabytes. Have you added + large file support to the build of cpio. Regards Keith + Ansell..... + /archive/html/bug-gnu-utils/2003-03/msg00024.html (4,329 bytes) + + 7. cpio-2.5 typos (score: 36) + Author: Thomas Klausner <wiz@danbala.ifoer.tuwien.ac.at> + Date: Sat, 21 Dec 2002 23:53:38 +0100 + In cpio-2.5, in cpio.texi (and thus cpio.1) and main.c the word + 'compatibility' is misspelled as 'compatability'. Please fix, + thanks. Thomas -- Thomas Klausner - wiz@bogus.example.com What + is wanted + /archive/html/bug-gnu-utils/2002-12/msg00200.html (3,783 bytes) + + 9. Re: bug in cpio with tapechange in copy-in-mode (score: 46) + Author: Paul Eggert <eggert@twinsun.com> + Date: Mon, 5 Aug 2002 12:28:33 -0700 (PDT) + Thanks for your bug report. Can you please verify that the bug + still exists in the latest CPIO version + <ftp://ftp.gnu.org/gnu/cpio/cpio-2.5.tar.gz>, and if so, please + send a patch to <bug-cpio@bogus. + /archive/html/bug-gnu-utils/2002-08/msg00127.html (4,275 bytes) + + 10. bug in cpio with tapechange in copy-in-mode (score: 34) + Author: Bernd =?ISO-8859-1?Q?Sch=FCler?= + <b.schueler@eckert-buerotechnik.de> + Date: 05 Aug 2002 18:37:56 +0200 + Hello, last i made a restore from tape, and no request for next + tape happend, only an read-error occured. Here is an quick + patch, please verify the problem and the patch-code. I'm not + sure, if the pr + /archive/html/bug-gnu-utils/2002-08/msg00122.html (4,518 bytes) + + 11. Re: CPIO Bug ? (score: 36) + Author: Albert Chin <bug-gnu-utils@lists.thewrittenword.com> + Date: Thu, 4 Jul 2002 19:31:04 -0500 + I think the default CPIO format understands only 16-bit inodes. + Look at the -H option. '-H newc' should work better for you. -- + albert chin (china@bogus.example.com) + /archive/html/bug-gnu-utils/2002-07/msg00091.html (4,286 bytes) + + 14. Re: bug in cpio? (score: 40) + Author: kasal@matsrv.math.cas.cz (Stepan Kasal) + Date: Thu, 13 Jun 2002 07:44:14 +0000 (UTC) + Hallo, the following option should help: -d, --make-directories + Create leading directories where needed. Details: cpio won't + create the directory for the file. Observe: kasal$ echo + /home/kasal/tmp/db + /archive/html/bug-gnu-utils/2002-06/msg00306.html (4,862 bytes) + + 15. bug in cpio? (score: 34) + Author: "Jeff Holt" <jeff.holt@hotsos.com> + Date: Wed, 12 Jun 2002 14:07:59 -0500 + According to the man page, I should be able to extract an + absolute pathname from an archive and have the file created + relative to the current directory (by removing the leading + ‘/’).<o:p> + /archive/html/bug-gnu-utils/2002-06/msg00296.html (5,331 bytes) + + 16. CPIO Bug ? (score: 35) + Author: =?iso-8859-1?Q?Gr=E9goire_Fiot?= + <gfiot@eiffageconstruction.fr> + Date: Tue, 14 May 2002 17:01:18 +0200 + Hello, We ve got a problem here using cpio: many "troncating + inode number" appear during the process: cpio -ocv Is that a + real problem? Does it corrupt files? Well.. what does that + mean? We have look + /archive/html/bug-gnu-utils/2002-05/msg00333.html (3,855 bytes) + + 23. [cpio texinfo] typo (score: 2) + Author: fabrice bauzac <fabrice.bauzac@wanadoo.fr> + Date: Tue, 7 May 2002 16:37:28 +0200 + Good afternoon, There is a typo in the Texinfo documentation of + GNU cpio, node "Copy-in mode": [--format=format] + [--owner=[user][:.][group]] [--no- preserve-owner] + [--message=message] [--help] [--ver + /archive/html/bug-gnu-utils/2002-05/msg00153.html (4,040 bytes) + + 26. cpio: memory exhausted (score: 43) + Author: Thomas McLaughlin <tamm@scotlegal.com> + Date: Thu, 18 Apr 2002 09:51:18 +0100 + This is probably not the place for my query, but I have + exhausted other avenues and would be glad of some help. I can't + work out what's going on with my nightly cpio backup. If I do: + cd / find . -pri + /archive/html/bug-gnu-utils/2002-04/msg00406.html (4,988 bytes) + + 30. cpio 2.4.2 bug? (score: 40) + Author: "H.J. Thomassen" <H.J.Thomassen@ATComputing.nl> + Date: Thu, 10 Jan 2002 18:09:10 +0100 (CET) + Hello, We use GNU-cpio 2.4.2 and have the following problem: + Short: Assume I have a directory with two filenames, which are + hardlinks to the same i-node. I make a crc-cpio archive with + both files; th + /archive/html/bug-gnu-utils/2002-01/msg00161.html (5,624 bytes) + + 32. GNU cpio suggestion (score: 42) + Author: "H.J.Thomassen" <hjt@ATComputing.nl> + Date: Mon, 17 Dec 2001 11:27:11 +0100 + Re: suggestion for GNU-cpio extension (plus reference + implementation) We use cpio for our backup purposes. The backup + is started automatically in the middle of the night. To chase + away all users we d + /archive/html/bug-gnu-utils/2001-12/msg00244.html (7,474 bytes) + + 35. GNU cpio compile problem (score: 34) + Author: Daniel Savard <dsavard@videotron.ca> + Date: Wed, 14 Nov 2001 12:43:11 -0500 + Hi, I am trying to make the GNU cpio utility (version 2.4.2) + using the gcc 3.0.2 compiler. The make failed on the userspec.c + file compilation. I then tried to compile with gcc 2.95.3 with + the followi + /archive/html/bug-gnu-utils/2001-11/msg00180.html (5,518 bytes) + + 36. cpio -d bug (fwd) (score: 47) + Author: Christian Smith <csmith@micromuse.com> + Date: Wed, 14 Nov 2001 02:06:46 +0000 (GMT) + This was bounced from bug-cpio@bogus.example.com I guess that + isn't set up yet. -- /"\ \ / ASCII RIBBON CAMPAIGN - AGAINST + HTML MAIL X - AGAINST MS ATTACHMENTS / \ $ cpio --version GNU + cpio version 2 + /archive/html/bug-gnu-utils/2001-11/msg00170.html (4,548 bytes) + + 38. [cpio] man page enhancement: a Example section ? (score: 5) + Author: Yannick Patois <patois@calvix.org> + Date: Wed, 24 Oct 2001 12:48:33 +0200 (CEST) + Hello, I seldom use cpio (as I think many people) and only had + to use it once or twice. IMHA, would be good to have a small + section with an example of most often performed actions + (creating an archiv + /archive/html/bug-gnu-utils/2001-10/msg00270.html (4,336 bytes) + + 39. Patch to cpio to enable verbose *skipping* of files (score: 40) + Author: Tomas Pospisek <tpo@sourcepole.ch> + Date: Mon, 8 Oct 2001 13:54:14 +0200 (CEST) + This patch enables cpio to be verbose about the files that it + does not copy, which is very handy for seeing cpio's progress + through a tape or simply for debuging. The patch along with a + Debian packag + /archive/html/bug-gnu-utils/2001-10/msg00083.html (4,548 bytes) + + 40. cpio-2.4.2 patch (score: 39) + Author: Alex Efros <powerman@sky.net.ua> + Date: Wed, 29 Aug 2001 07:36:31 +0300 (EEST) + Hi. Linux-2.4.9, GCC-3.0, GLIBC-2.2.4, cpio-2.4.2. Compile-time + errors: --cut-- gcc -c -DRETSIGTYPE=void -DHAVE_SYS_MTIO_H=1 + -DHAVE_NETDB_H=1 -DSTDC_HEADERS=1 -DHAVE_UNISTD_H=1 + -DHAVE_STRING_H=1 -DHA + /archive/html/bug-gnu-utils/2001-08/msg00264.html (5,259 bytes) + + 41. cpio copy-in and multiply-linked files (score: 35) + Author: Chris Jaeger <cjaeger@ensim.com> + Date: Tue, 07 Aug 2001 23:46:04 -0700 + Hi, I was wondering whether it was a bug or a feature that GNU + cpio, while in copy-in mode, will create a multiply-linked set + of files all of size 0 if the last linked file is not copied in + due to th + /archive/html/bug-gnu-utils/2001-08/msg00074.html (4,142 bytes) + + 42. Re: minor problems with slackware-current (score: 7) + Author: Cezary Sliwa <sliwa@cft.edu.pl> + Date: Wed, 1 Aug 2001 10:43:37 +0200 + "cpio --sparse" corrupts data. A fix attached. C.S. Attachment: + cpio-2.4.2-sparse.diff Description: Text document + /archive/html/bug-gnu-utils/2001-08/msg00000.html (3,989 bytes) + + 43. (no subject) (score: 2) + Author: brian@debian.org (Brian Mays) + Date: Sat, 07 Jul 2001 16:35:13 -0400 + When hard-linked files (along with many other files) are + archived to a cpio ustar format archive, the files are _not_ + all archived as hard links to each other in the archive. When + the same set of fil + /archive/html/bug-gnu-utils/2001-07/msg00080.html (5,666 bytes) + + 44. gnu cpio and files over 2G (score: 37) + Author: J.S.Peatfield@damtp.cam.ac.uk + Date: Wed, 2 May 2001 06:28:18 +0100 + As an increasing number of opertaing systems now support files + over 2G I took a look at the cpio (2.4.2) source to see how + hard it would be to make it cope, and was slightly shocked at + the number of + /archive/html/bug-gnu-utils/2001-05/msg00010.html (4,802 bytes) + + 45. cpio suggestion + patch (score: 38) + Author: Taylor Gautier <tgautier@s8.com> + Date: Fri, 20 Apr 2001 09:40:05 -0700 + I have a suggestion for cpio. The suggestion is to make it copy + files into a temporary name and then rename the file as the + last operation. Since UNIX filesystems are supposed to + gaurantee atomicity + /archive/html/bug-gnu-utils/2001-04/msg00169.html (10,674 + bytes) + + 46. [cpio 2.4.2] rmt build fails (score: 8) + Author: Gert <n8w8@n8w8.wox.org> + Date: Thu, 29 Mar 2001 21:28:52 +0200 (CEST) + Hi, The cpio 2.4.2 rmt tool fails to build on my system. I run + the following software: - Linux 2.4.2 - GCC 2.95.2 - GNU Make + 3.79.1 - GNU ld 2.10 (with BFD 2.10) - glibc 2.1.3 The build + fails like th + /archive/html/bug-gnu-utils/2001-03/msg00262.html (5,498 bytes) + + 47. cpio --sparse (score: 34) + Author: Cezary Sliwa <sliwa@cft.edu.pl> + Date: Mon, 26 Mar 2001 10:43:34 +0200 (CEST) + the '--sparse' option of gnu cpio causes data corruption + (blocks of zeros are lost or appended to other files). C.S. + /archive/html/bug-gnu-utils/2001-03/msg00235.html (3,671 bytes) + + 49. Re: bug with gnu cpio 2.4.2 (score: 38) + Author: Hans-Bernhard Broeker <broeker@physik.rwth-aachen.de> + Date: 6 Mar 2001 15:19:34 GMT + This would happen if cpio want to do any user interaction (ask + for the next tape cartridge, because the current one is full, + e.g.). Cron jobs don't have access to a terminal (/dev/tty), so + this will + /archive/html/bug-gnu-utils/2001-03/msg00029.html (5,062 bytes) + + 50. bug with gnu cpio 2.4.2 (score: 37) + Author: dominique.bieber@sagem.com + Date: Tue, 6 Mar 2001 12:27:14 +0100 + Hi, I have a problem using cpio with a Red Hat 6.2 whith a + 2.2.14-5.0smp kernel. The backup device is a HP DAT DDS4 20/40 + with the right cartridge. The cpio is launched by the cron. + During the backup + /archive/html/bug-gnu-utils/2001-03/msg00024.html (4,315 bytes) + + 52. [PATCH] cpio 2.4.2 does not compile with libc 2.2, gcc 2.95 + (score: 38) + Author: "John Fremlin" <chief@bandits.org> + Date: 11 Feb 2001 22:19:09 +0000 + In fact it violates the GNU coding standards by declaring stuff + when it shouldn't. Tsk, tsk. Attachment: cpio-2.4.2-build.patch + Description: Text Data -- http://www.penguinpowered.com/~vii + /archive/html/bug-gnu-utils/2001-02/msg00065.html (4,169 bytes) + + 53. cpio-2.4.2: data corruption bug (score: 35) + Author: Todd Kelley <toddk@oeone.com> + Date: Fri, 09 Feb 2001 17:00:06 -0500 + Hello, Recently at OEone we fixed a bug in GNU cpio-2.4.2: When + a file over about 0.5 megabyes grows while it is being + archived, it and all files following it in the archive are + corrupted. The crc do + /archive/html/bug-gnu-utils/2001-02/msg00062.html (4,297 bytes) + + 54. cpio 2.4.2 unconditionally takes the tape drive offline (score: + 39) + Author: Scott Larson <scowl@plaza.ds.adp.com> + Date: Thu, 11 Jan 2001 13:15:52 -0800 + We have been copying multiple volumes to a single tape with the + System 5 version of cpio. The gnu version of cpio doesn't + support this since it takes the tape offline (i.e. ejects the + tape) after rea + /archive/html/bug-gnu-utils/2001-01/msg00087.html (4,264 bytes) + + 55. cpio -t can see international filenames, find -ls also suffers + (score: 35) + Author: "Dan Jacobson" <jidanni@kimo.FiXcomTHiS.tw> + Date: Tue, 26 Dec 2000 07:38:53 +0800 + GNU cpio version 2.4.2 with cpio -t I can see Chinese [big5] + filenames. with -tv, they become \267\247 etc Just like what + happens with find . -print vs. find . -ls -- + http://www.geocities.com/jidanni + /archive/html/bug-gnu-utils/2000-12/msg00143.html (4,084 bytes) + + 56. cpio-2.4.2 compilation problems (score: 34) + Author: Thomas =?iso-8859-1?q?K=F6ller?= <tkoeller@gmx.net> + Date: Wed, 20 Dec 2000 02:50:24 +0100 + I encountered several problems building cpio-2.4.2. I am + running linux-2.2.17, glibc-2.1.3 and gcc 2.95.2. The errors I + received were mostly due to the source files re-declaring + things unconditionall + /archive/html/bug-gnu-utils/2000-12/msg00109.html (5,782 bytes) + + 58. cpio-2.4.2 & glibc-2.* (score: 46) + Author: Florian Wunderlich <fwunderlich@devbrain.de> + Date: Mon, 18 Dec 2000 16:25:00 +0100 + I still do not see a new version of cpio or at least extra + patches that fix it so it works with the glibc. Thus, here is a + simple patch to make it compile with glibc: diff -u + cpio-2.4.2-old/rmt.c cpi + /archive/html/bug-gnu-utils/2000-12/msg00098.html (4,846 bytes) + + 60. cpio-2.4.2 signed-unsigned int disagreement with malloc (score: + 39) + Author: Antonomasia <ant@notatla.demon.co.uk> + Date: Mon, 27 Nov 2000 07:05:01 GMT + copyin.c: 534 link_name = (char *) xmalloc ((unsigned int) + file_hdr.c_filesize + 1); 535 link_name[file_hdr.c_filesize] = + '\0'; file_hdr.c_filesize can be a large negative number as + seen here then th + /archive/html/bug-gnu-utils/2000-11/msg00171.html (4,718 bytes) + + 61. gnu CPIO (score: 38) + Author: Clark Cooper <Clark.Cooper@vc3.com> + Date: Mon, 13 Nov 2000 13:21:07 -0500 (EST) + The gnu version of CPIO appears to send all output to stderr. + Take for instance a need to have the list of files copied and + any errors separated as should be produced by the following: + find . -print + /archive/html/bug-gnu-utils/2000-11/msg00089.html (3,903 bytes) + + 62. Desire enhancement to GNU cpio 2.4.2 (score: 35) + Author: Dave Dykstra <dwd@bell-labs.com> + Date: Mon, 13 Nov 2000 10:24:56 -0600 + I have a new GNU/Linux system with large disks on which I need + to generate cpio files for many different systems including + older ones that don't support the "newc" format, only the "odc" + format. The + /archive/html/bug-gnu-utils/2000-11/msg00087.html (5,115 bytes) + + 65. cpio pass-through can corrupt files (score: 36) + Author: "Parrott, Jeff" <Jeff.Parrott@sea.siemens.com> + Date: Mon, 16 Oct 2000 13:32:57 -0400 + I have seen corrupted files as a result of using the + pass-through option in cpio. The corruption occurs when + active/in-use (and growing) files are being copied. The problem + is that the file size has + /archive/html/bug-gnu-utils/2000-10/msg00087.html (4,974 bytes) + + 66. [Bug-gnu-utils] A small problem with cpio (score: 36) + Author: Chris Hall <Chris@clapham.org> + Date: Fri, 15 Sep 2000 11:05:56 +0100 + Hi, I'm running cpio 2.4.2 on AIX 4.3.3 and have a problem with + very large files, I get this output when running the command: $ + ls -l total 2867988 drwxrwxrwx 2 root sys 512 Sep 14 17:05 + chris/ -rw-r + /archive/html/bug-gnu-utils/2000-09/msg00004.html (4,481 bytes) diff --git a/contrib/cpio/doc/cpio.1 b/contrib/cpio/doc/cpio.1 new file mode 100644 index 0000000..dc3eb80 --- /dev/null +++ b/contrib/cpio/doc/cpio.1 @@ -0,0 +1,41 @@ +.TH CPIO 1L \" -*- nroff -*- +.SH NAME +cpio \- copy files to and from archives +.SH SYNOPSIS +.B cpio +{\-o|\-\-create} [\-0acvABLV] [\-C bytes] [\-H format] [\-M message] +[\-O [[user@]host:]archive] [\-F [[user@]host:]archive] +[\-\-file=[[user@]host:]archive] [\-\-format=format] [\-\-message=message] +[\-\-null] [\-\-reset-access-time] [\-\-verbose] [\-\-dot] [\-\-append] +[\-\-block-size=blocks] [\-\-dereference] [\-\-io-size=bytes] [\-\-quiet] +[\-\-force\-local] [\-\-rsh-command=command] [\-\-help] [\-\-version] +< name-list [> archive] + +.B cpio +{\-i|\-\-extract} [\-bcdfmnrtsuvBSV] [\-C bytes] [\-E file] [\-H format] +[\-M message] [\-R [user][:.][group]] [\-I [[user@]host:]archive] +[\-F [[user@]host:]archive] [\-\-file=[[user@]host:]archive] +[\-\-make-directories] [\-\-nonmatching] [\-\-preserve-modification-time] +[\-\-numeric-uid-gid] [\-\-rename] [\-t|\-\-list] [\-\-swap-bytes] [\-\-swap] [\-\-dot] +[\-\-unconditional] [\-\-verbose] [\-\-block-size=blocks] [\-\-swap-halfwords] +[\-\-io-size=bytes] [\-\-pattern-file=file] [\-\-format=format] +[\-\-owner=[user][:.][group]] [\-\-no-preserve-owner] [\-\-message=message] +[\-\-force\-local] [\-\-no\-absolute\-filenames] [\-\-sparse] +[\-\-only\-verify\-crc] [\-\-quiet] [\-\-rsh-command=command] [\-\-help] +[\-\-version] [pattern...] [< archive] + +.B cpio +{\-p|\-\-pass-through} [\-0adlmuvLV] [\-R [user][:.][group]] +[\-\-null] [\-\-reset-access-time] [\-\-make-directories] [\-\-link] [\-\-quiet] +[\-\-preserve-modification-time] [\-\-unconditional] [\-\-verbose] [\-\-dot] +[\-\-dereference] [\-\-owner=[user][:.][group]] [\-\-no-preserve-owner] +[\-\-sparse] [\-\-help] [\-\-version] destination-directory < name-list +.SH DESCRIPTION +GNU cpio is fully documented in the texinfo documentation. To access the +help from your command line, type +.PP +\fBinfo cpio +.PP +The online copy of the documentation is available at the following address: +.PP +http://www.gnu.org/software/cpio/manual diff --git a/contrib/cpio/doc/cpio.texi b/contrib/cpio/doc/cpio.texi new file mode 100644 index 0000000..ae534f4 --- /dev/null +++ b/contrib/cpio/doc/cpio.texi @@ -0,0 +1,563 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename cpio.info +@settitle cpio +@setchapternewpage off +@set VERSION GNU cpio 2.5 +@set RELEASEDATE June 2002 +@c %**end of header + +@ifinfo +@format +START-INFO-DIR-ENTRY +* cpio: (cpio). Making tape (or disk) archives. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This file documents @value{VERSION}. + +Copyright (C) 1995, 2001, 2002 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph + + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + + +@titlepage +@title GNU CPIO +@subtitle @value{VERSION} @value{RELEASEDATE} +@author by Robert Carleton +@c copyright page +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1995, 2001, 2002 Free Software Foundation, Inc. +@sp 2 +This is the first edition of the GNU cpio documentation,@* +and is consistent with @value{VERSION}.@* +@sp 2 +Published by the Free Software Foundation @* +59 Temple Place - Suite 330, @* +Boston, MA 02111-1307, USA @* + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by the Free Software Foundation. +@end titlepage + +@ifinfo +@node Top, Introduction, (dir), (dir) +@comment node-name, next, previous, up +@top + +GNU cpio is a tool for creating and extracting archives, or copying +files from one place to another. It handles a number of cpio formats as +well as reading and writing tar files. This is the first edition of the +GNU cpio documentation and is consistant with @value{VERSION}. + +@menu +* Introduction:: +* Tutorial:: Getting started. +* Invoking `cpio':: How to invoke `cpio'. +* Media:: Using tapes and other archive media. +* Concept Index:: Concept index. + + --- The Detailed Node Listing --- + +Invoking cpio + +* Copy-out mode:: +* Copy-in mode:: +* Copy-pass mode:: +* Options:: +@end menu + +@end ifinfo + +@node Introduction, Tutorial, Top, Top +@comment node-name, next, previous, up +@chapter Introduction + +GNU cpio copies files into or out of a cpio or tar archive, The archive +can be another file on the disk, a magnetic tape, or a pipe. + +GNU cpio supports the following archive formats: binary, old ASCII, new +ASCII, crc, HPUX binary, HPUX old ASCII, old tar, and POSIX.1 tar. The +tar format is provided for compatability with the tar program. By +default, cpio creates binary format archives, for compatibility with +older cpio programs. When extracting from archives, cpio automatically +recognizes which kind of archive it is reading and can read archives +created on machines with a different byte-order. + +@node Tutorial, Invoking `cpio', Introduction, Top +@comment node-name, next, previous, up +@chapter Tutorial +@cindex creating a cpio archive +@cindex extracting a cpio archive +@cindex copying directory structures +@cindex passing directory structures + + +GNU cpio performs three primary functions. Copying files to an +archive, Extracting files from an archive, and passing files to another +directory tree. An archive can be a file on disk, one or more floppy +disks, or one or more tapes. + +When creating an archive, cpio takes the list of files to be processed +from the standard input, and then sends the archive to the standard +output, or to the device defined by the @samp{-F} option. +@xref{Copy-out mode}. Usually find or ls is used to provide this list +to the standard input. In the following example you can see the +possibilities for archiving the contents of a single directory. + + +@example +@cartouche +% ls | cpio -ov > directory.cpio +@end cartouche +@end example + +The @samp{-o} option creates the archive, and the @samp{-v} option +prints the names of the files archived as they are added. Notice that +the options can be put together after a single @samp{-} or can be placed +separately on the command line. The @samp{>} redirects the cpio output +to the file @samp{directory.cpio}. + + +If you wanted to archive an entire directory tree, the find command can +provide the file list to cpio: + + +@example +@cartouche +% find . -print -depth | cpio -ov > tree.cpio +@end cartouche +@end example + + +This will take all the files in the current directory, the directories +below and place them in the archive tree.cpio. Again the @samp{-o} +creates an archive, and the @samp{-v} option shows you the name of the +files as they are archived. @xref{Copy-out mode}. Using the `.' in the +find statement will give you more flexibility when doing restores, as it +will save file names with a relative path vice a hard wired, absolute +path. The @samp{-depth} option forces @samp{find} to print of the +entries in a directory before printing the directory itself. This +limits the effects of restrictive directory permissions by printing the +directory entries in a directory before the directory name itself. + + + + +Extracting an archive requires a bit more thought because cpio will not +create directories by default. Another characteristic, is it will not +overwrite existing files unless you tell it to. + + +@example +@cartouche +% cpio -iv < directory.cpio +@end cartouche +@end example + +This will retrieve the files archived in the file directory.cpio and +place them in the present directory. The @samp{-i} option extracts the +archive and the @samp{-v} shows the file names as they are extracted. +If you are dealing with an archived directory tree, you need to use the +@samp{-d} option to create directories as necessary, something like: + +@example +@cartouche +% cpio -idv < tree.cpio +@end cartouche +@end example + +This will take the contents of the archive tree.cpio and extract it to +the current directory. If you try to extract the files on top of files +of the same name that already exist (and have the same or later +modification time) cpio will not extract the file unless told to do so +by the -u option. @xref{Copy-in mode}. + + +In copy-pass mode, cpio copies files from one directory tree to another, +combining the copy-out and copy-in steps without actually using an +archive. It reads the list of files to copy from the standard input; +the directory into which it will copy them is given as a non-option +argument. @xref{Copy-pass mode}. + +@example +@cartouche +% find . -depth -print0 | cpio --null -pvd new-dir +@end cartouche +@end example + + +The example shows copying the files of the present directory, and +sub-directories to a new directory called new-dir. Some new options are +the @samp{-print0} available with GNU find, combined with the +@samp{--null} option of cpio. These two options act together to send +file names between find and cpio, even if special characters are +embedded in the file names. Another is @samp{-p}, which tells cpio to +pass the files it finds to the directory @samp{new-dir}. + +@node Invoking `cpio', Media, Tutorial, Top +@comment node-name, next, previous, up +@chapter Invoking cpio +@cindex invoking cpio +@cindex command line options + +@menu +* Copy-out mode:: +* Copy-in mode:: +* Copy-pass mode:: +* Options:: +@end menu + +@node Copy-out mode, Copy-in mode, Invoking `cpio', Invoking `cpio' +@comment node-name, next, previous, up +@section Copy-out mode + +In copy-out mode, cpio copies files into an archive. It reads a list +of filenames, one per line, on the standard input, and writes the +archive onto the standard output. A typical way to generate the list +of filenames is with the find command; you should give find the -depth +option to minimize problems with permissions on directories that are +unreadable. +@xref{Options}. + +@example +cpio @{-o|--create@} [-0acvABLV] [-C bytes] [-H format] +[-M message] [-O [[user@@]host:]archive] [-F [[user@@]host:]archive] +[--file=[[user@@]host:]archive] [--format=format] +[--message=message][--null] [--reset-access-time] [--verbose] +[--dot] [--append] [--block-size=blocks] [--dereference] +[--io-size=bytes] [--rsh-command=command] [--help] [--version] +< name-list [> archive] +@end example + +@node Copy-in mode, Copy-pass mode, Copy-out mode, Invoking `cpio' +@comment node-name, next, previous, up +@section Copy-in mode + +In copy-in mode, cpio copies files out of an archive or lists the +archive contents. It reads the archive from the standard input. Any +non-option command line arguments are shell globbing patterns; only +files in the archive whose names match one or more of those patterns are +copied from the archive. Unlike in the shell, an initial `.' in a +filename does match a wildcard at the start of a pattern, and a `/' in a +filename can match wildcards. If no patterns are given, all files are +extracted. @xref{Options}. + +@example +cpio @{-i|--extract@} [-bcdfmnrtsuvBSV] [-C bytes] [-E file] +[-H format] [-M message] [-R [user][:.][group]] +[-I [[user@@]host:]archive] [-F [[user@@]host:]archive] +[--file=[[user@@]host:]archive] [--make-directories] +[--nonmatching] [--preserve-modification-time] +[--numeric-uid-gid] [--rename] [--list] [--swap-bytes] [--swap] +[--dot] [--unconditional] [--verbose] [--block-size=blocks] +[--swap-halfwords] [--io-size=bytes] [--pattern-file=file] +[--format=format] [--owner=[user][:.][group]] +[--no-preserve-owner] [--message=message] [--help] [--version] +[-no-absolute-filenames] [--sparse] [-only-verify-crc] [-quiet] +[--rsh-command=command] [pattern...] [< archive] +@end example + +@node Copy-pass mode, Options, Copy-in mode, Invoking `cpio' +@comment node-name, next, previous, up +@section Copy-pass mode + +In copy-pass mode, cpio copies files from one directory tree to +another, combining the copy-out and copy-in steps without actually +using an archive. It reads the list of files to copy from the +standard input; the directory into which it will copy them is given as +a non-option argument. +@xref{Options}. + +@example +cpio @{-p|--pass-through@} [-0adlmuvLV] [-R [user][:.][group]] +[--null] [--reset-access-time] [--make-directories] [--link] +[--preserve-modification-time] [--unconditional] [--verbose] +[--dot] [--dereference] [--owner=[user][:.][group]] [--sparse] +[--no-preserve-owner] [--help] [--version] destination-directory +< name-list +@end example + + + +@node Options, , Copy-pass mode, Invoking `cpio' +@comment node-name, next, previous, up +@section Options + + +@table @code + + +@item -0, --null +Read a list of filenames terminated by a null character, instead of a +newline, so that files whose names contain newlines can be archived. +GNU find is one way to produce a list of null-terminated filenames. +This option may be used in copy-out and copy-pass modes. + +@item -a, --reset-access-time +Reset the access times of files after reading them, so +that it does not look like they have just been read. + +@item -A, --append +Append to an existing archive. Only works in copy-out +mode. The archive must be a disk file specified with +the -O or -F (--file) option. + +@item -b, --swap +Swap both halfwords of words and bytes of halfwords in the data. +Equivalent to -sS. This option may be used in copy-in mode. Use this +option to convert 32-bit integers between big-endian and little-endian +machines. + +@item -B +Set the I/O block size to 5120 bytes. Initially the +block size is 512 bytes. + +@item --block-size=BLOCK-SIZE +Set the I/O block size to BLOCK-SIZE * 512 bytes. + +@item -c +Use the old portable (ASCII) archive format. + +@item -C IO-SIZE, --io-size=IO-SIZE +Set the I/O block size to IO-SIZE bytes. + +@item -d, --make-directories +Create leading directories where needed. + +@item -E FILE, --pattern-file=FILE +Read additional patterns specifying filenames to extract or list from +FILE. The lines of FILE are treated as if they had been non-option +arguments to cpio. This option is used in copy-in mode, + +@item -f, --nonmatching +Only copy files that do not match any of the given +patterns. + +@item -F, --file=archive +Archive filename to use instead of standard input or output. To use a +tape drive on another machine as the archive, use a filename that starts +with `HOSTNAME:'. The hostname can be preceded by a username and an +`@@' to access the remote tape drive as that user, if you have +permission to do so (typically an entry in that user's `~/.rhosts' +file). + +@item --force-local +With -F, -I, or -O, take the archive file name to be a +local file even if it contains a colon, which would +ordinarily indicate a remote host name. + +@item -H FORMAT, --format=FORMAT +Use archive format FORMAT. The valid formats are listed below; the same +names are also recognized in all-caps. The default in copy-in mode is +to automatically detect the archive format, and in copy-out mode is +@samp{bin}. + +@table @samp +@item bin +The obsolete binary format. + +@item odc +The old (POSIX.1) portable format. + +@item newc +The new (SVR4) portable format, which supports file systems having more +than 65536 i-nodes. + +@item crc +The new (SVR4) portable format with a checksum added. + +@item tar +The old tar format. + +@item ustar +The POSIX.1 tar format. Also recognizes GNU tar archives, which are +similar but not identical. + +@item hpbin +The obsolete binary format used by HPUX's cpio (which stores device +files differently). + +@item hpodc +The portable format used by HPUX's cpio (which stores device files +differently). +@end table + +@item -i, --extract +Run in copy-in mode. +@xref{Copy-in mode}. + +@item -I archive +Archive filename to use instead of standard input. To use a tape drive +on another machine as the archive, use a filename that starts with +`HOSTNAME:'. The hostname can be preceded by a username and an `@@' to +access the remote tape drive as that user, if you have permission to do +so (typically an entry in that user's `~/.rhosts' file). + +@item -k +Ignored; for compatibility with other versions of cpio. + +@item -l, --link +Link files instead of copying them, when possible. + +@item -L, --dereference +Copy the file that a symbolic link points to, rather than the symbolic +link itself. + +@item -m, --preserve-modification-time +Retain previous file modification times when creating files. + +@item -M MESSAGE, --message=MESSAGE +Print MESSAGE when the end of a volume of the backup media (such as a +tape or a floppy disk) is reached, to prompt the user to insert a new +volume. If MESSAGE contains the string "%d", it is replaced by the +current volume number (starting at 1). + +@item -n, --numeric-uid-gid +Show numeric UID and GID instead of translating them into names when using the +@samp{--verbose option}. + +@item --no-absolute-filenames +Create all files relative to the current directory in copy-in mode, even +if they have an absolute file name in the archive. + +@item --no-preserve-owner +Do not change the ownership of the files; leave them owned by the user +extracting them. This is the default for non-root users, so that users +on System V don't inadvertantly give away files. This option can be +used in copy-in mode and copy-pass mode + +@item -o, --create +Run in copy-out mode. +@xref{Copy-out mode}. + +@item -O archive +Archive filename to use instead of standard output. To use a tape drive +on another machine as the archive, use a filename that starts with +`HOSTNAME:'. The hostname can be preceded by a username and an `@@' to +access the remote tape drive as that user, if you have permission to do +so (typically an entry in that user's `~/.rhosts' file). + +@item --only-verify-crc +Verify the CRC's of each file in the archive, when reading a CRC format +archive. Don't actually extract the files. + +@item -p, --pass-through +Run in copy-pass mode. +@xref{Copy-pass mode}. + +@item --quiet +Do not print the number of blocks copied. + +@item -r, --rename +Interactively rename files. + +@item -R [user][:.][group], --owner [user][:.][group] +Set the ownership of all files created to the specified user and/or +group in copy-out and copy-pass modes. Either the user, the group, or +both, must be present. If the group is omitted but the ":" or "." +separator is given, use the given user's login group. Only the +super-user can change files' ownership. + +@item --rsh-command=COMMAND +Notifies cpio that is should use COMMAND to communicate with remote +devices. + +@item -s, --swap-bytes +Swap the bytes of each halfword (pair of bytes) in the files.This option +can be used in copy-in mode. + +@item -S, --swap-halfwords +Swap the halfwords of each word (4 bytes) in the files. This option may +be used in copy-in mode. + +@item --sparse +Write files with large blocks of zeros as sparse files. This option is +used in copy-in and copy-pass modes. + +@item -t, --list +Print a table of contents of the input. + +@item -u, --unconditional +Replace all files, without asking whether to replace +existing newer files with older files. + +@item -v, --verbose +List the files processed, or with @samp{-t}, give an @samp{ls -l} style +table of contents listing. In a verbose table of contents of a ustar +archive, user and group names in the archive that do not exist on the +local system are replaced by the names that correspond locally to the +numeric UID and GID stored in the archive. + +@item -V --dot +Print a @kbd{.} for each file processed. + +@item --version +Print the cpio program version number and exit. +@end table + + +@node Media, Concept Index, Invoking `cpio', Top +@comment node-name, next, previous, up +@chapter Magnetic Media +@cindex magnetic media + +Archives are usually written on removable media--tape cartridges, mag +tapes, or floppy disks. + +The amount of data a tape or disk holds depends not only on its size, +but also on how it is formatted. A 2400 foot long reel of mag tape +holds 40 megabytes of data when formated at 1600 bits per inch. The +physically smaller EXABYTE tape cartridge holds 2.3 gigabytes. + +Magnetic media are re-usable--once the archive on a tape is no longer +needed, the archive can be erased and the tape or disk used over. Media +quality does deteriorate with use, however. Most tapes or disks should +be disgarded when they begin to produce data errors. + +Magnetic media are written and erased using magnetic fields, and should +be protected from such fields to avoid damage to stored data. Sticking +a floppy disk to a filing cabinet using a magnet is probably not a good +idea. + + +@node Concept Index, , Media, Top +@comment node-name, next, previous, up +@unnumbered Concept Index +@printindex cp +@contents +@bye diff --git a/contrib/cpio/lib/alloca_.h b/contrib/cpio/lib/alloca_.h new file mode 100644 index 0000000..1099551 --- /dev/null +++ b/contrib/cpio/lib/alloca_.h @@ -0,0 +1,54 @@ +/* Memory allocation on the stack. + + Copyright (C) 1995, 1999, 2001, 2002, 2003, 2004 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* When this file is included, it may be preceded only by preprocessor + declarations. Thanks to AIX. Therefore we include it right after + "config.h", not later. */ + +#ifndef _ALLOCA_H +# define _ALLOCA_H + +/* alloca (N) returns a pointer to N bytes of memory + allocated on the stack, which will last until the function returns. + Use of alloca should be avoided: + - inside arguments of function calls - undefined behaviour, + - in inline functions - the allocation may actually last until the + calling function returns, + - for huge N (say, N >= 65536) - you never know how large (or small) + the stack is, and when the stack cannot fulfill the memory allocation + request, the program just crashes. + */ + +#ifdef __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#endif /* _ALLOCA_H */ diff --git a/contrib/cpio/lib/argp-ba.c b/contrib/cpio/lib/argp-ba.c new file mode 100644 index 0000000..c471228 --- /dev/null +++ b/contrib/cpio/lib/argp-ba.c @@ -0,0 +1,25 @@ +/* Default definition for ARGP_PROGRAM_BUG_ADDRESS. + Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* If set by the user program, it should point to string that is the + bug-reporting address for the program. It will be printed by argp_help if + the ARGP_HELP_BUG_ADDR flag is set (as it is by various standard help + messages), embedded in a sentence that says something like `Report bugs to + ADDR.'. */ +const char *argp_program_bug_address; diff --git a/contrib/cpio/lib/argp-eexst.c b/contrib/cpio/lib/argp-eexst.c new file mode 100644 index 0000000..d5cd28c --- /dev/null +++ b/contrib/cpio/lib/argp-eexst.c @@ -0,0 +1,31 @@ +/* Default definition for ARGP_ERR_EXIT_STATUS + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sysexits.h> + +#include "argp.h" + +/* The exit status that argp will use when exiting due to a parsing error. + If not defined or set by the user program, this defaults to EX_USAGE from + <sysexits.h>. */ +error_t argp_err_exit_status = EX_USAGE; diff --git a/contrib/cpio/lib/argp-fmtstream.c b/contrib/cpio/lib/argp-fmtstream.c new file mode 100644 index 0000000..c88c3db --- /dev/null +++ b/contrib/cpio/lib/argp-fmtstream.c @@ -0,0 +1,440 @@ +/* Word-wrapping and line-truncating streams + Copyright (C) 1997,1998,1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This package emulates glibc `line_wrap_stream' semantics for systems that + don't have that. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> +#include <ctype.h> + +#include "argp-fmtstream.h" +#include "argp-namefrob.h" + +#ifndef ARGP_FMTSTREAM_USE_LINEWRAP + +#ifndef isblank +#define isblank(ch) ((ch)==' ' || (ch)=='\t') +#endif + +#if defined _LIBC && defined USE_IN_LIBIO +# include <wchar.h> +# include <libio/libioP.h> +# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a) +#endif + +#define INIT_BUF_SIZE 200 +#define PRINTF_SIZE_GUESS 150 + +/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines + written on it with LMARGIN spaces and limits them to RMARGIN columns + total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by + replacing the whitespace before them with a newline and WMARGIN spaces. + Otherwise, chars beyond RMARGIN are simply dropped until a newline. + Returns NULL if there was an error. */ +argp_fmtstream_t +__argp_make_fmtstream (FILE *stream, + size_t lmargin, size_t rmargin, ssize_t wmargin) +{ + argp_fmtstream_t fs; + + fs = (struct argp_fmtstream *) malloc (sizeof (struct argp_fmtstream)); + if (fs != NULL) + { + fs->stream = stream; + + fs->lmargin = lmargin; + fs->rmargin = rmargin; + fs->wmargin = wmargin; + fs->point_col = 0; + fs->point_offs = 0; + + fs->buf = (char *) malloc (INIT_BUF_SIZE); + if (! fs->buf) + { + free (fs); + fs = 0; + } + else + { + fs->p = fs->buf; + fs->end = fs->buf + INIT_BUF_SIZE; + } + } + + return fs; +} +#if 0 +/* Not exported. */ +#ifdef weak_alias +weak_alias (__argp_make_fmtstream, argp_make_fmtstream) +#endif +#endif + +/* Flush FS to its stream, and free it (but don't close the stream). */ +void +__argp_fmtstream_free (argp_fmtstream_t fs) +{ + __argp_fmtstream_update (fs); + if (fs->p > fs->buf) + { +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + __fwprintf (fs->stream, L"%.*s", (int) (fs->p - fs->buf), fs->buf); + else +#endif + fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); + } + free (fs->buf); + free (fs); +} +#if 0 +/* Not exported. */ +#ifdef weak_alias +weak_alias (__argp_fmtstream_free, argp_fmtstream_free) +#endif +#endif + +/* Process FS's buffer so that line wrapping is done from POINT_OFFS to the + end of its buffer. This code is mostly from glibc stdio/linewrap.c. */ +void +__argp_fmtstream_update (argp_fmtstream_t fs) +{ + char *buf, *nl; + size_t len; + + /* Scan the buffer for newlines. */ + buf = fs->buf + fs->point_offs; + while (buf < fs->p) + { + size_t r; + + if (fs->point_col == 0 && fs->lmargin != 0) + { + /* We are starting a new line. Print spaces to the left margin. */ + const size_t pad = fs->lmargin; + if (fs->p + pad < fs->end) + { + /* We can fit in them in the buffer by moving the + buffer text up and filling in the beginning. */ + memmove (buf + pad, buf, fs->p - buf); + fs->p += pad; /* Compensate for bigger buffer. */ + memset (buf, ' ', pad); /* Fill in the spaces. */ + buf += pad; /* Don't bother searching them. */ + } + else + { + /* No buffer space for spaces. Must flush. */ + size_t i; + for (i = 0; i < pad; i++) + { +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + putwc_unlocked (L' ', fs->stream); + else +#endif + putc_unlocked (' ', fs->stream); + } + } + fs->point_col = pad; + } + + len = fs->p - buf; + nl = memchr (buf, '\n', len); + + if (fs->point_col < 0) + fs->point_col = 0; + + if (!nl) + { + /* The buffer ends in a partial line. */ + + if (fs->point_col + len < fs->rmargin) + { + /* The remaining buffer text is a partial line and fits + within the maximum line width. Advance point for the + characters to be written and stop scanning. */ + fs->point_col += len; + break; + } + else + /* Set the end-of-line pointer for the code below to + the end of the buffer. */ + nl = fs->p; + } + else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin) + { + /* The buffer contains a full line that fits within the maximum + line width. Reset point and scan the next line. */ + fs->point_col = 0; + buf = nl + 1; + continue; + } + + /* This line is too long. */ + r = fs->rmargin - 1; + + if (fs->wmargin < 0) + { + /* Truncate the line by overwriting the excess with the + newline and anything after it in the buffer. */ + if (nl < fs->p) + { + memmove (buf + (r - fs->point_col), nl, fs->p - nl); + fs->p -= buf + (r - fs->point_col) - nl; + /* Reset point for the next line and start scanning it. */ + fs->point_col = 0; + buf += r + 1; /* Skip full line plus \n. */ + } + else + { + /* The buffer ends with a partial line that is beyond the + maximum line width. Advance point for the characters + written, and discard those past the max from the buffer. */ + fs->point_col += len; + fs->p -= fs->point_col - r; + break; + } + } + else + { + /* Do word wrap. Go to the column just past the maximum line + width and scan back for the beginning of the word there. + Then insert a line break. */ + + char *p, *nextline; + int i; + + p = buf + (r + 1 - fs->point_col); + while (p >= buf && !isblank (*p)) + --p; + nextline = p + 1; /* This will begin the next line. */ + + if (nextline > buf) + { + /* Swallow separating blanks. */ + if (p >= buf) + do + --p; + while (p >= buf && isblank (*p)); + nl = p + 1; /* The newline will replace the first blank. */ + } + else + { + /* A single word that is greater than the maximum line width. + Oh well. Put it on an overlong line by itself. */ + p = buf + (r + 1 - fs->point_col); + /* Find the end of the long word. */ + do + ++p; + while (p < nl && !isblank (*p)); + if (p == nl) + { + /* It already ends a line. No fussing required. */ + fs->point_col = 0; + buf = nl + 1; + continue; + } + /* We will move the newline to replace the first blank. */ + nl = p; + /* Swallow separating blanks. */ + do + ++p; + while (isblank (*p)); + /* The next line will start here. */ + nextline = p; + } + + /* Note: There are a bunch of tests below for + NEXTLINE == BUF + LEN + 1; this case is where NL happens to fall + at the end of the buffer, and NEXTLINE is in fact empty (and so + we need not be careful to maintain its contents). */ + + if ((nextline == buf + len + 1 + ? fs->end - nl < fs->wmargin + 1 + : nextline - (nl + 1) < fs->wmargin) + && fs->p > nextline) + { + /* The margin needs more blanks than we removed. */ + if (fs->end - fs->p > fs->wmargin + 1) + /* Make some space for them. */ + { + size_t mv = fs->p - nextline; + memmove (nl + 1 + fs->wmargin, nextline, mv); + nextline = nl + 1 + fs->wmargin; + len = nextline + mv - buf; + *nl++ = '\n'; + } + else + /* Output the first line so we can use the space. */ + { +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + __fwprintf (fs->stream, L"%.*s\n", + (int) (nl - fs->buf), fs->buf); + else +#endif + { + if (nl > fs->buf) + fwrite_unlocked (fs->buf, 1, nl - fs->buf, fs->stream); + putc_unlocked ('\n', fs->stream); + } + len += buf - fs->buf; + nl = buf = fs->buf; + } + } + else + /* We can fit the newline and blanks in before + the next word. */ + *nl++ = '\n'; + + if (nextline - nl >= fs->wmargin + || (nextline == buf + len + 1 && fs->end - nextline >= fs->wmargin)) + /* Add blanks up to the wrap margin column. */ + for (i = 0; i < fs->wmargin; ++i) + *nl++ = ' '; + else + for (i = 0; i < fs->wmargin; ++i) +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + putwc_unlocked (L' ', fs->stream); + else +#endif + putc_unlocked (' ', fs->stream); + + /* Copy the tail of the original buffer into the current buffer + position. */ + if (nl < nextline) + memmove (nl, nextline, buf + len - nextline); + len -= nextline - buf; + + /* Continue the scan on the remaining lines in the buffer. */ + buf = nl; + + /* Restore bufp to include all the remaining text. */ + fs->p = nl + len; + + /* Reset the counter of what has been output this line. If wmargin + is 0, we want to avoid the lmargin getting added, so we set + point_col to a magic value of -1 in that case. */ + fs->point_col = fs->wmargin ? fs->wmargin : -1; + } + } + + /* Remember that we've scanned as far as the end of the buffer. */ + fs->point_offs = fs->p - fs->buf; +} + +/* Ensure that FS has space for AMOUNT more bytes in its buffer, either by + growing the buffer, or by flushing it. True is returned iff we succeed. */ +int +__argp_fmtstream_ensure (struct argp_fmtstream *fs, size_t amount) +{ + if ((size_t) (fs->end - fs->p) < amount) + { + ssize_t wrote; + + /* Flush FS's buffer. */ + __argp_fmtstream_update (fs); + +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + { + __fwprintf (fs->stream, L"%.*s", (int) (fs->p - fs->buf), fs->buf); + wrote = fs->p - fs->buf; + } + else +#endif + wrote = fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); + if (wrote == fs->p - fs->buf) + { + fs->p = fs->buf; + fs->point_offs = 0; + } + else + { + fs->p -= wrote; + fs->point_offs -= wrote; + memmove (fs->buf, fs->buf + wrote, fs->p - fs->buf); + return 0; + } + + if ((size_t) (fs->end - fs->buf) < amount) + /* Gotta grow the buffer. */ + { + size_t old_size = fs->end - fs->buf; + size_t new_size = old_size + amount; + char *new_buf; + + if (new_size < old_size || ! (new_buf = realloc (fs->buf, new_size))) + { + __set_errno (ENOMEM); + return 0; + } + + fs->buf = new_buf; + fs->end = new_buf + new_size; + fs->p = fs->buf; + } + } + + return 1; +} + +ssize_t +__argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...) +{ + int out; + size_t avail; + size_t size_guess = PRINTF_SIZE_GUESS; /* How much space to reserve. */ + + do + { + va_list args; + + if (! __argp_fmtstream_ensure (fs, size_guess)) + return -1; + + va_start (args, fmt); + avail = fs->end - fs->p; + out = __vsnprintf (fs->p, avail, fmt, args); + va_end (args); + if ((size_t) out >= avail) + size_guess = out + 1; + } + while ((size_t) out >= avail); + + fs->p += out; + + return out; +} +#if 0 +/* Not exported. */ +#ifdef weak_alias +weak_alias (__argp_fmtstream_printf, argp_fmtstream_printf) +#endif +#endif + +#endif /* !ARGP_FMTSTREAM_USE_LINEWRAP */ diff --git a/contrib/cpio/lib/argp-fmtstream.h b/contrib/cpio/lib/argp-fmtstream.h new file mode 100644 index 0000000..e71df10 --- /dev/null +++ b/contrib/cpio/lib/argp-fmtstream.h @@ -0,0 +1,309 @@ +/* Word-wrapping and line-truncating streams. + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This package emulates glibc `line_wrap_stream' semantics for systems that + don't have that. If the system does have it, it is just a wrapper for + that. This header file is only used internally while compiling argp, and + shouldn't be installed. */ + +#ifndef _ARGP_FMTSTREAM_H +#define _ARGP_FMTSTREAM_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || __STRICT_ANSI__ +# define __format__ format +# define __printf__ printf +# endif +#endif + +#if (_LIBC - 0 && !defined (USE_IN_LIBIO)) \ + || (defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H)) +/* line_wrap_stream is available, so use that. */ +#define ARGP_FMTSTREAM_USE_LINEWRAP +#endif + +#ifdef ARGP_FMTSTREAM_USE_LINEWRAP +/* Just be a simple wrapper for line_wrap_stream; the semantics are + *slightly* different, as line_wrap_stream doesn't actually make a new + object, it just modifies the given stream (reversibly) to do + line-wrapping. Since we control who uses this code, it doesn't matter. */ + +#include <linewrap.h> + +typedef FILE *argp_fmtstream_t; + +#define argp_make_fmtstream line_wrap_stream +#define __argp_make_fmtstream line_wrap_stream +#define argp_fmtstream_free line_unwrap_stream +#define __argp_fmtstream_free line_unwrap_stream + +#define __argp_fmtstream_putc(fs,ch) putc(ch,fs) +#define argp_fmtstream_putc(fs,ch) putc(ch,fs) +#define __argp_fmtstream_puts(fs,str) fputs(str,fs) +#define argp_fmtstream_puts(fs,str) fputs(str,fs) +#define __argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs) +#define argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs) +#define __argp_fmtstream_printf fprintf +#define argp_fmtstream_printf fprintf + +#define __argp_fmtstream_lmargin line_wrap_lmargin +#define argp_fmtstream_lmargin line_wrap_lmargin +#define __argp_fmtstream_set_lmargin line_wrap_set_lmargin +#define argp_fmtstream_set_lmargin line_wrap_set_lmargin +#define __argp_fmtstream_rmargin line_wrap_rmargin +#define argp_fmtstream_rmargin line_wrap_rmargin +#define __argp_fmtstream_set_rmargin line_wrap_set_rmargin +#define argp_fmtstream_set_rmargin line_wrap_set_rmargin +#define __argp_fmtstream_wmargin line_wrap_wmargin +#define argp_fmtstream_wmargin line_wrap_wmargin +#define __argp_fmtstream_set_wmargin line_wrap_set_wmargin +#define argp_fmtstream_set_wmargin line_wrap_set_wmargin +#define __argp_fmtstream_point line_wrap_point +#define argp_fmtstream_point line_wrap_point + +#else /* !ARGP_FMTSTREAM_USE_LINEWRAP */ +/* Guess we have to define our own version. */ + +#ifndef __const +#define __const const +#endif + +struct argp_fmtstream +{ + FILE *stream; /* The stream we're outputting to. */ + + size_t lmargin, rmargin; /* Left and right margins. */ + ssize_t wmargin; /* Margin to wrap to, or -1 to truncate. */ + + /* Point in buffer to which we've processed for wrapping, but not output. */ + size_t point_offs; + /* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin. */ + ssize_t point_col; + + char *buf; /* Output buffer. */ + char *p; /* Current end of text in BUF. */ + char *end; /* Absolute end of BUF. */ +}; + +typedef struct argp_fmtstream *argp_fmtstream_t; + +/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines + written on it with LMARGIN spaces and limits them to RMARGIN columns + total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by + replacing the whitespace before them with a newline and WMARGIN spaces. + Otherwise, chars beyond RMARGIN are simply dropped until a newline. + Returns NULL if there was an error. */ +extern argp_fmtstream_t __argp_make_fmtstream (FILE *__stream, + size_t __lmargin, + size_t __rmargin, + ssize_t __wmargin); +extern argp_fmtstream_t argp_make_fmtstream (FILE *__stream, + size_t __lmargin, + size_t __rmargin, + ssize_t __wmargin); + +/* Flush __FS to its stream, and free it (but don't close the stream). */ +extern void __argp_fmtstream_free (argp_fmtstream_t __fs); +extern void argp_fmtstream_free (argp_fmtstream_t __fs); + +extern ssize_t __argp_fmtstream_printf (argp_fmtstream_t __fs, + __const char *__fmt, ...) + __attribute__ ((__format__ (printf, 2, 3))); +extern ssize_t argp_fmtstream_printf (argp_fmtstream_t __fs, + __const char *__fmt, ...) + __attribute__ ((__format__ (printf, 2, 3))); + +extern int __argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch); +extern int argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch); + +extern int __argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str); +extern int argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str); + +extern size_t __argp_fmtstream_write (argp_fmtstream_t __fs, + __const char *__str, size_t __len); +extern size_t argp_fmtstream_write (argp_fmtstream_t __fs, + __const char *__str, size_t __len); + +/* Access macros for various bits of state. */ +#define argp_fmtstream_lmargin(__fs) ((__fs)->lmargin) +#define argp_fmtstream_rmargin(__fs) ((__fs)->rmargin) +#define argp_fmtstream_wmargin(__fs) ((__fs)->wmargin) +#define __argp_fmtstream_lmargin argp_fmtstream_lmargin +#define __argp_fmtstream_rmargin argp_fmtstream_rmargin +#define __argp_fmtstream_wmargin argp_fmtstream_wmargin + +/* Set __FS's left margin to LMARGIN and return the old value. */ +extern size_t argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, + size_t __lmargin); +extern size_t __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, + size_t __lmargin); + +/* Set __FS's right margin to __RMARGIN and return the old value. */ +extern size_t argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, + size_t __rmargin); +extern size_t __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, + size_t __rmargin); + +/* Set __FS's wrap margin to __WMARGIN and return the old value. */ +extern size_t argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, + size_t __wmargin); +extern size_t __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, + size_t __wmargin); + +/* Return the column number of the current output point in __FS. */ +extern size_t argp_fmtstream_point (argp_fmtstream_t __fs); +extern size_t __argp_fmtstream_point (argp_fmtstream_t __fs); + +/* Internal routines. */ +extern void _argp_fmtstream_update (argp_fmtstream_t __fs); +extern void __argp_fmtstream_update (argp_fmtstream_t __fs); +extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount); +extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount); + +#ifdef __OPTIMIZE__ +/* Inline versions of above routines. */ + +#if !_LIBC +#define __argp_fmtstream_putc argp_fmtstream_putc +#define __argp_fmtstream_puts argp_fmtstream_puts +#define __argp_fmtstream_write argp_fmtstream_write +#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin +#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin +#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin +#define __argp_fmtstream_point argp_fmtstream_point +#define __argp_fmtstream_update _argp_fmtstream_update +#define __argp_fmtstream_ensure _argp_fmtstream_ensure +#endif + +#ifndef ARGP_FS_EI +#define ARGP_FS_EI extern inline +#endif + +ARGP_FS_EI size_t +__argp_fmtstream_write (argp_fmtstream_t __fs, + __const char *__str, size_t __len) +{ + if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len)) + { + memcpy (__fs->p, __str, __len); + __fs->p += __len; + return __len; + } + else + return 0; +} + +ARGP_FS_EI int +__argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str) +{ + size_t __len = strlen (__str); + if (__len) + { + size_t __wrote = __argp_fmtstream_write (__fs, __str, __len); + return __wrote == __len ? 0 : -1; + } + else + return 0; +} + +ARGP_FS_EI int +__argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch) +{ + if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1)) + return *__fs->p++ = __ch; + else + return EOF; +} + +/* Set __FS's left margin to __LMARGIN and return the old value. */ +ARGP_FS_EI size_t +__argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->lmargin; + __fs->lmargin = __lmargin; + return __old; +} + +/* Set __FS's right margin to __RMARGIN and return the old value. */ +ARGP_FS_EI size_t +__argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->rmargin; + __fs->rmargin = __rmargin; + return __old; +} + +/* Set FS's wrap margin to __WMARGIN and return the old value. */ +ARGP_FS_EI size_t +__argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->wmargin; + __fs->wmargin = __wmargin; + return __old; +} + +/* Return the column number of the current output point in __FS. */ +ARGP_FS_EI size_t +__argp_fmtstream_point (argp_fmtstream_t __fs) +{ + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + return __fs->point_col >= 0 ? __fs->point_col : 0; +} + +#if !_LIBC +#undef __argp_fmtstream_putc +#undef __argp_fmtstream_puts +#undef __argp_fmtstream_write +#undef __argp_fmtstream_set_lmargin +#undef __argp_fmtstream_set_rmargin +#undef __argp_fmtstream_set_wmargin +#undef __argp_fmtstream_point +#undef __argp_fmtstream_update +#undef __argp_fmtstream_ensure +#endif + +#endif /* __OPTIMIZE__ */ + +#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */ + +#endif /* argp-fmtstream.h */ diff --git a/contrib/cpio/lib/argp-fs-xinl.c b/contrib/cpio/lib/argp-fs-xinl.c new file mode 100644 index 0000000..a4d14a2 --- /dev/null +++ b/contrib/cpio/lib/argp-fs-xinl.c @@ -0,0 +1,43 @@ +/* Real definitions for extern inline functions in argp-fmtstream.h + Copyright (C) 1997, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define ARGP_FS_EI +#undef __OPTIMIZE__ +#define __OPTIMIZE__ 1 +#include "argp-fmtstream.h" + +#if 0 +/* Not exported. */ +/* Add weak aliases. */ +#if _LIBC - 0 && !defined (ARGP_FMTSTREAM_USE_LINEWRAP) && defined (weak_alias) + +weak_alias (__argp_fmtstream_putc, argp_fmtstream_putc) +weak_alias (__argp_fmtstream_puts, argp_fmtstream_puts) +weak_alias (__argp_fmtstream_write, argp_fmtstream_write) +weak_alias (__argp_fmtstream_set_lmargin, argp_fmtstream_set_lmargin) +weak_alias (__argp_fmtstream_set_rmargin, argp_fmtstream_set_rmargin) +weak_alias (__argp_fmtstream_set_wmargin, argp_fmtstream_set_wmargin) +weak_alias (__argp_fmtstream_point, argp_fmtstream_point) + +#endif +#endif diff --git a/contrib/cpio/lib/argp-help.c b/contrib/cpio/lib/argp-help.c new file mode 100644 index 0000000..6035764 --- /dev/null +++ b/contrib/cpio/lib/argp-help.c @@ -0,0 +1,1884 @@ +/* Hierarchial argument parsing help output + Copyright (C) 1995-2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <alloca.h> +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdarg.h> +#include <ctype.h> +#include <limits.h> +#ifdef USE_IN_LIBIO +# include <wchar.h> +#endif + +#ifdef _LIBC +# include <libintl.h> +# undef dgettext +# define dgettext(domain, msgid) \ + INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES) +#else +# include "gettext.h" +#endif + +#include "argp.h" +#include "argp-fmtstream.h" +#include "argp-namefrob.h" + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +/* User-selectable (using an environment variable) formatting parameters. + + These may be specified in an environment variable called `ARGP_HELP_FMT', + with a contents like: VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2 + Where VALn must be a positive integer. The list of variables is in the + UPARAM_NAMES vector, below. */ + +/* Default parameters. */ +#define DUP_ARGS 0 /* True if option argument can be duplicated. */ +#define DUP_ARGS_NOTE 1 /* True to print a note about duplicate args. */ +#define SHORT_OPT_COL 2 /* column in which short options start */ +#define LONG_OPT_COL 6 /* column in which long options start */ +#define DOC_OPT_COL 2 /* column in which doc options start */ +#define OPT_DOC_COL 29 /* column in which option text starts */ +#define HEADER_COL 1 /* column in which group headers are printed */ +#define USAGE_INDENT 12 /* indentation of wrapped usage lines */ +#define RMARGIN 79 /* right margin used for wrapping */ + +/* User-selectable (using an environment variable) formatting parameters. + They must all be of type `int' for the parsing code to work. */ +struct uparams +{ + /* If true, arguments for an option are shown with both short and long + options, even when a given option has both, e.g. `-x ARG, --longx=ARG'. + If false, then if an option has both, the argument is only shown with + the long one, e.g., `-x, --longx=ARG', and a message indicating that + this really means both is printed below the options. */ + int dup_args; + + /* This is true if when DUP_ARGS is false, and some duplicate arguments have + been suppressed, an explanatory message should be printed. */ + int dup_args_note; + + /* Various output columns. */ + int short_opt_col; + int long_opt_col; + int doc_opt_col; + int opt_doc_col; + int header_col; + int usage_indent; + int rmargin; + + int valid; /* True when the values in here are valid. */ +}; + +/* This is a global variable, as user options are only ever read once. */ +static struct uparams uparams = { + DUP_ARGS, DUP_ARGS_NOTE, + SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL, + USAGE_INDENT, RMARGIN, + 0 +}; + +/* A particular uparam, and what the user name is. */ +struct uparam_name +{ + const char *name; /* User name. */ + int is_bool; /* Whether it's `boolean'. */ + size_t uparams_offs; /* Location of the (int) field in UPARAMS. */ +}; + +/* The name-field mappings we know about. */ +static const struct uparam_name uparam_names[] = +{ + { "dup-args", 1, offsetof (struct uparams, dup_args) }, + { "dup-args-note", 1, offsetof (struct uparams, dup_args_note) }, + { "short-opt-col", 0, offsetof (struct uparams, short_opt_col) }, + { "long-opt-col", 0, offsetof (struct uparams, long_opt_col) }, + { "doc-opt-col", 0, offsetof (struct uparams, doc_opt_col) }, + { "opt-doc-col", 0, offsetof (struct uparams, opt_doc_col) }, + { "header-col", 0, offsetof (struct uparams, header_col) }, + { "usage-indent", 0, offsetof (struct uparams, usage_indent) }, + { "rmargin", 0, offsetof (struct uparams, rmargin) }, + { 0 } +}; + +/* Read user options from the environment, and fill in UPARAMS appropiately. */ +static void +fill_in_uparams (const struct argp_state *state) +{ + const char *var = getenv ("ARGP_HELP_FMT"); + +#define SKIPWS(p) do { while (isspace (*p)) p++; } while (0); + + if (var) + /* Parse var. */ + while (*var) + { + SKIPWS (var); + + if (isalpha (*var)) + { + size_t var_len; + const struct uparam_name *un; + int unspec = 0, val = 0; + const char *arg = var; + + while (isalnum (*arg) || *arg == '-' || *arg == '_') + arg++; + var_len = arg - var; + + SKIPWS (arg); + + if (*arg == '\0' || *arg == ',') + unspec = 1; + else if (*arg == '=') + { + arg++; + SKIPWS (arg); + } + + if (unspec) + { + if (var[0] == 'n' && var[1] == 'o' && var[2] == '-') + { + val = 0; + var += 3; + var_len -= 3; + } + else + val = 1; + } + else if (isdigit (*arg)) + { + val = atoi (arg); + while (isdigit (*arg)) + arg++; + SKIPWS (arg); + } + + for (un = uparam_names; un->name; un++) + if (strlen (un->name) == var_len + && strncmp (var, un->name, var_len) == 0) + { + if (unspec && !un->is_bool) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, "\ +%.*s: ARGP_HELP_FMT parameter requires a value"), + (int) var_len, var); + else + *(int *)((char *)&uparams + un->uparams_offs) = val; + break; + } + if (! un->name) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, "\ +%.*s: Unknown ARGP_HELP_FMT parameter"), + (int) var_len, var); + + var = arg; + if (*var == ',') + var++; + } + else if (*var) + { + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "Garbage in ARGP_HELP_FMT: %s"), var); + break; + } + } +} + +/* Returns true if OPT hasn't been marked invisible. Visibility only affects + whether OPT is displayed or used in sorting, not option shadowing. */ +#define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN)) + +/* Returns true if OPT is an alias for an earlier option. */ +#define oalias(opt) ((opt)->flags & OPTION_ALIAS) + +/* Returns true if OPT is an documentation-only entry. */ +#define odoc(opt) ((opt)->flags & OPTION_DOC) + +/* Returns true if OPT should not be translated */ +#define onotrans(opt) ((opt)->flags & OPTION_NO_TRANS) + +/* Returns true if OPT is the end-of-list marker for a list of options. */ +#define oend(opt) __option_is_end (opt) + +/* Returns true if OPT has a short option. */ +#define oshort(opt) __option_is_short (opt) + +/* + The help format for a particular option is like: + + -xARG, -yARG, --long1=ARG, --long2=ARG Documentation... + + Where ARG will be omitted if there's no argument, for this option, or + will be surrounded by "[" and "]" appropiately if the argument is + optional. The documentation string is word-wrapped appropiately, and if + the list of options is long enough, it will be started on a separate line. + If there are no short options for a given option, the first long option is + indented slighly in a way that's supposed to make most long options appear + to be in a separate column. + + For example, the following output (from ps): + + -p PID, --pid=PID List the process PID + --pgrp=PGRP List processes in the process group PGRP + -P, -x, --no-parent Include processes without parents + -Q, --all-fields Don't elide unusable fields (normally if there's + some reason ps can't print a field for any + process, it's removed from the output entirely) + -r, --reverse, --gratuitously-long-reverse-option + Reverse the order of any sort + --session[=SID] Add the processes from the session SID (which + defaults to the sid of the current process) + + Here are some more options: + -f ZOT, --foonly=ZOT Glork a foonly + -z, --zaza Snit a zar + + -?, --help Give this help list + --usage Give a short usage message + -V, --version Print program version + + The struct argp_option array for the above could look like: + + { + {"pid", 'p', "PID", 0, "List the process PID"}, + {"pgrp", OPT_PGRP, "PGRP", 0, "List processes in the process group PGRP"}, + {"no-parent", 'P', 0, 0, "Include processes without parents"}, + {0, 'x', 0, OPTION_ALIAS}, + {"all-fields",'Q', 0, 0, "Don't elide unusable fields (normally" + " if there's some reason ps can't" + " print a field for any process, it's" + " removed from the output entirely)" }, + {"reverse", 'r', 0, 0, "Reverse the order of any sort"}, + {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS}, + {"session", OPT_SESS, "SID", OPTION_ARG_OPTIONAL, + "Add the processes from the session" + " SID (which defaults to the sid of" + " the current process)" }, + + {0,0,0,0, "Here are some more options:"}, + {"foonly", 'f', "ZOT", 0, "Glork a foonly"}, + {"zaza", 'z', 0, 0, "Snit a zar"}, + + {0} + } + + Note that the last three options are automatically supplied by argp_parse, + unless you tell it not to with ARGP_NO_HELP. + +*/ + +/* Returns true if CH occurs between BEG and END. */ +static int +find_char (char ch, char *beg, char *end) +{ + while (beg < end) + if (*beg == ch) + return 1; + else + beg++; + return 0; +} + +struct hol_cluster; /* fwd decl */ + +struct hol_entry +{ + /* First option. */ + const struct argp_option *opt; + /* Number of options (including aliases). */ + unsigned num; + + /* A pointers into the HOL's short_options field, to the first short option + letter for this entry. The order of the characters following this point + corresponds to the order of options pointed to by OPT, and there are at + most NUM. A short option recorded in a option following OPT is only + valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's + probably been shadowed by some other entry). */ + char *short_options; + + /* Entries are sorted by their group first, in the order: + 1, 2, ..., n, 0, -m, ..., -2, -1 + and then alphabetically within each group. The default is 0. */ + int group; + + /* The cluster of options this entry belongs to, or 0 if none. */ + struct hol_cluster *cluster; + + /* The argp from which this option came. */ + const struct argp *argp; +}; + +/* A cluster of entries to reflect the argp tree structure. */ +struct hol_cluster +{ + /* A descriptive header printed before options in this cluster. */ + const char *header; + + /* Used to order clusters within the same group with the same parent, + according to the order in which they occurred in the parent argp's child + list. */ + int index; + + /* How to sort this cluster with respect to options and other clusters at the + same depth (clusters always follow options in the same group). */ + int group; + + /* The cluster to which this cluster belongs, or 0 if it's at the base + level. */ + struct hol_cluster *parent; + + /* The argp from which this cluster is (eventually) derived. */ + const struct argp *argp; + + /* The distance this cluster is from the root. */ + int depth; + + /* Clusters in a given hol are kept in a linked list, to make freeing them + possible. */ + struct hol_cluster *next; +}; + +/* A list of options for help. */ +struct hol +{ + /* An array of hol_entry's. */ + struct hol_entry *entries; + /* The number of entries in this hol. If this field is zero, the others + are undefined. */ + unsigned num_entries; + + /* A string containing all short options in this HOL. Each entry contains + pointers into this string, so the order can't be messed with blindly. */ + char *short_options; + + /* Clusters of entries in this hol. */ + struct hol_cluster *clusters; +}; + +/* Create a struct hol from the options in ARGP. CLUSTER is the + hol_cluster in which these entries occur, or 0, if at the root. */ +static struct hol * +make_hol (const struct argp *argp, struct hol_cluster *cluster) +{ + char *so; + const struct argp_option *o; + const struct argp_option *opts = argp->options; + struct hol_entry *entry; + unsigned num_short_options = 0; + struct hol *hol = malloc (sizeof (struct hol)); + + assert (hol); + + hol->num_entries = 0; + hol->clusters = 0; + + if (opts) + { + int cur_group = 0; + + /* The first option must not be an alias. */ + assert (! oalias (opts)); + + /* Calculate the space needed. */ + for (o = opts; ! oend (o); o++) + { + if (! oalias (o)) + hol->num_entries++; + if (oshort (o)) + num_short_options++; /* This is an upper bound. */ + } + + hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries); + hol->short_options = malloc (num_short_options + 1); + + assert (hol->entries && hol->short_options); + if (SIZE_MAX <= UINT_MAX) + assert (hol->num_entries <= SIZE_MAX / sizeof (struct hol_entry)); + + /* Fill in the entries. */ + so = hol->short_options; + for (o = opts, entry = hol->entries; ! oend (o); entry++) + { + entry->opt = o; + entry->num = 0; + entry->short_options = so; + entry->group = cur_group = + o->group + ? o->group + : ((!o->name && !o->key) + ? cur_group + 1 + : cur_group); + entry->cluster = cluster; + entry->argp = argp; + + do + { + entry->num++; + if (oshort (o) && ! find_char (o->key, hol->short_options, so)) + /* O has a valid short option which hasn't already been used.*/ + *so++ = o->key; + o++; + } + while (! oend (o) && oalias (o)); + } + *so = '\0'; /* null terminated so we can find the length */ + } + + return hol; +} + +/* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the + associated argp child list entry), INDEX, and PARENT, and return a pointer + to it. ARGP is the argp that this cluster results from. */ +static struct hol_cluster * +hol_add_cluster (struct hol *hol, int group, const char *header, int index, + struct hol_cluster *parent, const struct argp *argp) +{ + struct hol_cluster *cl = malloc (sizeof (struct hol_cluster)); + if (cl) + { + cl->group = group; + cl->header = header; + + cl->index = index; + cl->parent = parent; + cl->argp = argp; + cl->depth = parent ? parent->depth + 1 : 0; + + cl->next = hol->clusters; + hol->clusters = cl; + } + return cl; +} + +/* Free HOL and any resources it uses. */ +static void +hol_free (struct hol *hol) +{ + struct hol_cluster *cl = hol->clusters; + + while (cl) + { + struct hol_cluster *next = cl->next; + free (cl); + cl = next; + } + + if (hol->num_entries > 0) + { + free (hol->entries); + free (hol->short_options); + } + + free (hol); +} + +static int +hol_entry_short_iterate (const struct hol_entry *entry, + int (*func)(const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie), + const char *domain, void *cookie) +{ + unsigned nopts; + int val = 0; + const struct argp_option *opt, *real = entry->opt; + char *so = entry->short_options; + + for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) + if (oshort (opt) && *so == opt->key) + { + if (!oalias (opt)) + real = opt; + if (ovisible (opt)) + val = (*func)(opt, real, domain, cookie); + so++; + } + + return val; +} + +static inline int +__attribute__ ((always_inline)) +hol_entry_long_iterate (const struct hol_entry *entry, + int (*func)(const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie), + const char *domain, void *cookie) +{ + unsigned nopts; + int val = 0; + const struct argp_option *opt, *real = entry->opt; + + for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) + if (opt->name) + { + if (!oalias (opt)) + real = opt; + if (ovisible (opt)) + val = (*func)(opt, real, domain, cookie); + } + + return val; +} + +/* Iterator that returns true for the first short option. */ +static inline int +until_short (const struct argp_option *opt, const struct argp_option *real, + const char *domain, void *cookie) +{ + return oshort (opt) ? opt->key : 0; +} + +/* Returns the first valid short option in ENTRY, or 0 if there is none. */ +static char +hol_entry_first_short (const struct hol_entry *entry) +{ + return hol_entry_short_iterate (entry, until_short, + entry->argp->argp_domain, 0); +} + +/* Returns the first valid long option in ENTRY, or 0 if there is none. */ +static const char * +hol_entry_first_long (const struct hol_entry *entry) +{ + const struct argp_option *opt; + unsigned num; + for (opt = entry->opt, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + return opt->name; + return 0; +} + +/* Returns the entry in HOL with the long option name NAME, or 0 if there is + none. */ +static struct hol_entry * +hol_find_entry (struct hol *hol, const char *name) +{ + struct hol_entry *entry = hol->entries; + unsigned num_entries = hol->num_entries; + + while (num_entries-- > 0) + { + const struct argp_option *opt = entry->opt; + unsigned num_opts = entry->num; + + while (num_opts-- > 0) + if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0) + return entry; + else + opt++; + + entry++; + } + + return 0; +} + +/* If an entry with the long option NAME occurs in HOL, set it's special + sort position to GROUP. */ +static void +hol_set_group (struct hol *hol, const char *name, int group) +{ + struct hol_entry *entry = hol_find_entry (hol, name); + if (entry) + entry->group = group; +} + +/* Order by group: 0, 1, 2, ..., n, -m, ..., -2, -1. + EQ is what to return if GROUP1 and GROUP2 are the same. */ +static int +group_cmp (int group1, int group2, int eq) +{ + if (group1 == group2) + return eq; + else if ((group1 < 0 && group2 < 0) || (group1 >= 0 && group2 >= 0)) + return group1 - group2; + else + return group2 - group1; +} + +/* Compare clusters CL1 & CL2 by the order that they should appear in + output. */ +static int +hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2) +{ + /* If one cluster is deeper than the other, use its ancestor at the same + level, so that finding the common ancestor is straightforward. */ + while (cl1->depth < cl2->depth) + cl1 = cl1->parent; + while (cl2->depth < cl1->depth) + cl2 = cl2->parent; + + /* Now reduce both clusters to their ancestors at the point where both have + a common parent; these can be directly compared. */ + while (cl1->parent != cl2->parent) + cl1 = cl1->parent, cl2 = cl2->parent; + + return group_cmp (cl1->group, cl2->group, cl2->index - cl1->index); +} + +/* Return the ancestor of CL that's just below the root (i.e., has a parent + of 0). */ +static struct hol_cluster * +hol_cluster_base (struct hol_cluster *cl) +{ + while (cl->parent) + cl = cl->parent; + return cl; +} + +/* Return true if CL1 is a child of CL2. */ +static int +hol_cluster_is_child (const struct hol_cluster *cl1, + const struct hol_cluster *cl2) +{ + while (cl1 && cl1 != cl2) + cl1 = cl1->parent; + return cl1 == cl2; +} + +/* Given the name of a OPTION_DOC option, modifies NAME to start at the tail + that should be used for comparisons, and returns true iff it should be + treated as a non-option. */ +static int +canon_doc_option (const char **name) +{ + int non_opt; + + if (!*name) + non_opt = 1; + else + { + /* Skip initial whitespace. */ + while (isspace (**name)) + (*name)++; + /* Decide whether this looks like an option (leading `-') or not. */ + non_opt = (**name != '-'); + /* Skip until part of name used for sorting. */ + while (**name && !isalnum (**name)) + (*name)++; + } + return non_opt; +} + +/* Order ENTRY1 & ENTRY2 by the order which they should appear in a help + listing. */ +static int +hol_entry_cmp (const struct hol_entry *entry1, + const struct hol_entry *entry2) +{ + /* The group numbers by which the entries should be ordered; if either is + in a cluster, then this is just the group within the cluster. */ + int group1 = entry1->group, group2 = entry2->group; + + if (entry1->cluster != entry2->cluster) + { + /* The entries are not within the same cluster, so we can't compare them + directly, we have to use the appropiate clustering level too. */ + if (! entry1->cluster) + /* ENTRY1 is at the `base level', not in a cluster, so we have to + compare it's group number with that of the base cluster in which + ENTRY2 resides. Note that if they're in the same group, the + clustered option always comes laster. */ + return group_cmp (group1, hol_cluster_base (entry2->cluster)->group, -1); + else if (! entry2->cluster) + /* Likewise, but ENTRY2's not in a cluster. */ + return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1); + else + /* Both entries are in clusters, we can just compare the clusters. */ + return hol_cluster_cmp (entry1->cluster, entry2->cluster); + } + else if (group1 == group2) + /* The entries are both in the same cluster and group, so compare them + alphabetically. */ + { + int short1 = hol_entry_first_short (entry1); + int short2 = hol_entry_first_short (entry2); + int doc1 = odoc (entry1->opt); + int doc2 = odoc (entry2->opt); + const char *long1 = hol_entry_first_long (entry1); + const char *long2 = hol_entry_first_long (entry2); + + if (doc1) + doc1 = canon_doc_option (&long1); + if (doc2) + doc2 = canon_doc_option (&long2); + + if (doc1 != doc2) + /* `documentation' options always follow normal options (or + documentation options that *look* like normal options). */ + return doc1 - doc2; + else if (!short1 && !short2 && long1 && long2) + /* Only long options. */ + return __strcasecmp (long1, long2); + else + /* Compare short/short, long/short, short/long, using the first + character of long options. Entries without *any* valid + options (such as options with OPTION_HIDDEN set) will be put + first, but as they're not displayed, it doesn't matter where + they are. */ + { + char first1 = short1 ? short1 : long1 ? *long1 : 0; + char first2 = short2 ? short2 : long2 ? *long2 : 0; +#ifdef _tolower + int lower_cmp = _tolower (first1) - _tolower (first2); +#else + int lower_cmp = tolower (first1) - tolower (first2); +#endif + /* Compare ignoring case, except when the options are both the + same letter, in which case lower-case always comes first. */ + return lower_cmp ? lower_cmp : first2 - first1; + } + } + else + /* Within the same cluster, but not the same group, so just compare + groups. */ + return group_cmp (group1, group2, 0); +} + +/* Version of hol_entry_cmp with correct signature for qsort. */ +static int +hol_entry_qcmp (const void *entry1_v, const void *entry2_v) +{ + return hol_entry_cmp (entry1_v, entry2_v); +} + +/* Sort HOL by group and alphabetically by option name (with short options + taking precedence over long). Since the sorting is for display purposes + only, the shadowing of options isn't effected. */ +static void +hol_sort (struct hol *hol) +{ + if (hol->num_entries > 0) + qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), + hol_entry_qcmp); +} + +/* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow + any in MORE with the same name. */ +static void +hol_append (struct hol *hol, struct hol *more) +{ + struct hol_cluster **cl_end = &hol->clusters; + + /* Steal MORE's cluster list, and add it to the end of HOL's. */ + while (*cl_end) + cl_end = &(*cl_end)->next; + *cl_end = more->clusters; + more->clusters = 0; + + /* Merge entries. */ + if (more->num_entries > 0) + { + if (hol->num_entries == 0) + { + hol->num_entries = more->num_entries; + hol->entries = more->entries; + hol->short_options = more->short_options; + more->num_entries = 0; /* Mark MORE's fields as invalid. */ + } + else + /* Append the entries in MORE to those in HOL, taking care to only add + non-shadowed SHORT_OPTIONS values. */ + { + unsigned left; + char *so, *more_so; + struct hol_entry *e; + unsigned num_entries = hol->num_entries + more->num_entries; + struct hol_entry *entries = + malloc (num_entries * sizeof (struct hol_entry)); + unsigned hol_so_len = strlen (hol->short_options); + char *short_options = + malloc (hol_so_len + strlen (more->short_options) + 1); + + assert (entries && short_options); + if (SIZE_MAX <= UINT_MAX) + assert (num_entries <= SIZE_MAX / sizeof (struct hol_entry)); + + __mempcpy (__mempcpy (entries, hol->entries, + hol->num_entries * sizeof (struct hol_entry)), + more->entries, + more->num_entries * sizeof (struct hol_entry)); + + __mempcpy (short_options, hol->short_options, hol_so_len); + + /* Fix up the short options pointers from HOL. */ + for (e = entries, left = hol->num_entries; left > 0; e++, left--) + e->short_options += (short_options - hol->short_options); + + /* Now add the short options from MORE, fixing up its entries + too. */ + so = short_options + hol_so_len; + more_so = more->short_options; + for (left = more->num_entries; left > 0; e++, left--) + { + int opts_left; + const struct argp_option *opt; + + e->short_options = so; + + for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--) + { + int ch = *more_so; + if (oshort (opt) && ch == opt->key) + /* The next short option in MORE_SO, CH, is from OPT. */ + { + if (! find_char (ch, short_options, + short_options + hol_so_len)) + /* The short option CH isn't shadowed by HOL's options, + so add it to the sum. */ + *so++ = ch; + more_so++; + } + } + } + + *so = '\0'; + + free (hol->entries); + free (hol->short_options); + + hol->entries = entries; + hol->num_entries = num_entries; + hol->short_options = short_options; + } + } + + hol_free (more); +} + +/* Inserts enough spaces to make sure STREAM is at column COL. */ +static void +indent_to (argp_fmtstream_t stream, unsigned col) +{ + int needed = col - __argp_fmtstream_point (stream); + while (needed-- > 0) + __argp_fmtstream_putc (stream, ' '); +} + +/* Output to STREAM either a space, or a newline if there isn't room for at + least ENSURE characters before the right margin. */ +static void +space (argp_fmtstream_t stream, size_t ensure) +{ + if (__argp_fmtstream_point (stream) + ensure + >= __argp_fmtstream_rmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + else + __argp_fmtstream_putc (stream, ' '); +} + +/* If the option REAL has an argument, we print it in using the printf + format REQ_FMT or OPT_FMT depending on whether it's a required or + optional argument. */ +static void +arg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt, + const char *domain, argp_fmtstream_t stream) +{ + if (real->arg) + { + if (real->flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, opt_fmt, + dgettext (domain, real->arg)); + else + __argp_fmtstream_printf (stream, req_fmt, + dgettext (domain, real->arg)); + } +} + +/* Helper functions for hol_entry_help. */ + +/* State used during the execution of hol_help. */ +struct hol_help_state +{ + /* PREV_ENTRY should contain the previous entry printed, or 0. */ + struct hol_entry *prev_entry; + + /* If an entry is in a different group from the previous one, and SEP_GROUPS + is true, then a blank line will be printed before any output. */ + int sep_groups; + + /* True if a duplicate option argument was suppressed (only ever set if + UPARAMS.dup_args is false). */ + int suppressed_dup_arg; +}; + +/* Some state used while printing a help entry (used to communicate with + helper functions). See the doc for hol_entry_help for more info, as most + of the fields are copied from its arguments. */ +struct pentry_state +{ + const struct hol_entry *entry; + argp_fmtstream_t stream; + struct hol_help_state *hhstate; + + /* True if nothing's been printed so far. */ + int first; + + /* If non-zero, the state that was used to print this help. */ + const struct argp_state *state; +}; + +/* If a user doc filter should be applied to DOC, do so. */ +static const char * +filter_doc (const char *doc, int key, const struct argp *argp, + const struct argp_state *state) +{ + if (argp->help_filter) + /* We must apply a user filter to this output. */ + { + void *input = __argp_input (argp, state); + return (*argp->help_filter) (key, doc, input); + } + else + /* No filter. */ + return doc; +} + +/* Prints STR as a header line, with the margin lines set appropiately, and + notes the fact that groups should be separated with a blank line. ARGP is + the argp that should dictate any user doc filtering to take place. Note + that the previous wrap margin isn't restored, but the left margin is reset + to 0. */ +static void +print_header (const char *str, const struct argp *argp, + struct pentry_state *pest) +{ + const char *tstr = dgettext (argp->argp_domain, str); + const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state); + + if (fstr) + { + if (*fstr) + { + if (pest->hhstate->prev_entry) + /* Precede with a blank line. */ + __argp_fmtstream_putc (pest->stream, '\n'); + indent_to (pest->stream, uparams.header_col); + __argp_fmtstream_set_lmargin (pest->stream, uparams.header_col); + __argp_fmtstream_set_wmargin (pest->stream, uparams.header_col); + __argp_fmtstream_puts (pest->stream, fstr); + __argp_fmtstream_set_lmargin (pest->stream, 0); + __argp_fmtstream_putc (pest->stream, '\n'); + } + + pest->hhstate->sep_groups = 1; /* Separate subsequent groups. */ + } + + if (fstr != tstr) + free ((char *) fstr); +} + +/* Inserts a comma if this isn't the first item on the line, and then makes + sure we're at least to column COL. If this *is* the first item on a line, + prints any pending whitespace/headers that should precede this line. Also + clears FIRST. */ +static void +comma (unsigned col, struct pentry_state *pest) +{ + if (pest->first) + { + const struct hol_entry *pe = pest->hhstate->prev_entry; + const struct hol_cluster *cl = pest->entry->cluster; + + if (pest->hhstate->sep_groups && pe && pest->entry->group != pe->group) + __argp_fmtstream_putc (pest->stream, '\n'); + + if (cl && cl->header && *cl->header + && (!pe + || (pe->cluster != cl + && !hol_cluster_is_child (pe->cluster, cl)))) + /* If we're changing clusters, then this must be the start of the + ENTRY's cluster unless that is an ancestor of the previous one + (in which case we had just popped into a sub-cluster for a bit). + If so, then print the cluster's header line. */ + { + int old_wm = __argp_fmtstream_wmargin (pest->stream); + print_header (cl->header, cl->argp, pest); + __argp_fmtstream_set_wmargin (pest->stream, old_wm); + } + + pest->first = 0; + } + else + __argp_fmtstream_puts (pest->stream, ", "); + + indent_to (pest->stream, col); +} + +/* Print help for ENTRY to STREAM. */ +static void +hol_entry_help (struct hol_entry *entry, const struct argp_state *state, + argp_fmtstream_t stream, struct hol_help_state *hhstate) +{ + unsigned num; + const struct argp_option *real = entry->opt, *opt; + char *so = entry->short_options; + int have_long_opt = 0; /* We have any long options. */ + /* Saved margins. */ + int old_lm = __argp_fmtstream_set_lmargin (stream, 0); + int old_wm = __argp_fmtstream_wmargin (stream); + /* PEST is a state block holding some of our variables that we'd like to + share with helper functions. */ + struct pentry_state pest = { entry, stream, hhstate, 1, state }; + + if (! odoc (real)) + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + { + have_long_opt = 1; + break; + } + + /* First emit short options. */ + __argp_fmtstream_set_wmargin (stream, uparams.short_opt_col); /* For truly bizarre cases. */ + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (oshort (opt) && opt->key == *so) + /* OPT has a valid (non shadowed) short option. */ + { + if (ovisible (opt)) + { + comma (uparams.short_opt_col, &pest); + __argp_fmtstream_putc (stream, '-'); + __argp_fmtstream_putc (stream, *so); + if (!have_long_opt || uparams.dup_args) + arg (real, " %s", "[%s]", state->root_argp->argp_domain, stream); + else if (real->arg) + hhstate->suppressed_dup_arg = 1; + } + so++; + } + + /* Now, long options. */ + if (odoc (real)) + /* A `documentation' option. */ + { + __argp_fmtstream_set_wmargin (stream, uparams.doc_opt_col); + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && *opt->name && ovisible (opt)) + { + comma (uparams.doc_opt_col, &pest); + /* Calling dgettext here isn't quite right, since sorting will + have been done on the original; but documentation options + should be pretty rare anyway... */ + __argp_fmtstream_puts (stream, + onotrans (opt) ? + opt->name : + dgettext (state->root_argp->argp_domain, + opt->name)); + } + } + else + /* A real long option. */ + { + int first_long_opt = 1; + + __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col); + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + { + comma (uparams.long_opt_col, &pest); + __argp_fmtstream_printf (stream, "--%s", opt->name); + if (first_long_opt || uparams.dup_args) + arg (real, "=%s", "[=%s]", state->root_argp->argp_domain, + stream); + else if (real->arg) + hhstate->suppressed_dup_arg = 1; + } + } + + /* Next, documentation strings. */ + __argp_fmtstream_set_lmargin (stream, 0); + + if (pest.first) + { + /* Didn't print any switches, what's up? */ + if (!oshort (real) && !real->name) + /* This is a group header, print it nicely. */ + print_header (real->doc, entry->argp, &pest); + else + /* Just a totally shadowed option or null header; print nothing. */ + goto cleanup; /* Just return, after cleaning up. */ + } + else + { + const char *tstr = real->doc ? dgettext (state->root_argp->argp_domain, + real->doc) : 0; + const char *fstr = filter_doc (tstr, real->key, entry->argp, state); + if (fstr && *fstr) + { + unsigned int col = __argp_fmtstream_point (stream); + + __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col); + __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col); + + if (col > (unsigned int) (uparams.opt_doc_col + 3)) + __argp_fmtstream_putc (stream, '\n'); + else if (col >= (unsigned int) uparams.opt_doc_col) + __argp_fmtstream_puts (stream, " "); + else + indent_to (stream, uparams.opt_doc_col); + + __argp_fmtstream_puts (stream, fstr); + } + if (fstr && fstr != tstr) + free ((char *) fstr); + + /* Reset the left margin. */ + __argp_fmtstream_set_lmargin (stream, 0); + __argp_fmtstream_putc (stream, '\n'); + } + + hhstate->prev_entry = entry; + +cleanup: + __argp_fmtstream_set_lmargin (stream, old_lm); + __argp_fmtstream_set_wmargin (stream, old_wm); +} + +/* Output a long help message about the options in HOL to STREAM. */ +static void +hol_help (struct hol *hol, const struct argp_state *state, + argp_fmtstream_t stream) +{ + unsigned num; + struct hol_entry *entry; + struct hol_help_state hhstate = { 0, 0, 0 }; + + for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--) + hol_entry_help (entry, state, stream, &hhstate); + + if (hhstate.suppressed_dup_arg && uparams.dup_args_note) + { + const char *tstr = dgettext (state->root_argp->argp_domain, "\ +Mandatory or optional arguments to long options are also mandatory or \ +optional for any corresponding short options."); + const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE, + state ? state->root_argp : 0, state); + if (fstr && *fstr) + { + __argp_fmtstream_putc (stream, '\n'); + __argp_fmtstream_puts (stream, fstr); + __argp_fmtstream_putc (stream, '\n'); + } + if (fstr && fstr != tstr) + free ((char *) fstr); + } +} + +/* Helper functions for hol_usage. */ + +/* If OPT is a short option without an arg, append its key to the string + pointer pointer to by COOKIE, and advance the pointer. */ +static int +add_argless_short_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + char **snao_end = cookie; + if (!(opt->arg || real->arg) + && !((opt->flags | real->flags) & OPTION_NO_USAGE)) + *(*snao_end)++ = opt->key; + return 0; +} + +/* If OPT is a short option with an arg, output a usage entry for it to the + stream pointed at by COOKIE. */ +static int +usage_argful_short_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + argp_fmtstream_t stream = cookie; + const char *arg = opt->arg; + int flags = opt->flags | real->flags; + + if (! arg) + arg = real->arg; + + if (arg && !(flags & OPTION_NO_USAGE)) + { + arg = dgettext (domain, arg); + + if (flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg); + else + { + /* Manually do line wrapping so that it (probably) won't + get wrapped at the embedded space. */ + space (stream, 6 + strlen (arg)); + __argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg); + } + } + + return 0; +} + +/* Output a usage entry for the long option opt to the stream pointed at by + COOKIE. */ +static int +usage_long_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + argp_fmtstream_t stream = cookie; + const char *arg = opt->arg; + int flags = opt->flags | real->flags; + + if (! arg) + arg = real->arg; + + if (! (flags & OPTION_NO_USAGE)) + { + if (arg) + { + arg = dgettext (domain, arg); + if (flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg); + else + __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg); + } + else + __argp_fmtstream_printf (stream, " [--%s]", opt->name); + } + + return 0; +} + +/* Print a short usage description for the arguments in HOL to STREAM. */ +static void +hol_usage (struct hol *hol, argp_fmtstream_t stream) +{ + if (hol->num_entries > 0) + { + unsigned nentries; + struct hol_entry *entry; + char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1); + char *snao_end = short_no_arg_opts; + + /* First we put a list of short options without arguments. */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_short_iterate (entry, add_argless_short_opt, + entry->argp->argp_domain, &snao_end); + if (snao_end > short_no_arg_opts) + { + *snao_end++ = 0; + __argp_fmtstream_printf (stream, " [-%s]", short_no_arg_opts); + } + + /* Now a list of short options *with* arguments. */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_short_iterate (entry, usage_argful_short_opt, + entry->argp->argp_domain, stream); + + /* Finally, a list of long options (whew!). */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_long_iterate (entry, usage_long_opt, + entry->argp->argp_domain, stream); + } +} + +/* Make a HOL containing all levels of options in ARGP. CLUSTER is the + cluster in which ARGP's entries should be clustered, or 0. */ +static struct hol * +argp_hol (const struct argp *argp, struct hol_cluster *cluster) +{ + const struct argp_child *child = argp->children; + struct hol *hol = make_hol (argp, cluster); + if (child) + while (child->argp) + { + struct hol_cluster *child_cluster = + ((child->group || child->header) + /* Put CHILD->argp within its own cluster. */ + ? hol_add_cluster (hol, child->group, child->header, + child - argp->children, cluster, argp) + /* Just merge it into the parent's cluster. */ + : cluster); + hol_append (hol, argp_hol (child->argp, child_cluster)) ; + child++; + } + return hol; +} + +/* Calculate how many different levels with alternative args strings exist in + ARGP. */ +static size_t +argp_args_levels (const struct argp *argp) +{ + size_t levels = 0; + const struct argp_child *child = argp->children; + + if (argp->args_doc && strchr (argp->args_doc, '\n')) + levels++; + + if (child) + while (child->argp) + levels += argp_args_levels ((child++)->argp); + + return levels; +} + +/* Print all the non-option args documented in ARGP to STREAM. Any output is + preceded by a space. LEVELS is a pointer to a byte vector the length + returned by argp_args_levels; it should be initialized to zero, and + updated by this routine for the next call if ADVANCE is true. True is + returned as long as there are more patterns to output. */ +static int +argp_args_usage (const struct argp *argp, const struct argp_state *state, + char **levels, int advance, argp_fmtstream_t stream) +{ + char *our_level = *levels; + int multiple = 0; + const struct argp_child *child = argp->children; + const char *tdoc = dgettext (argp->argp_domain, argp->args_doc), *nl = 0; + const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp, state); + + if (fdoc) + { + const char *cp = fdoc; + nl = __strchrnul (cp, '\n'); + if (*nl != '\0') + /* This is a `multi-level' args doc; advance to the correct position + as determined by our state in LEVELS, and update LEVELS. */ + { + int i; + multiple = 1; + for (i = 0; i < *our_level; i++) + cp = nl + 1, nl = __strchrnul (cp, '\n'); + (*levels)++; + } + + /* Manually do line wrapping so that it (probably) won't get wrapped at + any embedded spaces. */ + space (stream, 1 + nl - cp); + + __argp_fmtstream_write (stream, cp, nl - cp); + } + if (fdoc && fdoc != tdoc) + free ((char *)fdoc); /* Free user's modified doc string. */ + + if (child) + while (child->argp) + advance = !argp_args_usage ((child++)->argp, state, levels, advance, stream); + + if (advance && multiple) + { + /* Need to increment our level. */ + if (*nl) + /* There's more we can do here. */ + { + (*our_level)++; + advance = 0; /* Our parent shouldn't advance also. */ + } + else if (*our_level > 0) + /* We had multiple levels, but used them up; reset to zero. */ + *our_level = 0; + } + + return !advance; +} + +/* Print the documentation for ARGP to STREAM; if POST is false, then + everything preceeding a `\v' character in the documentation strings (or + the whole string, for those with none) is printed, otherwise, everything + following the `\v' character (nothing for strings without). Each separate + bit of documentation is separated a blank line, and if PRE_BLANK is true, + then the first is as well. If FIRST_ONLY is true, only the first + occurrence is output. Returns true if anything was output. */ +static int +argp_doc (const struct argp *argp, const struct argp_state *state, + int post, int pre_blank, int first_only, + argp_fmtstream_t stream) +{ + const char *text; + const char *inp_text; + void *input = 0; + int anything = 0; + size_t inp_text_limit = 0; + const char *doc = dgettext (argp->argp_domain, argp->doc); + const struct argp_child *child = argp->children; + + if (doc) + { + char *vt = strchr (doc, '\v'); + inp_text = post ? (vt ? vt + 1 : 0) : doc; + inp_text_limit = (!post && vt) ? (vt - doc) : 0; + } + else + inp_text = 0; + + if (argp->help_filter) + /* We have to filter the doc strings. */ + { + if (inp_text_limit) + /* Copy INP_TEXT so that it's nul-terminated. */ + inp_text = __strndup (inp_text, inp_text_limit); + input = __argp_input (argp, state); + text = + (*argp->help_filter) (post + ? ARGP_KEY_HELP_POST_DOC + : ARGP_KEY_HELP_PRE_DOC, + inp_text, input); + } + else + text = (const char *) inp_text; + + if (text) + { + if (pre_blank) + __argp_fmtstream_putc (stream, '\n'); + + if (text == inp_text && inp_text_limit) + __argp_fmtstream_write (stream, inp_text, inp_text_limit); + else + __argp_fmtstream_puts (stream, text); + + if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + + anything = 1; + } + + if (text && text != inp_text) + free ((char *) text); /* Free TEXT returned from the help filter. */ + if (inp_text && inp_text_limit && argp->help_filter) + free ((char *) inp_text); /* We copied INP_TEXT, so free it now. */ + + if (post && argp->help_filter) + /* Now see if we have to output a ARGP_KEY_HELP_EXTRA text. */ + { + text = (*argp->help_filter) (ARGP_KEY_HELP_EXTRA, 0, input); + if (text) + { + if (anything || pre_blank) + __argp_fmtstream_putc (stream, '\n'); + __argp_fmtstream_puts (stream, text); + free ((char *) text); + if (__argp_fmtstream_point (stream) + > __argp_fmtstream_lmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + anything = 1; + } + } + + if (child) + while (child->argp && !(first_only && anything)) + anything |= + argp_doc ((child++)->argp, state, + post, anything || pre_blank, first_only, + stream); + + return anything; +} + +/* Output a usage message for ARGP to STREAM. If called from + argp_state_help, STATE is the relevent parsing state. FLAGS are from the + set ARGP_HELP_*. NAME is what to use wherever a `program name' is + needed. */ +static void +_help (const struct argp *argp, const struct argp_state *state, FILE *stream, + unsigned flags, char *name) +{ + int anything = 0; /* Whether we've output anything. */ + struct hol *hol = 0; + argp_fmtstream_t fs; + + if (! stream) + return; + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __flockfile (stream); +#endif + + if (! uparams.valid) + fill_in_uparams (state); + + fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0); + if (! fs) + { +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __funlockfile (stream); +#endif + return; + } + + if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG)) + { + hol = argp_hol (argp, 0); + + /* If present, these options always come last. */ + hol_set_group (hol, "help", -1); + hol_set_group (hol, "version", -1); + + hol_sort (hol); + } + + if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE)) + /* Print a short `Usage:' message. */ + { + int first_pattern = 1, more_patterns; + size_t num_pattern_levels = argp_args_levels (argp); + char *pattern_levels = alloca (num_pattern_levels); + + memset (pattern_levels, 0, num_pattern_levels); + + do + { + int old_lm; + int old_wm = __argp_fmtstream_set_wmargin (fs, uparams.usage_indent); + char *levels = pattern_levels; + + if (first_pattern) + __argp_fmtstream_printf (fs, "%s %s", + dgettext (argp->argp_domain, "Usage:"), + name); + else + __argp_fmtstream_printf (fs, "%s %s", + dgettext (argp->argp_domain, " or: "), + name); + + /* We set the lmargin as well as the wmargin, because hol_usage + manually wraps options with newline to avoid annoying breaks. */ + old_lm = __argp_fmtstream_set_lmargin (fs, uparams.usage_indent); + + if (flags & ARGP_HELP_SHORT_USAGE) + /* Just show where the options go. */ + { + if (hol->num_entries > 0) + __argp_fmtstream_puts (fs, dgettext (argp->argp_domain, + " [OPTION...]")); + } + else + /* Actually print the options. */ + { + hol_usage (hol, fs); + flags |= ARGP_HELP_SHORT_USAGE; /* But only do so once. */ + } + + more_patterns = argp_args_usage (argp, state, &levels, 1, fs); + + __argp_fmtstream_set_wmargin (fs, old_wm); + __argp_fmtstream_set_lmargin (fs, old_lm); + + __argp_fmtstream_putc (fs, '\n'); + anything = 1; + + first_pattern = 0; + } + while (more_patterns); + } + + if (flags & ARGP_HELP_PRE_DOC) + anything |= argp_doc (argp, state, 0, 0, 1, fs); + + if (flags & ARGP_HELP_SEE) + { + __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\ +Try `%s --help' or `%s --usage' for more information.\n"), + name, name); + anything = 1; + } + + if (flags & ARGP_HELP_LONG) + /* Print a long, detailed help message. */ + { + /* Print info about all the options. */ + if (hol->num_entries > 0) + { + if (anything) + __argp_fmtstream_putc (fs, '\n'); + hol_help (hol, state, fs); + anything = 1; + } + } + + if (flags & ARGP_HELP_POST_DOC) + /* Print any documentation strings at the end. */ + anything |= argp_doc (argp, state, 1, anything, 0, fs); + + if ((flags & ARGP_HELP_BUG_ADDR) && argp_program_bug_address) + { + if (anything) + __argp_fmtstream_putc (fs, '\n'); + __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, + "Report bugs to %s.\n"), + argp_program_bug_address); + anything = 1; + } + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __funlockfile (stream); +#endif + + if (hol) + hol_free (hol); + + __argp_fmtstream_free (fs); +} + +/* Output a usage message for ARGP to STREAM. FLAGS are from the set + ARGP_HELP_*. NAME is what to use wherever a `program name' is needed. */ +void __argp_help (const struct argp *argp, FILE *stream, + unsigned flags, char *name) +{ + _help (argp, 0, stream, flags, name); +} +#ifdef weak_alias +weak_alias (__argp_help, argp_help) +#endif + +#if ! (defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) +char * +__argp_short_program_name (void) +{ +# if HAVE_DECL_PROGRAM_INVOCATION_NAME + char *name = strrchr (program_invocation_name, '/'); + return name ? name + 1 : program_invocation_name; +# else + /* FIXME: What now? Miles suggests that it is better to use NULL, + but currently the value is passed on directly to fputs_unlocked, + so that requires more changes. */ +# if __GNUC__ +# warning No reasonable value to return +# endif /* __GNUC__ */ + return ""; +# endif +} +#endif + +/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are + from the set ARGP_HELP_*. */ +void +__argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags) +{ + if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream) + { + if (state && (state->flags & ARGP_LONG_ONLY)) + flags |= ARGP_HELP_LONG_ONLY; + + _help (state ? state->root_argp : 0, state, stream, flags, + state ? state->name : __argp_short_program_name ()); + + if (!state || ! (state->flags & ARGP_NO_EXIT)) + { + if (flags & ARGP_HELP_EXIT_ERR) + exit (argp_err_exit_status); + if (flags & ARGP_HELP_EXIT_OK) + exit (0); + } + } +} +#ifdef weak_alias +weak_alias (__argp_state_help, argp_state_help) +#endif + +/* If appropriate, print the printf string FMT and following args, preceded + by the program name and `:', to stderr, and followed by a `Try ... --help' + message, then exit (1). */ +void +__argp_error (const struct argp_state *state, const char *fmt, ...) +{ + if (!state || !(state->flags & ARGP_NO_ERRS)) + { + FILE *stream = state ? state->err_stream : stderr; + + if (stream) + { + va_list ap; + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __flockfile (stream); +#endif + + va_start (ap, fmt); + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + { + char *buf; + + __asprintf (&buf, fmt, ap); + + __fwprintf (stream, L"%s: %s\n", + state ? state->name : __argp_short_program_name (), + buf); + + free (buf); + } + else +#endif + { + fputs_unlocked (state + ? state->name : __argp_short_program_name (), + stream); + putc_unlocked (':', stream); + putc_unlocked (' ', stream); + + vfprintf (stream, fmt, ap); + + putc_unlocked ('\n', stream); + } + + __argp_state_help (state, stream, ARGP_HELP_STD_ERR); + + va_end (ap); + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __funlockfile (stream); +#endif + } + } +} +#ifdef weak_alias +weak_alias (__argp_error, argp_error) +#endif + +/* Similar to the standard gnu error-reporting function error(), but will + respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print + to STATE->err_stream. This is useful for argument parsing code that is + shared between program startup (when exiting is desired) and runtime + option parsing (when typically an error code is returned instead). The + difference between this function and argp_error is that the latter is for + *parsing errors*, and the former is for other problems that occur during + parsing but don't reflect a (syntactic) problem with the input. */ +void +__argp_failure (const struct argp_state *state, int status, int errnum, + const char *fmt, ...) +{ + if (!state || !(state->flags & ARGP_NO_ERRS)) + { + FILE *stream = state ? state->err_stream : stderr; + + if (stream) + { +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __flockfile (stream); +#endif + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + __fwprintf (stream, L"%s", + state ? state->name : __argp_short_program_name ()); + else +#endif + fputs_unlocked (state + ? state->name : __argp_short_program_name (), + stream); + + if (fmt) + { + va_list ap; + + va_start (ap, fmt); +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + { + char *buf; + + __asprintf (&buf, fmt, ap); + + __fwprintf (stream, L": %s", buf); + + free (buf); + } + else +#endif + { + putc_unlocked (':', stream); + putc_unlocked (' ', stream); + + vfprintf (stream, fmt, ap); + } + + va_end (ap); + } + + if (errnum) + { + char buf[200]; + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + __fwprintf (stream, L": %s", + __strerror_r (errnum, buf, sizeof (buf))); + else +#endif + { + char const *s = NULL; + putc_unlocked (':', stream); + putc_unlocked (' ', stream); +#if _LIBC || (HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P) + s = __strerror_r (errnum, buf, sizeof buf); +#elif HAVE_DECL_STRERROR_R + if (__strerror_r (errnum, buf, sizeof buf) == 0) + s = buf; +#endif +#if !_LIBC + if (! s && ! (s = strerror (errnum))) + s = "Unknown system error"; /* FIXME: translate this */ +#endif + fputs (s, stream); + } + } + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + putwc_unlocked (L'\n', stream); + else +#endif + putc_unlocked ('\n', stream); + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __funlockfile (stream); +#endif + + if (status && (!state || !(state->flags & ARGP_NO_EXIT))) + exit (status); + } + } +} +#ifdef weak_alias +weak_alias (__argp_failure, argp_failure) +#endif diff --git a/contrib/cpio/lib/argp-namefrob.h b/contrib/cpio/lib/argp-namefrob.h new file mode 100644 index 0000000..09cafd0 --- /dev/null +++ b/contrib/cpio/lib/argp-namefrob.h @@ -0,0 +1,156 @@ +/* Name frobnication for compiling argp outside of glibc + Copyright (C) 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !_LIBC +/* This code is written for inclusion in gnu-libc, and uses names in the + namespace reserved for libc. If we're not compiling in libc, define those + names to be the normal ones instead. */ + +/* argp-parse functions */ +#undef __argp_parse +#define __argp_parse argp_parse +#undef __option_is_end +#define __option_is_end _option_is_end +#undef __option_is_short +#define __option_is_short _option_is_short +#undef __argp_input +#define __argp_input _argp_input + +/* argp-help functions */ +#undef __argp_help +#define __argp_help argp_help +#undef __argp_error +#define __argp_error argp_error +#undef __argp_failure +#define __argp_failure argp_failure +#undef __argp_state_help +#define __argp_state_help argp_state_help +#undef __argp_usage +#define __argp_usage argp_usage + +/* argp-fmtstream functions */ +#undef __argp_make_fmtstream +#define __argp_make_fmtstream argp_make_fmtstream +#undef __argp_fmtstream_free +#define __argp_fmtstream_free argp_fmtstream_free +#undef __argp_fmtstream_putc +#define __argp_fmtstream_putc argp_fmtstream_putc +#undef __argp_fmtstream_puts +#define __argp_fmtstream_puts argp_fmtstream_puts +#undef __argp_fmtstream_write +#define __argp_fmtstream_write argp_fmtstream_write +#undef __argp_fmtstream_printf +#define __argp_fmtstream_printf argp_fmtstream_printf +#undef __argp_fmtstream_set_lmargin +#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin +#undef __argp_fmtstream_set_rmargin +#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin +#undef __argp_fmtstream_set_wmargin +#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin +#undef __argp_fmtstream_point +#define __argp_fmtstream_point argp_fmtstream_point +#undef __argp_fmtstream_update +#define __argp_fmtstream_update _argp_fmtstream_update +#undef __argp_fmtstream_ensure +#define __argp_fmtstream_ensure _argp_fmtstream_ensure +#undef __argp_fmtstream_lmargin +#define __argp_fmtstream_lmargin argp_fmtstream_lmargin +#undef __argp_fmtstream_rmargin +#define __argp_fmtstream_rmargin argp_fmtstream_rmargin +#undef __argp_fmtstream_wmargin +#define __argp_fmtstream_wmargin argp_fmtstream_wmargin + +#include "mempcpy.h" +#include "strcase.h" +#include "strchrnul.h" +#include "strndup.h" + +/* normal libc functions we call */ +#undef __flockfile +#define __flockfile flockfile +#undef __funlockfile +#define __funlockfile funlockfile +#undef __mempcpy +#define __mempcpy mempcpy +#undef __sleep +#define __sleep sleep +#undef __strcasecmp +#define __strcasecmp strcasecmp +#undef __strchrnul +#define __strchrnul strchrnul +#undef __strerror_r +#define __strerror_r strerror_r +#undef __strndup +#define __strndup strndup +#undef __vsnprintf +#define __vsnprintf vsnprintf + +#if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED +# define clearerr_unlocked(x) clearerr (x) +#endif +#if defined(HAVE_DECL_FEOF_UNLOCKED) && !HAVE_DECL_FEOF_UNLOCKED +# define feof_unlocked(x) feof (x) +# endif +#if defined(HAVE_DECL_FERROR_UNLOCKED) && !HAVE_DECL_FERROR_UNLOCKED +# define ferror_unlocked(x) ferror (x) +# endif +#if defined(HAVE_DECL_FFLUSH_UNLOCKED) && !HAVE_DECL_FFLUSH_UNLOCKED +# define fflush_unlocked(x) fflush (x) +# endif +#if defined(HAVE_DECL_FGETS_UNLOCKED) && !HAVE_DECL_FGETS_UNLOCKED +# define fgets_unlocked(x,y,z) fgets (x,y,z) +# endif +#if defined(HAVE_DECL_FPUTC_UNLOCKED) && !HAVE_DECL_FPUTC_UNLOCKED +# define fputc_unlocked(x,y) fputc (x,y) +# endif +#if defined(HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED +# define fputs_unlocked(x,y) fputs (x,y) +# endif +#if defined(HAVE_DECL_FREAD_UNLOCKED) && !HAVE_DECL_FREAD_UNLOCKED +# define fread_unlocked(w,x,y,z) fread (w,x,y,z) +# endif +#if defined(HAVE_DECL_FWRITE_UNLOCKED) && !HAVE_DECL_FWRITE_UNLOCKED +# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) +# endif +#if defined(HAVE_DECL_GETC_UNLOCKED) && !HAVE_DECL_GETC_UNLOCKED +# define getc_unlocked(x) getc (x) +# endif +#if defined(HAVE_DECL_GETCHAR_UNLOCKED) && !HAVE_DECL_GETCHAR_UNLOCKED +# define getchar_unlocked() getchar () +# endif +#if defined(HAVE_DECL_PUTC_UNLOCKED) && !HAVE_DECL_PUTC_UNLOCKED +# define putc_unlocked(x,y) putc (x,y) +# endif +#if defined(HAVE_DECL_PUTCHAR_UNLOCKED) && !HAVE_DECL_PUTCHAR_UNLOCKED +# define putchar_unlocked(x) putchar (x) +# endif + +extern char *__argp_basename (char *name); + +#endif /* !_LIBC */ + +#ifndef __set_errno +#define __set_errno(e) (errno = (e)) +#endif + +#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME +# define __argp_short_program_name() (program_invocation_short_name) +#else +extern char *__argp_short_program_name (void); +#endif diff --git a/contrib/cpio/lib/argp-parse.c b/contrib/cpio/lib/argp-parse.c new file mode 100644 index 0000000..9195b87 --- /dev/null +++ b/contrib/cpio/lib/argp-parse.c @@ -0,0 +1,926 @@ +/* Hierarchial argument parsing, layered over getopt + Copyright (C) 1995-2000, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <alloca.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <getopt.h> +#include <getopt_int.h> + +#ifdef _LIBC +# include <libintl.h> +# undef dgettext +# define dgettext(domain, msgid) \ + INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES) +#else +# include "gettext.h" +#endif +#define N_(msgid) (msgid) + +#include "argp.h" +#include "argp-namefrob.h" + +/* Getopt return values. */ +#define KEY_END (-1) /* The end of the options. */ +#define KEY_ARG 1 /* A non-option argument. */ +#define KEY_ERR '?' /* An error parsing the options. */ + +/* The meta-argument used to prevent any further arguments being interpreted + as options. */ +#define QUOTE "--" + +/* The number of bits we steal in a long-option value for our own use. */ +#define GROUP_BITS CHAR_BIT + +/* The number of bits available for the user value. */ +#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS) +#define USER_MASK ((1 << USER_BITS) - 1) + +/* EZ alias for ARGP_ERR_UNKNOWN. */ +#define EBADKEY ARGP_ERR_UNKNOWN + +/* Default options. */ + +/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep + for one second intervals, decrementing _ARGP_HANG until it's zero. Thus + you can force the program to continue by attaching a debugger and setting + it to 0 yourself. */ +static volatile int _argp_hang; + +#define OPT_PROGNAME -2 +#define OPT_USAGE -3 +#define OPT_HANG -4 + +static const struct argp_option argp_default_options[] = +{ + {"help", '?', 0, 0, N_("Give this help list"), -1}, + {"usage", OPT_USAGE, 0, 0, N_("Give a short usage message"), 0}, + {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, N_("Set the program name"), 0}, + {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, + N_("Hang for SECS seconds (default 3600)"), 0}, + {NULL, 0, 0, 0, NULL, 0} +}; + +static error_t +argp_default_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case '?': + __argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); + break; + case OPT_USAGE: + __argp_state_help (state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); + break; + + case OPT_PROGNAME: /* Set the program name. */ +#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_NAME + program_invocation_name = arg; +#endif + /* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka + __PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined + to be that, so we have to be a bit careful here.] */ + + /* Update what we use for messages. */ + state->name = strrchr (arg, '/'); + if (state->name) + state->name++; + else + state->name = arg; + +#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME + program_invocation_short_name = state->name; +#endif + + if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) + == ARGP_PARSE_ARGV0) + /* Update what getopt uses too. */ + state->argv[0] = arg; + + break; + + case OPT_HANG: + _argp_hang = atoi (arg ? arg : "3600"); + while (_argp_hang-- > 0) + __sleep (1); + break; + + default: + return EBADKEY; + } + return 0; +} + +static const struct argp argp_default_argp = + {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL, "libc"}; + + +static const struct argp_option argp_version_options[] = +{ + {"version", 'V', 0, 0, N_("Print program version"), -1}, + {NULL, 0, 0, 0, NULL, 0} +}; + +static error_t +argp_version_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'V': + if (argp_program_version_hook) + (*argp_program_version_hook) (state->out_stream, state); + else if (argp_program_version) + fprintf (state->out_stream, "%s\n", argp_program_version); + else + __argp_error (state, dgettext (state->root_argp->argp_domain, + "(PROGRAM ERROR) No version known!?")); + if (! (state->flags & ARGP_NO_EXIT)) + exit (0); + break; + default: + return EBADKEY; + } + return 0; +} + +static const struct argp argp_version_argp = + {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"}; + +/* Returns the offset into the getopt long options array LONG_OPTIONS of a + long option with called NAME, or -1 if none is found. Passing NULL as + NAME will return the number of options. */ +static int +find_long_option (struct option *long_options, const char *name) +{ + struct option *l = long_options; + while (l->name != NULL) + if (name != NULL && strcmp (l->name, name) == 0) + return l - long_options; + else + l++; + if (name == NULL) + return l - long_options; + else + return -1; +} + + +/* The state of a `group' during parsing. Each group corresponds to a + particular argp structure from the tree of such descending from the top + level argp passed to argp_parse. */ +struct group +{ + /* This group's parsing function. */ + argp_parser_t parser; + + /* Which argp this group is from. */ + const struct argp *argp; + + /* Points to the point in SHORT_OPTS corresponding to the end of the short + options for this group. We use it to determine from which group a + particular short options is from. */ + char *short_end; + + /* The number of non-option args sucessfully handled by this parser. */ + unsigned args_processed; + + /* This group's parser's parent's group. */ + struct group *parent; + unsigned parent_index; /* And the our position in the parent. */ + + /* These fields are swapped into and out of the state structure when + calling this group's parser. */ + void *input, **child_inputs; + void *hook; +}; + +/* Call GROUP's parser with KEY and ARG, swapping any group-specific info + from STATE before calling, and back into state afterwards. If GROUP has + no parser, EBADKEY is returned. */ +static error_t +group_parse (struct group *group, struct argp_state *state, int key, char *arg) +{ + if (group->parser) + { + error_t err; + state->hook = group->hook; + state->input = group->input; + state->child_inputs = group->child_inputs; + state->arg_num = group->args_processed; + err = (*group->parser)(key, arg, state); + group->hook = state->hook; + return err; + } + else + return EBADKEY; +} + +struct parser +{ + const struct argp *argp; + + /* SHORT_OPTS is the getopt short options string for the union of all the + groups of options. */ + char *short_opts; + /* LONG_OPTS is the array of getop long option structures for the union of + all the groups of options. */ + struct option *long_opts; + /* OPT_DATA is the getopt data used for the re-entrant getopt. */ + struct _getopt_data opt_data; + + /* States of the various parsing groups. */ + struct group *groups; + /* The end of the GROUPS array. */ + struct group *egroup; + /* An vector containing storage for the CHILD_INPUTS field in all groups. */ + void **child_inputs; + + /* True if we think using getopt is still useful; if false, then + remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is + cleared whenever getopt returns KEY_END, but may be set again if the user + moves the next argument pointer backwards. */ + int try_getopt; + + /* State block supplied to parsing routines. */ + struct argp_state state; + + /* Memory used by this parser. */ + void *storage; +}; + +/* The next usable entries in the various parser tables being filled in by + convert_options. */ +struct parser_convert_state +{ + struct parser *parser; + char *short_end; + struct option *long_end; + void **child_inputs_end; +}; + +/* Converts all options in ARGP (which is put in GROUP) and ancestors + into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and + CVT->LONG_END are the points at which new options are added. Returns the + next unused group entry. CVT holds state used during the conversion. */ +static struct group * +convert_options (const struct argp *argp, + struct group *parent, unsigned parent_index, + struct group *group, struct parser_convert_state *cvt) +{ + /* REAL is the most recent non-alias value of OPT. */ + const struct argp_option *real = argp->options; + const struct argp_child *children = argp->children; + + if (real || argp->parser) + { + const struct argp_option *opt; + + if (real) + for (opt = real; !__option_is_end (opt); opt++) + { + if (! (opt->flags & OPTION_ALIAS)) + /* OPT isn't an alias, so we can use values from it. */ + real = opt; + + if (! (real->flags & OPTION_DOC)) + /* A real option (not just documentation). */ + { + if (__option_is_short (opt)) + /* OPT can be used as a short option. */ + { + *cvt->short_end++ = opt->key; + if (real->arg) + { + *cvt->short_end++ = ':'; + if (real->flags & OPTION_ARG_OPTIONAL) + *cvt->short_end++ = ':'; + } + *cvt->short_end = '\0'; /* keep 0 terminated */ + } + + if (opt->name + && find_long_option (cvt->parser->long_opts, opt->name) < 0) + /* OPT can be used as a long option. */ + { + cvt->long_end->name = opt->name; + cvt->long_end->has_arg = + (real->arg + ? (real->flags & OPTION_ARG_OPTIONAL + ? optional_argument + : required_argument) + : no_argument); + cvt->long_end->flag = 0; + /* we add a disambiguating code to all the user's + values (which is removed before we actually call + the function to parse the value); this means that + the user loses use of the high 8 bits in all his + values (the sign of the lower bits is preserved + however)... */ + cvt->long_end->val = + ((opt->key | real->key) & USER_MASK) + + (((group - cvt->parser->groups) + 1) << USER_BITS); + + /* Keep the LONG_OPTS list terminated. */ + (++cvt->long_end)->name = NULL; + } + } + } + + group->parser = argp->parser; + group->argp = argp; + group->short_end = cvt->short_end; + group->args_processed = 0; + group->parent = parent; + group->parent_index = parent_index; + group->input = 0; + group->hook = 0; + group->child_inputs = 0; + + if (children) + /* Assign GROUP's CHILD_INPUTS field some space from + CVT->child_inputs_end.*/ + { + unsigned num_children = 0; + while (children[num_children].argp) + num_children++; + group->child_inputs = cvt->child_inputs_end; + cvt->child_inputs_end += num_children; + } + + parent = group++; + } + else + parent = 0; + + if (children) + { + unsigned index = 0; + while (children->argp) + group = + convert_options (children++->argp, parent, index++, group, cvt); + } + + return group; +} + +/* Find the merged set of getopt options, with keys appropiately prefixed. */ +static void +parser_convert (struct parser *parser, const struct argp *argp, int flags) +{ + struct parser_convert_state cvt; + + cvt.parser = parser; + cvt.short_end = parser->short_opts; + cvt.long_end = parser->long_opts; + cvt.child_inputs_end = parser->child_inputs; + + if (flags & ARGP_IN_ORDER) + *cvt.short_end++ = '-'; + else if (flags & ARGP_NO_ARGS) + *cvt.short_end++ = '+'; + *cvt.short_end = '\0'; + + cvt.long_end->name = NULL; + + parser->argp = argp; + + if (argp) + parser->egroup = convert_options (argp, 0, 0, parser->groups, &cvt); + else + parser->egroup = parser->groups; /* No parsers at all! */ +} + +/* Lengths of various parser fields which we will allocated. */ +struct parser_sizes +{ + size_t short_len; /* Getopt short options string. */ + size_t long_len; /* Getopt long options vector. */ + size_t num_groups; /* Group structures we allocate. */ + size_t num_child_inputs; /* Child input slots. */ +}; + +/* For ARGP, increments the NUM_GROUPS field in SZS by the total number of + argp structures descended from it, and the SHORT_LEN & LONG_LEN fields by + the maximum lengths of the resulting merged getopt short options string and + long-options array, respectively. */ +static void +calc_sizes (const struct argp *argp, struct parser_sizes *szs) +{ + const struct argp_child *child = argp->children; + const struct argp_option *opt = argp->options; + + if (opt || argp->parser) + { + szs->num_groups++; + if (opt) + { + int num_opts = 0; + while (!__option_is_end (opt++)) + num_opts++; + szs->short_len += num_opts * 3; /* opt + up to 2 `:'s */ + szs->long_len += num_opts; + } + } + + if (child) + while (child->argp) + { + calc_sizes ((child++)->argp, szs); + szs->num_child_inputs++; + } +} + +/* Initializes PARSER to parse ARGP in a manner described by FLAGS. */ +static error_t +parser_init (struct parser *parser, const struct argp *argp, + int argc, char **argv, int flags, void *input) +{ + error_t err = 0; + struct group *group; + struct parser_sizes szs; + struct _getopt_data opt_data = _GETOPT_DATA_INITIALIZER; + + szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1; + szs.long_len = 0; + szs.num_groups = 0; + szs.num_child_inputs = 0; + + if (argp) + calc_sizes (argp, &szs); + + /* Lengths of the various bits of storage used by PARSER. */ +#define GLEN (szs.num_groups + 1) * sizeof (struct group) +#define CLEN (szs.num_child_inputs * sizeof (void *)) +#define LLEN ((szs.long_len + 1) * sizeof (struct option)) +#define SLEN (szs.short_len + 1) + + parser->storage = malloc (GLEN + CLEN + LLEN + SLEN); + if (! parser->storage) + return ENOMEM; + + parser->groups = parser->storage; + parser->child_inputs = parser->storage + GLEN; + parser->long_opts = parser->storage + GLEN + CLEN; + parser->short_opts = parser->storage + GLEN + CLEN + LLEN; + parser->opt_data = opt_data; + + memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *)); + parser_convert (parser, argp, flags); + + memset (&parser->state, 0, sizeof (struct argp_state)); + parser->state.root_argp = parser->argp; + parser->state.argc = argc; + parser->state.argv = argv; + parser->state.flags = flags; + parser->state.err_stream = stderr; + parser->state.out_stream = stdout; + parser->state.next = 0; /* Tell getopt to initialize. */ + parser->state.pstate = parser; + + parser->try_getopt = 1; + + /* Call each parser for the first time, giving it a chance to propagate + values to child parsers. */ + if (parser->groups < parser->egroup) + parser->groups->input = input; + for (group = parser->groups; + group < parser->egroup && (!err || err == EBADKEY); + group++) + { + if (group->parent) + /* If a child parser, get the initial input value from the parent. */ + group->input = group->parent->child_inputs[group->parent_index]; + + if (!group->parser + && group->argp->children && group->argp->children->argp) + /* For the special case where no parsing function is supplied for an + argp, propagate its input to its first child, if any (this just + makes very simple wrapper argps more convenient). */ + group->child_inputs[0] = group->input; + + err = group_parse (group, &parser->state, ARGP_KEY_INIT, 0); + } + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + + if (err) + return err; + + if (parser->state.flags & ARGP_NO_ERRS) + { + parser->opt_data.opterr = 0; + if (parser->state.flags & ARGP_PARSE_ARGV0) + /* getopt always skips ARGV[0], so we have to fake it out. As long + as OPTERR is 0, then it shouldn't actually try to access it. */ + parser->state.argv--, parser->state.argc++; + } + else + parser->opt_data.opterr = 1; /* Print error messages. */ + + if (parser->state.argv == argv && argv[0]) + /* There's an argv[0]; use it for messages. */ + { + char *short_name = strrchr (argv[0], '/'); + parser->state.name = short_name ? short_name + 1 : argv[0]; + } + else + parser->state.name = __argp_short_program_name (); + + return 0; +} + +/* Free any storage consumed by PARSER (but not PARSER itself). */ +static error_t +parser_finalize (struct parser *parser, + error_t err, int arg_ebadkey, int *end_index) +{ + struct group *group; + + if (err == EBADKEY && arg_ebadkey) + /* Suppress errors generated by unparsed arguments. */ + err = 0; + + if (! err) + { + if (parser->state.next == parser->state.argc) + /* We successfully parsed all arguments! Call all the parsers again, + just a few more times... */ + { + for (group = parser->groups; + group < parser->egroup && (!err || err==EBADKEY); + group++) + if (group->args_processed == 0) + err = group_parse (group, &parser->state, ARGP_KEY_NO_ARGS, 0); + for (group = parser->egroup - 1; + group >= parser->groups && (!err || err==EBADKEY); + group--) + err = group_parse (group, &parser->state, ARGP_KEY_END, 0); + + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + + /* Tell the user that all arguments are parsed. */ + if (end_index) + *end_index = parser->state.next; + } + else if (end_index) + /* Return any remaining arguments to the user. */ + *end_index = parser->state.next; + else + /* No way to return the remaining arguments, they must be bogus. */ + { + if (!(parser->state.flags & ARGP_NO_ERRS) + && parser->state.err_stream) + fprintf (parser->state.err_stream, + dgettext (parser->argp->argp_domain, + "%s: Too many arguments\n"), + parser->state.name); + err = EBADKEY; + } + } + + /* Okay, we're all done, with either an error or success; call the parsers + to indicate which one. */ + + if (err) + { + /* Maybe print an error message. */ + if (err == EBADKEY) + /* An appropriate message describing what the error was should have + been printed earlier. */ + __argp_state_help (&parser->state, parser->state.err_stream, + ARGP_HELP_STD_ERR); + + /* Since we didn't exit, give each parser an error indication. */ + for (group = parser->groups; group < parser->egroup; group++) + group_parse (group, &parser->state, ARGP_KEY_ERROR, 0); + } + else + /* Notify parsers of success, and propagate back values from parsers. */ + { + /* We pass over the groups in reverse order so that child groups are + given a chance to do there processing before passing back a value to + the parent. */ + for (group = parser->egroup - 1 + ; group >= parser->groups && (!err || err == EBADKEY) + ; group--) + err = group_parse (group, &parser->state, ARGP_KEY_SUCCESS, 0); + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + } + + /* Call parsers once more, to do any final cleanup. Errors are ignored. */ + for (group = parser->egroup - 1; group >= parser->groups; group--) + group_parse (group, &parser->state, ARGP_KEY_FINI, 0); + + if (err == EBADKEY) + err = EINVAL; + + free (parser->storage); + + return err; +} + +/* Call the user parsers to parse the non-option argument VAL, at the current + position, returning any error. The state NEXT pointer is assumed to have + been adjusted (by getopt) to point after this argument; this function will + adjust it correctly to reflect however many args actually end up being + consumed. */ +static error_t +parser_parse_arg (struct parser *parser, char *val) +{ + /* Save the starting value of NEXT, first adjusting it so that the arg + we're parsing is again the front of the arg vector. */ + int index = --parser->state.next; + error_t err = EBADKEY; + struct group *group; + int key = 0; /* Which of ARGP_KEY_ARG[S] we used. */ + + /* Try to parse the argument in each parser. */ + for (group = parser->groups + ; group < parser->egroup && err == EBADKEY + ; group++) + { + parser->state.next++; /* For ARGP_KEY_ARG, consume the arg. */ + key = ARGP_KEY_ARG; + err = group_parse (group, &parser->state, key, val); + + if (err == EBADKEY) + /* This parser doesn't like ARGP_KEY_ARG; try ARGP_KEY_ARGS instead. */ + { + parser->state.next--; /* For ARGP_KEY_ARGS, put back the arg. */ + key = ARGP_KEY_ARGS; + err = group_parse (group, &parser->state, key, 0); + } + } + + if (! err) + { + if (key == ARGP_KEY_ARGS) + /* The default for ARGP_KEY_ARGS is to assume that if NEXT isn't + changed by the user, *all* arguments should be considered + consumed. */ + parser->state.next = parser->state.argc; + + if (parser->state.next > index) + /* Remember that we successfully processed a non-option + argument -- but only if the user hasn't gotten tricky and set + the clock back. */ + (--group)->args_processed += (parser->state.next - index); + else + /* The user wants to reparse some args, give getopt another try. */ + parser->try_getopt = 1; + } + + return err; +} + +/* Call the user parsers to parse the option OPT, with argument VAL, at the + current position, returning any error. */ +static error_t +parser_parse_opt (struct parser *parser, int opt, char *val) +{ + /* The group key encoded in the high bits; 0 for short opts or + group_number + 1 for long opts. */ + int group_key = opt >> USER_BITS; + error_t err = EBADKEY; + + if (group_key == 0) + /* A short option. By comparing OPT's position in SHORT_OPTS to the + various starting positions in each group's SHORT_END field, we can + determine which group OPT came from. */ + { + struct group *group; + char *short_index = strchr (parser->short_opts, opt); + + if (short_index) + for (group = parser->groups; group < parser->egroup; group++) + if (group->short_end > short_index) + { + err = group_parse (group, &parser->state, opt, + parser->opt_data.optarg); + break; + } + } + else + /* A long option. We use shifts instead of masking for extracting + the user value in order to preserve the sign. */ + err = + group_parse (&parser->groups[group_key - 1], &parser->state, + (opt << GROUP_BITS) >> GROUP_BITS, + parser->opt_data.optarg); + + if (err == EBADKEY) + /* At least currently, an option not recognized is an error in the + parser, because we pre-compute which parser is supposed to deal + with each option. */ + { + static const char bad_key_err[] = + N_("(PROGRAM ERROR) Option should have been recognized!?"); + if (group_key == 0) + __argp_error (&parser->state, "-%c: %s", opt, + dgettext (parser->argp->argp_domain, bad_key_err)); + else + { + struct option *long_opt = parser->long_opts; + while (long_opt->val != opt && long_opt->name) + long_opt++; + __argp_error (&parser->state, "--%s: %s", + long_opt->name ? long_opt->name : "???", + dgettext (parser->argp->argp_domain, bad_key_err)); + } + } + + return err; +} + +/* Parse the next argument in PARSER (as indicated by PARSER->state.next). + Any error from the parsers is returned, and *ARGP_EBADKEY indicates + whether a value of EBADKEY is due to an unrecognized argument (which is + generally not fatal). */ +static error_t +parser_parse_next (struct parser *parser, int *arg_ebadkey) +{ + int opt; + error_t err = 0; + + if (parser->state.quoted && parser->state.next < parser->state.quoted) + /* The next argument pointer has been moved to before the quoted + region, so pretend we never saw the quoting `--', and give getopt + another chance. If the user hasn't removed it, getopt will just + process it again. */ + parser->state.quoted = 0; + + if (parser->try_getopt && !parser->state.quoted) + /* Give getopt a chance to parse this. */ + { + /* Put it back in OPTIND for getopt. */ + parser->opt_data.optind = parser->state.next; + /* Distinguish KEY_ERR from a real option. */ + parser->opt_data.optopt = KEY_END; + if (parser->state.flags & ARGP_LONG_ONLY) + opt = _getopt_long_only_r (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0, + &parser->opt_data); + else + opt = _getopt_long_r (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0, + &parser->opt_data); + /* And see what getopt did. */ + parser->state.next = parser->opt_data.optind; + + if (opt == KEY_END) + /* Getopt says there are no more options, so stop using + getopt; we'll continue if necessary on our own. */ + { + parser->try_getopt = 0; + if (parser->state.next > 1 + && strcmp (parser->state.argv[parser->state.next - 1], QUOTE) + == 0) + /* Not only is this the end of the options, but it's a + `quoted' region, which may have args that *look* like + options, so we definitely shouldn't try to use getopt past + here, whatever happens. */ + parser->state.quoted = parser->state.next; + } + else if (opt == KEY_ERR && parser->opt_data.optopt != KEY_END) + /* KEY_ERR can have the same value as a valid user short + option, but in the case of a real error, getopt sets OPTOPT + to the offending character, which can never be KEY_END. */ + { + *arg_ebadkey = 0; + return EBADKEY; + } + } + else + opt = KEY_END; + + if (opt == KEY_END) + { + /* We're past what getopt considers the options. */ + if (parser->state.next >= parser->state.argc + || (parser->state.flags & ARGP_NO_ARGS)) + /* Indicate that we're done. */ + { + *arg_ebadkey = 1; + return EBADKEY; + } + else + /* A non-option arg; simulate what getopt might have done. */ + { + opt = KEY_ARG; + parser->opt_data.optarg = parser->state.argv[parser->state.next++]; + } + } + + if (opt == KEY_ARG) + /* A non-option argument; try each parser in turn. */ + err = parser_parse_arg (parser, parser->opt_data.optarg); + else + err = parser_parse_opt (parser, opt, parser->opt_data.optarg); + + if (err == EBADKEY) + *arg_ebadkey = (opt == KEY_END || opt == KEY_ARG); + + return err; +} + +/* Parse the options strings in ARGC & ARGV according to the argp in ARGP. + FLAGS is one of the ARGP_ flags above. If END_INDEX is non-NULL, the + index in ARGV of the first unparsed option is returned in it. If an + unknown option is present, EINVAL is returned; if some parser routine + returned a non-zero value, it is returned; otherwise 0 is returned. */ +error_t +__argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, + int *end_index, void *input) +{ + error_t err; + struct parser parser; + + /* If true, then err == EBADKEY is a result of a non-option argument failing + to be parsed (which in some cases isn't actually an error). */ + int arg_ebadkey = 0; + + if (! (flags & ARGP_NO_HELP)) + /* Add our own options. */ + { + struct argp_child *child = alloca (4 * sizeof (struct argp_child)); + struct argp *top_argp = alloca (sizeof (struct argp)); + + /* TOP_ARGP has no options, it just serves to group the user & default + argps. */ + memset (top_argp, 0, sizeof (*top_argp)); + top_argp->children = child; + + memset (child, 0, 4 * sizeof (struct argp_child)); + + if (argp) + (child++)->argp = argp; + (child++)->argp = &argp_default_argp; + if (argp_program_version || argp_program_version_hook) + (child++)->argp = &argp_version_argp; + child->argp = 0; + + argp = top_argp; + } + + /* Construct a parser for these arguments. */ + err = parser_init (&parser, argp, argc, argv, flags, input); + + if (! err) + /* Parse! */ + { + while (! err) + err = parser_parse_next (&parser, &arg_ebadkey); + err = parser_finalize (&parser, err, arg_ebadkey, end_index); + } + + return err; +} +#ifdef weak_alias +weak_alias (__argp_parse, argp_parse) +#endif + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +void * +__argp_input (const struct argp *argp, const struct argp_state *state) +{ + if (state) + { + struct group *group; + struct parser *parser = state->pstate; + + for (group = parser->groups; group < parser->egroup; group++) + if (group->argp == argp) + return group->input; + } + + return 0; +} +#ifdef weak_alias +weak_alias (__argp_input, _argp_input) +#endif diff --git a/contrib/cpio/lib/argp-pv.c b/contrib/cpio/lib/argp-pv.c new file mode 100644 index 0000000..f93a22e --- /dev/null +++ b/contrib/cpio/lib/argp-pv.c @@ -0,0 +1,24 @@ +/* Default definition for ARGP_PROGRAM_VERSION. + Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* If set by the user program to a non-zero value, then a default option + --version is added (unless the ARGP_NO_HELP flag is used), which will + print this this string followed by a newline and exit (unless the + ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ +const char *argp_program_version; diff --git a/contrib/cpio/lib/argp-pvh.c b/contrib/cpio/lib/argp-pvh.c new file mode 100644 index 0000000..5474251 --- /dev/null +++ b/contrib/cpio/lib/argp-pvh.c @@ -0,0 +1,31 @@ +/* Default definition for ARGP_PROGRAM_VERSION_HOOK. + Copyright (C) 1996, 1997, 1999, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "argp.h" + +/* If set by the user program to a non-zero value, then a default option + --version is added (unless the ARGP_NO_HELP flag is used), which calls + this function with a stream to print the version to and a pointer to the + current parsing state, and then exits (unless the ARGP_NO_EXIT flag is + used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ +void (*argp_program_version_hook) (FILE *stream, struct argp_state *state) = NULL; diff --git a/contrib/cpio/lib/argp-xinl.c b/contrib/cpio/lib/argp-xinl.c new file mode 100644 index 0000000..51d3e20 --- /dev/null +++ b/contrib/cpio/lib/argp-xinl.c @@ -0,0 +1,43 @@ +/* Real definitions for extern inline functions in argp.h + Copyright (C) 1997, 1998, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined _LIBC || defined HAVE_FEATURES_H +# include <features.h> +#endif + +#ifndef __USE_EXTERN_INLINES +# define __USE_EXTERN_INLINES 1 +#endif +#define ARGP_EI +#undef __OPTIMIZE__ +#define __OPTIMIZE__ 1 +#include "argp.h" + +/* Add weak aliases. */ +#if _LIBC - 0 && defined (weak_alias) + +weak_alias (__argp_usage, argp_usage) +weak_alias (__option_is_short, _option_is_short) +weak_alias (__option_is_end, _option_is_end) + +#endif diff --git a/contrib/cpio/lib/argp.h b/contrib/cpio/lib/argp.h new file mode 100644 index 0000000..0c65a4c --- /dev/null +++ b/contrib/cpio/lib/argp.h @@ -0,0 +1,604 @@ +/* Hierarchial argument parsing, layered over getopt. + Copyright (C) 1995-1999,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.ai.mit.edu>. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ARGP_H +#define _ARGP_H + +#include <stdio.h> +#include <ctype.h> +#include <getopt.h> + +#define __need_error_t +#include <errno.h> + +#ifndef __const +# define __const const +#endif + +#ifndef __THROW +# define __THROW +#endif +#ifndef __NTH +# define __NTH(fct) fct __THROW +#endif + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || __STRICT_ANSI__ +# define __format__ format +# define __printf__ printf +# endif +#endif + +/* GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". */ +#ifndef __restrict +# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) +# if defined restrict || 199901L <= __STDC_VERSION__ +# define __restrict restrict +# else +# define __restrict +# endif +# endif +#endif + +#ifndef __error_t_defined +typedef int error_t; +# define __error_t_defined +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* A description of a particular option. A pointer to an array of + these is passed in the OPTIONS field of an argp structure. Each option + entry can correspond to one long option and/or one short option; more + names for the same option can be added by following an entry in an option + array with options having the OPTION_ALIAS flag set. */ +struct argp_option +{ + /* The long option name. For more than one name for the same option, you + can use following options with the OPTION_ALIAS flag set. */ + __const char *name; + + /* What key is returned for this option. If > 0 and printable, then it's + also accepted as a short option. */ + int key; + + /* If non-NULL, this is the name of the argument associated with this + option, which is required unless the OPTION_ARG_OPTIONAL flag is set. */ + __const char *arg; + + /* OPTION_ flags. */ + int flags; + + /* The doc string for this option. If both NAME and KEY are 0, This string + will be printed outdented from the normal option column, making it + useful as a group header (it will be the first thing printed in its + group); in this usage, it's conventional to end the string with a `:'. */ + __const char *doc; + + /* The group this option is in. In a long help message, options are sorted + alphabetically within each group, and the groups presented in the order + 0, 1, 2, ..., n, -m, ..., -2, -1. Every entry in an options array with + if this field 0 will inherit the group number of the previous entry, or + zero if it's the first one, unless its a group header (NAME and KEY both + 0), in which case, the previous entry + 1 is the default. Automagic + options such as --help are put into group -1. */ + int group; +}; + +/* The argument associated with this option is optional. */ +#define OPTION_ARG_OPTIONAL 0x1 + +/* This option isn't displayed in any help messages. */ +#define OPTION_HIDDEN 0x2 + +/* This option is an alias for the closest previous non-alias option. This + means that it will be displayed in the same help entry, and will inherit + fields other than NAME and KEY from the aliased option. */ +#define OPTION_ALIAS 0x4 + +/* This option isn't actually an option (and so should be ignored by the + actual option parser), but rather an arbitrary piece of documentation that + should be displayed in much the same manner as the options. If this flag + is set, then the option NAME field is displayed unmodified (e.g., no `--' + prefix is added) at the left-margin (where a *short* option would normally + be displayed), and the documentation string in the normal place. The NAME + field will be translated using gettext, unless OPTION_NO_TRANS is set (see + below). For purposes of sorting, any leading whitespace and punctuation is + ignored, except that if the first non-whitespace character is not `-', this + entry is displayed after all options (and OPTION_DOC entries with a leading + `-') in the same group. */ +#define OPTION_DOC 0x8 + +/* This option shouldn't be included in `long' usage messages (but is still + included in help messages). This is mainly intended for options that are + completely documented in an argp's ARGS_DOC field, in which case including + the option in the generic usage list would be redundant. For instance, + if ARGS_DOC is "FOO BAR\n-x BLAH", and the `-x' option's purpose is to + distinguish these two cases, -x should probably be marked + OPTION_NO_USAGE. */ +#define OPTION_NO_USAGE 0x10 + +/* Valid only in conjunction with OPTION_DOC. This option disables translation + of option name. */ +#define OPTION_NO_TRANS 0x20 + + +struct argp; /* fwd declare this type */ +struct argp_state; /* " */ +struct argp_child; /* " */ + +/* The type of a pointer to an argp parsing function. */ +typedef error_t (*argp_parser_t) (int key, char *arg, + struct argp_state *state); + +/* What to return for unrecognized keys. For special ARGP_KEY_ keys, such + returns will simply be ignored. For user keys, this error will be turned + into EINVAL (if the call to argp_parse is such that errors are propagated + back to the user instead of exiting); returning EINVAL itself would result + in an immediate stop to parsing in *all* cases. */ +#define ARGP_ERR_UNKNOWN E2BIG /* Hurd should never need E2BIG. XXX */ + +/* Special values for the KEY argument to an argument parsing function. + ARGP_ERR_UNKNOWN should be returned if they aren't understood. + + The sequence of keys to a parsing function is either (where each + uppercased word should be prefixed by `ARGP_KEY_' and opt is a user key): + + INIT opt... NO_ARGS END SUCCESS -- No non-option arguments at all + or INIT (opt | ARG)... END SUCCESS -- All non-option args parsed + or INIT (opt | ARG)... SUCCESS -- Some non-option arg unrecognized + + The third case is where every parser returned ARGP_KEY_UNKNOWN for an + argument, in which case parsing stops at that argument (returning the + unparsed arguments to the caller of argp_parse if requested, or stopping + with an error message if not). + + If an error occurs (either detected by argp, or because the parsing + function returned an error value), then the parser is called with + ARGP_KEY_ERROR, and no further calls are made. */ + +/* This is not an option at all, but rather a command line argument. If a + parser receiving this key returns success, the fact is recorded, and the + ARGP_KEY_NO_ARGS case won't be used. HOWEVER, if while processing the + argument, a parser function decrements the NEXT field of the state it's + passed, the option won't be considered processed; this is to allow you to + actually modify the argument (perhaps into an option), and have it + processed again. */ +#define ARGP_KEY_ARG 0 +/* There are remaining arguments not parsed by any parser, which may be found + starting at (STATE->argv + STATE->next). If success is returned, but + STATE->next left untouched, it's assumed that all arguments were consume, + otherwise, the parser should adjust STATE->next to reflect any arguments + consumed. */ +#define ARGP_KEY_ARGS 0x1000006 +/* There are no more command line arguments at all. */ +#define ARGP_KEY_END 0x1000001 +/* Because it's common to want to do some special processing if there aren't + any non-option args, user parsers are called with this key if they didn't + successfully process any non-option arguments. Called just before + ARGP_KEY_END (where more general validity checks on previously parsed + arguments can take place). */ +#define ARGP_KEY_NO_ARGS 0x1000002 +/* Passed in before any parsing is done. Afterwards, the values of each + element of the CHILD_INPUT field, if any, in the state structure is + copied to each child's state to be the initial value of the INPUT field. */ +#define ARGP_KEY_INIT 0x1000003 +/* Use after all other keys, including SUCCESS & END. */ +#define ARGP_KEY_FINI 0x1000007 +/* Passed in when parsing has successfully been completed (even if there are + still arguments remaining). */ +#define ARGP_KEY_SUCCESS 0x1000004 +/* Passed in if an error occurs. */ +#define ARGP_KEY_ERROR 0x1000005 + +/* An argp structure contains a set of options declarations, a function to + deal with parsing one, documentation string, a possible vector of child + argp's, and perhaps a function to filter help output. When actually + parsing options, getopt is called with the union of all the argp + structures chained together through their CHILD pointers, with conflicts + being resolved in favor of the first occurrence in the chain. */ +struct argp +{ + /* An array of argp_option structures, terminated by an entry with both + NAME and KEY having a value of 0. */ + __const struct argp_option *options; + + /* What to do with an option from this structure. KEY is the key + associated with the option, and ARG is any associated argument (NULL if + none was supplied). If KEY isn't understood, ARGP_ERR_UNKNOWN should be + returned. If a non-zero, non-ARGP_ERR_UNKNOWN value is returned, then + parsing is stopped immediately, and that value is returned from + argp_parse(). For special (non-user-supplied) values of KEY, see the + ARGP_KEY_ definitions below. */ + argp_parser_t parser; + + /* A string describing what other arguments are wanted by this program. It + is only used by argp_usage to print the `Usage:' message. If it + contains newlines, the strings separated by them are considered + alternative usage patterns, and printed on separate lines (lines after + the first are prefix by ` or: ' instead of `Usage:'). */ + __const char *args_doc; + + /* If non-NULL, a string containing extra text to be printed before and + after the options in a long help message (separated by a vertical tab + `\v' character). */ + __const char *doc; + + /* A vector of argp_children structures, terminated by a member with a 0 + argp field, pointing to child argps should be parsed with this one. Any + conflicts are resolved in favor of this argp, or early argps in the + CHILDREN list. This field is useful if you use libraries that supply + their own argp structure, which you want to use in conjunction with your + own. */ + __const struct argp_child *children; + + /* If non-zero, this should be a function to filter the output of help + messages. KEY is either a key from an option, in which case TEXT is + that option's help text, or a special key from the ARGP_KEY_HELP_ + defines, below, describing which other help text TEXT is. The function + should return either TEXT, if it should be used as-is, a replacement + string, which should be malloced, and will be freed by argp, or NULL, + meaning `print nothing'. The value for TEXT is *after* any translation + has been done, so if any of the replacement text also needs translation, + that should be done by the filter function. INPUT is either the input + supplied to argp_parse, or NULL, if argp_help was called directly. */ + char *(*help_filter) (int __key, __const char *__text, void *__input); + + /* If non-zero the strings used in the argp library are translated using + the domain described by this string. Otherwise the currently installed + default domain is used. */ + const char *argp_domain; +}; + +/* Possible KEY arguments to a help filter function. */ +#define ARGP_KEY_HELP_PRE_DOC 0x2000001 /* Help text preceeding options. */ +#define ARGP_KEY_HELP_POST_DOC 0x2000002 /* Help text following options. */ +#define ARGP_KEY_HELP_HEADER 0x2000003 /* Option header string. */ +#define ARGP_KEY_HELP_EXTRA 0x2000004 /* After all other documentation; + TEXT is NULL for this key. */ +/* Explanatory note emitted when duplicate option arguments have been + suppressed. */ +#define ARGP_KEY_HELP_DUP_ARGS_NOTE 0x2000005 +#define ARGP_KEY_HELP_ARGS_DOC 0x2000006 /* Argument doc string. */ + +/* When an argp has a non-zero CHILDREN field, it should point to a vector of + argp_child structures, each of which describes a subsidiary argp. */ +struct argp_child +{ + /* The child parser. */ + __const struct argp *argp; + + /* Flags for this child. */ + int flags; + + /* If non-zero, an optional header to be printed in help output before the + child options. As a side-effect, a non-zero value forces the child + options to be grouped together; to achieve this effect without actually + printing a header string, use a value of "". */ + __const char *header; + + /* Where to group the child options relative to the other (`consolidated') + options in the parent argp; the values are the same as the GROUP field + in argp_option structs, but all child-groupings follow parent options at + a particular group level. If both this field and HEADER are zero, then + they aren't grouped at all, but rather merged with the parent options + (merging the child's grouping levels with the parents). */ + int group; +}; + +/* Parsing state. This is provided to parsing functions called by argp, + which may examine and, as noted, modify fields. */ +struct argp_state +{ + /* The top level ARGP being parsed. */ + __const struct argp *root_argp; + + /* The argument vector being parsed. May be modified. */ + int argc; + char **argv; + + /* The index in ARGV of the next arg that to be parsed. May be modified. */ + int next; + + /* The flags supplied to argp_parse. May be modified. */ + unsigned flags; + + /* While calling a parsing function with a key of ARGP_KEY_ARG, this is the + number of the current arg, starting at zero, and incremented after each + such call returns. At all other times, this is the number of such + arguments that have been processed. */ + unsigned arg_num; + + /* If non-zero, the index in ARGV of the first argument following a special + `--' argument (which prevents anything following being interpreted as an + option). Only set once argument parsing has proceeded past this point. */ + int quoted; + + /* An arbitrary pointer passed in from the user. */ + void *input; + /* Values to pass to child parsers. This vector will be the same length as + the number of children for the current parser. */ + void **child_inputs; + + /* For the parser's use. Initialized to 0. */ + void *hook; + + /* The name used when printing messages. This is initialized to ARGV[0], + or PROGRAM_INVOCATION_NAME if that is unavailable. */ + char *name; + + /* Streams used when argp prints something. */ + FILE *err_stream; /* For errors; initialized to stderr. */ + FILE *out_stream; /* For information; initialized to stdout. */ + + void *pstate; /* Private, for use by argp. */ +}; + +/* Flags for argp_parse (note that the defaults are those that are + convenient for program command line parsing): */ + +/* Don't ignore the first element of ARGV. Normally (and always unless + ARGP_NO_ERRS is set) the first element of the argument vector is + skipped for option parsing purposes, as it corresponds to the program name + in a command line. */ +#define ARGP_PARSE_ARGV0 0x01 + +/* Don't print error messages for unknown options to stderr; unless this flag + is set, ARGP_PARSE_ARGV0 is ignored, as ARGV[0] is used as the program + name in the error messages. This flag implies ARGP_NO_EXIT (on the + assumption that silent exiting upon errors is bad behaviour). */ +#define ARGP_NO_ERRS 0x02 + +/* Don't parse any non-option args. Normally non-option args are parsed by + calling the parse functions with a key of ARGP_KEY_ARG, and the actual arg + as the value. Since it's impossible to know which parse function wants to + handle it, each one is called in turn, until one returns 0 or an error + other than ARGP_ERR_UNKNOWN; if an argument is handled by no one, the + argp_parse returns prematurely (but with a return value of 0). If all + args have been parsed without error, all parsing functions are called one + last time with a key of ARGP_KEY_END. This flag needn't normally be set, + as the normal behavior is to stop parsing as soon as some argument can't + be handled. */ +#define ARGP_NO_ARGS 0x04 + +/* Parse options and arguments in the same order they occur on the command + line -- normally they're rearranged so that all options come first. */ +#define ARGP_IN_ORDER 0x08 + +/* Don't provide the standard long option --help, which causes usage and + option help information to be output to stdout, and exit (0) called. */ +#define ARGP_NO_HELP 0x10 + +/* Don't exit on errors (they may still result in error messages). */ +#define ARGP_NO_EXIT 0x20 + +/* Use the gnu getopt `long-only' rules for parsing arguments. */ +#define ARGP_LONG_ONLY 0x40 + +/* Turns off any message-printing/exiting options. */ +#define ARGP_SILENT (ARGP_NO_EXIT | ARGP_NO_ERRS | ARGP_NO_HELP) + +/* Parse the options strings in ARGC & ARGV according to the options in ARGP. + FLAGS is one of the ARGP_ flags above. If ARG_INDEX is non-NULL, the + index in ARGV of the first unparsed option is returned in it. If an + unknown option is present, ARGP_ERR_UNKNOWN is returned; if some parser + routine returned a non-zero value, it is returned; otherwise 0 is + returned. This function may also call exit unless the ARGP_NO_HELP flag + is set. INPUT is a pointer to a value to be passed in to the parser. */ +extern error_t argp_parse (__const struct argp *__restrict __argp, + int __argc, char **__restrict __argv, + unsigned __flags, int *__restrict __arg_index, + void *__restrict __input); +extern error_t __argp_parse (__const struct argp *__restrict __argp, + int __argc, char **__restrict __argv, + unsigned __flags, int *__restrict __arg_index, + void *__restrict __input); + +/* Global variables. */ + +/* If defined or set by the user program to a non-zero value, then a default + option --version is added (unless the ARGP_NO_HELP flag is used), which + will print this string followed by a newline and exit (unless the + ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ +extern __const char *argp_program_version; + +/* If defined or set by the user program to a non-zero value, then a default + option --version is added (unless the ARGP_NO_HELP flag is used), which + calls this function with a stream to print the version to and a pointer to + the current parsing state, and then exits (unless the ARGP_NO_EXIT flag is + used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ +extern void (*argp_program_version_hook) (FILE *__restrict __stream, + struct argp_state *__restrict + __state); + +/* If defined or set by the user program, it should point to string that is + the bug-reporting address for the program. It will be printed by + argp_help if the ARGP_HELP_BUG_ADDR flag is set (as it is by various + standard help messages), embedded in a sentence that says something like + `Report bugs to ADDR.'. */ +extern __const char *argp_program_bug_address; + +/* The exit status that argp will use when exiting due to a parsing error. + If not defined or set by the user program, this defaults to EX_USAGE from + <sysexits.h>. */ +extern error_t argp_err_exit_status; + +/* Flags for argp_help. */ +#define ARGP_HELP_USAGE 0x01 /* a Usage: message. */ +#define ARGP_HELP_SHORT_USAGE 0x02 /* " but don't actually print options. */ +#define ARGP_HELP_SEE 0x04 /* a `Try ... for more help' message. */ +#define ARGP_HELP_LONG 0x08 /* a long help message. */ +#define ARGP_HELP_PRE_DOC 0x10 /* doc string preceding long help. */ +#define ARGP_HELP_POST_DOC 0x20 /* doc string following long help. */ +#define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC) +#define ARGP_HELP_BUG_ADDR 0x40 /* bug report address */ +#define ARGP_HELP_LONG_ONLY 0x80 /* modify output appropriately to + reflect ARGP_LONG_ONLY mode. */ + +/* These ARGP_HELP flags are only understood by argp_state_help. */ +#define ARGP_HELP_EXIT_ERR 0x100 /* Call exit(1) instead of returning. */ +#define ARGP_HELP_EXIT_OK 0x200 /* Call exit(0) instead of returning. */ + +/* The standard thing to do after a program command line parsing error, if an + error message has already been printed. */ +#define ARGP_HELP_STD_ERR \ + (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) +/* The standard thing to do after a program command line parsing error, if no + more specific error message has been printed. */ +#define ARGP_HELP_STD_USAGE \ + (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) +/* The standard thing to do in response to a --help option. */ +#define ARGP_HELP_STD_HELP \ + (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK \ + | ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR) + +/* Output a usage message for ARGP to STREAM. FLAGS are from the set + ARGP_HELP_*. */ +extern void argp_help (__const struct argp *__restrict __argp, + FILE *__restrict __stream, + unsigned __flags, char *__restrict __name); +extern void __argp_help (__const struct argp *__restrict __argp, + FILE *__restrict __stream, unsigned __flags, + char *__name); + +/* The following routines are intended to be called from within an argp + parsing routine (thus taking an argp_state structure as the first + argument). They may or may not print an error message and exit, depending + on the flags in STATE -- in any case, the caller should be prepared for + them *not* to exit, and should return an appropiate error after calling + them. [argp_usage & argp_error should probably be called argp_state_..., + but they're used often enough that they should be short] */ + +/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are + from the set ARGP_HELP_*. */ +extern void argp_state_help (__const struct argp_state *__restrict __state, + FILE *__restrict __stream, + unsigned int __flags); +extern void __argp_state_help (__const struct argp_state *__restrict __state, + FILE *__restrict __stream, + unsigned int __flags); + +/* Possibly output the standard usage message for ARGP to stderr and exit. */ +extern void argp_usage (__const struct argp_state *__state); +extern void __argp_usage (__const struct argp_state *__state); + +/* If appropriate, print the printf string FMT and following args, preceded + by the program name and `:', to stderr, and followed by a `Try ... --help' + message, then exit (1). */ +extern void argp_error (__const struct argp_state *__restrict __state, + __const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern void __argp_error (__const struct argp_state *__restrict __state, + __const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + +/* Similar to the standard gnu error-reporting function error(), but will + respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print + to STATE->err_stream. This is useful for argument parsing code that is + shared between program startup (when exiting is desired) and runtime + option parsing (when typically an error code is returned instead). The + difference between this function and argp_error is that the latter is for + *parsing errors*, and the former is for other problems that occur during + parsing but don't reflect a (syntactic) problem with the input. */ +extern void argp_failure (__const struct argp_state *__restrict __state, + int __status, int __errnum, + __const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +extern void __argp_failure (__const struct argp_state *__restrict __state, + int __status, int __errnum, + __const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); + +/* Returns true if the option OPT is a valid short option. */ +extern int _option_is_short (__const struct argp_option *__opt) __THROW; +extern int __option_is_short (__const struct argp_option *__opt) __THROW; + +/* Returns true if the option OPT is in fact the last (unused) entry in an + options array. */ +extern int _option_is_end (__const struct argp_option *__opt) __THROW; +extern int __option_is_end (__const struct argp_option *__opt) __THROW; + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +extern void *_argp_input (__const struct argp *__restrict __argp, + __const struct argp_state *__restrict __state) + __THROW; +extern void *__argp_input (__const struct argp *__restrict __argp, + __const struct argp_state *__restrict __state) + __THROW; + +#ifdef __USE_EXTERN_INLINES + +# if !_LIBC +# define __argp_usage argp_usage +# define __argp_state_help argp_state_help +# define __option_is_short _option_is_short +# define __option_is_end _option_is_end +# endif + +# ifndef ARGP_EI +# define ARGP_EI extern __inline__ +# endif + +ARGP_EI void +__NTH (__argp_usage (__const struct argp_state *__state)) +{ + __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE); +} + +ARGP_EI int +__NTH (__option_is_short (__const struct argp_option *__opt)) +{ + if (__opt->flags & OPTION_DOC) + return 0; + else + { + int __key = __opt->key; + return __key > 0 && isprint (__key); + } +} + +ARGP_EI int +__NTH (__option_is_end (__const struct argp_option *__opt)) +{ + return !__opt->key && !__opt->name && !__opt->doc && !__opt->group; +} + +# if !_LIBC +# undef __argp_usage +# undef __argp_state_help +# undef __option_is_short +# undef __option_is_end +# endif +#endif /* Use extern inlines. */ + +#ifdef __cplusplus +} +#endif + +#endif /* argp.h */ diff --git a/contrib/cpio/lib/basename.c b/contrib/cpio/lib/basename.c new file mode 100644 index 0000000..adb9f02 --- /dev/null +++ b/contrib/cpio/lib/basename.c @@ -0,0 +1,79 @@ +/* basename.c -- return the last element in a path + + Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "dirname.h" +#include <string.h> + +/* In general, we can't use the builtin `basename' function if available, + since it has different meanings in different environments. + In some environments the builtin `basename' modifies its argument. + + Return the address of the last file name component of NAME. If + NAME has no file name components because it is all slashes, return + NAME if it is empty, the address of its last slash otherwise. */ + +char * +base_name (char const *name) +{ + char const *base = name + FILE_SYSTEM_PREFIX_LEN (name); + char const *p; + + for (p = base; *p; p++) + { + if (ISSLASH (*p)) + { + /* Treat multiple adjacent slashes like a single slash. */ + do p++; + while (ISSLASH (*p)); + + /* If the file name ends in slash, use the trailing slash as + the basename if no non-slashes have been found. */ + if (! *p) + { + if (ISSLASH (*base)) + base = p - 1; + break; + } + + /* *P is a non-slash preceded by a slash. */ + base = p; + } + } + + return (char *) base; +} + +/* Return the length of of the basename NAME. Typically NAME is the + value returned by base_name. Act like strlen (NAME), except omit + redundant trailing slashes. */ + +size_t +base_len (char const *name) +{ + size_t len; + + for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) + continue; + + return len; +} diff --git a/contrib/cpio/lib/dirname.c b/contrib/cpio/lib/dirname.c new file mode 100644 index 0000000..7671a0d --- /dev/null +++ b/contrib/cpio/lib/dirname.c @@ -0,0 +1,121 @@ +/* dirname.c -- return all but the last element in a path + + Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "dirname.h" + +#include <string.h> +#include "xalloc.h" + +/* Return the length of `dirname (PATH)', or zero if PATH is + in the working directory. Works properly even if + there are trailing slashes (by effectively ignoring them). */ +size_t +dir_len (char const *path) +{ + size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (path); + size_t length; + + /* Strip the basename and any redundant slashes before it. */ + for (length = base_name (path) - path; prefix_length < length; length--) + if (! ISSLASH (path[length - 1])) + return length; + + /* But don't strip the only slash from "/". */ + return prefix_length + ISSLASH (path[prefix_length]); +} + +/* Return the leading directories part of PATH, + allocated with xmalloc. + Works properly even if there are trailing slashes + (by effectively ignoring them). */ + +char * +dir_name (char const *path) +{ + size_t length = dir_len (path); + bool append_dot = (length == FILE_SYSTEM_PREFIX_LEN (path)); + char *newpath = xmalloc (length + append_dot + 1); + memcpy (newpath, path, length); + if (append_dot) + newpath[length++] = '.'; + newpath[length] = 0; + return newpath; +} + +#ifdef TEST_DIRNAME +/* + +Run the test like this (expect no output): + gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall \ + basename.c dirname.c xmalloc.c error.c + sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out + +If it's been built on a DOS or Windows platforms, run another test like +this (again, expect no output): + sed -n '/^BEGIN-DOS-DATA$/,/^END-DOS-DATA$/p' dirname.c|grep -v DATA|./a.out + +BEGIN-DATA +foo//// . +bar/foo//// bar +foo/ . +/ / +. . +a . +END-DATA + +BEGIN-DOS-DATA +c:///// c:/ +c:/ c:/ +c:/. c:/ +c:foo c:. +c:foo/bar c:foo +END-DOS-DATA + +*/ + +# define MAX_BUFF_LEN 1024 +# include <stdio.h> + +char *program_name; + +int +main (int argc, char *argv[]) +{ + char buff[MAX_BUFF_LEN + 1]; + + program_name = argv[0]; + + buff[MAX_BUFF_LEN] = 0; + while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) + { + char path[MAX_BUFF_LEN]; + char expected_result[MAX_BUFF_LEN]; + char const *result; + sscanf (buff, "%s %s", path, expected_result); + result = dir_name (path); + if (strcmp (result, expected_result)) + printf ("%s: got %s, expected %s\n", path, result, expected_result); + } + return 0; +} +#endif diff --git a/contrib/cpio/lib/dirname.h b/contrib/cpio/lib/dirname.h new file mode 100644 index 0000000..bc2400a --- /dev/null +++ b/contrib/cpio/lib/dirname.h @@ -0,0 +1,47 @@ +/* Take file names apart into directory and base names. + + Copyright (C) 1998, 2001, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef DIRNAME_H_ +# define DIRNAME_H_ 1 + +# include <stdbool.h> +# include <stddef.h> + +# ifndef DIRECTORY_SEPARATOR +# define DIRECTORY_SEPARATOR '/' +# endif + +# ifndef ISSLASH +# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) +# endif + +# ifndef FILE_SYSTEM_PREFIX_LEN +# define FILE_SYSTEM_PREFIX_LEN(Filename) 0 +# endif + +# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)]) +# define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) + +char *base_name (char const *path); +char *dir_name (char const *path); +size_t base_len (char const *path); +size_t dir_len (char const *path); + +bool strip_trailing_slashes (char *path); + +#endif /* not DIRNAME_H_ */ diff --git a/contrib/cpio/lib/error.c b/contrib/cpio/lib/error.c new file mode 100644 index 0000000..9bb3e55 --- /dev/null +++ b/contrib/cpio/lib/error.c @@ -0,0 +1,306 @@ +/* Error handler for noninteractive utilities + Copyright (C) 1990-1998, 2000-2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "error.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _LIBC +# include <libintl.h> +#else +# include "gettext.h" +#endif + +#ifdef _LIBC +# include <wchar.h> +# define mbsrtowcs __mbsrtowcs +#endif + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifndef _ +# define _(String) String +#endif + +/* If NULL, error will flush stdout, then print on stderr the program + name, a colon and a space. Otherwise, error will call this + function without parameters instead. */ +void (*error_print_progname) (void); + +/* This variable is incremented each time `error' is called. */ +unsigned int error_message_count; + +#ifdef _LIBC +/* In the GNU C library, there is a predefined variable for this. */ + +# define program_name program_invocation_name +# include <errno.h> +# include <libio/libioP.h> + +/* In GNU libc we want do not want to use the common name `error' directly. + Instead make it a weak alias. */ +extern void __error (int status, int errnum, const char *message, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +extern void __error_at_line (int status, int errnum, const char *file_name, + unsigned int line_number, const char *message, + ...) + __attribute__ ((__format__ (__printf__, 5, 6)));; +# define error __error +# define error_at_line __error_at_line + +# include <libio/iolibio.h> +# define fflush(s) INTUSE(_IO_fflush) (s) +# undef putc +# define putc(c, fp) INTUSE(_IO_putc) (c, fp) + +# include <bits/libc-lock.h> + +#else /* not _LIBC */ + +# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P +# ifndef HAVE_DECL_STRERROR_R +"this configure-time declaration test was not run" +# endif +char *strerror_r (); +# endif + +# ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +# endif + +/* The calling program should define program_name and set it to the + name of the executing program. */ +extern char *program_name; + +# if HAVE_STRERROR_R || defined strerror_r +# define __strerror_r strerror_r +# endif +#endif /* not _LIBC */ + +static void +print_errno_message (int errnum) +{ + char const *s = NULL; + +#if defined HAVE_STRERROR_R || _LIBC + char errbuf[1024]; +# if STRERROR_R_CHAR_P || _LIBC + s = __strerror_r (errnum, errbuf, sizeof errbuf); +# else + if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0) + s = errbuf; +# endif +#endif + +#if !_LIBC + if (! s && ! (s = strerror (errnum))) + s = _("Unknown system error"); +#endif + +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + { + __fwprintf (stderr, L": %s", s); + return; + } +#endif + + fprintf (stderr, ": %s", s); +} + +static void +error_tail (int status, int errnum, const char *message, va_list args) +{ +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + { +# define ALLOCA_LIMIT 2000 + size_t len = strlen (message) + 1; + const wchar_t *wmessage = L"out of memory"; + wchar_t *wbuf = (len < ALLOCA_LIMIT + ? alloca (len * sizeof *wbuf) + : len <= SIZE_MAX / sizeof *wbuf + ? malloc (len * sizeof *wbuf) + : NULL); + + if (wbuf) + { + size_t res; + mbstate_t st; + const char *tmp = message; + memset (&st, '\0', sizeof (st)); + res = mbsrtowcs (wbuf, &tmp, len, &st); + wmessage = res == (size_t) -1 ? L"???" : wbuf; + } + + __vfwprintf (stderr, wmessage, args); + if (! (len < ALLOCA_LIMIT)) + free (wbuf); + } + else +#endif + vfprintf (stderr, message, args); + va_end (args); + + ++error_message_count; + if (errnum) + print_errno_message (errnum); +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + putwc (L'\n', stderr); + else +#endif + putc ('\n', stderr); + fflush (stderr); + if (status) + exit (status); +} + + +/* Print the program name and error message MESSAGE, which is a printf-style + format string with optional args. + If ERRNUM is nonzero, print its corresponding system error message. + Exit with status STATUS if it is nonzero. */ +void +error (int status, int errnum, const char *message, ...) +{ + va_list args; + +#if defined _LIBC && defined __libc_ptf_call + /* We do not want this call to be cut short by a thread + cancellation. Therefore disable cancellation for now. */ + int state = PTHREAD_CANCEL_ENABLE; + __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), + 0); +#endif + + fflush (stdout); +#ifdef _LIBC + _IO_flockfile (stderr); +#endif + if (error_print_progname) + (*error_print_progname) (); + else + { +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s: ", program_name); + else +#endif + fprintf (stderr, "%s: ", program_name); + } + + va_start (args, message); + error_tail (status, errnum, message, args); + +#ifdef _LIBC + _IO_funlockfile (stderr); +# ifdef __libc_ptf_call + __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); +# endif +#endif +} + +/* Sometimes we want to have at most one error per line. This + variable controls whether this mode is selected or not. */ +int error_one_per_line; + +void +error_at_line (int status, int errnum, const char *file_name, + unsigned int line_number, const char *message, ...) +{ + va_list args; + + if (error_one_per_line) + { + static const char *old_file_name; + static unsigned int old_line_number; + + if (old_line_number == line_number + && (file_name == old_file_name + || strcmp (old_file_name, file_name) == 0)) + /* Simply return and print nothing. */ + return; + + old_file_name = file_name; + old_line_number = line_number; + } + +#if defined _LIBC && defined __libc_ptf_call + /* We do not want this call to be cut short by a thread + cancellation. Therefore disable cancellation for now. */ + int state = PTHREAD_CANCEL_ENABLE; + __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), + 0); +#endif + + fflush (stdout); +#ifdef _LIBC + _IO_flockfile (stderr); +#endif + if (error_print_progname) + (*error_print_progname) (); + else + { +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s: ", program_name); + else +#endif + fprintf (stderr, "%s:", program_name); + } + + if (file_name != NULL) + { +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s:%d: ", file_name, line_number); + else +#endif + fprintf (stderr, "%s:%d: ", file_name, line_number); + } + + va_start (args, message); + error_tail (status, errnum, message, args); + +#ifdef _LIBC + _IO_funlockfile (stderr); +# ifdef __libc_ptf_call + __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); +# endif +#endif +} + +#ifdef _LIBC +/* Make the weak alias. */ +# undef error +# undef error_at_line +weak_alias (__error, error) +weak_alias (__error_at_line, error_at_line) +#endif diff --git a/contrib/cpio/lib/error.h b/contrib/cpio/lib/error.h new file mode 100644 index 0000000..8ed6359 --- /dev/null +++ b/contrib/cpio/lib/error.h @@ -0,0 +1,66 @@ +/* Declaration for error-reporting function + Copyright (C) 1995, 1996, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ERROR_H +#define _ERROR_H 1 + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Print a message with `fprintf (stderr, FORMAT, ...)'; + if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). + If STATUS is nonzero, terminate the program with `exit (STATUS)'. */ + +extern void error (int __status, int __errnum, const char *__format, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + +extern void error_at_line (int __status, int __errnum, const char *__fname, + unsigned int __lineno, const char *__format, ...) + __attribute__ ((__format__ (__printf__, 5, 6))); + +/* If NULL, error will flush stdout, then print on stderr the program + name, a colon and a space. Otherwise, error will call this + function without parameters instead. */ +extern void (*error_print_progname) (void); + +/* This variable is incremented each time `error' is called. */ +extern unsigned int error_message_count; + +/* Sometimes we want to have at most one error per line. This + variable controls whether this mode is selected or not. */ +extern int error_one_per_line; + +#ifdef __cplusplus +} +#endif + +#endif /* error.h */ diff --git a/contrib/cpio/lib/exit.h b/contrib/cpio/lib/exit.h new file mode 100644 index 0000000..4e8d465 --- /dev/null +++ b/contrib/cpio/lib/exit.h @@ -0,0 +1,32 @@ +/* exit() function. + Copyright (C) 1995, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _EXIT_H +#define _EXIT_H + +/* Get exit() declaration. */ +#include <stdlib.h> + +/* Some systems do not define EXIT_*, even with STDC_HEADERS. */ +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif +#ifndef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif + +#endif /* _EXIT_H */ diff --git a/contrib/cpio/lib/exitfail.c b/contrib/cpio/lib/exitfail.c new file mode 100644 index 0000000..2ae5f69 --- /dev/null +++ b/contrib/cpio/lib/exitfail.c @@ -0,0 +1,27 @@ +/* Failure exit status + + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "exitfail.h" +#include "exit.h" + +int volatile exit_failure = EXIT_FAILURE; diff --git a/contrib/cpio/lib/exitfail.h b/contrib/cpio/lib/exitfail.h new file mode 100644 index 0000000..cf5ab71 --- /dev/null +++ b/contrib/cpio/lib/exitfail.h @@ -0,0 +1,20 @@ +/* Failure exit status + + Copyright (C) 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +extern int volatile exit_failure; diff --git a/contrib/cpio/lib/full-write.c b/contrib/cpio/lib/full-write.c new file mode 100644 index 0000000..d119977 --- /dev/null +++ b/contrib/cpio/lib/full-write.c @@ -0,0 +1,83 @@ +/* An interface to read and write that retries (if necessary) until complete. + + Copyright (C) 1993, 1994, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#ifdef FULL_READ +# include "full-read.h" +#else +# include "full-write.h" +#endif + +#include <errno.h> + +#ifdef FULL_READ +# include "safe-read.h" +# define safe_rw safe_read +# define full_rw full_read +# undef const +# define const /* empty */ +#else +# include "safe-write.h" +# define safe_rw safe_write +# define full_rw full_write +#endif + +#ifdef FULL_READ +/* Set errno to zero upon EOF. */ +# define ZERO_BYTE_TRANSFER_ERRNO 0 +#else +/* Some buggy drivers return 0 when one tries to write beyond + a device's end. (Example: Linux 1.2.13 on /dev/fd0.) + Set errno to ENOSPC so they get a sensible diagnostic. */ +# define ZERO_BYTE_TRANSFER_ERRNO ENOSPC +#endif + +/* Write(read) COUNT bytes at BUF to(from) descriptor FD, retrying if + interrupted or if a partial write(read) occurs. Return the number + of bytes transferred. + When writing, set errno if fewer than COUNT bytes are written. + When reading, if fewer than COUNT bytes are read, you must examine + errno to distinguish failure from EOF (errno == 0). */ +size_t +full_rw (int fd, const void *buf, size_t count) +{ + size_t total = 0; + const char *ptr = buf; + + while (count > 0) + { + size_t n_rw = safe_rw (fd, ptr, count); + if (n_rw == (size_t) -1) + break; + if (n_rw == 0) + { + errno = ZERO_BYTE_TRANSFER_ERRNO; + break; + } + total += n_rw; + ptr += n_rw; + count -= n_rw; + } + + return total; +} diff --git a/contrib/cpio/lib/full-write.h b/contrib/cpio/lib/full-write.h new file mode 100644 index 0000000..2637903 --- /dev/null +++ b/contrib/cpio/lib/full-write.h @@ -0,0 +1,35 @@ +/* An interface to write() that writes all it is asked to write. + + Copyright (C) 2002-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stddef.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Write COUNT bytes at BUF to descriptor FD, retrying if interrupted + or if partial writes occur. Return the number of bytes successfully + written, setting errno if that is less than COUNT. */ +extern size_t full_write (int fd, const void *buf, size_t count); + + +#ifdef __cplusplus +} +#endif diff --git a/contrib/cpio/lib/getopt.c b/contrib/cpio/lib/getopt.c new file mode 100644 index 0000000..ef790b7 --- /dev/null +++ b/contrib/cpio/lib/getopt.c @@ -0,0 +1,1241 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002,2003,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include <stdlib.h> +# include <unistd.h> +#endif /* GNU C library. */ + +#include <string.h> + +#ifdef VMS +# include <unixlib.h> +#endif + +#ifdef _LIBC +# include <libintl.h> +#else +# include "gettext.h" +# define _(msgid) gettext (msgid) +#endif + +#if defined _LIBC && defined USE_IN_LIBIO +# include <wchar.h> +#endif + +#ifndef attribute_hidden +# define attribute_hidden +#endif + +/* Unlike standard Unix `getopt', functions like `getopt_long' + let the user intersperse the options with the other arguments. + + As `getopt_long' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Using `getopt' or setting the environment variable POSIXLY_CORRECT + disables permutation. + Then the application's behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" +#include "getopt_int.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Keep a global copy of all internal members of getopt_data. */ + +static struct _getopt_data getopt_data; + + +#ifndef __GNU_LIBRARY__ + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +#endif /* not __GNU_LIBRARY__ */ + +#ifdef _LIBC +/* Stored original parameters. + XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ +extern int __libc_argc; +extern char **__libc_argv; + +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +# ifdef USE_NONOPTION_FLAGS +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ + if (d->__nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (char **argv, struct _getopt_data *d) +{ + int bottom = d->__first_nonopt; + int middle = d->__last_nonopt; + int top = d->optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + d->__nonoption_flags_max_len), + '\0', top + 1 - d->__nonoption_flags_max_len); + d->__nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + d->__first_nonopt += (d->optind - d->__last_nonopt); + d->__last_nonopt = d->optind; +} + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (int argc, char **argv, const char *optstring, + int posixly_correct, struct _getopt_data *d) +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + d->__first_nonopt = d->__last_nonopt = d->optind; + + d->__nextchar = NULL; + + d->__posixly_correct = posixly_correct || !!getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + d->__ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + d->__ordering = REQUIRE_ORDER; + ++optstring; + } + else if (d->__posixly_correct) + d->__ordering = REQUIRE_ORDER; + else + d->__ordering = PERMUTE; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + if (!d->__posixly_correct + && argc == __libc_argc && argv == __libc_argv) + { + if (d->__nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + d->__nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = d->__nonoption_flags_max_len = strlen (orig_str); + if (d->__nonoption_flags_max_len < argc) + d->__nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (d->__nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + d->__nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', d->__nonoption_flags_max_len - len); + } + } + d->__nonoption_flags_len = d->__nonoption_flags_max_len; + } + else + d->__nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. + + If POSIXLY_CORRECT is nonzero, behave as if the POSIXLY_CORRECT + environment variable were set. */ + +int +_getopt_internal_r (int argc, char **argv, const char *optstring, + const struct option *longopts, int *longind, + int long_only, int posixly_correct, struct _getopt_data *d) +{ + int print_errors = d->opterr; + if (optstring[0] == ':') + print_errors = 0; + + if (argc < 1) + return -1; + + d->optarg = NULL; + + if (d->optind == 0 || !d->__initialized) + { + if (d->optind == 0) + d->optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring, + posixly_correct, d); + d->__initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \ + || (d->optind < d->__nonoption_flags_len \ + && __getopt_nonoption_flags[d->optind] == '1')) +#else +# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') +#endif + + if (d->__nextchar == NULL || *d->__nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (d->__last_nonopt > d->optind) + d->__last_nonopt = d->optind; + if (d->__first_nonopt > d->optind) + d->__first_nonopt = d->optind; + + if (d->__ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (d->__first_nonopt != d->__last_nonopt + && d->__last_nonopt != d->optind) + exchange ((char **) argv, d); + else if (d->__last_nonopt != d->optind) + d->__first_nonopt = d->optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (d->optind < argc && NONOPTION_P) + d->optind++; + d->__last_nonopt = d->optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (d->optind != argc && !strcmp (argv[d->optind], "--")) + { + d->optind++; + + if (d->__first_nonopt != d->__last_nonopt + && d->__last_nonopt != d->optind) + exchange ((char **) argv, d); + else if (d->__first_nonopt == d->__last_nonopt) + d->__first_nonopt = d->optind; + d->__last_nonopt = argc; + + d->optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (d->optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (d->__first_nonopt != d->__last_nonopt) + d->optind = d->__first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (d->__ordering == REQUIRE_ORDER) + return -1; + d->optarg = argv[d->optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + d->__nextchar = (argv[d->optind] + 1 + + (longopts != NULL && argv[d->optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[d->optind][1] == '-' + || (long_only && (argv[d->optind][2] + || !strchr (optstring, argv[d->optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[d->optind]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[d->optind]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optind++; + d->optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + d->optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (argv[d->optind - 1][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("\ +%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#else + fprintf (stderr, _("\ +%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("\ +%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[d->optind - 1][0], + pfound->name); +#else + fprintf (stderr, _("\ +%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[d->optind - 1][0], + pfound->name); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + + d->__nextchar += strlen (d->__nextchar); + + d->optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option `%s' requires an argument\n"), + argv[0], argv[d->optind - 1]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[d->optind - 1]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen (d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[d->optind][1] == '-' + || strchr (optstring, *d->__nextchar) == NULL) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (argv[d->optind][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), + argv[0], d->__nextchar); +#else + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], d->__nextchar); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[d->optind][0], d->__nextchar); +#else + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[d->optind][0], d->__nextchar); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + d->__nextchar = (char *) ""; + d->optind++; + d->optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *d->__nextchar++; + char *temp = strchr (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*d->__nextchar == '\0') + ++d->optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (d->__posixly_correct) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: illegal option -- %c\n"), + argv[0], c); +#else + fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); +#endif + } + else + { +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: invalid option -- %c\n"), + argv[0], c); +#else + fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + d->optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, + _("%s: option requires an argument -- %c\n"), + argv[0], c) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `d->optind' once; + increment it again when taking next ARGV-elt as argument. */ + d->optarg = argv[d->optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; + nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[d->optind]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[d->optind]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + + d->__nextchar += strlen (d->__nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option `%s' requires an argument\n"), + argv[0], argv[d->optind - 1]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[d->optind - 1]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen (d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + d->__nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else + d->optarg = NULL; + d->__nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option requires an argument -- %c\n"), + argv[0], c) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + d->optarg = argv[d->optind++]; + d->__nextchar = NULL; + } + } + return c; + } +} + +int +_getopt_internal (int argc, char **argv, const char *optstring, + const struct option *longopts, int *longind, + int long_only, int posixly_correct) +{ + int result; + + getopt_data.optind = optind; + getopt_data.opterr = opterr; + + result = _getopt_internal_r (argc, argv, optstring, longopts, longind, + long_only, posixly_correct, &getopt_data); + + optind = getopt_data.optind; + optarg = getopt_data.optarg; + optopt = getopt_data.optopt; + + return result; +} + +/* glibc gets a LSB-compliant getopt. + Standalone applications get a POSIX-compliant getopt. */ +#if _LIBC +enum { POSIXLY_CORRECT = 0 }; +#else +enum { POSIXLY_CORRECT = 1 }; +#endif + +int +getopt (int argc, char *const *argv, const char *optstring) +{ + return _getopt_internal (argc, (char **) argv, optstring, NULL, NULL, 0, + POSIXLY_CORRECT); +} + + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/contrib/cpio/lib/getopt1.c b/contrib/cpio/lib/getopt1.c new file mode 100644 index 0000000..a747237 --- /dev/null +++ b/contrib/cpio/lib/getopt1.c @@ -0,0 +1,174 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef _LIBC +# include <getopt.h> +#else +# include "getopt.h" +#endif +#include "getopt_int.h" + +#include <stdio.h> + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include <stdlib.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (int argc, char *__getopt_argv_const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 0, 0); +} + +int +_getopt_long_r (int argc, char **argv, const char *options, + const struct option *long_options, int *opt_index, + struct _getopt_data *d) +{ + return _getopt_internal_r (argc, argv, options, long_options, opt_index, + 0, 0, d); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (int argc, char *__getopt_argv_const *argv, + const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 1, 0); +} + +int +_getopt_long_only_r (int argc, char **argv, const char *options, + const struct option *long_options, int *opt_index, + struct _getopt_data *d) +{ + return _getopt_internal_r (argc, argv, options, long_options, opt_index, + 1, 0, d); +} + + +#ifdef TEST + +#include <stdio.h> + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/contrib/cpio/lib/getopt_.h b/contrib/cpio/lib/getopt_.h new file mode 100644 index 0000000..83ac8b1 --- /dev/null +++ b/contrib/cpio/lib/getopt_.h @@ -0,0 +1,227 @@ +/* Declarations for getopt. + Copyright (C) 1989-1994,1996-1999,2001,2003,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +/* Standalone applications should #define __GETOPT_PREFIX to an + identifier that prefixes the external functions and variables + defined in this header. When this happens, include the + headers that might declare getopt so that they will not cause + confusion if included after this file. Then systematically rename + identifiers so that they do not collide with the system functions + and variables. Renaming avoids problems with some compilers and + linkers. */ +#if defined __GETOPT_PREFIX && !defined __need_getopt +# include <stdlib.h> +# include <stdio.h> +# if HAVE_UNISTD_H +# include <unistd.h> +# endif +# undef __need_getopt +# undef getopt +# undef getopt_long +# undef getopt_long_only +# undef optarg +# undef opterr +# undef optind +# undef optopt +# define __GETOPT_CONCAT(x, y) x ## y +# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y) +# define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y) +# define getopt __GETOPT_ID (getopt) +# define getopt_long __GETOPT_ID (getopt_long) +# define getopt_long_only __GETOPT_ID (getopt_long_only) +# define optarg __GETOPT_ID (optarg) +# define opterr __GETOPT_ID (opterr) +# define optind __GETOPT_ID (optind) +# define optopt __GETOPT_ID (optopt) +#endif + +/* Standalone applications get correct prototypes for getopt_long and + getopt_long_only; they declare "char **argv". libc uses prototypes + with "char *const *argv" that are incorrect because getopt_long and + getopt_long_only can permute argv; this is required for backward + compatibility (e.g., for LSB 2.0.1). + + This used to be `#if defined __GETOPT_PREFIX && !defined __need_getopt', + but it caused redefinition warnings if both unistd.h and getopt.h were + included, since unistd.h includes getopt.h having previously defined + __need_getopt. + + The only place where __getopt_argv_const is used is in definitions + of getopt_long and getopt_long_only below, but these are visible + only if __need_getopt is not defined, so it is quite safe to rewrite + the conditional as follows: +*/ +#if !defined __need_getopt +# if defined __GETOPT_PREFIX +# define __getopt_argv_const /* empty */ +# else +# define __getopt_argv_const const +# endif +#endif + +/* If __GNU_LIBRARY__ is not already defined, either we are being used + standalone, or this is the first header included in the source file. + If we are being used with glibc, we need to include <features.h>, but + that does not exist if we are standalone. So: if __GNU_LIBRARY__ is + not defined, include <ctype.h>, which will pull in <features.h> for us + if it's from glibc. (Why ctype.h? It's guaranteed to exist and it + doesn't flood the namespace with stuff the way some other headers do.) */ +#if !defined __GNU_LIBRARY__ +# include <ctype.h> +#endif + +#ifndef __THROW +# ifndef __GNUC_PREREQ +# define __GNUC_PREREQ(maj, min) (0) +# endif +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) + __THROW; + +#ifndef __need_getopt +extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; +extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; + +#endif + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/contrib/cpio/lib/getopt_int.h b/contrib/cpio/lib/getopt_int.h new file mode 100644 index 0000000..e5bc3f2 --- /dev/null +++ b/contrib/cpio/lib/getopt_int.h @@ -0,0 +1,131 @@ +/* Internal declarations for getopt. + Copyright (C) 1989-1994,1996-1999,2001,2003,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_INT_H +#define _GETOPT_INT_H 1 + +extern int _getopt_internal (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only, int __posixly_correct); + + +/* Reentrant versions which can handle parsing multiple argument + vectors at the same time. */ + +/* Data type for reentrant functions. */ +struct _getopt_data +{ + /* These have exactly the same meaning as the corresponding global + variables, except that they are used for the reentrant + versions of getopt. */ + int optind; + int opterr; + int optopt; + char *optarg; + + /* Internal members. */ + + /* True if the internal members have been initialized. */ + int __initialized; + + /* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + char *__nextchar; + + /* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters, or by calling getopt. + + PERMUTE is the default. We permute the contents of ARGV as we + scan, so that eventually all the non-options are at the end. + This allows options to be given in any order, even with programs + that were not written to expect this. + + RETURN_IN_ORDER is an option available to programs that were + written to expect options and other ARGV-elements in any order + and that care about the ordering of the two. We describe each + non-option ARGV-element as if it were the argument of an option + with character code 1. Using `-' as the first character of the + list of option characters selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + + enum + { + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER + } __ordering; + + /* If the POSIXLY_CORRECT environment variable is set + or getopt was called. */ + int __posixly_correct; + + + /* Handle permutation of arguments. */ + + /* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first + of them; `last_nonopt' is the index after the last of them. */ + + int __first_nonopt; + int __last_nonopt; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + int __nonoption_flags_max_len; + int __nonoption_flags_len; +# endif +}; + +/* The initializer is necessary to set OPTIND and OPTERR to their + default values and to clear the initialization flag. */ +#define _GETOPT_DATA_INITIALIZER { 1, 1 } + +extern int _getopt_internal_r (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only, int __posixly_correct, + struct _getopt_data *__data); + +extern int _getopt_long_r (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + struct _getopt_data *__data); + +extern int _getopt_long_only_r (int ___argc, char **___argv, + const char *__shortopts, + const struct option *__longopts, + int *__longind, + struct _getopt_data *__data); + +#endif /* getopt_int.h */ diff --git a/contrib/cpio/lib/gettext.h b/contrib/cpio/lib/gettext.h new file mode 100644 index 0000000..835732e --- /dev/null +++ b/contrib/cpio/lib/gettext.h @@ -0,0 +1,68 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ diff --git a/contrib/cpio/lib/localedir.h b/contrib/cpio/lib/localedir.h new file mode 100644 index 0000000..7460e6f --- /dev/null +++ b/contrib/cpio/lib/localedir.h @@ -0,0 +1,4 @@ +#define LOCALEDIR "/usr/local/share/locale" +#ifndef DEFAULT_RMT_COMMAND +# define DEFAULT_RMT_COMMAND "/usr/local/libexec/rmt" +#endif diff --git a/contrib/cpio/lib/mempcpy.c b/contrib/cpio/lib/mempcpy.c new file mode 100644 index 0000000..3ac42af --- /dev/null +++ b/contrib/cpio/lib/mempcpy.c @@ -0,0 +1,29 @@ +/* Copy memory area and return pointer after last written byte. + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Specification. */ +#include "mempcpy.h" + +#include <string.h> + +/* Copy N bytes of SRC to DEST, return pointer to bytes after the + last written byte. */ +void * +mempcpy (void *dest, const void *src, size_t n) +{ + return (char *) memcpy (dest, src, n) + n; +} diff --git a/contrib/cpio/lib/mempcpy.h b/contrib/cpio/lib/mempcpy.h new file mode 100644 index 0000000..4cc7a50 --- /dev/null +++ b/contrib/cpio/lib/mempcpy.h @@ -0,0 +1,36 @@ +/* Copy memory area and return pointer after last written byte. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef mempcpy + +# if HAVE_MEMPCPY + +/* Get mempcpy() declaration. */ +# include <string.h> + +# else + +/* Get size_t */ +# include <stddef.h> + +/* Copy N bytes of SRC to DEST, return pointer to bytes after the + last written byte. */ +extern void *mempcpy (void *dest, const void *src, size_t n); + +# endif + +#endif diff --git a/contrib/cpio/lib/rmt.h b/contrib/cpio/lib/rmt.h new file mode 100644 index 0000000..1fd2f29 --- /dev/null +++ b/contrib/cpio/lib/rmt.h @@ -0,0 +1,99 @@ +/* Definitions for communicating with a remote tape drive. + + Copyright (C) 1988, 1992, 1996, 1997, 2001, 2003, 2004 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +extern char *rmt_command; +extern char *rmt_dev_name__; + +int rmt_open__ (const char *, int, int, const char *); +int rmt_close__ (int); +size_t rmt_read__ (int, char *, size_t); +size_t rmt_write__ (int, char *, size_t); +off_t rmt_lseek__ (int, off_t, int); +int rmt_ioctl__ (int, int, char *); + +extern bool force_local_option; + +/* A filename is remote if it contains a colon not preceded by a slash, + to take care of `/:/' which is a shorthand for `/.../<CELL-NAME>/fs' + on machines running OSF's Distributing Computing Environment (DCE) and + Distributed File System (DFS). However, when --force-local, a + filename is never remote. */ + +#define _remdev(dev_name) \ + (!force_local_option && (rmt_dev_name__ = strchr (dev_name, ':')) \ + && rmt_dev_name__ > (dev_name) \ + && ! memchr (dev_name, '/', rmt_dev_name__ - (dev_name))) + +#define _isrmt(fd) \ + ((fd) >= __REM_BIAS) + +#define __REM_BIAS (1 << 30) + +#ifndef O_CREAT +# define O_CREAT 01000 +#endif + +#define rmtopen(dev_name, oflag, mode, command) \ + (_remdev (dev_name) ? rmt_open__ (dev_name, oflag, __REM_BIAS, command) \ + : open (dev_name, oflag, mode)) + +#define rmtaccess(dev_name, amode) \ + (_remdev (dev_name) ? 0 : access (dev_name, amode)) + +#define rmtstat(dev_name, buffer) \ + (_remdev (dev_name) ? (errno = EOPNOTSUPP), -1 : stat (dev_name, buffer)) + +#define rmtcreat(dev_name, mode, command) \ + (_remdev (dev_name) \ + ? rmt_open__ (dev_name, 1 | O_CREAT, __REM_BIAS, command) \ + : creat (dev_name, mode)) + +#define rmtlstat(dev_name, muffer) \ + (_remdev (dev_name) ? (errno = EOPNOTSUPP), -1 : lstat (dev_name, buffer)) + +#define rmtread(fd, buffer, length) \ + (_isrmt (fd) ? rmt_read__ (fd - __REM_BIAS, buffer, length) \ + : safe_read (fd, buffer, length)) + +#define rmtwrite(fd, buffer, length) \ + (_isrmt (fd) ? rmt_write__ (fd - __REM_BIAS, buffer, length) \ + : full_write (fd, buffer, length)) + +#define rmtlseek(fd, offset, where) \ + (_isrmt (fd) ? rmt_lseek__ (fd - __REM_BIAS, offset, where) \ + : lseek (fd, offset, where)) + +#define rmtclose(fd) \ + (_isrmt (fd) ? rmt_close__ (fd - __REM_BIAS) : close (fd)) + +#define rmtioctl(fd, request, argument) \ + (_isrmt (fd) ? rmt_ioctl__ (fd - __REM_BIAS, request, argument) \ + : ioctl (fd, request, argument)) + +#define rmtdup(fd) \ + (_isrmt (fd) ? (errno = EOPNOTSUPP), -1 : dup (fd)) + +#define rmtfstat(fd, buffer) \ + (_isrmt (fd) ? (errno = EOPNOTSUPP), -1 : fstat (fd, buffer)) + +#define rmtfcntl(cd, command, argument) \ + (_isrmt (fd) ? (errno = EOPNOTSUPP), -1 : fcntl (fd, command, argument)) + +#define rmtisatty(fd) \ + (_isrmt (fd) ? 0 : isatty (fd)) diff --git a/contrib/cpio/lib/rtapelib.c b/contrib/cpio/lib/rtapelib.c new file mode 100644 index 0000000..0e499b6 --- /dev/null +++ b/contrib/cpio/lib/rtapelib.c @@ -0,0 +1,740 @@ +/* Functions for communicating with a remote tape drive. + + Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2004 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol + which rdump and rrestore use. Unfortunately, the man page is *WRONG*. + The author of the routines I'm including originally wrote his code just + based on the man page, and it didn't work, so he went to the rdump source + to figure out why. The only thing he had to change was to check for the + 'F' return code in addition to the 'E', and to separate the various + arguments with \n instead of a space. I personally don't think that this + is much of a problem, but I wanted to point it out. -- Arnold Robbins + + Originally written by Jeff Lee, modified some by Arnold Robbins. Redone + as a library that can replace open, read, write, etc., by Fred Fish, with + some additional work by Arnold Robbins. Modified to make all rmt* calls + into macros for speed by Jay Fenlason. Use -DWITH_REXEC for rexec + code, courtesy of Dan Kegel. */ + +#include "system.h" +#include <safe-read.h> +#include <full-write.h> + +/* Try hard to get EOPNOTSUPP defined. 486/ISC has it in net/errno.h, + 3B2/SVR3 has it in sys/inet.h. Otherwise, like on MSDOS, use EINVAL. */ + +#ifndef EOPNOTSUPP +# if HAVE_NET_ERRNO_H +# include <net/errno.h> +# endif +# if HAVE_SYS_INET_H +# include <sys/inet.h> +# endif +# ifndef EOPNOTSUPP +# define EOPNOTSUPP EINVAL +# endif +#endif + +#include <signal.h> + +#if HAVE_NETDB_H +# include <netdb.h> +#endif + +#include <rmt.h> +#include <localedir.h> + +/* Exit status if exec errors. */ +#define EXIT_ON_EXEC_ERROR 128 + +/* FIXME: Size of buffers for reading and writing commands to rmt. */ +#define COMMAND_BUFFER_SIZE 64 + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +/* FIXME: Maximum number of simultaneous remote tape connections. */ +#define MAXUNIT 4 + +#define PREAD 0 /* read file descriptor from pipe() */ +#define PWRITE 1 /* write file descriptor from pipe() */ + +/* Return the parent's read side of remote tape connection Fd. */ +#define READ_SIDE(Fd) (from_remote[Fd][PREAD]) + +/* Return the parent's write side of remote tape connection Fd. */ +#define WRITE_SIDE(Fd) (to_remote[Fd][PWRITE]) + +/* The pipes for receiving data from remote tape drives. */ +static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + +/* The pipes for sending data to remote tape drives. */ +static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + +char *rmt_command = DEFAULT_RMT_COMMAND; + +/* Temporary variable used by macros in rmt.h. */ +char *rmt_dev_name__; + +/* If true, always consider file names to be local, even if they contain + colons */ +bool force_local_option; + + + +/* Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE. */ +static void +_rmt_shutdown (int handle, int errno_value) +{ + close (READ_SIDE (handle)); + close (WRITE_SIDE (handle)); + READ_SIDE (handle) = -1; + WRITE_SIDE (handle) = -1; + errno = errno_value; +} + +/* Attempt to perform the remote tape command specified in BUFFER on + remote tape connection HANDLE. Return 0 if successful, -1 on + error. */ +static int +do_command (int handle, const char *buffer) +{ + /* Save the current pipe handler and try to make the request. */ + + size_t length = strlen (buffer); + RETSIGTYPE (*pipe_handler) () = signal (SIGPIPE, SIG_IGN); + ssize_t written = full_write (WRITE_SIDE (handle), buffer, length); + signal (SIGPIPE, pipe_handler); + + if (written == length) + return 0; + + /* Something went wrong. Close down and go home. */ + + _rmt_shutdown (handle, EIO); + return -1; +} + +static char * +get_status_string (int handle, char *command_buffer) +{ + char *cursor; + int counter; + + /* Read the reply command line. */ + + for (counter = 0, cursor = command_buffer; + counter < COMMAND_BUFFER_SIZE; + counter++, cursor++) + { + if (safe_read (READ_SIDE (handle), cursor, 1) != 1) + { + _rmt_shutdown (handle, EIO); + return 0; + } + if (*cursor == '\n') + { + *cursor = '\0'; + break; + } + } + + if (counter == COMMAND_BUFFER_SIZE) + { + _rmt_shutdown (handle, EIO); + return 0; + } + + /* Check the return status. */ + + for (cursor = command_buffer; *cursor; cursor++) + if (*cursor != ' ') + break; + + if (*cursor == 'E' || *cursor == 'F') + { + /* Skip the error message line. */ + + /* FIXME: there is better to do than merely ignoring error messages + coming from the remote end. Translate them, too... */ + + { + char character; + + while (safe_read (READ_SIDE (handle), &character, 1) == 1) + if (character == '\n') + break; + } + + errno = atoi (cursor + 1); + + if (*cursor == 'F') + _rmt_shutdown (handle, errno); + + return 0; + } + + /* Check for mis-synced pipes. */ + + if (*cursor != 'A') + { + _rmt_shutdown (handle, EIO); + return 0; + } + + /* Got an `A' (success) response. */ + + return cursor + 1; +} + +/* Read and return the status from remote tape connection HANDLE. If + an error occurred, return -1 and set errno. */ +static long int +get_status (int handle) +{ + char command_buffer[COMMAND_BUFFER_SIZE]; + const char *status = get_status_string (handle, command_buffer); + if (status) + { + long int result = atol (status); + if (0 <= result) + return result; + errno = EIO; + } + return -1; +} + +static off_t +get_status_off (int handle) +{ + char command_buffer[COMMAND_BUFFER_SIZE]; + const char *status = get_status_string (handle, command_buffer); + + if (! status) + return -1; + else + { + /* Parse status, taking care to check for overflow. + We can't use standard functions, + since off_t might be longer than long. */ + + off_t count = 0; + int negative; + + for (; *status == ' ' || *status == '\t'; status++) + continue; + + negative = *status == '-'; + status += negative || *status == '+'; + + for (;;) + { + int digit = *status++ - '0'; + if (9 < (unsigned) digit) + break; + else + { + off_t c10 = 10 * count; + off_t nc = negative ? c10 - digit : c10 + digit; + if (c10 / 10 != count || (negative ? c10 < nc : nc < c10)) + return -1; + count = nc; + } + } + + return count; + } +} + +#if WITH_REXEC + +/* Execute /etc/rmt as user USER on remote system HOST using rexec. + Return a file descriptor of a bidirectional socket for stdin and + stdout. If USER is zero, use the current username. + + By default, this code is not used, since it requires that the user + have a .netrc file in his/her home directory, or that the + application designer be willing to have rexec prompt for login and + password info. This may be unacceptable, and .rhosts files for use + with rsh are much more common on BSD systems. */ +static int +_rmt_rexec (char *host, char *user) +{ + int saved_stdin = dup (STDIN_FILENO); + int saved_stdout = dup (STDOUT_FILENO); + struct servent *rexecserv; + int result; + + /* When using cpio -o < filename, stdin is no longer the tty. But the + rexec subroutine reads the login and the passwd on stdin, to allow + remote execution of the command. So, reopen stdin and stdout on + /dev/tty before the rexec and give them back their original value + after. */ + + if (! freopen ("/dev/tty", "r", stdin)) + freopen ("/dev/null", "r", stdin); + if (! freopen ("/dev/tty", "w", stdout)) + freopen ("/dev/null", "w", stdout); + + if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv) + error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available")); + + result = rexec (&host, rexecserv->s_port, user, 0, rmt_command, 0); + if (fclose (stdin) == EOF) + error (0, errno, _("stdin")); + fdopen (saved_stdin, "r"); + if (fclose (stdout) == EOF) + error (0, errno, _("stdout")); + fdopen (saved_stdout, "w"); + + return result; +} + +#endif /* WITH_REXEC */ + +/* Place into BUF a string representing OFLAG, which must be suitable + as argument 2 of `open'. BUF must be large enough to hold the + result. This function should generate a string that decode_oflag + can parse. */ +static void +encode_oflag (char *buf, int oflag) +{ + sprintf (buf, "%d ", oflag); + + switch (oflag & O_ACCMODE) + { + case O_RDONLY: strcat (buf, "O_RDONLY"); break; + case O_RDWR: strcat (buf, "O_RDWR"); break; + case O_WRONLY: strcat (buf, "O_WRONLY"); break; + default: abort (); + } + +#ifdef O_APPEND + if (oflag & O_APPEND) strcat (buf, "|O_APPEND"); +#endif + if (oflag & O_CREAT) strcat (buf, "|O_CREAT"); +#ifdef O_DSYNC + if (oflag & O_DSYNC) strcat (buf, "|O_DSYNC"); +#endif + if (oflag & O_EXCL) strcat (buf, "|O_EXCL"); +#ifdef O_LARGEFILE + if (oflag & O_LARGEFILE) strcat (buf, "|O_LARGEFILE"); +#endif +#ifdef O_NOCTTY + if (oflag & O_NOCTTY) strcat (buf, "|O_NOCTTY"); +#endif +#ifdef O_NONBLOCK + if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK"); +#endif +#ifdef O_RSYNC + if (oflag & O_RSYNC) strcat (buf, "|O_RSYNC"); +#endif +#ifdef O_SYNC + if (oflag & O_SYNC) strcat (buf, "|O_SYNC"); +#endif + if (oflag & O_TRUNC) strcat (buf, "|O_TRUNC"); +} + +/* Open a file (a magnetic tape device?) on the system specified in + FILE_NAME, as the given user. FILE_NAME has the form `[USER@]HOST:FILE'. + OPEN_MODE is O_RDONLY, O_WRONLY, etc. If successful, return the + remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On + error, return -1. */ +int +rmt_open__ (const char *file_name, int open_mode, int bias, + const char *remote_shell) +{ + int remote_pipe_number; /* pseudo, biased file descriptor */ + char *file_name_copy; /* copy of file_name string */ + char *remote_host; /* remote host name */ + char *remote_file; /* remote file name (often a device) */ + char *remote_user; /* remote user name */ + + /* Find an unused pair of file descriptors. */ + + for (remote_pipe_number = 0; + remote_pipe_number < MAXUNIT; + remote_pipe_number++) + if (READ_SIDE (remote_pipe_number) == -1 + && WRITE_SIDE (remote_pipe_number) == -1) + break; + + if (remote_pipe_number == MAXUNIT) + { + errno = EMFILE; + return -1; + } + + /* Pull apart the system and device, and optional user. */ + + { + char *cursor; + + file_name_copy = xstrdup (file_name); + remote_host = file_name_copy; + remote_user = 0; + remote_file = 0; + + for (cursor = file_name_copy; *cursor; cursor++) + switch (*cursor) + { + default: + break; + + case '\n': + /* Do not allow newlines in the file_name, since the protocol + uses newline delimiters. */ + free (file_name_copy); + errno = ENOENT; + return -1; + + case '@': + if (!remote_user) + { + remote_user = remote_host; + *cursor = '\0'; + remote_host = cursor + 1; + } + break; + + case ':': + if (!remote_file) + { + *cursor = '\0'; + remote_file = cursor + 1; + } + break; + } + } + + /* FIXME: Should somewhat validate the decoding, here. */ + + if (remote_user && *remote_user == '\0') + remote_user = 0; + +#if WITH_REXEC + + /* Execute the remote command using rexec. */ + + READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user); + if (READ_SIDE (remote_pipe_number) < 0) + { + int e = errno; + free (file_name_copy); + errno = e; + return -1; + } + + WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number); + +#else /* not WITH_REXEC */ + { + const char *remote_shell_basename; + pid_t status; + + /* Identify the remote command to be executed. */ + + if (!remote_shell) + { +#ifdef REMOTE_SHELL + remote_shell = REMOTE_SHELL; +#else + free (file_name_copy); + errno = EIO; + return -1; +#endif + } + remote_shell_basename = base_name (remote_shell); + + /* Set up the pipes for the `rsh' command, and fork. */ + + if (pipe (to_remote[remote_pipe_number]) == -1 + || pipe (from_remote[remote_pipe_number]) == -1) + { + int e = errno; + free (file_name_copy); + errno = e; + return -1; + } + + status = fork (); + if (status == -1) + { + int e = errno; + free (file_name_copy); + errno = e; + return -1; + } + + if (status == 0) + { + /* Child. */ + + close (STDIN_FILENO); + dup (to_remote[remote_pipe_number][PREAD]); + close (to_remote[remote_pipe_number][PREAD]); + close (to_remote[remote_pipe_number][PWRITE]); + + close (STDOUT_FILENO); + dup (from_remote[remote_pipe_number][PWRITE]); + close (from_remote[remote_pipe_number][PREAD]); + close (from_remote[remote_pipe_number][PWRITE]); + + sys_reset_uid_gid (); + + if (remote_user) + execl (remote_shell, remote_shell_basename, remote_host, + "-l", remote_user, rmt_command, (char *) 0); + else + execl (remote_shell, remote_shell_basename, remote_host, + rmt_command, (char *) 0); + + /* Bad problems if we get here. */ + + /* In a previous version, _exit was used here instead of exit. */ + error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell")); + } + + /* Parent. */ + + close (from_remote[remote_pipe_number][PWRITE]); + close (to_remote[remote_pipe_number][PREAD]); + } +#endif /* not WITH_REXEC */ + + /* Attempt to open the tape device. */ + + { + size_t remote_file_len = strlen (remote_file); + char *command_buffer = xmalloc (remote_file_len + 1000); + sprintf (command_buffer, "O%s\n", remote_file); + encode_oflag (command_buffer + remote_file_len + 2, open_mode); + strcat (command_buffer, "\n"); + if (do_command (remote_pipe_number, command_buffer) == -1 + || get_status (remote_pipe_number) == -1) + { + int e = errno; + free (command_buffer); + free (file_name_copy); + _rmt_shutdown (remote_pipe_number, e); + return -1; + } + free (command_buffer); + } + + free (file_name_copy); + return remote_pipe_number + bias; +} + +/* Close remote tape connection HANDLE and shut down. Return 0 if + successful, -1 on error. */ +int +rmt_close__ (int handle) +{ + long int status; + + if (do_command (handle, "C\n") == -1) + return -1; + + status = get_status (handle); + _rmt_shutdown (handle, errno); + return status; +} + +/* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE. + Return the number of bytes read on success, SAFE_READ_ERROR on error. */ +size_t +rmt_read__ (int handle, char *buffer, size_t length) +{ + char command_buffer[COMMAND_BUFFER_SIZE]; + size_t status; + size_t rlen; + size_t counter; + + sprintf (command_buffer, "R%lu\n", (unsigned long) length); + if (do_command (handle, command_buffer) == -1 + || (status = get_status (handle)) == SAFE_READ_ERROR) + return SAFE_READ_ERROR; + + for (counter = 0; counter < status; counter += rlen, buffer += rlen) + { + rlen = safe_read (READ_SIDE (handle), buffer, status - counter); + if (rlen == SAFE_READ_ERROR || rlen == 0) + { + _rmt_shutdown (handle, EIO); + return SAFE_READ_ERROR; + } + } + + return status; +} + +/* Write LENGTH bytes from BUFFER to remote tape connection HANDLE. + Return the number of bytes written. */ +size_t +rmt_write__ (int handle, char *buffer, size_t length) +{ + char command_buffer[COMMAND_BUFFER_SIZE]; + RETSIGTYPE (*pipe_handler) (); + size_t written; + + sprintf (command_buffer, "W%lu\n", (unsigned long) length); + if (do_command (handle, command_buffer) == -1) + return 0; + + pipe_handler = signal (SIGPIPE, SIG_IGN); + written = full_write (WRITE_SIDE (handle), buffer, length); + signal (SIGPIPE, pipe_handler); + if (written == length) + { + long int r = get_status (handle); + if (r < 0) + return 0; + if (r == length) + return length; + written = r; + } + + /* Write error. */ + + _rmt_shutdown (handle, EIO); + return written; +} + +/* Perform an imitation lseek operation on remote tape connection + HANDLE. Return the new file offset if successful, -1 if on error. */ +off_t +rmt_lseek__ (int handle, off_t offset, int whence) +{ + char command_buffer[COMMAND_BUFFER_SIZE]; + char operand_buffer[UINTMAX_STRSIZE_BOUND]; + uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset; + char *p = operand_buffer + sizeof operand_buffer; + + *--p = 0; + do + *--p = '0' + (int) (u % 10); + while ((u /= 10) != 0); + if (offset < 0) + *--p = '-'; + + switch (whence) + { + case SEEK_SET: whence = 0; break; + case SEEK_CUR: whence = 1; break; + case SEEK_END: whence = 2; break; + default: abort (); + } + + sprintf (command_buffer, "L%s\n%d\n", p, whence); + + if (do_command (handle, command_buffer) == -1) + return -1; + + return get_status_off (handle); +} + +/* Perform a raw tape operation on remote tape connection HANDLE. + Return the results of the ioctl, or -1 on error. */ +int +rmt_ioctl__ (int handle, int operation, char *argument) +{ + switch (operation) + { + default: + errno = EOPNOTSUPP; + return -1; + +#ifdef MTIOCTOP + case MTIOCTOP: + { + char command_buffer[COMMAND_BUFFER_SIZE]; + char operand_buffer[UINTMAX_STRSIZE_BOUND]; + uintmax_t u = (((struct mtop *) argument)->mt_count < 0 + ? - (uintmax_t) ((struct mtop *) argument)->mt_count + : (uintmax_t) ((struct mtop *) argument)->mt_count); + char *p = operand_buffer + sizeof operand_buffer; + + *--p = 0; + do + *--p = '0' + (int) (u % 10); + while ((u /= 10) != 0); + if (((struct mtop *) argument)->mt_count < 0) + *--p = '-'; + + /* MTIOCTOP is the easy one. Nothing is transferred in binary. */ + + sprintf (command_buffer, "I%d\n%s\n", + ((struct mtop *) argument)->mt_op, p); + if (do_command (handle, command_buffer) == -1) + return -1; + + return get_status (handle); + } +#endif /* MTIOCTOP */ + +#ifdef MTIOCGET + case MTIOCGET: + { + ssize_t status; + size_t counter; + + /* Grab the status and read it directly into the structure. This + assumes that the status buffer is not padded and that 2 shorts + fit in a long without any word alignment problems; i.e., the + whole struct is contiguous. NOTE - this is probably NOT a good + assumption. */ + + if (do_command (handle, "S") == -1 + || (status = get_status (handle), status == -1)) + return -1; + + for (; status > 0; status -= counter, argument += counter) + { + counter = safe_read (READ_SIDE (handle), argument, status); + if (counter == SAFE_READ_ERROR || counter == 0) + { + _rmt_shutdown (handle, EIO); + return -1; + } + } + + /* Check for byte position. mt_type (or mt_model) is a small integer + field (normally) so we will check its magnitude. If it is larger + than 256, we will assume that the bytes are swapped and go through + and reverse all the bytes. */ + + if (((struct mtget *) argument)->MTIO_CHECK_FIELD < 256) + return 0; + + for (counter = 0; counter < status; counter += 2) + { + char copy = argument[counter]; + + argument[counter] = argument[counter + 1]; + argument[counter + 1] = copy; + } + + return 0; + } +#endif /* MTIOCGET */ + + } +} diff --git a/contrib/cpio/lib/safe-read.c b/contrib/cpio/lib/safe-read.c new file mode 100644 index 0000000..6f8bd78 --- /dev/null +++ b/contrib/cpio/lib/safe-read.c @@ -0,0 +1,82 @@ +/* An interface to read and write that retries after interrupts. + + Copyright (C) 1993, 1994, 1998, 2002, 2003, 2004 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#ifdef SAFE_WRITE +# include "safe-write.h" +#else +# include "safe-read.h" +#endif + +/* Get ssize_t. */ +#include <sys/types.h> +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <errno.h> + +#ifdef EINTR +# define IS_EINTR(x) ((x) == EINTR) +#else +# define IS_EINTR(x) 0 +#endif + +#include <limits.h> + +#ifdef SAFE_WRITE +# define safe_rw safe_write +# define rw write +#else +# define safe_rw safe_read +# define rw read +# undef const +# define const /* empty */ +#endif + +/* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if + interrupted. Return the actual number of bytes read(written), zero for EOF, + or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */ +size_t +safe_rw (int fd, void const *buf, size_t count) +{ + /* Work around a bug in Tru64 5.1. Attempting to read more than + INT_MAX bytes fails with errno == EINVAL. See + <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>. + When decreasing COUNT, keep it block-aligned. */ + enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 }; + + for (;;) + { + ssize_t result = rw (fd, buf, count); + + if (0 <= result) + return result; + else if (IS_EINTR (errno)) + continue; + else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count) + count = BUGGY_READ_MAXIMUM; + else + return result; + } +} diff --git a/contrib/cpio/lib/safe-read.h b/contrib/cpio/lib/safe-read.h new file mode 100644 index 0000000..cbe6e0b --- /dev/null +++ b/contrib/cpio/lib/safe-read.h @@ -0,0 +1,25 @@ +/* An interface to read() that retries after interrupts. + Copyright (C) 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stddef.h> + +#define SAFE_READ_ERROR ((size_t) -1) + +/* Read up to COUNT bytes at BUF from descriptor FD, retrying if interrupted. + Return the actual number of bytes read, zero for EOF, or SAFE_READ_ERROR + upon error. */ +extern size_t safe_read (int fd, void *buf, size_t count); diff --git a/contrib/cpio/lib/safe-write.c b/contrib/cpio/lib/safe-write.c new file mode 100644 index 0000000..fbafa7c --- /dev/null +++ b/contrib/cpio/lib/safe-write.c @@ -0,0 +1,19 @@ +/* An interface to write that retries after interrupts. + Copyright (C) 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define SAFE_WRITE +#include "safe-read.c" diff --git a/contrib/cpio/lib/safe-write.h b/contrib/cpio/lib/safe-write.h new file mode 100644 index 0000000..ab1f45b --- /dev/null +++ b/contrib/cpio/lib/safe-write.h @@ -0,0 +1,25 @@ +/* An interface to write() that retries after interrupts. + Copyright (C) 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stddef.h> + +#define SAFE_WRITE_ERROR ((size_t) -1) + +/* Write up to COUNT bytes at BUF to descriptor FD, retrying if interrupted. + Return the actual number of bytes written, zero for EOF, or SAFE_WRITE_ERROR + upon error. */ +extern size_t safe_write (int fd, const void *buf, size_t count); diff --git a/contrib/cpio/lib/savedir.c b/contrib/cpio/lib/savedir.c new file mode 100644 index 0000000..c92e62e --- /dev/null +++ b/contrib/cpio/lib/savedir.c @@ -0,0 +1,123 @@ +/* savedir.c -- save the list of files in a directory in a string + + Copyright 1990, 1997, 1998, 1999, 2000, 2001, 2003, 2004 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "savedir.h" + +#include <sys/types.h> + +#include <errno.h> + +#if HAVE_DIRENT_H +# include <dirent.h> +#else +# define dirent direct +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +#ifdef CLOSEDIR_VOID +/* Fake a return value. */ +# define CLOSEDIR(d) (closedir (d), 0) +#else +# define CLOSEDIR(d) closedir (d) +#endif + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "xalloc.h" + +/* Return a freshly allocated string containing the filenames + in directory DIR, separated by '\0' characters; + the end is marked by two '\0' characters in a row. + Return NULL (setting errno) if DIR cannot be opened, read, or closed. */ + +#ifndef NAME_SIZE_DEFAULT +# define NAME_SIZE_DEFAULT 512 +#endif + +char * +savedir (const char *dir) +{ + DIR *dirp; + struct dirent *dp; + char *name_space; + size_t allocated = NAME_SIZE_DEFAULT; + size_t used = 0; + int save_errno; + + dirp = opendir (dir); + if (dirp == NULL) + return NULL; + + name_space = xmalloc (allocated); + + errno = 0; + while ((dp = readdir (dirp)) != NULL) + { + /* Skip "", ".", and "..". "" is returned by at least one buggy + implementation: Solaris 2.4 readdir on NFS file systems. */ + char const *entry = dp->d_name; + if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0') + { + size_t entry_size = strlen (entry) + 1; + if (used + entry_size < used) + xalloc_die (); + if (allocated <= used + entry_size) + { + do + { + if (2 * allocated < allocated) + xalloc_die (); + allocated *= 2; + } + while (allocated <= used + entry_size); + + name_space = xrealloc (name_space, allocated); + } + memcpy (name_space + used, entry, entry_size); + used += entry_size; + } + } + name_space[used] = '\0'; + save_errno = errno; + if (CLOSEDIR (dirp) != 0) + save_errno = errno; + if (save_errno != 0) + { + free (name_space); + errno = save_errno; + return NULL; + } + return name_space; +} diff --git a/contrib/cpio/lib/savedir.h b/contrib/cpio/lib/savedir.h new file mode 100644 index 0000000..bd33085 --- /dev/null +++ b/contrib/cpio/lib/savedir.h @@ -0,0 +1,26 @@ +/* Save the list of files in a directory in a string. + + Copyright 1997, 1999, 2001, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ + +#if !defined SAVEDIR_H_ +# define SAVEDIR_H_ + +char *savedir (const char *dir); + +#endif diff --git a/contrib/cpio/lib/strcase.h b/contrib/cpio/lib/strcase.h new file mode 100644 index 0000000..9461392 --- /dev/null +++ b/contrib/cpio/lib/strcase.h @@ -0,0 +1,47 @@ +/* Case-insensitive string comparison functions. + Copyright (C) 1995-1996, 2001, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _STRCASE_H +#define _STRCASE_H + +#include <stddef.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Compare strings S1 and S2, ignoring case, returning less than, equal to or + greater than zero if S1 is lexicographically less than, equal to or greater + than S2. + Note: This function does not work correctly in multibyte locales. */ +extern int strcasecmp (const char *s1, const char *s2); + +/* Compare no more than N characters of strings S1 and S2, ignoring case, + returning less than, equal to or greater than zero if S1 is + lexicographically less than, equal to or greater than S2. + Note: This function can not work correctly in multibyte locales. */ +extern int strncasecmp (const char *s1, const char *s2, size_t n); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _STRCASE_H */ diff --git a/contrib/cpio/lib/strchrnul.c b/contrib/cpio/lib/strchrnul.c new file mode 100644 index 0000000..be85312 --- /dev/null +++ b/contrib/cpio/lib/strchrnul.c @@ -0,0 +1,30 @@ +/* Searching in a string. + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Specification. */ +#include "strchrnul.h" + +/* Find the first occurrence of C in S or the final NUL byte. */ +char * +strchrnul (const char *s, int c_in) +{ + char c = c_in; + while (*s && (*s != c)) + s++; + + return (char *) s; +} diff --git a/contrib/cpio/lib/strchrnul.h b/contrib/cpio/lib/strchrnul.h new file mode 100644 index 0000000..f7589e9 --- /dev/null +++ b/contrib/cpio/lib/strchrnul.h @@ -0,0 +1,28 @@ +/* Searching in a string. + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_STRCHRNUL + +/* Get strchrnul() declaration. */ +#include <string.h> + +#else + +/* Find the first occurrence of C in S or the final NUL byte. */ +extern char *strchrnul (const char *s, int c_in); + +#endif diff --git a/contrib/cpio/lib/stripslash.c b/contrib/cpio/lib/stripslash.c new file mode 100644 index 0000000..9998e64 --- /dev/null +++ b/contrib/cpio/lib/stripslash.c @@ -0,0 +1,39 @@ +/* stripslash.c -- remove redundant trailing slashes from a file name + Copyright (C) 1990, 2001, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "dirname.h" + +/* Remove trailing slashes from PATH. + Return true if a trailing slash was removed. + This is useful when using filename completion from a shell that + adds a "/" after directory names (such as tcsh and bash), because + the Unix rename and rmdir system calls return an "Invalid argument" error + when given a path that ends in "/" (except for the root directory). */ + +bool +strip_trailing_slashes (char *path) +{ + char *base = base_name (path); + char *base_lim = base + base_len (base); + bool had_slash = (*base_lim != '\0'); + *base_lim = '\0'; + return had_slash; +} diff --git a/contrib/cpio/lib/strndup.c b/contrib/cpio/lib/strndup.c new file mode 100644 index 0000000..f85627e --- /dev/null +++ b/contrib/cpio/lib/strndup.c @@ -0,0 +1,55 @@ +/* Copyright (C) 1996, 1997, 1998, 2000, 2003 Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#ifndef HAVE_DECL_STRNLEN +"this configure-time declaration test was not run" +#endif +#if !HAVE_DECL_STRNLEN +size_t strnlen (); +#endif + +#undef __strndup +#undef strndup + +#ifndef weak_alias +# define __strndup strndup +#endif + +char * +__strndup (const char *s, size_t n) +{ + size_t len = strnlen (s, n); + char *new = malloc (len + 1); + + if (new == NULL) + return NULL; + + new[len] = '\0'; + return memcpy (new, s, len); +} +#ifdef weak_alias +weak_alias (__strndup, strndup) +#endif diff --git a/contrib/cpio/lib/strndup.h b/contrib/cpio/lib/strndup.h new file mode 100644 index 0000000..318e799 --- /dev/null +++ b/contrib/cpio/lib/strndup.h @@ -0,0 +1,30 @@ +/* Duplicate a size-bounded string. + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_STRNDUP + +/* Get strndup() declaration. */ +#include <string.h> + +#else + +#include <stddef.h> + +/* Return a newly allocated copy of at most N bytes of STRING. */ +extern char *strndup (const char *string, size_t n); + +#endif diff --git a/contrib/cpio/lib/strnlen.c b/contrib/cpio/lib/strnlen.c new file mode 100644 index 0000000..c9f3898 --- /dev/null +++ b/contrib/cpio/lib/strnlen.c @@ -0,0 +1,48 @@ +/* Find the length of STRING, but scan at most MAXLEN characters. + Copyright (C) 1996, 1997, 1998, 2000-2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif +#undef strnlen + +#include <string.h> + +#undef __strnlen +#undef strnlen + +#ifndef _LIBC +# define strnlen rpl_strnlen +#endif + +#ifndef weak_alias +# define __strnlen strnlen +#endif + +/* Find the length of STRING, but scan at most MAXLEN characters. + If no '\0' terminator is found in that many characters, return MAXLEN. */ + +size_t +__strnlen (const char *string, size_t maxlen) +{ + const char *end = memchr (string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} +#ifdef weak_alias +weak_alias (__strnlen, strnlen) +#endif diff --git a/contrib/cpio/lib/system.h b/contrib/cpio/lib/system.h new file mode 100644 index 0000000..0914195 --- /dev/null +++ b/contrib/cpio/lib/system.h @@ -0,0 +1,524 @@ +/* System dependent definitions for GNU tar. + + Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, + 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include <alloca.h> + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(spec) /* empty */ +# endif +#endif + +#include <sys/types.h> +#include <ctype.h> + +/* IN_CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given + as an argument to <ctype.h> macros like `isspace'. */ +#if STDC_HEADERS +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177) +#endif + +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) +#define ISODIGIT(c) ((unsigned) (c) - '0' <= 7) +#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) + +/* Declare string and memory handling routines. Take care that an ANSI + string.h and pre-ANSI memory.h might conflict, and that memory.h and + strings.h conflict on some systems. */ + +#if STDC_HEADERS || HAVE_STRING_H +# include <string.h> +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +#else +# include <strings.h> +# ifndef strchr +# define strchr index +# endif +# ifndef strrchr +# define strrchr rindex +# endif +# ifndef memcpy +# define memcpy(d, s, n) bcopy ((char const *) (s), (char *) (d), n) +# endif +# ifndef memcmp +# define memcmp(a, b, n) bcmp ((char const *) (a), (char const *) (b), n) +# endif +#endif + +/* Declare errno. */ + +#include <errno.h> +#ifndef errno +extern int errno; +#endif + +/* Declare open parameters. */ + +#if HAVE_FCNTL_H +# include <fcntl.h> +#else +# include <sys/file.h> +#endif + /* Pick only one of the next three: */ +#ifndef O_RDONLY +# define O_RDONLY 0 /* only allow read */ +#endif +#ifndef O_WRONLY +# define O_WRONLY 1 /* only allow write */ +#endif +#ifndef O_RDWR +# define O_RDWR 2 /* both are allowed */ +#endif +#ifndef O_ACCMODE +# define O_ACCMODE (O_RDONLY | O_RDWR | O_WRONLY) +#endif + /* The rest can be OR-ed in to the above: */ +#ifndef O_CREAT +# define O_CREAT 8 /* create file if needed */ +#endif +#ifndef O_EXCL +# define O_EXCL 16 /* file cannot already exist */ +#endif +#ifndef O_TRUNC +# define O_TRUNC 32 /* truncate file on open */ +#endif + /* MS-DOG forever, with my love! */ +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +/* Declare file status routines and bits. */ + +#include <sys/stat.h> + +#if !HAVE_LSTAT && !defined lstat +# define lstat stat +#endif + +#if STX_HIDDEN && !_LARGE_FILES /* AIX */ +# ifdef stat +# undef stat +# endif +# define stat(file_name, buf) statx (file_name, buf, STATSIZE, STX_HIDDEN) +# ifdef lstat +# undef lstat +# endif +# define lstat(file_name, buf) statx (file_name, buf, STATSIZE, STX_HIDDEN | STX_LINK) +#endif + +#if STAT_MACROS_BROKEN +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISCTG +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISLNK +# undef S_ISREG +# undef S_ISSOCK +#endif + +/* On MSDOS, there are missing things from <sys/stat.h>. */ +#if MSDOS +# define S_ISUID 0 +# define S_ISGID 0 +# define S_ISVTX 0 +#endif + +#ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISREG +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif + +#ifndef S_ISBLK +# ifdef S_IFBLK +# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +# else +# define S_ISBLK(mode) 0 +# endif +#endif +#ifndef S_ISCHR +# ifdef S_IFCHR +# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +# else +# define S_ISCHR(mode) 0 +# endif +#endif +#ifndef S_ISCTG +# ifdef S_IFCTG +# define S_ISCTG(mode) (((mode) & S_IFMT) == S_IFCTG) +# else +# define S_ISCTG(mode) 0 +# endif +#endif +#ifndef S_ISDOOR +# define S_ISDOOR(mode) 0 +#endif +#ifndef S_ISFIFO +# ifdef S_IFIFO +# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +# else +# define S_ISFIFO(mode) 0 +# endif +#endif +#ifndef S_ISLNK +# ifdef S_IFLNK +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +# else +# define S_ISLNK(mode) 0 +# endif +#endif +#ifndef S_ISSOCK +# ifdef S_IFSOCK +# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(mode) 0 +# endif +#endif + +#if !HAVE_MKFIFO && !defined mkfifo && defined S_IFIFO +# define mkfifo(file_name, mode) (mknod (file_name, (mode) | S_IFIFO, 0)) +#endif + +#ifndef S_ISUID +# define S_ISUID 0004000 +#endif +#ifndef S_ISGID +# define S_ISGID 0002000 +#endif +#ifndef S_ISVTX +# define S_ISVTX 0001000 +#endif +#ifndef S_IRUSR +# define S_IRUSR 0000400 +#endif +#ifndef S_IWUSR +# define S_IWUSR 0000200 +#endif +#ifndef S_IXUSR +# define S_IXUSR 0000100 +#endif +#ifndef S_IRGRP +# define S_IRGRP 0000040 +#endif +#ifndef S_IWGRP +# define S_IWGRP 0000020 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0000010 +#endif +#ifndef S_IROTH +# define S_IROTH 0000004 +#endif +#ifndef S_IWOTH +# define S_IWOTH 0000002 +#endif +#ifndef S_IXOTH +# define S_IXOTH 0000001 +#endif + +#define MODE_WXUSR (S_IWUSR | S_IXUSR) +#define MODE_R (S_IRUSR | S_IRGRP | S_IROTH) +#define MODE_RW (S_IWUSR | S_IWGRP | S_IWOTH | MODE_R) +#define MODE_RWX (S_IXUSR | S_IXGRP | S_IXOTH | MODE_RW) +#define MODE_ALL (S_ISUID | S_ISGID | S_ISVTX | MODE_RWX) + +/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION. */ +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +# define SEEK_CUR 1 +#endif +#ifndef SEEK_END +# define SEEK_END 2 +#endif + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +/* Declare make device, major and minor. Since major is a function on + SVR4, we have to resort to GOT_MAJOR instead of just testing if + major is #define'd. */ + +#if MAJOR_IN_MKDEV +# include <sys/mkdev.h> +# define GOT_MAJOR +#endif + +#if MAJOR_IN_SYSMACROS +# include <sys/sysmacros.h> +# define GOT_MAJOR +#endif + +/* Some <sys/types.h> defines the macros. */ +#ifdef major +# define GOT_MAJOR +#endif + +#ifndef GOT_MAJOR +# if MSDOS +# define major(device) (device) +# define minor(device) (device) +# define makedev(major, minor) (((major) << 8) | (minor)) +# define GOT_MAJOR +# endif +#endif + +/* For HP-UX before HP-UX 8, major/minor are not in <sys/sysmacros.h>. */ +#ifndef GOT_MAJOR +# if defined(hpux) || defined(__hpux__) || defined(__hpux) +# include <sys/mknod.h> +# define GOT_MAJOR +# endif +#endif + +#ifndef GOT_MAJOR +# define major(device) (((device) >> 8) & 0xff) +# define minor(device) ((device) & 0xff) +# define makedev(major, minor) (((major) << 8) | (minor)) +#endif + +#undef GOT_MAJOR + +/* Declare wait status. */ + +#if HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(s) (((s) >> 8) & 0xff) +#endif +#ifndef WIFSIGNALED +# define WIFSIGNALED(s) (((s) & 0xffff) - 1 < (unsigned) 0xff) +#endif +#ifndef WTERMSIG +# define WTERMSIG(s) ((s) & 0x7f) +#endif + +/* FIXME: It is wrong to use BLOCKSIZE for buffers when the logical block + size is greater than 512 bytes; so ST_BLKSIZE code below, in preparation + for some cleanup in this area, later. */ + +/* Extract or fake data from a `struct stat'. ST_BLKSIZE gives the + optimal I/O blocksize for the file, in bytes. Some systems, like + Sequents, return st_blksize of 0 on pipes. */ + +#define DEFAULT_ST_BLKSIZE 512 + +#if !HAVE_ST_BLKSIZE +# define ST_BLKSIZE(statbuf) DEFAULT_ST_BLKSIZE +#else +# define ST_BLKSIZE(statbuf) \ + ((statbuf).st_blksize > 0 ? (statbuf).st_blksize : DEFAULT_ST_BLKSIZE) +#endif + +/* Extract or fake data from a `struct stat'. ST_NBLOCKS gives the + number of ST_NBLOCKSIZE-byte blocks in the file (including indirect blocks). + HP-UX counts st_blocks in 1024-byte units, + this loses when mixing HP-UX and BSD filesystems with NFS. AIX PS/2 + counts st_blocks in 4K units. */ + +#if !HAVE_ST_BLOCKS +# if defined(_POSIX_SOURCE) || !defined(BSIZE) +# define ST_NBLOCKS(statbuf) ((statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0)) +# else + off_t st_blocks (); +# define ST_NBLOCKS(statbuf) (st_blocks ((statbuf).st_size)) +# endif +#else +# define ST_NBLOCKS(statbuf) ((statbuf).st_blocks) +# if defined(hpux) || defined(__hpux__) || defined(__hpux) +# define ST_NBLOCKSIZE 1024 +# else +# if defined(_AIX) && defined(_I386) +# define ST_NBLOCKSIZE (4 * 1024) +# endif +# endif +#endif + +#ifndef ST_NBLOCKSIZE +#define ST_NBLOCKSIZE 512 +#endif + +/* This is a real challenge to properly get MTIO* symbols :-(. ISC uses + <sys/gentape.h>. SCO and BSDi uses <sys/tape.h>; BSDi also requires + <sys/tprintf.h> and <sys/device.h> for defining tp_dev and tpr_t. It + seems that the rest use <sys/mtio.h>, which itself requires other files, + depending on systems. Pyramid defines _IOW in <sgtty.h>, for example. */ + +#if HAVE_SYS_GENTAPE_H +# include <sys/gentape.h> +#else +# if HAVE_SYS_TAPE_H +# if HAVE_SYS_DEVICE_H +# include <sys/device.h> +# endif +# if HAVE_SYS_PARAM_H +# include <sys/param.h> +# endif +# if HAVE_SYS_BUF_H +# include <sys/buf.h> +# endif +# if HAVE_SYS_TPRINTF_H +# include <sys/tprintf.h> +# endif +# include <sys/tape.h> +# else +# if HAVE_SYS_MTIO_H +# include <sys/ioctl.h> +# if HAVE_SGTTY_H +# include <sgtty.h> +# endif +# if HAVE_SYS_IO_TRIOCTL_H +# include <sys/io/trioctl.h> +# endif +# include <sys/mtio.h> +# endif +# endif +#endif + +/* Declare standard functions. */ + +#if STDC_HEADERS +# include <stdlib.h> +#else +void *malloc (); +char *getenv (); +#endif + +#include <stdbool.h> +#include <stddef.h> + +#include <stdio.h> +#if !defined _POSIX_VERSION && MSDOS +# include <io.h> +#endif + +#if WITH_DMALLOC +# undef HAVE_DECL_VALLOC +# define DMALLOC_FUNC_CHECK +# include <dmalloc.h> +#endif + +#include <limits.h> + +#ifndef MB_LEN_MAX +# define MB_LEN_MAX 1 +#endif + +#if HAVE_INTTYPES_H +# include <inttypes.h> +#endif + +/* These macros work even on ones'-complement hosts (!). + The extra casts work around common compiler bugs. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +#define TYPE_MINIMUM(t) (TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \ + : (t) 0) +#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) + +/* Bound on length of the string representing an integer value of type t. + Subtract one for the sign bit if t is signed; + 302 / 1000 is log10 (2) rounded up; + add one for integer division truncation; + add one more for a minus sign if t is signed. */ +#define INT_STRLEN_BOUND(t) \ + ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \ + + 1 + TYPE_SIGNED (t)) + +#define UINTMAX_STRSIZE_BOUND (INT_STRLEN_BOUND (uintmax_t) + 1) + +/* Prototypes for external functions. */ + +#if HAVE_LOCALE_H +# include <locale.h> +#endif +#if !HAVE_SETLOCALE +# define setlocale(category, locale) /* empty */ +#endif + +#include <time.h> +#if defined(HAVE_SYS_TIME_H) && defined(TIME_WITH_SYS_TIME) +# include <sys/time.h> +#endif +#if ! HAVE_DECL_TIME +time_t time (); +#endif + +#ifdef HAVE_UTIME_H +# include <utime.h> +#endif + +/* Library modules. */ + +#include <dirname.h> +#include <error.h> +#include <savedir.h> +#include <unlocked-io.h> +#include <xalloc.h> + +#include <gettext.h> +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + +#if MSDOS +# include <process.h> +# define SET_BINARY_MODE(arc) setmode(arc, O_BINARY) +# define ERRNO_IS_EACCES errno == EACCES +# define mkdir(file, mode) (mkdir) (file) +# define TTY_NAME "con" +# define sys_reset_uid_gid() +#else +# include <pwd.h> +# include <grp.h> +# define SET_BINARY_MODE(arc) +# define ERRNO_IS_EACCES 0 +# define TTY_NAME "/dev/tty" +# define sys_reset_uid_gid() \ + do { setuid (getuid ()); setgid (getgid ()); } while (0) +#endif + +#if XENIX +# include <sys/inode.h> +#endif diff --git a/contrib/cpio/lib/unlocked-io.h b/contrib/cpio/lib/unlocked-io.h new file mode 100644 index 0000000..3ff42f2 --- /dev/null +++ b/contrib/cpio/lib/unlocked-io.h @@ -0,0 +1,137 @@ +/* Prefer faster, non-thread-safe stdio functions if available. + + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering. */ + +#ifndef UNLOCKED_IO_H +#define UNLOCKED_IO_H 1 + +/* These are wrappers for functions/macros from the GNU C library, and + from other C libraries supporting POSIX's optional thread-safe functions. + + The standard I/O functions are thread-safe. These *_unlocked ones are + more efficient but not thread-safe. That they're not thread-safe is + fine since all of the applications in this package are single threaded. + + Also, some code that is shared with the GNU C library may invoke + the *_unlocked functions directly. On hosts that lack those + functions, invoke the non-thread-safe versions instead. */ + +#include <stdio.h> + +#if HAVE_DECL_CLEARERR_UNLOCKED +# undef clearerr +# define clearerr(x) clearerr_unlocked (x) +#else +# define clearerr_unlocked(x) clearerr (x) +#endif + +#if HAVE_DECL_FEOF_UNLOCKED +# undef feof +# define feof(x) feof_unlocked (x) +#else +# define feof_unlocked(x) feof (x) +#endif + +#if HAVE_DECL_FERROR_UNLOCKED +# undef ferror +# define ferror(x) ferror_unlocked (x) +#else +# define ferror_unlocked(x) ferror (x) +#endif + +#if HAVE_DECL_FFLUSH_UNLOCKED +# undef fflush +# define fflush(x) fflush_unlocked (x) +#else +# define fflush_unlocked(x) fflush (x) +#endif + +#if HAVE_DECL_FGETS_UNLOCKED +# undef fgets +# define fgets(x,y,z) fgets_unlocked (x,y,z) +#else +# define fgets_unlocked(x,y,z) fgets (x,y,z) +#endif + +#if HAVE_DECL_FPUTC_UNLOCKED +# undef fputc +# define fputc(x,y) fputc_unlocked (x,y) +#else +# define fputc_unlocked(x,y) fputc (x,y) +#endif + +#if HAVE_DECL_FPUTS_UNLOCKED +# undef fputs +# define fputs(x,y) fputs_unlocked (x,y) +#else +# define fputs_unlocked(x,y) fputs (x,y) +#endif + +#if HAVE_DECL_FREAD_UNLOCKED +# undef fread +# define fread(w,x,y,z) fread_unlocked (w,x,y,z) +#else +# define fread_unlocked(w,x,y,z) fread (w,x,y,z) +#endif + +#if HAVE_DECL_FWRITE_UNLOCKED +# undef fwrite +# define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z) +#else +# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) +#endif + +#if HAVE_DECL_GETC_UNLOCKED +# undef getc +# define getc(x) getc_unlocked (x) +#else +# define getc_unlocked(x) getc (x) +#endif + +#if HAVE_DECL_GETCHAR_UNLOCKED +# undef getchar +# define getchar() getchar_unlocked () +#else +# define getchar_unlocked() getchar () +#endif + +#if HAVE_DECL_PUTC_UNLOCKED +# undef putc +# define putc(x,y) putc_unlocked (x,y) +#else +# define putc_unlocked(x,y) putc (x,y) +#endif + +#if HAVE_DECL_PUTCHAR_UNLOCKED +# undef putchar +# define putchar(x) putchar_unlocked (x) +#else +# define putchar_unlocked(x) putchar (x) +#endif + +#undef flockfile +#define flockfile(x) ((void) 0) + +#undef ftrylockfile +#define ftrylockfile(x) 0 + +#undef funlockfile +#define funlockfile(x) ((void) 0) + +#endif /* UNLOCKED_IO_H */ diff --git a/contrib/cpio/lib/xalloc-die.c b/contrib/cpio/lib/xalloc-die.c new file mode 100644 index 0000000..ca3a689 --- /dev/null +++ b/contrib/cpio/lib/xalloc-die.c @@ -0,0 +1,45 @@ +/* Report a memory allocation failure and exit. + + Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "xalloc.h" + +#include <stdlib.h> + +#include "error.h" +#include "exitfail.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + +void +xalloc_die (void) +{ + error (exit_failure, 0, "%s", _("memory exhausted")); + + /* The `noreturn' cannot be given to error, since it may return if + its first argument is 0. To help compilers understand the + xalloc_die does not return, call abort. Also, the abort is a + safety feature if exit_failure is 0 (which shouldn't happen). */ + abort (); +} diff --git a/contrib/cpio/lib/xalloc.h b/contrib/cpio/lib/xalloc.h new file mode 100644 index 0000000..8d0fcf0 --- /dev/null +++ b/contrib/cpio/lib/xalloc.h @@ -0,0 +1,79 @@ +/* xalloc.h -- malloc with out-of-memory checking + + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef XALLOC_H_ +# define XALLOC_H_ + +# include <stddef.h> + + +# ifdef __cplusplus +extern "C" { +# endif + + +# ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +# endif + +# ifndef ATTRIBUTE_NORETURN +# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +# endif + +/* This function is always triggered when memory is exhausted. + It must be defined by the application, either explicitly + or by using gnulib's xalloc-die module. This is the + function to call when one wants the program to die because of a + memory allocation failure. */ +extern void xalloc_die (void) ATTRIBUTE_NORETURN; + +void *xmalloc (size_t s); +void *xnmalloc (size_t n, size_t s); +void *xzalloc (size_t s); +void *xcalloc (size_t n, size_t s); +void *xrealloc (void *p, size_t s); +void *xnrealloc (void *p, size_t n, size_t s); +void *x2realloc (void *p, size_t *pn); +void *x2nrealloc (void *p, size_t *pn, size_t s); +void *xmemdup (void const *p, size_t s); +char *xstrdup (char const *str); + +/* Return 1 if an array of N objects, each of size S, cannot exist due + to size arithmetic overflow. S must be positive and N must be + nonnegative. This is a macro, not an inline function, so that it + works correctly even when SIZE_MAX < N. + + By gnulib convention, SIZE_MAX represents overflow in size + calculations, so the conservative dividend to use here is + SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. + However, malloc (SIZE_MAX) fails on all known hosts where + sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for + exactly-SIZE_MAX allocations on such hosts; this avoids a test and + branch when S is known to be 1. */ +# define xalloc_oversized(n, s) \ + ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) + +# ifdef __cplusplus +} +# endif + + +#endif /* !XALLOC_H_ */ diff --git a/contrib/cpio/lib/xmalloc.c b/contrib/cpio/lib/xmalloc.c new file mode 100644 index 0000000..13c2490 --- /dev/null +++ b/contrib/cpio/lib/xmalloc.c @@ -0,0 +1,229 @@ +/* xmalloc.c -- malloc with out of memory checking + + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "xalloc.h" + +#include <stdlib.h> +#include <string.h> + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +/* Allocate an array of N objects, each with S bytes of memory, + dynamically, with error checking. S must be nonzero. */ + +static inline void * +xnmalloc_inline (size_t n, size_t s) +{ + void *p; + if (xalloc_oversized (n, s) || (! (p = malloc (n * s)) && n != 0)) + xalloc_die (); + return p; +} + +void * +xnmalloc (size_t n, size_t s) +{ + return xnmalloc_inline (n, s); +} + +/* Allocate N bytes of memory dynamically, with error checking. */ + +void * +xmalloc (size_t n) +{ + return xnmalloc_inline (n, 1); +} + +/* Change the size of an allocated block of memory P to an array of N + objects each of S bytes, with error checking. S must be nonzero. */ + +static inline void * +xnrealloc_inline (void *p, size_t n, size_t s) +{ + if (xalloc_oversized (n, s) || (! (p = realloc (p, n * s)) && n != 0)) + xalloc_die (); + return p; +} + +void * +xnrealloc (void *p, size_t n, size_t s) +{ + return xnrealloc_inline (p, n, s); +} + +/* Change the size of an allocated block of memory P to N bytes, + with error checking. */ + +void * +xrealloc (void *p, size_t n) +{ + return xnrealloc_inline (p, n, 1); +} + + +/* If P is null, allocate a block of at least *PN such objects; + otherwise, reallocate P so that it contains more than *PN objects + each of S bytes. *PN must be nonzero unless P is null, and S must + be nonzero. Set *PN to the new number of objects, and return the + pointer to the new block. *PN is never set to zero, and the + returned pointer is never null. + + Repeated reallocations are guaranteed to make progress, either by + allocating an initial block with a nonzero size, or by allocating a + larger block. + + In the following implementation, nonzero sizes are doubled so that + repeated reallocations have O(N log N) overall cost rather than + O(N**2) cost, but the specification for this function does not + guarantee that sizes are doubled. + + Here is an example of use: + + int *p = NULL; + size_t used = 0; + size_t allocated = 0; + + void + append_int (int value) + { + if (used == allocated) + p = x2nrealloc (p, &allocated, sizeof *p); + p[used++] = value; + } + + This causes x2nrealloc to allocate a block of some nonzero size the + first time it is called. + + To have finer-grained control over the initial size, set *PN to a + nonzero value before calling this function with P == NULL. For + example: + + int *p = NULL; + size_t used = 0; + size_t allocated = 0; + size_t allocated1 = 1000; + + void + append_int (int value) + { + if (used == allocated) + { + p = x2nrealloc (p, &allocated1, sizeof *p); + allocated = allocated1; + } + p[used++] = value; + } + + */ + +static inline void * +x2nrealloc_inline (void *p, size_t *pn, size_t s) +{ + size_t n = *pn; + + if (! p) + { + if (! n) + { + /* The approximate size to use for initial small allocation + requests, when the invoking code specifies an old size of + zero. 64 bytes is the largest "small" request for the + GNU C library malloc. */ + enum { DEFAULT_MXFAST = 64 }; + + n = DEFAULT_MXFAST / s; + n += !n; + } + } + else + { + if (SIZE_MAX / 2 / s < n) + xalloc_die (); + n *= 2; + } + + *pn = n; + return xrealloc (p, n * s); +} + +void * +x2nrealloc (void *p, size_t *pn, size_t s) +{ + return x2nrealloc_inline (p, pn, s); +} + +/* If P is null, allocate a block of at least *PN bytes; otherwise, + reallocate P so that it contains more than *PN bytes. *PN must be + nonzero unless P is null. Set *PN to the new block's size, and + return the pointer to the new block. *PN is never set to zero, and + the returned pointer is never null. */ + +void * +x2realloc (void *p, size_t *pn) +{ + return x2nrealloc_inline (p, pn, 1); +} + +/* Allocate S bytes of zeroed memory dynamically, with error checking. + There's no need for xnzalloc (N, S), since it would be equivalent + to xcalloc (N, S). */ + +void * +xzalloc (size_t s) +{ + return memset (xmalloc (s), 0, s); +} + +/* Allocate zeroed memory for N elements of S bytes, with error + checking. S must be nonzero. */ + +void * +xcalloc (size_t n, size_t s) +{ + void *p; + /* Test for overflow, since some calloc implementations don't have + proper overflow checks. */ + if (xalloc_oversized (n, s) || (! (p = calloc (n, s)) && n != 0)) + xalloc_die (); + return p; +} + +/* Clone an object P of size S, with error checking. There's no need + for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any + need for an arithmetic overflow check. */ + +void * +xmemdup (void const *p, size_t s) +{ + return memcpy (xmalloc (s), p, s); +} + +/* Clone STRING. */ + +char * +xstrdup (char const *string) +{ + return xmemdup (string, strlen (string) + 1); +} diff --git a/contrib/cpio/src/copyin.c b/contrib/cpio/src/copyin.c new file mode 100644 index 0000000..a1063a3 --- /dev/null +++ b/contrib/cpio/src/copyin.c @@ -0,0 +1,1588 @@ +/* copyin.c - extract or list a cpio archive + Copyright (C) 1990,1991,1992,2001,2002,2003,2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <system.h> + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "filetypes.h" +#include "cpiohdr.h" +#include "dstring.h" +#include "extern.h" +#include "defer.h" +#include <rmt.h> +#ifndef FNM_PATHNAME +#include <fnmatch.h> +#endif + +#ifndef HAVE_LCHOWN +#define lchown chown +#endif + +static void copyin_regular_file(struct new_cpio_header* file_hdr, + int in_file_des); + +void +warn_junk_bytes (long bytes_skipped) +{ + error (0, 0, ngettext ("warning: skipped %ld byte of junk", + "warning: skipped %ld bytes of junk", bytes_skipped), + bytes_skipped); +} + + +static int +query_rename(struct new_cpio_header* file_hdr, FILE *tty_in, FILE *tty_out, + FILE *rename_in) +{ + char *str_res; /* Result for string function. */ + static dynamic_string new_name; /* New file name for rename option. */ + static int initialized_new_name = false; + if (!initialized_new_name) + { + ds_init (&new_name, 128); + initialized_new_name = true; + } + + if (rename_flag) + { + fprintf (tty_out, _("rename %s -> "), file_hdr->c_name); + fflush (tty_out); + str_res = ds_fgets (tty_in, &new_name); + } + else + { + str_res = ds_fgetstr (rename_in, &new_name, '\n'); + } + if (str_res == NULL || str_res[0] == 0) + { + return -1; + } + else + /* Debian hack: file_hrd.c_name is sometimes set to + point to static memory by code in tar.c. This + causes a segfault. This has been fixed and an + additional check to ensure that the file name + is not too long has been added. (Reported by + Horst Knobloch.) This bug has been reported to + "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */ + { + if (archive_format != arf_tar && archive_format != arf_ustar) + { + free (file_hdr->c_name); + file_hdr->c_name = xstrdup (new_name.ds_string); + } + else + { + if (is_tar_filename_too_long (new_name.ds_string)) + error (0, 0, _("%s: file name too long"), + new_name.ds_string); + else + strcpy (file_hdr->c_name, new_name.ds_string); + } + } + return 0; +} + +/* Skip the padding on IN_FILE_DES after a header or file, + up to the next header. + The number of bytes skipped is based on OFFSET -- the current offset + from the last start of a header (or file) -- and the current + header type. */ + +static void +tape_skip_padding (int in_file_des, int offset) +{ + int pad; + + if (archive_format == arf_crcascii || archive_format == arf_newascii) + pad = (4 - (offset % 4)) % 4; + else if (archive_format == arf_binary || archive_format == arf_hpbinary) + pad = (2 - (offset % 2)) % 2; + else if (archive_format == arf_tar || archive_format == arf_ustar) + pad = (512 - (offset % 512)) % 512; + else + pad = 0; + + if (pad != 0) + tape_toss_input (in_file_des, pad); +} + + +static void +list_file(struct new_cpio_header* file_hdr, int in_file_des) +{ + if (verbose_flag) + { +#ifdef CP_IFLNK + if ((file_hdr->c_mode & CP_IFMT) == CP_IFLNK) + { + if (archive_format != arf_tar && archive_format != arf_ustar) + { + char *link_name = NULL; /* Name of hard and symbolic links. */ + + link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1); + link_name[file_hdr->c_filesize] = '\0'; + tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize); + long_format (file_hdr, link_name); + free (link_name); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + return; + } + else + { + long_format (file_hdr, file_hdr->c_tar_linkname); + return; + } + } + else +#endif + long_format (file_hdr, (char *) 0); + } + else + { + /* Debian hack: Modified to print a list of filenames + terminiated by a null character when the -t and -0 + flags are used. This has been submitted as a + suggestion to "bug-gnu-utils@prep.ai.mit.edu". -BEM */ + printf ("%s%c", file_hdr->c_name, name_end); + } + + crc = 0; + tape_toss_input (in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + if (only_verify_crc_flag) + { +#ifdef CP_IFLNK + if ((file_hdr->c_mode & CP_IFMT) == CP_IFLNK) + { + return; /* links don't have a checksum */ + } +#endif + if (crc != file_hdr->c_chksum) + { + error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), + file_hdr->c_name, crc, file_hdr->c_chksum); + } + } +} + +static int +try_existing_file(struct new_cpio_header* file_hdr, int in_file_des, + int *existing_dir) +{ + struct stat file_stat; + + *existing_dir = false; + if (lstat (file_hdr->c_name, &file_stat) == 0) + { + if (S_ISDIR (file_stat.st_mode) + && ((file_hdr->c_mode & CP_IFMT) == CP_IFDIR)) + { + /* If there is already a directory there that + we are trying to create, don't complain about + it. */ + *existing_dir = true; + return 0; + } + else if (!unconditional_flag + && file_hdr->c_mtime <= file_stat.st_mtime) + { + error (0, 0, _("%s not created: newer or same age version exists"), + file_hdr->c_name); + tape_toss_input (in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + return -1; /* Go to the next file. */ + } + else if (S_ISDIR (file_stat.st_mode) + ? rmdir (file_hdr->c_name) + : unlink (file_hdr->c_name)) + { + error (0, errno, _("cannot remove current %s"), + file_hdr->c_name); + tape_toss_input (in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + return -1; /* Go to the next file. */ + } + } + return 0; +} + +/* The newc and crc formats store multiply linked copies of the same file + in the archive only once. The actual data is attached to the last link + in the archive, and the other links all have a filesize of 0. When a + file in the archive has multiple links and a filesize of 0, its data is + probably "attatched" to another file in the archive, so we can't create + it right away. We have to "defer" creating it until we have created + the file that has the data "attatched" to it. We keep a list of the + "defered" links on deferments. */ + +struct deferment *deferments = NULL; + +/* Add a file header to the deferments list. For now they all just + go on one list, although we could optimize this if necessary. */ + +static void +defer_copyin (struct new_cpio_header *file_hdr) +{ + struct deferment *d; + d = create_deferment (file_hdr); + d->next = deferments; + deferments = d; + return; +} + +/* We just created a file that (probably) has some other links to it + which have been defered. Go through all of the links on the deferments + list and create any which are links to this file. */ + +static void +create_defered_links (struct new_cpio_header *file_hdr) +{ + struct deferment *d; + struct deferment *d_prev; + int ino; + int maj; + int min; + int link_res; + ino = file_hdr->c_ino; + maj = file_hdr->c_dev_maj; + min = file_hdr->c_dev_min; + d = deferments; + d_prev = NULL; + while (d != NULL) + { + if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj) + && (d->header.c_dev_min == min) ) + { + struct deferment *d_free; + link_res = link_to_name (d->header.c_name, file_hdr->c_name); + if (link_res < 0) + { + error (0, errno, _("cannot link %s to %s"), + d->header.c_name, file_hdr->c_name); + } + if (d_prev != NULL) + d_prev->next = d->next; + else + deferments = d->next; + d_free = d; + d = d->next; + free_deferment (d_free); + } + else + { + d_prev = d; + d = d->next; + } + } +} + +/* We are skipping a file but there might be other links to it that we + did not skip, so we have to copy its data for the other links. Find + the first link that we didn't skip and try to create that. That will + then create the other deferred links. */ + +static int +create_defered_links_to_skipped (struct new_cpio_header *file_hdr, + int in_file_des) +{ + struct deferment *d; + struct deferment *d_prev; + int ino; + int maj; + int min; + int link_res; + if (file_hdr->c_filesize == 0) + { + /* The file doesn't have any data attached to it so we don't have + to bother. */ + return -1; + } + ino = file_hdr->c_ino; + maj = file_hdr->c_dev_maj; + min = file_hdr->c_dev_min; + d = deferments; + d_prev = NULL; + while (d != NULL) + { + if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj) + && (d->header.c_dev_min == min) ) + { + if (d_prev != NULL) + d_prev->next = d->next; + else + deferments = d->next; + free (file_hdr->c_name); + file_hdr->c_name = xstrdup(d->header.c_name); + free_deferment (d); + copyin_regular_file(file_hdr, in_file_des); + return 0; + } + else + { + d_prev = d; + d = d->next; + } + } + return -1; +} + +/* If we had a multiply linked file that really was empty then we would + have defered all of its links, since we never found any with data + "attached", and they will still be on the deferment list even when + we are done reading the whole archive. Write out all of these + empty links that are still on the deferments list. */ + +static void +create_final_defers () +{ + struct deferment *d; + int link_res; + int out_file_des; + struct utimbuf times; /* For setting file times. */ + /* Initialize this in case it has members we don't know to set. */ + bzero (×, sizeof (struct utimbuf)); + + for (d = deferments; d != NULL; d = d->next) + { + /* Debian hack: A line, which could cause an endless loop, was + removed (97/1/2). It was reported by Ronald F. Guilmette to + the upstream maintainers. -BEM */ + /* Debian hack: This was reported by Horst Knobloch. This bug has + been reported to "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM + */ + link_res = link_to_maj_min_ino (d->header.c_name, + d->header.c_dev_maj, d->header.c_dev_min, + d->header.c_ino); + if (link_res == 0) + { + continue; + } + out_file_des = open (d->header.c_name, + O_CREAT | O_WRONLY | O_BINARY, 0600); + if (out_file_des < 0 && create_dir_flag) + { + create_all_directories (d->header.c_name); + out_file_des = open (d->header.c_name, + O_CREAT | O_WRONLY | O_BINARY, + 0600); + } + if (out_file_des < 0) + { + error (0, errno, "%s", d->header.c_name); + continue; + } + + if (close (out_file_des) < 0) + error (0, errno, "%s", d->header.c_name); + + /* File is now copied; set attributes. */ + if (!no_chown_flag) + if ((chown (d->header.c_name, + set_owner_flag ? set_owner : d->header.c_uid, + set_group_flag ? set_group : d->header.c_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", d->header.c_name); + /* chown may have turned off some permissions we wanted. */ + if (chmod (d->header.c_name, (int) d->header.c_mode) < 0) + error (0, errno, "%s", d->header.c_name); + if (retain_time_flag) + { + times.actime = times.modtime = d->header.c_mtime; + if (utime (d->header.c_name, ×) < 0) + error (0, errno, "%s", d->header.c_name); + } + } +} + +static void +copyin_regular_file (struct new_cpio_header* file_hdr, int in_file_des) +{ + int out_file_des; /* Output file descriptor. */ + + if (to_stdout_option) + out_file_des = STDOUT_FILENO; + else + { + /* Can the current file be linked to a previously copied file? */ + if (file_hdr->c_nlink > 1 + && (archive_format == arf_newascii + || archive_format == arf_crcascii) ) + { + int link_res; + if (file_hdr->c_filesize == 0) + { + /* The newc and crc formats store multiply linked copies + of the same file in the archive only once. The + actual data is attached to the last link in the + archive, and the other links all have a filesize + of 0. Since this file has multiple links and a + filesize of 0, its data is probably attatched to + another file in the archive. Save the link, and + process it later when we get the actual data. We + can't just create it with length 0 and add the + data later, in case the file is readonly. We still + lose if its parent directory is readonly (and we aren't + running as root), but there's nothing we can do about + that. */ + defer_copyin (file_hdr); + tape_toss_input (in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + return; + } + /* If the file has data (filesize != 0), then presumably + any other links have already been defer_copyin'ed(), + but GNU cpio version 2.0-2.2 didn't do that, so we + still have to check for links here (and also in case + the archive was created and later appeneded to). */ + /* Debian hack: (97/1/2) This was reported by Ronald + F. Guilmette to the upstream maintainers. -BEM */ + link_res = link_to_maj_min_ino (file_hdr->c_name, + file_hdr->c_dev_maj, file_hdr->c_dev_min, + file_hdr->c_ino); + if (link_res == 0) + { + tape_toss_input (in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + return; + } + } + else if (file_hdr->c_nlink > 1 + && archive_format != arf_tar + && archive_format != arf_ustar) + { + int link_res; + /* Debian hack: (97/1/2) This was reported by Ronald + F. Guilmette to the upstream maintainers. -BEM */ + link_res = link_to_maj_min_ino (file_hdr->c_name, + file_hdr->c_dev_maj, + file_hdr->c_dev_min, + file_hdr->c_ino); + if (link_res == 0) + { + tape_toss_input (in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + return; + } + } + else if ((archive_format == arf_tar || archive_format == arf_ustar) + && file_hdr->c_tar_linkname + && file_hdr->c_tar_linkname[0] != '\0') + { + int link_res; + link_res = link_to_name (file_hdr->c_name, file_hdr->c_tar_linkname); + if (link_res < 0) + { + error (0, errno, _("cannot link %s to %s"), + file_hdr->c_tar_linkname, file_hdr->c_name); + } + return; + } + + /* If not linked, copy the contents of the file. */ + out_file_des = open (file_hdr->c_name, + O_CREAT | O_WRONLY | O_BINARY, 0600); + + if (out_file_des < 0 && create_dir_flag) + { + create_all_directories (file_hdr->c_name); + out_file_des = open (file_hdr->c_name, + O_CREAT | O_WRONLY | O_BINARY, + 0600); + } + + if (out_file_des < 0) + { + error (0, errno, "%s", file_hdr->c_name); + tape_toss_input (in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + return; + } + } + + crc = 0; + if (swap_halfwords_flag) + { + if ((file_hdr->c_filesize % 4) == 0) + swapping_halfwords = true; + else + error (0, 0, _("cannot swap halfwords of %s: odd number of halfwords"), + file_hdr->c_name); + } + if (swap_bytes_flag) + { + if ((file_hdr->c_filesize % 2) == 0) + swapping_bytes = true; + else + error (0, 0, _("cannot swap bytes of %s: odd number of bytes"), + file_hdr->c_name); + } + copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr->c_filesize); + disk_empty_output_buffer (out_file_des); + + if (to_stdout_option) + { + if (archive_format == arf_crcascii) + { + if (crc != file_hdr->c_chksum) + error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), + file_hdr->c_name, crc, file_hdr->c_chksum); + } + tape_skip_padding (in_file_des, file_hdr->c_filesize); + return; + } + + /* Debian hack to fix a bug in the --sparse option. + This bug has been reported to + "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */ + if (delayed_seek_count > 0) + { + lseek (out_file_des, delayed_seek_count-1, SEEK_CUR); + write (out_file_des, "", 1); + delayed_seek_count = 0; + } + if (close (out_file_des) < 0) + error (0, errno, "%s", file_hdr->c_name); + + if (archive_format == arf_crcascii) + { + if (crc != file_hdr->c_chksum) + error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), + file_hdr->c_name, crc, file_hdr->c_chksum); + } + + /* File is now copied; set attributes. */ + if (!no_chown_flag) + if ((chown (file_hdr->c_name, + set_owner_flag ? set_owner : file_hdr->c_uid, + set_group_flag ? set_group : file_hdr->c_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", file_hdr->c_name); + + /* chown may have turned off some permissions we wanted. */ + if (chmod (file_hdr->c_name, (int) file_hdr->c_mode) < 0) + error (0, errno, "%s", file_hdr->c_name); + + if (retain_time_flag) + { + struct utimbuf times; /* For setting file times. */ + /* Initialize this in case it has members we don't know to set. */ + bzero (×, sizeof (struct utimbuf)); + + times.actime = times.modtime = file_hdr->c_mtime; + if (utime (file_hdr->c_name, ×) < 0) + error (0, errno, "%s", file_hdr->c_name); + } + + tape_skip_padding (in_file_des, file_hdr->c_filesize); + if (file_hdr->c_nlink > 1 + && (archive_format == arf_newascii || archive_format == arf_crcascii) ) + { + /* (see comment above for how the newc and crc formats + store multiple links). Now that we have the data + for this file, create any other links to it which + we defered. */ + create_defered_links (file_hdr); + } +} + +static void +copyin_directory(struct new_cpio_header* file_hdr, int existing_dir) +{ + int res; /* Result of various function calls. */ +#ifdef HPUX_CDF + int cdf_flag; /* True if file is a CDF. */ + int cdf_char; /* Index of `+' char indicating a CDF. */ +#endif + + if (to_stdout_option) + return; + + /* Strip any trailing `/'s off the filename; tar puts + them on. We might as well do it here in case anybody + else does too, since they cause strange things to happen. */ + strip_trailing_slashes (file_hdr->c_name); + + /* Ignore the current directory. It must already exist, + and we don't want to change its permission, ownership + or time. */ + if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0') + { + return; + } + +#ifdef HPUX_CDF + cdf_flag = 0; +#endif + if (!existing_dir) + + { +#ifdef HPUX_CDF + /* If the directory name ends in a + and is SUID, + then it is a CDF. Strip the trailing + from + the name before creating it. */ + cdf_char = strlen (file_hdr->c_name) - 1; + if ( (cdf_char > 0) && + (file_hdr->c_mode & 04000) && + (file_hdr->c_name [cdf_char] == '+') ) + { + file_hdr->c_name [cdf_char] = '\0'; + cdf_flag = 1; + } +#endif + res = mkdir (file_hdr->c_name, file_hdr->c_mode); + } + else + res = 0; + if (res < 0 && create_dir_flag) + { + create_all_directories (file_hdr->c_name); + res = mkdir (file_hdr->c_name, file_hdr->c_mode); + } + if (res < 0) + { + /* In some odd cases where the file_hdr->c_name includes `.', + the directory may have actually been created by + create_all_directories(), so the mkdir will fail + because the directory exists. If that's the case, + don't complain about it. */ + struct stat file_stat; + if ( (errno != EEXIST) || + (lstat (file_hdr->c_name, &file_stat) != 0) || + !(S_ISDIR (file_stat.st_mode) ) ) + { + error (0, errno, "%s", file_hdr->c_name); + return; + } + } + if (!no_chown_flag) + if ((chown (file_hdr->c_name, + set_owner_flag ? set_owner : file_hdr->c_uid, + set_group_flag ? set_group : file_hdr->c_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", file_hdr->c_name); + /* chown may have turned off some permissions we wanted. */ + if (chmod (file_hdr->c_name, (int) file_hdr->c_mode) < 0) + error (0, errno, "%s", file_hdr->c_name); +#ifdef HPUX_CDF + if (cdf_flag) + /* Once we "hide" the directory with the chmod(), + we have to refer to it using name+ instead of name. */ + file_hdr->c_name [cdf_char] = '+'; +#endif + if (retain_time_flag) + { + struct utimbuf times; /* For setting file times. */ + /* Initialize this in case it has members we don't know to set. */ + bzero (×, sizeof (struct utimbuf)); + + times.actime = times.modtime = file_hdr->c_mtime; + if (utime (file_hdr->c_name, ×) < 0) + error (0, errno, "%s", file_hdr->c_name); + } +} + +static void +copyin_device(struct new_cpio_header* file_hdr) +{ + int res; /* Result of various function calls. */ + + if (to_stdout_option) + return; + + if (file_hdr->c_nlink > 1 && archive_format != arf_tar + && archive_format != arf_ustar) + { + int link_res; + /* Debian hack: This was reported by Horst + Knobloch. This bug has been reported to + "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */ + link_res = link_to_maj_min_ino (file_hdr->c_name, + file_hdr->c_dev_maj, file_hdr->c_dev_min, + file_hdr->c_ino); + if (link_res == 0) + { + return; + } + } + else if (archive_format == arf_ustar && + file_hdr->c_tar_linkname && + file_hdr->c_tar_linkname [0] != '\0') + { + int link_res; + link_res = link_to_name (file_hdr->c_name, + file_hdr->c_tar_linkname); + if (link_res < 0) + { + error (0, errno, _("cannot link %s to %s"), + file_hdr->c_tar_linkname, file_hdr->c_name); + /* Something must be wrong, because we couldn't + find the file to link to. But can we assume + that the device maj/min numbers are correct + and fall through to the mknod? It's probably + safer to just return, rather than possibly + creating a bogus device file. */ + } + return; + } + + res = mknod (file_hdr->c_name, file_hdr->c_mode, + makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min)); + if (res < 0 && create_dir_flag) + { + create_all_directories (file_hdr->c_name); + res = mknod (file_hdr->c_name, file_hdr->c_mode, + makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min)); + } + if (res < 0) + { + error (0, errno, "%s", file_hdr->c_name); + return; + } + if (!no_chown_flag) + if ((chown (file_hdr->c_name, + set_owner_flag ? set_owner : file_hdr->c_uid, + set_group_flag ? set_group : file_hdr->c_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", file_hdr->c_name); + /* chown may have turned off some permissions we wanted. */ + if (chmod (file_hdr->c_name, file_hdr->c_mode) < 0) + error (0, errno, "%s", file_hdr->c_name); + if (retain_time_flag) + { + struct utimbuf times; /* For setting file times. */ + /* Initialize this in case it has members we don't know to set. */ + bzero (×, sizeof (struct utimbuf)); + + times.actime = times.modtime = file_hdr->c_mtime; + if (utime (file_hdr->c_name, ×) < 0) + error (0, errno, "%s", file_hdr->c_name); + } +} + +static void +copyin_link(struct new_cpio_header *file_hdr, int in_file_des) +{ + char *link_name = NULL; /* Name of hard and symbolic links. */ + int res; /* Result of various function calls. */ + + if (to_stdout_option) + return; + + if (archive_format != arf_tar && archive_format != arf_ustar) + { + link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1); + link_name[file_hdr->c_filesize] = '\0'; + tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + } + else + { + link_name = xstrdup (file_hdr->c_tar_linkname); + } + + res = UMASKED_SYMLINK (link_name, file_hdr->c_name, + file_hdr->c_mode); + if (res < 0 && create_dir_flag) + { + create_all_directories (file_hdr->c_name); + res = UMASKED_SYMLINK (link_name, file_hdr->c_name, + file_hdr->c_mode); + } + if (res < 0) + { + error (0, errno, "%s", file_hdr->c_name); + free (link_name); + return; + } + if (!no_chown_flag) + if ((lchown (file_hdr->c_name, + set_owner_flag ? set_owner : file_hdr->c_uid, + set_group_flag ? set_group : file_hdr->c_gid) < 0) + && errno != EPERM) + { + error (0, errno, "%s", file_hdr->c_name); + } + free (link_name); +} + +static void +copyin_file (struct new_cpio_header* file_hdr, int in_file_des) +{ + int existing_dir; + + if (!to_stdout_option + && try_existing_file (file_hdr, in_file_des, &existing_dir) < 0) + return; + + /* Do the real copy or link. */ + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFREG: + copyin_regular_file(file_hdr, in_file_des); + break; + + case CP_IFDIR: + copyin_directory(file_hdr, existing_dir); + break; + + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + copyin_device(file_hdr); + break; + +#ifdef CP_IFLNK + case CP_IFLNK: + copyin_link(file_hdr, in_file_des); + break; +#endif + + default: + error (0, 0, _("%s: unknown file type"), file_hdr->c_name); + tape_toss_input (in_file_des, file_hdr->c_filesize); + tape_skip_padding (in_file_des, file_hdr->c_filesize); + } +} + + +/* Current time for verbose table. */ +static time_t current_time; + + +/* Print the file described by FILE_HDR in long format. + If LINK_NAME is nonzero, it is the name of the file that + this file is a symbolic link to. */ + +void +long_format (struct new_cpio_header *file_hdr, char *link_name) +{ + char mbuf[11]; + char tbuf[40]; + time_t when; + + mode_string (file_hdr->c_mode, mbuf); + mbuf[10] = '\0'; + + /* Get time values ready to print. */ + when = file_hdr->c_mtime; + strcpy (tbuf, ctime (&when)); + if (current_time - when > 6L * 30L * 24L * 60L * 60L + || current_time - when < 0L) + { + /* The file is older than 6 months, or in the future. + Show the year instead of the time of day. */ + strcpy (tbuf + 11, tbuf + 19); + } + tbuf[16] = '\0'; + + printf ("%s %3u ", mbuf, file_hdr->c_nlink); + + if (numeric_uid) + printf ("%-8u %-8u ", (unsigned int) file_hdr->c_uid, + (unsigned int) file_hdr->c_gid); + else + printf ("%-8.8s %-8.8s ", getuser (file_hdr->c_uid), + getgroup (file_hdr->c_gid)); + + if ((file_hdr->c_mode & CP_IFMT) == CP_IFCHR + || (file_hdr->c_mode & CP_IFMT) == CP_IFBLK) + printf ("%3u, %3u ", file_hdr->c_rdev_maj, + file_hdr->c_rdev_min); + else + printf ("%8lu ", file_hdr->c_filesize); + + printf ("%s ", tbuf + 4); + + print_name_with_quoting (file_hdr->c_name); + if (link_name) + { + printf (" -> "); + print_name_with_quoting (link_name); + } + putc ('\n', stdout); +} + +void +print_name_with_quoting (register char *p) +{ + register unsigned char c; + + while ( (c = *p++) ) + { + switch (c) + { + case '\\': + printf ("\\\\"); + break; + + case '\n': + printf ("\\n"); + break; + + case '\b': + printf ("\\b"); + break; + + case '\r': + printf ("\\r"); + break; + + case '\t': + printf ("\\t"); + break; + + case '\f': + printf ("\\f"); + break; + + case ' ': + printf ("\\ "); + break; + + case '"': + printf ("\\\""); + break; + + default: + if (c > 040 && c < 0177) + putchar (c); + else + printf ("\\%03o", (unsigned int) c); + } + } +} + +/* Read a pattern file (for the -E option). Put a list of + `num_patterns' elements in `save_patterns'. Any patterns that were + already in `save_patterns' (from the command line) are preserved. */ + +static void +read_pattern_file () +{ + int max_new_patterns; + char **new_save_patterns; + int new_num_patterns; + int i; + dynamic_string pattern_name; + FILE *pattern_fp; + + if (num_patterns < 0) + num_patterns = 0; + max_new_patterns = 1 + num_patterns; + new_save_patterns = (char **) xmalloc (max_new_patterns * sizeof (char *)); + new_num_patterns = num_patterns; + ds_init (&pattern_name, 128); + + pattern_fp = fopen (pattern_file_name, "r"); + if (pattern_fp == NULL) + error (1, errno, "%s", pattern_file_name); + while (ds_fgetstr (pattern_fp, &pattern_name, '\n') != NULL) + { + if (new_num_patterns >= max_new_patterns) + { + max_new_patterns += 1; + new_save_patterns = (char **) + xrealloc ((char *) new_save_patterns, + max_new_patterns * sizeof (char *)); + } + new_save_patterns[new_num_patterns] = xstrdup (pattern_name.ds_string); + ++new_num_patterns; + } + if (ferror (pattern_fp) || fclose (pattern_fp) == EOF) + error (1, errno, "%s", pattern_file_name); + + for (i = 0; i < num_patterns; ++i) + new_save_patterns[i] = save_patterns[i]; + + save_patterns = new_save_patterns; + num_patterns = new_num_patterns; +} + + + + +/* Return 16-bit integer I with the bytes swapped. */ +#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff)) + +/* Read the header, including the name of the file, from file + descriptor IN_DES into FILE_HDR. */ + +void +read_in_header (struct new_cpio_header *file_hdr, int in_des) +{ + long bytes_skipped = 0; /* Bytes of junk found before magic number. */ + + /* Search for a valid magic number. */ + + if (archive_format == arf_unknown) + { + char tmpbuf[512]; + int check_tar; + int peeked_bytes; + + while (archive_format == arf_unknown) + { + peeked_bytes = tape_buffered_peek (tmpbuf, in_des, 512); + if (peeked_bytes < 6) + error (1, 0, _("premature end of archive")); + + if (!strncmp (tmpbuf, "070701", 6)) + archive_format = arf_newascii; + else if (!strncmp (tmpbuf, "070707", 6)) + archive_format = arf_oldascii; + else if (!strncmp (tmpbuf, "070702", 6)) + { + archive_format = arf_crcascii; + crc_i_flag = true; + } + else if ((*((unsigned short *) tmpbuf) == 070707) || + (*((unsigned short *) tmpbuf) == swab_short ((unsigned short) 070707))) + archive_format = arf_binary; + else if (peeked_bytes >= 512 + && (check_tar = is_tar_header (tmpbuf))) + { + if (check_tar == 2) + archive_format = arf_ustar; + else + archive_format = arf_tar; + } + else + { + tape_buffered_read ((char *) tmpbuf, in_des, 1L); + ++bytes_skipped; + } + } + } + + if (archive_format == arf_tar || archive_format == arf_ustar) + { + if (append_flag) + last_header_start = input_bytes - io_block_size + + (in_buff - input_buffer); + if (bytes_skipped > 0) + warn_junk_bytes (bytes_skipped); + + read_in_tar_header (file_hdr, in_des); + return; + } + + file_hdr->c_tar_linkname = NULL; + + tape_buffered_read ((char *) file_hdr, in_des, 6L); + while (1) + { + if (append_flag) + last_header_start = input_bytes - io_block_size + + (in_buff - input_buffer) - 6; + if (archive_format == arf_newascii + && !strncmp ((char *) file_hdr, "070701", 6)) + { + if (bytes_skipped > 0) + warn_junk_bytes (bytes_skipped); + read_in_new_ascii (file_hdr, in_des); + break; + } + if (archive_format == arf_crcascii + && !strncmp ((char *) file_hdr, "070702", 6)) + { + if (bytes_skipped > 0) + warn_junk_bytes (bytes_skipped); + + read_in_new_ascii (file_hdr, in_des); + break; + } + if ( (archive_format == arf_oldascii || archive_format == arf_hpoldascii) + && !strncmp ((char *) file_hdr, "070707", 6)) + { + if (bytes_skipped > 0) + warn_junk_bytes (bytes_skipped); + + read_in_old_ascii (file_hdr, in_des); + break; + } + if ( (archive_format == arf_binary || archive_format == arf_hpbinary) + && (file_hdr->c_magic == 070707 + || file_hdr->c_magic == swab_short ((unsigned short) 070707))) + { + /* Having to skip 1 byte because of word alignment is normal. */ + if (bytes_skipped > 0) + warn_junk_bytes (bytes_skipped); + + read_in_binary (file_hdr, in_des); + break; + } + bytes_skipped++; + bcopy ((char *) file_hdr + 1, (char *) file_hdr, 5); + tape_buffered_read ((char *) file_hdr + 5, in_des, 1L); + } +} + +/* Fill in FILE_HDR by reading an old-format ASCII format cpio header from + file descriptor IN_DES, except for the magic number, which is + already filled in. */ + +void +read_in_old_ascii (struct new_cpio_header *file_hdr, int in_des) +{ + char ascii_header[78]; + unsigned long dev; + unsigned long rdev; + + tape_buffered_read (ascii_header, in_des, 70L); + ascii_header[70] = '\0'; + sscanf (ascii_header, + "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo", + &dev, &file_hdr->c_ino, + &file_hdr->c_mode, &file_hdr->c_uid, &file_hdr->c_gid, + &file_hdr->c_nlink, &rdev, &file_hdr->c_mtime, + &file_hdr->c_namesize, &file_hdr->c_filesize); + file_hdr->c_dev_maj = major (dev); + file_hdr->c_dev_min = minor (dev); + file_hdr->c_rdev_maj = major (rdev); + file_hdr->c_rdev_min = minor (rdev); + + /* Read file name from input. */ + if (file_hdr->c_name != NULL) + free (file_hdr->c_name); + file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize + 1); + tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize); + + /* HP/UX cpio creates archives that look just like ordinary archives, + but for devices it sets major = 0, minor = 1, and puts the + actual major/minor number in the filesize field. See if this + is an HP/UX cpio archive, and if so fix it. We have to do this + here because process_copy_in() assumes filesize is always 0 + for devices. */ + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + if (file_hdr->c_filesize != 0 + && file_hdr->c_rdev_maj == 0 + && file_hdr->c_rdev_min == 1) + { + file_hdr->c_rdev_maj = major (file_hdr->c_filesize); + file_hdr->c_rdev_min = minor (file_hdr->c_filesize); + file_hdr->c_filesize = 0; + } + break; + default: + break; + } +} + +/* Fill in FILE_HDR by reading a new-format ASCII format cpio header from + file descriptor IN_DES, except for the magic number, which is + already filled in. */ + +void +read_in_new_ascii (struct new_cpio_header *file_hdr, int in_des) +{ + char ascii_header[112]; + + tape_buffered_read (ascii_header, in_des, 104L); + ascii_header[104] = '\0'; + sscanf (ascii_header, + "%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx", + &file_hdr->c_ino, &file_hdr->c_mode, &file_hdr->c_uid, + &file_hdr->c_gid, &file_hdr->c_nlink, &file_hdr->c_mtime, + &file_hdr->c_filesize, &file_hdr->c_dev_maj, &file_hdr->c_dev_min, + &file_hdr->c_rdev_maj, &file_hdr->c_rdev_min, &file_hdr->c_namesize, + &file_hdr->c_chksum); + /* Read file name from input. */ + if (file_hdr->c_name != NULL) + free (file_hdr->c_name); + file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize); + tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize); + + /* In SVR4 ASCII format, the amount of space allocated for the header + is rounded up to the next long-word, so we might need to drop + 1-3 bytes. */ + tape_skip_padding (in_des, file_hdr->c_namesize + 110); +} + +/* Fill in FILE_HDR by reading a binary format cpio header from + file descriptor IN_DES, except for the first 6 bytes (the magic + number, device, and inode number), which are already filled in. */ + +void +read_in_binary (struct new_cpio_header *file_hdr, int in_des) +{ + struct old_cpio_header short_hdr; + + /* Copy the data into the short header, then later transfer + it into the argument long header. */ + short_hdr.c_dev = ((struct old_cpio_header *) file_hdr)->c_dev; + short_hdr.c_ino = ((struct old_cpio_header *) file_hdr)->c_ino; + tape_buffered_read (((char *) &short_hdr) + 6, in_des, 20L); + + /* If the magic number is byte swapped, fix the header. */ + if (file_hdr->c_magic == swab_short ((unsigned short) 070707)) + { + static int warned = 0; + + /* Alert the user that they might have to do byte swapping on + the file contents. */ + if (warned == 0) + { + error (0, 0, _("warning: archive header has reverse byte-order")); + warned = 1; + } + swab_array ((char *) &short_hdr, 13); + } + + file_hdr->c_dev_maj = major (short_hdr.c_dev); + file_hdr->c_dev_min = minor (short_hdr.c_dev); + file_hdr->c_ino = short_hdr.c_ino; + file_hdr->c_mode = short_hdr.c_mode; + file_hdr->c_uid = short_hdr.c_uid; + file_hdr->c_gid = short_hdr.c_gid; + file_hdr->c_nlink = short_hdr.c_nlink; + file_hdr->c_rdev_maj = major (short_hdr.c_rdev); + file_hdr->c_rdev_min = minor (short_hdr.c_rdev); + file_hdr->c_mtime = (unsigned long) short_hdr.c_mtimes[0] << 16 + | short_hdr.c_mtimes[1]; + + file_hdr->c_namesize = short_hdr.c_namesize; + file_hdr->c_filesize = (unsigned long) short_hdr.c_filesizes[0] << 16 + | short_hdr.c_filesizes[1]; + + /* Read file name from input. */ + if (file_hdr->c_name != NULL) + free (file_hdr->c_name); + file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize); + tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize); + + /* In binary mode, the amount of space allocated in the header for + the filename is `c_namesize' rounded up to the next short-word, + so we might need to drop a byte. */ + if (file_hdr->c_namesize % 2) + tape_toss_input (in_des, 1L); + + /* HP/UX cpio creates archives that look just like ordinary archives, + but for devices it sets major = 0, minor = 1, and puts the + actual major/minor number in the filesize field. See if this + is an HP/UX cpio archive, and if so fix it. We have to do this + here because process_copy_in() assumes filesize is always 0 + for devices. */ + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + if (file_hdr->c_filesize != 0 + && file_hdr->c_rdev_maj == 0 + && file_hdr->c_rdev_min == 1) + { + file_hdr->c_rdev_maj = major (file_hdr->c_filesize); + file_hdr->c_rdev_min = minor (file_hdr->c_filesize); + file_hdr->c_filesize = 0; + } + break; + default: + break; + } +} + +/* Exchange the bytes of each element of the array of COUNT shorts + starting at PTR. */ + +void +swab_array (char *ptr, int count) +{ + char tmp; + + while (count-- > 0) + { + tmp = *ptr; + *ptr = *(ptr + 1); + ++ptr; + *ptr = tmp; + ++ptr; + } +} + +/* Read the collection from standard input and create files + in the file system. */ + +void +process_copy_in () +{ + char done = false; /* True if trailer reached. */ + FILE *tty_in; /* Interactive file for rename option. */ + FILE *tty_out; /* Interactive file for rename option. */ + FILE *rename_in; /* Batch file for rename option. */ + struct stat file_stat; /* Output file stat record. */ + struct new_cpio_header file_hdr; /* Output header information. */ + int in_file_des; /* Input file descriptor. */ + char skip_file; /* Flag for use with patterns. */ + int i; /* Loop index variable. */ + + /* Initialize the copy in. */ + if (pattern_file_name) + { + read_pattern_file (); + } + file_hdr.c_name = NULL; + + if (rename_batch_file) + { + rename_in = fopen (rename_batch_file, "r"); + if (rename_in == NULL) + { + error (2, errno, TTY_NAME); + } + } + else if (rename_flag) + { + /* Open interactive file pair for rename operation. */ + tty_in = fopen (TTY_NAME, "r"); + if (tty_in == NULL) + { + error (2, errno, TTY_NAME); + } + tty_out = fopen (TTY_NAME, "w"); + if (tty_out == NULL) + { + error (2, errno, TTY_NAME); + } + } + + /* Get date and time if needed for processing the table option. */ + if (table_flag && verbose_flag) + { + time (¤t_time); + } + + /* Check whether the input file might be a tape. */ + in_file_des = archive_des; + if (_isrmt (in_file_des)) + { + input_is_special = 1; + input_is_seekable = 0; + } + else + { + if (fstat (in_file_des, &file_stat)) + error (1, errno, _("standard input is closed")); + input_is_special = +#ifdef S_ISBLK + S_ISBLK (file_stat.st_mode) || +#endif + S_ISCHR (file_stat.st_mode); + input_is_seekable = S_ISREG (file_stat.st_mode); + } + output_is_seekable = true; + + /* While there is more input in the collection, process the input. */ + while (!done) + { + swapping_halfwords = swapping_bytes = false; + + /* Start processing the next file by reading the header. */ + read_in_header (&file_hdr, in_file_des); + +#ifdef DEBUG_CPIO + if (debug_flag) + { + struct new_cpio_header *h; + h = &file_hdr; + fprintf (stderr, + "magic = 0%o, ino = %d, mode = 0%o, uid = %d, gid = %d\n", + h->c_magic, h->c_ino, h->c_mode, h->c_uid, h->c_gid); + fprintf (stderr, + "nlink = %d, mtime = %d, filesize = %d, dev_maj = 0x%x\n", + h->c_nlink, h->c_mtime, h->c_filesize, h->c_dev_maj); + fprintf (stderr, + "dev_min = 0x%x, rdev_maj = 0x%x, rdev_min = 0x%x, namesize = %d\n", + h->c_dev_min, h->c_rdev_maj, h->c_rdev_min, h->c_namesize); + fprintf (stderr, + "chksum = %d, name = \"%s\", tar_linkname = \"%s\"\n", + h->c_chksum, h->c_name, + h->c_tar_linkname ? h->c_tar_linkname : "(null)" ); + + } +#endif + /* Is this the header for the TRAILER file? */ + if (strcmp ("TRAILER!!!", file_hdr.c_name) == 0) + { + done = true; + break; + } + + /* Do we have to ignore absolute paths, and if so, does the filename + have an absolute path? */ + if (no_abs_paths_flag && file_hdr.c_name && file_hdr.c_name [0] == '/') + { + char *p; + + p = file_hdr.c_name; + while (*p == '/') + ++p; + if (*p == '\0') + { + strcpy (file_hdr.c_name, "."); + } + else + { + /* Debian hack: file_hrd.c_name is sometimes set to + point to static memory by code in tar.c. This + causes a segfault. Therefore, memmove is used + instead of freeing and reallocating. (Reported by + Horst Knobloch.) This bug has been reported to + "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */ + (void)memmove (file_hdr.c_name, p, (size_t)(strlen (p) + 1)); + } + } + + /* Does the file name match one of the given patterns? */ + if (num_patterns <= 0) + skip_file = false; + else + { + skip_file = copy_matching_files; + for (i = 0; i < num_patterns + && skip_file == copy_matching_files; i++) + { + if (fnmatch (save_patterns[i], file_hdr.c_name, 0) == 0) + skip_file = !copy_matching_files; + } + } + + if (skip_file) + { + /* If we're skipping a file with links, there might be other + links that we didn't skip, and this file might have the + data for the links. If it does, we'll copy in the data + to the links, but not to this file. */ + if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii + || archive_format == arf_crcascii) ) + { + if (create_defered_links_to_skipped(&file_hdr, in_file_des) < 0) + { + tape_toss_input (in_file_des, file_hdr.c_filesize); + tape_skip_padding (in_file_des, file_hdr.c_filesize); + } + } + else + { + tape_toss_input (in_file_des, file_hdr.c_filesize); + tape_skip_padding (in_file_des, file_hdr.c_filesize); + } + } + else if (table_flag) + { + list_file(&file_hdr, in_file_des); + } + else if (append_flag) + { + tape_toss_input (in_file_des, file_hdr.c_filesize); + tape_skip_padding (in_file_des, file_hdr.c_filesize); + } + else if (only_verify_crc_flag) + { +#ifdef CP_IFLNK + if ((file_hdr.c_mode & CP_IFMT) == CP_IFLNK) + { + if (archive_format != arf_tar && archive_format != arf_ustar) + { + tape_toss_input (in_file_des, file_hdr.c_filesize); + tape_skip_padding (in_file_des, file_hdr.c_filesize); + continue; + } + } +#endif + crc = 0; + tape_toss_input (in_file_des, file_hdr.c_filesize); + tape_skip_padding (in_file_des, file_hdr.c_filesize); + if (crc != file_hdr.c_chksum) + { + error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), + file_hdr.c_name, crc, file_hdr.c_chksum); + } + /* Debian hack: -v and -V now work with --only-verify-crc. + (99/11/10) -BEM */ + if (verbose_flag) + { + fprintf (stderr, "%s\n", file_hdr.c_name); + } + if (dot_flag) + { + fputc ('.', stderr); + } + } + else + { + /* Copy the input file into the directory structure. */ + + /* Do we need to rename the file? */ + if (rename_flag || rename_batch_file) + { + if (query_rename(&file_hdr, tty_in, tty_out, rename_in) < 0) + { + tape_toss_input (in_file_des, file_hdr.c_filesize); + tape_skip_padding (in_file_des, file_hdr.c_filesize); + continue; + } + } + + copyin_file(&file_hdr, in_file_des); + + if (verbose_flag) + fprintf (stderr, "%s\n", file_hdr.c_name); + if (dot_flag) + fputc ('.', stderr); + } + } + + if (dot_flag) + fputc ('\n', stderr); + + if (append_flag) + return; + + if (archive_format == arf_newascii || archive_format == arf_crcascii) + { + create_final_defers (); + } + if (!quiet_flag) + { + int blocks; + blocks = (input_bytes + io_block_size - 1) / io_block_size; + fprintf (stderr, ngettext ("%d block\n", "%d blocks\n", blocks), blocks); + } +} + diff --git a/contrib/cpio/src/copyout.c b/contrib/cpio/src/copyout.c new file mode 100644 index 0000000..23da993 --- /dev/null +++ b/contrib/cpio/src/copyout.c @@ -0,0 +1,803 @@ +/* copyout.c - create a cpio archive + Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <system.h> + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "filetypes.h" +#include "cpiohdr.h" +#include "dstring.h" +#include "extern.h" +#include "defer.h" +#include <rmt.h> + +/* Read FILE_SIZE bytes of FILE_NAME from IN_FILE_DES and + compute and return a checksum for them. */ + +static unsigned long +read_for_checksum (int in_file_des, int file_size, char *file_name) +{ + unsigned long crc; + char buf[BUFSIZ]; + int bytes_left; + int bytes_read; + int i; + + crc = 0; + + for (bytes_left = file_size; bytes_left > 0; bytes_left -= bytes_read) + { + bytes_read = read (in_file_des, buf, BUFSIZ); + if (bytes_read < 0) + error (1, errno, _("cannot read checksum for %s"), file_name); + if (bytes_read == 0) + break; + if (bytes_left < bytes_read) + bytes_read = bytes_left; + for (i = 0; i < bytes_read; ++i) + crc += buf[i] & 0xff; + } + if (lseek (in_file_des, 0L, SEEK_SET)) + error (1, errno, _("cannot read checksum for %s"), file_name); + + return crc; +} + +/* Write out NULs to fill out the rest of the current block on + OUT_FILE_DES. */ + +static void +tape_clear_rest_of_block (int out_file_des) +{ + while (output_size < io_block_size) + { + if ((io_block_size - output_size) > 512) + tape_buffered_write (zeros_512, out_file_des, 512); + else + tape_buffered_write (zeros_512, out_file_des, io_block_size - output_size); + } +} + +/* Write NULs on OUT_FILE_DES to move from OFFSET (the current location) + to the end of the header. */ + +static void +tape_pad_output (int out_file_des, int offset) +{ + int pad; + + if (archive_format == arf_newascii || archive_format == arf_crcascii) + pad = (4 - (offset % 4)) % 4; + else if (archive_format == arf_tar || archive_format == arf_ustar) + pad = (512 - (offset % 512)) % 512; + else if (archive_format != arf_oldascii && archive_format != arf_hpoldascii) + pad = (2 - (offset % 2)) % 2; + else + pad = 0; + + if (pad != 0) + tape_buffered_write (zeros_512, out_file_des, pad); +} + + +/* When creating newc and crc archives if a file has multiple (hard) + links, we don't put any of them into the archive until we have seen + all of them (or until we get to the end of the list of files that + are going into the archive and know that we have seen all of the links + to the file that we will see). We keep these "defered" files on + this list. */ + +struct deferment *deferouts = NULL; + +/* Count the number of other (hard) links to this file that have + already been defered. */ + +static int +count_defered_links_to_dev_ino (struct new_cpio_header *file_hdr) +{ + struct deferment *d; + int ino; + int maj; + int min; + int count; + ino = file_hdr->c_ino; + maj = file_hdr->c_dev_maj; + min = file_hdr->c_dev_min; + count = 0; + for (d = deferouts; d != NULL; d = d->next) + { + if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj) + && (d->header.c_dev_min == min) ) + ++count; + } + return count; +} + +/* Is this file_hdr the last (hard) link to a file? I.e., have + we already seen and defered all of the other links? */ + +static int +last_link (struct new_cpio_header *file_hdr) +{ + int other_files_sofar; + + other_files_sofar = count_defered_links_to_dev_ino (file_hdr); + if (file_hdr->c_nlink == (other_files_sofar + 1) ) + { + return 1; + } + return 0; +} + + +/* Add the file header for a link that is being defered to the deferouts + list. */ + +static void +add_link_defer (struct new_cpio_header *file_hdr) +{ + struct deferment *d; + d = create_deferment (file_hdr); + d->next = deferouts; + deferouts = d; +} + +/* We are about to put a file into a newc or crc archive that is + multiply linked. We have already seen and defered all of the + other links to the file but haven't written them into the archive. + Write the other links into the archive, and remove them from the + deferouts list. */ + +static void +writeout_other_defers (struct new_cpio_header *file_hdr, int out_des) +{ + struct deferment *d; + struct deferment *d_prev; + int ino; + int maj; + int min; + ino = file_hdr->c_ino; + maj = file_hdr->c_dev_maj; + min = file_hdr->c_dev_min; + d_prev = NULL; + d = deferouts; + while (d != NULL) + { + if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj) + && (d->header.c_dev_min == min) ) + { + struct deferment *d_free; + d->header.c_filesize = 0; + write_out_header (&d->header, out_des); + if (d_prev != NULL) + d_prev->next = d->next; + else + deferouts = d->next; + d_free = d; + d = d->next; + free_deferment (d_free); + } + else + { + d_prev = d; + d = d->next; + } + } + return; +} + +/* Write a file into the archive. This code is the same as + the code in process_copy_out(), but we need it here too + for writeout_final_defers() to call. */ + +static void +writeout_defered_file (struct new_cpio_header *header, int out_file_des) +{ + int in_file_des; + struct new_cpio_header file_hdr; + struct utimbuf times; /* For setting file times. */ + /* Initialize this in case it has members we don't know to set. */ + bzero (×, sizeof (struct utimbuf)); + + file_hdr = *header; + + + in_file_des = open (header->c_name, + O_RDONLY | O_BINARY, 0); + if (in_file_des < 0) + { + error (0, errno, "%s", header->c_name); + return; + } + + if (archive_format == arf_crcascii) + file_hdr.c_chksum = read_for_checksum (in_file_des, + file_hdr.c_filesize, + header->c_name); + + write_out_header (&file_hdr, out_file_des); + copy_files_disk_to_tape (in_file_des, out_file_des, file_hdr.c_filesize, header->c_name); + warn_if_file_changed(header->c_name, file_hdr.c_filesize, file_hdr.c_mtime); + + if (archive_format == arf_tar || archive_format == arf_ustar) + add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj, + file_hdr.c_dev_min); + + tape_pad_output (out_file_des, file_hdr.c_filesize); + + if (close (in_file_des) < 0) + error (0, errno, "%s", header->c_name); + if (reset_time_flag) + { + times.actime = file_hdr.c_mtime; + times.modtime = file_hdr.c_mtime; + /* Debian hack: Silently ignore EROFS because reading the file + won't have upset its timestamp if it's on a read-only + filesystem. This has been submitted as a suggestion to + "bug-gnu-utils@prep.ai.mit.edu". -BEM */ + if (utime (file_hdr.c_name, ×) < 0 + && errno != EROFS) + error (0, errno, "%s", file_hdr.c_name); + } + return; +} + +/* When writing newc and crc format archives we defer multiply linked + files until we have seen all of the links to the file. If a file + has links to it that aren't going into the archive, then we will + never see the "last" link to the file, so at the end we just write + all of the leftover defered files into the archive. */ + +static void +writeout_final_defers (int out_des) +{ + struct deferment *d; + int other_count; + while (deferouts != NULL) + { + d = deferouts; + other_count = count_defered_links_to_dev_ino (&d->header); + if (other_count == 1) + { + writeout_defered_file (&d->header, out_des); + } + else + { + struct new_cpio_header file_hdr; + file_hdr = d->header; + file_hdr.c_filesize = 0; + write_out_header (&file_hdr, out_des); + } + deferouts = deferouts->next; + } +} + + +/* Write out header FILE_HDR, including the file name, to file + descriptor OUT_DES. */ + +void +write_out_header (struct new_cpio_header *file_hdr, int out_des) +{ + if (archive_format == arf_newascii || archive_format == arf_crcascii) + { + char ascii_header[112]; + char *magic_string; + + if (archive_format == arf_crcascii) + magic_string = "070702"; + else + magic_string = "070701"; + sprintf (ascii_header, + "%6s%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx", + magic_string, + file_hdr->c_ino, file_hdr->c_mode, file_hdr->c_uid, + file_hdr->c_gid, file_hdr->c_nlink, file_hdr->c_mtime, + file_hdr->c_filesize, file_hdr->c_dev_maj, file_hdr->c_dev_min, + file_hdr->c_rdev_maj, file_hdr->c_rdev_min, file_hdr->c_namesize, + file_hdr->c_chksum); + tape_buffered_write (ascii_header, out_des, 110L); + + /* Write file name to output. */ + tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize); + tape_pad_output (out_des, file_hdr->c_namesize + 110); + } + else if (archive_format == arf_oldascii || archive_format == arf_hpoldascii) + { + char ascii_header[78]; + dev_t dev; + dev_t rdev; + + if (archive_format == arf_oldascii) + { + dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min); + rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min); + } + else + { + /* HP/UX cpio creates archives that look just like ordinary archives, + but for devices it sets major = 0, minor = 1, and puts the + actual major/minor number in the filesize field. */ + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + file_hdr->c_filesize = makedev (file_hdr->c_rdev_maj, + file_hdr->c_rdev_min); + rdev = 1; + break; + default: + dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min); + rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min); + break; + } + } + + if ((warn_option & CPIO_WARN_TRUNCATE) && (file_hdr->c_ino >> 16) != 0) + error (0, 0, _("%s: truncating inode number"), file_hdr->c_name); + + /* Debian hack: The type of dev_t has changed in glibc. Fixed output + to ensure that a long int is passed to sprintf. This has been + reported to "bug-gnu-utils@prep.ai.mit.edu". (1998/5/26) -BEM */ + sprintf (ascii_header, + "%06ho%06lo%06lo%06lo%06lo%06lo%06lo%06lo%011lo%06lo%011lo", + file_hdr->c_magic & 0xFFFF, (long) dev & 0xFFFF, + file_hdr->c_ino & 0xFFFF, file_hdr->c_mode & 0xFFFF, + file_hdr->c_uid & 0xFFFF, file_hdr->c_gid & 0xFFFF, + file_hdr->c_nlink & 0xFFFF, (long) rdev & 0xFFFF, + file_hdr->c_mtime, file_hdr->c_namesize & 0xFFFF, + file_hdr->c_filesize); + tape_buffered_write (ascii_header, out_des, 76L); + + /* Write file name to output. */ + tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize); + } + else if (archive_format == arf_tar || archive_format == arf_ustar) + { + write_out_tar_header (file_hdr, out_des); + } + else + { + struct old_cpio_header short_hdr; + + short_hdr.c_magic = 070707; + short_hdr.c_dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min); + + if ((warn_option & CPIO_WARN_TRUNCATE) && (file_hdr->c_ino >> 16) != 0) + error (0, 0, _("%s: truncating inode number"), file_hdr->c_name); + + short_hdr.c_ino = file_hdr->c_ino & 0xFFFF; + short_hdr.c_mode = file_hdr->c_mode & 0xFFFF; + short_hdr.c_uid = file_hdr->c_uid & 0xFFFF; + short_hdr.c_gid = file_hdr->c_gid & 0xFFFF; + short_hdr.c_nlink = file_hdr->c_nlink & 0xFFFF; + if (archive_format != arf_hpbinary) + short_hdr.c_rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min); + else + { + switch (file_hdr->c_mode & CP_IFMT) + { + /* HP/UX cpio creates archives that look just like ordinary + archives, but for devices it sets major = 0, minor = 1, and + puts the actual major/minor number in the filesize field. */ + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + file_hdr->c_filesize = makedev (file_hdr->c_rdev_maj, + file_hdr->c_rdev_min); + short_hdr.c_rdev = makedev (0, 1); + break; + default: + short_hdr.c_rdev = makedev (file_hdr->c_rdev_maj, + file_hdr->c_rdev_min); + break; + } + } + short_hdr.c_mtimes[0] = file_hdr->c_mtime >> 16; + short_hdr.c_mtimes[1] = file_hdr->c_mtime & 0xFFFF; + + short_hdr.c_namesize = file_hdr->c_namesize & 0xFFFF; + + short_hdr.c_filesizes[0] = file_hdr->c_filesize >> 16; + short_hdr.c_filesizes[1] = file_hdr->c_filesize & 0xFFFF; + + /* Output the file header. */ + tape_buffered_write ((char *) &short_hdr, out_des, 26L); + + /* Write file name to output. */ + tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize); + + tape_pad_output (out_des, file_hdr->c_namesize + 26); + } +} + +/* Read a list of file names from the standard input + and write a cpio collection on the standard output. + The format of the header depends on the compatibility (-c) flag. */ + +void +process_copy_out () +{ + int res; /* Result of functions. */ + dynamic_string input_name; /* Name of file read from stdin. */ + struct utimbuf times; /* For resetting file times after copy. */ + struct stat file_stat; /* Stat record for file. */ + struct new_cpio_header file_hdr; /* Output header information. */ + int in_file_des; /* Source file descriptor. */ + int out_file_des; /* Output file descriptor. */ + char *p; + + /* Initialize the copy out. */ + ds_init (&input_name, 128); + /* Initialize this in case it has members we don't know to set. */ + bzero (×, sizeof (struct utimbuf)); + file_hdr.c_magic = 070707; + + /* Check whether the output file might be a tape. */ + out_file_des = archive_des; + if (_isrmt (out_file_des)) + { + output_is_special = 1; + output_is_seekable = 0; + } + else + { + if (fstat (out_file_des, &file_stat)) + error (1, errno, _("standard output is closed")); + output_is_special = +#ifdef S_ISBLK + S_ISBLK (file_stat.st_mode) || +#endif + S_ISCHR (file_stat.st_mode); + output_is_seekable = S_ISREG (file_stat.st_mode); + } + + if (append_flag) + { + process_copy_in (); + prepare_append (out_file_des); + } + + /* Copy files with names read from stdin. */ + while (ds_fgetstr (stdin, &input_name, name_end) != NULL) + { + /* Check for blank line. */ + if (input_name.ds_string[0] == 0) + { + error (0, 0, _("blank line ignored")); + continue; + } + + /* Process next file. */ + if ((*xstat) (input_name.ds_string, &file_stat) < 0) + error (0, errno, "%s", input_name.ds_string); + else + { + /* Set values in output header. */ + file_hdr.c_dev_maj = major (file_stat.st_dev); + file_hdr.c_dev_min = minor (file_stat.st_dev); + file_hdr.c_ino = file_stat.st_ino; + /* For POSIX systems that don't define the S_IF macros, + we can't assume that S_ISfoo means the standard Unix + S_IFfoo bit(s) are set. So do it manually, with a + different name. Bleah. */ + file_hdr.c_mode = (file_stat.st_mode & 07777); + if (S_ISREG (file_stat.st_mode)) + file_hdr.c_mode |= CP_IFREG; + else if (S_ISDIR (file_stat.st_mode)) + file_hdr.c_mode |= CP_IFDIR; +#ifdef S_ISBLK + else if (S_ISBLK (file_stat.st_mode)) + file_hdr.c_mode |= CP_IFBLK; +#endif +#ifdef S_ISCHR + else if (S_ISCHR (file_stat.st_mode)) + file_hdr.c_mode |= CP_IFCHR; +#endif +#ifdef S_ISFIFO + else if (S_ISFIFO (file_stat.st_mode)) + file_hdr.c_mode |= CP_IFIFO; +#endif +#ifdef S_ISLNK + else if (S_ISLNK (file_stat.st_mode)) + file_hdr.c_mode |= CP_IFLNK; +#endif +#ifdef S_ISSOCK + else if (S_ISSOCK (file_stat.st_mode)) + file_hdr.c_mode |= CP_IFSOCK; +#endif +#ifdef S_ISNWK + else if (S_ISNWK (file_stat.st_mode)) + file_hdr.c_mode |= CP_IFNWK; +#endif + file_hdr.c_uid = file_stat.st_uid; + file_hdr.c_gid = file_stat.st_gid; + file_hdr.c_nlink = file_stat.st_nlink; + file_hdr.c_rdev_maj = major (file_stat.st_rdev); + file_hdr.c_rdev_min = minor (file_stat.st_rdev); + file_hdr.c_mtime = file_stat.st_mtime; + file_hdr.c_filesize = file_stat.st_size; + file_hdr.c_chksum = 0; + file_hdr.c_tar_linkname = NULL; + + if (archive_format == arf_tar || archive_format == arf_ustar) + { + if (file_hdr.c_mode & CP_IFDIR) + { + int len = strlen (input_name.ds_string); + /* Make sure the name ends with a slash */ + if (input_name.ds_string[len-1] != '/') + { + ds_resize (&input_name, len + 2); + input_name.ds_string[len] = '/'; + input_name.ds_string[len+1] = 0; + } + } + } + + /* Strip leading `./' from the filename. */ + p = input_name.ds_string; + while (*p == '.' && *(p + 1) == '/') + { + ++p; + while (*p == '/') + ++p; + } +#ifndef HPUX_CDF + file_hdr.c_name = p; + file_hdr.c_namesize = strlen (p) + 1; +#else + if ( (archive_format != arf_tar) && (archive_format != arf_ustar) ) + { + /* We mark CDF's in cpio files by adding a 2nd `/' after the + "hidden" directory name. We need to do this so we can + properly recreate the directory as hidden (in case the + files of a directory go into the archive before the + directory itself (e.g from "find ... -depth ... | cpio")). */ + file_hdr.c_name = add_cdf_double_slashes (p); + file_hdr.c_namesize = strlen (file_hdr.c_name) + 1; + } + else + { + /* We don't mark CDF's in tar files. We assume the "hidden" + directory will always go into the archive before any of + its files. */ + file_hdr.c_name = p; + file_hdr.c_namesize = strlen (p) + 1; + } +#endif + if ((archive_format == arf_tar || archive_format == arf_ustar) + && is_tar_filename_too_long (file_hdr.c_name)) + { + error (0, 0, _("%s: file name too long"), + file_hdr.c_name); + continue; + } + + /* Copy the named file to the output. */ + switch (file_hdr.c_mode & CP_IFMT) + { + case CP_IFREG: + if (archive_format == arf_tar || archive_format == arf_ustar) + { + char *otherfile; + if ((otherfile = find_inode_file (file_hdr.c_ino, + file_hdr.c_dev_maj, + file_hdr.c_dev_min))) + { + file_hdr.c_tar_linkname = otherfile; + write_out_header (&file_hdr, out_file_des); + break; + } + } + if ( (archive_format == arf_newascii || archive_format == arf_crcascii) + && (file_hdr.c_nlink > 1) ) + { + if (last_link (&file_hdr) ) + { + writeout_other_defers (&file_hdr, out_file_des); + } + else + { + add_link_defer (&file_hdr); + break; + } + } + in_file_des = open (input_name.ds_string, + O_RDONLY | O_BINARY, 0); + if (in_file_des < 0) + { + error (0, errno, "%s", input_name.ds_string); + continue; + } + + if (archive_format == arf_crcascii) + file_hdr.c_chksum = read_for_checksum (in_file_des, + file_hdr.c_filesize, + input_name.ds_string); + + write_out_header (&file_hdr, out_file_des); + copy_files_disk_to_tape (in_file_des, out_file_des, file_hdr.c_filesize, input_name.ds_string); + warn_if_file_changed(input_name.ds_string, file_hdr.c_filesize, + file_hdr.c_mtime); + + if (archive_format == arf_tar || archive_format == arf_ustar) + add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj, + file_hdr.c_dev_min); + + tape_pad_output (out_file_des, file_hdr.c_filesize); + + if (close (in_file_des) < 0) + error (0, errno, "%s", input_name.ds_string); + if (reset_time_flag) + { + times.actime = file_stat.st_atime; + times.modtime = file_stat.st_mtime; + /* Debian hack: Silently ignore EROFS because + reading the file won't have upset its timestamp + if it's on a read-only filesystem. This has been + submitted as a suggestion to + "bug-gnu-utils@prep.ai.mit.edu". -BEM */ + if (utime (file_hdr.c_name, ×) < 0 + && errno != EROFS) + error (0, errno, "%s", file_hdr.c_name); + } + break; + + case CP_IFDIR: + file_hdr.c_filesize = 0; + write_out_header (&file_hdr, out_file_des); + break; + + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + if (archive_format == arf_tar) + { + error (0, 0, _("%s not dumped: not a regular file"), + file_hdr.c_name); + continue; + } + else if (archive_format == arf_ustar) + { + char *otherfile; + if ((otherfile = find_inode_file (file_hdr.c_ino, + file_hdr.c_dev_maj, + file_hdr.c_dev_min))) + { + /* This file is linked to another file already in the + archive, so write it out as a hard link. */ + file_hdr.c_mode = (file_stat.st_mode & 07777); + file_hdr.c_mode |= CP_IFREG; + file_hdr.c_tar_linkname = otherfile; + write_out_header (&file_hdr, out_file_des); + break; + } + add_inode (file_hdr.c_ino, file_hdr.c_name, + file_hdr.c_dev_maj, file_hdr.c_dev_min); + } + file_hdr.c_filesize = 0; + write_out_header (&file_hdr, out_file_des); + break; + +#ifdef CP_IFLNK + case CP_IFLNK: + { + char *link_name = (char *) xmalloc (file_stat.st_size + 1); + int link_size; + + link_size = readlink (input_name.ds_string, link_name, + file_stat.st_size); + if (link_size < 0) + { + error (0, errno, "%s", input_name.ds_string); + free (link_name); + continue; + } + file_hdr.c_filesize = link_size; + if (archive_format == arf_tar || archive_format == arf_ustar) + { + if (link_size + 1 > 100) + { + error (0, 0, _("%s: symbolic link too long"), + file_hdr.c_name); + } + else + { + link_name[link_size] = '\0'; + file_hdr.c_tar_linkname = link_name; + write_out_header (&file_hdr, out_file_des); + } + } + else + { + write_out_header (&file_hdr, out_file_des); + tape_buffered_write (link_name, out_file_des, link_size); + tape_pad_output (out_file_des, link_size); + } + free (link_name); + } + break; +#endif + + default: + error (0, 0, _("%s: unknown file type"), input_name.ds_string); + } + + if (verbose_flag) + fprintf (stderr, "%s\n", input_name.ds_string); + if (dot_flag) + fputc ('.', stderr); + } + } + + writeout_final_defers(out_file_des); + /* The collection is complete; append the trailer. */ + file_hdr.c_ino = 0; + file_hdr.c_mode = 0; + file_hdr.c_uid = 0; + file_hdr.c_gid = 0; + file_hdr.c_nlink = 1; /* Must be 1 for crc format. */ + file_hdr.c_dev_maj = 0; + file_hdr.c_dev_min = 0; + file_hdr.c_rdev_maj = 0; + file_hdr.c_rdev_min = 0; + file_hdr.c_mtime = 0; + file_hdr.c_chksum = 0; + + file_hdr.c_filesize = 0; + file_hdr.c_namesize = 11; + file_hdr.c_name = "TRAILER!!!"; + if (archive_format != arf_tar && archive_format != arf_ustar) + write_out_header (&file_hdr, out_file_des); + else + { + tape_buffered_write (zeros_512, out_file_des, 512); + tape_buffered_write (zeros_512, out_file_des, 512); + } + + /* Fill up the output block. */ + tape_clear_rest_of_block (out_file_des); + tape_empty_output_buffer (out_file_des); + if (dot_flag) + fputc ('\n', stderr); + if (!quiet_flag) + { + res = (output_bytes + io_block_size - 1) / io_block_size; + fprintf (stderr, ngettext ("%d block\n", "%d blocks\n", res), res); + } +} + + diff --git a/contrib/cpio/src/copypass.c b/contrib/cpio/src/copypass.c new file mode 100644 index 0000000..db6f327 --- /dev/null +++ b/contrib/cpio/src/copypass.c @@ -0,0 +1,464 @@ +/* copypass.c - cpio copy pass sub-function. + Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <system.h> + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "filetypes.h" +#include "cpiohdr.h" +#include "dstring.h" +#include "extern.h" + +#ifndef HAVE_LCHOWN +#define lchown chown +#endif + +/* Copy files listed on the standard input into directory `directory_name'. + If `link_flag', link instead of copying. */ + +void +process_copy_pass () +{ + dynamic_string input_name; /* Name of file from stdin. */ + dynamic_string output_name; /* Name of new file. */ + int dirname_len; /* Length of `directory_name'. */ + int res; /* Result of functions. */ + char *slash; /* For moving past slashes in input name. */ + struct utimbuf times; /* For resetting file times after copy. */ + struct stat in_file_stat; /* Stat record for input file. */ + struct stat out_file_stat; /* Stat record for output file. */ + int in_file_des; /* Input file descriptor. */ + int out_file_des; /* Output file descriptor. */ + int existing_dir; /* True if file is a dir & already exists. */ +#ifdef HPUX_CDF + int cdf_flag; + int cdf_char; +#endif + + /* Initialize the copy pass. */ + dirname_len = strlen (directory_name); + ds_init (&input_name, 128); + ds_init (&output_name, dirname_len + 2); + strcpy (output_name.ds_string, directory_name); + output_name.ds_string[dirname_len] = '/'; + output_is_seekable = true; + /* Initialize this in case it has members we don't know to set. */ + bzero (×, sizeof (struct utimbuf)); + + /* Copy files with names read from stdin. */ + while (ds_fgetstr (stdin, &input_name, name_end) != NULL) + { + int link_res = -1; + + /* Check for blank line and ignore it if found. */ + if (input_name.ds_string[0] == '\0') + { + error (0, 0, _("blank line ignored")); + continue; + } + + /* Check for current directory and ignore it if found. */ + if (input_name.ds_string[0] == '.' + && (input_name.ds_string[1] == '\0' + || (input_name.ds_string[1] == '/' + && input_name.ds_string[2] == '\0'))) + continue; + + if ((*xstat) (input_name.ds_string, &in_file_stat) < 0) + { + error (0, errno, "%s", input_name.ds_string); + continue; + } + + /* Make the name of the new file. */ + for (slash = input_name.ds_string; *slash == '/'; ++slash) + ; +#ifdef HPUX_CDF + /* For CDF's we add a 2nd `/' after all "hidden" directories. + This kind of a kludge, but it's what we do when creating + archives, and it's easier to do this than to separately + keep track of which directories in a path are "hidden". */ + slash = add_cdf_double_slashes (slash); +#endif + ds_resize (&output_name, dirname_len + strlen (slash) + 2); + strcpy (output_name.ds_string + dirname_len + 1, slash); + + existing_dir = false; + if (lstat (output_name.ds_string, &out_file_stat) == 0) + { + if (S_ISDIR (out_file_stat.st_mode) + && S_ISDIR (in_file_stat.st_mode)) + { + /* If there is already a directory there that + we are trying to create, don't complain about it. */ + existing_dir = true; + } + else if (!unconditional_flag + && in_file_stat.st_mtime <= out_file_stat.st_mtime) + { + error (0, 0, _("%s not created: newer or same age version exists"), + output_name.ds_string); + continue; /* Go to the next file. */ + } + else if (S_ISDIR (out_file_stat.st_mode) + ? rmdir (output_name.ds_string) + : unlink (output_name.ds_string)) + { + error (0, errno, _("cannot remove current %s"), + output_name.ds_string); + continue; /* Go to the next file. */ + } + } + + /* Do the real copy or link. */ + if (S_ISREG (in_file_stat.st_mode)) + { + /* Can the current file be linked to a another file? + Set link_name to the original file name. */ + if (link_flag) + /* User said to link it if possible. Try and link to + the original copy. If that fails we'll still try + and link to a copy we've already made. */ + link_res = link_to_name (output_name.ds_string, + input_name.ds_string); + if ( (link_res < 0) && (in_file_stat.st_nlink > 1) ) + link_res = link_to_maj_min_ino (output_name.ds_string, + major (in_file_stat.st_dev), + minor (in_file_stat.st_dev), + in_file_stat.st_ino); + + /* If the file was not linked, copy contents of file. */ + if (link_res < 0) + { + in_file_des = open (input_name.ds_string, + O_RDONLY | O_BINARY, 0); + if (in_file_des < 0) + { + error (0, errno, "%s", input_name.ds_string); + continue; + } + out_file_des = open (output_name.ds_string, + O_CREAT | O_WRONLY | O_BINARY, 0600); + if (out_file_des < 0 && create_dir_flag) + { + create_all_directories (output_name.ds_string); + out_file_des = open (output_name.ds_string, + O_CREAT | O_WRONLY | O_BINARY, 0600); + } + if (out_file_des < 0) + { + error (0, errno, "%s", output_name.ds_string); + close (in_file_des); + continue; + } + + copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string); + disk_empty_output_buffer (out_file_des); + /* Debian hack to fix a bug in the --sparse option. + This bug has been reported to + "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */ + if (delayed_seek_count > 0) + { + lseek (out_file_des, delayed_seek_count-1, SEEK_CUR); + write (out_file_des, "", 1); + delayed_seek_count = 0; + } + if (close (in_file_des) < 0) + error (0, errno, "%s", input_name.ds_string); + if (close (out_file_des) < 0) + error (0, errno, "%s", output_name.ds_string); + + /* Set the attributes of the new file. */ + if (!no_chown_flag) + if ((chown (output_name.ds_string, + set_owner_flag ? set_owner : in_file_stat.st_uid, + set_group_flag ? set_group : in_file_stat.st_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", output_name.ds_string); + /* chown may have turned off some permissions we wanted. */ + if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) + error (0, errno, "%s", output_name.ds_string); + if (reset_time_flag) + { + times.actime = in_file_stat.st_atime; + times.modtime = in_file_stat.st_mtime; + /* Debian hack: Silently ignore EROFS because + reading the file won't have upset its timestamp + if it's on a read-only filesystem. This has been + submitted as a suggestion to + "bug-gnu-utils@prep.ai.mit.edu". -BEM */ + if (utime (input_name.ds_string, ×) < 0 + && errno != EROFS) + error (0, errno, "%s", input_name.ds_string); + if (utime (output_name.ds_string, ×) < 0 + && errno != EROFS) + error (0, errno, "%s", output_name.ds_string); + } + if (retain_time_flag) + { + times.actime = times.modtime = in_file_stat.st_mtime; + if (utime (output_name.ds_string, ×) < 0) + error (0, errno, "%s", output_name.ds_string); + } + warn_if_file_changed(input_name.ds_string, in_file_stat.st_size, + in_file_stat.st_mtime); + } + } + else if (S_ISDIR (in_file_stat.st_mode)) + { +#ifdef HPUX_CDF + cdf_flag = 0; +#endif + if (!existing_dir) + { +#ifdef HPUX_CDF + /* If the directory name ends in a + and is SUID, + then it is a CDF. Strip the trailing + from the name + before creating it. */ + cdf_char = strlen (output_name.ds_string) - 1; + if ( (cdf_char > 0) && + (in_file_stat.st_mode & 04000) && + (output_name.ds_string [cdf_char] == '+') ) + { + output_name.ds_string [cdf_char] = '\0'; + cdf_flag = 1; + } +#endif + res = mkdir (output_name.ds_string, in_file_stat.st_mode); + + } + else + res = 0; + if (res < 0 && create_dir_flag) + { + create_all_directories (output_name.ds_string); + res = mkdir (output_name.ds_string, in_file_stat.st_mode); + } + if (res < 0) + { + /* In some odd cases where the output_name includes `.', + the directory may have actually been created by + create_all_directories(), so the mkdir will fail + because the directory exists. If that's the case, + don't complain about it. */ + if ( (errno != EEXIST) || + (lstat (output_name.ds_string, &out_file_stat) != 0) || + !(S_ISDIR (out_file_stat.st_mode) ) ) + { + error (0, errno, "%s", output_name.ds_string); + continue; + } + } + if (!no_chown_flag) + if ((chown (output_name.ds_string, + set_owner_flag ? set_owner : in_file_stat.st_uid, + set_group_flag ? set_group : in_file_stat.st_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", output_name.ds_string); + /* chown may have turned off some permissions we wanted. */ + if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) + error (0, errno, "%s", output_name.ds_string); +#ifdef HPUX_CDF + if (cdf_flag) + /* Once we "hide" the directory with the chmod(), + we have to refer to it using name+ isntead of name. */ + output_name.ds_string [cdf_char] = '+'; +#endif + if (retain_time_flag) + { + times.actime = times.modtime = in_file_stat.st_mtime; + if (utime (output_name.ds_string, ×) < 0) + error (0, errno, "%s", output_name.ds_string); + } + } + else if (S_ISCHR (in_file_stat.st_mode) || + S_ISBLK (in_file_stat.st_mode) || +#ifdef S_ISFIFO + S_ISFIFO (in_file_stat.st_mode) || +#endif +#ifdef S_ISSOCK + S_ISSOCK (in_file_stat.st_mode) || +#endif + 0) + { + /* Can the current file be linked to a another file? + Set link_name to the original file name. */ + if (link_flag) + /* User said to link it if possible. */ + link_res = link_to_name (output_name.ds_string, + input_name.ds_string); + if ( (link_res < 0) && (in_file_stat.st_nlink > 1) ) + link_res = link_to_maj_min_ino (output_name.ds_string, + major (in_file_stat.st_dev), + minor (in_file_stat.st_dev), + in_file_stat.st_ino); + + if (link_res < 0) + { + res = mknod (output_name.ds_string, in_file_stat.st_mode, + in_file_stat.st_rdev); + if (res < 0 && create_dir_flag) + { + create_all_directories (output_name.ds_string); + res = mknod (output_name.ds_string, in_file_stat.st_mode, + in_file_stat.st_rdev); + } + if (res < 0) + { + error (0, errno, "%s", output_name.ds_string); + continue; + } + if (!no_chown_flag) + if ((chown (output_name.ds_string, + set_owner_flag ? set_owner : in_file_stat.st_uid, + set_group_flag ? set_group : in_file_stat.st_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", output_name.ds_string); + /* chown may have turned off some permissions we wanted. */ + if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) + error (0, errno, "%s", output_name.ds_string); + if (retain_time_flag) + { + times.actime = times.modtime = in_file_stat.st_mtime; + if (utime (output_name.ds_string, ×) < 0) + error (0, errno, "%s", output_name.ds_string); + } + } + } + +#ifdef S_ISLNK + else if (S_ISLNK (in_file_stat.st_mode)) + { + char *link_name; + int link_size; + link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1); + + link_size = readlink (input_name.ds_string, link_name, + in_file_stat.st_size); + if (link_size < 0) + { + error (0, errno, "%s", input_name.ds_string); + free (link_name); + continue; + } + link_name[link_size] = '\0'; + + res = UMASKED_SYMLINK (link_name, output_name.ds_string, + in_file_stat.st_mode); + if (res < 0 && create_dir_flag) + { + create_all_directories (output_name.ds_string); + res = UMASKED_SYMLINK (link_name, output_name.ds_string, + in_file_stat.st_mode); + } + if (res < 0) + { + error (0, errno, "%s", output_name.ds_string); + free (link_name); + continue; + } + + /* Set the attributes of the new link. */ + if (!no_chown_flag) + if ((lchown (output_name.ds_string, + set_owner_flag ? set_owner : in_file_stat.st_uid, + set_group_flag ? set_group : in_file_stat.st_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", output_name.ds_string); + free (link_name); + } +#endif + else + { + error (0, 0, _("%s: unknown file type"), input_name.ds_string); + } + + if (verbose_flag) + fprintf (stderr, "%s\n", output_name.ds_string); + if (dot_flag) + fputc ('.', stderr); + } + + if (dot_flag) + fputc ('\n', stderr); + if (!quiet_flag) + { + res = (output_bytes + io_block_size - 1) / io_block_size; + fprintf (stderr, ngettext ("%d block\n", "%d blocks\n", res), res); + } +} + +/* Try and create a hard link from FILE_NAME to another file + with the given major/minor device number and inode. If no other + file with the same major/minor/inode numbers is known, add this file + to the list of known files and associated major/minor/inode numbers + and return -1. If another file with the same major/minor/inode + numbers is found, try and create another link to it using + link_to_name, and return 0 for success and -1 for failure. */ + +int +link_to_maj_min_ino (char *file_name, int st_dev_maj, int st_dev_min, + int st_ino) +{ + int link_res; + char *link_name; + link_res = -1; + /* Is the file a link to a previously copied file? */ + link_name = find_inode_file (st_ino, + st_dev_maj, + st_dev_min); + if (link_name == NULL) + add_inode (st_ino, file_name, + st_dev_maj, + st_dev_min); + else + link_res = link_to_name (file_name, link_name); + return link_res; +} + +/* Try and create a hard link from LINK_NAME to LINK_TARGET. If + `create_dir_flag' is set, any non-existent (parent) directories + needed by LINK_NAME will be created. If the link is successfully + created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n". + If the link can not be created and `link_flag' is set, print + "cannot link LINK_TARGET to LINK_NAME\n". Return 0 if the link + is created, -1 otherwise. */ + +int +link_to_name (char *link_name, char *link_target) +{ + int res = link (link_target, link_name); + if (res < 0 && create_dir_flag) + { + create_all_directories (link_name); + res = link (link_target, link_name); + } + if (res == 0) + { + if (verbose_flag) + error (0, 0, _("%s linked to %s"), + link_target, link_name); + } + else if (link_flag) + { + error (0, errno, _("cannot link %s to %s"), + link_target, link_name); + } + return res; +} diff --git a/contrib/cpio/src/cpio.h b/contrib/cpio/src/cpio.h new file mode 100644 index 0000000..3861ab0 --- /dev/null +++ b/contrib/cpio/src/cpio.h @@ -0,0 +1,69 @@ +/* Extended cpio format from POSIX.1. + Copyright (C) 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _CPIO_H + +#define _CPIO_H 1 + +/* A cpio archive consists of a sequence of files. + Each file has a 76 byte header, + a variable length, NUL terminated filename, + and variable length file data. + A header for a filename "TRAILER!!!" indicates the end of the archive. */ + +/* All the fields in the header are ISO 646 (approximately ASCII) strings + of octal numbers, left padded, not NUL terminated. + + Field Name Length in Bytes Notes + c_magic 6 must be "070707" + c_dev 6 + c_ino 6 + c_mode 6 see below for value + c_uid 6 + c_gid 6 + c_nlink 6 + c_rdev 6 only valid for chr and blk special files + c_mtime 11 + c_namesize 6 count includes terminating NUL in pathname + c_filesize 11 must be 0 for FIFOs and directories */ + +/* Values for c_mode, OR'd together: */ + +#define C_IRUSR 000400 +#define C_IWUSR 000200 +#define C_IXUSR 000100 +#define C_IRGRP 000040 +#define C_IWGRP 000020 +#define C_IXGRP 000010 +#define C_IROTH 000004 +#define C_IWOTH 000002 +#define C_IXOTH 000001 + +#define C_ISUID 004000 +#define C_ISGID 002000 +#define C_ISVTX 001000 + +#define C_ISBLK 060000 +#define C_ISCHR 020000 +#define C_ISDIR 040000 +#define C_ISFIFO 010000 +#define C_ISSOCK 0140000 +#define C_ISLNK 0120000 +#define C_ISCTG 0110000 +#define C_ISREG 0100000 + +#endif /* cpio.h */ diff --git a/contrib/cpio/src/cpiohdr.h b/contrib/cpio/src/cpiohdr.h new file mode 100644 index 0000000..c3943b4 --- /dev/null +++ b/contrib/cpio/src/cpiohdr.h @@ -0,0 +1,90 @@ +/* Extended cpio header from POSIX.1. + Copyright (C) 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _CPIOHDR_H + +#define _CPIOHDR_H 1 + +#include <cpio.h> + +struct old_cpio_header +{ + unsigned short c_magic; + short c_dev; + unsigned short c_ino; + unsigned short c_mode; + unsigned short c_uid; + unsigned short c_gid; + unsigned short c_nlink; + short c_rdev; + unsigned short c_mtimes[2]; + unsigned short c_namesize; + unsigned short c_filesizes[2]; + unsigned long c_mtime; /* Long-aligned copy of `c_mtimes'. */ + unsigned long c_filesize; /* Long-aligned copy of `c_filesizes'. */ + char *c_name; +}; + +/* "New" portable format and CRC format: + + Each file has a 110 byte header, + a variable length, NUL terminated filename, + and variable length file data. + A header for a filename "TRAILER!!!" indicates the end of the archive. */ + +/* All the fields in the header are ISO 646 (approximately ASCII) strings + of hexadecimal numbers, left padded, not NUL terminated. + + Field Name Length in Bytes Notes + c_magic 6 "070701" for "new" portable format + "070702" for CRC format + c_ino 8 + c_mode 8 + c_uid 8 + c_gid 8 + c_nlink 8 + c_mtime 8 + c_filesize 8 must be 0 for FIFOs and directories + c_maj 8 + c_min 8 + c_rmaj 8 only valid for chr and blk special files + c_rmin 8 only valid for chr and blk special files + c_namesize 8 count includes terminating NUL in pathname + c_chksum 8 0 for "new" portable format; for CRC format + the sum of all the bytes in the file */ + +struct new_cpio_header +{ + unsigned short c_magic; + unsigned long c_ino; + unsigned long c_mode; + unsigned long c_uid; + unsigned long c_gid; + unsigned long c_nlink; + unsigned long c_mtime; + unsigned long c_filesize; + long c_dev_maj; + long c_dev_min; + long c_rdev_maj; + long c_rdev_min; + unsigned long c_namesize; + unsigned long c_chksum; + char *c_name; + char *c_tar_linkname; +}; + +#endif /* cpiohdr.h */ diff --git a/contrib/cpio/src/defer.c b/contrib/cpio/src/defer.c new file mode 100644 index 0000000..cb6fb40 --- /dev/null +++ b/contrib/cpio/src/defer.c @@ -0,0 +1,42 @@ +/* defer.c - handle "defered" links in newc and crc archives + Copyright (C) 1993,2003,2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <system.h> + +#include <stdio.h> +#include <sys/types.h> +#include "cpiohdr.h" +#include "extern.h" +#include "defer.h" + +struct deferment * +create_deferment (struct new_cpio_header *file_hdr) +{ + struct deferment *d; + d = (struct deferment *) xmalloc (sizeof (struct deferment) ); + d->header = *file_hdr; + d->header.c_name = (char *) xmalloc (strlen (file_hdr->c_name) + 1); + strcpy (d->header.c_name, file_hdr->c_name); + return d; +} + +void +free_deferment (struct deferment *d) +{ + free (d->header.c_name); + free (d); +} diff --git a/contrib/cpio/src/defer.h b/contrib/cpio/src/defer.h new file mode 100644 index 0000000..657257f --- /dev/null +++ b/contrib/cpio/src/defer.h @@ -0,0 +1,25 @@ +/* defer.h + Copyright (C) 1993, 2001, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +struct deferment + { + struct deferment *next; + struct new_cpio_header header; + }; + +struct deferment *create_deferment P_((struct new_cpio_header *file_hdr)); +void free_deferment P_((struct deferment *d)); diff --git a/contrib/cpio/src/dstring.c b/contrib/cpio/src/dstring.c new file mode 100644 index 0000000..e3cdae7 --- /dev/null +++ b/contrib/cpio/src/dstring.c @@ -0,0 +1,107 @@ +/* dstring.c - The dynamic string handling routines used by cpio. + Copyright (C) 1990, 1991, 1992, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> +#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) +#include <string.h> +#else +#include <strings.h> +#endif +#include "dstring.h" + +#if __STDC__ +# define P_(s) s +#else +# define P_(s) () +#endif +char *xmalloc P_((unsigned n)); +char *xrealloc P_((char *p, unsigned n)); + +/* Initialiaze dynamic string STRING with space for SIZE characters. */ + +void +ds_init (dynamic_string *string, int size) +{ + string->ds_length = size; + string->ds_string = (char *) xmalloc (size); +} + +/* Expand dynamic string STRING, if necessary, to hold SIZE characters. */ + +void +ds_resize (dynamic_string *string, int size) +{ + if (size > string->ds_length) + { + string->ds_length = size; + string->ds_string = (char *) xrealloc ((char *) string->ds_string, size); + } +} + +/* Dynamic string S gets a string terminated by the EOS character + (which is removed) from file F. S will increase + in size during the function if the string from F is longer than + the current size of S. + Return NULL if end of file is detected. Otherwise, + Return a pointer to the null-terminated string in S. */ + +char * +ds_fgetstr (FILE *f, dynamic_string *s, char eos) +{ + int insize; /* Amount needed for line. */ + int strsize; /* Amount allocated for S. */ + int next_ch; + + /* Initialize. */ + insize = 0; + strsize = s->ds_length; + + /* Read the input string. */ + next_ch = getc (f); + while (next_ch != eos && next_ch != EOF) + { + if (insize >= strsize - 1) + { + ds_resize (s, strsize * 2 + 2); + strsize = s->ds_length; + } + s->ds_string[insize++] = next_ch; + next_ch = getc (f); + } + s->ds_string[insize++] = '\0'; + + if (insize == 1 && next_ch == EOF) + return NULL; + else + return s->ds_string; +} + +char * +ds_fgets (FILE *f, dynamic_string *s) +{ + return ds_fgetstr (f, s, '\n'); +} + +char * +ds_fgetname (FILE *f, dynamic_string *s) +{ + return ds_fgetstr (f, s, '\0'); +} diff --git a/contrib/cpio/src/dstring.h b/contrib/cpio/src/dstring.h new file mode 100644 index 0000000..1615518 --- /dev/null +++ b/contrib/cpio/src/dstring.h @@ -0,0 +1,49 @@ +/* dstring.h - Dynamic string handling include file. Requires strings.h. + Copyright (C) 1990, 1991, 1992, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NULL +#define NULL 0 +#endif + +/* A dynamic string consists of record that records the size of an + allocated string and the pointer to that string. The actual string + is a normal zero byte terminated string that can be used with the + usual string functions. The major difference is that the + dynamic_string routines know how to get more space if it is needed + by allocating new space and copying the current string. */ + +typedef struct +{ + int ds_length; /* Actual amount of storage allocated. */ + char *ds_string; /* String. */ +} dynamic_string; + + +/* Macros that look similar to the original string functions. + WARNING: These macros work only on pointers to dynamic string records. + If used with a real record, an "&" must be used to get the pointer. */ +#define ds_strlen(s) strlen ((s)->ds_string) +#define ds_strcmp(s1, s2) strcmp ((s1)->ds_string, (s2)->ds_string) +#define ds_strncmp(s1, s2, n) strncmp ((s1)->ds_string, (s2)->ds_string, n) +#define ds_index(s, c) index ((s)->ds_string, c) +#define ds_rindex(s, c) rindex ((s)->ds_string, c) + +void ds_init (dynamic_string *string, int size); +void ds_resize (dynamic_string *string, int size); +char *ds_fgetname (FILE *f, dynamic_string *s); +char *ds_fgets (FILE *f, dynamic_string *s); +char *ds_fgetstr (FILE *f, dynamic_string *s, char eos); diff --git a/contrib/cpio/src/extern.h b/contrib/cpio/src/extern.h new file mode 100644 index 0000000..e6e3d6e --- /dev/null +++ b/contrib/cpio/src/extern.h @@ -0,0 +1,200 @@ +/* extern.h - External declarations for cpio. Requires system.h. + Copyright (C) 1990, 1991, 1992, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +enum archive_format +{ + arf_unknown, arf_binary, arf_oldascii, arf_newascii, arf_crcascii, + arf_tar, arf_ustar, arf_hpoldascii, arf_hpbinary +}; +extern enum archive_format archive_format; +extern int reset_time_flag; +extern int io_block_size; +extern int create_dir_flag; +extern int rename_flag; +extern char *rename_batch_file; +extern int table_flag; +extern int unconditional_flag; +extern int verbose_flag; +extern int dot_flag; +extern int link_flag; +extern int retain_time_flag; +extern int crc_i_flag; +extern int append_flag; +extern int swap_bytes_flag; +extern int swap_halfwords_flag; +extern int swapping_bytes; +extern int swapping_halfwords; +extern int set_owner_flag; +extern uid_t set_owner; +extern int set_group_flag; +extern gid_t set_group; +extern int no_chown_flag; +extern int sparse_flag; +extern int quiet_flag; +extern int only_verify_crc_flag; +extern int no_abs_paths_flag; +extern unsigned int warn_option; + +/* Values for warn_option */ +#define CPIO_WARN_NONE 0 +#define CPIO_WARN_TRUNCATE 0x01 +#define CPIO_WARN_ALL (unsigned int)-1 + +extern bool to_stdout_option; + +extern int last_header_start; +extern int copy_matching_files; +extern int numeric_uid; +extern char *pattern_file_name; +extern char *new_media_message; +extern char *new_media_message_with_number; +extern char *new_media_message_after_number; +extern int archive_des; +extern char *archive_name; +extern char *rsh_command_option; +extern unsigned long crc; +extern int delayed_seek_count; +#ifdef DEBUG_CPIO +extern int debug_flag; +#endif + +extern char *input_buffer, *output_buffer; +extern char *in_buff, *out_buff; +extern long input_buffer_size; +extern long input_size, output_size; +#ifdef __GNUC__ +extern long long input_bytes, output_bytes; +#else +extern long input_bytes, output_bytes; +#endif +extern char zeros_512[]; +extern char *directory_name; +extern char **save_patterns; +extern int num_patterns; +extern char name_end; +extern char input_is_special; +extern char output_is_special; +extern char input_is_seekable; +extern char output_is_seekable; +extern char *program_name; +extern int (*xstat) (); +extern void (*copy_function) (); + +#if defined PROTOTYPES || (defined __STDC__ && __STDC__) +# define P_(s) s +#else +# define P_(s) () +#endif + +/* copyin.c */ +void warn_junk_bytes P_((long bytes_skipped)); +void read_in_header P_((struct new_cpio_header *file_hdr, int in_des)); +void read_in_old_ascii P_((struct new_cpio_header *file_hdr, int in_des)); +void read_in_new_ascii P_((struct new_cpio_header *file_hdr, int in_des)); +void read_in_binary P_((struct new_cpio_header *file_hdr, int in_des)); +void swab_array P_((char *arg, int count)); +void process_copy_in P_((void)); +void long_format P_((struct new_cpio_header *file_hdr, char *link_name)); +void print_name_with_quoting P_((char *p)); + +/* copyout.c */ +void write_out_header P_((struct new_cpio_header *file_hdr, int out_des)); +void process_copy_out P_((void)); + +/* copypass.c */ +void process_copy_pass P_((void)); +int link_to_maj_min_ino P_((char *file_name, int st_dev_maj, + int st_dev_min, int st_ino)); +int link_to_name P_((char *link_name, char *link_target)); + +/* dirname.c */ +char *dirname P_((char *path)); + +/* filemode.c */ +void mode_string P_((unsigned int mode, char *str)); + +/* idcache.c */ +#ifndef __MSDOS__ +char *getgroup (); +char *getuser (); +uid_t *getuidbyname (); +gid_t *getgidbyname (); +#endif + +/* main.c */ +void process_args P_((int argc, char *argv[])); +void initialize_buffers P_((void)); + +/* makepath.c */ +int make_path P_((char *argpath, int mode, int parent_mode, + uid_t owner, gid_t group, char *verbose_fmt_string)); + +/* tar.c */ +void write_out_tar_header P_((struct new_cpio_header *file_hdr, int out_des)); +int null_block P_((long *block, int size)); +void read_in_tar_header P_((struct new_cpio_header *file_hdr, int in_des)); +int otoa P_((char *s, unsigned long *n)); +int is_tar_header P_((char *buf)); +int is_tar_filename_too_long P_((char *name)); + +/* userspec.c */ +#ifndef __MSDOS__ +char *parse_user_spec P_((char *name, uid_t *uid, gid_t *gid, + char **username, char **groupname)); +#endif + +/* util.c */ +void tape_empty_output_buffer P_((int out_des)); +void disk_empty_output_buffer P_((int out_des)); +void swahw_array P_((char *ptr, int count)); +void tape_buffered_write P_((char *in_buf, int out_des, long num_bytes)); +void tape_buffered_read P_((char *in_buf, int in_des, long num_bytes)); +int tape_buffered_peek P_((char *peek_buf, int in_des, int num_bytes)); +void tape_toss_input P_((int in_des, long num_bytes)); +void copy_files_tape_to_disk P_((int in_des, int out_des, long num_bytes)); +void copy_files_disk_to_tape P_((int in_des, int out_des, long num_bytes, char *filename)); +void copy_files_disk_to_disk P_((int in_des, int out_des, long num_bytes, char *filename)); +void warn_if_file_changed P_((char *file_name, unsigned long old_file_size, + unsigned long old_file_mtime)); +void create_all_directories P_((char *name)); +void prepare_append P_((int out_file_des)); +char *find_inode_file P_((unsigned long node_num, + unsigned long major_num, unsigned long minor_num)); +void add_inode P_((unsigned long node_num, char *file_name, + unsigned long major_num, unsigned long minor_num)); +int open_archive P_((char *file)); +void tape_offline P_((int tape_des)); +void get_next_reel P_((int tape_des)); +void set_new_media_message P_((char *message)); +#if defined(__MSDOS__) && !defined(__GNUC__) +int chown P_((char *path, int owner, int group)); +#endif +#ifdef __TURBOC__ +int utime P_((char *filename, struct utimbuf *utb)); +#endif +#ifdef HPUX_CDF +char *add_cdf_double_slashes P_((char *filename)); +#endif + +#define DISK_IO_BLOCK_SIZE (512) + +/* FIXME: Move to system.h? */ +#ifndef SYMLINK_USES_UMASK +# define UMASKED_SYMLINK(name1,name2,mode) symlink(name1,name2) +#else +# define UMASKED_SYMLINK(name1,name2,mode) umasked_symlink(name1,name2,mode) +#endif /* SYMLINK_USES_UMASK */ diff --git a/contrib/cpio/src/filemode.c b/contrib/cpio/src/filemode.c new file mode 100644 index 0000000..ff4d379 --- /dev/null +++ b/contrib/cpio/src/filemode.c @@ -0,0 +1,242 @@ +/* filemode.c -- make a string describing file modes + Copyright (C) 1985, 1990, 1993, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#if !S_IRUSR +# if S_IREAD +# define S_IRUSR S_IREAD +# else +# define S_IRUSR 00400 +# endif +#endif + +#if !S_IWUSR +# if S_IWRITE +# define S_IWUSR S_IWRITE +# else +# define S_IWUSR 00200 +# endif +#endif + +#if !S_IXUSR +# if S_IEXEC +# define S_IXUSR S_IEXEC +# else +# define S_IXUSR 00100 +# endif +#endif + +#ifdef STAT_MACROS_BROKEN +#undef S_ISBLK +#undef S_ISCHR +#undef S_ISDIR +#undef S_ISFIFO +#undef S_ISLNK +#undef S_ISMPB +#undef S_ISMPC +#undef S_ISNWK +#undef S_ISREG +#undef S_ISSOCK +#endif /* STAT_MACROS_BROKEN. */ + +#if !defined(S_ISBLK) && defined(S_IFBLK) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISDIR) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISFIFO) && defined(S_IFIFO) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ +#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +#endif +#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ +#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +#endif + +/* Return a character indicating the type of file described by + file mode BITS: + 'd' for directories + 'b' for block special files + 'c' for character special files + 'm' for multiplexor files + 'l' for symbolic links + 's' for sockets + 'p' for fifos + '-' for regular files + '?' for any other file type. */ + +static char +ftypelet (long bits) +{ +#ifdef S_ISBLK + if (S_ISBLK (bits)) + return 'b'; +#endif + if (S_ISCHR (bits)) + return 'c'; + if (S_ISDIR (bits)) + return 'd'; + if (S_ISREG (bits)) + return '-'; +#ifdef S_ISFIFO + if (S_ISFIFO (bits)) + return 'p'; +#endif +#ifdef S_ISLNK + if (S_ISLNK (bits)) + return 'l'; +#endif +#ifdef S_ISSOCK + if (S_ISSOCK (bits)) + return 's'; +#endif +#ifdef S_ISMPC + if (S_ISMPC (bits)) + return 'm'; +#endif +#ifdef S_ISNWK + if (S_ISNWK (bits)) + return 'n'; +#endif + return '?'; +} + +/* Look at read, write, and execute bits in BITS and set + flags in CHARS accordingly. */ + +static void +rwx (unsigned short bits, char *chars) +{ + chars[0] = (bits & S_IRUSR) ? 'r' : '-'; + chars[1] = (bits & S_IWUSR) ? 'w' : '-'; + chars[2] = (bits & S_IXUSR) ? 'x' : '-'; +} + +/* Set the 's' and 't' flags in file attributes string CHARS, + according to the file mode BITS. */ + +static void +setst (unsigned short bits, char *chars) +{ +#ifdef S_ISUID + if (bits & S_ISUID) + { + if (chars[3] != 'x') + /* Set-uid, but not executable by owner. */ + chars[3] = 'S'; + else + chars[3] = 's'; + } +#endif +#ifdef S_ISGID + if (bits & S_ISGID) + { + if (chars[6] != 'x') + /* Set-gid, but not executable by group. */ + chars[6] = 'S'; + else + chars[6] = 's'; + } +#endif +#ifdef S_ISVTX + if (bits & S_ISVTX) + { + if (chars[9] != 'x') + /* Sticky, but not executable by others. */ + chars[9] = 'T'; + else + chars[9] = 't'; + } +#endif +} + +/* Like filemodestring (see below), but only the relevant part of the + `struct stat' is given as an argument. */ + +void +mode_string (unsigned short mode, char *str) +{ + str[0] = ftypelet ((long) mode); + rwx ((mode & 0700) << 0, &str[1]); + rwx ((mode & 0070) << 3, &str[4]); + rwx ((mode & 0007) << 6, &str[7]); + setst (mode, str); +} + +/* filemodestring - fill in string STR with an ls-style ASCII + representation of the st_mode field of file stats block STATP. + 10 characters are stored in STR; no terminating null is added. + The characters stored in STR are: + + 0 File type. 'd' for directory, 'c' for character + special, 'b' for block special, 'm' for multiplex, + 'l' for symbolic link, 's' for socket, 'p' for fifo, + '-' for regular, '?' for any other file type + + 1 'r' if the owner may read, '-' otherwise. + + 2 'w' if the owner may write, '-' otherwise. + + 3 'x' if the owner may execute, 's' if the file is + set-user-id, '-' otherwise. + 'S' if the file is set-user-id, but the execute + bit isn't set. + + 4 'r' if group members may read, '-' otherwise. + + 5 'w' if group members may write, '-' otherwise. + + 6 'x' if group members may execute, 's' if the file is + set-group-id, '-' otherwise. + 'S' if it is set-group-id but not executable. + + 7 'r' if any user may read, '-' otherwise. + + 8 'w' if any user may write, '-' otherwise. + + 9 'x' if any user may execute, 't' if the file is "sticky" + (will be retained in swap space after execution), '-' + otherwise. + 'T' if the file is sticky but not executable. */ + +void +filemodestring (struct stat *statp, char *str) +{ + mode_string (statp->st_mode, str); +} + diff --git a/contrib/cpio/src/filetypes.h b/contrib/cpio/src/filetypes.h new file mode 100644 index 0000000..9f785a1 --- /dev/null +++ b/contrib/cpio/src/filetypes.h @@ -0,0 +1,84 @@ +/* filetypes.h - deal with POSIX annoyances + Copyright (C) 1991 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Include sys/types.h and sys/stat.h before this file. */ + +#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */ +#define mode_t unsigned short +#endif + +/* Define the POSIX macros for systems that lack them. */ +#if !defined(S_ISBLK) && defined(S_IFBLK) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISDIR) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISFIFO) && defined(S_IFIFO) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX network special */ +#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +#endif + +/* Define the file type bits used in cpio archives. + They have the same values as the S_IF bits in traditional Unix. */ + +#define CP_IFMT 0170000 /* Mask for all file type bits. */ + +#if defined(S_ISBLK) +#define CP_IFBLK 0060000 +#endif +#if defined(S_ISCHR) +#define CP_IFCHR 0020000 +#endif +#if defined(S_ISDIR) +#define CP_IFDIR 0040000 +#endif +#if defined(S_ISREG) +#define CP_IFREG 0100000 +#endif +#if defined(S_ISFIFO) +#define CP_IFIFO 0010000 +#endif +#if defined(S_ISLNK) +#define CP_IFLNK 0120000 +#endif +#if defined(S_ISSOCK) +#define CP_IFSOCK 0140000 +#endif +#if defined(S_ISNWK) +#define CP_IFNWK 0110000 +#endif + +#ifndef S_ISLNK +#define lstat stat +#endif +int lstat (); +int stat (); diff --git a/contrib/cpio/src/global.c b/contrib/cpio/src/global.c new file mode 100644 index 0000000..97b6bea --- /dev/null +++ b/contrib/cpio/src/global.c @@ -0,0 +1,203 @@ +/* global.c - global variables and initial values for cpio. + Copyright (C) 1990, 1991, 1992, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <system.h> + +#include <sys/types.h> +#include "cpiohdr.h" +#include "dstring.h" +#include "extern.h" + +/* If true, reset access times after reading files (-a). */ +int reset_time_flag = false; + +/* Block size value, initially 512. -B sets to 5120. */ +int io_block_size = 512; + +/* The header format to recognize and produce. */ +enum archive_format archive_format = arf_unknown; + +/* If true, create directories as needed. (-d with -i or -p) */ +int create_dir_flag = false; + +/* If true, interactively rename files. (-r) */ +int rename_flag = false; + +/* If non-NULL, the name of a file that will be read to + rename all of the files in the archive. --rename-batch-file. */ +char *rename_batch_file = NULL; + +/* If true, print a table of contents of input. (-t) */ +int table_flag = false; + +/* If true, copy unconditionally (older replaces newer). (-u) */ +int unconditional_flag = false; + +/* If true, list the files processed, or ls -l style output with -t. (-v) */ +int verbose_flag = false; + +/* If true, print a . for each file processed. (-V) */ +int dot_flag = false; + +/* If true, link files whenever possible. Used with -p option. (-l) */ +int link_flag = false; + +/* If true, retain previous file modification time. (-m) */ +int retain_time_flag = false; + +/* Set true if crc_flag is true and we are doing a cpio -i. Used + by copy_files so it knows whether to compute the crc. */ +int crc_i_flag = false; + +/* If true, append to end of archive. (-A) */ +int append_flag = false; + +/* If true, swap bytes of each file during cpio -i. */ +int swap_bytes_flag = false; + +/* If true, swap halfwords of each file during cpio -i. */ +int swap_halfwords_flag = false; + +/* If true, we are swapping halfwords on the current file. */ +int swapping_halfwords = false; + +/* If true, we are swapping bytes on the current file. */ +int swapping_bytes = false; + +/* If true, set ownership of all files to UID `set_owner'. */ +int set_owner_flag = false; +uid_t set_owner; + +/* If true, set group ownership of all files to GID `set_group'. */ +int set_group_flag = false; +gid_t set_group; + +/* If true, do not chown the files. */ +int no_chown_flag = false; + +/* If true, try to write sparse ("holey") files. */ +int sparse_flag = false; + +/* If true, don't report number of blocks copied. */ +int quiet_flag = false; + +/* If true, only read the archive and verify the files' CRC's, don't + actually extract the files. */ +int only_verify_crc_flag = false; + +/* If true, don't use any absolute paths, prefix them by `./'. */ +int no_abs_paths_flag = false; + +#ifdef DEBUG_CPIO +/* If true, print debugging information. */ +int debug_flag = false; +#endif + +/* File position of last header read. Only used during -A to determine + where the old TRAILER!!! record started. */ +int last_header_start = 0; + +/* With -i; if true, copy only files that match any of the given patterns; + if false, copy only files that do not match any of the patterns. (-f) */ +int copy_matching_files = true; + +/* With -itv; if true, list numeric uid and gid instead of translating them + into names. */ +int numeric_uid = false; + +/* Name of file containing additional patterns (-E). */ +char *pattern_file_name = NULL; + +/* Message to print when end of medium is reached (-M). */ +char *new_media_message = NULL; + +/* With -M with %d, message to print when end of medium is reached. */ +char *new_media_message_with_number = NULL; +char *new_media_message_after_number = NULL; + +/* File descriptor containing the archive. */ +int archive_des; + +/* Name of file containing the archive, if known; NULL if stdin/out. */ +char *archive_name = NULL; + +/* Name of the remote shell command, if known; NULL otherwise. */ +char *rsh_command_option = NULL; + +/* CRC checksum. */ +unsigned long crc; + +/* Input and output buffers. */ +char *input_buffer, *output_buffer; + +/* The size of the input buffer. */ +long input_buffer_size; + +/* Current locations in `input_buffer' and `output_buffer'. */ +char *in_buff, *out_buff; + +/* Current number of bytes stored at `input_buff' and `output_buff'. */ +long input_size, output_size; + +/* Total number of bytes read and written for all files. + Now that many tape drives hold more than 4Gb we need more than 32 + bits to hold input_bytes and output_bytes. But it's not worth + the trouble of adding special multi-precision arithmetic if the + compiler doesn't support 64 bit ints since input_bytes and + output_bytes are only used to print the number of blocks copied. */ +#ifdef __GNUC__ +long long input_bytes, output_bytes; +#else +long input_bytes, output_bytes; +#endif + +/* 512 bytes of 0; used for various padding operations. */ +char zeros_512[512]; + +/* Saving of argument values for later reference. */ +char *directory_name = NULL; +char **save_patterns; +int num_patterns; + +/* Character that terminates file names read from stdin. */ +char name_end = '\n'; + +/* true if input (cpio -i) or output (cpio -o) is a device node. */ +char input_is_special = false; +char output_is_special = false; + +/* true if lseek works on the input. */ +char input_is_seekable = false; + +/* true if lseek works on the output. */ +char output_is_seekable = false; + +/* Print extra warning messages */ +unsigned int warn_option = 0; + +/* Extract to standard output? */ +bool to_stdout_option = false; + +/* The name this program was run with. */ +char *program_name; + +/* A pointer to either lstat or stat, depending on whether + dereferencing of symlinks is done for input files. */ +int (*xstat) (); + +/* Which copy operation to perform. (-i, -o, -p) */ +void (*copy_function) () = 0; diff --git a/contrib/cpio/src/idcache.c b/contrib/cpio/src/idcache.c new file mode 100644 index 0000000..d3bf482 --- /dev/null +++ b/contrib/cpio/src/idcache.c @@ -0,0 +1,206 @@ +/* idcache.c -- map user and group IDs, cached for speed + Copyright (C) 1985, 1988, 1989, 1990, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> + +#if defined(STDC_HEADERS) || defined(HAVE_STRING_H) +#include <string.h> +#else +#include <strings.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifndef _POSIX_VERSION +struct passwd *getpwuid (); +struct passwd *getpwnam (); +struct group *getgrgid (); +struct group *getgrnam (); +#endif + +char *xmalloc (); +char *xstrdup (); + +struct userid +{ + union + { + uid_t u; + gid_t g; + } id; + char *name; + struct userid *next; +}; + +static struct userid *user_alist; + +/* The members of this list have names not in the local passwd file. */ +static struct userid *nouser_alist; + +/* Translate UID to a login name or a stringified number, + with cache. */ + +char * +getuser (uid_t uid) +{ + register struct userid *tail; + struct passwd *pwent; + char usernum_string[20]; + + for (tail = user_alist; tail; tail = tail->next) + if (tail->id.u == uid) + return tail->name; + + pwent = getpwuid (uid); + tail = (struct userid *) xmalloc (sizeof (struct userid)); + tail->id.u = uid; + if (pwent == 0) + { + sprintf (usernum_string, "%u", (unsigned) uid); + tail->name = xstrdup (usernum_string); + } + else + tail->name = xstrdup (pwent->pw_name); + + /* Add to the head of the list, so most recently used is first. */ + tail->next = user_alist; + user_alist = tail; + return tail->name; +} + +/* Translate USER to a UID, with cache. + Return NULL if there is no such user. + (We also cache which user names have no passwd entry, + so we don't keep looking them up.) */ + +uid_t * +getuidbyname (char *user) +{ + register struct userid *tail; + struct passwd *pwent; + + for (tail = user_alist; tail; tail = tail->next) + /* Avoid a function call for the most common case. */ + if (*tail->name == *user && !strcmp (tail->name, user)) + return &tail->id.u; + + for (tail = nouser_alist; tail; tail = tail->next) + /* Avoid a function call for the most common case. */ + if (*tail->name == *user && !strcmp (tail->name, user)) + return 0; + + pwent = getpwnam (user); + + tail = (struct userid *) xmalloc (sizeof (struct userid)); + tail->name = xstrdup (user); + + /* Add to the head of the list, so most recently used is first. */ + if (pwent) + { + tail->id.u = pwent->pw_uid; + tail->next = user_alist; + user_alist = tail; + return &tail->id.u; + } + + tail->next = nouser_alist; + nouser_alist = tail; + return 0; +} + +/* Use the same struct as for userids. */ +static struct userid *group_alist; +static struct userid *nogroup_alist; + +/* Translate GID to a group name or a stringified number, + with cache. */ + +char * +getgroup (gid_t gid) +{ + register struct userid *tail; + struct group *grent; + char groupnum_string[20]; + + for (tail = group_alist; tail; tail = tail->next) + if (tail->id.g == gid) + return tail->name; + + grent = getgrgid (gid); + tail = (struct userid *) xmalloc (sizeof (struct userid)); + tail->id.g = gid; + if (grent == 0) + { + sprintf (groupnum_string, "%u", (unsigned int) gid); + tail->name = xstrdup (groupnum_string); + } + else + tail->name = xstrdup (grent->gr_name); + + /* Add to the head of the list, so most recently used is first. */ + tail->next = group_alist; + group_alist = tail; + return tail->name; +} + +/* Translate GROUP to a UID, with cache. + Return NULL if there is no such group. + (We also cache which group names have no group entry, + so we don't keep looking them up.) */ + +gid_t * +getgidbyname (char *group) +{ + register struct userid *tail; + struct group *grent; + + for (tail = group_alist; tail; tail = tail->next) + /* Avoid a function call for the most common case. */ + if (*tail->name == *group && !strcmp (tail->name, group)) + return &tail->id.g; + + for (tail = nogroup_alist; tail; tail = tail->next) + /* Avoid a function call for the most common case. */ + if (*tail->name == *group && !strcmp (tail->name, group)) + return 0; + + grent = getgrnam (group); + + tail = (struct userid *) xmalloc (sizeof (struct userid)); + tail->name = xstrdup (group); + + /* Add to the head of the list, so most recently used is first. */ + if (grent) + { + tail->id.g = grent->gr_gid; + tail->next = group_alist; + group_alist = tail; + return &tail->id.g; + } + + tail->next = nogroup_alist; + nogroup_alist = tail; + return 0; +} diff --git a/contrib/cpio/src/main.c b/contrib/cpio/src/main.c new file mode 100644 index 0000000..cd96e58 --- /dev/null +++ b/contrib/cpio/src/main.c @@ -0,0 +1,763 @@ +/* main.c - main program and argument processing for cpio. + Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Phil Nelson <phil@cs.wwu.edu>, + David MacKenzie <djm@gnu.ai.mit.edu>, + John Oleynick <juo@klinzhai.rutgers.edu>, + and Sergey Poznyakoff <gray@mirddin.farlep.net> */ + +#include <system.h> + +#include <stdio.h> +#include <getopt.h> +#include <argp.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef HAVE_LOCALE_H +# include <locale.h> +#endif + +#include "filetypes.h" +#include "cpiohdr.h" +#include "dstring.h" +#include "extern.h" +#include <rmt.h> +#include <localedir.h> + +enum cpio_options { + NO_ABSOLUTE_FILENAMES_OPTION=256, + NO_PRESERVE_OWNER_OPTION, + ONLY_VERIFY_CRC_OPTION, + RENAME_BATCH_FILE_OPTION, + RSH_COMMAND_OPTION, + QUIET_OPTION, + SPARSE_OPTION, + FORCE_LOCAL_OPTION, + DEBUG_OPTION, + BLOCK_SIZE_OPTION, + TO_STDOUT_OPTION, + + USAGE_OPTION, + LICENSE_OPTION, + VERSION_OPTION +}; + +const char *argp_program_version = "cpio (" PACKAGE_NAME ") " VERSION; +const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; +static char doc[] = N_("GNU `cpio' copies files to and from archives\n\ +\n\ +Examples:\n\ + # Copy files named in name-list to the archive\n\ + cpio -o < name-list [> archive]\n\ + # Extract files from the archive\n\ + cpio -i [< archive]\n\ + # Copy files named in name-list to destination-directory\n\ + cpio -p destination-directory < name-list\n"); + +/* Print usage error message and exit with error. */ + +#define USAGE_ERROR(args) do { error args; exit(2); } while (0) +#define CHECK_USAGE(cond, opt, mode_opt) \ + if (cond) USAGE_ERROR((0, 0, _("%s is meaningless with %s"), opt, mode_opt)); + +static struct argp_option options[] = { + {NULL, 0, NULL, 0, + N_("Main operation mode:"), 10}, + {"create", 'o', 0, 0, + N_("Create the archive (run in copy-out mode)"), 10}, + {"extract", 'i', 0, 0, + N_("Extract files from an archive (run in copy-in mode)")}, + {"pass-through", 'p', 0, 0, + N_("Run in copy-pass mode"), 10}, + {"list", 't', 0, 0, + N_("Print a table of contents of the input"), 10}, + + {NULL, 0, NULL, 0, + N_("Operation modifiers valid in any mode:"), 100}, + + {"file", 'F', N_("[[USER@]HOST:]FILE-NAME"), 0, + N_("Use this FILE-NAME instead of standard input or output. Optional USER and HOST specify the user and host names in case of a remote archive"), 110}, + {"force-local", FORCE_LOCAL_OPTION, 0, 0, + N_("Archive file is local, even if its name contains colons"), 110}, + {"format", 'H', N_("FORMAT"), 0, + N_("Use given archive FORMAT"), 110}, + {NULL, 'B', NULL, 0, + N_("Set the I/O block size to 5120 bytes"), 110}, + {"block-size", BLOCK_SIZE_OPTION, N_("BLOCK-SIZE"), 0, + N_("Set the I/O block size to BLOCK-SIZE * 512 bytes"), 110}, + {NULL, 'c', NULL, 0, + N_("Use the old portable (ASCII) archive format"), 0}, + {"dot", 'V', NULL, 0, + N_("Print a \".\" for each file processed"), 110}, + {"io-size", 'C', N_("NUMBER"), 0, + N_("Set the I/O block size to the given NUMBER of bytes"), 110}, + {"message", 'M', N_("STRING"), 0, + N_("Print STRING when the end of a volume of the backup media is reached"), + 110}, + {"nonmatching", 'f', 0, 0, + N_("Only copy files that do not match any of the given patterns"), 110}, + {"numeric-uid-gid", 'n', 0, 0, + N_("In the verbose table of contents listing, show numeric UID and GID"), + 110}, + {"rsh-command", RSH_COMMAND_OPTION, N_("COMMAND"), 0, + N_("Use remote COMMAND instead of rsh"), 110}, + {"quiet", QUIET_OPTION, NULL, 0, + N_("Do not print the number of blocks copied"), 110}, + {"verbose", 'v', NULL, 0, + N_("Verbosely list the files processed"), 110}, +#ifdef DEBUG_CPIO + {"debug", DEBUG_OPTION, NULL, 0, + N_("Enable debugging info"), 110}, +#endif + {"warning", 'W', N_("FLAG"), 0, + N_("Control warning display. Currently FLAG is one of 'none', 'truncate', 'all'. Multiple options accumulate."), 110 }, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid only in copy-in mode:"), 200}, + {"pattern-file", 'E', N_("FILE"), 0, + N_("In copy-in mode, read additional patterns specifying filenames to extract or list from FILE"), 210}, + {"no-absolute-filenames", NO_ABSOLUTE_FILENAMES_OPTION, 0, 0, + N_("Create all files relative to the current directory"), 210}, + {"only-verify-crc", ONLY_VERIFY_CRC_OPTION, 0, 0, + N_("When reading a CRC format archive in copy-in mode, only verify the CRC's of each file in the archive, don't actually extract the files"), 210}, + {"rename", 'r', 0, 0, + N_("Interactively rename files"), 210}, + {"rename-batch-file", RENAME_BATCH_FILE_OPTION, N_("FILE"), OPTION_HIDDEN, + "", 210}, + {"swap", 'b', NULL, 0, + N_("Swap both halfwords of words and bytes of halfwords in the data. Equivalent to -sS"), 210}, + {"swap-bytes", 's', NULL, 0, + N_("Swap the bytes of each halfword in the files"), 210}, + {"swap-halfwords", 'S', NULL, 0, + N_("Swap the halfwords of each word (4 bytes) in the files"), + 210}, + {"to-stdout", TO_STDOUT_OPTION, NULL, 0, + N_("Extract files to standard output"), 210}, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid only in copy-out mode:"), 300}, + {"append", 'A', 0, 0, + N_("Append to an existing archive."), 310 }, + {NULL, 'O', N_("[[USER@]HOST:]FILE-NAME"), 0, + N_("Archive filename to use instead of standard output. Optional USER and HOST specify the user and host names in case of a remote archive"), 310}, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid only in copy-pass mode:"), 400}, + {"link", 'l', 0, 0, + N_("Link files instead of copying them, when possible"), 410}, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid for copy-out and copy-pass modes:"), 500}, + {"null", '0', 0, 0, + N_("A list of filenames is terminated by a null character instead of a newline"), 510 }, + {NULL, 'I', N_("[[USER@]HOST:]FILE-NAME"), 0, + N_("Archive filename to use instead of standard input. Optional USER and HOST specify the user and host names in case of a remote archive"), 510}, + {"dereference", 'L', 0, 0, + N_("Dereference symbolic links (copy the files that they point to instead of copying the links)."), 510}, + {"owner", 'R', N_("[USER][:.][GROUP]"), 0, + N_("Set the ownership of all files created to the specified USER and/or GROUP"), 510}, + {"sparse", SPARSE_OPTION, NULL, 0, + N_("Write files with large blocks of zeros as sparse files"), 510}, + {"reset-access-time", 'a', NULL, 0, + N_("Reset the access times of files after reading them"), 510}, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid for copy-in and copy-pass modes:"), 600}, + {"preserve-modification-time", 'm', 0, 0, + N_("Retain previous file modification times when creating files"), 610}, + {"make-directories", 'd', 0, 0, + N_("Create leading directories where needed"), 610}, + {"no-preserve-owner", NO_PRESERVE_OWNER_OPTION, 0, 0, + N_("Do not change the ownership of the files"), 610}, + {"unconditional", 'u', NULL, 0, + N_("Replace all files unconditionally"), 610}, + + {NULL, 0, NULL, 0, + N_("Informative options:"), 700 }, + + {"help", '?', 0, 0, N_("Give this help list"), -1}, + {"usage", USAGE_OPTION, 0, 0, N_("Give a short usage message"), -1}, + {"license", LICENSE_OPTION, 0, 0, N_("Print license and exit"), -1}, + {"version", VERSION_OPTION, 0, 0, N_("Print program version"), -1}, + /* FIXME -V (--dot) conflicts with the default short option for + --version */ + + {0, 0, 0, 0} +}; + +static char *input_archive_name = 0; +static char *output_archive_name = 0; + +static void +license () +{ + printf ("%s (%s) %s\n%s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION, + "Copyright (C) 2004 Free Software Foundation, Inc.\n"); + printf (_(" GNU cpio is free software; you can redistribute it and/or modify\n" + " it under the terms of the GNU General Public License as published by\n" + " the Free Software Foundation; either version 2 of the License, or\n" + " (at your option) any later version.\n" + "\n" + " GNU cpio is distributed in the hope that it will be useful,\n" + " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + " GNU General Public License for more details.\n" + "\n" + " You should have received a copy of the GNU General Public License\n" + " along with GNU cpio; if not, write to the Free Software\n" + " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n")); + exit (0); +} + +static int +warn_control (char *arg) +{ + static struct warn_tab { + char *name; + int flag; + } warn_tab[] = { + { "none", CPIO_WARN_ALL }, + { "truncate", CPIO_WARN_TRUNCATE }, + { "all", CPIO_WARN_ALL }, + { NULL } + }; + struct warn_tab *wt; + int offset = 0; + + if (strcmp (arg, "none") == 0) + { + warn_option = 0; + return 0; + } + + if (strlen (arg) > 2 && memcmp (arg, "no-", 3) == 0) + offset = 3; + + for (wt = warn_tab; wt->name; wt++) + if (strcmp (arg + offset, wt->name) == 0) + { + if (offset) + warn_option &= ~wt->flag; + else + warn_option |= wt->flag; + return 0; + } + + return 1; +} + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case '0': /* Read null-terminated filenames. */ + name_end = '\0'; + break; + + case 'a': /* Reset access times. */ + reset_time_flag = true; + break; + + case 'A': /* Append to the archive. */ + append_flag = true; + break; + + case 'b': /* Swap bytes and halfwords. */ + swap_bytes_flag = true; + swap_halfwords_flag = true; + break; + + case 'B': /* Set block size to 5120. */ + io_block_size = 5120; + break; + + case BLOCK_SIZE_OPTION: /* --block-size */ + io_block_size = atoi (arg); + if (io_block_size < 1) + error (2, 0, _("invalid block size")); + io_block_size *= 512; + break; + + case 'c': /* Use the old portable ASCII format. */ + if (archive_format != arf_unknown) + USAGE_ERROR ((0, 0, _("Archive format multiply defined"))); +#ifdef SVR4_COMPAT + archive_format = arf_newascii; /* -H newc. */ +#else + archive_format = arf_oldascii; /* -H odc. */ +#endif + break; + + case 'C': /* Block size. */ + io_block_size = atoi (arg); + if (io_block_size < 1) + error (2, 0, _("invalid block size")); + break; + + case 'd': /* Create directories where needed. */ + create_dir_flag = true; + break; + + case 'f': /* Only copy files not matching patterns. */ + copy_matching_files = false; + break; + + case 'E': /* Pattern file name. */ + pattern_file_name = arg; + break; + + case 'F': /* Archive file name. */ + archive_name = arg; + break; + + case 'H': /* Header format name. */ + if (archive_format != arf_unknown) + USAGE_ERROR ((0, 0, _("Archive format multiply defined"))); + if (!strcasecmp (arg, "crc")) + archive_format = arf_crcascii; + else if (!strcasecmp (arg, "newc")) + archive_format = arf_newascii; + else if (!strcasecmp (arg, "odc")) + archive_format = arf_oldascii; + else if (!strcasecmp (arg, "bin")) + archive_format = arf_binary; + else if (!strcasecmp (arg, "ustar")) + archive_format = arf_ustar; + else if (!strcasecmp (arg, "tar")) + archive_format = arf_tar; + else if (!strcasecmp (arg, "hpodc")) + archive_format = arf_hpoldascii; + else if (!strcasecmp (arg, "hpbin")) + archive_format = arf_hpbinary; + else + error (2, 0, _("\ +invalid archive format `%s'; valid formats are:\n\ +crc newc odc bin ustar tar (all-caps also recognized)"), arg); + break; + + case 'i': /* Copy-in mode. */ + if (copy_function != 0) + USAGE_ERROR ((0, 0, _("Mode already defined"))); + copy_function = process_copy_in; + break; + + case 'I': /* Input archive file name. */ + input_archive_name = arg; + break; + + case 'k': /* Handle corrupted archives. We always handle + corrupted archives, but recognize this + option for compatability. */ + break; + + case 'l': /* Link files when possible. */ + link_flag = true; + break; + + case 'L': /* Dereference symbolic links. */ + xstat = stat; + break; + + case 'm': /* Retain previous file modify times. */ + retain_time_flag = true; + break; + + case 'M': /* New media message. */ + set_new_media_message (arg); + break; + + case 'n': /* Long list owner and group as numbers. */ + numeric_uid = true; + break; + + case NO_ABSOLUTE_FILENAMES_OPTION: /* --no-absolute-filenames */ + no_abs_paths_flag = true; + break; + + case NO_PRESERVE_OWNER_OPTION: /* --no-preserve-owner */ + if (set_owner_flag || set_group_flag) + USAGE_ERROR ((0, 0, + _("--no-preserve-owner cannot be used with --owner"))); + no_chown_flag = true; + break; + + case 'o': /* Copy-out mode. */ + if (copy_function != 0) + USAGE_ERROR ((0, 0, _("Mode already defined"))); + copy_function = process_copy_out; + break; + + case 'O': /* Output archive file name. */ + output_archive_name = arg; + break; + + case ONLY_VERIFY_CRC_OPTION: + only_verify_crc_flag = true; + break; + + case 'p': /* Copy-pass mode. */ + if (copy_function != 0) + USAGE_ERROR ((0, 0, _("Mode already defined"))); + copy_function = process_copy_pass; + break; + + case RSH_COMMAND_OPTION: + rsh_command_option = arg; + break; + + case 'r': /* Interactively rename. */ + rename_flag = true; + break; + + case RENAME_BATCH_FILE_OPTION: + rename_batch_file = arg; + break; + + case QUIET_OPTION: + quiet_flag = true; + break; + + case 'R': /* Set the owner. */ + if (no_chown_flag) + USAGE_ERROR ((0, 0, + _("--owner cannot be used with --no-preserve-owner"))); + { + char *e, *u, *g; + + e = parse_user_spec (arg, &set_owner, &set_group, &u, &g); + if (e) + error (2, 0, "%s: %s", arg, e); + if (u) + { + free (u); + set_owner_flag = true; + } + if (g) + { + free (g); + set_group_flag = true; + } + } + break; + + case 's': /* Swap bytes. */ + swap_bytes_flag = true; + break; + + case 'S': /* Swap halfwords. */ + swap_halfwords_flag = true; + break; + + case 't': /* Only print a list. */ + table_flag = true; + break; + + case 'u': /* Replace all! Unconditionally! */ + unconditional_flag = true; + break; + + case 'v': /* Verbose! */ + verbose_flag = true; + break; + + case 'V': /* Print `.' for each file. */ + dot_flag = true; + break; + + case 'W': + if (warn_control (arg)) + argp_error (state, _("Invalid value for --warning option: %s"), arg); + break; + + case SPARSE_OPTION: + sparse_flag = true; + break; + + case FORCE_LOCAL_OPTION: + force_local_option = 1; + break; + +#ifdef DEBUG_CPIO + case DEBUG_OPTION: + debug_flag = true; + break; +#endif + + case TO_STDOUT_OPTION: + to_stdout_option = true; + break; + + case '?': + argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); + break; + + case USAGE_OPTION: + argp_state_help (state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); + break; + + case VERSION_OPTION: + fprintf (state->out_stream, "%s\n", argp_program_version); + exit (0); + + case LICENSE_OPTION: + license (); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, + parse_opt, + N_("[destination-directory]"), + doc, + NULL, + NULL, + NULL +}; + +/* Process the arguments. Set all options and set up the copy pass + directory or the copy in patterns. */ + +void +process_args (int argc, char *argv[]) +{ + void (*copy_in) (); /* Work around for pcc bug. */ + void (*copy_out) (); + int index; + + if (argc < 2) + USAGE_ERROR ((0, 0, + _("You must specify one of -oipt options.\nTry `%s --help' or `%s --usage' for more information.\n"), + program_name, program_name)); + + xstat = lstat; + + if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER|ARGP_NO_HELP, &index, NULL)) + exit (1); + + /* Do error checking and look at other args. */ + + if (copy_function == 0) + { + if (table_flag) + copy_function = process_copy_in; + else + USAGE_ERROR ((0, 0, + _("You must specify one of -oipt options.\nTry `%s --help' or `%s --usage' for more information.\n"), + program_name, program_name)); + } + + /* Work around for pcc bug. */ + copy_in = process_copy_in; + copy_out = process_copy_out; + + if (copy_function == copy_in) + { + archive_des = 0; + CHECK_USAGE(link_flag, "--link", "--extract"); + CHECK_USAGE(reset_time_flag, "--reset", "--extract"); + CHECK_USAGE(xstat != lstat, "--dereference", "--extract"); + CHECK_USAGE(append_flag, "--append", "--extract"); + CHECK_USAGE(sparse_flag, "--sparse", "--extract"); + CHECK_USAGE(output_archive_name, "-O", "--extract"); + if (to_stdout_option) + { + CHECK_USAGE(create_dir_flag, "--make-directories", "--to-stdout"); + CHECK_USAGE(rename_flag, "--rename", "--to-stdout"); + CHECK_USAGE(no_chown_flag, "--no-preserve-owner", "--to-stdout"); + CHECK_USAGE(set_owner_flag||set_group_flag, "--owner", "--to-stdout"); + CHECK_USAGE(retain_time_flag, "--preserve-modification-time", + "--to-stdout"); + } + + if (archive_name && input_archive_name) + USAGE_ERROR((0, 0, _("Both -I and -F are used in copy-in mode"))); + + if (archive_format == arf_crcascii) + crc_i_flag = true; + num_patterns = argc - index; + save_patterns = &argv[index]; + if (input_archive_name) + archive_name = input_archive_name; + } + else if (copy_function == copy_out) + { + if (index != argc) + USAGE_ERROR ((0, 0, _("Too many arguments"))); + + archive_des = 1; + CHECK_USAGE(create_dir_flag, "--make-directories", "--create"); + CHECK_USAGE(rename_flag, "--rename", "--create"); + CHECK_USAGE(table_flag, "--list", "--create"); + CHECK_USAGE(unconditional_flag, "--unconditional", "--create"); + CHECK_USAGE(link_flag, "--link", "--create"); + CHECK_USAGE(retain_time_flag, "--preserve-modification-time", + "--create"); + CHECK_USAGE(no_chown_flag, "--no-preserve-owner", "--create"); + CHECK_USAGE(set_owner_flag||set_group_flag, "--owner", "--create"); + CHECK_USAGE(swap_bytes_flag, "--swap-bytes (--swap)", "--create"); + CHECK_USAGE(swap_halfwords_flag, "--swap-halfwords (--swap)", + "--create"); + CHECK_USAGE(to_stdout_option, "--to-stdout", "--create"); + + if (append_flag && !(archive_name || output_archive_name)) + USAGE_ERROR ((0, 0, + _("--append is used but no archive file name is given (use -F or -O options"))); + + CHECK_USAGE(rename_batch_file, "--rename-batch-file", "--create"); + CHECK_USAGE(no_abs_paths_flag, "--no-absolute-pathnames", "--create"); + CHECK_USAGE(input_archive_name, "-I", "--create"); + if (archive_name && output_archive_name) + USAGE_ERROR ((0, 0, _("Both -O and -F are used in copy-out mode"))); + + if (archive_format == arf_unknown) + archive_format = arf_binary; + if (output_archive_name) + archive_name = output_archive_name; + } + else + { + /* Copy pass. */ + if (index != argc - 1) + USAGE_ERROR ((0, 0, _("Too many arguments"))); + + if (archive_format != arf_unknown) + USAGE_ERROR((0, 0, + _("Archive format is not specified in copy-pass mode (use --format option)"))); + + CHECK_USAGE(swap_bytes_flag, "--swap-bytes (--swap)", "--pass-through"); + CHECK_USAGE(swap_halfwords_flag, "--swap-halfwords (--swap)", + "--pass-through"); + CHECK_USAGE(table_flag, "--list", "--pass-through"); + CHECK_USAGE(rename_flag, "--rename", "--pass-through"); + CHECK_USAGE(append_flag, "--append", "--pass-through"); + CHECK_USAGE(rename_batch_file, "--rename-batch-file", "--pass-through"); + CHECK_USAGE(no_abs_paths_flag, "--no-absolute-pathnames", + "--pass-through"); + CHECK_USAGE(to_stdout_option, "--to-stdout", "--pass-through"); + + directory_name = argv[index]; + } + + if (archive_name) + { + if (copy_function != copy_in && copy_function != copy_out) + USAGE_ERROR ((0, 0, + _("-F can be used only with --create or --extract"))); + archive_des = open_archive (archive_name); + if (archive_des < 0) + error (1, errno, "%s", archive_name); + } + + /* Prevent SysV non-root users from giving away files inadvertantly. + This happens automatically on BSD, where only root can give + away files. */ + if (set_owner_flag == false && set_group_flag == false && geteuid ()) + no_chown_flag = true; +} + +/* Initialize the input and output buffers to their proper size and + initialize all variables associated with the input and output + buffers. */ + +void +initialize_buffers () +{ + int in_buf_size, out_buf_size; + + if (copy_function == process_copy_in) + { + /* Make sure the input buffer can always hold 2 blocks and that it + is big enough to hold 1 tar record (512 bytes) even if it + is not aligned on a block boundary. The extra buffer space + is needed by process_copyin and peek_in_buf to automatically + figure out what kind of archive it is reading. */ + if (io_block_size >= 512) + in_buf_size = 2 * io_block_size; + else + in_buf_size = 1024; + out_buf_size = DISK_IO_BLOCK_SIZE; + } + else if (copy_function == process_copy_out) + { + in_buf_size = DISK_IO_BLOCK_SIZE; + out_buf_size = io_block_size; + } + else + { + in_buf_size = DISK_IO_BLOCK_SIZE; + out_buf_size = DISK_IO_BLOCK_SIZE; + } + + input_buffer = (char *) xmalloc (in_buf_size); + in_buff = input_buffer; + input_buffer_size = in_buf_size; + input_size = 0; + input_bytes = 0; + + output_buffer = (char *) xmalloc (out_buf_size); + out_buff = output_buffer; + output_size = 0; + output_bytes = 0; + + /* Clear the block of zeros. */ + bzero (zeros_512, 512); +} + +int +main (int argc, char *argv[]) +{ +#ifdef HAVE_LOCALE_H + setlocale (LC_ALL, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = argv[0]; + umask (0); + +#ifdef __TURBOC__ + _fmode = O_BINARY; /* Put stdin and stdout in binary mode. */ +#endif +#ifdef __EMX__ /* gcc on OS/2. */ + _response (&argc, &argv); + _wildcard (&argc, &argv); +#endif + + process_args (argc, argv); + + initialize_buffers (); + + (*copy_function) (); + + if (archive_des >= 0 && rmtclose (archive_des) == -1) + error (1, errno, _("error closing archive")); + + exit (0); +} diff --git a/contrib/cpio/src/makepath.c b/contrib/cpio/src/makepath.c new file mode 100644 index 0000000..9587ba8 --- /dev/null +++ b/contrib/cpio/src/makepath.c @@ -0,0 +1,301 @@ +/* makepath.c -- Ensure that a directory path exists. + Copyright (C) 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie <djm@gnu.ai.mit.edu> and + Jim Meyering <meyering@cs.utexas.edu>. */ + +/* This copy of makepath is almost like the fileutils one, but has + changes for HPUX CDF's. Maybe the 2 versions of makepath can + come together again in the future. */ + +#include <system.h> + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#else +#ifdef _AIX + #pragma alloca +#else +char *alloca (); +#endif +#endif +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#if !defined(S_ISDIR) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +#include <errno.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#else +extern int errno; +#endif + +#if defined(STDC_HEADERS) || defined(HAVE_STRING_H) +#include <string.h> +#ifndef index +#define index strchr +#endif +#else +#include <strings.h> +#endif + +/* Ensure that the directory ARGPATH exists. + Remove any trailing slashes from ARGPATH before calling this function. + + Make any leading directories that don't already exist, with + permissions PARENT_MODE. + If the last element of ARGPATH does not exist, create it as + a new directory with permissions MODE. + If OWNER and GROUP are non-negative, make them the UID and GID of + created directories. + If VERBOSE_FMT_STRING is nonzero, use it as a printf format + string for printing a message after successfully making a directory, + with the name of the directory that was just made as an argument. + + Return 0 if ARGPATH exists as a directory with the proper + ownership and permissions when done, otherwise 1. */ + +int +make_path (char *argpath, + int mode, + int parent_mode, + uid_t owner, + gid_t group, + char *verbose_fmt_string) +{ + char *dirpath; /* A copy we can scribble NULs on. */ + struct stat stats; + int retval = 0; + int oldmask = umask (0); + dirpath = alloca (strlen (argpath) + 1); + strcpy (dirpath, argpath); + + if (stat (dirpath, &stats)) + { + char *slash; + int tmp_mode; /* Initial perms for leading dirs. */ + int re_protect; /* Should leading dirs be unwritable? */ + struct ptr_list + { + char *dirname_end; + struct ptr_list *next; + }; + struct ptr_list *p, *leading_dirs = NULL; + + /* If leading directories shouldn't be writable or executable, + or should have set[ug]id or sticky bits set and we are setting + their owners, we need to fix their permissions after making them. */ + if (((parent_mode & 0300) != 0300) + || (owner != (uid_t) -1 && group != (gid_t) -1 + && (parent_mode & 07000) != 0)) + { + tmp_mode = 0700; + re_protect = 1; + } + else + { + tmp_mode = parent_mode; + re_protect = 0; + } + + slash = dirpath; + while (*slash == '/') + slash++; + while ((slash = index (slash, '/'))) + { +#ifdef HPUX_CDF + int iscdf; + iscdf = 0; +#endif + *slash = '\0'; + if (stat (dirpath, &stats)) + { +#ifdef HPUX_CDF + /* If this component of the pathname ends in `+' and is + followed by 2 `/'s, then this is a CDF. We remove the + `+' from the name and create the directory. Later + we will "hide" the directory. */ + if ( (*(slash +1) == '/') && (*(slash -1) == '+') ) + { + iscdf = 1; + *(slash -1) = '\0'; + } +#endif + if (mkdir (dirpath, tmp_mode)) + { + error (0, errno, _("cannot make directory `%s'"), dirpath); + umask (oldmask); + return 1; + } + else + { + if (verbose_fmt_string != NULL) + error (0, 0, verbose_fmt_string, dirpath); + + if (owner != (uid_t) -1 && group != (gid_t) -1 + && chown (dirpath, owner, group) +#ifdef AFS + && errno != EPERM +#endif + ) + { + error (0, errno, "%s", dirpath); + retval = 1; + } + if (re_protect) + { + struct ptr_list *new = (struct ptr_list *) + alloca (sizeof (struct ptr_list)); + new->dirname_end = slash; + new->next = leading_dirs; + leading_dirs = new; + } +#ifdef HPUX_CDF + if (iscdf) + { + /* If this is a CDF, "hide" the directory by setting + its hidden/setuid bit. Also add the `+' back to + its name (since once it's "hidden" we must refer + to as `name+' instead of `name'). */ + chmod (dirpath, 04700); + *(slash - 1) = '+'; + } +#endif + } + } + else if (!S_ISDIR (stats.st_mode)) + { + error (0, 0, _("`%s' exists but is not a directory"), dirpath); + umask (oldmask); + return 1; + } + + *slash++ = '/'; + + /* Avoid unnecessary calls to `stat' when given + pathnames containing multiple adjacent slashes. */ + while (*slash == '/') + slash++; + } + + /* We're done making leading directories. + Make the final component of the path. */ + + if (mkdir (dirpath, mode)) + { + /* In some cases, if the final component in dirpath was `.' then we + just got an EEXIST error from that last mkdir(). If that's + the case, ignore it. */ + if ( (errno != EEXIST) || + (stat (dirpath, &stats) != 0) || + (!S_ISDIR (stats.st_mode) ) ) + { + error (0, errno, _("cannot make directory `%s'"), dirpath); + umask (oldmask); + return 1; + } + } + if (verbose_fmt_string != NULL) + error (0, 0, verbose_fmt_string, dirpath); + + if (owner != (uid_t) -1 && group != (gid_t) -1) + { + if (chown (dirpath, owner, group) +#ifdef AFS + && errno != EPERM +#endif + ) + { + error (0, errno, "%s", dirpath); + retval = 1; + } + } + /* chown may have turned off some permission bits we wanted. */ + if ((mode & 07000) != 0 && chmod (dirpath, mode)) + { + error (0, errno, "%s", dirpath); + retval = 1; + } + + /* If the mode for leading directories didn't include owner "wx" + privileges, we have to reset their protections to the correct + value. */ + for (p = leading_dirs; p != NULL; p = p->next) + { + *(p->dirname_end) = '\0'; +#if 0 + /* cpio always calls make_path with parent mode 0700, so + we don't have to do this. If we ever do have to do this, + we have to stat the directory first to get the setuid + bit so we don't break HP CDF's. */ + if (chmod (dirpath, parent_mode)) + { + error (0, errno, "%s", dirpath); + retval = 1; + } +#endif + + } + } + else + { + /* We get here if the entire path already exists. */ + + if (!S_ISDIR (stats.st_mode)) + { + error (0, 0, _("`%s' exists but is not a directory"), dirpath); + umask (oldmask); + return 1; + } + + /* chown must precede chmod because on some systems, + chown clears the set[ug]id bits for non-superusers, + resulting in incorrect permissions. + On System V, users can give away files with chown and then not + be able to chmod them. So don't give files away. */ + + if (owner != (uid_t) -1 && group != (gid_t) -1 + && chown (dirpath, owner, group) +#ifdef AFS + && errno != EPERM +#endif + ) + { + error (0, errno, "%s", dirpath); + retval = 1; + } + if (chmod (dirpath, mode)) + { + error (0, errno, "%s", dirpath); + retval = 1; + } + } + + umask (oldmask); + return retval; +} diff --git a/contrib/cpio/src/safe-stat.h b/contrib/cpio/src/safe-stat.h new file mode 100644 index 0000000..3a37970 --- /dev/null +++ b/contrib/cpio/src/safe-stat.h @@ -0,0 +1 @@ +#define SAFE_STAT(path,pbuf) stat(path,pbuf) diff --git a/contrib/cpio/src/tar.c b/contrib/cpio/src/tar.c new file mode 100644 index 0000000..939d83a --- /dev/null +++ b/contrib/cpio/src/tar.c @@ -0,0 +1,500 @@ +/* tar.c - read in write tar headers for cpio + Copyright (C) 1992, 2001, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <system.h> + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "filetypes.h" +#include "cpiohdr.h" +#include "dstring.h" +#include "extern.h" +#include <rmt.h> +#include "tarhdr.h" + +/* Stash the tar linkname in static storage. */ + +static char * +stash_tar_linkname (char *linkname) +{ + static char hold_tar_linkname[TARLINKNAMESIZE + 1]; + + strncpy (hold_tar_linkname, linkname, TARLINKNAMESIZE); + hold_tar_linkname[TARLINKNAMESIZE] = '\0'; + return hold_tar_linkname; +} + +/* Try to split a long file name into prefix and suffix parts separated + by a slash. Return the length of the prefix (not counting the slash). */ + +static size_t +split_long_name (const char *name, size_t length) +{ + size_t i; + + if (length > TARPREFIXSIZE) + length = TARPREFIXSIZE+2; + for (i = length - 1; i > 0; i--) + if (name[i] == '/') + break; + return i; +} + +/* Stash the tar filename and optional prefix in static storage. */ + +static char * +stash_tar_filename (char *prefix, char *filename) +{ + static char hold_tar_filename[TARNAMESIZE + TARPREFIXSIZE + 2]; + if (prefix == NULL || *prefix == '\0') + { + strncpy (hold_tar_filename, filename, TARNAMESIZE); + hold_tar_filename[TARNAMESIZE] = '\0'; + } + else + { + strncpy (hold_tar_filename, prefix, TARPREFIXSIZE); + hold_tar_filename[TARPREFIXSIZE] = '\0'; + strcat (hold_tar_filename, "/"); + strncat (hold_tar_filename, filename, TARNAMESIZE); + hold_tar_filename[TARPREFIXSIZE + TARNAMESIZE] = '\0'; + } + return hold_tar_filename; +} + +/* Convert a number into a string of octal digits. + Convert long VALUE into a DIGITS-digit field at WHERE, + including a trailing space and room for a NUL. DIGITS==3 means + 1 digit, a space, and room for a NUL. + + We assume the trailing NUL is already there and don't fill it in. + This fact is used by start_header and finish_header, so don't change it! + + This is be equivalent to: + sprintf (where, "%*lo ", digits - 2, value); + except that sprintf fills in the trailing NUL and we don't. */ + +static void +to_oct (register long value, register int digits, register char *where) +{ + --digits; /* Leave the trailing NUL slot alone. */ + + /* Produce the digits -- at least one. */ + do + { + where[--digits] = '0' + (char) (value & 7); /* One octal digit. */ + value >>= 3; + } + while (digits > 0 && value != 0); + + /* Add leading zeroes, if necessary. */ + while (digits > 0) + where[--digits] = '0'; +} + + + +/* Compute and return a checksum for TAR_HDR, + counting the checksum bytes as if they were spaces. */ + +unsigned long +tar_checksum (struct tar_header *tar_hdr) +{ + unsigned long sum = 0; + char *p = (char *) tar_hdr; + char *q = p + TARRECORDSIZE; + int i; + + while (p < tar_hdr->chksum) + sum += *p++ & 0xff; + for (i = 0; i < 8; ++i) + { + sum += ' '; + ++p; + } + while (p < q) + sum += *p++ & 0xff; + return sum; +} + +/* Write out header FILE_HDR, including the file name, to file + descriptor OUT_DES. */ + +void +write_out_tar_header (struct new_cpio_header *file_hdr, int out_des) +{ + int name_len; + union tar_record tar_rec; + struct tar_header *tar_hdr = (struct tar_header *) &tar_rec; + + bzero ((char *) &tar_rec, TARRECORDSIZE); + + /* process_copy_out must ensure that file_hdr->c_name is short enough, + or we will lose here. */ + + name_len = strlen (file_hdr->c_name); + if (name_len <= TARNAMESIZE) + { + strncpy (tar_hdr->name, file_hdr->c_name, name_len); + } + else + { + /* Fit as much as we can into `name', the rest into `prefix'. */ + int prefix_len = split_long_name (file_hdr->c_name, name_len); + + strncpy (tar_hdr->prefix, file_hdr->c_name, prefix_len); + strncpy (tar_hdr->name, file_hdr->c_name + prefix_len + 1, + name_len - prefix_len - 1); + } + + /* Ustar standard (POSIX.1-1988) requires the mode to contain only 3 octal + digits */ + to_oct (file_hdr->c_mode & MODE_ALL, 8, tar_hdr->mode); + to_oct (file_hdr->c_uid, 8, tar_hdr->uid); + to_oct (file_hdr->c_gid, 8, tar_hdr->gid); + to_oct (file_hdr->c_filesize, 12, tar_hdr->size); + to_oct (file_hdr->c_mtime, 12, tar_hdr->mtime); + + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFREG: + if (file_hdr->c_tar_linkname) + { + /* process_copy_out makes sure that c_tar_linkname is shorter + than TARLINKNAMESIZE. */ + strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname, + TARLINKNAMESIZE); + tar_hdr->typeflag = LNKTYPE; + to_oct (0, 12, tar_hdr->size); + } + else + tar_hdr->typeflag = REGTYPE; + break; + case CP_IFDIR: + tar_hdr->typeflag = DIRTYPE; + break; + case CP_IFCHR: + tar_hdr->typeflag = CHRTYPE; + break; + case CP_IFBLK: + tar_hdr->typeflag = BLKTYPE; + break; +#ifdef CP_IFIFO + case CP_IFIFO: + tar_hdr->typeflag = FIFOTYPE; + break; +#endif /* CP_IFIFO */ +#ifdef CP_IFLNK + case CP_IFLNK: + tar_hdr->typeflag = SYMTYPE; + /* process_copy_out makes sure that c_tar_linkname is shorter + than TARLINKNAMESIZE. */ + strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname, + TARLINKNAMESIZE); + to_oct (0, 12, tar_hdr->size); + break; +#endif /* CP_IFLNK */ + } + + if (archive_format == arf_ustar) + { + char *name; + + strncpy (tar_hdr->magic, TMAGIC, TMAGLEN); + strncpy (tar_hdr->magic + TMAGLEN, TVERSION, TVERSLEN); + + name = getuser (file_hdr->c_uid); + if (name) + strcpy (tar_hdr->uname, name); + name = getgroup (file_hdr->c_gid); + if (name) + strcpy (tar_hdr->gname, name); + + to_oct (file_hdr->c_rdev_maj, 8, tar_hdr->devmajor); + to_oct (file_hdr->c_rdev_min, 8, tar_hdr->devminor); + } + + to_oct (tar_checksum (tar_hdr), 8, tar_hdr->chksum); + + tape_buffered_write ((char *) &tar_rec, out_des, TARRECORDSIZE); +} + +/* Return nonzero iff all the bytes in BLOCK are NUL. + SIZE is the number of bytes to check in BLOCK; it must be a + multiple of sizeof (long). */ + +int +null_block (long *block, int size) +{ + register long *p = block; + register int i = size / sizeof (long); + + while (i--) + if (*p++) + return 0; + return 1; +} + +/* Read a tar header, including the file name, from file descriptor IN_DES + into FILE_HDR. */ + +void +read_in_tar_header (struct new_cpio_header *file_hdr, int in_des) +{ + long bytes_skipped = 0; + int warned = false; + union tar_record tar_rec; + struct tar_header *tar_hdr = (struct tar_header *) &tar_rec; + uid_t *uidp; + gid_t *gidp; + + tape_buffered_read ((char *) &tar_rec, in_des, TARRECORDSIZE); + + /* Check for a block of 0's. */ + if (null_block ((long *) &tar_rec, TARRECORDSIZE)) + { +#if 0 + /* Found one block of 512 0's. If the next block is also all 0's + then this is the end of the archive. If not, assume the + previous block was all corruption and continue reading + the archive. */ + /* Commented out because GNU tar sometimes creates archives with + only one block of 0's at the end. This happened for the + cpio 2.0 distribution! */ + tape_buffered_read ((char *) &tar_rec, in_des, TARRECORDSIZE); + if (null_block ((long *) &tar_rec, TARRECORDSIZE)) +#endif + { + file_hdr->c_name = "TRAILER!!!"; + return; + } +#if 0 + bytes_skipped = TARRECORDSIZE; +#endif + } + + while (1) + { + otoa (tar_hdr->chksum, &file_hdr->c_chksum); + + if (file_hdr->c_chksum != tar_checksum (tar_hdr)) + { + /* If the checksum is bad, skip 1 byte and try again. When + we try again we do not look for an EOF record (all zeros), + because when we start skipping bytes in a corrupted archive + the chances are pretty good that we might stumble across + 2 blocks of 512 zeros (that probably is not really the last + record) and it is better to miss the EOF and give the user + a "premature EOF" error than to give up too soon on a corrupted + archive. */ + if (!warned) + { + error (0, 0, _("invalid header: checksum error")); + warned = true; + } + bcopy (((char *) &tar_rec) + 1, (char *) &tar_rec, + TARRECORDSIZE - 1); + tape_buffered_read (((char *) &tar_rec) + (TARRECORDSIZE - 1), in_des, 1); + ++bytes_skipped; + continue; + } + + if (archive_format != arf_ustar) + file_hdr->c_name = stash_tar_filename (NULL, tar_hdr->name); + else + file_hdr->c_name = stash_tar_filename (tar_hdr->prefix, tar_hdr->name); + file_hdr->c_nlink = 1; + otoa (tar_hdr->mode, &file_hdr->c_mode); + file_hdr->c_mode = file_hdr->c_mode & 07777; + /* Debian hack: This version of cpio uses the -n flag also to extract + tar archives using the numeric UID/GID instead of the user/group + names in /etc/passwd and /etc/groups. (98/10/15) -BEM */ + if (archive_format == arf_ustar && !numeric_uid + && (uidp = getuidbyname (tar_hdr->uname))) + file_hdr->c_uid = *uidp; + else + otoa (tar_hdr->uid, &file_hdr->c_uid); + + if (archive_format == arf_ustar && !numeric_uid + && (gidp = getgidbyname (tar_hdr->gname))) + file_hdr->c_gid = *gidp; + else + otoa (tar_hdr->gid, &file_hdr->c_gid); + otoa (tar_hdr->size, &file_hdr->c_filesize); + otoa (tar_hdr->mtime, &file_hdr->c_mtime); + otoa (tar_hdr->devmajor, (unsigned long *) &file_hdr->c_rdev_maj); + otoa (tar_hdr->devminor, (unsigned long *) &file_hdr->c_rdev_min); + file_hdr->c_tar_linkname = NULL; + + switch (tar_hdr->typeflag) + { + case REGTYPE: + case CONTTYPE: /* For now, punt. */ + default: + file_hdr->c_mode |= CP_IFREG; + break; + case DIRTYPE: + file_hdr->c_mode |= CP_IFDIR; + break; + case CHRTYPE: + file_hdr->c_mode |= CP_IFCHR; + /* If a POSIX tar header has a valid linkname it's always supposed + to set typeflag to be LNKTYPE. System V.4 tar seems to + be broken, and for device files with multiple links it + puts the name of the link into linkname, but leaves typeflag + as CHRTYPE, BLKTYPE, FIFOTYPE, etc. */ + file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname); + + /* Does POSIX say that the filesize must be 0 for devices? We + assume so, but HPUX's POSIX tar sets it to be 1 which causes + us problems (when reading an archive we assume we can always + skip to the next file by skipping filesize bytes). For + now at least, it's easier to clear filesize for devices, + rather than check everywhere we skip in copyin.c. */ + file_hdr->c_filesize = 0; + break; + case BLKTYPE: + file_hdr->c_mode |= CP_IFBLK; + file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname); + file_hdr->c_filesize = 0; + break; +#ifdef CP_IFIFO + case FIFOTYPE: + file_hdr->c_mode |= CP_IFIFO; + file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname); + file_hdr->c_filesize = 0; + break; +#endif + case SYMTYPE: +#ifdef CP_IFLNK + file_hdr->c_mode |= CP_IFLNK; + file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname); + file_hdr->c_filesize = 0; + break; + /* Else fall through. */ +#endif + case LNKTYPE: + file_hdr->c_mode |= CP_IFREG; + file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname); + file_hdr->c_filesize = 0; + break; + + case AREGTYPE: + /* Old tar format; if the last char in filename is '/' then it is + a directory, otherwise it's a regular file. */ + if (file_hdr->c_name[strlen (file_hdr->c_name) - 1] == '/') + file_hdr->c_mode |= CP_IFDIR; + else + file_hdr->c_mode |= CP_IFREG; + break; + } + break; + } + if (bytes_skipped > 0) + warn_junk_bytes (bytes_skipped); +} + +/* Convert the string of octal digits S into a number and store + it in *N. Return nonzero if the whole string was converted, + zero if there was something after the number. + Skip leading and trailing spaces. */ + +int +otoa (char *s, unsigned long *n) +{ + unsigned long val = 0; + + while (*s == ' ') + ++s; + while (*s >= '0' && *s <= '7') + val = 8 * val + *s++ - '0'; + while (*s == ' ') + ++s; + *n = val; + return *s == '\0'; +} + +/* Return + 2 if BUF is a valid POSIX tar header (the checksum is correct + and it has the "ustar" magic string), + 1 if BUF is a valid old tar header (the checksum is correct), + 0 otherwise. */ + +int +is_tar_header (char *buf) +{ + struct tar_header *tar_hdr = (struct tar_header *) buf; + unsigned long chksum; + + otoa (tar_hdr->chksum, &chksum); + + if (chksum != tar_checksum (tar_hdr)) + return 0; + + /* GNU tar 1.10 and previous set the magic field to be "ustar " instead + of "ustar\0". Only look at the first 5 characters of the magic + field so we can recognize old GNU tar ustar archives. */ + if (!strncmp (tar_hdr->magic, TMAGIC, TMAGLEN - 1)) + return 2; + return 1; +} + +/* Return true if the filename is too long to fit in a tar header. + For old tar headers, if the filename's length is less than or equal + to 100 then it will fit, otherwise it will not. For POSIX tar headers, + if the filename's length is less than or equal to 100 then it + will definitely fit, and if it is greater than 256 then it + will definitely not fit. If the length is between 100 and 256, + then the filename will fit only if it is possible to break it + into a 155 character "prefix" and 100 character "name". There + must be a slash between the "prefix" and the "name", although + the slash is not stored or counted in either the "prefix" or + the "name", and there must be at least one character in both + the "prefix" and the "name". If it is not possible to break down + the filename like this then it will not fit. */ + +int +is_tar_filename_too_long (char *name) +{ + int whole_name_len; + int prefix_name_len; + char *p; + + whole_name_len = strlen (name); + if (whole_name_len <= TARNAMESIZE) + return false; + + if (archive_format != arf_ustar) + return true; + + if (whole_name_len > TARNAMESIZE + TARPREFIXSIZE + 1) + return true; + + /* See whether we can split up the name into acceptably-sized + `prefix' and `name' (`p') pieces. */ + prefix_name_len = split_long_name (name, whole_name_len); + + /* Interestingly, a name consisting of a slash followed by + TARNAMESIZE characters can't be stored, because the prefix + would be empty, and thus ignored. */ + if (prefix_name_len == 0 + || whole_name_len - prefix_name_len - 1 > TARNAMESIZE) + return true; + + return false; +} diff --git a/contrib/cpio/src/tar.h b/contrib/cpio/src/tar.h new file mode 100644 index 0000000..79f289e --- /dev/null +++ b/contrib/cpio/src/tar.h @@ -0,0 +1,112 @@ +/* Extended tar format from POSIX.1. + Copyright (C) 1992 Free Software Foundation, Inc. + Written by David J. MacKenzie. + +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 this 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 _TAR_H + +#define _TAR_H 1 + + +/* A tar archive consists of 512-byte blocks. + Each file in the archive has a header block followed by 0+ data blocks. + Two blocks of NUL bytes indicate the end of the archive. */ + +/* The fields of header blocks: + All strings are stored as ISO 646 (approximately ASCII) strings. + + Fields are numeric unless otherwise noted below; numbers are ISO 646 + representations of octal numbers, with leading zeros as needed. + + linkname is only valid when typeflag==LNKTYPE. It doesn't use prefix; + files that are links to pathnames >100 chars long can not be stored + in a tar archive. + + If typeflag=={LNKTYPE,SYMTYPE,DIRTYPE} then size must be 0. + + devmajor and devminor are only valid for typeflag=={BLKTYPE,CHRTYPE}. + + chksum contains the sum of all 512 bytes in the header block, + treating each byte as an 8-bit unsigned value and treating the + 8 bytes of chksum as blank characters. + + uname and gname are used in preference to uid and gid, if those + names exist locally. + + Field Name Byte Offset Length in Bytes Field Type + name 0 100 NUL-terminated if NUL fits + mode 100 8 + uid 108 8 + gid 116 8 + size 124 12 + mtime 136 12 + chksum 148 8 + typeflag 156 1 see below + linkname 157 100 NUL-terminated if NUL fits + magic 257 6 must be TMAGIC (NUL term.) + version 263 2 must be TVERSION + uname 265 32 NUL-terminated + gname 297 32 NUL-terminated + devmajor 329 8 + devminor 337 8 + prefix 345 155 NUL-terminated if NUL fits + + If the first character of prefix is '\0', the file name is name; + otherwise, it is prefix/name. Files whose pathnames don't fit in that + length can not be stored in a tar archive. */ + +/* The bits in mode: */ +#define TSUID 04000 +#define TSGID 02000 +#define TSVTX 01000 +#define TUREAD 00400 +#define TUWRITE 00200 +#define TUEXEC 00100 +#define TGREAD 00040 +#define TGWRITE 00020 +#define TGEXEC 00010 +#define TOREAD 00004 +#define TOWRITE 00002 +#define TOEXEC 00001 + +/* The values for typeflag: + Values 'A'-'Z' are reserved for custom implementations. + All other values are reserved for future POSIX.1 revisions. */ + +#define REGTYPE '0' /* Regular file (preferred code). */ +#define AREGTYPE '\0' /* Regular file (alternate code). */ +#define LNKTYPE '1' /* Hard link. */ +#define SYMTYPE '2' /* Symbolic link (hard if not supported). */ +#define CHRTYPE '3' /* Character special. */ +#define BLKTYPE '4' /* Block special. */ +#define DIRTYPE '5' /* Directory. */ +#define FIFOTYPE '6' /* Named pipe. */ +#define CONTTYPE '7' /* Contiguous file */ + /* (regular file if not supported). */ + +/* Contents of magic field and its length. */ +#define TMAGIC "ustar" +#define TMAGLEN 6 + +/* Contents of the version field and its length. */ +#define TVERSION "00" +#define TVERSLEN 2 + + +#endif /* tar.h */ diff --git a/contrib/cpio/src/tarhdr.h b/contrib/cpio/src/tarhdr.h new file mode 100644 index 0000000..8b1211d --- /dev/null +++ b/contrib/cpio/src/tarhdr.h @@ -0,0 +1,62 @@ +/* Extended tar header from POSIX.1. + Copyright (C) 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _TARHDR_H + +#define _TARHDR_H 1 + +#include <tar.h> + +/* Size of `name' field. */ +#define TARNAMESIZE 100 + +/* Size of `linkname' field. */ +#define TARLINKNAMESIZE 100 + +/* Size of `prefix' field. */ +#define TARPREFIXSIZE 155 + +/* Size of entire tar header. */ +#define TARRECORDSIZE 512 + +struct tar_header +{ + char name[TARNAMESIZE]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag; + char linkname[TARLINKNAMESIZE]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[TARPREFIXSIZE]; +}; + +union tar_record +{ + struct tar_header header; + char buffer[TARRECORDSIZE]; +}; + +#endif /* tarhdr.h */ diff --git a/contrib/cpio/src/userspec.c b/contrib/cpio/src/userspec.c new file mode 100644 index 0000000..c426acd --- /dev/null +++ b/contrib/cpio/src/userspec.c @@ -0,0 +1,257 @@ +/* userspec.c -- Parse a user and group string. + Copyright (C) 1989, 1990, 1991, 1992, 2001, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ + +#include <system.h> + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#else +#ifdef _AIX + #pragma alloca +#else +char *alloca (); +#endif +#endif +#endif + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> + +#if !HAVE_DECL_GETPWNAM +extern struct passwd *getpwnam (const char *name); +#endif +#if !HAVE_DECL_GETGRNAM +extern struct group *getgrnam (const char *name); +#endif +#if !HAVE_DECL_GETGRGID +extern struct group *getgrgid (gid_t gid); +#endif + +#ifndef HAVE_ENDPWENT +# define endpwent() +#endif +#ifndef HAVE_ENDGRENT +# define endgrent() +#endif + +/* Perform the equivalent of the statement `dest = strdup (src);', + but obtaining storage via alloca instead of from the heap. */ + +#define V_STRDUP(dest, src) \ + do \ + { \ + int _len = strlen ((src)); \ + (dest) = (char *) alloca (_len + 1); \ + strcpy (dest, src); \ + } \ + while (0) + +/* Return nonzero if STR represents an unsigned decimal integer, + otherwise return 0. */ + +static int +isnumber (const char *str) +{ + for (; *str; str++) + if (!isdigit (*str)) + return 0; + return 1; +} + +/* Extract from NAME, which has the form "[user][:.][group]", + a USERNAME, UID U, GROUPNAME, and GID G. + Either user or group, or both, must be present. + If the group is omitted but the ":" or "." separator is given, + use the given user's login group. + + USERNAME and GROUPNAME will be in newly malloc'd memory. + Either one might be NULL instead, indicating that it was not + given and the corresponding numeric ID was left unchanged. + + Return NULL if successful, a static error message string if not. */ + +const char * +parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid, + char **username_arg, char **groupname_arg) +{ + static const char *tired = "virtual memory exhausted"; + const char *error_msg; + char *spec; /* A copy we can write on. */ + struct passwd *pwd; + struct group *grp; + char *g, *u, *separator; + char *groupname; + + error_msg = NULL; + *username_arg = *groupname_arg = NULL; + groupname = NULL; + + V_STRDUP (spec, spec_arg); + + /* Find the separator if there is one. */ + separator = index (spec, ':'); + if (separator == NULL) + separator = index (spec, '.'); + + /* Replace separator with a NUL. */ + if (separator != NULL) + *separator = '\0'; + + /* Set U and G to non-zero length strings corresponding to user and + group specifiers or to NULL. */ + u = (*spec == '\0' ? NULL : spec); + + g = (separator == NULL || *(separator + 1) == '\0' + ? NULL + : separator + 1); + + if (u == NULL && g == NULL) + return "can not omit both user and group"; + + if (u != NULL) + { + pwd = getpwnam (u); + if (pwd == NULL) + { + + if (!isnumber (u)) + error_msg = _("invalid user"); + else + { + int use_login_group; + use_login_group = (separator != NULL && g == NULL); + if (use_login_group) + error_msg = _("cannot get the login group of a numeric UID"); + else + *uid = atoi (u); + } + } + else + { + *uid = pwd->pw_uid; + if (g == NULL && separator != NULL) + { + /* A separator was given, but a group was not specified, + so get the login group. */ + *gid = pwd->pw_gid; + grp = getgrgid (pwd->pw_gid); + if (grp == NULL) + { + /* This is enough room to hold the unsigned decimal + representation of any 32-bit quantity and the trailing + zero byte. */ + char uint_buf[21]; + sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid)); + V_STRDUP (groupname, uint_buf); + } + else + { + V_STRDUP (groupname, grp->gr_name); + } + endgrent (); + } + } + endpwent (); + } + + if (g != NULL && error_msg == NULL) + { + /* Explicit group. */ + grp = getgrnam (g); + if (grp == NULL) + { + if (!isnumber (g)) + error_msg = _("invalid group"); + else + *gid = atoi (g); + } + else + *gid = grp->gr_gid; + endgrent (); /* Save a file descriptor. */ + + if (error_msg == NULL) + V_STRDUP (groupname, g); + } + + if (error_msg == NULL) + { + if (u != NULL) + { + *username_arg = strdup (u); + if (*username_arg == NULL) + error_msg = tired; + } + + if (groupname != NULL && error_msg == NULL) + { + *groupname_arg = strdup (groupname); + if (*groupname_arg == NULL) + { + if (*username_arg != NULL) + { + free (*username_arg); + *username_arg = NULL; + } + error_msg = tired; + } + } + } + + return error_msg; +} + +#ifdef TEST + +#define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s)) + +int +main (int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) + { + const char *e; + char *username, *groupname; + uid_t uid; + gid_t gid; + char *tmp; + + tmp = strdup (argv[i]); + e = parse_user_spec (tmp, &uid, &gid, &username, &groupname); + free (tmp); + printf ("%s: %u %u %s %s %s\n", + argv[i], + (unsigned int) uid, + (unsigned int) gid, + NULL_CHECK (username), + NULL_CHECK (groupname), + NULL_CHECK (e)); + } + + exit (0); +} + +#endif diff --git a/contrib/cpio/src/util.c b/contrib/cpio/src/util.c new file mode 100644 index 0000000..4b64648 --- /dev/null +++ b/contrib/cpio/src/util.c @@ -0,0 +1,1247 @@ +/* util.c - Several utility routines for cpio. + Copyright (C) 1990, 1991, 1992, 2001, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <system.h> + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "cpiohdr.h" +#include "dstring.h" +#include "extern.h" +#include <rmt.h> + +#include <sys/ioctl.h> + +#ifdef HAVE_SYS_MTIO_H +#ifdef HAVE_SYS_IO_TRIOCTL_H +#include <sys/io/trioctl.h> +#endif +#include <sys/mtio.h> +#endif + +#if !HAVE_DECL_ERRNO +extern int errno; +#endif + +/* Write `output_size' bytes of `output_buffer' to file + descriptor OUT_DES and reset `output_size' and `out_buff'. */ + +void +tape_empty_output_buffer (int out_des) +{ + int bytes_written; + +#ifdef BROKEN_LONG_TAPE_DRIVER + static long output_bytes_before_lseek = 0; + + /* Some tape drivers seem to have a signed internal seek pointer and + they lose if it overflows and becomes negative (e.g. when writing + tapes > 2Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the + seek pointer and prevent it from overflowing. */ + if (output_is_special + && ( (output_bytes_before_lseek += output_size) >= 1073741824L) ) + { + lseek(out_des, 0L, SEEK_SET); + output_bytes_before_lseek = 0; + } +#endif + + bytes_written = rmtwrite (out_des, output_buffer, output_size); + if (bytes_written != output_size) + { + int rest_bytes_written; + int rest_output_size; + + if (output_is_special + && (bytes_written >= 0 + || (bytes_written < 0 + && (errno == ENOSPC || errno == EIO || errno == ENXIO)))) + { + get_next_reel (out_des); + if (bytes_written > 0) + rest_output_size = output_size - bytes_written; + else + rest_output_size = output_size; + rest_bytes_written = rmtwrite (out_des, output_buffer, + rest_output_size); + if (rest_bytes_written != rest_output_size) + error (1, errno, _("write error")); + } + else + error (1, errno, _("write error")); + } + output_bytes += output_size; + out_buff = output_buffer; + output_size = 0; +} + +/* Write `output_size' bytes of `output_buffer' to file + descriptor OUT_DES and reset `output_size' and `out_buff'. + If `swapping_halfwords' or `swapping_bytes' is set, + do the appropriate swapping first. Our callers have + to make sure to only set these flags if `output_size' + is appropriate (a multiple of 4 for `swapping_halfwords', + 2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE + must always be a multiple of 4 helps us (and our callers) + insure this. */ + +void +disk_empty_output_buffer (int out_des) +{ + int bytes_written; + + if (swapping_halfwords || swapping_bytes) + { + if (swapping_halfwords) + { + int complete_words; + complete_words = output_size / 4; + swahw_array (output_buffer, complete_words); + if (swapping_bytes) + swab_array (output_buffer, 2 * complete_words); + } + else + { + int complete_halfwords; + complete_halfwords = output_size /2; + swab_array (output_buffer, complete_halfwords); + } + } + + if (sparse_flag) + bytes_written = sparse_write (out_des, output_buffer, output_size); + else + bytes_written = write (out_des, output_buffer, output_size); + + if (bytes_written != output_size) + { + error (1, errno, _("write error")); + } + output_bytes += output_size; + out_buff = output_buffer; + output_size = 0; +} + +/* Exchange the halfwords of each element of the array of COUNT longs + starting at PTR. PTR does not have to be aligned at a word + boundary. */ + +void +swahw_array (char *ptr, int count) +{ + char tmp; + + for (; count > 0; --count) + { + tmp = *ptr; + *ptr = *(ptr + 2); + *(ptr + 2) = tmp; + ++ptr; + tmp = *ptr; + *ptr = *(ptr + 2); + *(ptr + 2) = tmp; + ptr += 3; + } +} + +/* Read at most NUM_BYTES or `io_block_size' bytes, whichever is smaller, + into the start of `input_buffer' from file descriptor IN_DES. + Set `input_size' to the number of bytes read and reset `in_buff'. + Exit with an error if end of file is reached. */ + +#ifdef BROKEN_LONG_TAPE_DRIVER +static long input_bytes_before_lseek = 0; +#endif + +static void +tape_fill_input_buffer (int in_des, int num_bytes) +{ +#ifdef BROKEN_LONG_TAPE_DRIVER + /* Some tape drivers seem to have a signed internal seek pointer and + they lose if it overflows and becomes negative (e.g. when writing + tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the + seek pointer and prevent it from overflowing. */ + if (input_is_special + && ( (input_bytes_before_lseek += num_bytes) >= 1073741824L) ) + { + lseek(in_des, 0L, SEEK_SET); + input_bytes_before_lseek = 0; + } +#endif + in_buff = input_buffer; + num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size; + input_size = rmtread (in_des, input_buffer, num_bytes); + if (input_size == 0 && input_is_special) + { + get_next_reel (in_des); + input_size = rmtread (in_des, input_buffer, num_bytes); + } + if (input_size < 0) + error (1, errno, _("read error")); + if (input_size == 0) + { + error (0, 0, _("premature end of file")); + exit (1); + } + input_bytes += input_size; +} + +/* Read at most NUM_BYTES or `DISK_IO_BLOCK_SIZE' bytes, whichever is smaller, + into the start of `input_buffer' from file descriptor IN_DES. + Set `input_size' to the number of bytes read and reset `in_buff'. + Exit with an error if end of file is reached. */ + +static int +disk_fill_input_buffer (int in_des, int num_bytes) +{ + in_buff = input_buffer; + num_bytes = (num_bytes < DISK_IO_BLOCK_SIZE) ? num_bytes : DISK_IO_BLOCK_SIZE; + input_size = read (in_des, input_buffer, num_bytes); + if (input_size < 0) + { + input_size = 0; + return (-1); + } + else if (input_size == 0) + return (1); + input_bytes += input_size; + return (0); +} + +/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full. + When `out_buff' fills up, flush it to file descriptor OUT_DES. */ + +void +tape_buffered_write (char *in_buf, int out_des, long num_bytes) +{ + register long bytes_left = num_bytes; /* Bytes needing to be copied. */ + register long space_left; /* Room left in output buffer. */ + + while (bytes_left > 0) + { + space_left = io_block_size - output_size; + if (space_left == 0) + tape_empty_output_buffer (out_des); + else + { + if (bytes_left < space_left) + space_left = bytes_left; + bcopy (in_buf, out_buff, (unsigned) space_left); + out_buff += space_left; + output_size += space_left; + in_buf += space_left; + bytes_left -= space_left; + } + } +} + +/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full. + When `out_buff' fills up, flush it to file descriptor OUT_DES. */ + +void +disk_buffered_write (char *in_buf, int out_des, long num_bytes) +{ + register long bytes_left = num_bytes; /* Bytes needing to be copied. */ + register long space_left; /* Room left in output buffer. */ + + while (bytes_left > 0) + { + space_left = DISK_IO_BLOCK_SIZE - output_size; + if (space_left == 0) + disk_empty_output_buffer (out_des); + else + { + if (bytes_left < space_left) + space_left = bytes_left; + bcopy (in_buf, out_buff, (unsigned) space_left); + out_buff += space_left; + output_size += space_left; + in_buf += space_left; + bytes_left -= space_left; + } + } +} + +/* Copy NUM_BYTES of buffer `in_buff' into IN_BUF. + `in_buff' may be partly full. + When `in_buff' is exhausted, refill it from file descriptor IN_DES. */ + +void +tape_buffered_read (char *in_buf, int in_des, long num_bytes) +{ + register long bytes_left = num_bytes; /* Bytes needing to be copied. */ + register long space_left; /* Bytes to copy from input buffer. */ + + while (bytes_left > 0) + { + if (input_size == 0) + tape_fill_input_buffer (in_des, io_block_size); + if (bytes_left < input_size) + space_left = bytes_left; + else + space_left = input_size; + bcopy (in_buff, in_buf, (unsigned) space_left); + in_buff += space_left; + in_buf += space_left; + input_size -= space_left; + bytes_left -= space_left; + } +} + +/* Copy the the next NUM_BYTES bytes of `input_buffer' into PEEK_BUF. + If NUM_BYTES bytes are not available, read the next `io_block_size' bytes + into the end of `input_buffer' and update `input_size'. + + Return the number of bytes copied into PEEK_BUF. + If the number of bytes returned is less than NUM_BYTES, + then EOF has been reached. */ + +int +tape_buffered_peek (char *peek_buf, int in_des, int num_bytes) +{ + long tmp_input_size; + long got_bytes; + char *append_buf; + +#ifdef BROKEN_LONG_TAPE_DRIVER + /* Some tape drivers seem to have a signed internal seek pointer and + they lose if it overflows and becomes negative (e.g. when writing + tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the + seek pointer and prevent it from overflowing. */ + if (input_is_special + && ( (input_bytes_before_lseek += num_bytes) >= 1073741824L) ) + { + lseek(in_des, 0L, SEEK_SET); + input_bytes_before_lseek = 0; + } +#endif + + while (input_size < num_bytes) + { + append_buf = in_buff + input_size; + if ( (append_buf - input_buffer) >= input_buffer_size) + { + /* We can keep up to 2 "blocks" (either the physical block size + or 512 bytes(the size of a tar record), which ever is + larger) in the input buffer when we are peeking. We + assume that our caller will never be interested in peeking + ahead at more than 512 bytes, so we know that by the time + we need a 3rd "block" in the buffer we can throw away the + first block to make room. */ + int half; + half = input_buffer_size / 2; + bcopy (input_buffer + half, input_buffer, half); + in_buff = in_buff - half; + append_buf = append_buf - half; + } + tmp_input_size = rmtread (in_des, append_buf, io_block_size); + if (tmp_input_size == 0) + { + if (input_is_special) + { + get_next_reel (in_des); + tmp_input_size = rmtread (in_des, append_buf, io_block_size); + } + else + break; + } + if (tmp_input_size < 0) + error (1, errno, _("read error")); + input_bytes += tmp_input_size; + input_size += tmp_input_size; + } + if (num_bytes <= input_size) + got_bytes = num_bytes; + else + got_bytes = input_size; + bcopy (in_buff, peek_buf, (unsigned) got_bytes); + return got_bytes; +} + +/* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */ + +void +tape_toss_input (int in_des, long num_bytes) +{ + register long bytes_left = num_bytes; /* Bytes needing to be copied. */ + register long space_left; /* Bytes to copy from input buffer. */ + + while (bytes_left > 0) + { + if (input_size == 0) + tape_fill_input_buffer (in_des, io_block_size); + if (bytes_left < input_size) + space_left = bytes_left; + else + space_left = input_size; + + if (crc_i_flag && only_verify_crc_flag) + { + int k; + for (k = 0; k < space_left; ++k) + crc += in_buff[k] & 0xff; + } + + in_buff += space_left; + input_size -= space_left; + bytes_left -= space_left; + } +} + +static void +write_nuls_to_file (long num_bytes, int out_des, + void (*writer) (char *in_buf, int out_des, long num_bytes)) +{ + long blocks; + long extra_bytes; + long i; + + blocks = num_bytes / 512; + extra_bytes = num_bytes % 512; + for (i = 0; i < blocks; ++i) + writer (zeros_512, out_des, 512); + if (extra_bytes) + writer (zeros_512, out_des, extra_bytes); +} + +/* Copy a file using the input and output buffers, which may start out + partly full. After the copy, the files are not closed nor the last + block flushed to output, and the input buffer may still be partly + full. If `crc_i_flag' is set, add each byte to `crc'. + IN_DES is the file descriptor for input; + OUT_DES is the file descriptor for output; + NUM_BYTES is the number of bytes to copy. */ + +void +copy_files_tape_to_disk (int in_des, int out_des, long num_bytes) +{ + long size; + long k; + + while (num_bytes > 0) + { + if (input_size == 0) + tape_fill_input_buffer (in_des, io_block_size); + size = (input_size < num_bytes) ? input_size : num_bytes; + if (crc_i_flag) + { + for (k = 0; k < size; ++k) + crc += in_buff[k] & 0xff; + } + disk_buffered_write (in_buff, out_des, size); + num_bytes -= size; + input_size -= size; + in_buff += size; + } +} +/* Copy a file using the input and output buffers, which may start out + partly full. After the copy, the files are not closed nor the last + block flushed to output, and the input buffer may still be partly + full. If `crc_i_flag' is set, add each byte to `crc'. + IN_DES is the file descriptor for input; + OUT_DES is the file descriptor for output; + NUM_BYTES is the number of bytes to copy. */ + +void +copy_files_disk_to_tape (int in_des, int out_des, long num_bytes, + char *filename) +{ + long size; + long k; + int rc; + long original_num_bytes; + + original_num_bytes = num_bytes; + + while (num_bytes > 0) + { + if (input_size == 0) + if (rc = disk_fill_input_buffer (in_des, + num_bytes < DISK_IO_BLOCK_SIZE ? + num_bytes : DISK_IO_BLOCK_SIZE)) + { + if (rc > 0) + error (0, 0, _("File %s shrunk by %ld bytes, padding with zeros"), + filename, num_bytes); + else + error (0, 0, _("Read error at byte %ld in file %s, padding with zeros"), + original_num_bytes - num_bytes, filename); + write_nuls_to_file (num_bytes, out_des, tape_buffered_write); + break; + } + size = (input_size < num_bytes) ? input_size : num_bytes; + if (crc_i_flag) + { + for (k = 0; k < size; ++k) + crc += in_buff[k] & 0xff; + } + tape_buffered_write (in_buff, out_des, size); + num_bytes -= size; + input_size -= size; + in_buff += size; + } +} +/* Copy a file using the input and output buffers, which may start out + partly full. After the copy, the files are not closed nor the last + block flushed to output, and the input buffer may still be partly + full. If `crc_i_flag' is set, add each byte to `crc'. + IN_DES is the file descriptor for input; + OUT_DES is the file descriptor for output; + NUM_BYTES is the number of bytes to copy. */ + +void +copy_files_disk_to_disk (int in_des, int out_des, long num_bytes, + char *filename) +{ + long size; + long k; + long original_num_bytes; + int rc; + + original_num_bytes = num_bytes; + while (num_bytes > 0) + { + if (input_size == 0) + if (rc = disk_fill_input_buffer (in_des, num_bytes)) + { + if (rc > 0) + error (0, 0, _("File %s shrunk by %ld bytes, padding with zeros"), + filename, num_bytes); + else + error (0, 0, _("Read error at byte %ld in file %s, padding with zeros"), + original_num_bytes - num_bytes, filename); + write_nuls_to_file (num_bytes, out_des, disk_buffered_write); + break; + } + size = (input_size < num_bytes) ? input_size : num_bytes; + if (crc_i_flag) + { + for (k = 0; k < size; ++k) + crc += in_buff[k] & 0xff; + } + disk_buffered_write (in_buff, out_des, size); + num_bytes -= size; + input_size -= size; + in_buff += size; + } +} + +/* Warn if file changed while it was being copied. */ + +void +warn_if_file_changed (char *file_name, unsigned long old_file_size, + unsigned long old_file_mtime) +{ + struct stat new_file_stat; + if ((*xstat) (file_name, &new_file_stat) < 0) + { + error (0, errno, "%s", file_name); + return; + } + + /* Only check growth, shrinkage detected in copy_files_disk_to_{disk,tape}() + */ + if (new_file_stat.st_size > old_file_size) + error (0, 0, _("File %s grew, %ld new bytes not copied"), + file_name, (long)(new_file_stat.st_size - old_file_size)); + + else if (new_file_stat.st_mtime != old_file_mtime) + error (0, 0, _("File %s was modified while being copied"), file_name); +} + +/* Create all directories up to but not including the last part of NAME. + Do not destroy any nondirectories while creating directories. */ + +void +create_all_directories (char *name) +{ + char *dir; + int mode; +#ifdef HPUX_CDF + int cdf; +#endif + + dir = dir_name (name); + mode = 0700; +#ifdef HPUX_CDF + cdf = islastparentcdf (name); + if (cdf) + { + dir [strlen (dir) - 1] = '\0'; /* remove final + */ + mode = 04700; + } + +#endif + + if (dir == NULL) + error (2, 0, _("virtual memory exhausted")); + + if (dir[0] != '.' || dir[1] != '\0') + make_path (dir, mode, 0700, -1, -1, (char *) NULL); + + free (dir); +} + +/* Prepare to append to an archive. We have been in + process_copy_in, keeping track of the position where + the last header started in `last_header_start'. Now we + have the starting position of the last header (the TRAILER!!! + header, or blank record for tar archives) and we want to start + writing (appending) over the last header. The last header may + be in the middle of a block, so to keep the buffering in sync + we lseek back to the start of the block, read everything up + to but not including the last header, lseek back to the start + of the block, and then do a copy_buf_out of what we read. + Actually, we probably don't have to worry so much about keeping the + buffering perfect since you can only append to archives that + are disk files. */ + +void +prepare_append (int out_file_des) +{ + int start_of_header; + int start_of_block; + int useful_bytes_in_block; + char *tmp_buf; + + start_of_header = last_header_start; + /* Figure out how many bytes we will rewrite, and where they start. */ + useful_bytes_in_block = start_of_header % io_block_size; + start_of_block = start_of_header - useful_bytes_in_block; + + if (lseek (out_file_des, start_of_block, SEEK_SET) < 0) + error (1, errno, _("cannot seek on output")); + if (useful_bytes_in_block > 0) + { + tmp_buf = (char *) xmalloc (useful_bytes_in_block); + read (out_file_des, tmp_buf, useful_bytes_in_block); + if (lseek (out_file_des, start_of_block, SEEK_SET) < 0) + error (1, errno, _("cannot seek on output")); + /* fix juo -- is this copy_tape_buf_out? or copy_disk? */ + tape_buffered_write (tmp_buf, out_file_des, useful_bytes_in_block); + free (tmp_buf); + } + + /* We are done reading the archive, so clear these since they + will now be used for reading in files that we are appending + to the archive. */ + input_size = 0; + input_bytes = 0; + in_buff = input_buffer; +} + +/* Support for remembering inodes with multiple links. Used in the + "copy in" and "copy pass" modes for making links instead of copying + the file. */ + +struct inode_val +{ + unsigned long inode; + unsigned long major_num; + unsigned long minor_num; + char *file_name; +}; + +/* Inode hash table. Allocated by first call to add_inode. */ +static struct inode_val **hash_table = NULL; + +/* Size of current hash table. Initial size is 47. (47 = 2*22 + 3) */ +static int hash_size = 22; + +/* Number of elements in current hash table. */ +static int hash_num; + +/* Find the file name associated with NODE_NUM. If there is no file + associated with NODE_NUM, return NULL. */ + +char * +find_inode_file (unsigned long node_num, unsigned long major_num, + unsigned long minor_num) +{ + int start; /* Initial hash location. */ + int temp; /* Rehash search variable. */ + + if (hash_table != NULL) + { + /* Hash function is node number modulo the table size. */ + start = node_num % hash_size; + + /* Initial look into the table. */ + if (hash_table[start] == NULL) + return NULL; + if (hash_table[start]->inode == node_num + && hash_table[start]->major_num == major_num + && hash_table[start]->minor_num == minor_num) + return hash_table[start]->file_name; + + /* The home position is full with a different inode record. + Do a linear search terminated by a NULL pointer. */ + for (temp = (start + 1) % hash_size; + hash_table[temp] != NULL && temp != start; + temp = (temp + 1) % hash_size) + { + if (hash_table[temp]->inode == node_num + && hash_table[start]->major_num == major_num + && hash_table[start]->minor_num == minor_num) + return hash_table[temp]->file_name; + } + } + return NULL; +} + +/* Do the hash insert. Used in normal inserts and resizing the hash + table. It is guaranteed that there is room to insert the item. + NEW_VALUE is the pointer to the previously allocated inode, file + name association record. */ + +static void +hash_insert (struct inode_val *new_value) +{ + int start; /* Home position for the value. */ + int temp; /* Used for rehashing. */ + + /* Hash function is node number modulo the table size. */ + start = new_value->inode % hash_size; + + /* Do the initial look into the table. */ + if (hash_table[start] == NULL) + { + hash_table[start] = new_value; + return; + } + + /* If we get to here, the home position is full with a different inode + record. Do a linear search for the first NULL pointer and insert + the new item there. */ + temp = (start + 1) % hash_size; + while (hash_table[temp] != NULL) + temp = (temp + 1) % hash_size; + + /* Insert at the NULL. */ + hash_table[temp] = new_value; +} + +/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */ + +void +add_inode (unsigned long node_num, char *file_name, unsigned long major_num, + unsigned long minor_num) +{ + struct inode_val *temp; + + /* Create new inode record. */ + temp = (struct inode_val *) xmalloc (sizeof (struct inode_val)); + temp->inode = node_num; + temp->major_num = major_num; + temp->minor_num = minor_num; + temp->file_name = xstrdup (file_name); + + /* Do we have to increase the size of (or initially allocate) + the hash table? */ + if (hash_num == hash_size || hash_table == NULL) + { + struct inode_val **old_table; /* Pointer to old table. */ + int i; /* Index for re-insert loop. */ + + /* Save old table. */ + old_table = hash_table; + if (old_table == NULL) + hash_num = 0; + + /* Calculate new size of table and allocate it. + Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ... + where 3197 and most of the sizes after 6397 are not prime. The other + numbers listed are prime. */ + hash_size = 2 * hash_size + 3; + hash_table = (struct inode_val **) + xmalloc (hash_size * sizeof (struct inode_val *)); + bzero (hash_table, hash_size * sizeof (struct inode_val *)); + + /* Insert the values from the old table into the new table. */ + for (i = 0; i < hash_num; i++) + hash_insert (old_table[i]); + + if (old_table != NULL) + free (old_table); + } + + /* Insert the new record and increment the count of elements in the + hash table. */ + hash_insert (temp); + hash_num++; +} + + +/* Open FILE in the mode specified by the command line options + and return an open file descriptor for it, + or -1 if it can't be opened. */ + +int +open_archive (char *file) +{ + int fd; + void (*copy_in) (); /* Workaround for pcc bug. */ + + copy_in = process_copy_in; + + if (copy_function == copy_in) + fd = rmtopen (file, O_RDONLY | O_BINARY, 0666, rsh_command_option); + else + { + if (!append_flag) + fd = rmtopen (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666, + rsh_command_option); + else + fd = rmtopen (file, O_RDWR | O_BINARY, 0666, rsh_command_option); + } + + return fd; +} + +/* Attempt to rewind the tape drive on file descriptor TAPE_DES + and take it offline. */ + +void +tape_offline (int tape_des) +{ +#if defined(MTIOCTOP) && defined(MTOFFL) + struct mtop control; + + control.mt_op = MTOFFL; + control.mt_count = 1; + rmtioctl (tape_des, MTIOCTOP, (char*) &control); /* Don't care if it fails. */ +#endif +} + +/* The file on file descriptor TAPE_DES is assumed to be magnetic tape + (or floppy disk or other device) and the end of the medium + has been reached. Ask the user for to mount a new "tape" to continue + the processing. If the user specified the device name on the + command line (with the -I, -O, -F or --file options), then we can + automatically re-open the same device to use the next medium. If the + user did not specify the device name, then we have to ask them which + device to use. */ + +void +get_next_reel (int tape_des) +{ + static int reel_number = 1; + FILE *tty_in; /* File for interacting with user. */ + FILE *tty_out; /* File for interacting with user. */ + int old_tape_des; + char *next_archive_name; + dynamic_string new_name; + char *str_res; + + ds_init (&new_name, 128); + + /* Open files for interactive communication. */ + tty_in = fopen (TTY_NAME, "r"); + if (tty_in == NULL) + error (2, errno, TTY_NAME); + tty_out = fopen (TTY_NAME, "w"); + if (tty_out == NULL) + error (2, errno, TTY_NAME); + + old_tape_des = tape_des; + tape_offline (tape_des); + rmtclose (tape_des); + + /* Give message and wait for carrage return. User should hit carrage return + only after loading the next tape. */ + ++reel_number; + if (new_media_message) + fprintf (tty_out, "%s", new_media_message); + else if (new_media_message_with_number) + fprintf (tty_out, "%s%d%s", new_media_message_with_number, reel_number, + new_media_message_after_number); + else if (archive_name) + fprintf (tty_out, _("Found end of tape. Load next tape and press RETURN. ")); + else + fprintf (tty_out, _("Found end of tape. To continue, type device/file name when ready.\n")); + + fflush (tty_out); + + if (archive_name) + { + int c; + + do + c = getc (tty_in); + while (c != EOF && c != '\n'); + + tape_des = open_archive (archive_name); + if (tape_des == -1) + error (1, errno, "%s", archive_name); + } + else + { + do + { + if (tape_des < 0) + { + fprintf (tty_out, + _("To continue, type device/file name when ready.\n")); + fflush (tty_out); + } + + str_res = ds_fgets (tty_in, &new_name); + if (str_res == NULL || str_res[0] == '\0') + exit (1); + next_archive_name = str_res; + + tape_des = open_archive (next_archive_name); + if (tape_des == -1) + error (0, errno, "%s", next_archive_name); + } + while (tape_des < 0); + } + + /* We have to make sure that `tape_des' has not changed its value even + though we closed it and reopened it, since there are local + copies of it in other routines. This works fine on Unix (even with + rmtread and rmtwrite) since open will always return the lowest + available file descriptor and we haven't closed any files (e.g., + stdin, stdout or stderr) that were opened before we originally opened + the archive. */ + + if (tape_des != old_tape_des) + error (1, 0, _("internal error: tape descriptor changed from %d to %d"), + old_tape_des, tape_des); + + free (new_name.ds_string); + fclose (tty_in); + fclose (tty_out); +} + +/* If MESSAGE does not contain the string "%d", make `new_media_message' + a copy of MESSAGE. If MESSAGES does contain the string "%d", make + `new_media_message_with_number' a copy of MESSAGE up to, but + not including, the string "%d", and make `new_media_message_after_number' + a copy of MESSAGE after the string "%d". */ + +void +set_new_media_message (char *message) +{ + char *p; + int prev_was_percent; + + p = message; + prev_was_percent = 0; + while (*p != '\0') + { + if (*p == 'd' && prev_was_percent) + break; + prev_was_percent = (*p == '%'); + ++p; + } + if (*p == '\0') + { + new_media_message = xstrdup (message); + } + else + { + int length = p - message - 1; + + new_media_message_with_number = xmalloc (length + 1); + strncpy (new_media_message_with_number, message, length); + new_media_message_with_number[length] = '\0'; + length = strlen (p + 1); + new_media_message_after_number = xmalloc (length + 1); + strcpy (new_media_message_after_number, p + 1); + } +} + +#ifdef SYMLINK_USES_UMASK +/* Most machines always create symlinks with rwxrwxrwx protection, + but some (HP/UX 8.07; maybe DEC's OSF on MIPS, too?) use the + umask when creating symlinks, so if your umask is 022 you end + up with rwxr-xr-x symlinks (although HP/UX seems to completely + ignore the protection). There doesn't seem to be any way to + manipulate the modes once the symlinks are created (e.g. + a hypothetical "lchmod"), so to create them with the right + modes we have to set the umask first. */ + +int +umasked_symlink (char *name1, char *name2, int mode) +{ + int old_umask; + int rc; + mode = ~(mode & 0777) & 0777; + old_umask = umask (mode); + rc = symlink (name1, name2); + umask (old_umask); + return rc; +} +#endif /* SYMLINK_USES_UMASK */ + +#ifdef HPUX_CDF +/* When we create a cpio archive we mark CDF's by putting an extra `/' + after their component name so we can distinguish the CDF's when we + extract the archive (in case the "hidden" directory's files appear + in the archive before the directory itself). E.g., in the path + "a/b+/c", if b+ is a CDF, we will write this path as "a/b+//c" in + the archive so when we extract the archive we will know that b+ + is actually a CDF, and not an ordinary directory whose name happens + to end in `+'. We also do the same thing internally in copypass.c. */ + + +/* Take an input pathname and check it for CDF's. Insert an extra + `/' in the pathname after each "hidden" directory. If we add + any `/'s, return a malloced string (which it will reuse for + later calls so our caller doesn't have to worry about freeing + the string) instead of the original input string. */ + +char * +add_cdf_double_slashes (char *input_name) +{ + static char *ret_name = NULL; /* re-usuable return buffer (malloc'ed) */ + static int ret_size = -1; /* size of return buffer. */ + char *p; + char *q; + int n; + struct stat dir_stat; + + /* Search for a `/' preceeded by a `+'. */ + + for (p = input_name; *p != '\0'; ++p) + { + if ( (*p == '+') && (*(p + 1) == '/') ) + break; + } + + /* If we didn't find a `/' preceeded by a `+' then there are + no CDF's in this pathname. Return the original pathname. */ + + if (*p == '\0') + return input_name; + + /* There was a `/' preceeded by a `+' in the pathname. If it is a CDF + then we will need to copy the input pathname to our return + buffer so we can insert the extra `/'s. Since we can't tell + yet whether or not it is a CDF we will just always copy the + string to the return buffer. First we have to make sure the + buffer is large enough to hold the string and any number of + extra `/'s we might add. */ + + n = 2 * (strlen (input_name) + 1); + if (n >= ret_size) + { + if (ret_size < 0) + ret_name = (char *) malloc (n); + else + ret_name = (char *)realloc (ret_name, n); + ret_size = n; + } + + /* Clear the `/' after this component, so we can stat the pathname + up to and including this component. */ + ++p; + *p = '\0'; + if ((*xstat) (input_name, &dir_stat) < 0) + { + error (0, errno, "%s", input_name); + return input_name; + } + + /* Now put back the `/' after this component and copy the pathname up to + and including this component and its trailing `/' to the return + buffer. */ + *p++ = '/'; + strncpy (ret_name, input_name, p - input_name); + q = ret_name + (p - input_name); + + /* If it was a CDF, add another `/'. */ + if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) ) + *q++ = '/'; + + /* Go through the rest of the input pathname, copying it to the + return buffer, and adding an extra `/' after each CDF. */ + while (*p != '\0') + { + if ( (*p == '+') && (*(p + 1) == '/') ) + { + *q++ = *p++; + + *p = '\0'; + if ((*xstat) (input_name, &dir_stat) < 0) + { + error (0, errno, "%s", input_name); + return input_name; + } + *p = '/'; + + if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) ) + *q++ = '/'; + } + *q++ = *p++; + } + *q = '\0'; + + return ret_name; +} + +/* Is the last parent directory (e.g., c in a/b/c/d) a CDF? If the + directory name ends in `+' and is followed by 2 `/'s instead of 1 + then it is. This is only the case for cpio archives, but we don't + have to worry about tar because tar always has the directory before + its files (or else we lose). */ +int +islastparentcdf (char *path) +{ + char *newpath; + char *slash; + int slash_count; + int length; /* Length of result, not including NUL. */ + + slash = rindex (path, '/'); + if (slash == 0) + return 0; + else + { + slash_count = 0; + while (slash > path && *slash == '/') + { + ++slash_count; + --slash; + } + + + if ( (*slash == '+') && (slash_count >= 2) ) + return 1; + } + return 0; +} +#endif + +#define DISKBLOCKSIZE (512) + +enum sparse_write_states { begin, in_zeros, not_in_zeros }; + + +static int +buf_all_zeros (char *buf, int bufsize) +{ + int i; + for (i = 0; i < bufsize; ++i) + { + if (*buf++ != '\0') + return 0; + } + return 1; +} + +int delayed_seek_count = 0; + +/* Write NBYTE bytes from BUF to remote tape connection FILDES. + Return the number of bytes written on success, -1 on error. */ + +int +sparse_write (int fildes, char *buf, unsigned int nbyte) +{ + int complete_block_count; + int leftover_bytes_count; + int seek_count; + int write_count; + char *cur_write_start; + int lseek_rc; + int write_rc; + int i; + enum sparse_write_states state; + + complete_block_count = nbyte / DISKBLOCKSIZE; + leftover_bytes_count = nbyte % DISKBLOCKSIZE; + + if (delayed_seek_count != 0) + state = in_zeros; + else + state = begin; + + seek_count = delayed_seek_count; + + for (i = 0; i < complete_block_count; ++i) + { + switch (state) + { + case begin : + if (buf_all_zeros (buf, DISKBLOCKSIZE)) + { + seek_count = DISKBLOCKSIZE; + state = in_zeros; + } + else + { + cur_write_start = buf; + write_count = DISKBLOCKSIZE; + state = not_in_zeros; + } + buf += DISKBLOCKSIZE; + break; + case in_zeros : + if (buf_all_zeros (buf, DISKBLOCKSIZE)) + { + seek_count += DISKBLOCKSIZE; + } + else + { + lseek (fildes, seek_count, SEEK_CUR); + cur_write_start = buf; + write_count = DISKBLOCKSIZE; + state = not_in_zeros; + } + buf += DISKBLOCKSIZE; + break; + case not_in_zeros : + if (buf_all_zeros (buf, DISKBLOCKSIZE)) + { + write_rc = write (fildes, cur_write_start, write_count); + seek_count = DISKBLOCKSIZE; + state = in_zeros; + } + else + { + write_count += DISKBLOCKSIZE; + } + buf += DISKBLOCKSIZE; + break; + } + } + + switch (state) + { + case begin : + case in_zeros : + delayed_seek_count = seek_count; + break; + case not_in_zeros : + write_rc = write (fildes, cur_write_start, write_count); + delayed_seek_count = 0; + break; + } + + if (leftover_bytes_count != 0) + { + if (delayed_seek_count != 0) + { + lseek_rc = lseek (fildes, delayed_seek_count, SEEK_CUR); + delayed_seek_count = 0; + } + write_rc = write (fildes, buf, leftover_bytes_count); + } + return nbyte; +} |