summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authortjr <tjr@FreeBSD.org>2005-10-01 04:37:08 +0000
committertjr <tjr@FreeBSD.org>2005-10-01 04:37:08 +0000
commitc36d8046bb9e942d877c8e9414f17fc3b88be160 (patch)
tree2fe4e8cc881bec8eb4702a6ce75c06c7d8667738 /contrib
parent22bb48addfe7a42ef866f6f9cb16473f00eae5b5 (diff)
downloadFreeBSD-src-c36d8046bb9e942d877c8e9414f17fc3b88be160.zip
FreeBSD-src-c36d8046bb9e942d877c8e9414f17fc3b88be160.tar.gz
Import GNU cpio 2.6 (trimmed)
Diffstat (limited to 'contrib')
-rw-r--r--contrib/cpio/ABOUT-NLS705
-rw-r--r--contrib/cpio/AUTHORS6
-rw-r--r--contrib/cpio/COPYING11
-rw-r--r--contrib/cpio/ChangeLog433
-rw-r--r--contrib/cpio/INSTALL231
-rw-r--r--contrib/cpio/NEWS61
-rw-r--r--contrib/cpio/README6
-rw-r--r--contrib/cpio/THANKS14
-rw-r--r--contrib/cpio/TODO356
-rw-r--r--contrib/cpio/doc/cpio.141
-rw-r--r--contrib/cpio/doc/cpio.texi563
-rw-r--r--contrib/cpio/lib/alloca_.h54
-rw-r--r--contrib/cpio/lib/argp-ba.c25
-rw-r--r--contrib/cpio/lib/argp-eexst.c31
-rw-r--r--contrib/cpio/lib/argp-fmtstream.c440
-rw-r--r--contrib/cpio/lib/argp-fmtstream.h309
-rw-r--r--contrib/cpio/lib/argp-fs-xinl.c43
-rw-r--r--contrib/cpio/lib/argp-help.c1884
-rw-r--r--contrib/cpio/lib/argp-namefrob.h156
-rw-r--r--contrib/cpio/lib/argp-parse.c926
-rw-r--r--contrib/cpio/lib/argp-pv.c24
-rw-r--r--contrib/cpio/lib/argp-pvh.c31
-rw-r--r--contrib/cpio/lib/argp-xinl.c43
-rw-r--r--contrib/cpio/lib/argp.h604
-rw-r--r--contrib/cpio/lib/basename.c79
-rw-r--r--contrib/cpio/lib/dirname.c121
-rw-r--r--contrib/cpio/lib/dirname.h47
-rw-r--r--contrib/cpio/lib/error.c306
-rw-r--r--contrib/cpio/lib/error.h66
-rw-r--r--contrib/cpio/lib/exit.h32
-rw-r--r--contrib/cpio/lib/exitfail.c27
-rw-r--r--contrib/cpio/lib/exitfail.h20
-rw-r--r--contrib/cpio/lib/full-write.c83
-rw-r--r--contrib/cpio/lib/full-write.h35
-rw-r--r--contrib/cpio/lib/getopt.c1241
-rw-r--r--contrib/cpio/lib/getopt1.c174
-rw-r--r--contrib/cpio/lib/getopt_.h227
-rw-r--r--contrib/cpio/lib/getopt_int.h131
-rw-r--r--contrib/cpio/lib/gettext.h68
-rw-r--r--contrib/cpio/lib/localedir.h4
-rw-r--r--contrib/cpio/lib/mempcpy.c29
-rw-r--r--contrib/cpio/lib/mempcpy.h36
-rw-r--r--contrib/cpio/lib/rmt.h99
-rw-r--r--contrib/cpio/lib/rtapelib.c740
-rw-r--r--contrib/cpio/lib/safe-read.c82
-rw-r--r--contrib/cpio/lib/safe-read.h25
-rw-r--r--contrib/cpio/lib/safe-write.c19
-rw-r--r--contrib/cpio/lib/safe-write.h25
-rw-r--r--contrib/cpio/lib/savedir.c123
-rw-r--r--contrib/cpio/lib/savedir.h26
-rw-r--r--contrib/cpio/lib/strcase.h47
-rw-r--r--contrib/cpio/lib/strchrnul.c30
-rw-r--r--contrib/cpio/lib/strchrnul.h28
-rw-r--r--contrib/cpio/lib/stripslash.c39
-rw-r--r--contrib/cpio/lib/strndup.c55
-rw-r--r--contrib/cpio/lib/strndup.h30
-rw-r--r--contrib/cpio/lib/strnlen.c48
-rw-r--r--contrib/cpio/lib/system.h524
-rw-r--r--contrib/cpio/lib/unlocked-io.h137
-rw-r--r--contrib/cpio/lib/xalloc-die.c45
-rw-r--r--contrib/cpio/lib/xalloc.h79
-rw-r--r--contrib/cpio/lib/xmalloc.c229
-rw-r--r--contrib/cpio/src/copyin.c1588
-rw-r--r--contrib/cpio/src/copyout.c803
-rw-r--r--contrib/cpio/src/copypass.c464
-rw-r--r--contrib/cpio/src/cpio.h69
-rw-r--r--contrib/cpio/src/cpiohdr.h90
-rw-r--r--contrib/cpio/src/defer.c42
-rw-r--r--contrib/cpio/src/defer.h25
-rw-r--r--contrib/cpio/src/dstring.c107
-rw-r--r--contrib/cpio/src/dstring.h49
-rw-r--r--contrib/cpio/src/extern.h200
-rw-r--r--contrib/cpio/src/filemode.c242
-rw-r--r--contrib/cpio/src/filetypes.h84
-rw-r--r--contrib/cpio/src/global.c203
-rw-r--r--contrib/cpio/src/idcache.c206
-rw-r--r--contrib/cpio/src/main.c763
-rw-r--r--contrib/cpio/src/makepath.c301
-rw-r--r--contrib/cpio/src/safe-stat.h1
-rw-r--r--contrib/cpio/src/tar.c500
-rw-r--r--contrib/cpio/src/tar.h112
-rw-r--r--contrib/cpio/src/tarhdr.h62
-rw-r--r--contrib/cpio/src/userspec.c257
-rw-r--r--contrib/cpio/src/util.c1247
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
+ &#8216;/&#8217;).<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 (&times, 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, &times) < 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 (&times, sizeof (struct utimbuf));
+
+ times.actime = times.modtime = file_hdr->c_mtime;
+ if (utime (file_hdr->c_name, &times) < 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 (&times, sizeof (struct utimbuf));
+
+ times.actime = times.modtime = file_hdr->c_mtime;
+ if (utime (file_hdr->c_name, &times) < 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 (&times, sizeof (struct utimbuf));
+
+ times.actime = times.modtime = file_hdr->c_mtime;
+ if (utime (file_hdr->c_name, &times) < 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 (&current_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 (&times, 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, &times) < 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 (&times, 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, &times) < 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 (&times, 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, &times) < 0
+ && errno != EROFS)
+ error (0, errno, "%s", input_name.ds_string);
+ if (utime (output_name.ds_string, &times) < 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, &times) < 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, &times) < 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, &times) < 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;
+}
OpenPOWER on IntegriCloud