diff --git a/.cvsignore b/.cvsignore index c269a82..32c9d57 100644 --- a/.cvsignore +++ b/.cvsignore @@ -5,3 +5,4 @@ coreutils-5.94.tar.bz2 coreutils-5.95.tar.bz2 coreutils-5.96.tar.bz2 coreutils-5.97.tar.bz2 +coreutils-6.7.tar.bz2 diff --git a/coreutils-5.2.1-runuser.patch b/coreutils-5.2.1-runuser.patch index 1851872..0fd6ae0 100644 --- a/coreutils-5.2.1-runuser.patch +++ b/coreutils-5.2.1-runuser.patch @@ -1,6 +1,27 @@ ---- coreutils-5.97/src/su.c.runuser 2006-07-21 14:32:13.000000000 +0100 -+++ coreutils-5.97/src/su.c 2006-07-21 15:40:16.000000000 +0100 -@@ -132,9 +132,15 @@ +--- coreutils-6.7/tests/help-version.runuser 2006-12-07 09:06:04.000000000 +0000 ++++ coreutils-6.7/tests/help-version 2007-01-09 17:31:44.000000000 +0000 +@@ -168,6 +168,7 @@ + seq_args=10 + sleep_args=0 + su_args=--version ++runuser_args=--version + + # I'd rather not run sync, since it spins up disks that I've + # deliberately caused to spin down (but not unmounted). +--- coreutils-6.7/README.runuser 2006-11-24 21:28:27.000000000 +0000 ++++ coreutils-6.7/README 2007-01-09 17:32:16.000000000 +0000 +@@ -11,7 +11,7 @@ + dd df dir dircolors dirname du echo env expand expr factor false fmt fold + ginstall groups head hostid hostname id join kill link ln logname ls + md5sum mkdir mkfifo mknod mv nice nl nohup od paste pathchk pinky pr +- printenv printf ptx pwd readlink rm rmdir seq sha1sum sha224sum sha256sum ++ printenv printf ptx pwd readlink rm rmdir runuser seq sha1sum sha224sum sha256sum + sha384sum sha512sum shred shuf sleep sort split stat stty su sum sync tac + tail tee test touch tr true tsort tty uname unexpand uniq unlink uptime + users vdir wc who whoami yes +--- coreutils-6.7/src/su.c.runuser 2007-01-09 17:27:56.000000000 +0000 ++++ coreutils-6.7/src/su.c 2007-01-09 17:30:12.000000000 +0000 +@@ -110,9 +110,15 @@ #include "error.h" /* The official name of this program (e.g., no `g' prefix). */ @@ -16,7 +37,7 @@ #if HAVE_PATHS_H # include -@@ -172,6 +178,10 @@ +@@ -150,6 +156,10 @@ #ifndef USE_PAM char *crypt (); #endif @@ -24,10 +45,10 @@ +#define CHECKPASSWD 1 +#endif + - char *getpass (); char *getusershell (); void endusershell (); -@@ -180,7 +190,11 @@ + void setusershell (); +@@ -157,7 +167,11 @@ extern char **environ; static void run_shell (char const *, char const *, char **, size_t, @@ -40,7 +61,7 @@ #ifdef USE_PAM ; #else -@@ -210,6 +224,10 @@ +@@ -187,6 +201,10 @@ {"login", no_argument, NULL, 'l'}, {"preserve-environment", no_argument, NULL, 'p'}, {"shell", required_argument, NULL, 's'}, @@ -51,7 +72,7 @@ {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} -@@ -307,10 +325,12 @@ +@@ -288,10 +306,12 @@ retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh); PAM_BAIL_P; @@ -64,7 +85,7 @@ caller = getpwuid(getuid()); if(caller != NULL && caller->pw_name != NULL) { -@@ -327,6 +347,11 @@ +@@ -308,6 +328,11 @@ retval = pam_set_item(pamh, PAM_TTY, tty_name); PAM_BAIL_P; } @@ -76,7 +97,7 @@ retval = pam_authenticate(pamh, 0); PAM_BAIL_P; retval = pam_acct_mgmt(pamh, 0); -@@ -336,6 +361,7 @@ +@@ -317,6 +342,7 @@ PAM_BAIL_P; } PAM_BAIL_P; @@ -84,7 +105,7 @@ /* must be authenticated if this point was reached */ return 1; #else /* !USE_PAM */ -@@ -417,11 +443,22 @@ +@@ -398,11 +424,22 @@ /* Become the user and group(s) specified by PW. */ static void @@ -109,7 +130,7 @@ #ifdef USE_PAM pam_close_session(pamh, 0); pam_end(pamh, PAM_ABORT); -@@ -468,7 +505,11 @@ +@@ -449,7 +486,11 @@ static void run_shell (char const *shell, char const *command, char **additional_args, @@ -122,7 +143,7 @@ { size_t n_args = 1 + fast_startup + 2 * !!command + n_additional_args + 1; char const **args = xnmalloc (n_args, sizeof *args); -@@ -499,7 +540,11 @@ +@@ -480,7 +521,11 @@ child = fork(); if (child == 0) { /* child shell */ @@ -135,7 +156,7 @@ pam_end(pamh, 0); if (!same_session) setsid (); -@@ -676,6 +721,12 @@ +@@ -657,6 +702,12 @@ char *shell = NULL; struct passwd *pw; struct passwd pw_copy; @@ -148,7 +169,7 @@ initialize_main (&argc, &argv); program_name = argv[0]; -@@ -690,7 +741,11 @@ +@@ -671,7 +722,11 @@ simulate_login = false; change_environment = true; @@ -161,7 +182,7 @@ { switch (optc) { -@@ -720,6 +775,28 @@ +@@ -701,6 +756,28 @@ shell = optarg; break; @@ -190,7 +211,7 @@ case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -@@ -758,7 +835,20 @@ +@@ -739,7 +816,20 @@ : DEFAULT_SHELL); endpwent (); @@ -212,7 +233,7 @@ { #ifdef SYSLOG_FAILURE log_su (pw, false); -@@ -790,8 +880,16 @@ +@@ -771,8 +861,16 @@ modify_environment (pw, shell); #ifndef USE_PAM @@ -231,8 +252,8 @@ +#endif + ); } ---- coreutils-5.97/src/Makefile.am.runuser 2006-07-21 14:32:13.000000000 +0100 -+++ coreutils-5.97/src/Makefile.am 2006-07-21 14:32:13.000000000 +0100 +--- coreutils-6.7/src/Makefile.am.runuser 2007-01-09 17:27:56.000000000 +0000 ++++ coreutils-6.7/src/Makefile.am 2007-01-09 17:27:56.000000000 +0000 @@ -17,7 +17,7 @@ ## along with this program; if not, write to the Free Software Foundation, ## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -242,9 +263,9 @@ bin_SCRIPTS = groups bin_PROGRAMS = [ chgrp chown chmod cp dd dircolors du \ -@@ -94,6 +94,10 @@ - - su_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@ +@@ -112,6 +112,10 @@ + mv_LDADD += $(LIB_ACL) + ginstall_LDADD += $(LIB_ACL) +runuser_SOURCES = su.c +runuser_CFLAGS = -DRUNUSER -DAUTHORS="\"David MacKenzie, Dan Walsh\"" @@ -253,7 +274,7 @@ $(PROGRAMS): ../lib/libcoreutils.a SUFFIXES = .sh -@@ -108,7 +112,7 @@ +@@ -126,7 +130,7 @@ chmod +x $@-t mv $@-t $@ @@ -262,18 +283,8 @@ installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` ---- coreutils-5.97/tests/help-version.runuser 2006-06-01 08:26:09.000000000 +0100 -+++ coreutils-5.97/tests/help-version 2006-07-21 14:32:13.000000000 +0100 -@@ -137,6 +137,7 @@ - seq_args=10 - sleep_args=0 - su_args=--version -+runuser_args=--version - test_args=foo - - # This is necessary in the unusual event that there is ---- coreutils-5.97/AUTHORS.runuser 2006-07-21 14:32:13.000000000 +0100 -+++ coreutils-5.97/AUTHORS 2006-07-21 14:32:13.000000000 +0100 +--- coreutils-6.7/AUTHORS.runuser 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/AUTHORS 2007-01-09 17:27:56.000000000 +0000 @@ -60,6 +60,7 @@ readlink: Dmitry V. Levin rm: Paul Rubin, David MacKenzie, Richard Stallman, Jim Meyering @@ -282,26 +293,34 @@ seq: Ulrich Drepper sha1sum: Ulrich Drepper, Scott Miller, David Madore sha224sum: Ulrich Drepper, Scott Miller, David Madore ---- coreutils-5.97/README.runuser 2006-07-21 14:32:13.000000000 +0100 -+++ coreutils-5.97/README 2006-07-21 14:32:13.000000000 +0100 -@@ -12,7 +12,7 @@ - df dir dircolors dirname du echo env expand expr factor false fmt fold - ginstall groups head hostid hostname id join kill link ln logname ls - md5sum mkdir mkfifo mknod mv nice nl nohup od paste pathchk pinky pr -- printenv printf ptx pwd readlink rm rmdir seq sha1sum sha224sum -+ printenv printf ptx pwd readlink rm rmdir runuser seq sha1sum sha224sum - sha256sum sha384sum sha512sum shred sleep sort - split stat stty su sum sync tac tail tee test touch tr true tsort tty - uname unexpand uniq unlink uptime users vdir wc who whoami yes ---- /dev/null 2006-07-21 09:48:40.571484750 +0100 -+++ coreutils-5.97/man/runuser.x 2006-07-21 14:32:13.000000000 +0100 +--- coreutils-6.7/man/Makefile.am.runuser 2006-11-16 08:49:56.000000000 +0000 ++++ coreutils-6.7/man/Makefile.am 2007-01-09 17:32:38.000000000 +0000 +@@ -26,7 +26,7 @@ + link.1 ln.1 logname.1 \ + ls.1 md5sum.1 mkdir.1 mkfifo.1 mknod.1 mv.1 nl.1 nohup.1 od.1 \ + paste.1 pathchk.1 pr.1 printenv.1 printf.1 ptx.1 pwd.1 readlink.1 \ +- rm.1 rmdir.1 seq.1 sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \ ++ rm.1 rmdir.1 runuser.1 seq.1 sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \ + shred.1 shuf.1 sleep.1 sort.1 split.1 stat.1 \ + su.1 sum.1 sync.1 tac.1 tail.1 tee.1 test.1 touch.1 tr.1 true.1 tsort.1 \ + tty.1 unexpand.1 uniq.1 unlink.1 vdir.1 wc.1 \ +@@ -105,6 +105,7 @@ + readlink.1: $(common_dep) $(srcdir)/readlink.x ../src/readlink.c + rm.1: $(common_dep) $(srcdir)/rm.x ../src/rm.c + rmdir.1: $(common_dep) $(srcdir)/rmdir.x ../src/rmdir.c ++runuser.1: $(common_dep) $(srcdir)/runuser.x ../src/su.c + seq.1: $(common_dep) $(srcdir)/seq.x ../src/seq.c + sha1sum.1: $(common_dep) $(srcdir)/sha1sum.x ../src/md5sum.c + sha224sum.1: $(common_dep) $(srcdir)/sha224sum.x ../src/md5sum.c +--- /dev/null 2007-01-09 09:38:07.860075128 +0000 ++++ coreutils-6.7/man/runuser.x 2007-01-09 17:27:56.000000000 +0000 @@ -0,0 +1,4 @@ +[NAME] +runuser \- run a shell with substitute user and group IDs +[DESCRIPTION] +.\" Add any additional description here ---- /dev/null 2006-09-11 09:20:12.657562250 +0100 -+++ coreutils-5.97/man/runuser.1 2006-09-11 13:34:45.000000000 +0100 +--- /dev/null 2007-01-09 09:38:07.860075128 +0000 ++++ coreutils-6.7/man/runuser.1 2007-01-09 17:27:56.000000000 +0000 @@ -0,0 +1,68 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.33. +.TH RUNUSER "1" "September 2004" "runuser (coreutils) 5.2.1" "User Commands" @@ -371,22 +390,3 @@ +.B info coreutils su +.PP +should give you access to the complete manual. ---- coreutils-5.97/man/Makefile.am.runuser 2006-07-21 14:32:13.000000000 +0100 -+++ coreutils-5.97/man/Makefile.am 2006-07-21 14:32:13.000000000 +0100 -@@ -7,7 +7,7 @@ - link.1 ln.1 logname.1 \ - ls.1 md5sum.1 mkdir.1 mkfifo.1 mknod.1 mv.1 nice.1 nl.1 nohup.1 od.1 \ - paste.1 pathchk.1 pinky.1 pr.1 printenv.1 printf.1 ptx.1 pwd.1 readlink.1 \ -- rm.1 rmdir.1 seq.1 sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \ -+ rm.1 rmdir.1 runuser.1 seq.1 sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \ - shred.1 sleep.1 sort.1 split.1 stat.1 stty.1 \ - su.1 sum.1 sync.1 tac.1 tail.1 tee.1 test.1 touch.1 tr.1 true.1 tsort.1 \ - tty.1 uname.1 unexpand.1 uniq.1 unlink.1 uptime.1 users.1 vdir.1 wc.1 \ -@@ -83,6 +83,7 @@ - readlink.1: $(common_dep) $(srcdir)/readlink.x ../src/readlink.c - rm.1: $(common_dep) $(srcdir)/rm.x ../src/rm.c - rmdir.1: $(common_dep) $(srcdir)/rmdir.x ../src/rmdir.c -+runuser.1: $(common_dep) $(srcdir)/runuser.x ../src/su.c - seq.1: $(common_dep) $(srcdir)/seq.x ../src/seq.c - sha1sum.1: $(common_dep) $(srcdir)/sha1sum.x ../src/md5sum.c - sha224sum.1: $(common_dep) $(srcdir)/sha224sum.x ../src/md5sum.c diff --git a/coreutils-6.7.tar.bz2.sig b/coreutils-6.7.tar.bz2.sig new file mode 100644 index 0000000..cc2977f --- /dev/null +++ b/coreutils-6.7.tar.bz2.sig @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQBFeKRc/dLerNMzy6ERAiEJAJ435eWCOpfJkoCKoSpnh8Fwwb9XugCgnQ5H +SYg6l7M/jyvUdsFM1yS4RKk= +=GOOc +-----END PGP SIGNATURE----- diff --git a/coreutils-getgrouplist.patch b/coreutils-getgrouplist.patch index 0e2851d..0be83c0 100644 --- a/coreutils-getgrouplist.patch +++ b/coreutils-getgrouplist.patch @@ -1,18 +1,8 @@ ---- coreutils-5.92/m4/jm-macros.m4.getgrouplist 2005-09-25 06:57:46.000000000 +0100 -+++ coreutils-5.92/m4/jm-macros.m4 2005-10-25 14:28:45.000000000 +0100 -@@ -105,6 +105,7 @@ - fchmod \ - fchown \ - ftruncate \ -+ getgrouplist \ - hasmntopt \ - isascii \ - iswspace \ ---- coreutils-5.92/lib/getugroups.c.getgrouplist 2005-09-22 07:47:18.000000000 +0100 -+++ coreutils-5.92/lib/getugroups.c 2005-10-25 14:28:02.000000000 +0100 -@@ -23,6 +23,9 @@ - # include - #endif +--- coreutils-6.7/lib/getugroups.c.getgrouplist 2006-09-14 10:53:58.000000000 +0100 ++++ coreutils-6.7/lib/getugroups.c 2007-01-09 17:33:09.000000000 +0000 +@@ -21,6 +21,9 @@ + + #include +/* We do not need this code if getgrouplist(3) is available. */ +#ifndef HAVE_GETGROUPLIST @@ -20,13 +10,13 @@ #include #include /* grp.h on alpha OSF1 V2.0 uses "FILE *". */ #include -@@ -105,3 +108,4 @@ +@@ -102,3 +105,4 @@ return count; } +#endif /* have getgrouplist */ ---- coreutils-5.92/src/id.c.getgrouplist 2005-08-11 22:02:57.000000000 +0100 -+++ coreutils-5.92/src/id.c 2005-10-25 14:30:41.000000000 +0100 +--- coreutils-6.7/src/id.c.getgrouplist 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/src/id.c 2007-01-09 17:33:09.000000000 +0000 @@ -253,7 +253,14 @@ if (!username) max_n_groups = getgroups (0, NULL); @@ -67,3 +57,13 @@ } if (ng < 0) +--- coreutils-6.7/m4/jm-macros.m4.getgrouplist 2006-12-06 11:04:22.000000000 +0000 ++++ coreutils-6.7/m4/jm-macros.m4 2007-01-09 17:33:47.000000000 +0000 +@@ -64,6 +64,7 @@ + fchown \ + fchmod \ + ftruncate \ ++ getgrouplist \ + iswspace \ + mkfifo \ + mbrlen \ diff --git a/coreutils-i18n.patch b/coreutils-i18n.patch index 63c1e93..73e309e 100644 --- a/coreutils-i18n.patch +++ b/coreutils-i18n.patch @@ -1,5 +1,140 @@ ---- coreutils-5.95/src/expand.c.i18n 2005-08-12 08:16:25.000000000 +0100 -+++ coreutils-5.95/src/expand.c 2006-05-15 15:08:57.000000000 +0100 +--- /dev/null 2007-01-09 09:38:07.860075128 +0000 ++++ coreutils-6.7/tests/sort/sort-mb-tests 2007-01-09 17:18:28.000000000 +0000 +@@ -0,0 +1,58 @@ ++#! /bin/sh ++case $# in ++ 0) xx='../../src/sort';; ++ *) xx="$1";; ++esac ++test "$VERBOSE" && echo=echo || echo=: ++$echo testing program: $xx ++errors=0 ++test "$srcdir" || srcdir=. ++test "$VERBOSE" && $xx --version 2> /dev/null ++ ++export LC_ALL=en_US.UTF-8 ++locale -k LC_CTYPE 2>&1 | grep -q charmap.*UTF-8 || exit 77 ++errors=0 ++ ++$xx -t @ -k2 -n mb1.I > mb1.O ++code=$? ++if test $code != 0; then ++ $echo "Test mb1 failed: $xx return code $code differs from expected value 0" 1>&2 ++ errors=`expr $errors + 1` ++else ++ cmp mb1.O $srcdir/mb1.X > /dev/null 2>&1 ++ case $? in ++ 0) if test "$VERBOSE"; then $echo "passed mb1"; fi;; ++ 1) $echo "Test mb1 failed: files mb1.O and $srcdir/mb1.X differ" 1>&2 ++ (diff -c mb1.O $srcdir/mb1.X) 2> /dev/null ++ errors=`expr $errors + 1`;; ++ 2) $echo "Test mb1 may have failed." 1>&2 ++ $echo The command "cmp mb1.O $srcdir/mb1.X" failed. 1>&2 ++ errors=`expr $errors + 1`;; ++ esac ++fi ++ ++$xx -t @ -k4 -n mb2.I > mb2.O ++code=$? ++if test $code != 0; then ++ $echo "Test mb2 failed: $xx return code $code differs from expected value 0" 1>&2 ++ errors=`expr $errors + 1` ++else ++ cmp mb2.O $srcdir/mb2.X > /dev/null 2>&1 ++ case $? in ++ 0) if test "$VERBOSE"; then $echo "passed mb2"; fi;; ++ 1) $echo "Test mb2 failed: files mb2.O and $srcdir/mb2.X differ" 1>&2 ++ (diff -c mb2.O $srcdir/mb2.X) 2> /dev/null ++ errors=`expr $errors + 1`;; ++ 2) $echo "Test mb2 may have failed." 1>&2 ++ $echo The command "cmp mb2.O $srcdir/mb2.X" failed. 1>&2 ++ errors=`expr $errors + 1`;; ++ esac ++fi ++ ++if test $errors = 0; then ++ $echo Passed all 113 tests. 1>&2 ++else ++ $echo Failed $errors tests. 1>&2 ++fi ++test $errors = 0 || errors=1 ++exit $errors +--- /dev/null 2007-01-09 09:38:07.860075128 +0000 ++++ coreutils-6.7/tests/sort/mb2.I 2007-01-09 17:18:28.000000000 +0000 +@@ -0,0 +1,4 @@ ++Apple@AA10@@20 ++Banana@AA5@@30 ++Citrus@AA20@@5 ++Cherry@AA30@@10 +--- /dev/null 2007-01-09 09:38:07.860075128 +0000 ++++ coreutils-6.7/tests/sort/mb2.X 2007-01-09 17:18:28.000000000 +0000 +@@ -0,0 +1,4 @@ ++Citrus@AA20@@5 ++Cherry@AA30@@10 ++Apple@AA10@@20 ++Banana@AA5@@30 +--- /dev/null 2007-01-09 09:38:07.860075128 +0000 ++++ coreutils-6.7/tests/sort/mb1.I 2007-01-09 17:18:28.000000000 +0000 +@@ -0,0 +1,4 @@ ++Apple@10 ++Banana@5 ++Citrus@20 ++Cherry@30 +--- /dev/null 2007-01-09 09:38:07.860075128 +0000 ++++ coreutils-6.7/tests/sort/mb1.X 2007-01-09 17:18:28.000000000 +0000 +@@ -0,0 +1,4 @@ ++Banana@5 ++Apple@10 ++Citrus@20 ++Cherry@30 +--- coreutils-6.7/tests/sort/Makefile.am.i18n 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/tests/sort/Makefile.am 2007-01-09 17:25:00.000000000 +0000 +@@ -64,14 +64,16 @@ + nul-tab.E + ##test-files-end + +-EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) +-noinst_SCRIPTS = $x-tests ++run_gen += mb1.0 mb2.0 ++ ++EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) mb1.I mb1.X mb2.I mb2.X ++noinst_SCRIPTS = $x-tests # $x-mb-tests + TESTS_ENVIRONMENT = \ + PATH="$(VG_PATH_PREFIX)`pwd`/../../src$(PATH_SEPARATOR)$$PATH" + + editpl = sed -e 's,@''PERL''@,$(PERL),g' -e 's,@''srcdir''@,$(srcdir),g' + +-TESTS = $x-tests ++TESTS = $x-tests $x-mb-tests + + mk_script = $(srcdir)/../mk-script + $(srcdir)/$x-tests: $(mk_script) Test.pm Makefile.am +--- coreutils-6.7/lib/linebuffer.h.i18n 2005-05-14 07:44:24.000000000 +0100 ++++ coreutils-6.7/lib/linebuffer.h 2007-01-09 17:18:28.000000000 +0000 +@@ -22,6 +22,11 @@ + + # include + ++/* Get mbstate_t. */ ++# if HAVE_WCHAR_H ++# include ++# endif ++ + /* A `struct linebuffer' holds a line of text. */ + + struct linebuffer +@@ -29,6 +34,9 @@ + size_t size; /* Allocated. */ + size_t length; /* Used. */ + char *buffer; ++# if HAVE_WCHAR_H ++ mbstate_t state; ++# endif + }; + + /* Initialize linebuffer LINEBUFFER for use. */ +--- coreutils-6.7/src/expand.c.i18n 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/src/expand.c 2007-01-09 17:18:28.000000000 +0000 @@ -38,11 +38,28 @@ #include #include @@ -29,7 +164,7 @@ /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "expand" -@@ -182,6 +199,7 @@ +@@ -183,6 +200,7 @@ stops = num_start + len - 1; } } @@ -37,7 +172,7 @@ else { error (0, 0, _("tab size contains invalid character(s): %s"), -@@ -364,6 +382,142 @@ +@@ -365,6 +383,142 @@ } } @@ -180,7 +315,7 @@ int main (int argc, char **argv) { -@@ -428,7 +582,12 @@ +@@ -429,7 +583,12 @@ file_list = (optind < argc ? &argv[optind] : stdin_argv); @@ -194,8 +329,2397 @@ if (have_read_stdin && fclose (stdin) != 0) error (EXIT_FAILURE, errno, "-"); ---- coreutils-5.95/src/pr.c.i18n 2005-09-16 08:50:33.000000000 +0100 -+++ coreutils-5.95/src/pr.c 2006-05-15 15:09:08.000000000 +0100 +--- coreutils-6.7/src/join.c.i18n 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/src/join.c 2007-01-09 17:18:28.000000000 +0000 +@@ -23,16 +23,30 @@ + #include + #include + ++/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ ++/* Get iswblank(), towupper. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "hard-locale.h" + #include "linebuffer.h" +-#include "memcasecmp.h" + #include "quote.h" + #include "stdio--.h" + #include "xmemcoll.h" + #include "xstrtol.h" + ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no `g' prefix). */ + #define PROGRAM_NAME "join" + +@@ -104,10 +118,12 @@ + /* Last element in `outlist', where a new element can be added. */ + static struct outlist *outlist_end = &outlist_head; + +-/* Tab character separating fields. If negative, fields are separated +- by any nonempty string of blanks, otherwise by exactly one +- tab character whose value (when cast to unsigned char) equals TAB. */ +-static int tab = -1; ++/* Tab character separating fields. If NULL, fields are separated ++ by any nonempty string of blanks. */ ++static char *tab = NULL; ++ ++/* The number of bytes used for tab. */ ++static size_t tablen = 0; + + static struct option const longopts[] = + { +@@ -190,6 +206,8 @@ + + /* Fill in the `fields' structure in LINE. */ + ++/* Fill in the `fields' structure in LINE. */ ++ + static void + xfields (struct line *line) + { +@@ -199,10 +217,11 @@ + if (ptr == lim) + return; + +- if (0 <= tab) ++ if (tab != NULL) + { ++ unsigned char t = tab[0]; + char *sep; +- for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1) ++ for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1) + extract_field (line, ptr, sep - ptr); + } + else +@@ -229,6 +248,148 @@ + extract_field (line, ptr, lim - ptr); + } + ++#if HAVE_MBRTOWC ++static void ++xfields_multibyte (struct line *line) ++{ ++ char *ptr = line->buf.buffer; ++ char const *lim = ptr + line->buf.length - 1; ++ wchar_t wc = 0; ++ size_t mblength = 1; ++ mbstate_t state, state_bak; ++ ++ memset (&state, 0, sizeof (mbstate_t)); ++ ++ if (ptr == lim) ++ return; ++ ++ if (tab != NULL) ++ { ++ unsigned char t = tab[0]; ++ char *sep = ptr; ++ for (; ptr < lim; ptr = sep + mblength) ++ { ++ sep = ptr; ++ while (sep < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (mblength == tablen && !memcmp (sep, tab, mblength)) ++ break; ++ else ++ { ++ sep += mblength; ++ continue; ++ } ++ } ++ ++ if (sep == lim) ++ break; ++ ++ extract_field (line, ptr, sep - ptr); ++ } ++ } ++ else ++ { ++ /* Skip leading blanks before the first field. */ ++ while(ptr < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank(wc)) ++ break; ++ ptr += mblength; ++ } ++ ++ do ++ { ++ char *sep; ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ sep = ptr + mblength; ++ while (sep != lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (iswblank (wc)) ++ break; ++ ++ sep += mblength; ++ } ++ ++ extract_field (line, ptr, sep - ptr); ++ if (sep == lim) ++ return; ++ ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ ptr = sep + mblength; ++ while (ptr != lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank (wc)) ++ break; ++ ++ ptr += mblength; ++ } ++ } ++ while (ptr != lim); ++ } ++ ++ extract_field (line, ptr, lim - ptr); ++} ++#endif ++ + /* Read a line from FP into LINE and split it into fields. + Return true if successful. */ + +@@ -249,6 +410,11 @@ + line->nfields_allocated = 0; + line->nfields = 0; + line->fields = NULL; ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ xfields_multibyte (line); ++ else ++#endif + xfields (line); + return true; + } +@@ -303,56 +469,114 @@ + keycmp (struct line const *line1, struct line const *line2) + { + /* Start of field to compare in each file. */ +- char *beg1; +- char *beg2; +- +- size_t len1; +- size_t len2; /* Length of fields to compare. */ ++ char *beg[2]; ++ char *copy[2]; ++ size_t len[2]; /* Length of fields to compare. */ + int diff; ++ int i, j; + + if (join_field_1 < line1->nfields) + { +- beg1 = line1->fields[join_field_1].beg; +- len1 = line1->fields[join_field_1].len; ++ beg[0] = line1->fields[join_field_1].beg; ++ len[0] = line1->fields[join_field_1].len; + } + else + { +- beg1 = NULL; +- len1 = 0; ++ beg[0] = NULL; ++ len[0] = 0; + } + + if (join_field_2 < line2->nfields) + { +- beg2 = line2->fields[join_field_2].beg; +- len2 = line2->fields[join_field_2].len; ++ beg[1] = line2->fields[join_field_2].beg; ++ len[1] = line2->fields[join_field_2].len; + } + else + { +- beg2 = NULL; +- len2 = 0; ++ beg[1] = NULL; ++ len[1] = 0; + } + +- if (len1 == 0) +- return len2 == 0 ? 0 : -1; +- if (len2 == 0) ++ if (len[0] == 0) ++ return len[1] == 0 ? 0 : -1; ++ if (len[1] == 0) + return 1; + + if (ignore_case) + { +- /* FIXME: ignore_case does not work with NLS (in particular, +- with multibyte chars). */ +- diff = memcasecmp (beg1, beg2, MIN (len1, len2)); ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ size_t mblength; ++ wchar_t wc, uwc; ++ mbstate_t state, state_bak; ++ ++ memset (&state, '\0', sizeof (mbstate_t)); ++ ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = alloca (len[i] + 1); ++ ++ for (j = 0; j < MIN (len[0], len[1]);) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state); ++ ++ switch (mblength) ++ { ++ case (size_t) -1: ++ case (size_t) -2: ++ state = state_bak; ++ /* Fall through */ ++ case 0: ++ mblength = 1; ++ break; ++ ++ default: ++ uwc = towupper (wc); ++ ++ if (uwc != wc) ++ { ++ mbstate_t state_wc; ++ ++ memset (&state_wc, '\0', sizeof (mbstate_t)); ++ wcrtomb (copy[i] + j, uwc, &state_wc); ++ } ++ else ++ memcpy (copy[i] + j, beg[i] + j, mblength); ++ } ++ j += mblength; ++ } ++ copy[i][j] = '\0'; ++ } ++ } ++ else ++#endif ++ { ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = alloca (len[i] + 1); ++ ++ for (j = 0; j < MIN (len[0], len[1]); j++) ++ copy[i][j] = toupper (beg[i][j]); ++ ++ copy[i][j] = '\0'; ++ } ++ } + } + else + { +- if (hard_LC_COLLATE) +- return xmemcoll (beg1, len1, beg2, len2); +- diff = memcmp (beg1, beg2, MIN (len1, len2)); ++ copy[0] = (unsigned char *) beg[0]; ++ copy[1] = (unsigned char *) beg[1]; + } + ++ if (hard_LC_COLLATE) ++ return xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]); ++ diff = memcmp (copy[0], copy[1], MIN (len[0], len[1])); ++ + if (diff) + return diff; +- return len1 < len2 ? -1 : len1 != len2; ++ return len[0] - len[1]; + } + + /* Print field N of LINE if it exists and is nonempty, otherwise +@@ -377,11 +601,18 @@ + + /* Print the join of LINE1 and LINE2. */ + ++#define PUT_TAB_CHAR \ ++ do \ ++ { \ ++ (tab != NULL) ? \ ++ fwrite(tab, sizeof(char), tablen, stdout) : putchar (' '); \ ++ } \ ++ while (0) ++ + static void + prjoin (struct line const *line1, struct line const *line2) + { + const struct outlist *outlist; +- char output_separator = tab < 0 ? ' ' : tab; + + outlist = outlist_head.next; + if (outlist) +@@ -397,12 +628,12 @@ + if (o->file == 0) + { + if (line1 == &uni_blank) +- { ++ { + line = line2; + field = join_field_2; + } + else +- { ++ { + line = line1; + field = join_field_1; + } +@@ -416,7 +647,7 @@ + o = o->next; + if (o == NULL) + break; +- putchar (output_separator); ++ PUT_TAB_CHAR; + } + putchar ('\n'); + } +@@ -434,23 +665,23 @@ + prfield (join_field_1, line1); + for (i = 0; i < join_field_1 && i < line1->nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line1); + } + for (i = join_field_1 + 1; i < line1->nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line1); + } + + for (i = 0; i < join_field_2 && i < line2->nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line2); + } + for (i = join_field_2 + 1; i < line2->nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line2); + } + putchar ('\n'); +@@ -862,20 +1093,41 @@ + + case 't': + { +- unsigned char newtab = optarg[0]; +- if (! newtab) ++ char *newtab; ++ size_t newtablen; ++ if (! optarg[0]) + error (EXIT_FAILURE, 0, _("empty tab")); +- if (optarg[1]) ++ newtab = xstrdup (optarg); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ mbstate_t state; ++ ++ memset (&state, 0, sizeof (mbstate_t)); ++ newtablen = mbrtowc (NULL, newtab, ++ strnlen (newtab, MB_LEN_MAX), ++ &state); ++ if (newtablen == (size_t) 0 ++ || newtablen == (size_t) -1 ++ || newtablen == (size_t) -2) ++ newtablen = 1; ++ } ++ else ++#endif ++ newtablen = 1; ++ ++ if (newtablen == 1 && newtab[1]) ++ { ++ if (STREQ (newtab, "\\0")) ++ newtab[0] = '\0'; ++ } ++ if (tab != NULL && strcmp (tab, newtab)) + { +- if (STREQ (optarg, "\\0")) +- newtab = '\0'; +- else +- error (EXIT_FAILURE, 0, _("multi-character tab %s"), +- quote (optarg)); ++ free (newtab); ++ error (EXIT_FAILURE, 0, _("incompatible tabs")); + } +- if (0 <= tab && tab != newtab) +- error (EXIT_FAILURE, 0, _("incompatible tabs")); + tab = newtab; ++ tablen = newtablen; + } + break; + +--- coreutils-6.7/src/uniq.c.i18n 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/src/uniq.c 2007-01-09 17:18:28.000000000 +0000 +@@ -23,6 +23,16 @@ + #include + #include + ++/* Get mbstate_t, mbrtowc(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ ++/* Get isw* functions. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "argmatch.h" + #include "linebuffer.h" +@@ -32,7 +42,19 @@ + #include "quote.h" + #include "xmemcoll.h" + #include "xstrtol.h" +-#include "memcasecmp.h" ++#include "xmemcoll.h" ++ ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + + /* The official name of this program (e.g., no `g' prefix). */ + #define PROGRAM_NAME "uniq" +@@ -109,6 +131,10 @@ + /* Select whether/how to delimit groups of duplicate lines. */ + static enum delimit_method delimit_groups; + ++/* Function pointers. */ ++static char * ++(*find_field) (struct linebuffer *line); ++ + static struct option const longopts[] = + { + {"count", no_argument, NULL, 'c'}, +@@ -189,7 +215,7 @@ + return a pointer to the beginning of the line's field to be compared. */ + + static char * +-find_field (const struct linebuffer *line) ++find_field_uni (struct linebuffer *line) + { + size_t count; + char *lp = line->buffer; +@@ -210,6 +236,83 @@ + return lp + i; + } + ++#if HAVE_MBRTOWC ++ ++# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL) \ ++ do \ ++ { \ ++ mbstate_t state_bak; \ ++ \ ++ CONVFAIL = 0; \ ++ state_bak = *STATEP; \ ++ \ ++ MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP); \ ++ \ ++ switch (MBLENGTH) \ ++ { \ ++ case (size_t)-2: \ ++ case (size_t)-1: \ ++ *STATEP = state_bak; \ ++ CONVFAIL++; \ ++ /* Fall through */ \ ++ case 0: \ ++ MBLENGTH = 1; \ ++ } \ ++ } \ ++ while (0) ++ ++static char * ++find_field_multi (struct linebuffer *line) ++{ ++ size_t count; ++ char *lp = line->buffer; ++ size_t size = line->length - 1; ++ size_t pos; ++ size_t mblength; ++ wchar_t wc; ++ mbstate_t *statep; ++ int convfail; ++ ++ pos = 0; ++ statep = &(line->state); ++ ++ /* skip fields. */ ++ for (count = 0; count < skip_fields && pos < size; count++) ++ { ++ while (pos < size) ++ { ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ ++ if (convfail || !iswblank (wc)) ++ { ++ pos += mblength; ++ break; ++ } ++ pos += mblength; ++ } ++ ++ while (pos < size) ++ { ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ ++ if (!convfail && iswblank (wc)) ++ break; ++ ++ pos += mblength; ++ } ++ } ++ ++ /* skip fields. */ ++ for (count = 0; count < skip_chars && pos < size; count++) ++ { ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ pos += mblength; ++ } ++ ++ return lp + pos; ++} ++#endif ++ + /* Return false if two strings OLD and NEW match, true if not. + OLD and NEW point not to the beginnings of the lines + but rather to the beginnings of the fields to compare. +@@ -218,6 +321,8 @@ + static bool + different (char *old, char *new, size_t oldlen, size_t newlen) + { ++ char *copy_old, *copy_new; ++ + if (check_chars < oldlen) + oldlen = check_chars; + if (check_chars < newlen) +@@ -225,14 +330,92 @@ + + if (ignore_case) + { +- /* FIXME: This should invoke strcoll somehow. */ +- return oldlen != newlen || memcasecmp (old, new, oldlen); ++ size_t i; ++ ++ copy_old = alloca (oldlen + 1); ++ copy_new = alloca (oldlen + 1); ++ ++ for (i = 0; i < oldlen; i++) ++ { ++ copy_old[i] = toupper (old[i]); ++ copy_new[i] = toupper (new[i]); ++ } + } +- else if (hard_LC_COLLATE) +- return xmemcoll (old, oldlen, new, newlen) != 0; + else +- return oldlen != newlen || memcmp (old, new, oldlen); ++ { ++ copy_old = (char *)old; ++ copy_new = (char *)new; ++ } ++ ++ return xmemcoll (copy_old, oldlen, copy_new, newlen); ++} ++ ++#if HAVE_MBRTOWC ++static int ++different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate) ++{ ++ size_t i, j, chars; ++ const char *str[2]; ++ char *copy[2]; ++ size_t len[2]; ++ mbstate_t state[2]; ++ size_t mblength; ++ wchar_t wc, uwc; ++ mbstate_t state_bak; ++ ++ str[0] = old; ++ str[1] = new; ++ len[0] = oldlen; ++ len[1] = newlen; ++ state[0] = oldstate; ++ state[1] = newstate; ++ ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = alloca (len[i] + 1); ++ ++ for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++) ++ { ++ state_bak = state[i]; ++ mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i])); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: ++ case (size_t)-2: ++ state[i] = state_bak; ++ /* Fall through */ ++ case 0: ++ mblength = 1; ++ break; ++ ++ default: ++ if (ignore_case) ++ { ++ uwc = towupper (wc); ++ ++ if (uwc != wc) ++ { ++ mbstate_t state_wc; ++ ++ memset (&state_wc, '\0', sizeof(mbstate_t)); ++ wcrtomb (copy[i] + j, uwc, &state_wc); ++ } ++ else ++ memcpy (copy[i] + j, str[i] + j, mblength); ++ } ++ else ++ memcpy (copy[i] + j, str[i] + j, mblength); ++ } ++ j += mblength; ++ } ++ copy[i][j] = '\0'; ++ len[i] = j; ++ } ++ ++ return xmemcoll (copy[0], len[0], copy[1], len[1]); + } ++#endif + + /* Output the line in linebuffer LINE to standard output + provided that the switches say it should be output. +@@ -286,15 +469,43 @@ + { + char *prevfield IF_LINT (= NULL); + size_t prevlen IF_LINT (= 0); ++#if HAVE_MBRTOWC ++ mbstate_t prevstate; ++ ++ memset (&prevstate, '\0', sizeof (mbstate_t)); ++#endif + + while (!feof (stdin)) + { + char *thisfield; + size_t thislen; ++#if HAVE_MBRTOWC ++ mbstate_t thisstate; ++#endif ++ + if (readlinebuffer (thisline, stdin) == 0) + break; + thisfield = find_field (thisline); + thislen = thisline->length - 1 - (thisfield - thisline->buffer); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ thisstate = thisline->state; ++ ++ if (prevline->length == 0 || different_multi ++ (thisfield, prevfield, thislen, prevlen, thisstate, prevstate)) ++ { ++ fwrite (thisline->buffer, sizeof (char), ++ thisline->length, stdout); ++ ++ SWAP_LINES (prevline, thisline); ++ prevfield = thisfield; ++ prevlen = thislen; ++ prevstate = thisstate; ++ } ++ } ++ else ++#endif + if (prevline->length == 0 + || different (thisfield, prevfield, thislen, prevlen)) + { +@@ -313,17 +524,26 @@ + size_t prevlen; + uintmax_t match_count = 0; + bool first_delimiter = true; ++#if HAVE_MBRTOWC ++ mbstate_t prevstate; ++#endif + + if (readlinebuffer (prevline, stdin) == 0) + goto closefiles; + prevfield = find_field (prevline); + prevlen = prevline->length - 1 - (prevfield - prevline->buffer); ++#if HAVE_MBRTOWC ++ prevstate = prevline->state; ++#endif + + while (!feof (stdin)) + { + bool match; + char *thisfield; + size_t thislen; ++#if HAVE_MBRTOWC ++ mbstate_t thisstate; ++#endif + if (readlinebuffer (thisline, stdin) == 0) + { + if (ferror (stdin)) +@@ -332,6 +552,15 @@ + } + thisfield = find_field (thisline); + thislen = thisline->length - 1 - (thisfield - thisline->buffer); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ thisstate = thisline->state; ++ match = !different_multi (thisfield, prevfield, ++ thislen, prevlen, thisstate, prevstate); ++ } ++ else ++#endif + match = !different (thisfield, prevfield, thislen, prevlen); + match_count += match; + +@@ -364,6 +593,9 @@ + SWAP_LINES (prevline, thisline); + prevfield = thisfield; + prevlen = thislen; ++#if HAVE_MBRTOWC ++ prevstate = thisstate; ++#endif + if (!match) + match_count = 0; + } +@@ -408,6 +640,19 @@ + + atexit (close_stdout); + ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ find_field = find_field_multi; ++ } ++ else ++#endif ++ { ++ find_field = find_field_uni; ++ } ++ ++ ++ + skip_chars = 0; + skip_fields = 0; + check_chars = SIZE_MAX; +--- coreutils-6.7/src/fold.c.i18n 2006-10-24 23:35:57.000000000 +0100 ++++ coreutils-6.7/src/fold.c 2007-01-09 17:23:46.000000000 +0000 +@@ -23,11 +23,33 @@ + #include + #include + ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ ++/* Get iswprint(), iswblank(), wcwidth(). */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "quote.h" + #include "xstrtol.h" + ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# undef MB_LEN_MAX ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + #define TAB_WIDTH 8 + + /* The official name of this program (e.g., no `g' prefix). */ +@@ -35,23 +57,44 @@ + + #define AUTHORS "David MacKenzie" + ++#define FATAL_ERROR(Message) \ ++ do \ ++ { \ ++ error (0, 0, (Message)); \ ++ usage (2); \ ++ } \ ++ while (0) ++ ++enum operating_mode ++{ ++ /* Fold texts by columns that are at the given positions. */ ++ column_mode, ++ ++ /* Fold texts by bytes that are at the given positions. */ ++ byte_mode, ++ ++ /* Fold texts by characters that are at the given positions. */ ++ character_mode, ++}; ++ + /* The name this program was run with. */ + char *program_name; + ++/* The argument shows current mode. (Default: column_mode) */ ++static enum operating_mode operating_mode; ++ + /* If nonzero, try to break on whitespace. */ + static bool break_spaces; + +-/* If nonzero, count bytes, not column positions. */ +-static bool count_bytes; +- + /* If nonzero, at least one of the files we read was standard input. */ + static bool have_read_stdin; + +-static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::"; ++static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::"; + + static struct option const longopts[] = + { + {"bytes", no_argument, NULL, 'b'}, ++ {"characters", no_argument, NULL, 'c'}, + {"spaces", no_argument, NULL, 's'}, + {"width", required_argument, NULL, 'w'}, + {GETOPT_HELP_OPTION_DECL}, +@@ -81,6 +124,7 @@ + "), stdout); + fputs (_("\ + -b, --bytes count bytes rather than columns\n\ ++ -c, --characters count characters rather than columns\n\ + -s, --spaces break at spaces\n\ + -w, --width=WIDTH use WIDTH columns instead of 80\n\ + "), stdout); +@@ -98,7 +142,7 @@ + static size_t + adjust_column (size_t column, char c) + { +- if (!count_bytes) ++ if (operating_mode != byte_mode) + { + if (c == '\b') + { +@@ -121,30 +165,14 @@ + to stdout, with maximum line length WIDTH. + Return true if successful. */ + +-static bool +-fold_file (char const *filename, size_t width) ++static void ++fold_text (FILE *istream, size_t width, int *saved_errno) + { +- FILE *istream; + int c; + size_t column = 0; /* Screen column where next char will go. */ + size_t offset_out = 0; /* Index in `line_out' for next char. */ + static char *line_out = NULL; + static size_t allocated_out = 0; +- int saved_errno; +- +- if (STREQ (filename, "-")) +- { +- istream = stdin; +- have_read_stdin = true; +- } +- else +- istream = fopen (filename, "r"); +- +- if (istream == NULL) +- { +- error (0, errno, "%s", filename); +- return false; +- } + + while ((c = getc (istream)) != EOF) + { +@@ -172,6 +200,15 @@ + bool found_blank = false; + size_t logical_end = offset_out; + ++ /* If LINE_OUT has no wide character, ++ put a new wide character in LINE_OUT ++ if column is bigger than width. */ ++ if (offset_out == 0) ++ { ++ line_out[offset_out++] = c; ++ continue; ++ } ++ + /* Look for the last blank. */ + while (logical_end) + { +@@ -218,11 +255,225 @@ + line_out[offset_out++] = c; + } + +- saved_errno = errno; ++ *saved_errno = errno; ++ ++ if (offset_out) ++ fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); ++ ++ free(line_out); ++} ++ ++#if HAVE_MBRTOWC ++static void ++fold_multibyte_text (FILE *istream, size_t width, int *saved_errno) ++{ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ size_t buflen = 0; /* The length of the byte sequence in buf. */ ++ char *bufpos; /* Next read position of BUF. */ ++ wint_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character which shows ++ as same character as WC. */ ++ mbstate_t state, state_bak; /* State of the stream. */ ++ int convfail; /* 1, when conversion is failed. Otherwise 0. */ ++ ++ char *line_out = NULL; ++ size_t offset_out = 0; /* Index in `line_out' for next char. */ ++ size_t allocated_out = 0; ++ ++ int increment; ++ size_t column = 0; ++ ++ size_t last_blank_pos; ++ size_t last_blank_column; ++ int is_blank_seen; ++ int last_blank_increment; ++ int is_bs_following_last_blank; ++ size_t bs_following_last_blank_num; ++ int is_cr_after_last_blank; ++ ++#define CLEAR_FLAGS \ ++ do \ ++ { \ ++ last_blank_pos = 0; \ ++ last_blank_column = 0; \ ++ is_blank_seen = 0; \ ++ is_bs_following_last_blank = 0; \ ++ bs_following_last_blank_num = 0; \ ++ is_cr_after_last_blank = 0; \ ++ } \ ++ while (0) ++ ++#define START_NEW_LINE \ ++ do \ ++ { \ ++ putchar ('\n'); \ ++ column = 0; \ ++ offset_out = 0; \ ++ CLEAR_FLAGS; \ ++ } \ ++ while (0) ++ ++ CLEAR_FLAGS; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ for (;; bufpos += mblength, buflen -= mblength) ++ { ++ if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream)) ++ { ++ memmove (buf, bufpos, buflen); ++ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream); ++ bufpos = buf; ++ } ++ ++ if (buflen < 1) ++ break; ++ ++ /* Get a wide character. */ ++ convfail = 0; ++ state_bak = state; ++ mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: ++ case (size_t)-2: ++ convfail++; ++ state = state_bak; ++ /* Fall through. */ ++ ++ case 0: ++ mblength = 1; ++ break; ++ } ++ ++rescan: ++ if (operating_mode == byte_mode) /* byte mode */ ++ increment = mblength; ++ else if (operating_mode == character_mode) /* character mode */ ++ increment = 1; ++ else /* column mode */ ++ { ++ if (convfail) ++ increment = 1; ++ else ++ { ++ switch (wc) ++ { ++ case L'\n': ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ continue; ++ ++ case L'\b': ++ increment = (column > 0) ? -1 : 0; ++ break; ++ ++ case L'\r': ++ increment = -1 * column; ++ break; ++ ++ case L'\t': ++ increment = 8 - column % 8; ++ break; ++ ++ default: ++ increment = wcwidth (wc); ++ increment = (increment < 0) ? 0 : increment; ++ } ++ } ++ } ++ ++ if (column + increment > width && break_spaces && last_blank_pos) ++ { ++ fwrite (line_out, sizeof(char), last_blank_pos, stdout); ++ putchar ('\n'); ++ ++ offset_out = offset_out - last_blank_pos; ++ column = column - last_blank_column + ((is_cr_after_last_blank) ++ ? last_blank_increment : bs_following_last_blank_num); ++ memmove (line_out, line_out + last_blank_pos, offset_out); ++ CLEAR_FLAGS; ++ goto rescan; ++ } ++ ++ if (column + increment > width && column != 0) ++ { ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ goto rescan; ++ } ++ ++ if (allocated_out < offset_out + mblength) ++ { ++ allocated_out += 1024; ++ line_out = xrealloc (line_out, allocated_out); ++ } ++ ++ memcpy (line_out + offset_out, bufpos, mblength); ++ offset_out += mblength; ++ column += increment; ++ ++ if (is_blank_seen && !convfail && wc == L'\r') ++ is_cr_after_last_blank = 1; ++ ++ if (is_bs_following_last_blank && !convfail && wc == L'\b') ++ ++bs_following_last_blank_num; ++ else ++ is_bs_following_last_blank = 0; ++ ++ if (break_spaces && !convfail && iswblank (wc)) ++ { ++ last_blank_pos = offset_out; ++ last_blank_column = column; ++ is_blank_seen = 1; ++ last_blank_increment = increment; ++ is_bs_following_last_blank = 1; ++ bs_following_last_blank_num = 0; ++ is_cr_after_last_blank = 0; ++ } ++ } ++ ++ *saved_errno = errno; + + if (offset_out) + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + ++ free(line_out); ++} ++#endif ++ ++/* Fold file FILENAME, or standard input if FILENAME is "-", ++ to stdout, with maximum line length WIDTH. ++ Return 0 if successful, 1 if an error occurs. */ ++ ++static bool ++fold_file (char *filename, size_t width) ++{ ++ FILE *istream; ++ int saved_errno; ++ ++ if (STREQ (filename, "-")) ++ { ++ istream = stdin; ++ have_read_stdin = 1; ++ } ++ else ++ istream = fopen (filename, "r"); ++ ++ if (istream == NULL) ++ { ++ error (0, errno, "%s", filename); ++ return 1; ++ } ++ ++ /* Define how ISTREAM is being folded. */ ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ fold_multibyte_text (istream, width, &saved_errno); ++ else ++#endif ++ fold_text (istream, width, &saved_errno); ++ + if (ferror (istream)) + { + error (0, saved_errno, "%s", filename); +@@ -255,7 +506,8 @@ + + atexit (close_stdout); + +- break_spaces = count_bytes = have_read_stdin = false; ++ operating_mode = column_mode; ++ break_spaces = have_read_stdin = false; + + while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) + { +@@ -264,7 +516,15 @@ + switch (optc) + { + case 'b': /* Count bytes rather than columns. */ +- count_bytes = true; ++ if (operating_mode != column_mode) ++ FATAL_ERROR (_("only one way of folding may be specified")); ++ operating_mode = byte_mode; ++ break; ++ ++ case 'c': ++ if (operating_mode != column_mode) ++ FATAL_ERROR (_("only one way of folding may be specified")); ++ operating_mode = character_mode; + break; + + case 's': /* Break at word boundaries. */ +--- coreutils-6.7/src/sort.c.i18n 2006-11-13 18:14:02.000000000 +0000 ++++ coreutils-6.7/src/sort.c 2007-01-09 17:18:28.000000000 +0000 +@@ -23,9 +23,18 @@ + + #include + ++#include + #include + #include + #include ++#if HAVE_WCHAR_H ++# include ++#endif ++/* Get isw* functions. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "hard-locale.h" +@@ -98,14 +107,38 @@ + /* Thousands separator; if -1, then there isn't one. */ + static int thousands_sep; + ++static int force_general_numcompare = 0; ++ + /* Nonzero if the corresponding locales are hard. */ + static bool hard_LC_COLLATE; +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + static bool hard_LC_TIME; + #endif + + #define NONZERO(x) ((x) != 0) + ++/* get a multibyte character's byte length. */ ++#define GET_BYTELEN_OF_CHAR(LIM, PTR, MBLENGTH, STATE) \ ++ do \ ++ { \ ++ wchar_t wc; \ ++ mbstate_t state_bak; \ ++ \ ++ state_bak = STATE; \ ++ mblength = mbrtowc (&wc, PTR, LIM - PTR, &STATE); \ ++ \ ++ switch (MBLENGTH) \ ++ { \ ++ case (size_t)-1: \ ++ case (size_t)-2: \ ++ STATE = state_bak; \ ++ /* Fall through. */ \ ++ case 0: \ ++ MBLENGTH = 1; \ ++ } \ ++ } \ ++ while (0) ++ + /* The kind of blanks for '-b' to skip in various options. */ + enum blanktype { bl_start, bl_end, bl_both }; + +@@ -243,13 +276,11 @@ + they were read if all keys compare equal. */ + static bool stable; + +-/* If TAB has this value, blanks separate fields. */ +-enum { TAB_DEFAULT = CHAR_MAX + 1 }; +- +-/* Tab character separating fields. If TAB_DEFAULT, then fields are ++/* Tab character separating fields. If tab_length is 0, then fields are + separated by the empty string between a non-blank character and a blank + character. */ +-static int tab = TAB_DEFAULT; ++static char tab[MB_LEN_MAX + 1]; ++static size_t tab_length = 0; + + /* Flag to remove consecutive duplicate lines from the output. + Only the last of a sequence of equal lines will be output. */ +@@ -408,6 +439,44 @@ + static struct tempnode *volatile temphead; + static struct tempnode *volatile *temptail = &temphead; + ++/* Function pointers. */ ++static void ++(*inittables) (void); ++static char * ++(*begfield) (const struct line*, const struct keyfield *); ++static char * ++(*limfield) (const struct line*, const struct keyfield *); ++static int ++(*getmonth) (char const *, size_t); ++static int ++(*keycompare) (const struct line *, const struct line *); ++static int ++(*numcompare) (const char *, const char *); ++ ++/* Test for white space multibyte character. ++ Set LENGTH the byte length of investigated multibyte character. */ ++#if HAVE_MBRTOWC ++static int ++ismbblank (const char *str, size_t len, size_t *length) ++{ ++ size_t mblength; ++ wchar_t wc; ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ mblength = mbrtowc (&wc, str, len, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ *length = 1; ++ return 0; ++ } ++ ++ *length = (mblength < 1) ? 1 : mblength; ++ return iswblank (wc); ++} ++#endif ++ + /* Clean up any remaining temporary files. */ + + static void +@@ -561,7 +630,7 @@ + free (node); + } + +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + + static int + struct_month_cmp (const void *m1, const void *m2) +@@ -576,7 +645,7 @@ + /* Initialize the character class tables. */ + + static void +-inittables (void) ++inittables_uni (void) + { + size_t i; + +@@ -588,7 +657,7 @@ + fold_toupper[i] = toupper (i); + } + +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + /* If we're not in the "C" locale, read different names for months. */ + if (hard_LC_TIME) + { +@@ -614,6 +683,64 @@ + #endif + } + ++#if HAVE_MBRTOWC ++static void ++inittables_mb (void) ++{ ++ int i, j, k, l; ++ char *name, *s; ++ size_t s_len, mblength; ++ char mbc[MB_LEN_MAX]; ++ wchar_t wc, pwc; ++ mbstate_t state_mb, state_wc; ++ ++ for (i = 0; i < MONTHS_PER_YEAR; i++) ++ { ++ s = (char *) nl_langinfo (ABMON_1 + i); ++ s_len = strlen (s); ++ monthtab[i].name = name = (char *) xmalloc (s_len + 1); ++ monthtab[i].val = i + 1; ++ ++ memset (&state_mb, '\0', sizeof (mbstate_t)); ++ memset (&state_wc, '\0', sizeof (mbstate_t)); ++ ++ for (j = 0; j < s_len;) ++ { ++ if (!ismbblank (s + j, s_len - j, &mblength)) ++ break; ++ j += mblength; ++ } ++ ++ for (k = 0; j < s_len;) ++ { ++ mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb); ++ assert (mblength != (size_t)-1 && mblength != (size_t)-2); ++ if (mblength == 0) ++ break; ++ ++ pwc = towupper (wc); ++ if (pwc == wc) ++ { ++ memcpy (mbc, s + j, mblength); ++ j += mblength; ++ } ++ else ++ { ++ j += mblength; ++ mblength = wcrtomb (mbc, pwc, &state_wc); ++ assert (mblength != (size_t)0 && mblength != (size_t)-1); ++ } ++ ++ for (l = 0; l < mblength; l++) ++ name[k++] = mbc[l]; ++ } ++ name[k] = '\0'; ++ } ++ qsort ((void *) monthtab, MONTHS_PER_YEAR, ++ sizeof (struct month), struct_month_cmp); ++} ++#endif ++ + /* Specify the amount of main memory to use when sorting. */ + static void + specify_sort_size (char const *s) +@@ -824,7 +951,7 @@ + by KEY in LINE. */ + + static char * +-begfield (const struct line *line, const struct keyfield *key) ++begfield_uni (const struct line *line, const struct keyfield *key) + { + char *ptr = line->text, *lim = ptr + line->length - 1; + size_t sword = key->sword; +@@ -834,10 +961,10 @@ + /* The leading field separator itself is included in a field when -t + is absent. */ + +- if (tab != TAB_DEFAULT) ++ if (tab_length) + while (ptr < lim && sword--) + { +- while (ptr < lim && *ptr != tab) ++ while (ptr < lim && *ptr != tab[0]) + ++ptr; + if (ptr < lim) + ++ptr; +@@ -865,11 +992,70 @@ + return ptr; + } + ++#if HAVE_MBRTOWC ++static char * ++begfield_mb (const struct line *line, const struct keyfield *key) ++{ ++ int i; ++ char *ptr = line->text, *lim = ptr + line->length - 1; ++ size_t sword = key->sword; ++ size_t schar = key->schar; ++ size_t mblength; ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ if (tab_length) ++ while (ptr < lim && sword--) ++ { ++ while (ptr < lim && memcmp (ptr, tab, tab_length) != 0) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ if (ptr < lim) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ } ++ else ++ while (ptr < lim && sword--) ++ { ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ if (ptr < lim) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ } ++ ++ if (key->skipsblanks) ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ ++ for (i = 0; i < schar; i++) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ++ if (ptr + mblength > lim) ++ break; ++ else ++ ptr += mblength; ++ } ++ ++ return ptr; ++} ++#endif ++ + /* Return the limit of (a pointer to the first character after) the field + in LINE specified by KEY. */ + + static char * +-limfield (const struct line *line, const struct keyfield *key) ++limfield_uni (const struct line *line, const struct keyfield *key) + { + char *ptr = line->text, *lim = ptr + line->length - 1; + size_t eword = key->eword, echar = key->echar; +@@ -882,10 +1068,10 @@ + `beginning' is the first character following the delimiting TAB. + Otherwise, leave PTR pointing at the first `blank' character after + the preceding field. */ +- if (tab != TAB_DEFAULT) ++ if (tab_length) + while (ptr < lim && eword--) + { +- while (ptr < lim && *ptr != tab) ++ while (ptr < lim && *ptr != tab[0]) + ++ptr; + if (ptr < lim && (eword | echar)) + ++ptr; +@@ -931,10 +1117,10 @@ + */ + + /* Make LIM point to the end of (one byte past) the current field. */ +- if (tab != TAB_DEFAULT) ++ if (tab_length) + { + char *newlim; +- newlim = memchr (ptr, tab, lim - ptr); ++ newlim = memchr (ptr, tab[0], lim - ptr); + if (newlim) + lim = newlim; + } +@@ -967,6 +1153,107 @@ + return ptr; + } + ++#if HAVE_MBRTOWC ++static char * ++limfield_mb (const struct line *line, const struct keyfield *key) ++{ ++ char *ptr = line->text, *lim = ptr + line->length - 1; ++ size_t eword = key->eword, echar = key->echar; ++ int i; ++ size_t mblength; ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ if (tab_length) ++ while (ptr < lim && eword--) ++ { ++ while (ptr < lim && memcmp (ptr, tab, tab_length) != 0) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ if (ptr < lim && (eword | echar)) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ } ++ else ++ while (ptr < lim && eword--) ++ { ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ if (ptr < lim) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ } ++ ++ ++# ifdef POSIX_UNSPECIFIED ++ /* Make LIM point to the end of (one byte past) the current field. */ ++ if (tab_length) ++ { ++ char *newlim, *p; ++ ++ newlim = NULL; ++ for (p = ptr; p < lim;) ++ { ++ if (memcmp (p, tab, tab_length) == 0) ++ { ++ newlim = p; ++ break; ++ } ++ ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ p += mblength; ++ } ++ } ++ else ++ { ++ char *newlim; ++ newlim = ptr; ++ ++ while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength)) ++ newlim += mblength; ++ if (ptr < lim) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength)) ++ newlim += mblength; ++ lim = newlim; ++ } ++# endif ++ ++ /* If we're skipping leading blanks, don't start counting characters ++ * until after skipping past any leading blanks. */ ++ if (key->skipsblanks) ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ /* Advance PTR by ECHAR (if possible), but no further than LIM. */ ++ for (i = 0; i < echar; i++) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ++ if (ptr + mblength > lim) ++ break; ++ else ++ ptr += mblength; ++ } ++ ++ return ptr; ++} ++#endif ++ + /* Fill BUF reading from FP, moving buf->left bytes from the end + of buf->buf to the beginning first. If EOF is reached and the + file wasn't terminated by a newline, supply one. Set up BUF's line +@@ -1049,8 +1336,24 @@ + else + { + if (key->skipsblanks) +- while (blanks[to_uchar (*line_start)]) +- line_start++; ++ { ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ size_t mblength; ++ mbstate_t state; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ while (line_start < line->keylim && ++ ismbblank (line_start, ++ line->keylim - line_start, ++ &mblength)) ++ line_start += mblength; ++ } ++ else ++#endif ++ while (blanks[to_uchar (*line_start)]) ++ line_start++; ++ } + line->keybeg = line_start; + } + } +@@ -1083,7 +1386,7 @@ + hideously fast. */ + + static int +-numcompare (const char *a, const char *b) ++numcompare_uni (const char *a, const char *b) + { + while (blanks[to_uchar (*a)]) + a++; +@@ -1093,6 +1396,25 @@ + return strnumcmp (a, b, decimal_point, thousands_sep); + } + ++#if HAVE_MBRTOWC ++static int ++numcompare_mb (const char *a, const char *b) ++{ ++ size_t mblength, len; ++ len = strlen (a); /* okay for UTF-8 */ ++ while (*a && ismbblank (a, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength)) ++ { ++ a += mblength; ++ len -= mblength; ++ } ++ len = strlen (b); /* okay for UTF-8 */ ++ while (*b && ismbblank (b, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength)) ++ b += mblength; ++ ++ return strnumcmp (a, b, decimal_point, thousands_sep); ++} ++#endif /* HAV_EMBRTOWC */ ++ + static int + general_numcompare (const char *sa, const char *sb) + { +@@ -1126,7 +1448,7 @@ + Return 0 if the name in S is not recognized. */ + + static int +-getmonth (char const *month, size_t len) ++getmonth_uni (char const *month, size_t len) + { + size_t lo = 0; + size_t hi = MONTHS_PER_YEAR; +@@ -1281,11 +1603,79 @@ + return diff; + } + ++#if HAVE_MBRTOWC ++static int ++getmonth_mb (const char *s, size_t len) ++{ ++ char *month; ++ register size_t i; ++ register int lo = 0, hi = MONTHS_PER_YEAR, result; ++ char *tmp; ++ size_t wclength, mblength; ++ const char **pp; ++ const wchar_t **wpp; ++ wchar_t *month_wcs; ++ mbstate_t state; ++ ++ while (len > 0 && ismbblank (s, len, &mblength)) ++ { ++ s += mblength; ++ len -= mblength; ++ } ++ ++ if (len == 0) ++ return 0; ++ ++ month = (char *) alloca (len + 1); ++ ++ tmp = (char *) alloca (len + 1); ++ memcpy (tmp, s, len); ++ tmp[len] = '\0'; ++ pp = (const char **)&tmp; ++ month_wcs = (wchar_t *) alloca ((len + 1) * sizeof (wchar_t)); ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ wclength = mbsrtowcs (month_wcs, pp, len + 1, &state); ++ assert (wclength != (size_t)-1 && *pp == NULL); ++ ++ for (i = 0; i < wclength; i++) ++ { ++ month_wcs[i] = towupper(month_wcs[i]); ++ if (iswblank (month_wcs[i])) ++ { ++ month_wcs[i] = L'\0'; ++ break; ++ } ++ } ++ ++ wpp = (const wchar_t **)&month_wcs; ++ ++ mblength = wcsrtombs (month, wpp, len + 1, &state); ++ assert (mblength != (-1) && *wpp == NULL); ++ ++ do ++ { ++ int ix = (lo + hi) / 2; ++ ++ if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0) ++ hi = ix; ++ else ++ lo = ix; ++ } ++ while (hi - lo > 1); ++ ++ result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name)) ++ ? monthtab[lo].val : 0); ++ ++ return result; ++} ++#endif ++ + /* Compare two lines A and B trying every key in sequence until there + are no more keys or a difference is found. */ + + static int +-keycompare (const struct line *a, const struct line *b) ++keycompare_uni (const struct line *a, const struct line *b) + { + struct keyfield const *key = keylist; + +@@ -1458,6 +1848,177 @@ + return key->reverse ? -diff : diff; + } + ++#if HAVE_MBRTOWC ++static int ++keycompare_mb (const struct line *a, const struct line *b) ++{ ++ struct keyfield *key = keylist; ++ ++ /* For the first iteration only, the key positions have been ++ precomputed for us. */ ++ char *texta = a->keybeg; ++ char *textb = b->keybeg; ++ char *lima = a->keylim; ++ char *limb = b->keylim; ++ ++ size_t mblength_a, mblength_b; ++ wchar_t wc_a, wc_b; ++ mbstate_t state_a, state_b; ++ ++ int diff; ++ ++ memset (&state_a, '\0', sizeof(mbstate_t)); ++ memset (&state_b, '\0', sizeof(mbstate_t)); ++ ++ for (;;) ++ { ++ unsigned char *translate = (unsigned char *) key->translate; ++ bool const *ignore = key->ignore; ++ ++ /* Find the lengths. */ ++ size_t lena = lima <= texta ? 0 : lima - texta; ++ size_t lenb = limb <= textb ? 0 : limb - textb; ++ ++ /* Actually compare the fields. */ ++ if (key->numeric | key->general_numeric) ++ { ++ char savea = *lima, saveb = *limb; ++ ++ *lima = *limb = '\0'; ++ if (force_general_numcompare) ++ diff = general_numcompare (texta, textb); ++ else ++ diff = ((key->numeric ? numcompare : general_numcompare) ++ (texta, textb)); ++ *lima = savea, *limb = saveb; ++ } ++ else if (key->month) ++ diff = getmonth (texta, lena) - getmonth (textb, lenb); ++ else ++ { ++ if (ignore || translate) ++ { ++ char *copy_a = (char *) alloca (lena + 1 + lenb + 1); ++ char *copy_b = copy_a + lena + 1; ++ size_t new_len_a, new_len_b; ++ size_t i, j; ++ ++ /* Ignore and/or translate chars before comparing. */ ++# define IGNORE_CHARS(NEW_LEN, LEN, TEXT, COPY, WC, MBLENGTH, STATE) \ ++ do \ ++ { \ ++ wchar_t uwc; \ ++ char mbc[MB_LEN_MAX]; \ ++ mbstate_t state_wc; \ ++ \ ++ for (NEW_LEN = i = 0; i < LEN;) \ ++ { \ ++ mbstate_t state_bak; \ ++ \ ++ state_bak = STATE; \ ++ MBLENGTH = mbrtowc (&WC, TEXT + i, LEN - i, &STATE); \ ++ \ ++ if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1 \ ++ || MBLENGTH == 0) \ ++ { \ ++ if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1) \ ++ STATE = state_bak; \ ++ if (!ignore) \ ++ COPY[NEW_LEN++] = TEXT[i++]; \ ++ continue; \ ++ } \ ++ \ ++ if (ignore) \ ++ { \ ++ if ((ignore == nonprinting && !iswprint (WC)) \ ++ || (ignore == nondictionary \ ++ && !iswalnum (WC) && !iswblank (WC))) \ ++ { \ ++ i += MBLENGTH; \ ++ continue; \ ++ } \ ++ } \ ++ \ ++ if (translate) \ ++ { \ ++ \ ++ uwc = towupper(WC); \ ++ if (WC == uwc) \ ++ { \ ++ memcpy (mbc, TEXT + i, MBLENGTH); \ ++ i += MBLENGTH; \ ++ } \ ++ else \ ++ { \ ++ i += MBLENGTH; \ ++ WC = uwc; \ ++ memset (&state_wc, '\0', sizeof (mbstate_t)); \ ++ \ ++ MBLENGTH = wcrtomb (mbc, WC, &state_wc); \ ++ assert (MBLENGTH != (size_t)-1 && MBLENGTH != 0); \ ++ } \ ++ \ ++ for (j = 0; j < MBLENGTH; j++) \ ++ COPY[NEW_LEN++] = mbc[j]; \ ++ } \ ++ else \ ++ for (j = 0; j < MBLENGTH; j++) \ ++ COPY[NEW_LEN++] = TEXT[i++]; \ ++ } \ ++ COPY[NEW_LEN] = '\0'; \ ++ } \ ++ while (0) ++ IGNORE_CHARS (new_len_a, lena, texta, copy_a, ++ wc_a, mblength_a, state_a); ++ IGNORE_CHARS (new_len_b, lenb, textb, copy_b, ++ wc_b, mblength_b, state_b); ++ diff = xmemcoll (copy_a, new_len_a, copy_b, new_len_b); ++ } ++ else if (lena == 0) ++ diff = - NONZERO (lenb); ++ else if (lenb == 0) ++ goto greater; ++ else ++ diff = xmemcoll (texta, lena, textb, lenb); ++ } ++ ++ if (diff) ++ goto not_equal; ++ ++ key = key->next; ++ if (! key) ++ break; ++ ++ /* Find the beginning and limit of the next field. */ ++ if (key->eword != -1) ++ lima = limfield (a, key), limb = limfield (b, key); ++ else ++ lima = a->text + a->length - 1, limb = b->text + b->length - 1; ++ ++ if (key->sword != -1) ++ texta = begfield (a, key), textb = begfield (b, key); ++ else ++ { ++ texta = a->text, textb = b->text; ++ if (key->skipsblanks) ++ { ++ while (texta < lima && ismbblank (texta, lima - texta, &mblength_a)) ++ texta += mblength_a; ++ while (textb < limb && ismbblank (textb, limb - textb, &mblength_b)) ++ textb += mblength_b; ++ } ++ } ++ } ++ ++ return 0; ++ ++greater: ++ diff = 1; ++not_equal: ++ return key->reverse ? -diff : diff; ++} ++#endif ++ + /* Compare two lines A and B, returning negative, zero, or positive + depending on whether A compares less than, equal to, or greater than B. */ + +@@ -2309,7 +2870,7 @@ + atexit (close_stdout); + + hard_LC_COLLATE = hard_locale (LC_COLLATE); +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + hard_LC_TIME = hard_locale (LC_TIME); + #endif + +@@ -2330,6 +2891,27 @@ + thousands_sep = -1; + } + ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ inittables = inittables_mb; ++ begfield = begfield_mb; ++ limfield = limfield_mb; ++ getmonth = getmonth_mb; ++ keycompare = keycompare_mb; ++ numcompare = numcompare_mb; ++ } ++ else ++#endif ++ { ++ inittables = inittables_uni; ++ begfield = begfield_uni; ++ limfield = limfield_uni; ++ getmonth = getmonth_uni; ++ keycompare = keycompare_uni; ++ numcompare = numcompare_uni; ++ } ++ + have_read_stdin = false; + inittables (); + +@@ -2544,13 +3126,35 @@ + + case 't': + { +- char newtab = optarg[0]; +- if (! newtab) ++ char newtab[MB_LEN_MAX + 1]; ++ size_t newtab_length = 1; ++ strncpy (newtab, optarg, MB_LEN_MAX); ++ if (! newtab[0]) + error (SORT_FAILURE, 0, _("empty tab")); +- if (optarg[1]) ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ wchar_t wc; ++ mbstate_t state; ++ size_t i; ++ ++ memset (&state, '\0', sizeof (mbstate_t)); ++ newtab_length = mbrtowc (&wc, newtab, strnlen (newtab, ++ MB_LEN_MAX), ++ &state); ++ switch (newtab_length) ++ { ++ case (size_t) -1: ++ case (size_t) -2: ++ case 0: ++ newtab_length = 1; ++ } ++ } ++#endif ++ if (newtab_length == 1 && optarg[1]) + { + if (STREQ (optarg, "\\0")) +- newtab = '\0'; ++ newtab[0] = '\0'; + else + { + /* Provoke with `sort -txx'. Complain about +@@ -2561,9 +3165,12 @@ + quote (optarg)); + } + } +- if (tab != TAB_DEFAULT && tab != newtab) ++ if (tab_length ++ && (tab_length != newtab_length ++ || memcmp (tab, newtab, tab_length) != 0)) + error (SORT_FAILURE, 0, _("incompatible tabs")); +- tab = newtab; ++ memcpy (tab, newtab, newtab_length); ++ tab_length = newtab_length; + } + break; + +--- coreutils-6.7/src/unexpand.c.i18n 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/src/unexpand.c 2007-01-09 17:18:28.000000000 +0000 +@@ -39,11 +39,28 @@ + #include + #include + #include ++ ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "quote.h" + #include "xstrndup.h" + ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no `g' prefix). */ + #define PROGRAM_NAME "unexpand" + +@@ -110,6 +127,208 @@ + {NULL, 0, NULL, 0} + }; + ++static FILE *next_file (FILE *fp); ++ ++#if HAVE_MBRTOWC ++static void ++unexpand_multibyte (void) ++{ ++ FILE *fp; /* Input stream. */ ++ mbstate_t i_state; /* Current shift state of the input stream. */ ++ mbstate_t i_state_bak; /* Back up the I_STATE. */ ++ mbstate_t o_state; /* Current shift state of the output stream. */ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen = 0; /* The length of the byte sequence in buf. */ ++ wint_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character ++ which shows as same character as WC. */ ++ ++ /* Index in `tab_list' of next tabstop: */ ++ int tab_index = 0; /* For calculating width of pending tabs. */ ++ int print_tab_index = 0; /* For printing as many tabs as possible. */ ++ unsigned int column = 0; /* Column on screen of next char. */ ++ int next_tab_column; /* Column the next tab stop is on. */ ++ int convert = 1; /* If nonzero, perform translations. */ ++ unsigned int pending = 0; /* Pending columns of blanks. */ ++ ++ fp = next_file ((FILE *) NULL); ++ if (fp == NULL) ++ return; ++ ++ memset (&o_state, '\0', sizeof(mbstate_t)); ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ ++ for (;;) ++ { ++ if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp)) ++ { ++ memmove (buf, bufpos, buflen); ++ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp); ++ bufpos = buf; ++ } ++ ++ /* Get a wide character. */ ++ if (buflen < 1) ++ { ++ mblength = 1; ++ wc = WEOF; ++ } ++ else ++ { ++ i_state_bak = i_state; ++ mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &i_state); ++ } ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ i_state = i_state_bak; ++ wc = L'\0'; ++ } ++ ++ if (wc == L' ' && convert && column < INT_MAX) ++ { ++ ++pending; ++ ++column; ++ } ++ else if (wc == L'\t' && convert) ++ { ++ if (tab_size == 0) ++ { ++ /* Do not let tab_index == first_free_tab; ++ stop when it is 1 less. */ ++ while (tab_index < first_free_tab - 1 ++ && column >= tab_list[tab_index]) ++ tab_index++; ++ next_tab_column = tab_list[tab_index]; ++ if (tab_index < first_free_tab - 1) ++ tab_index++; ++ if (column >= next_tab_column) ++ { ++ convert = 0; /* Ran out of tab stops. */ ++ goto flush_pend_mb; ++ } ++ } ++ else ++ { ++ next_tab_column = column + tab_size - column % tab_size; ++ } ++ pending += next_tab_column - column; ++ column = next_tab_column; ++ } ++ else ++ { ++flush_pend_mb: ++ /* Flush pending spaces. Print as many tabs as possible, ++ then print the rest as spaces. */ ++ if (pending == 1) ++ { ++ putchar (' '); ++ pending = 0; ++ } ++ column -= pending; ++ while (pending > 0) ++ { ++ if (tab_size == 0) ++ { ++ /* Do not let print_tab_index == first_free_tab; ++ stop when it is 1 less. */ ++ while (print_tab_index < first_free_tab - 1 ++ && column >= tab_list[print_tab_index]) ++ print_tab_index++; ++ next_tab_column = tab_list[print_tab_index]; ++ if (print_tab_index < first_free_tab - 1) ++ print_tab_index++; ++ } ++ else ++ { ++ next_tab_column = ++ column + tab_size - column % tab_size; ++ } ++ if (next_tab_column - column <= pending) ++ { ++ putchar ('\t'); ++ pending -= next_tab_column - column; ++ column = next_tab_column; ++ } ++ else ++ { ++ --print_tab_index; ++ column += pending; ++ while (pending != 0) ++ { ++ putchar (' '); ++ pending--; ++ } ++ } ++ } ++ ++ if (wc == WEOF) ++ { ++ fp = next_file (fp); ++ if (fp == NULL) ++ break; /* No more files. */ ++ else ++ { ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ continue; ++ } ++ } ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ if (convert) ++ { ++ ++column; ++ if (convert_entire_line == 0) ++ convert = 0; ++ } ++ mblength = 1; ++ putchar (buf[0]); ++ } ++ else if (mblength == 0) ++ { ++ if (convert && convert_entire_line == 0) ++ convert = 0; ++ mblength = 1; ++ putchar ('\0'); ++ } ++ else ++ { ++ if (convert) ++ { ++ if (wc == L'\b') ++ { ++ if (column > 0) ++ --column; ++ } ++ else ++ { ++ int width; /* The width of WC. */ ++ ++ width = wcwidth (wc); ++ column += (width > 0) ? width : 0; ++ if (convert_entire_line == 0) ++ convert = 0; ++ } ++ } ++ ++ if (wc == L'\n') ++ { ++ tab_index = print_tab_index = 0; ++ column = pending = 0; ++ convert = 1; ++ } ++ fwrite (bufpos, sizeof(char), mblength, stdout); ++ } ++ } ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++} ++#endif ++ ++ + void + usage (int status) + { +@@ -531,7 +750,12 @@ + + file_list = (optind < argc ? &argv[optind] : stdin_argv); + +- unexpand (); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ unexpand_multibyte (); ++ else ++#endif ++ unexpand (); + + if (have_read_stdin && fclose (stdin) != 0) + error (EXIT_FAILURE, errno, "-"); +--- coreutils-6.7/src/pr.c.i18n 2006-10-24 23:59:25.000000000 +0100 ++++ coreutils-6.7/src/pr.c 2007-01-09 17:18:28.000000000 +0000 @@ -313,6 +313,32 @@ #include @@ -918,2402 +3442,8 @@ /* We've just printed some files and need to clean up things before looking for more options and printing the next batch of files. ---- coreutils-5.95/src/join.c.i18n 2005-08-12 08:16:25.000000000 +0100 -+++ coreutils-5.95/src/join.c 2006-05-15 15:08:57.000000000 +0100 -@@ -23,16 +23,30 @@ - #include - #include - -+/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth(). */ -+#if HAVE_WCHAR_H -+# include -+#endif -+ -+/* Get iswblank(), towupper. */ -+#if HAVE_WCTYPE_H -+# include -+#endif -+ - #include "system.h" - #include "error.h" - #include "hard-locale.h" - #include "linebuffer.h" --#include "memcasecmp.h" - #include "quote.h" - #include "stdio--.h" - #include "xmemcoll.h" - #include "xstrtol.h" - -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ -+#if HAVE_MBRTOWC && defined mbstate_t -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) -+#endif -+ - /* The official name of this program (e.g., no `g' prefix). */ - #define PROGRAM_NAME "join" - -@@ -104,10 +118,12 @@ - /* Last element in `outlist', where a new element can be added. */ - static struct outlist *outlist_end = &outlist_head; - --/* Tab character separating fields. If negative, fields are separated -- by any nonempty string of blanks, otherwise by exactly one -- tab character whose value (when cast to unsigned char) equals TAB. */ --static int tab = -1; -+/* Tab character separating fields. If NULL, fields are separated -+ by any nonempty string of blanks. */ -+static char *tab = NULL; -+ -+/* The number of bytes used for tab. */ -+static size_t tablen = 0; - - static struct option const longopts[] = - { -@@ -197,6 +213,8 @@ - - /* Fill in the `fields' structure in LINE. */ - -+/* Fill in the `fields' structure in LINE. */ -+ - static void - xfields (struct line *line) - { -@@ -206,10 +224,11 @@ - if (ptr == lim) - return; - -- if (0 <= tab) -+ if (tab != NULL) - { -+ unsigned char t = tab[0]; - char *sep; -- for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1) -+ for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1) - extract_field (line, ptr, sep - ptr); - } - else -@@ -236,6 +255,148 @@ - extract_field (line, ptr, lim - ptr); - } - -+#if HAVE_MBRTOWC -+static void -+xfields_multibyte (struct line *line) -+{ -+ char *ptr = line->buf.buffer; -+ char const *lim = ptr + line->buf.length - 1; -+ wchar_t wc = 0; -+ size_t mblength = 1; -+ mbstate_t state, state_bak; -+ -+ memset (&state, 0, sizeof (mbstate_t)); -+ -+ if (ptr == lim) -+ return; -+ -+ if (tab != NULL) -+ { -+ unsigned char t = tab[0]; -+ char *sep = ptr; -+ for (; ptr < lim; ptr = sep + mblength) -+ { -+ sep = ptr; -+ while (sep < lim) -+ { -+ state_bak = state; -+ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); -+ -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ mblength = 1; -+ state = state_bak; -+ } -+ mblength = (mblength < 1) ? 1 : mblength; -+ -+ if (mblength == tablen && !memcmp (sep, tab, mblength)) -+ break; -+ else -+ { -+ sep += mblength; -+ continue; -+ } -+ } -+ -+ if (sep == lim) -+ break; -+ -+ extract_field (line, ptr, sep - ptr); -+ } -+ } -+ else -+ { -+ /* Skip leading blanks before the first field. */ -+ while(ptr < lim) -+ { -+ state_bak = state; -+ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); -+ -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ mblength = 1; -+ state = state_bak; -+ break; -+ } -+ mblength = (mblength < 1) ? 1 : mblength; -+ -+ if (!iswblank(wc)) -+ break; -+ ptr += mblength; -+ } -+ -+ do -+ { -+ char *sep; -+ state_bak = state; -+ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ mblength = 1; -+ state = state_bak; -+ break; -+ } -+ mblength = (mblength < 1) ? 1 : mblength; -+ -+ sep = ptr + mblength; -+ while (sep != lim) -+ { -+ state_bak = state; -+ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ mblength = 1; -+ state = state_bak; -+ break; -+ } -+ mblength = (mblength < 1) ? 1 : mblength; -+ -+ if (iswblank (wc)) -+ break; -+ -+ sep += mblength; -+ } -+ -+ extract_field (line, ptr, sep - ptr); -+ if (sep == lim) -+ return; -+ -+ state_bak = state; -+ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ mblength = 1; -+ state = state_bak; -+ break; -+ } -+ mblength = (mblength < 1) ? 1 : mblength; -+ -+ ptr = sep + mblength; -+ while (ptr != lim) -+ { -+ state_bak = state; -+ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ mblength = 1; -+ state = state_bak; -+ break; -+ } -+ mblength = (mblength < 1) ? 1 : mblength; -+ -+ if (!iswblank (wc)) -+ break; -+ -+ ptr += mblength; -+ } -+ } -+ while (ptr != lim); -+ } -+ -+ extract_field (line, ptr, lim - ptr); -+} -+#endif -+ - /* Read a line from FP into LINE and split it into fields. - Return true if successful. */ - -@@ -256,6 +417,11 @@ - line->nfields_allocated = 0; - line->nfields = 0; - line->fields = NULL; -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ xfields_multibyte (line); -+ else -+#endif - xfields (line); - return true; - } -@@ -310,56 +476,114 @@ - keycmp (struct line const *line1, struct line const *line2) - { - /* Start of field to compare in each file. */ -- char *beg1; -- char *beg2; -- -- size_t len1; -- size_t len2; /* Length of fields to compare. */ -+ char *beg[2]; -+ char *copy[2]; -+ size_t len[2]; /* Length of fields to compare. */ - int diff; -+ int i, j; - - if (join_field_1 < line1->nfields) - { -- beg1 = line1->fields[join_field_1].beg; -- len1 = line1->fields[join_field_1].len; -+ beg[0] = line1->fields[join_field_1].beg; -+ len[0] = line1->fields[join_field_1].len; - } - else - { -- beg1 = NULL; -- len1 = 0; -+ beg[0] = NULL; -+ len[0] = 0; - } - - if (join_field_2 < line2->nfields) - { -- beg2 = line2->fields[join_field_2].beg; -- len2 = line2->fields[join_field_2].len; -+ beg[1] = line2->fields[join_field_2].beg; -+ len[1] = line2->fields[join_field_2].len; - } - else - { -- beg2 = NULL; -- len2 = 0; -+ beg[1] = NULL; -+ len[1] = 0; - } - -- if (len1 == 0) -- return len2 == 0 ? 0 : -1; -- if (len2 == 0) -+ if (len[0] == 0) -+ return len[1] == 0 ? 0 : -1; -+ if (len[1] == 0) - return 1; - - if (ignore_case) - { -- /* FIXME: ignore_case does not work with NLS (in particular, -- with multibyte chars). */ -- diff = memcasecmp (beg1, beg2, MIN (len1, len2)); -+#ifdef HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ size_t mblength; -+ wchar_t wc, uwc; -+ mbstate_t state, state_bak; -+ -+ memset (&state, '\0', sizeof (mbstate_t)); -+ -+ for (i = 0; i < 2; i++) -+ { -+ copy[i] = alloca (len[i] + 1); -+ -+ for (j = 0; j < MIN (len[0], len[1]);) -+ { -+ state_bak = state; -+ mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state); -+ -+ switch (mblength) -+ { -+ case (size_t) -1: -+ case (size_t) -2: -+ state = state_bak; -+ /* Fall through */ -+ case 0: -+ mblength = 1; -+ break; -+ -+ default: -+ uwc = towupper (wc); -+ -+ if (uwc != wc) -+ { -+ mbstate_t state_wc; -+ -+ memset (&state_wc, '\0', sizeof (mbstate_t)); -+ wcrtomb (copy[i] + j, uwc, &state_wc); -+ } -+ else -+ memcpy (copy[i] + j, beg[i] + j, mblength); -+ } -+ j += mblength; -+ } -+ copy[i][j] = '\0'; -+ } -+ } -+ else -+#endif -+ { -+ for (i = 0; i < 2; i++) -+ { -+ copy[i] = alloca (len[i] + 1); -+ -+ for (j = 0; j < MIN (len[0], len[1]); j++) -+ copy[i][j] = toupper (beg[i][j]); -+ -+ copy[i][j] = '\0'; -+ } -+ } - } - else - { -- if (hard_LC_COLLATE) -- return xmemcoll (beg1, len1, beg2, len2); -- diff = memcmp (beg1, beg2, MIN (len1, len2)); -+ copy[0] = (unsigned char *) beg[0]; -+ copy[1] = (unsigned char *) beg[1]; - } - -+ if (HAVE_SETLOCALE && hard_LC_COLLATE) -+ return xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]); -+ diff = memcmp (copy[0], copy[1], MIN (len[0], len[1])); -+ - if (diff) - return diff; -- return len1 < len2 ? -1 : len1 != len2; -+ return len[0] - len[1]; - } - - /* Print field N of LINE if it exists and is nonempty, otherwise -@@ -384,11 +608,18 @@ - - /* Print the join of LINE1 and LINE2. */ - -+#define PUT_TAB_CHAR \ -+ do \ -+ { \ -+ (tab != NULL) ? \ -+ fwrite(tab, sizeof(char), tablen, stdout) : putchar (' '); \ -+ } \ -+ while (0) -+ - static void - prjoin (struct line const *line1, struct line const *line2) - { - const struct outlist *outlist; -- char output_separator = tab < 0 ? ' ' : tab; - - outlist = outlist_head.next; - if (outlist) -@@ -404,12 +635,12 @@ - if (o->file == 0) - { - if (line1 == &uni_blank) -- { -+ { - line = line2; - field = join_field_2; - } - else -- { -+ { - line = line1; - field = join_field_1; - } -@@ -423,7 +654,7 @@ - o = o->next; - if (o == NULL) - break; -- putchar (output_separator); -+ PUT_TAB_CHAR; - } - putchar ('\n'); - } -@@ -441,23 +672,23 @@ - prfield (join_field_1, line1); - for (i = 0; i < join_field_1 && i < line1->nfields; ++i) - { -- putchar (output_separator); -+ PUT_TAB_CHAR; - prfield (i, line1); - } - for (i = join_field_1 + 1; i < line1->nfields; ++i) - { -- putchar (output_separator); -+ PUT_TAB_CHAR; - prfield (i, line1); - } - - for (i = 0; i < join_field_2 && i < line2->nfields; ++i) - { -- putchar (output_separator); -+ PUT_TAB_CHAR; - prfield (i, line2); - } - for (i = join_field_2 + 1; i < line2->nfields; ++i) - { -- putchar (output_separator); -+ PUT_TAB_CHAR; - prfield (i, line2); - } - putchar ('\n'); -@@ -869,20 +1100,41 @@ - - case 't': - { -- unsigned char newtab = optarg[0]; -- if (! newtab) -+ char *newtab; -+ size_t newtablen; -+ if (! optarg[0]) - error (EXIT_FAILURE, 0, _("empty tab")); -- if (optarg[1]) -+ newtab = xstrdup (optarg); -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ mbstate_t state; -+ -+ memset (&state, 0, sizeof (mbstate_t)); -+ newtablen = mbrtowc (NULL, newtab, -+ strnlen (newtab, MB_LEN_MAX), -+ &state); -+ if (newtablen == (size_t) 0 -+ || newtablen == (size_t) -1 -+ || newtablen == (size_t) -2) -+ newtablen = 1; -+ } -+ else -+#endif -+ newtablen = 1; -+ -+ if (newtablen == 1 && newtab[1]) -+ { -+ if (STREQ (newtab, "\\0")) -+ newtab[0] = '\0'; -+ } -+ if (tab != NULL && strcmp (tab, newtab)) - { -- if (STREQ (optarg, "\\0")) -- newtab = '\0'; -- else -- error (EXIT_FAILURE, 0, _("multi-character tab %s"), -- quote (optarg)); -+ free (newtab); -+ error (EXIT_FAILURE, 0, _("incompatible tabs")); - } -- if (0 <= tab && tab != newtab) -- error (EXIT_FAILURE, 0, _("incompatible tabs")); - tab = newtab; -+ tablen = newtablen; - } - break; - ---- coreutils-5.95/src/sort.c 2006-05-15 15:08:57.000000000 +0100 -+++ coreutils-5.97/src/sort.c 2006-08-15 17:43:38.000000000 +0100 -@@ -23,9 +23,18 @@ - - #include - -+#include - #include - #include - #include -+#if HAVE_WCHAR_H -+# include -+#endif -+/* Get isw* functions. */ -+#if HAVE_WCTYPE_H -+# include -+#endif -+ - #include "system.h" - #include "error.h" - #include "hard-locale.h" -@@ -95,14 +104,38 @@ - /* Thousands separator; if -1, then there isn't one. */ - static int thousands_sep; - -+static int force_general_numcompare = 0; -+ - /* Nonzero if the corresponding locales are hard. */ - static bool hard_LC_COLLATE; --#if HAVE_NL_LANGINFO -+#if HAVE_LANGINFO_CODESET - static bool hard_LC_TIME; - #endif - - #define NONZERO(x) ((x) != 0) - -+/* get a multibyte character's byte length. */ -+#define GET_BYTELEN_OF_CHAR(LIM, PTR, MBLENGTH, STATE) \ -+ do \ -+ { \ -+ wchar_t wc; \ -+ mbstate_t state_bak; \ -+ \ -+ state_bak = STATE; \ -+ mblength = mbrtowc (&wc, PTR, LIM - PTR, &STATE); \ -+ \ -+ switch (MBLENGTH) \ -+ { \ -+ case (size_t)-1: \ -+ case (size_t)-2: \ -+ STATE = state_bak; \ -+ /* Fall through. */ \ -+ case 0: \ -+ MBLENGTH = 1; \ -+ } \ -+ } \ -+ while (0) -+ - /* The kind of blanks for '-b' to skip in various options. */ - enum blanktype { bl_start, bl_end, bl_both }; - -@@ -239,13 +272,11 @@ - they were read if all keys compare equal. */ - static bool stable; - --/* If TAB has this value, blanks separate fields. */ --enum { TAB_DEFAULT = CHAR_MAX + 1 }; -- --/* Tab character separating fields. If TAB_DEFAULT, then fields are -+/* Tab character separating fields. If tab_length is 0, then fields are - separated by the empty string between a non-blank character and a blank - character. */ --static int tab = TAB_DEFAULT; -+static char tab[MB_LEN_MAX + 1]; -+static size_t tab_length = 0; - - /* Flag to remove consecutive duplicate lines from the output. - Only the last of a sequence of equal lines will be output. */ -@@ -392,6 +423,44 @@ - static struct tempnode *volatile temphead; - static struct tempnode *volatile *temptail = &temphead; - -+/* Function pointers. */ -+static void -+(*inittables) (void); -+static char * -+(*begfield) (const struct line*, const struct keyfield *); -+static char * -+(*limfield) (const struct line*, const struct keyfield *); -+static int -+(*getmonth) (char const *, size_t); -+static int -+(*keycompare) (const struct line *, const struct line *); -+static int -+(*numcompare) (const char *, const char *); -+ -+/* Test for white space multibyte character. -+ Set LENGTH the byte length of investigated multibyte character. */ -+#if HAVE_MBRTOWC -+static int -+ismbblank (const char *str, size_t len, size_t *length) -+{ -+ size_t mblength; -+ wchar_t wc; -+ mbstate_t state; -+ -+ memset (&state, '\0', sizeof(mbstate_t)); -+ mblength = mbrtowc (&wc, str, len, &state); -+ -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ *length = 1; -+ return 0; -+ } -+ -+ *length = (mblength < 1) ? 1 : mblength; -+ return iswblank (wc); -+} -+#endif -+ - /* Clean up any remaining temporary files. */ - - static void -@@ -545,7 +614,7 @@ - free (node); - } - --#if HAVE_NL_LANGINFO -+#if HAVE_LANGINFO_CODESET - - static int - struct_month_cmp (const void *m1, const void *m2) -@@ -560,7 +629,7 @@ - /* Initialize the character class tables. */ - - static void --inittables (void) -+inittables_uni (void) - { - size_t i; - -@@ -572,7 +641,7 @@ - fold_toupper[i] = (ISLOWER (i) ? toupper (i) : i); - } - --#if HAVE_NL_LANGINFO -+#if HAVE_LANGINFO_CODESET - /* If we're not in the "C" locale, read different names for months. */ - if (hard_LC_TIME) - { -@@ -598,6 +667,64 @@ - #endif - } - -+#if HAVE_MBRTOWC -+static void -+inittables_mb (void) -+{ -+ int i, j, k, l; -+ char *name, *s; -+ size_t s_len, mblength; -+ char mbc[MB_LEN_MAX]; -+ wchar_t wc, pwc; -+ mbstate_t state_mb, state_wc; -+ -+ for (i = 0; i < MONTHS_PER_YEAR; i++) -+ { -+ s = (char *) nl_langinfo (ABMON_1 + i); -+ s_len = strlen (s); -+ monthtab[i].name = name = (char *) xmalloc (s_len + 1); -+ monthtab[i].val = i + 1; -+ -+ memset (&state_mb, '\0', sizeof (mbstate_t)); -+ memset (&state_wc, '\0', sizeof (mbstate_t)); -+ -+ for (j = 0; j < s_len;) -+ { -+ if (!ismbblank (s + j, s_len - j, &mblength)) -+ break; -+ j += mblength; -+ } -+ -+ for (k = 0; j < s_len;) -+ { -+ mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb); -+ assert (mblength != (size_t)-1 && mblength != (size_t)-2); -+ if (mblength == 0) -+ break; -+ -+ pwc = towupper (wc); -+ if (pwc == wc) -+ { -+ memcpy (mbc, s + j, mblength); -+ j += mblength; -+ } -+ else -+ { -+ j += mblength; -+ mblength = wcrtomb (mbc, pwc, &state_wc); -+ assert (mblength != (size_t)0 && mblength != (size_t)-1); -+ } -+ -+ for (l = 0; l < mblength; l++) -+ name[k++] = mbc[l]; -+ } -+ name[k] = '\0'; -+ } -+ qsort ((void *) monthtab, MONTHS_PER_YEAR, -+ sizeof (struct month), struct_month_cmp); -+} -+#endif -+ - /* Specify the amount of main memory to use when sorting. */ - static void - specify_sort_size (char const *s) -@@ -808,7 +935,7 @@ - by KEY in LINE. */ - - static char * --begfield (const struct line *line, const struct keyfield *key) -+begfield_uni (const struct line *line, const struct keyfield *key) - { - char *ptr = line->text, *lim = ptr + line->length - 1; - size_t sword = key->sword; -@@ -818,10 +945,10 @@ - /* The leading field separator itself is included in a field when -t - is absent. */ - -- if (tab != TAB_DEFAULT) -+ if (tab_length) - while (ptr < lim && sword--) - { -- while (ptr < lim && *ptr != tab) -+ while (ptr < lim && *ptr != tab[0]) - ++ptr; - if (ptr < lim) - ++ptr; -@@ -849,11 +976,70 @@ - return ptr; - } - -+#if HAVE_MBRTOWC -+static char * -+begfield_mb (const struct line *line, const struct keyfield *key) -+{ -+ int i; -+ char *ptr = line->text, *lim = ptr + line->length - 1; -+ size_t sword = key->sword; -+ size_t schar = key->schar; -+ size_t mblength; -+ mbstate_t state; -+ -+ memset (&state, '\0', sizeof(mbstate_t)); -+ -+ if (tab_length) -+ while (ptr < lim && sword--) -+ { -+ while (ptr < lim && memcmp (ptr, tab, tab_length) != 0) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ if (ptr < lim) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ } -+ else -+ while (ptr < lim && sword--) -+ { -+ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ if (ptr < lim) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ } -+ -+ if (key->skipsblanks) -+ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ -+ for (i = 0; i < schar; i++) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ -+ if (ptr + mblength > lim) -+ break; -+ else -+ ptr += mblength; -+ } -+ -+ return ptr; -+} -+#endif -+ - /* Return the limit of (a pointer to the first character after) the field - in LINE specified by KEY. */ - - static char * --limfield (const struct line *line, const struct keyfield *key) -+limfield_uni (const struct line *line, const struct keyfield *key) - { - char *ptr = line->text, *lim = ptr + line->length - 1; - size_t eword = key->eword, echar = key->echar; -@@ -866,10 +1052,10 @@ - `beginning' is the first character following the delimiting TAB. - Otherwise, leave PTR pointing at the first `blank' character after - the preceding field. */ -- if (tab != TAB_DEFAULT) -+ if (tab_length) - while (ptr < lim && eword--) - { -- while (ptr < lim && *ptr != tab) -+ while (ptr < lim && *ptr != tab[0]) - ++ptr; - if (ptr < lim && (eword | echar)) - ++ptr; -@@ -915,10 +1101,10 @@ - */ - - /* Make LIM point to the end of (one byte past) the current field. */ -- if (tab != TAB_DEFAULT) -+ if (tab_length) - { - char *newlim; -- newlim = memchr (ptr, tab, lim - ptr); -+ newlim = memchr (ptr, tab[0], lim - ptr); - if (newlim) - lim = newlim; - } -@@ -951,6 +1137,107 @@ - return ptr; - } - -+#if HAVE_MBRTOWC -+static char * -+limfield_mb (const struct line *line, const struct keyfield *key) -+{ -+ char *ptr = line->text, *lim = ptr + line->length - 1; -+ size_t eword = key->eword, echar = key->echar; -+ int i; -+ size_t mblength; -+ mbstate_t state; -+ -+ memset (&state, '\0', sizeof(mbstate_t)); -+ -+ if (tab_length) -+ while (ptr < lim && eword--) -+ { -+ while (ptr < lim && memcmp (ptr, tab, tab_length) != 0) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ if (ptr < lim && (eword | echar)) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ } -+ else -+ while (ptr < lim && eword--) -+ { -+ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ if (ptr < lim) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ } -+ -+ -+# ifdef POSIX_UNSPECIFIED -+ /* Make LIM point to the end of (one byte past) the current field. */ -+ if (tab_length) -+ { -+ char *newlim, *p; -+ -+ newlim = NULL; -+ for (p = ptr; p < lim;) -+ { -+ if (memcmp (p, tab, tab_length) == 0) -+ { -+ newlim = p; -+ break; -+ } -+ -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ p += mblength; -+ } -+ } -+ else -+ { -+ char *newlim; -+ newlim = ptr; -+ -+ while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength)) -+ newlim += mblength; -+ if (ptr < lim) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength)) -+ newlim += mblength; -+ lim = newlim; -+ } -+# endif -+ -+ /* If we're skipping leading blanks, don't start counting characters -+ * until after skipping past any leading blanks. */ -+ if (key->skipsblanks) -+ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ -+ memset (&state, '\0', sizeof(mbstate_t)); -+ -+ /* Advance PTR by ECHAR (if possible), but no further than LIM. */ -+ for (i = 0; i < echar; i++) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ -+ if (ptr + mblength > lim) -+ break; -+ else -+ ptr += mblength; -+ } -+ -+ return ptr; -+} -+#endif -+ - /* Fill BUF reading from FP, moving buf->left bytes from the end - of buf->buf to the beginning first. If EOF is reached and the - file wasn't terminated by a newline, supply one. Set up BUF's line -@@ -1033,8 +1320,24 @@ - else - { - if (key->skipsblanks) -- while (blanks[to_uchar (*line_start)]) -- line_start++; -+ { -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ size_t mblength; -+ mbstate_t state; -+ memset (&state, '\0', sizeof(mbstate_t)); -+ while (line_start < line->keylim && -+ ismbblank (line_start, -+ line->keylim - line_start, -+ &mblength)) -+ line_start += mblength; -+ } -+ else -+#endif -+ while (blanks[to_uchar (*line_start)]) -+ line_start++; -+ } - line->keybeg = line_start; - } - } -@@ -1067,7 +1370,7 @@ - hideously fast. */ - - static int --numcompare (const char *a, const char *b) -+numcompare_uni (const char *a, const char *b) - { - while (blanks[to_uchar (*a)]) - a++; -@@ -1077,6 +1380,25 @@ - return strnumcmp (a, b, decimal_point, thousands_sep); - } - -+#if HAVE_MBRTOWC -+static int -+numcompare_mb (const char *a, const char *b) -+{ -+ size_t mblength, len; -+ len = strlen (a); /* okay for UTF-8 */ -+ while (*a && ismbblank (a, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength)) -+ { -+ a += mblength; -+ len -= mblength; -+ } -+ len = strlen (b); /* okay for UTF-8 */ -+ while (*b && ismbblank (b, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength)) -+ b += mblength; -+ -+ return strnumcmp (a, b, decimal_point, thousands_sep); -+} -+#endif /* HAV_EMBRTOWC */ -+ - static int - general_numcompare (const char *sa, const char *sb) - { -@@ -1110,7 +1432,7 @@ - Return 0 if the name in S is not recognized. */ - - static int --getmonth (char const *month, size_t len) -+getmonth_uni (char const *month, size_t len) - { - size_t lo = 0; - size_t hi = MONTHS_PER_YEAR; -@@ -1152,11 +1474,79 @@ - return 0; - } - -+#if HAVE_MBRTOWC -+static int -+getmonth_mb (const char *s, size_t len) -+{ -+ char *month; -+ register size_t i; -+ register int lo = 0, hi = MONTHS_PER_YEAR, result; -+ char *tmp; -+ size_t wclength, mblength; -+ const char **pp; -+ const wchar_t **wpp; -+ wchar_t *month_wcs; -+ mbstate_t state; -+ -+ while (len > 0 && ismbblank (s, len, &mblength)) -+ { -+ s += mblength; -+ len -= mblength; -+ } -+ -+ if (len == 0) -+ return 0; -+ -+ month = (char *) alloca (len + 1); -+ -+ tmp = (char *) alloca (len + 1); -+ memcpy (tmp, s, len); -+ tmp[len] = '\0'; -+ pp = (const char **)&tmp; -+ month_wcs = (wchar_t *) alloca ((len + 1) * sizeof (wchar_t)); -+ memset (&state, '\0', sizeof(mbstate_t)); -+ -+ wclength = mbsrtowcs (month_wcs, pp, len + 1, &state); -+ assert (wclength != (size_t)-1 && *pp == NULL); -+ -+ for (i = 0; i < wclength; i++) -+ { -+ month_wcs[i] = towupper(month_wcs[i]); -+ if (iswblank (month_wcs[i])) -+ { -+ month_wcs[i] = L'\0'; -+ break; -+ } -+ } -+ -+ wpp = (const wchar_t **)&month_wcs; -+ -+ mblength = wcsrtombs (month, wpp, len + 1, &state); -+ assert (mblength != (-1) && *wpp == NULL); -+ -+ do -+ { -+ int ix = (lo + hi) / 2; -+ -+ if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0) -+ hi = ix; -+ else -+ lo = ix; -+ } -+ while (hi - lo > 1); -+ -+ result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name)) -+ ? monthtab[lo].val : 0); -+ -+ return result; -+} -+#endif -+ - /* Compare two lines A and B trying every key in sequence until there - are no more keys or a difference is found. */ - - static int --keycompare (const struct line *a, const struct line *b) -+keycompare_uni (const struct line *a, const struct line *b) - { - struct keyfield const *key = keylist; - -@@ -1326,6 +1716,177 @@ - return key->reverse ? -diff : diff; - } - -+#if HAVE_MBRTOWC -+static int -+keycompare_mb (const struct line *a, const struct line *b) -+{ -+ struct keyfield *key = keylist; -+ -+ /* For the first iteration only, the key positions have been -+ precomputed for us. */ -+ char *texta = a->keybeg; -+ char *textb = b->keybeg; -+ char *lima = a->keylim; -+ char *limb = b->keylim; -+ -+ size_t mblength_a, mblength_b; -+ wchar_t wc_a, wc_b; -+ mbstate_t state_a, state_b; -+ -+ int diff; -+ -+ memset (&state_a, '\0', sizeof(mbstate_t)); -+ memset (&state_b, '\0', sizeof(mbstate_t)); -+ -+ for (;;) -+ { -+ unsigned char *translate = (unsigned char *) key->translate; -+ bool const *ignore = key->ignore; -+ -+ /* Find the lengths. */ -+ size_t lena = lima <= texta ? 0 : lima - texta; -+ size_t lenb = limb <= textb ? 0 : limb - textb; -+ -+ /* Actually compare the fields. */ -+ if (key->numeric | key->general_numeric) -+ { -+ char savea = *lima, saveb = *limb; -+ -+ *lima = *limb = '\0'; -+ if (force_general_numcompare) -+ diff = general_numcompare (texta, textb); -+ else -+ diff = ((key->numeric ? numcompare : general_numcompare) -+ (texta, textb)); -+ *lima = savea, *limb = saveb; -+ } -+ else if (key->month) -+ diff = getmonth (texta, lena) - getmonth (textb, lenb); -+ else -+ { -+ if (ignore || translate) -+ { -+ char *copy_a = (char *) alloca (lena + 1 + lenb + 1); -+ char *copy_b = copy_a + lena + 1; -+ size_t new_len_a, new_len_b; -+ size_t i, j; -+ -+ /* Ignore and/or translate chars before comparing. */ -+# define IGNORE_CHARS(NEW_LEN, LEN, TEXT, COPY, WC, MBLENGTH, STATE) \ -+ do \ -+ { \ -+ wchar_t uwc; \ -+ char mbc[MB_LEN_MAX]; \ -+ mbstate_t state_wc; \ -+ \ -+ for (NEW_LEN = i = 0; i < LEN;) \ -+ { \ -+ mbstate_t state_bak; \ -+ \ -+ state_bak = STATE; \ -+ MBLENGTH = mbrtowc (&WC, TEXT + i, LEN - i, &STATE); \ -+ \ -+ if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1 \ -+ || MBLENGTH == 0) \ -+ { \ -+ if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1) \ -+ STATE = state_bak; \ -+ if (!ignore) \ -+ COPY[NEW_LEN++] = TEXT[i++]; \ -+ continue; \ -+ } \ -+ \ -+ if (ignore) \ -+ { \ -+ if ((ignore == nonprinting && !iswprint (WC)) \ -+ || (ignore == nondictionary \ -+ && !iswalnum (WC) && !iswblank (WC))) \ -+ { \ -+ i += MBLENGTH; \ -+ continue; \ -+ } \ -+ } \ -+ \ -+ if (translate) \ -+ { \ -+ \ -+ uwc = towupper(WC); \ -+ if (WC == uwc) \ -+ { \ -+ memcpy (mbc, TEXT + i, MBLENGTH); \ -+ i += MBLENGTH; \ -+ } \ -+ else \ -+ { \ -+ i += MBLENGTH; \ -+ WC = uwc; \ -+ memset (&state_wc, '\0', sizeof (mbstate_t)); \ -+ \ -+ MBLENGTH = wcrtomb (mbc, WC, &state_wc); \ -+ assert (MBLENGTH != (size_t)-1 && MBLENGTH != 0); \ -+ } \ -+ \ -+ for (j = 0; j < MBLENGTH; j++) \ -+ COPY[NEW_LEN++] = mbc[j]; \ -+ } \ -+ else \ -+ for (j = 0; j < MBLENGTH; j++) \ -+ COPY[NEW_LEN++] = TEXT[i++]; \ -+ } \ -+ COPY[NEW_LEN] = '\0'; \ -+ } \ -+ while (0) -+ IGNORE_CHARS (new_len_a, lena, texta, copy_a, -+ wc_a, mblength_a, state_a); -+ IGNORE_CHARS (new_len_b, lenb, textb, copy_b, -+ wc_b, mblength_b, state_b); -+ diff = xmemcoll (copy_a, new_len_a, copy_b, new_len_b); -+ } -+ else if (lena == 0) -+ diff = - NONZERO (lenb); -+ else if (lenb == 0) -+ goto greater; -+ else -+ diff = xmemcoll (texta, lena, textb, lenb); -+ } -+ -+ if (diff) -+ goto not_equal; -+ -+ key = key->next; -+ if (! key) -+ break; -+ -+ /* Find the beginning and limit of the next field. */ -+ if (key->eword != -1) -+ lima = limfield (a, key), limb = limfield (b, key); -+ else -+ lima = a->text + a->length - 1, limb = b->text + b->length - 1; -+ -+ if (key->sword != -1) -+ texta = begfield (a, key), textb = begfield (b, key); -+ else -+ { -+ texta = a->text, textb = b->text; -+ if (key->skipsblanks) -+ { -+ while (texta < lima && ismbblank (texta, lima - texta, &mblength_a)) -+ texta += mblength_a; -+ while (textb < limb && ismbblank (textb, limb - textb, &mblength_b)) -+ textb += mblength_b; -+ } -+ } -+ } -+ -+ return 0; -+ -+greater: -+ diff = 1; -+not_equal: -+ return key->reverse ? -diff : diff; -+} -+#endif -+ - /* Compare two lines A and B, returning negative, zero, or positive - depending on whether A compares less than, equal to, or greater than B. */ - -@@ -2127,7 +2688,7 @@ - atexit (close_stdout); - - hard_LC_COLLATE = hard_locale (LC_COLLATE); --#if HAVE_NL_LANGINFO -+#if HAVE_LANGINFO_CODESET - hard_LC_TIME = hard_locale (LC_TIME); - #endif - -@@ -2148,6 +2709,27 @@ - thousands_sep = -1; - } - -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ inittables = inittables_mb; -+ begfield = begfield_mb; -+ limfield = limfield_mb; -+ getmonth = getmonth_mb; -+ keycompare = keycompare_mb; -+ numcompare = numcompare_mb; -+ } -+ else -+#endif -+ { -+ inittables = inittables_uni; -+ begfield = begfield_uni; -+ limfield = limfield_uni; -+ getmonth = getmonth_uni; -+ keycompare = keycompare_uni; -+ numcompare = numcompare_uni; -+ } -+ - have_read_stdin = false; - inittables (); - -@@ -2349,13 +2931,35 @@ - - case 't': - { -- char newtab = optarg[0]; -- if (! newtab) -+ char newtab[MB_LEN_MAX + 1]; -+ size_t newtab_length = 1; -+ strncpy (newtab, optarg, MB_LEN_MAX); -+ if (! newtab[0]) - error (SORT_FAILURE, 0, _("empty tab")); -- if (optarg[1]) -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ wchar_t wc; -+ mbstate_t state; -+ size_t i; -+ -+ memset (&state, '\0', sizeof (mbstate_t)); -+ newtab_length = mbrtowc (&wc, newtab, strnlen (newtab, -+ MB_LEN_MAX), -+ &state); -+ switch (newtab_length) -+ { -+ case (size_t) -1: -+ case (size_t) -2: -+ case 0: -+ newtab_length = 1; -+ } -+ } -+#endif -+ if (newtab_length == 1 && optarg[1]) - { - if (STREQ (optarg, "\\0")) -- newtab = '\0'; -+ newtab[0] = '\0'; - else - { - /* Provoke with `sort -txx'. Complain about -@@ -2366,9 +2970,12 @@ - quote (optarg)); - } - } -- if (tab != TAB_DEFAULT && tab != newtab) -+ if (tab_length -+ && (tab_length != newtab_length -+ || memcmp (tab, newtab, tab_length) != 0)) - error (SORT_FAILURE, 0, _("incompatible tabs")); -- tab = newtab; -+ memcpy (tab, newtab, newtab_length); -+ tab_length = newtab_length; - } - break; - ---- coreutils-5.95/src/uniq.c.i18n 2005-07-05 07:32:54.000000000 +0100 -+++ coreutils-5.95/src/uniq.c 2006-05-15 15:08:57.000000000 +0100 -@@ -23,6 +23,16 @@ - #include - #include - -+/* Get mbstate_t, mbrtowc(). */ -+#if HAVE_WCHAR_H -+# include -+#endif -+ -+/* Get isw* functions. */ -+#if HAVE_WCTYPE_H -+# include -+#endif -+ - #include "system.h" - #include "argmatch.h" - #include "linebuffer.h" -@@ -32,7 +42,19 @@ - #include "quote.h" - #include "xmemcoll.h" - #include "xstrtol.h" --#include "memcasecmp.h" -+#include "xmemcoll.h" -+ -+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC -+ installation; work around this configuration error. */ -+#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 -+# define MB_LEN_MAX 16 -+#endif -+ -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ -+#if HAVE_MBRTOWC && defined mbstate_t -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) -+#endif -+ - - /* The official name of this program (e.g., no `g' prefix). */ - #define PROGRAM_NAME "uniq" -@@ -109,6 +131,10 @@ - /* Select whether/how to delimit groups of duplicate lines. */ - static enum delimit_method delimit_groups; - -+/* Function pointers. */ -+static char * -+(*find_field) (struct linebuffer *line); -+ - static struct option const longopts[] = - { - {"count", no_argument, NULL, 'c'}, -@@ -189,7 +215,7 @@ - return a pointer to the beginning of the line's field to be compared. */ - - static char * --find_field (const struct linebuffer *line) -+find_field_uni (struct linebuffer *line) - { - size_t count; - char *lp = line->buffer; -@@ -210,6 +236,83 @@ - return lp + i; - } - -+#if HAVE_MBRTOWC -+ -+# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL) \ -+ do \ -+ { \ -+ mbstate_t state_bak; \ -+ \ -+ CONVFAIL = 0; \ -+ state_bak = *STATEP; \ -+ \ -+ MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP); \ -+ \ -+ switch (MBLENGTH) \ -+ { \ -+ case (size_t)-2: \ -+ case (size_t)-1: \ -+ *STATEP = state_bak; \ -+ CONVFAIL++; \ -+ /* Fall through */ \ -+ case 0: \ -+ MBLENGTH = 1; \ -+ } \ -+ } \ -+ while (0) -+ -+static char * -+find_field_multi (struct linebuffer *line) -+{ -+ size_t count; -+ char *lp = line->buffer; -+ size_t size = line->length - 1; -+ size_t pos; -+ size_t mblength; -+ wchar_t wc; -+ mbstate_t *statep; -+ int convfail; -+ -+ pos = 0; -+ statep = &(line->state); -+ -+ /* skip fields. */ -+ for (count = 0; count < skip_fields && pos < size; count++) -+ { -+ while (pos < size) -+ { -+ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); -+ -+ if (convfail || !iswblank (wc)) -+ { -+ pos += mblength; -+ break; -+ } -+ pos += mblength; -+ } -+ -+ while (pos < size) -+ { -+ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); -+ -+ if (!convfail && iswblank (wc)) -+ break; -+ -+ pos += mblength; -+ } -+ } -+ -+ /* skip fields. */ -+ for (count = 0; count < skip_chars && pos < size; count++) -+ { -+ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); -+ pos += mblength; -+ } -+ -+ return lp + pos; -+} -+#endif -+ - /* Return false if two strings OLD and NEW match, true if not. - OLD and NEW point not to the beginnings of the lines - but rather to the beginnings of the fields to compare. -@@ -218,6 +321,8 @@ - static bool - different (char *old, char *new, size_t oldlen, size_t newlen) - { -+ char *copy_old, *copy_new; -+ - if (check_chars < oldlen) - oldlen = check_chars; - if (check_chars < newlen) -@@ -225,14 +330,92 @@ - - if (ignore_case) - { -- /* FIXME: This should invoke strcoll somehow. */ -- return oldlen != newlen || memcasecmp (old, new, oldlen); -+ size_t i; -+ -+ copy_old = alloca (oldlen + 1); -+ copy_new = alloca (oldlen + 1); -+ -+ for (i = 0; i < oldlen; i++) -+ { -+ copy_old[i] = toupper (old[i]); -+ copy_new[i] = toupper (new[i]); -+ } - } -- else if (hard_LC_COLLATE) -- return xmemcoll (old, oldlen, new, newlen) != 0; - else -- return oldlen != newlen || memcmp (old, new, oldlen); -+ { -+ copy_old = (char *)old; -+ copy_new = (char *)new; -+ } -+ -+ return xmemcoll (copy_old, oldlen, copy_new, newlen); -+} -+ -+#if HAVE_MBRTOWC -+static int -+different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate) -+{ -+ size_t i, j, chars; -+ const char *str[2]; -+ char *copy[2]; -+ size_t len[2]; -+ mbstate_t state[2]; -+ size_t mblength; -+ wchar_t wc, uwc; -+ mbstate_t state_bak; -+ -+ str[0] = old; -+ str[1] = new; -+ len[0] = oldlen; -+ len[1] = newlen; -+ state[0] = oldstate; -+ state[1] = newstate; -+ -+ for (i = 0; i < 2; i++) -+ { -+ copy[i] = alloca (len[i] + 1); -+ -+ for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++) -+ { -+ state_bak = state[i]; -+ mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i])); -+ -+ switch (mblength) -+ { -+ case (size_t)-1: -+ case (size_t)-2: -+ state[i] = state_bak; -+ /* Fall through */ -+ case 0: -+ mblength = 1; -+ break; -+ -+ default: -+ if (ignore_case) -+ { -+ uwc = towupper (wc); -+ -+ if (uwc != wc) -+ { -+ mbstate_t state_wc; -+ -+ memset (&state_wc, '\0', sizeof(mbstate_t)); -+ wcrtomb (copy[i] + j, uwc, &state_wc); -+ } -+ else -+ memcpy (copy[i] + j, str[i] + j, mblength); -+ } -+ else -+ memcpy (copy[i] + j, str[i] + j, mblength); -+ } -+ j += mblength; -+ } -+ copy[i][j] = '\0'; -+ len[i] = j; -+ } -+ -+ return xmemcoll (copy[0], len[0], copy[1], len[1]); - } -+#endif - - /* Output the line in linebuffer LINE to standard output - provided that the switches say it should be output. -@@ -286,15 +469,43 @@ - { - char *prevfield IF_LINT (= NULL); - size_t prevlen IF_LINT (= 0); -+#if HAVE_MBRTOWC -+ mbstate_t prevstate; -+ -+ memset (&prevstate, '\0', sizeof (mbstate_t)); -+#endif - - while (!feof (stdin)) - { - char *thisfield; - size_t thislen; -+#if HAVE_MBRTOWC -+ mbstate_t thisstate; -+#endif -+ - if (readlinebuffer (thisline, stdin) == 0) - break; - thisfield = find_field (thisline); - thislen = thisline->length - 1 - (thisfield - thisline->buffer); -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ thisstate = thisline->state; -+ -+ if (prevline->length == 0 || different_multi -+ (thisfield, prevfield, thislen, prevlen, thisstate, prevstate)) -+ { -+ fwrite (thisline->buffer, sizeof (char), -+ thisline->length, stdout); -+ -+ SWAP_LINES (prevline, thisline); -+ prevfield = thisfield; -+ prevlen = thislen; -+ prevstate = thisstate; -+ } -+ } -+ else -+#endif - if (prevline->length == 0 - || different (thisfield, prevfield, thislen, prevlen)) - { -@@ -313,17 +524,26 @@ - size_t prevlen; - uintmax_t match_count = 0; - bool first_delimiter = true; -+#if HAVE_MBRTOWC -+ mbstate_t prevstate; -+#endif - - if (readlinebuffer (prevline, stdin) == 0) - goto closefiles; - prevfield = find_field (prevline); - prevlen = prevline->length - 1 - (prevfield - prevline->buffer); -+#if HAVE_MBRTOWC -+ prevstate = prevline->state; -+#endif - - while (!feof (stdin)) - { - bool match; - char *thisfield; - size_t thislen; -+#if HAVE_MBRTOWC -+ mbstate_t thisstate; -+#endif - if (readlinebuffer (thisline, stdin) == 0) - { - if (ferror (stdin)) -@@ -332,6 +552,15 @@ - } - thisfield = find_field (thisline); - thislen = thisline->length - 1 - (thisfield - thisline->buffer); -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ thisstate = thisline->state; -+ match = !different_multi (thisfield, prevfield, -+ thislen, prevlen, thisstate, prevstate); -+ } -+ else -+#endif - match = !different (thisfield, prevfield, thislen, prevlen); - match_count += match; - -@@ -364,6 +593,9 @@ - SWAP_LINES (prevline, thisline); - prevfield = thisfield; - prevlen = thislen; -+#if HAVE_MBRTOWC -+ prevstate = thisstate; -+#endif - if (!match) - match_count = 0; - } -@@ -408,6 +640,19 @@ - - atexit (close_stdout); - -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ find_field = find_field_multi; -+ } -+ else -+#endif -+ { -+ find_field = find_field_uni; -+ } -+ -+ -+ - skip_chars = 0; - skip_fields = 0; - check_chars = SIZE_MAX; ---- coreutils-5.95/src/unexpand.c.i18n 2005-08-12 08:16:25.000000000 +0100 -+++ coreutils-5.95/src/unexpand.c 2006-05-15 15:08:57.000000000 +0100 -@@ -39,11 +39,28 @@ - #include - #include - #include -+ -+/* Get mbstate_t, mbrtowc(), wcwidth(). */ -+#if HAVE_WCHAR_H -+# include -+#endif -+ - #include "system.h" - #include "error.h" - #include "quote.h" - #include "xstrndup.h" - -+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC -+ installation; work around this configuration error. */ -+#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 -+# define MB_LEN_MAX 16 -+#endif -+ -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ -+#if HAVE_MBRTOWC && defined mbstate_t -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) -+#endif -+ - /* The official name of this program (e.g., no `g' prefix). */ - #define PROGRAM_NAME "unexpand" - -@@ -110,6 +127,208 @@ - {NULL, 0, NULL, 0} - }; - -+static FILE *next_file (FILE *fp); -+ -+#if HAVE_MBRTOWC -+static void -+unexpand_multibyte (void) -+{ -+ FILE *fp; /* Input stream. */ -+ mbstate_t i_state; /* Current shift state of the input stream. */ -+ mbstate_t i_state_bak; /* Back up the I_STATE. */ -+ mbstate_t o_state; /* Current shift state of the output stream. */ -+ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ -+ char *bufpos; /* Next read position of BUF. */ -+ size_t buflen = 0; /* The length of the byte sequence in buf. */ -+ wint_t wc; /* A gotten wide character. */ -+ size_t mblength; /* The byte size of a multibyte character -+ which shows as same character as WC. */ -+ -+ /* Index in `tab_list' of next tabstop: */ -+ int tab_index = 0; /* For calculating width of pending tabs. */ -+ int print_tab_index = 0; /* For printing as many tabs as possible. */ -+ unsigned int column = 0; /* Column on screen of next char. */ -+ int next_tab_column; /* Column the next tab stop is on. */ -+ int convert = 1; /* If nonzero, perform translations. */ -+ unsigned int pending = 0; /* Pending columns of blanks. */ -+ -+ fp = next_file ((FILE *) NULL); -+ if (fp == NULL) -+ return; -+ -+ memset (&o_state, '\0', sizeof(mbstate_t)); -+ memset (&i_state, '\0', sizeof(mbstate_t)); -+ -+ for (;;) -+ { -+ if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp)) -+ { -+ memmove (buf, bufpos, buflen); -+ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp); -+ bufpos = buf; -+ } -+ -+ /* Get a wide character. */ -+ if (buflen < 1) -+ { -+ mblength = 1; -+ wc = WEOF; -+ } -+ else -+ { -+ i_state_bak = i_state; -+ mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &i_state); -+ } -+ -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ i_state = i_state_bak; -+ wc = L'\0'; -+ } -+ -+ if (wc == L' ' && convert && column < INT_MAX) -+ { -+ ++pending; -+ ++column; -+ } -+ else if (wc == L'\t' && convert) -+ { -+ if (tab_size == 0) -+ { -+ /* Do not let tab_index == first_free_tab; -+ stop when it is 1 less. */ -+ while (tab_index < first_free_tab - 1 -+ && column >= tab_list[tab_index]) -+ tab_index++; -+ next_tab_column = tab_list[tab_index]; -+ if (tab_index < first_free_tab - 1) -+ tab_index++; -+ if (column >= next_tab_column) -+ { -+ convert = 0; /* Ran out of tab stops. */ -+ goto flush_pend_mb; -+ } -+ } -+ else -+ { -+ next_tab_column = column + tab_size - column % tab_size; -+ } -+ pending += next_tab_column - column; -+ column = next_tab_column; -+ } -+ else -+ { -+flush_pend_mb: -+ /* Flush pending spaces. Print as many tabs as possible, -+ then print the rest as spaces. */ -+ if (pending == 1) -+ { -+ putchar (' '); -+ pending = 0; -+ } -+ column -= pending; -+ while (pending > 0) -+ { -+ if (tab_size == 0) -+ { -+ /* Do not let print_tab_index == first_free_tab; -+ stop when it is 1 less. */ -+ while (print_tab_index < first_free_tab - 1 -+ && column >= tab_list[print_tab_index]) -+ print_tab_index++; -+ next_tab_column = tab_list[print_tab_index]; -+ if (print_tab_index < first_free_tab - 1) -+ print_tab_index++; -+ } -+ else -+ { -+ next_tab_column = -+ column + tab_size - column % tab_size; -+ } -+ if (next_tab_column - column <= pending) -+ { -+ putchar ('\t'); -+ pending -= next_tab_column - column; -+ column = next_tab_column; -+ } -+ else -+ { -+ --print_tab_index; -+ column += pending; -+ while (pending != 0) -+ { -+ putchar (' '); -+ pending--; -+ } -+ } -+ } -+ -+ if (wc == WEOF) -+ { -+ fp = next_file (fp); -+ if (fp == NULL) -+ break; /* No more files. */ -+ else -+ { -+ memset (&i_state, '\0', sizeof(mbstate_t)); -+ continue; -+ } -+ } -+ -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ if (convert) -+ { -+ ++column; -+ if (convert_entire_line == 0) -+ convert = 0; -+ } -+ mblength = 1; -+ putchar (buf[0]); -+ } -+ else if (mblength == 0) -+ { -+ if (convert && convert_entire_line == 0) -+ convert = 0; -+ mblength = 1; -+ putchar ('\0'); -+ } -+ else -+ { -+ if (convert) -+ { -+ if (wc == L'\b') -+ { -+ if (column > 0) -+ --column; -+ } -+ else -+ { -+ int width; /* The width of WC. */ -+ -+ width = wcwidth (wc); -+ column += (width > 0) ? width : 0; -+ if (convert_entire_line == 0) -+ convert = 0; -+ } -+ } -+ -+ if (wc == L'\n') -+ { -+ tab_index = print_tab_index = 0; -+ column = pending = 0; -+ convert = 1; -+ } -+ fwrite (bufpos, sizeof(char), mblength, stdout); -+ } -+ } -+ buflen -= mblength; -+ bufpos += mblength; -+ } -+} -+#endif -+ -+ - void - usage (int status) - { -@@ -532,7 +751,12 @@ - - file_list = (optind < argc ? &argv[optind] : stdin_argv); - -- unexpand (); -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ unexpand_multibyte (); -+ else -+#endif -+ unexpand (); - - if (have_read_stdin && fclose (stdin) != 0) - error (EXIT_FAILURE, errno, "-"); ---- coreutils-5.95/src/fold.c.i18n 2005-08-12 08:29:38.000000000 +0100 -+++ coreutils-5.95/src/fold.c 2006-05-15 15:08:57.000000000 +0100 -@@ -23,11 +23,33 @@ - #include - #include - -+/* Get mbstate_t, mbrtowc(), wcwidth(). */ -+#if HAVE_WCHAR_H -+# include -+#endif -+ -+/* Get iswprint(), iswblank(), wcwidth(). */ -+#if HAVE_WCTYPE_H -+# include -+#endif -+ - #include "system.h" - #include "error.h" - #include "quote.h" - #include "xstrtol.h" - -+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC -+ installation; work around this configuration error. */ -+#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 -+# undef MB_LEN_MAX -+# define MB_LEN_MAX 16 -+#endif -+ -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ -+#if HAVE_MBRTOWC && defined mbstate_t -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) -+#endif -+ - #define TAB_WIDTH 8 - - /* The official name of this program (e.g., no `g' prefix). */ -@@ -35,23 +57,44 @@ - - #define AUTHORS "David MacKenzie" - -+#define FATAL_ERROR(Message) \ -+ do \ -+ { \ -+ error (0, 0, (Message)); \ -+ usage (2); \ -+ } \ -+ while (0) -+ -+enum operating_mode -+{ -+ /* Fold texts by columns that are at the given positions. */ -+ column_mode, -+ -+ /* Fold texts by bytes that are at the given positions. */ -+ byte_mode, -+ -+ /* Fold texts by characters that are at the given positions. */ -+ character_mode, -+}; -+ - /* The name this program was run with. */ - char *program_name; - -+/* The argument shows current mode. (Default: column_mode) */ -+static enum operating_mode operating_mode; -+ - /* If nonzero, try to break on whitespace. */ - static bool break_spaces; - --/* If nonzero, count bytes, not column positions. */ --static bool count_bytes; -- - /* If nonzero, at least one of the files we read was standard input. */ - static bool have_read_stdin; - --static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::"; -+static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::"; - - static struct option const longopts[] = - { - {"bytes", no_argument, NULL, 'b'}, -+ {"characters", no_argument, NULL, 'c'}, - {"spaces", no_argument, NULL, 's'}, - {"width", required_argument, NULL, 'w'}, - {GETOPT_HELP_OPTION_DECL}, -@@ -81,6 +124,7 @@ - "), stdout); - fputs (_("\ - -b, --bytes count bytes rather than columns\n\ -+ -c, --characters count characters rather than columns\n\ - -s, --spaces break at spaces\n\ - -w, --width=WIDTH use WIDTH columns instead of 80\n\ - "), stdout); -@@ -98,7 +142,7 @@ - static size_t - adjust_column (size_t column, char c) - { -- if (!count_bytes) -+ if (operating_mode != byte_mode) - { - if (c == '\b') - { -@@ -117,35 +161,14 @@ - return column; - } - --/* Fold file FILENAME, or standard input if FILENAME is "-", -- to stdout, with maximum line length WIDTH. -- Return true if successful. */ -- --static bool --fold_file (char *filename, size_t width) -+static void -+fold_text (FILE *istream, size_t width, int *saved_errno) - { -- FILE *istream; - int c; - size_t column = 0; /* Screen column where next char will go. */ - size_t offset_out = 0; /* Index in `line_out' for next char. */ - static char *line_out = NULL; - static size_t allocated_out = 0; -- int saved_errno; -- -- if (STREQ (filename, "-")) -- { -- istream = stdin; -- have_read_stdin = true; -- } -- else -- istream = fopen (filename, "r"); -- -- if (istream == NULL) -- { -- error (0, errno, "%s", filename); -- return false; -- } -- - while ((c = getc (istream)) != EOF) - { - if (offset_out + 1 >= allocated_out) -@@ -172,6 +195,15 @@ - bool found_blank = false; - size_t logical_end = offset_out; - -+ /* If LINE_OUT has no wide character, -+ put a new wide character in LINE_OUT -+ if column is bigger than width. */ -+ if (offset_out == 0) -+ { -+ line_out[offset_out++] = c; -+ continue; -+ } -+ - /* Look for the last blank. */ - while (logical_end) - { -@@ -218,11 +250,225 @@ - line_out[offset_out++] = c; - } - -- saved_errno = errno; -+ *saved_errno = errno; -+ -+ if (offset_out) -+ fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); -+ -+ free(line_out); -+} -+ -+#if HAVE_MBRTOWC -+static void -+fold_multibyte_text (FILE *istream, int width, int *saved_errno) -+{ -+ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ -+ size_t buflen = 0; /* The length of the byte sequence in buf. */ -+ char *bufpos; /* Next read position of BUF. */ -+ wint_t wc; /* A gotten wide character. */ -+ size_t mblength; /* The byte size of a multibyte character which shows -+ as same character as WC. */ -+ mbstate_t state, state_bak; /* State of the stream. */ -+ int convfail; /* 1, when conversion is failed. Otherwise 0. */ -+ -+ char *line_out = NULL; -+ size_t offset_out = 0; /* Index in `line_out' for next char. */ -+ size_t allocated_out = 0; -+ -+ int increment; -+ size_t column = 0; -+ -+ size_t last_blank_pos; -+ size_t last_blank_column; -+ int is_blank_seen; -+ int last_blank_increment; -+ int is_bs_following_last_blank; -+ size_t bs_following_last_blank_num; -+ int is_cr_after_last_blank; -+ -+#define CLEAR_FLAGS \ -+ do \ -+ { \ -+ last_blank_pos = 0; \ -+ last_blank_column = 0; \ -+ is_blank_seen = 0; \ -+ is_bs_following_last_blank = 0; \ -+ bs_following_last_blank_num = 0; \ -+ is_cr_after_last_blank = 0; \ -+ } \ -+ while (0) -+ -+#define START_NEW_LINE \ -+ do \ -+ { \ -+ putchar ('\n'); \ -+ column = 0; \ -+ offset_out = 0; \ -+ CLEAR_FLAGS; \ -+ } \ -+ while (0) -+ -+ CLEAR_FLAGS; -+ memset (&state, '\0', sizeof(mbstate_t)); -+ -+ for (;; bufpos += mblength, buflen -= mblength) -+ { -+ if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream)) -+ { -+ memmove (buf, bufpos, buflen); -+ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream); -+ bufpos = buf; -+ } -+ -+ if (buflen < 1) -+ break; -+ -+ /* Get a wide character. */ -+ convfail = 0; -+ state_bak = state; -+ mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state); -+ -+ switch (mblength) -+ { -+ case (size_t)-1: -+ case (size_t)-2: -+ convfail++; -+ state = state_bak; -+ /* Fall through. */ -+ -+ case 0: -+ mblength = 1; -+ break; -+ } -+ -+rescan: -+ if (operating_mode == byte_mode) /* byte mode */ -+ increment = mblength; -+ else if (operating_mode == character_mode) /* character mode */ -+ increment = 1; -+ else /* column mode */ -+ { -+ if (convfail) -+ increment = 1; -+ else -+ { -+ switch (wc) -+ { -+ case L'\n': -+ fwrite (line_out, sizeof(char), offset_out, stdout); -+ START_NEW_LINE; -+ continue; -+ -+ case L'\b': -+ increment = (column > 0) ? -1 : 0; -+ break; -+ -+ case L'\r': -+ increment = -1 * column; -+ break; -+ -+ case L'\t': -+ increment = 8 - column % 8; -+ break; -+ -+ default: -+ increment = wcwidth (wc); -+ increment = (increment < 0) ? 0 : increment; -+ } -+ } -+ } -+ -+ if (column + increment > width && break_spaces && last_blank_pos) -+ { -+ fwrite (line_out, sizeof(char), last_blank_pos, stdout); -+ putchar ('\n'); -+ -+ offset_out = offset_out - last_blank_pos; -+ column = column - last_blank_column + ((is_cr_after_last_blank) -+ ? last_blank_increment : bs_following_last_blank_num); -+ memmove (line_out, line_out + last_blank_pos, offset_out); -+ CLEAR_FLAGS; -+ goto rescan; -+ } -+ -+ if (column + increment > width && column != 0) -+ { -+ fwrite (line_out, sizeof(char), offset_out, stdout); -+ START_NEW_LINE; -+ goto rescan; -+ } -+ -+ if (allocated_out < offset_out + mblength) -+ { -+ allocated_out += 1024; -+ line_out = xrealloc (line_out, allocated_out); -+ } -+ -+ memcpy (line_out + offset_out, bufpos, mblength); -+ offset_out += mblength; -+ column += increment; -+ -+ if (is_blank_seen && !convfail && wc == L'\r') -+ is_cr_after_last_blank = 1; -+ -+ if (is_bs_following_last_blank && !convfail && wc == L'\b') -+ ++bs_following_last_blank_num; -+ else -+ is_bs_following_last_blank = 0; -+ -+ if (break_spaces && !convfail && iswblank (wc)) -+ { -+ last_blank_pos = offset_out; -+ last_blank_column = column; -+ is_blank_seen = 1; -+ last_blank_increment = increment; -+ is_bs_following_last_blank = 1; -+ bs_following_last_blank_num = 0; -+ is_cr_after_last_blank = 0; -+ } -+ } -+ -+ *saved_errno = errno; - - if (offset_out) - fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); - -+ free(line_out); -+} -+#endif -+ -+/* Fold file FILENAME, or standard input if FILENAME is "-", -+ to stdout, with maximum line length WIDTH. -+ Return 0 if successful, 1 if an error occurs. */ -+ -+static int -+fold_file (char *filename, int width) -+{ -+ FILE *istream; -+ int saved_errno; -+ -+ if (STREQ (filename, "-")) -+ { -+ istream = stdin; -+ have_read_stdin = 1; -+ } -+ else -+ istream = fopen (filename, "r"); -+ -+ if (istream == NULL) -+ { -+ error (0, errno, "%s", filename); -+ return 1; -+ } -+ -+ /* Define how ISTREAM is being folded. */ -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ fold_multibyte_text (istream, width, &saved_errno); -+ else -+#endif -+ fold_text (istream, width, &saved_errno); -+ - if (ferror (istream)) - { - error (0, saved_errno, "%s", filename); -@@ -255,7 +501,8 @@ - - atexit (close_stdout); - -- break_spaces = count_bytes = have_read_stdin = false; -+ operating_mode = column_mode; -+ break_spaces = have_read_stdin = false; - - while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) - { -@@ -264,7 +511,15 @@ - switch (optc) - { - case 'b': /* Count bytes rather than columns. */ -- count_bytes = true; -+ if (operating_mode != column_mode) -+ FATAL_ERROR (_("only one way of folding may be specified")); -+ operating_mode = byte_mode; -+ break; -+ -+ case 'c': -+ if (operating_mode != column_mode) -+ FATAL_ERROR (_("only one way of folding may be specified")); -+ operating_mode = character_mode; - break; - - case 's': /* Break at word boundaries. */ ---- coreutils-5.95/src/cut.c.i18n 2005-08-12 08:16:25.000000000 +0100 -+++ coreutils-5.95/src/cut.c 2006-05-15 15:08:57.000000000 +0100 +--- coreutils-6.7/src/cut.c.i18n 2006-11-27 10:25:51.000000000 +0000 ++++ coreutils-6.7/src/cut.c 2007-01-09 17:18:28.000000000 +0000 @@ -29,6 +29,11 @@ #include #include @@ -3468,7 +3598,7 @@ "), stdout); fputs (_("\ --complement complement the set of selected bytes, characters\n\ -@@ -360,7 +437,7 @@ +@@ -362,7 +439,7 @@ in_digits = false; /* Starting a range. */ if (dash_found) @@ -3477,7 +3607,7 @@ dash_found = true; fieldstr++; -@@ -385,14 +462,16 @@ +@@ -387,14 +464,16 @@ if (value == 0) { /* `n-'. From `initial' to end of line. */ @@ -3496,7 +3626,7 @@ /* Is there already a range going to end of line? */ if (eol_range_start != 0) -@@ -465,6 +544,9 @@ +@@ -467,6 +546,9 @@ if (operating_mode == byte_mode) error (0, 0, _("byte offset %s is too large"), quote (bad_num)); @@ -3506,7 +3636,7 @@ else error (0, 0, _("field number %s is too large"), quote (bad_num)); -@@ -475,7 +557,7 @@ +@@ -477,7 +559,7 @@ fieldstr++; } else @@ -3515,7 +3645,7 @@ } max_range_endpoint = 0; -@@ -568,6 +650,63 @@ +@@ -570,6 +652,63 @@ } } @@ -3579,7 +3709,7 @@ /* Read from stream STREAM, printing to standard output any selected fields. */ static void -@@ -689,13 +828,192 @@ +@@ -691,13 +830,192 @@ } } @@ -3775,7 +3905,7 @@ } /* Process file FILE to standard output. -@@ -745,6 +1063,8 @@ +@@ -747,6 +1065,8 @@ bool ok; bool delim_specified = false; char *spec_list_string IF_LINT(= NULL); @@ -3784,7 +3914,7 @@ initialize_main (&argc, &argv); program_name = argv[0]; -@@ -767,7 +1087,6 @@ +@@ -769,7 +1089,6 @@ switch (optc) { case 'b': @@ -3792,7 +3922,7 @@ /* Build the byte list. */ if (operating_mode != undefined_mode) FATAL_ERROR (_("only one type of list may be specified")); -@@ -775,6 +1094,14 @@ +@@ -777,6 +1096,14 @@ spec_list_string = optarg; break; @@ -3807,7 +3937,7 @@ case 'f': /* Build the field list. */ if (operating_mode != undefined_mode) -@@ -786,10 +1113,35 @@ +@@ -788,10 +1115,35 @@ case 'd': /* New delimiter. */ /* Interpret -d '' to mean `use the NUL byte as the delimiter.' */ @@ -3847,7 +3977,7 @@ break; case OUTPUT_DELIMITER_OPTION: -@@ -802,6 +1154,7 @@ +@@ -804,6 +1156,7 @@ break; case 'n': @@ -3855,7 +3985,7 @@ break; case 's': -@@ -824,7 +1177,7 @@ +@@ -826,7 +1179,7 @@ if (operating_mode == undefined_mode) FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); @@ -3864,7 +3994,7 @@ FATAL_ERROR (_("an input delimiter may be specified only\ when operating on fields")); -@@ -851,15 +1204,34 @@ +@@ -853,15 +1206,34 @@ } if (!delim_specified) @@ -3905,302 +4035,3 @@ } if (optind == argc) ---- coreutils-5.95/tests/sort/Makefile.am.i18n 2005-10-24 22:02:25.000000000 +0100 -+++ coreutils-5.95/tests/sort/Makefile.am 2006-05-15 15:08:57.000000000 +0100 -@@ -43,14 +43,16 @@ - nul-nls.E use-nl.O use-nl.E o2.O o2.E nul-tab.O nul-tab.E - ##test-files-end - --EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) --noinst_SCRIPTS = $x-tests -+run_gen += mb1.O mb2.O -+ -+EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) mb1.I mb1.X mb2.I mb2.X -+noinst_SCRIPTS = $x-tests # $x-mb-tests - TESTS_ENVIRONMENT = \ - PATH="`pwd`/../../src$(PATH_SEPARATOR)$$PATH" - - editpl = sed -e 's,@''PERL''@,$(PERL),g' -e 's,@''srcdir''@,$(srcdir),g' - --TESTS = $x-tests -+TESTS = $x-tests $x-mb-tests - - mk_script = $(srcdir)/../mk-script - $(srcdir)/$x-tests: $(mk_script) Test.pm Makefile.am ---- /dev/null 2006-05-15 09:11:19.652773000 +0100 -+++ coreutils-5.95/tests/sort/mb1.I 2006-05-15 15:08:57.000000000 +0100 -@@ -0,0 +1,4 @@ -+Apple@10 -+Banana@5 -+Citrus@20 -+Cherry@30 ---- /dev/null 2006-05-15 09:11:19.652773000 +0100 -+++ coreutils-5.95/tests/sort/mb1.X 2006-05-15 15:08:57.000000000 +0100 -@@ -0,0 +1,4 @@ -+Banana@5 -+Apple@10 -+Citrus@20 -+Cherry@30 ---- /dev/null 2006-05-15 09:11:19.652773000 +0100 -+++ coreutils-5.95/tests/sort/mb2.X 2006-05-15 15:08:57.000000000 +0100 -@@ -0,0 +1,4 @@ -+Citrus@AA20@@5 -+Cherry@AA30@@10 -+Apple@AA10@@20 -+Banana@AA5@@30 ---- /dev/null 2006-05-15 09:11:19.652773000 +0100 -+++ coreutils-5.95/tests/sort/sort-mb-tests 2006-05-15 15:08:57.000000000 +0100 -@@ -0,0 +1,58 @@ -+#! /bin/sh -+case $# in -+ 0) xx='../../src/sort';; -+ *) xx="$1";; -+esac -+test "$VERBOSE" && echo=echo || echo=: -+$echo testing program: $xx -+errors=0 -+test "$srcdir" || srcdir=. -+test "$VERBOSE" && $xx --version 2> /dev/null -+ -+export LC_ALL=en_US.UTF-8 -+locale -k LC_CTYPE 2>&1 | grep -q charmap.*UTF-8 || exit 77 -+errors=0 -+ -+$xx -t @ -k2 -n mb1.I > mb1.O -+code=$? -+if test $code != 0; then -+ $echo "Test mb1 failed: $xx return code $code differs from expected value 0" 1>&2 -+ errors=`expr $errors + 1` -+else -+ cmp mb1.O $srcdir/mb1.X > /dev/null 2>&1 -+ case $? in -+ 0) if test "$VERBOSE"; then $echo "passed mb1"; fi;; -+ 1) $echo "Test mb1 failed: files mb1.O and $srcdir/mb1.X differ" 1>&2 -+ (diff -c mb1.O $srcdir/mb1.X) 2> /dev/null -+ errors=`expr $errors + 1`;; -+ 2) $echo "Test mb1 may have failed." 1>&2 -+ $echo The command "cmp mb1.O $srcdir/mb1.X" failed. 1>&2 -+ errors=`expr $errors + 1`;; -+ esac -+fi -+ -+$xx -t @ -k4 -n mb2.I > mb2.O -+code=$? -+if test $code != 0; then -+ $echo "Test mb2 failed: $xx return code $code differs from expected value 0" 1>&2 -+ errors=`expr $errors + 1` -+else -+ cmp mb2.O $srcdir/mb2.X > /dev/null 2>&1 -+ case $? in -+ 0) if test "$VERBOSE"; then $echo "passed mb2"; fi;; -+ 1) $echo "Test mb2 failed: files mb2.O and $srcdir/mb2.X differ" 1>&2 -+ (diff -c mb2.O $srcdir/mb2.X) 2> /dev/null -+ errors=`expr $errors + 1`;; -+ 2) $echo "Test mb2 may have failed." 1>&2 -+ $echo The command "cmp mb2.O $srcdir/mb2.X" failed. 1>&2 -+ errors=`expr $errors + 1`;; -+ esac -+fi -+ -+if test $errors = 0; then -+ $echo Passed all 113 tests. 1>&2 -+else -+ $echo Failed $errors tests. 1>&2 -+fi -+test $errors = 0 || errors=1 -+exit $errors ---- coreutils-5.95/tests/sort/Makefile.in.i18n 2006-05-04 13:52:51.000000000 +0100 -+++ coreutils-5.95/tests/sort/Makefile.in 2006-05-15 15:08:57.000000000 +0100 -@@ -107,25 +107,25 @@ - $(top_srcdir)/m4/onceonly_2_57.m4 $(top_srcdir)/m4/openat.m4 \ - $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/perl.m4 \ - $(top_srcdir)/m4/physmem.m4 $(top_srcdir)/m4/po.m4 \ -- $(top_srcdir)/m4/posixtm.m4 $(top_srcdir)/m4/posixver.m4 \ -- $(top_srcdir)/m4/prereq.m4 $(top_srcdir)/m4/progtest.m4 \ -- $(top_srcdir)/m4/putenv.m4 $(top_srcdir)/m4/quote.m4 \ -- $(top_srcdir)/m4/quotearg.m4 $(top_srcdir)/m4/readlink.m4 \ -- $(top_srcdir)/m4/readtokens.m4 $(top_srcdir)/m4/readutmp.m4 \ -- $(top_srcdir)/m4/regex.m4 $(top_srcdir)/m4/rename.m4 \ -- $(top_srcdir)/m4/restrict.m4 $(top_srcdir)/m4/rmdir-errno.m4 \ -- $(top_srcdir)/m4/rmdir.m4 $(top_srcdir)/m4/root-dev-ino.m4 \ -- $(top_srcdir)/m4/rpmatch.m4 $(top_srcdir)/m4/safe-read.m4 \ -- $(top_srcdir)/m4/safe-write.m4 $(top_srcdir)/m4/same.m4 \ -- $(top_srcdir)/m4/save-cwd.m4 $(top_srcdir)/m4/savedir.m4 \ -- $(top_srcdir)/m4/setenv.m4 $(top_srcdir)/m4/settime.m4 \ -- $(top_srcdir)/m4/sha1.m4 $(top_srcdir)/m4/sig2str.m4 \ -- $(top_srcdir)/m4/signed.m4 $(top_srcdir)/m4/socklen.m4 \ -- $(top_srcdir)/m4/sockpfaf.m4 $(top_srcdir)/m4/ssize_t.m4 \ -- $(top_srcdir)/m4/st_dm_mode.m4 $(top_srcdir)/m4/stat-macros.m4 \ -- $(top_srcdir)/m4/stat-prog.m4 $(top_srcdir)/m4/stat-time.m4 \ -- $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stdint_h.m4 \ -- $(top_srcdir)/m4/stdio-safer.m4 \ -+ $(top_srcdir)/m4/posix_acl.m4 $(top_srcdir)/m4/posixtm.m4 \ -+ $(top_srcdir)/m4/posixver.m4 $(top_srcdir)/m4/prereq.m4 \ -+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/putenv.m4 \ -+ $(top_srcdir)/m4/quote.m4 $(top_srcdir)/m4/quotearg.m4 \ -+ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/readtokens.m4 \ -+ $(top_srcdir)/m4/readutmp.m4 $(top_srcdir)/m4/regex.m4 \ -+ $(top_srcdir)/m4/rename.m4 $(top_srcdir)/m4/restrict.m4 \ -+ $(top_srcdir)/m4/rmdir-errno.m4 $(top_srcdir)/m4/rmdir.m4 \ -+ $(top_srcdir)/m4/root-dev-ino.m4 $(top_srcdir)/m4/rpmatch.m4 \ -+ $(top_srcdir)/m4/safe-read.m4 $(top_srcdir)/m4/safe-write.m4 \ -+ $(top_srcdir)/m4/same.m4 $(top_srcdir)/m4/save-cwd.m4 \ -+ $(top_srcdir)/m4/savedir.m4 $(top_srcdir)/m4/setenv.m4 \ -+ $(top_srcdir)/m4/settime.m4 $(top_srcdir)/m4/sha1.m4 \ -+ $(top_srcdir)/m4/sig2str.m4 $(top_srcdir)/m4/signed.m4 \ -+ $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/sockpfaf.m4 \ -+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/st_dm_mode.m4 \ -+ $(top_srcdir)/m4/stat-macros.m4 $(top_srcdir)/m4/stat-prog.m4 \ -+ $(top_srcdir)/m4/stat-time.m4 $(top_srcdir)/m4/stdbool.m4 \ -+ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/stdio-safer.m4 \ - $(top_srcdir)/m4/stdlib-safer.m4 $(top_srcdir)/m4/stpcpy.m4 \ - $(top_srcdir)/m4/strcase.m4 $(top_srcdir)/m4/strcspn.m4 \ - $(top_srcdir)/m4/strdup.m4 $(top_srcdir)/m4/strftime.m4 \ -@@ -196,7 +196,6 @@ - GLIBC21 = @GLIBC21@ - GMSGFMT = @GMSGFMT@ - GNU_PACKAGE = @GNU_PACKAGE@ --GREP = @GREP@ - HAVE__BOOL = @HAVE__BOOL@ - HELP2MAN = @HELP2MAN@ - INSTALL_DATA = @INSTALL_DATA@ -@@ -207,6 +206,7 @@ - INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ - KMEM_GROUP = @KMEM_GROUP@ - LDFLAGS = @LDFLAGS@ -+LIBACL = @LIBACL@ - LIBICONV = @LIBICONV@ - LIBINTL = @LIBINTL@ - LIBOBJS = @LIBOBJS@ -@@ -217,6 +217,8 @@ - LIB_FDATASYNC = @LIB_FDATASYNC@ - LIB_GETHRXTIME = @LIB_GETHRXTIME@ - LIB_NANOSLEEP = @LIB_NANOSLEEP@ -+LIB_PAM = @LIB_PAM@ -+LIB_SELINUX = @LIB_SELINUX@ - LN_S = @LN_S@ - LTLIBICONV = @LTLIBICONV@ - LTLIBINTL = @LTLIBINTL@ -@@ -266,30 +268,23 @@ - build_os = @build_os@ - build_vendor = @build_vendor@ - datadir = @datadir@ --datarootdir = @datarootdir@ --docdir = @docdir@ --dvidir = @dvidir@ - exec_prefix = @exec_prefix@ - host = @host@ - host_alias = @host_alias@ - host_cpu = @host_cpu@ - host_os = @host_os@ - host_vendor = @host_vendor@ --htmldir = @htmldir@ - includedir = @includedir@ - infodir = @infodir@ - install_sh = @install_sh@ - libdir = @libdir@ - libexecdir = @libexecdir@ --localedir = @localedir@ - localstatedir = @localstatedir@ - mandir = @mandir@ - mkdir_p = @mkdir_p@ - oldincludedir = @oldincludedir@ --pdfdir = @pdfdir@ - prefix = @prefix@ - program_transform_name = @program_transform_name@ --psdir = @psdir@ - sbindir = @sbindir@ - sharedstatedir = @sharedstatedir@ - sysconfdir = @sysconfdir@ -@@ -316,33 +311,37 @@ - neg-nls.I neg-nls.X nul-nls.I nul-nls.X use-nl.I use-nl.X o2.I o2.X nul-tab.I \ - nul-tab.X - --run_gen = n1.O n1.E n2.O n2.E n3.O n3.E n4.O n4.E n5.O n5.E n6.O n6.E n7.O \ --n7.E n8a.O n8a.E n8b.O n8b.E n9a.O n9a.E n9b.O n9b.E n10a.O n10a.E n10b.O \ --n10b.E n11a.O n11a.E n11b.O n11b.E 01a.O 01a.E 02a.O 02a.E 02b.O 02b.E 02c.O \ --02c.E 02m.O 02m.E 02n.O 02n.E 02o.O 02o.E 02p.O 02p.E 03a.O 03a.E 03b.O 03b.E \ --03c.O 03c.E 03d.O 03d.E 03e.O 03e.E 03f.O 03f.E 03g.O 03g.E 03h.O 03h.E 03i.O \ --03i.E 04a.O 04a.E 04b.O 04b.E 04c.O 04c.E 04d.O 04d.E 04e.O 04e.E 05a.O 05a.E \ --05b.O 05b.E 05c.O 05c.E 05d.O 05d.E 05e.O 05e.E 05f.O 05f.E 06a.O 06a.E 06b.O \ --06b.E 06c.O 06c.E 06d.O 06d.E 06e.O 06e.E 06f.O 06f.E 07a.O 07a.E 07b.O 07b.E \ --07c.O 07c.E 07d.O 07d.E 08a.O 08a.E 08b.O 08b.E 09a.O 09a.E 09b.O 09b.E 09c.O \ --09c.E 09d.O 09d.E 10a.O 10a.E 10b.O 10b.E 10c.O 10c.E 10d.O 10d.E 10a0.O \ --10a0.E 10a1.O 10a1.E 10a2.O 10a2.E 10e.O 10e.E 10f.O 10f.E 10g.O 10g.E 11a.O \ --11a.E 11b.O 11b.E 11c.O 11c.E 11d.O 11d.E 12a.O 12a.E 12b.O 12b.E 12c.O 12c.E \ --12d.O 12d.E 13a.O 13a.E 13b.O 13b.E 14a.O 14a.E 14b.O 14b.E 15a.O 15a.E 15b.O \ --15b.E 15c.O 15c.E 15d.O 15d.E 15e.O 15e.E 16a.O 16a.E 17.O 17.E 18a.O 18a.E \ --18b.O 18b.E 18c.O 18c.E 18d.O 18d.E 18e.O 18e.E 19a.O 19a.E 19b.O 19b.E 20a.O \ --20a.E 21a.O 21a.E 21b.O 21b.E 21c.O 21c.E 21d.O 21d.E 21e.O 21e.E 21f.O 21f.E \ --21g.O 21g.E 22a.O 22a.E 22b.O 22b.E no-file1.O no-file1.E o-no-file1.O \ --o-no-file1.E create-empty.O create-empty.E neg-nls.O neg-nls.E nul-nls.O \ --nul-nls.E use-nl.O use-nl.E o2.O o2.E nul-tab.O nul-tab.E -- --EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) --noinst_SCRIPTS = $x-tests -+run_gen = n1.O n1.E n2.O n2.E n3.O n3.E n4.O n4.E n5.O n5.E n6.O n6.E \ -+ n7.O n7.E n8a.O n8a.E n8b.O n8b.E n9a.O n9a.E n9b.O n9b.E \ -+ n10a.O n10a.E n10b.O n10b.E n11a.O n11a.E n11b.O n11b.E 01a.O \ -+ 01a.E 02a.O 02a.E 02b.O 02b.E 02c.O 02c.E 02m.O 02m.E 02n.O \ -+ 02n.E 02o.O 02o.E 02p.O 02p.E 03a.O 03a.E 03b.O 03b.E 03c.O \ -+ 03c.E 03d.O 03d.E 03e.O 03e.E 03f.O 03f.E 03g.O 03g.E 03h.O \ -+ 03h.E 03i.O 03i.E 04a.O 04a.E 04b.O 04b.E 04c.O 04c.E 04d.O \ -+ 04d.E 04e.O 04e.E 05a.O 05a.E 05b.O 05b.E 05c.O 05c.E 05d.O \ -+ 05d.E 05e.O 05e.E 05f.O 05f.E 06a.O 06a.E 06b.O 06b.E 06c.O \ -+ 06c.E 06d.O 06d.E 06e.O 06e.E 06f.O 06f.E 07a.O 07a.E 07b.O \ -+ 07b.E 07c.O 07c.E 07d.O 07d.E 08a.O 08a.E 08b.O 08b.E 09a.O \ -+ 09a.E 09b.O 09b.E 09c.O 09c.E 09d.O 09d.E 10a.O 10a.E 10b.O \ -+ 10b.E 10c.O 10c.E 10d.O 10d.E 10a0.O 10a0.E 10a1.O 10a1.E \ -+ 10a2.O 10a2.E 10e.O 10e.E 10f.O 10f.E 10g.O 10g.E 11a.O 11a.E \ -+ 11b.O 11b.E 11c.O 11c.E 11d.O 11d.E 12a.O 12a.E 12b.O 12b.E \ -+ 12c.O 12c.E 12d.O 12d.E 13a.O 13a.E 13b.O 13b.E 14a.O 14a.E \ -+ 14b.O 14b.E 15a.O 15a.E 15b.O 15b.E 15c.O 15c.E 15d.O 15d.E \ -+ 15e.O 15e.E 16a.O 16a.E 17.O 17.E 18a.O 18a.E 18b.O 18b.E \ -+ 18c.O 18c.E 18d.O 18d.E 18e.O 18e.E 19a.O 19a.E 19b.O 19b.E \ -+ 20a.O 20a.E 21a.O 21a.E 21b.O 21b.E 21c.O 21c.E 21d.O 21d.E \ -+ 21e.O 21e.E 21f.O 21f.E 21g.O 21g.E 22a.O 22a.E 22b.O 22b.E \ -+ no-file1.O no-file1.E o-no-file1.O o-no-file1.E create-empty.O \ -+ create-empty.E neg-nls.O neg-nls.E nul-nls.O nul-nls.E \ -+ use-nl.O use-nl.E o2.O o2.E nul-tab.O nul-tab.E mb1.O mb2.O -+EXTRA_DIST = Test.pm $x-tests $(explicit) $(maint_gen) mb1.I mb1.X mb2.I mb2.X -+noinst_SCRIPTS = $x-tests # $x-mb-tests - TESTS_ENVIRONMENT = \ - PATH="`pwd`/../../src$(PATH_SEPARATOR)$$PATH" - - editpl = sed -e 's,@''PERL''@,$(PERL),g' -e 's,@''srcdir''@,$(srcdir),g' --TESTS = $x-tests -+TESTS = $x-tests $x-mb-tests - mk_script = $(srcdir)/../mk-script - MAINTAINERCLEANFILES = $x-tests $(maint_gen) - CLEANFILES = $(run_gen) ---- /dev/null 2006-05-15 09:11:19.652773000 +0100 -+++ coreutils-5.95/tests/sort/mb2.I 2006-05-15 15:08:57.000000000 +0100 -@@ -0,0 +1,4 @@ -+Apple@AA10@@20 -+Banana@AA5@@30 -+Citrus@AA20@@5 -+Cherry@AA30@@10 ---- coreutils-5.95/lib/linebuffer.h.i18n 2005-05-14 08:58:06.000000000 +0100 -+++ coreutils-5.95/lib/linebuffer.h 2006-05-15 15:08:57.000000000 +0100 -@@ -22,6 +22,11 @@ - - # include - -+/* Get mbstate_t. */ -+# if HAVE_WCHAR_H -+# include -+# endif -+ - /* A `struct linebuffer' holds a line of text. */ - - struct linebuffer -@@ -29,6 +34,9 @@ - size_t size; /* Allocated. */ - size_t length; /* Used. */ - char *buffer; -+# if HAVE_WCHAR_H -+ mbstate_t state; -+# endif - }; - - /* Initialize linebuffer LINEBUFFER for use. */ diff --git a/coreutils-pam.patch b/coreutils-pam.patch index ad3182e..a0fe36b 100644 --- a/coreutils-pam.patch +++ b/coreutils-pam.patch @@ -1,55 +1,16 @@ ---- coreutils-5.97/doc/coreutils.texi.pam 2006-02-07 08:31:28.000000000 +0000 -+++ coreutils-5.97/doc/coreutils.texi 2006-08-23 10:45:26.000000000 +0100 -@@ -12768,8 +12768,11 @@ - @findex syslog - @command{su} can optionally be compiled to use @code{syslog} to report - failed, and optionally successful, @command{su} attempts. (If the system --supports @code{syslog}.) However, GNU @command{su} does not check if the --user is a member of the @code{wheel} group; see below. -+supports @code{syslog}.) -+ -+This version of @command{su} has support for using PAM for -+authentication. You can edit @file{/etc/pam.d/su} to customize its -+behaviour. +--- coreutils-6.7/src/Makefile.am.pam 2006-11-24 21:28:10.000000000 +0000 ++++ coreutils-6.7/src/Makefile.am 2007-01-09 17:00:01.000000000 +0000 +@@ -103,7 +103,7 @@ + # If necessary, add -lm to resolve use of pow in lib/strtod.c. + uptime_LDADD = $(LDADD) $(POW_LIB) $(GETLOADAVG_LIBS) - The program accepts the following options. Also see @ref{Common options}. +-su_LDADD = $(LDADD) $(LIB_CRYPT) ++su_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@ -@@ -12850,33 +12853,6 @@ - the exit status of the subshell otherwise - @end display - --@cindex wheel group, not supported --@cindex group wheel, not supported --@cindex fascism --@subsection Why GNU @command{su} does not support the @samp{wheel} group -- --(This section is by Richard Stallman.) -- --@cindex Twenex --@cindex MIT AI lab --Sometimes a few of the users try to hold total power over all the --rest. For example, in 1984, a few users at the MIT AI lab decided to --seize power by changing the operator password on the Twenex system and --keeping it secret from everyone else. (I was able to thwart this coup --and give power back to the users by patching the kernel, but I --wouldn't know how to do that in Unix.) -- --However, occasionally the rulers do tell someone. Under the usual --@command{su} mechanism, once someone learns the root password who --sympathizes with the ordinary users, he or she can tell the rest. The --``wheel group'' feature would make this impossible, and thus cement the --power of the rulers. -- --I'm on the side of the masses, not that of the rulers. If you are --used to supporting the bosses and sysadmins in whatever they do, you --might find this idea strange at first. -- -- - @node Process control - @chapter Process control - ---- coreutils-5.97/src/su.c 2006-08-23 10:45:33.000000000 +0100 -+++ coreutils-5.97/src/su.c 2006-08-24 17:04:48.000000000 +0100 + dir_LDADD += $(LIB_ACL) + ls_LDADD += $(LIB_ACL) +--- coreutils-6.7/src/su.c.pam 2007-01-09 17:00:01.000000000 +0000 ++++ coreutils-6.7/src/su.c 2007-01-09 17:16:43.000000000 +0000 @@ -38,6 +38,16 @@ restricts who can su to UID 0 accounts. RMS considers that to be fascist. @@ -64,10 +25,10 @@ + +#endif + - Options: - -, -l, --login Make the subshell a login shell. - Unset all environment variables except -@@ -81,6 +91,15 @@ + Compile-time options: + -DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog. + -DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog. +@@ -59,6 +69,15 @@ prototype (returning `int') in . */ #define getusershell _getusershell_sys_proto_ @@ -81,19 +42,18 @@ +#endif /* USE_PAM */ + #include "system.h" - #include "dirname.h" + #include "getpass.h" -@@ -150,7 +169,9 @@ +@@ -128,15 +147,22 @@ /* The user to become if none is specified. */ #define DEFAULT_USER "root" +#ifndef USE_PAM char *crypt (); +#endif - char *getpass (); char *getusershell (); void endusershell (); -@@ -158,8 +179,13 @@ + void setusershell (); extern char **environ; @@ -108,7 +68,7 @@ /* The name this program was run with. */ char *program_name; -@@ -248,7 +274,26 @@ +@@ -225,7 +251,26 @@ } #endif @@ -135,7 +95,7 @@ Return true if the user gives the correct password for entry PW, false if not. Return true without asking for a password if run by UID 0 or if PW has an empty password. */ -@@ -256,6 +301,44 @@ +@@ -233,6 +278,44 @@ static bool correct_password (const struct passwd *pw) { @@ -180,7 +140,7 @@ char *unencrypted, *encrypted, *correct; #if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP /* Shadow passwd stuff for SVR3 and maybe other systems. */ -@@ -280,6 +363,7 @@ +@@ -257,6 +340,7 @@ encrypted = crypt (unencrypted, correct); memset (unencrypted, 0, strlen (unencrypted)); return STREQ (encrypted, correct); @@ -188,7 +148,7 @@ } /* Update `environ' for the new shell based on PW, with SHELL being -@@ -293,12 +377,18 @@ +@@ -270,12 +354,18 @@ /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. Unset all other environment variables. */ char const *term = getenv ("TERM"); @@ -207,7 +167,7 @@ xsetenv ("HOME", pw->pw_dir); xsetenv ("SHELL", shell); xsetenv ("USER", pw->pw_name); -@@ -331,8 +421,13 @@ +@@ -308,8 +398,13 @@ { #ifdef HAVE_INITGROUPS errno = 0; @@ -222,7 +182,7 @@ endgrent (); #endif if (setgid (pw->pw_gid)) -@@ -341,6 +436,31 @@ +@@ -318,6 +413,31 @@ error (EXIT_FAIL, errno, _("cannot set user id")); } @@ -254,7 +214,7 @@ /* Run SHELL, or DEFAULT_SHELL if SHELL is empty. If COMMAND is nonzero, pass it to the shell with the -c option. Pass ADDITIONAL_ARGS to the shell as more arguments; there -@@ -348,17 +468,49 @@ +@@ -325,17 +445,49 @@ static void run_shell (char const *shell, char const *command, char **additional_args, @@ -302,10 +262,10 @@ + if(chdir(pw->pw_dir)) + error(0, errno, _("warning: cannot change directory to %s"), pw->pw_dir); + - shell_basename = base_name (shell); + shell_basename = last_component (shell); arg0 = xmalloc (strlen (shell_basename) + 2); arg0[0] = '-'; -@@ -383,6 +535,66 @@ +@@ -360,6 +512,66 @@ error (0, errno, "%s", shell); exit (exit_status); } @@ -372,7 +332,9 @@ } /* Return true if SHELL is a restricted shell (one not returned by -@@ -552,7 +764,7 @@ +@@ -527,9 +739,9 @@ + shell = xstrdup (shell ? shell : pw->pw_shell); + modify_environment (pw, shell); +#ifndef USE_PAM change_identity (pw); @@ -383,22 +345,61 @@ - run_shell (shell, command, argv + optind, MAX (0, argc - optind)); + run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw); } ---- coreutils-5.97/src/Makefile.am.pam 2006-08-23 10:45:26.000000000 +0100 -+++ coreutils-5.97/src/Makefile.am 2006-08-23 10:45:26.000000000 +0100 -@@ -92,7 +92,7 @@ +--- coreutils-6.7/doc/coreutils.texi.pam 2006-10-27 15:30:48.000000000 +0100 ++++ coreutils-6.7/doc/coreutils.texi 2007-01-09 17:00:01.000000000 +0000 +@@ -13395,8 +13395,11 @@ + @findex syslog + @command{su} can optionally be compiled to use @code{syslog} to report + failed, and optionally successful, @command{su} attempts. (If the system +-supports @code{syslog}.) However, GNU @command{su} does not check if the +-user is a member of the @code{wheel} group; see below. ++supports @code{syslog}.) ++ ++This version of @command{su} has support for using PAM for ++authentication. You can edit @file{/etc/pam.d/su} to customize its ++behaviour. - uptime_LDADD = $(LDADD) $(GETLOADAVG_LIBS) + The program accepts the following options. Also see @ref{Common options}. --su_LDADD = $(LDADD) $(LIB_CRYPT) -+su_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@ +@@ -13477,33 +13480,6 @@ + the exit status of the subshell otherwise + @end display - $(PROGRAMS): ../lib/libcoreutils.a +-@cindex wheel group, not supported +-@cindex group wheel, not supported +-@cindex fascism +-@subsection Why GNU @command{su} does not support the @samp{wheel} group +- +-(This section is by Richard Stallman.) +- +-@cindex Twenex +-@cindex MIT AI lab +-Sometimes a few of the users try to hold total power over all the +-rest. For example, in 1984, a few users at the MIT AI lab decided to +-seize power by changing the operator password on the Twenex system and +-keeping it secret from everyone else. (I was able to thwart this coup +-and give power back to the users by patching the kernel, but I +-wouldn't know how to do that in Unix.) +- +-However, occasionally the rulers do tell someone. Under the usual +-@command{su} mechanism, once someone learns the root password who +-sympathizes with the ordinary users, he or she can tell the rest. The +-``wheel group'' feature would make this impossible, and thus cement the +-power of the rulers. +- +-I'm on the side of the masses, not that of the rulers. If you are +-used to supporting the bosses and sysadmins in whatever they do, you +-might find this idea strange at first. +- +- + @node Process control + @chapter Process control ---- coreutils-5.97/configure.ac.pam 2006-08-23 10:45:26.000000000 +0100 -+++ coreutils-5.97/configure.ac 2006-08-23 10:45:26.000000000 +0100 -@@ -27,6 +27,13 @@ - AB_INIT() - AM_INIT_AUTOMAKE([1.8.3 gnits dist-bzip2]) +--- coreutils-6.7/configure.ac.pam 2006-12-07 21:30:24.000000000 +0000 ++++ coreutils-6.7/configure.ac 2007-01-09 17:18:04.000000000 +0000 +@@ -39,6 +39,13 @@ + gl_INIT + coreutils_MACROS +dnl Give the chance to enable PAM +AC_ARG_ENABLE(pam, dnl @@ -407,18 +408,6 @@ +LIB_PAM="-ldl -lpam -lpam_misc" +AC_SUBST(LIB_PAM)]) + - gl_DEFAULT_POSIX2_VERSION - gl_USE_SYSTEM_EXTENSIONS - gl_PERL ---- coreutils-5.97/config.hin.pam 2006-08-23 10:45:26.000000000 +0100 -+++ coreutils-5.97/config.hin 2006-08-23 10:45:26.000000000 +0100 -@@ -1537,6 +1537,9 @@ - /* Define if you want access control list support. */ - #undef USE_ACL - -+/* Define if you want to use PAM */ -+#undef USE_PAM -+ - /* Version number of package */ - #undef VERSION - + AC_CHECK_FUNCS(uname, + OPTIONAL_BIN_PROGS="$OPTIONAL_BIN_PROGS uname\$(EXEEXT)" + MAN="$MAN uname.1") diff --git a/coreutils-selinux.patch b/coreutils-selinux.patch index 58d6a53..522d0dc 100644 --- a/coreutils-selinux.patch +++ b/coreutils-selinux.patch @@ -1,5 +1,666 @@ ---- /dev/null 2006-11-23 08:31:37.745607750 +0000 -+++ coreutils-5.97/src/chcon.c 2006-11-17 13:56:55.000000000 +0000 +--- coreutils-6.7/tests/help-version.selinux 2007-01-09 18:24:56.000000000 +0000 ++++ coreutils-6.7/tests/help-version 2007-01-09 18:24:57.000000000 +0000 +@@ -72,6 +72,8 @@ + + # Skip `test'; it doesn't accept --help or --version. + test $i = test && continue; ++ test $i = chcon && continue; ++ test $i = runcon && continue; + + # false fails even when invoked with --help or --version. + if test $i = false; then +@@ -198,7 +200,7 @@ + + for i in $all_programs; do + # Skip these. +- case $i in chroot|stty|tty|false) continue;; esac ++ case $i in chroot|stty|tty|false|chcon|runcon) continue;; esac + + rm -rf $tmp_in $tmp_in2 $tmp_dir $tmp_out + echo > $tmp_in +--- coreutils-6.7/src/ls.c.selinux 2006-11-27 10:25:51.000000000 +0000 ++++ coreutils-6.7/src/ls.c 2007-01-09 18:36:36.000000000 +0000 +@@ -110,6 +110,18 @@ + + #define AUTHORS "Richard Stallman", "David MacKenzie" + ++#ifdef WITH_SELINUX ++#include ++ ++static int print_scontext = 0; ++ ++ ++ ++ ++ ++ ++#endif ++ + #define obstack_chunk_alloc malloc + #define obstack_chunk_free free + +@@ -132,7 +144,8 @@ + symbolic_link, + sock, + whiteout, +- arg_directory ++ arg_directory, ++ command_line + }; + + /* Display letters and indicators for each filetype. +@@ -175,6 +188,10 @@ + /* For long listings, true if the file has an access control list. */ + bool have_acl; + #endif ++ ++#ifdef WITH_SELINUX ++ security_context_t scontext; ++#endif + }; + + #if USE_ACL +@@ -245,6 +262,9 @@ + static void sort_files (void); + static void parse_ls_color (void); + void usage (int status); ++#ifdef WITH_SELINUX ++static void print_scontext_format (const struct fileinfo *f); ++#endif + + /* The name this program was run with. */ + char *program_name; +@@ -353,7 +373,11 @@ + one_per_line, /* -1 */ + many_per_line, /* -C */ + horizontal, /* -x */ +- with_commas /* -m */ ++ with_commas, /* -m */ ++#ifdef WITH_SELINUX ++ security_format, /* -Z */ ++#endif ++ invalid_format + }; + + static enum format format; +@@ -734,6 +758,11 @@ + SHOW_CONTROL_CHARS_OPTION, + SI_OPTION, + SORT_OPTION, ++#ifdef WITH_SELINUX ++ CONTEXT_OPTION, ++ LCONTEXT_OPTION, ++ SCONTEXT_OPTION, ++#endif + TIME_OPTION, + TIME_STYLE_OPTION + }; +@@ -780,6 +809,11 @@ + {"time-style", required_argument, NULL, TIME_STYLE_OPTION}, + {"color", optional_argument, NULL, COLOR_OPTION}, + {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, ++#ifdef WITH_SELINUX ++ {"context", no_argument, 0, CONTEXT_OPTION}, ++ {"lcontext", no_argument, 0, LCONTEXT_OPTION}, ++ {"scontext", no_argument, 0, SCONTEXT_OPTION}, ++#endif + {"author", no_argument, NULL, AUTHOR_OPTION}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, +@@ -789,12 +823,19 @@ + static char const *const format_args[] = + { + "verbose", "long", "commas", "horizontal", "across", +- "vertical", "single-column", NULL ++ "vertical", "single-column", ++#ifdef WITH_SELINUX ++ "context", ++#endif ++ NULL + }; + static enum format const format_types[] = + { + long_format, long_format, with_commas, horizontal, horizontal, + many_per_line, one_per_line ++#ifdef WITH_SELINUX ++ , security_format ++#endif + }; + ARGMATCH_VERIFY (format_args, format_types); + +@@ -1218,6 +1259,9 @@ + + format_needs_stat = sort_type == sort_time || sort_type == sort_size + || format == long_format ++#ifdef WITH_SELINUX ++ || format == security_format || print_scontext ++#endif + || print_block_size; + format_needs_type = (! format_needs_stat + && (recursive +@@ -1248,7 +1292,7 @@ + } + else + do +- gobble_file (argv[i++], unknown, NOT_AN_INODE_NUMBER, true, ""); ++ gobble_file (argv[i++], command_line, NOT_AN_INODE_NUMBER, true, ""); + while (i < argc); + + if (files_index) +@@ -1411,6 +1455,9 @@ + ignore_mode = IGNORE_DEFAULT; + ignore_patterns = NULL; + hide_patterns = NULL; ++#ifdef WITH_SELINUX ++ print_scontext = 0; ++#endif + + /* FIXME: put this in a function. */ + { +@@ -1486,7 +1533,7 @@ + } + + while ((c = getopt_long (argc, argv, +- "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1", ++ "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1Z", + long_options, NULL)) != -1) + { + switch (c) +@@ -1609,6 +1656,13 @@ + format = horizontal; + break; + ++#ifdef WITH_SELINUX ++ case 'Z': ++ ++ print_scontext = 1; ++ format = security_format; ++ break; ++#endif + case 'A': + if (ignore_mode == IGNORE_DEFAULT) + ignore_mode = IGNORE_DOT_AND_DOTDOT; +@@ -1789,6 +1843,25 @@ + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + ++#ifdef WITH_SELINUX ++ ++ case CONTEXT_OPTION: /* new security format */ ++ ++ print_scontext = 1; ++ format = security_format; ++ break; ++ case LCONTEXT_OPTION: /* long format plus security context */ ++ ++ print_scontext = 1; ++ format = long_format; ++ break; ++ case SCONTEXT_OPTION: /* short form of new security format */ ++ ++ print_scontext = 0; ++ format = security_format; ++ break; ++#endif ++ + default: + usage (LS_FAILURE); + } +@@ -2485,6 +2558,12 @@ + { + free (files[i].name); + free (files[i].linkname); ++#ifdef WITH_SELINUX ++ if (files[i].scontext) { ++ freecon (files[i].scontext); ++ files[i].scontext=NULL; ++ } ++#endif + } + + files_index = 0; +@@ -2527,6 +2606,9 @@ + memset (f, '\0', sizeof *f); + f->stat.st_ino = inode; + f->filetype = type; ++#ifdef WITH_SELINUX ++ f->scontext = NULL; ++#endif + + if (command_line_arg + || format_needs_stat +@@ -2574,6 +2656,11 @@ + { + case DEREF_ALWAYS: + err = stat (absolute_name, &f->stat); ++#ifdef WITH_SELINUX ++ if (err>=0) ++ if (format == security_format || print_scontext) ++ getfilecon(absolute_name, &f->scontext); ++#endif + break; + + case DEREF_COMMAND_LINE_ARGUMENTS: +@@ -2582,6 +2669,11 @@ + { + bool need_lstat; + err = stat (absolute_name, &f->stat); ++#ifdef WITH_SELINUX ++ if (err>=0) ++ if (format == security_format || print_scontext) ++ getfilecon(absolute_name, &f->scontext); ++#endif + + if (dereference == DEREF_COMMAND_LINE_ARGUMENTS) + break; +@@ -2600,29 +2692,39 @@ + + default: /* DEREF_NEVER */ + err = lstat (absolute_name, &f->stat); ++#ifdef WITH_SELINUX ++ if (err == 0) ++ if (format == security_format || print_scontext) ++ lgetfilecon(absolute_name, &f->scontext); ++#endif + break; + } + +- if (err != 0) ++ f->stat_ok = (err == 0); ++ if (!f->stat_ok) + { + /* Failure to stat a command line argument leads to + an exit status of 2. For other files, stat failure + provokes an exit status of 1. */ +- file_failure (command_line_arg, +- _("cannot access %s"), absolute_name); +- if (command_line_arg) +- return 0; ++ if (type == command_line) ++ { ++ file_failure (2, _("cannot access %s"), absolute_name); ++ return 0; ++ } + +- f->name = xstrdup (name); ++ f->filetype = type; ++ memset (&f->stat, '\0', sizeof (f->stat)); ++ f->name = xstrdup (absolute_name); + files_index++; +- + return 0; + } + +- f->stat_ok = true; +- + #if USE_ACL +- if (format == long_format) ++ if (format == long_format ++#ifdef WITH_SELINUX ++ || format == security_format ++#endif ++ ) + { + int n = file_has_acl (absolute_name, &f->stat); + f->have_acl = (0 < n); +@@ -3158,6 +3260,16 @@ + DIRED_PUTCHAR ('\n'); + } + break; ++ ++#ifdef WITH_SELINUX ++ case security_format: ++ for (i = 0; i < files_index; i++) ++ { ++ print_scontext_format (files + i); ++ DIRED_PUTCHAR ('\n'); ++ } ++ break; ++#endif + } + } + +@@ -3412,6 +3524,15 @@ + The latter is wrong when nlink_width is zero. */ + p += strlen (p); + ++#ifdef WITH_SELINUX ++ ++ if (print_scontext) ++ { ++ sprintf (p, "%-32s ", f->scontext ? f->scontext : ""); ++ p += strlen (p); ++ } ++#endif ++ + DIRED_INDENT (); + + if (print_owner | print_group | print_author) +@@ -4351,6 +4472,16 @@ + -X sort alphabetically by entry extension\n\ + -1 list one file per line\n\ + "), stdout); ++#ifdef WITH_SELINUX ++printf(_("\nSELINUX options:\n\n\ ++ --lcontext Display security context. Enable -l. Lines\n\ ++ will probably be too wide for most displays.\n\ ++ -Z, --context Display security context so it fits on most\n\ ++ displays. Displays only mode, user, group,\n\ ++ security context and file name.\n\ ++ --scontext Display only security context and file name.\n\ ++\n\n")); ++#endif + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\n\ +@@ -4374,3 +4505,70 @@ + } + exit (status); + } ++ ++#ifdef WITH_SELINUX ++ ++static void ++print_scontext_format (const struct fileinfo *f) ++{ ++ char modebuf[12]; ++ ++ /* 7 fields that may require LONGEST_HUMAN_READABLE bytes, ++ 1 10-byte mode string, ++ 9 spaces, one following each of these fields, and ++ 1 trailing NUL byte. */ ++ ++ char init_bigbuf[7 * LONGEST_HUMAN_READABLE + 10 + 9 + 1]; ++ char *buf = init_bigbuf; ++ size_t bufsize = sizeof (init_bigbuf); ++ size_t s; ++ char *p; ++ const char *fmt; ++ char *user_name; ++ char *group_name; ++ int rv; ++ char *scontext; ++ ++ p = buf; ++ ++ if ( print_scontext ) { /* zero means terse listing */ ++ filemodestring (&f->stat, modebuf); ++ modebuf[10] = (FILE_HAS_ACL (f) ? '+' : ' '); ++ modebuf[11] = '\0'; ++ ++ /* print mode */ ++ ++ (void) sprintf (p, "%s ", modebuf); ++ p += strlen (p); ++ ++ /* print standard user and group */ ++ ++ DIRED_FPUTS (buf, stdout, p - buf); ++ format_user (f->stat.st_uid, owner_width, f->stat_ok); ++ format_group (f->stat.st_gid, group_width, f->stat_ok); ++ p = buf; ++ } ++ ++ (void) sprintf (p, "%-32s ", f->scontext ?: ""); ++ p += strlen (p); ++ ++ DIRED_INDENT (); ++ DIRED_FPUTS (buf, stdout, p - buf); ++ print_name_with_quoting (f->name, f->stat.st_mode, f->linkok, ++ f->stat_ok, f->filetype, &dired_obstack); ++ ++ if (f->filetype == symbolic_link) { ++ if (f->linkname) { ++ DIRED_FPUTS_LITERAL (" -> ", stdout); ++ print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1, ++ f->stat_ok, f->filetype, NULL); ++ if (indicator_style != none) ++ print_type_indicator (f->stat_ok, f->linkmode, f->filetype); ++ } ++ } ++ else { ++ if (indicator_style != none) ++ print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype); ++ } ++} ++#endif +--- coreutils-6.7/src/cp.c.selinux 2006-12-06 11:04:22.000000000 +0000 ++++ coreutils-6.7/src/cp.c 2007-01-09 18:24:57.000000000 +0000 +@@ -51,6 +51,11 @@ + + #define AUTHORS "Torbjorn Granlund", "David MacKenzie", "Jim Meyering" + ++#ifdef WITH_SELINUX ++#include /* for is_selinux_enabled() */ ++int selinux_enabled=0; ++#endif ++ + /* Used by do_copy, make_dir_parents_private, and re_protect + to keep a list of leading directories whose protections + need to be fixed after copying. */ +@@ -141,6 +146,9 @@ + {"target-directory", required_argument, NULL, 't'}, + {"update", no_argument, NULL, 'u'}, + {"verbose", no_argument, NULL, 'v'}, ++#ifdef WITH_SELINUX ++ {"context", required_argument, NULL, 'Z'}, ++#endif + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +@@ -194,6 +202,9 @@ + additional attributes: links, all\n\ + "), stdout); + fputs (_("\ ++ -c same as --preserve=context\n\ ++"), stdout); ++ fputs (_("\ + --no-preserve=ATTR_LIST don't preserve the specified attributes\n\ + --parents use full source file name under DIRECTORY\n\ + "), stdout); +@@ -219,6 +230,7 @@ + destination file is missing\n\ + -v, --verbose explain what is being done\n\ + -x, --one-file-system stay on this file system\n\ ++ -Z, --context=CONTEXT set security context of copy to CONTEXT\n\ + "), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); +@@ -736,6 +748,11 @@ + x->preserve_mode = false; + x->preserve_timestamps = false; + ++#ifdef WITH_SELINUX ++ x->preserve_security_context = false; ++ x->set_security_context = false; ++#endif ++ + x->require_preserve = false; + x->recursive = false; + x->sparse_mode = SPARSE_AUTO; +@@ -763,18 +780,19 @@ + PRESERVE_TIMESTAMPS, + PRESERVE_OWNERSHIP, + PRESERVE_LINK, ++ PRESERVE_CONTEXT, + PRESERVE_ALL + }; + static enum File_attribute const preserve_vals[] = + { + PRESERVE_MODE, PRESERVE_TIMESTAMPS, +- PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_ALL ++ PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_ALL + }; + /* Valid arguments to the `--preserve' option. */ + static char const* const preserve_args[] = + { + "mode", "timestamps", +- "ownership", "links", "all", NULL ++ "ownership", "links", "context", "all", NULL + }; + ARGMATCH_VERIFY (preserve_args, preserve_vals); + +@@ -810,11 +828,16 @@ + x->preserve_links = on_off; + break; + ++ case PRESERVE_CONTEXT: ++ x->preserve_security_context = on_off; ++ break; ++ + case PRESERVE_ALL: + x->preserve_mode = on_off; + x->preserve_timestamps = on_off; + x->preserve_ownership = on_off; + x->preserve_links = on_off; ++ x->preserve_security_context = on_off; + break; + + default: +@@ -839,6 +862,9 @@ + bool copy_contents = false; + char *target_directory = NULL; + bool no_target_directory = false; ++#ifdef WITH_SELINUX ++ selinux_enabled= (is_selinux_enabled()>0); ++#endif + + initialize_main (&argc, &argv); + program_name = argv[0]; +@@ -854,7 +880,11 @@ + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + ++#ifdef WITH_SELINUX ++ while ((c = getopt_long (argc, argv, "abcdfHilLprst:uvxPRS:TZ:", ++#else + while ((c = getopt_long (argc, argv, "abdfHilLprst:uvxPRS:T", ++#endif + long_opts, NULL)) + != -1) + { +@@ -865,12 +895,13 @@ + sparse_type_string, sparse_type); + break; + +- case 'a': /* Like -dpPR. */ ++ case 'a': /* Like -dpPRc. */ + x.dereference = DEREF_NEVER; + x.preserve_links = true; + x.preserve_ownership = true; + x.preserve_mode = true; + x.preserve_timestamps = true; ++ x.preserve_security_context = true; + x.require_preserve = true; + x.recursive = true; + break; +@@ -945,6 +976,36 @@ + case 'R': + x.recursive = true; + break; ++#ifdef WITH_SELINUX ++ case 'c': ++ if ( x.set_security_context ) { ++ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]); ++ exit( 1 ); ++ } ++ else if (selinux_enabled) ++ x.preserve_security_context = true; ++ break; ++ ++ case 'Z': ++ /* politely decline if we're not on a selinux-enabled kernel. */ ++ if( !selinux_enabled ) { ++ fprintf( stderr, "Warning: ignoring --context (-Z). " ++ "It requires a SELinux enabled kernel.\n" ); ++ break; ++ } ++ if ( x.preserve_security_context ) { ++ (void) fprintf(stderr, "%s: cannot force target context to '%s' and preserve it\n", argv[0], optarg); ++ exit( 1 ); ++ } ++ x.set_security_context = true; ++ /* if there's a security_context given set new path ++ components to that context, too */ ++ if ( setfscreatecon(optarg) < 0 ) { ++ (void) fprintf(stderr, _("cannot set default security context %s\n"), optarg); ++ exit( 1 ); ++ } ++ break; ++#endif + + case REPLY_OPTION: /* Deprecated */ + x.interactive = XARGMATCH ("--reply", optarg, +--- coreutils-6.7/src/Makefile.am.selinux 2007-01-09 18:24:56.000000000 +0000 ++++ coreutils-6.7/src/Makefile.am 2007-01-09 18:24:57.000000000 +0000 +@@ -20,14 +20,14 @@ + EXTRA_PROGRAMS = chroot df hostid nice pinky stty su runuser uname uptime users who + + bin_SCRIPTS = groups +-bin_PROGRAMS = [ chgrp chown chmod cp dd dircolors du \ ++bin_PROGRAMS = [ chcon chgrp chown chmod cp dd dircolors du \ + ginstall link ln dir vdir ls mkdir \ + mkfifo mknod mv nohup readlink rm rmdir shred stat sync touch unlink \ + cat cksum comm csplit cut expand fmt fold head join md5sum \ + nl od paste pr ptx sha1sum sha224sum sha256sum sha384sum sha512sum \ + shuf sort split sum tac tail tr tsort unexpand uniq wc \ + basename date dirname echo env expr factor false \ +- hostname id kill logname pathchk printenv printf pwd seq sleep tee \ ++ hostname id kill logname pathchk printenv printf pwd runcon seq sleep tee \ + test true tty whoami yes \ + base64 \ + $(OPTIONAL_BIN_PROGS) $(DF_PROG) +@@ -61,9 +61,9 @@ + LDADD = ../lib/libcoreutils.a $(LIBINTL) ../lib/libcoreutils.a + + # for eaccess in lib/euidaccess.c. +-cp_LDADD = $(LDADD) $(LIB_EACCESS) +-ginstall_LDADD = $(LDADD) $(LIB_EACCESS) +-mv_LDADD = $(LDADD) $(LIB_EACCESS) ++cp_LDADD = $(LDADD) $(LIB_EACCESS) @LIB_SELINUX@ ++ginstall_LDADD = $(LDADD) $(LIB_EACCESS) @LIB_SELINUX@ ++mv_LDADD = $(LDADD) $(LIB_EACCESS) @LIB_SELINUX@ + pathchk_LDADD = $(LDADD) $(LIB_EACCESS) + rm_LDADD = $(LDADD) $(LIB_EACCESS) + test_LDADD = $(LDADD) $(LIB_EACCESS) +@@ -72,12 +72,19 @@ + + # for clock_gettime and fdatasync + dd_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC) +-dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) +-ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) ++dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIB_SELINUX@ ++ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIB_SELINUX@ + pr_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) + shred_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC) + shuf_LDADD = $(LDADD) $(LIB_GETHRXTIME) +-vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) ++vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIB_SELINUX@ ++chcon_LDADD = $(LDADD) @LIB_SELINUX@ ++id_LDADD = $(LDADD) @LIB_SELINUX@ ++mkdir_LDADD = $(LDADD) @LIB_SELINUX@ ++mkfifo_LDADD = $(LDADD) @LIB_SELINUX@ ++mknod_LDADD = $(LDADD) @LIB_SELINUX@ ++stat_LDADD = $(LDADD) @LIB_SELINUX@ ++runcon_LDADD = $(LDADD) @LIB_SELINUX@ + + ## If necessary, add -lm to resolve use of pow in lib/strtod.c. + sort_LDADD = $(LDADD) $(POW_LIB) $(LIB_GETHRXTIME) +--- coreutils-6.7/src/copy.h.selinux 2006-12-06 11:04:22.000000000 +0000 ++++ coreutils-6.7/src/copy.h 2007-01-09 18:24:57.000000000 +0000 +@@ -127,6 +127,10 @@ + bool preserve_ownership; + bool preserve_mode; + bool preserve_timestamps; ++#ifdef WITH_SELINUX ++ bool preserve_security_context; ++ bool set_security_context; ++#endif + + /* Enabled for mv, and for cp by the --preserve=links option. + If true, attempt to preserve in the destination files any +--- /dev/null 2007-01-09 12:27:07.480840763 +0000 ++++ coreutils-6.7/src/chcon.c 2007-01-09 18:24:57.000000000 +0000 @@ -0,0 +1,421 @@ +/* chcontext -- change security context of a pathname */ + @@ -422,45 +1083,9 @@ + freecon(ref_context); + exit (errors); +} ---- coreutils-5.97/src/mv.c.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/src/mv.c 2006-11-17 13:56:55.000000000 +0000 -@@ -34,6 +34,11 @@ - #include "quote.h" - #include "remove.h" - -+#ifdef WITH_SELINUX -+#include /* for is_selinux_enabled() */ -+int selinux_enabled=0; -+#endif -+ - /* The official name of this program (e.g., no `g' prefix). */ - #define PROGRAM_NAME "mv" - -@@ -127,6 +132,10 @@ - x->preserve_links = true; - x->preserve_mode = true; - x->preserve_timestamps = true; -+#ifdef WITH_SELINUX -+ x->preserve_security_context = true; -+ x->set_security_context = false; -+#endif - x->require_preserve = false; /* FIXME: maybe make this an option */ - x->recursive = true; - x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */ -@@ -359,6 +368,10 @@ - - cp_option_init (&x); - -+#ifdef WITH_SELINUX -+ selinux_enabled= (is_selinux_enabled()>0); -+#endif -+ - /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); ---- coreutils-5.97/src/mkdir.c.selinux 2005-06-15 00:55:47.000000000 +0100 -+++ coreutils-5.97/src/mkdir.c 2006-11-17 13:56:55.000000000 +0000 -@@ -34,11 +34,18 @@ +--- coreutils-6.7/src/mkdir.c.selinux 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/src/mkdir.c 2007-01-09 18:24:57.000000000 +0000 +@@ -35,11 +35,18 @@ #define AUTHORS "David MacKenzie" @@ -479,7 +1104,7 @@ {"mode", required_argument, NULL, 'm'}, {"parents", no_argument, NULL, 'p'}, {"verbose", no_argument, NULL, 'v'}, -@@ -60,6 +67,11 @@ +@@ -61,6 +68,11 @@ Create the DIRECTORY(ies), if they do not already exist.\n\ \n\ "), stdout); @@ -491,7 +1116,7 @@ fputs (_("\ Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); -@@ -95,7 +107,11 @@ +@@ -154,7 +166,11 @@ atexit (close_stdout); @@ -503,9 +1128,9 @@ { switch (optc) { -@@ -108,6 +124,20 @@ +@@ -167,6 +183,20 @@ case 'v': /* --verbose */ - verbose_fmt_string = _("created directory %s"); + options.created_directory_format = _("created directory %s"); break; +#ifdef WITH_SELINUX + case 'Z': @@ -524,406 +1149,598 @@ case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: ---- coreutils-5.97/src/cp.c.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/src/cp.c 2006-11-17 13:56:55.000000000 +0000 -@@ -52,6 +52,11 @@ - - #define AUTHORS "Torbjorn Granlund", "David MacKenzie", "Jim Meyering" +--- coreutils-6.7/src/stat.c.selinux 2006-11-27 10:25:51.000000000 +0000 ++++ coreutils-6.7/src/stat.c 2007-01-09 18:24:58.000000000 +0000 +@@ -55,6 +55,13 @@ + # include + #endif +#ifdef WITH_SELINUX -+#include /* for is_selinux_enabled() */ -+int selinux_enabled=0; ++#include ++#define SECURITY_ID_T security_context_t ++#else ++#define SECURITY_ID_T char * +#endif + - /* Used by do_copy, make_dir_parents_private, and re_protect - to keep a list of leading directories whose protections - need to be fixed after copying. */ -@@ -142,6 +147,9 @@ - {"target-directory", required_argument, NULL, 't'}, - {"update", no_argument, NULL, 'u'}, - {"verbose", no_argument, NULL, 'v'}, + #include "system.h" + + #include "error.h" +@@ -158,6 +165,7 @@ + }; + + static struct option const long_options[] = { ++ {"context", no_argument, 0, 'Z'}, + {"dereference", no_argument, NULL, 'L'}, + {"file-system", no_argument, NULL, 'f'}, + {"filesystem", no_argument, NULL, 'f'}, /* obsolete and undocumented alias */ +@@ -397,7 +405,7 @@ + /* print statfs info */ + static void + print_statfs (char *pformat, size_t prefix_len, char m, char const *filename, +- void const *data) ++ void const *data, SECURITY_ID_T scontext) + { + STRUCT_STATVFS const *statfsbuf = data; + +@@ -472,7 +480,10 @@ + case 'd': + out_int (pformat, prefix_len, statfsbuf->f_ffree); + break; +- ++ case 'C': ++ strcat (pformat, "s"); ++ printf(scontext); ++ break; + default: + fputc ('?', stdout); + break; +@@ -482,7 +493,7 @@ + /* print stat info */ + static void + print_stat (char *pformat, size_t prefix_len, char m, +- char const *filename, void const *data) ++ char const *filename, void const *data, SECURITY_ID_T scontext) + { + struct stat *statbuf = (struct stat *) data; + struct passwd *pw_ent; +@@ -595,6 +606,10 @@ + else + out_uint (pformat, prefix_len, statbuf->st_ctime); + break; ++ case 'C': ++ strcat (pformat, "s"); ++ printf(pformat,scontext); ++ break; + default: + fputc ('?', stdout); + break; +@@ -641,8 +656,9 @@ + + static void + print_it (char const *format, char const *filename, +- void (*print_func) (char *, size_t, char, char const *, void const *), +- void const *data) ++ void (*print_func) (char *, size_t, char, char const *, void const *, ++ SECURITY_ID_T ), ++ void const *data, SECURITY_ID_T scontext) + { + /* Add 2 to accommodate our conversion of the stat `%s' format string + to the longer printf `%llu' one. */ +@@ -683,7 +699,7 @@ + putchar ('%'); + break; + default: +- print_func (dest, len + 1, *fmt_char, filename, data); ++ print_func (dest, len + 1, *fmt_char, filename, data, scontext); + break; + } + break; +@@ -746,9 +762,21 @@ + + /* Stat the file system and print what we find. */ + static bool +-do_statfs (char const *filename, bool terse, char const *format) ++do_statfs (char const *filename, bool terse, bool secure, char const *format) + { + STRUCT_STATVFS statfsbuf; ++ SECURITY_ID_T scontext = NULL; +#ifdef WITH_SELINUX -+ {"context", required_argument, NULL, 'Z'}, ++ if(is_selinux_enabled()) { ++ if (getfilecon(filename,&scontext)<0) { ++ if (secure) { ++ perror (filename); ++ return false; ++ } ++ scontext = NULL; ++ } ++ } +#endif - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -@@ -195,6 +203,9 @@ - additional attributes: links, all\n\ + + if (STATFS (filename, &statfsbuf) != 0) + { +@@ -759,25 +787,46 @@ + + if (format == NULL) + { +- format = (terse +- ? "%n %i %l %t %s %S %b %f %a %c %d\n" +- : " File: \"%n\"\n" +- " ID: %-8i Namelen: %-7l Type: %T\n" +- "Block size: %-10s Fundamental block size: %S\n" +- "Blocks: Total: %-10b Free: %-10f Available: %a\n" +- "Inodes: Total: %-10c Free: %d\n"); ++ if (terse) ++ { ++ if (secure) ++ format = "%n %i %l %t %s %S %b %f %a %c %d %C\n"; ++ else ++ format = "%n %i %l %t %s %S %b %f %a %c %d\n"; ++ } ++ else ++ { ++ if (secure) ++ format = " File: \"%n\"\n" ++ " ID: %-8i Namelen: %-7l Type: %T\n" ++ "Block size: %-10s Fundamental block size: %S\n" ++ "Blocks: Total: %-10b Free: %-10f Available: %a\n" ++ "Inodes: Total: %-10c Free: %d\n" ++ " S_Context: %C\n"; ++ else ++ format = " File: \"%n\"\n" ++ " ID: %-8i Namelen: %-7l Type: %T\n" ++ "Block size: %-10s Fundamental block size: %S\n" ++ "Blocks: Total: %-10b Free: %-10f Available: %a\n" ++ "Inodes: Total: %-10c Free: %d\n"; ++ } + } + +- print_it (format, filename, print_statfs, &statfsbuf); ++ print_it (format, filename, print_statfs, &statfsbuf, scontext); ++#ifdef WITH_SELINUX ++ if (scontext != NULL) ++ freecon(scontext); ++#endif + return true; + } + + /* stat the file and print what we find */ + static bool +-do_stat (char const *filename, bool follow_links, bool terse, ++do_stat (char const *filename, bool follow_links, bool terse, bool secure, + char const *format) + { + struct stat statbuf; ++ SECURITY_ID_T scontext = NULL; + + if ((follow_links ? stat : lstat) (filename, &statbuf) != 0) + { +@@ -785,11 +834,29 @@ + return false; + } + ++#ifdef WITH_SELINUX ++ if(is_selinux_enabled()) { ++ int i; ++ if (!follow_links) ++ i=lgetfilecon(filename, &scontext); ++ else ++ i=getfilecon(filename, &scontext); ++ if (i == -1 && secure) ++ { ++ perror (filename); ++ return false; ++ } ++ } ++#endif ++ + if (format == NULL) + { + if (terse) + { +- format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; ++ if (secure) ++ format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %C\n"; ++ else ++ format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; + } + else + { +@@ -807,16 +874,30 @@ + } + else + { +- format = +- " File: %N\n" +- " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" +- "Device: %Dh/%dd\tInode: %-10i Links: %h\n" +- "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" +- "Access: %x\n" "Modify: %y\n" "Change: %z\n"; ++ if (secure) ++ format = ++ " File: %N\n" ++ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" ++ "Device: %Dh/%dd\tInode: %-10i Links: %-5h" ++ " Device type: %t,%T\n" ++ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" ++ " S_Context: %C\n" ++ "Access: %x\n" "Modify: %y\n" "Change: %z\n"; ++ else ++ format = ++ " File: %N\n" ++ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" ++ "Device: %Dh/%dd\tInode: %-10i Links: %h\n" ++ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" ++ "Access: %x\n" "Modify: %y\n" "Change: %z\n"; + } + } + } +- print_it (format, filename, print_stat, &statbuf); ++ print_it (format, filename, print_stat, &statbuf, scontext); ++#ifdef WITH_SELINUX ++ if (scontext) ++ freecon(scontext); ++#endif + return true; + } + +@@ -833,6 +914,7 @@ + Display file or file system status.\n\ + \n\ + -L, --dereference follow links\n\ ++ -Z, --context print the security context \n\ + -f, --file-system display file system status instead of file status\n\ "), stdout); fputs (_("\ -+ -c same as --preserve=context\n\ -+"), stdout); -+ fputs (_("\ - --no-preserve=ATTR_LIST don't preserve the specified attributes\n\ - --parents use full source file name under DIRECTORY\n\ +@@ -892,6 +974,7 @@ + %c Total file nodes in file system\n\ + %d Free file nodes in file system\n\ + %f Free blocks in file system\n\ ++ %C - Security context in SELinux\n\ "), stdout); -@@ -220,6 +231,7 @@ - destination file is missing\n\ - -v, --verbose explain what is being done\n\ - -x, --one-file-system stay on this file system\n\ -+ -Z, --context=CONTEXT set security context of copy to CONTEXT\n\ - "), stdout); - fputs (HELP_OPTION_DESCRIPTION, stdout); - fputs (VERSION_OPTION_DESCRIPTION, stdout); -@@ -737,6 +749,11 @@ - x->preserve_mode = false; - x->preserve_timestamps = false; + fputs (_("\ + %i File System ID in hex\n\ +@@ -916,6 +999,7 @@ + bool follow_links = false; + bool fs = false; + bool terse = false; ++ bool secure = false; + char *format = NULL; + bool ok = true; -+#ifdef WITH_SELINUX -+ x->preserve_security_context = false; -+ x->set_security_context = false; -+#endif -+ - x->require_preserve = false; - x->recursive = false; - x->sparse_mode = SPARSE_AUTO; -@@ -764,18 +781,19 @@ - PRESERVE_TIMESTAMPS, - PRESERVE_OWNERSHIP, - PRESERVE_LINK, -+ PRESERVE_CONTEXT, - PRESERVE_ALL - }; - static enum File_attribute const preserve_vals[] = +@@ -927,7 +1011,7 @@ + + atexit (close_stdout); + +- while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1) ++ while ((c = getopt_long (argc, argv, "c:fLtZ", long_options, NULL)) != -1) { - PRESERVE_MODE, PRESERVE_TIMESTAMPS, -- PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_ALL -+ PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_ALL - }; - /* Valid arguments to the `--preserve' option. */ - static char const* const preserve_args[] = - { - "mode", "timestamps", -- "ownership", "links", "all", NULL -+ "ownership", "links", "context", "all", NULL - }; - ARGMATCH_VERIFY (preserve_args, preserve_vals); - -@@ -811,11 +829,16 @@ - x->preserve_links = on_off; + switch (c) + { +@@ -954,6 +1038,14 @@ + case 't': + terse = true; break; - -+ case PRESERVE_CONTEXT: -+ x->preserve_security_context = on_off; -+ break; -+ - case PRESERVE_ALL: - x->preserve_mode = on_off; - x->preserve_timestamps = on_off; - x->preserve_ownership = on_off; - x->preserve_links = on_off; -+ x->preserve_security_context = on_off; - break; - - default: -@@ -840,6 +863,9 @@ - bool copy_contents = false; - char *target_directory = NULL; - bool no_target_directory = false; -+#ifdef WITH_SELINUX -+ selinux_enabled= (is_selinux_enabled()>0); -+#endif - - initialize_main (&argc, &argv); - program_name = argv[0]; -@@ -855,7 +881,11 @@ - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); - -+#ifdef WITH_SELINUX -+ while ((c = getopt_long (argc, argv, "abcdfHilLprst:uvxPRS:TZ:", -+#else - while ((c = getopt_long (argc, argv, "abdfHilLprst:uvxPRS:T", -+#endif - long_opts, NULL)) - != -1) - { -@@ -866,12 +896,13 @@ - sparse_type_string, sparse_type); - break; - -- case 'a': /* Like -dpPR. */ -+ case 'a': /* Like -dpPRc. */ - x.dereference = DEREF_NEVER; - x.preserve_links = true; - x.preserve_ownership = true; - x.preserve_mode = true; - x.preserve_timestamps = true; -+ x.preserve_security_context = true; - x.require_preserve = true; - x.recursive = true; - break; -@@ -946,6 +977,36 @@ - case 'R': - x.recursive = true; - break; -+#ifdef WITH_SELINUX -+ case 'c': -+ if ( x.set_security_context ) { -+ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]); -+ exit( 1 ); -+ } -+ else if (selinux_enabled) -+ x.preserve_security_context = true; -+ break; -+ + case 'Z': -+ /* politely decline if we're not on a selinux-enabled kernel. */ -+ if( !selinux_enabled ) { -+ fprintf( stderr, "Warning: ignoring --context (-Z). " -+ "It requires a SELinux enabled kernel.\n" ); -+ break; -+ } -+ if ( x.preserve_security_context ) { -+ (void) fprintf(stderr, "%s: cannot force target context to '%s' and preserve it\n", argv[0], optarg); -+ exit( 1 ); -+ } -+ x.set_security_context = true; -+ /* if there's a security_context given set new path -+ components to that context, too */ -+ if ( setfscreatecon(optarg) < 0 ) { -+ (void) fprintf(stderr, _("cannot set default security context %s\n"), optarg); -+ exit( 1 ); ++ if((is_selinux_enabled()>0)) ++ secure = 1; ++ else { ++ error (0, 0, _("Kernel is not SELinux enabled")); ++ usage (EXIT_FAILURE); + } + break; -+#endif - case REPLY_OPTION: /* Deprecated */ - x.interactive = XARGMATCH ("--reply", optarg, ---- coreutils-5.97/src/install.c.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/src/install.c 2006-11-17 13:56:55.000000000 +0000 -@@ -48,6 +48,43 @@ - # include - #endif + case_GETOPT_HELP_CHAR; + +@@ -972,8 +1064,8 @@ + + for (i = optind; i < argc; i++) + ok &= (fs +- ? do_statfs (argv[i], terse, format) +- : do_stat (argv[i], follow_links, terse, format)); ++ ? do_statfs (argv[i], terse, secure, format) ++ : do_stat (argv[i], follow_links, terse, secure, format)); + + exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); + } +--- coreutils-6.7/src/mkfifo.c.selinux 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/src/mkfifo.c 2007-01-09 18:24:58.000000000 +0000 +@@ -32,11 +32,18 @@ + + #define AUTHORS "David MacKenzie" +#ifdef WITH_SELINUX +#include /* for is_selinux_enabled() */ -+int selinux_enabled=0; -+static int use_default_selinux_context = 1; -+/* Modify file context to match the specified policy, -+ If an error occurs the file will remain with the default directory -+ context.*/ -+static void setdefaultfilecon(const char *path) { -+ struct stat st; -+ security_context_t scontext=NULL; -+ if (selinux_enabled != 1) { -+ /* Indicate no context found. */ -+ return; -+ } -+ if (lstat(path, &st) != 0) -+ return; -+ -+ /* If there's an error determining the context, or it has none, -+ return to allow default context */ -+ if ((matchpathcon(path, st.st_mode, &scontext) != 0) || -+ (strcmp(scontext, "<>") == 0)) { -+ if (scontext != NULL) { -+ freecon(scontext); -+ } -+ return; -+ } -+ if (lsetfilecon(path, scontext) < 0) { -+ if (errno != ENOTSUP) { -+ error (0, errno, -+ _("warning: failed to change context of %s to %s"), path, scontext); -+ } -+ } -+ freecon(scontext); -+ return; -+} +#endif + - #if ! HAVE_ENDGRENT - # define endgrent() ((void) 0) - #endif -@@ -109,12 +146,18 @@ - static struct option const long_options[] = + /* The name this program was run with. */ + char *program_name; + + static struct option const longopts[] = { - {"backup", optional_argument, NULL, 'b'}, +#ifdef WITH_SELINUX + {"context", required_argument, NULL, 'Z'}, +#endif - {"directory", no_argument, NULL, 'd'}, - {"group", required_argument, NULL, 'g'}, {"mode", required_argument, NULL, 'm'}, - {"no-target-directory", no_argument, NULL, 'T'}, - {"owner", required_argument, NULL, 'o'}, - {"preserve-timestamps", no_argument, NULL, 'p'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, +@@ -56,6 +63,11 @@ + Create named pipes (FIFOs) with the given NAMEs.\n\ + \n\ + "), stdout); +#ifdef WITH_SELINUX -+ {"preserve_context", no_argument, NULL, 'P'}, ++ fputs (_("\ ++ -Z, --context=CONTEXT set security context (quoted string)\n\ ++"), stdout); +#endif - {"strip", no_argument, NULL, 's'}, - {"suffix", required_argument, NULL, 'S'}, - {"target-directory", required_argument, NULL, 't'}, -@@ -154,6 +197,10 @@ - x->stdin_tty = false; + fputs (_("\ + Mandatory arguments to long options are mandatory for short options too.\n\ + "), stdout); +@@ -85,13 +97,32 @@ - x->update = false; -+#ifdef WITH_SELINUX -+ x->preserve_security_context = false; -+ x->set_security_context = false; -+#endif - x->verbose = false; - x->dest_info = NULL; - x->src_info = NULL; -@@ -195,6 +242,10 @@ - bool no_target_directory = false; - int n_files; - char **file; -+#ifdef WITH_SELINUX -+ /* set iff kernel has extra selinux system calls */ -+ selinux_enabled = (is_selinux_enabled()>0); -+#endif - - initialize_main (&argc, &argv); - program_name = argv[0]; -@@ -216,7 +267,11 @@ - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + atexit (close_stdout); +- while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) ++ while ((optc = getopt_long (argc, argv, "m:" +#ifdef WITH_SELINUX -+ while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pPt:TvS:Z:", long_options, -+#else - while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:", long_options, ++ "Z:" +#endif - NULL)) != -1) ++ , longopts, NULL)) != -1) { switch (optc) -@@ -278,6 +333,41 @@ - case 'T': - no_target_directory = true; + { + case 'm': + specified_mode = optarg; break; +#ifdef WITH_SELINUX -+ case 'P': -+ /* politely decline if we're not on a selinux-enabled kernel. */ -+ if( !selinux_enabled ) { -+ fprintf( stderr, "Warning: ignoring --preserve_context (-P) " -+ "because the kernel is not selinux-enabled.\n" ); -+ break; -+ } -+ if ( x.set_security_context ) { -+ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]); -+ exit( 1 ); -+ } -+ x.preserve_security_context = true; -+ use_default_selinux_context = 0; -+ break ; + case 'Z': -+ /* politely decline if we're not on a selinux-enabled kernel. */ -+ if( !selinux_enabled) { -+ fprintf( stderr, "Warning: ignoring --context (-Z) " -+ "because the kernel is not selinux-enabled.\n" ); -+ break; -+ } -+ if ( x.preserve_security_context ) { -+ -+ (void) fprintf(stderr, "%s: cannot force target context == '%s' and preserve it\n", argv[0], optarg); -+ exit( 1 ); -+ } -+ use_default_selinux_context = 0; -+ x.set_security_context = true; -+ if (setfscreatecon(optarg)) { -+ (void) fprintf(stderr, "%s: cannot setup default context == '%s'\n", argv[0], optarg); -+ exit(1); -+ } ++ if (!(is_selinux_enabled()>0)) ++ { ++ fprintf( stderr, "Sorry, --context (-Z) can be used only on " ++ "a selinux-enabled kernel.\n" ); ++ exit (1); ++ } ++ if (setfscreatecon(optarg)) ++ { ++ fprintf( stderr, "Sorry, cannot set default context to %s.\n", optarg); ++ exit (1); ++ } + break; +#endif case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: -@@ -519,6 +609,10 @@ - ok = false; +--- coreutils-6.7/src/mknod.c.selinux 2006-10-22 17:54:15.000000000 +0100 ++++ coreutils-6.7/src/mknod.c 2007-01-09 18:24:58.000000000 +0000 +@@ -36,8 +36,15 @@ + /* The name this program was run with. */ + char *program_name; + ++#ifdef WITH_SELINUX ++#include ++#endif ++ + static struct option const longopts[] = + { ++#ifdef WITH_SELINUX ++ {"context", required_argument, NULL, 'Z'}, ++#endif + {"mode", required_argument, NULL, 'm'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, +@@ -58,6 +65,11 @@ + Create the special file NAME of the given TYPE.\n\ + \n\ + "), stdout); ++#ifdef WITH_SELINUX ++ fputs(_("\ ++ -Z, --context=CONTEXT set security context (quoted string)\n\ ++"), stdout); ++#endif + fputs (_("\ + Mandatory arguments to long options are mandatory for short options too.\n\ + "), stdout); +@@ -101,13 +113,31 @@ + + atexit (close_stdout); + ++#ifdef WITH_SELINUX ++ while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1) ++#else + while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) ++#endif + { + switch (optc) + { + case 'm': + specified_mode = optarg; + break; ++#ifdef WITH_SELINUX ++ case 'Z': ++ /* politely decline if we're not on a selinux-enabled kernel. */ ++ if( !(is_selinux_enabled()>0)) { ++ fprintf( stderr, "Sorry, --context (-Z) can be used only on " ++ "a selinux-enabled kernel.\n" ); ++ exit( 1 ); ++ } ++ if (setfscreatecon(optarg)) { ++ fprintf( stderr, "Sorry, cannot set default context to %s.\n", optarg); ++ exit( 1 ); ++ } ++ break; ++#endif + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: +--- coreutils-6.7/src/id.c.selinux 2007-01-09 18:24:57.000000000 +0000 ++++ coreutils-6.7/src/id.c 2007-01-09 18:24:58.000000000 +0000 +@@ -37,6 +37,20 @@ + + int getugroups (); + ++#ifdef WITH_SELINUX ++#include ++static void print_context (char* context); ++/* Print the SELinux context */ ++static void ++print_context(char *context) ++{ ++ printf ("%s", context); ++} ++ ++/* If nonzero, output only the SELinux context. -Z */ ++static int just_context = 0; ++ ++#endif + static void print_user (uid_t uid); + static void print_group (gid_t gid); + static void print_group_list (const char *username); +@@ -55,8 +69,14 @@ + /* True unless errors have been encountered. */ + static bool ok = true; + ++/* The SELinux context */ ++/* Set `context' to a known invalid value so print_full_info() will * ++ * know when `context' has not been set to a meaningful value. */ ++static security_context_t context=NULL; ++ + static struct option const longopts[] = + { ++ {"context", no_argument, NULL, 'Z'}, + {"group", no_argument, NULL, 'g'}, + {"groups", no_argument, NULL, 'G'}, + {"name", no_argument, NULL, 'n'}, +@@ -80,6 +100,7 @@ + Print information for USERNAME, or the current user.\n\ + \n\ + -a ignore, for compatibility with other versions\n\ ++ -Z, --context print only the context of the current process\n\ + -g, --group print only the effective group ID\n\ + -G, --groups print all group IDs\n\ + -n, --name print a name instead of a number, for -ugG\n\ +@@ -101,6 +122,7 @@ + main (int argc, char **argv) + { + int optc; ++ int selinux_enabled=(is_selinux_enabled()>0); + + /* If true, output the list of all group IDs. -G */ + bool just_group_list = false; +@@ -119,13 +141,24 @@ + + atexit (close_stdout); + +- while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1) ++ while ((optc = getopt_long (argc, argv, "agnruGZ", longopts, NULL)) != -1) + { + switch (optc) + { + case 'a': + /* Ignore -a, for compatibility with SVR4. */ + break; ++#ifdef WITH_SELINUX ++ case 'Z': ++ /* politely decline if we're not on a selinux-enabled kernel. */ ++ if( !selinux_enabled ) { ++ fprintf( stderr, "Sorry, --context (-Z) can be used only on " ++ "a selinux-enabled kernel.\n" ); ++ exit( 1 ); ++ } ++ just_context = 1; ++ break; ++#endif + case 'g': + just_group = true; + break; +@@ -148,8 +181,28 @@ + } } +- if (just_user + just_group + just_group_list > 1) +- error (EXIT_FAILURE, 0, _("cannot print only user and only group")); +#ifdef WITH_SELINUX -+ if (use_default_selinux_context) -+ setdefaultfilecon(name); -+#endif - return ok; - } - -@@ -663,6 +757,11 @@ - -T, --no-target-directory treat DEST as a normal file\n\ - -v, --verbose print the name of each directory as it is created\n\ - "), stdout); -+ fputs (_("\ -+ -P, --preserve_context (SELinux) Preserve security context\n\ -+ -Z, --context=CONTEXT (SELinux) Set security context of files and directories\n\ -+"), stdout); ++ if (argc - optind == 1) ++ if (just_context) error (1, 0, _("\ ++cannot print security context when user specified")); + - fputs (HELP_OPTION_DESCRIPTION, stdout); - fputs (VERSION_OPTION_DESCRIPTION, stdout); - fputs (_("\ ---- coreutils-5.97/src/copy.h.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/src/copy.h 2006-11-17 13:56:55.000000000 +0000 -@@ -127,6 +127,10 @@ - bool preserve_ownership; - bool preserve_mode; - bool preserve_timestamps; -+#ifdef WITH_SELINUX -+ bool preserve_security_context; -+ bool set_security_context; ++ if( just_context && !selinux_enabled) ++ error (1, 0, _("\ ++cannot display context when selinux not enabled")); ++ ++ /* If we are on a selinux-enabled kernel, get our context. * ++ * Otherwise, leave the context variable alone - it has * ++ * been initialized known invalid value; if we see this invalid * ++ * value later, we will know we are on a non-selinux kernel. */ ++ if( selinux_enabled ) ++ { ++ if (getcon(&context) && just_context) ++ error (1, 0, "can't get process context"); ++ } +#endif ++ ++ if (just_user + just_group + just_group_list + just_context > 1) ++ error (EXIT_FAILURE, 0, _("cannot print \"only\" of more than one choice")); - /* Enabled for mv, and for cp by the --preserve=links option. - If true, attempt to preserve in the destination files any ---- coreutils-5.97/src/Makefile.am.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/src/Makefile.am 2006-11-17 13:56:55.000000000 +0000 -@@ -20,14 +20,14 @@ - EXTRA_PROGRAMS = chroot df hostid nice pinky stty su runuser uname uptime users who + if (just_user + just_group + just_group_list == 0 && (use_real | use_name)) + error (EXIT_FAILURE, 0, +@@ -183,6 +236,10 @@ + print_group (use_real ? rgid : egid); + else if (just_group_list) + print_group_list (argv[optind]); ++#ifdef WITH_SELINUX ++ else if (just_context) ++ print_context (context); ++#endif + else + print_full_info (argv[optind]); + putchar ('\n'); +@@ -407,4 +464,9 @@ + free (groups); + } + #endif /* HAVE_GETGROUPS */ ++#ifdef WITH_SELINUX ++ if ( context != NULL ) { ++ printf(" context=%s",context); ++ } ++#endif + } +--- coreutils-6.7/src/mv.c.selinux 2006-10-23 10:09:10.000000000 +0100 ++++ coreutils-6.7/src/mv.c 2007-01-09 18:24:58.000000000 +0000 +@@ -33,6 +33,11 @@ + #include "quote.h" + #include "remove.h" - bin_SCRIPTS = groups --bin_PROGRAMS = [ chgrp chown chmod cp dd dircolors du \ -+bin_PROGRAMS = [ chgrp chown chmod chcon cp dd dircolors du \ - ginstall link ln dir vdir ls mkdir \ - mkfifo mknod mv nohup readlink rm rmdir shred stat sync touch unlink \ - cat cksum comm csplit cut expand fmt fold head join md5sum \ - nl od paste pr ptx sha1sum sha224sum sha256sum sha384sum sha512sum \ - sort split sum tac tail tr tsort unexpand uniq wc \ - basename date dirname echo env expr factor false \ -- hostname id kill logname pathchk printenv printf pwd seq sleep tee \ -+ hostname id kill logname pathchk printenv printf pwd runcon seq sleep tee \ - test true tty whoami yes \ - base64 \ - $(OPTIONAL_BIN_PROGS) $(DF_PROG) -@@ -52,9 +52,9 @@ - LDADD = ../lib/libcoreutils.a $(LIBINTL) ../lib/libcoreutils.a ++#ifdef WITH_SELINUX ++#include /* for is_selinux_enabled() */ ++int selinux_enabled=0; ++#endif ++ + /* The official name of this program (e.g., no `g' prefix). */ + #define PROGRAM_NAME "mv" - # for eaccess in lib/euidaccess.c. --cp_LDADD = $(LDADD) $(LIB_EACCESS) @LIBACL@ --ginstall_LDADD = $(LDADD) $(LIB_EACCESS) @LIBACL@ --mv_LDADD = $(LDADD) $(LIB_EACCESS) @LIBACL@ -+cp_LDADD = $(LDADD) $(LIB_EACCESS) @LIBACL@ @LIB_SELINUX@ -+ginstall_LDADD = $(LDADD) $(LIB_EACCESS) @LIBACL@ @LIB_SELINUX@ -+mv_LDADD = $(LDADD) $(LIB_EACCESS) @LIBACL@ @LIB_SELINUX@ - pathchk_LDADD = $(LDADD) $(LIB_EACCESS) - rm_LDADD = $(LDADD) $(LIB_EACCESS) - test_LDADD = $(LDADD) $(LIB_EACCESS) -@@ -63,11 +63,18 @@ +@@ -126,6 +131,10 @@ + x->preserve_links = true; + x->preserve_mode = true; + x->preserve_timestamps = true; ++#ifdef WITH_SELINUX ++ x->preserve_security_context = true; ++ x->set_security_context = false; ++#endif + x->require_preserve = false; /* FIXME: maybe make this an option */ + x->recursive = true; + x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */ +@@ -357,6 +366,10 @@ - # for clock_gettime and fdatasync - dd_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC) --dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ --ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ -+dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ @LIB_SELINUX@ -+ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ @LIB_SELINUX@ - pr_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) - shred_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC) --vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ -+vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ @LIB_SELINUX@ -+chcon_LDADD = $(LDADD) @LIB_SELINUX@ -+id_LDADD = $(LDADD) @LIB_SELINUX@ -+mkdir_LDADD = $(LDADD) @LIB_SELINUX@ -+mkfifo_LDADD = $(LDADD) @LIB_SELINUX@ -+mknod_LDADD = $(LDADD) @LIB_SELINUX@ -+stat_LDADD = $(LDADD) @LIB_SELINUX@ -+runcon_LDADD = $(LDADD) @LIB_SELINUX@ + cp_option_init (&x); - ## If necessary, add -lm to resolve use of pow in lib/strtod.c. - sort_LDADD = $(LDADD) $(POW_LIB) ---- /dev/null 2006-11-23 08:31:37.745607750 +0000 -+++ coreutils-5.97/src/runcon.c 2006-11-17 13:56:55.000000000 +0000 ++#ifdef WITH_SELINUX ++ selinux_enabled= (is_selinux_enabled()>0); ++#endif ++ + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); +--- /dev/null 2007-01-09 12:27:07.480840763 +0000 ++++ coreutils-6.7/src/runcon.c 2007-01-09 18:24:58.000000000 +0000 @@ -0,0 +1,253 @@ +/* + * runcon [ context | @@ -1178,1099 +1995,9 @@ + } + return 1; /* can't reach this statement.... */ +} ---- coreutils-5.97/src/ls.c.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/src/ls.c 2006-11-17 13:56:55.000000000 +0000 -@@ -135,6 +135,18 @@ - - #define AUTHORS "Richard Stallman", "David MacKenzie" - -+#ifdef WITH_SELINUX -+#include -+ -+static int print_scontext = 0; -+ -+ -+ -+ -+ -+ -+#endif -+ - #define obstack_chunk_alloc malloc - #define obstack_chunk_free free - -@@ -170,7 +182,8 @@ - symbolic_link DT_INIT (DT_LNK), - sock DT_INIT (DT_SOCK), - arg_directory DT_INIT (2 * (DT_UNKNOWN | DT_FIFO | DT_CHR | DT_DIR | DT_BLK -- | DT_REG | DT_LNK | DT_SOCK)) -+ | DT_REG | DT_LNK | DT_SOCK)), -+ command_line - }; - - struct fileinfo -@@ -179,6 +192,7 @@ - char *name; - - struct stat stat; -+ int stat_failed; - - /* For symbolic link, name of the file linked to, otherwise zero. */ - char *linkname; -@@ -197,6 +211,10 @@ - /* For long listings, true if the file has an access control list. */ - bool have_acl; - #endif -+ -+#ifdef WITH_SELINUX -+ security_context_t scontext; -+#endif - }; - - #if HAVE_ACL || USE_ACL -@@ -232,7 +250,8 @@ - static bool file_ignored (char const *name); - static uintmax_t gobble_file (char const *name, enum filetype type, - bool command_line_arg, char const *dirname); --static void print_color_indicator (const char *name, mode_t mode, int linkok); -+static void print_color_indicator (const char *name, mode_t mode, int linkok, -+ int stat_failed); - static void put_indicator (const struct bin_str *ind); - static void add_ignore_pattern (const char *pattern); - static void attach (char *dest, const char *dirname, const char *name); -@@ -253,7 +272,7 @@ - static void print_long_format (const struct fileinfo *f); - static void print_many_per_line (void); - static void print_name_with_quoting (const char *p, mode_t mode, -- int linkok, -+ int linkok, int stat_failed, - struct obstack *stack); - static void prep_non_filename_text (void); - static void print_type_indicator (mode_t mode); -@@ -263,6 +282,9 @@ - static void sort_files (void); - static void parse_ls_color (void); - void usage (int status); -+#ifdef WITH_SELINUX -+static void print_scontext_format (const struct fileinfo *f); -+#endif - - /* The name this program was run with. */ - char *program_name; -@@ -371,7 +393,11 @@ - one_per_line, /* -1 */ - many_per_line, /* -C */ - horizontal, /* -x */ -- with_commas /* -m */ -+ with_commas, /* -m */ -+#ifdef WITH_SELINUX -+ security_format, /* -Z */ -+#endif -+ invalid_format - }; - - static enum format format; -@@ -740,6 +766,11 @@ - SHOW_CONTROL_CHARS_OPTION, - SI_OPTION, - SORT_OPTION, -+#ifdef WITH_SELINUX -+ CONTEXT_OPTION, -+ LCONTEXT_OPTION, -+ SCONTEXT_OPTION, -+#endif - TIME_OPTION, - TIME_STYLE_OPTION - }; -@@ -784,6 +815,11 @@ - {"time-style", required_argument, NULL, TIME_STYLE_OPTION}, - {"color", optional_argument, NULL, COLOR_OPTION}, - {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, -+#ifdef WITH_SELINUX -+ {"context", no_argument, 0, CONTEXT_OPTION}, -+ {"lcontext", no_argument, 0, LCONTEXT_OPTION}, -+ {"scontext", no_argument, 0, SCONTEXT_OPTION}, -+#endif - {"author", no_argument, NULL, AUTHOR_OPTION}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, -@@ -793,12 +829,19 @@ - static char const *const format_args[] = - { - "verbose", "long", "commas", "horizontal", "across", -- "vertical", "single-column", NULL -+ "vertical", "single-column", -+#ifdef WITH_SELINUX -+ "context", -+#endif -+ NULL - }; - static enum format const format_types[] = - { - long_format, long_format, with_commas, horizontal, horizontal, - many_per_line, one_per_line -+#ifdef WITH_SELINUX -+ , security_format -+#endif - }; - ARGMATCH_VERIFY (format_args, format_types); - -@@ -1222,6 +1265,9 @@ - - format_needs_stat = sort_type == sort_time || sort_type == sort_size - || format == long_format -+#ifdef WITH_SELINUX -+ || format == security_format || print_scontext -+#endif - || dereference == DEREF_ALWAYS - || print_block_size || print_inode; - format_needs_type = (!format_needs_stat -@@ -1251,7 +1297,7 @@ - } - else - do -- gobble_file (argv[i++], unknown, true, ""); -+ gobble_file (argv[i++], command_line, true, ""); - while (i < argc); - - if (files_index) -@@ -1414,6 +1460,9 @@ - ignore_mode = IGNORE_DEFAULT; - ignore_patterns = NULL; - hide_patterns = NULL; -+#ifdef WITH_SELINUX -+ print_scontext = 0; -+#endif - - /* FIXME: put this in a function. */ - { -@@ -1489,7 +1538,7 @@ - } - - while ((c = getopt_long (argc, argv, -- "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1", -+ "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1Z", - long_options, NULL)) != -1) - { - switch (c) -@@ -1608,6 +1657,13 @@ - format = horizontal; - break; - -+#ifdef WITH_SELINUX -+ case 'Z': -+ -+ print_scontext = 1; -+ format = security_format; -+ break; -+#endif - case 'A': - if (ignore_mode == IGNORE_DEFAULT) - ignore_mode = IGNORE_DOT_AND_DOTDOT; -@@ -1784,6 +1840,25 @@ - - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - -+#ifdef WITH_SELINUX -+ -+ case CONTEXT_OPTION: /* new security format */ -+ -+ print_scontext = 1; -+ format = security_format; -+ break; -+ case LCONTEXT_OPTION: /* long format plus security context */ -+ -+ print_scontext = 1; -+ format = long_format; -+ break; -+ case SCONTEXT_OPTION: /* short form of new security format */ -+ -+ print_scontext = 0; -+ format = security_format; -+ break; -+#endif -+ - default: - usage (LS_FAILURE); - } -@@ -2468,6 +2543,12 @@ - { - free (files[i].name); - free (files[i].linkname); -+#ifdef WITH_SELINUX -+ if (files[i].scontext) { -+ freecon (files[i].scontext); -+ files[i].scontext=NULL; -+ } -+#endif - } - - files_index = 0; -@@ -2506,11 +2587,14 @@ - f->linkname = NULL; - f->linkmode = 0; - f->linkok = false; -+#ifdef WITH_SELINUX -+ f->scontext = NULL; -+#endif - - if (command_line_arg - || format_needs_stat - || (format_needs_type -- && (type == unknown -+ && (type == unknown || type == command_line - - /* FIXME: remove this disjunct. - I don't think we care about symlinks here, but for now -@@ -2547,6 +2631,11 @@ - { - case DEREF_ALWAYS: - err = stat (absolute_name, &f->stat); -+#ifdef WITH_SELINUX -+ if (err>=0) -+ if (format == security_format || print_scontext) -+ getfilecon(absolute_name, &f->scontext); -+#endif - break; - - case DEREF_COMMAND_LINE_ARGUMENTS: -@@ -2555,6 +2644,11 @@ - { - bool need_lstat; - err = stat (absolute_name, &f->stat); -+#ifdef WITH_SELINUX -+ if (err>=0) -+ if (format == security_format || print_scontext) -+ getfilecon(absolute_name, &f->scontext); -+#endif - - if (dereference == DEREF_COMMAND_LINE_ARGUMENTS) - break; -@@ -2573,17 +2667,41 @@ - - default: /* DEREF_NEVER */ - err = lstat (absolute_name, &f->stat); -+#ifdef WITH_SELINUX -+ if (err>=0) -+ if (format == security_format || print_scontext) -+ lgetfilecon(absolute_name, &f->scontext); -+#endif - break; - } - -- if (err < 0) -+ f->stat_failed = (err < 0); -+ if (f->stat_failed) - { -- file_failure (command_line_arg, "%s", absolute_name); -+ /* We treat stat failures for files the user named special. -+ There is no guarantee that these files really exist so -+ we do not print any information. */ -+ if (type == command_line) -+ { -+ file_failure (1, "%s", absolute_name); -+ return 0; -+ } -+ -+ f->filetype = type; -+ memset (&f->stat, '\0', sizeof (f->stat)); -+ -+ f->name = xstrdup (absolute_name); -+ files_index++; -+ - return 0; - } - - #if HAVE_ACL || USE_ACL -- if (format == long_format) -+ if (format == long_format -+#ifdef WITH_SELINUX -+ || format == security_format -+#endif -+ ) - { - int n = file_has_acl (absolute_name, &f->stat); - f->have_acl = (0 < n); -@@ -3072,6 +3190,16 @@ - DIRED_PUTCHAR ('\n'); - } - break; -+ -+#ifdef WITH_SELINUX -+ case security_format: -+ for (i = 0; i < files_index; i++) -+ { -+ print_scontext_format (files + i); -+ DIRED_PUTCHAR ('\n'); -+ } -+ break; -+#endif - } - } - -@@ -3179,17 +3307,19 @@ - WIDTH. */ - - static void --format_user (uid_t u, int width) -+format_user (uid_t u, int width, int stat_failed) - { -- format_user_or_group (numeric_ids ? NULL : getuser (u), u, width); -+ format_user_or_group (stat_failed ? "?" : -+ (numeric_ids ? NULL : getuser (u)), u, width); - } - - /* Likewise, for groups. */ - - static void --format_group (gid_t g, int width) -+format_group (gid_t g, int width, int stat_failed) - { -- format_user_or_group (numeric_ids ? NULL : getgroup (g), g, width); -+ format_user_or_group (stat_failed ? "?" : -+ (numeric_ids ? NULL : getgroup (g)), g, width); - } - - /* Return the number of columns that format_user_or_group will print. */ -@@ -3279,7 +3409,7 @@ - { - char hbuf[INT_BUFSIZE_BOUND (uintmax_t)]; - sprintf (p, "%*s ", inode_number_width, -- umaxtostr (f->stat.st_ino, hbuf)); -+ f->stat_failed ? "?" : umaxtostr (f->stat.st_ino, hbuf)); - p += inode_number_width + 1; - } - -@@ -3287,8 +3417,10 @@ - { - char hbuf[LONGEST_HUMAN_READABLE + 1]; - char const *blocks = -- human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts, -- ST_NBLOCKSIZE, output_block_size); -+ f->stat_failed -+ ? "?" -+ : human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts, -+ ST_NBLOCKSIZE, output_block_size); - int pad; - for (pad = block_size_width - mbswidth (blocks, 0); 0 < pad; pad--) - *p++ = ' '; -@@ -3302,10 +3434,18 @@ - { - char hbuf[INT_BUFSIZE_BOUND (uintmax_t)]; - sprintf (p, "%s %*s ", modebuf, nlink_width, -- umaxtostr (f->stat.st_nlink, hbuf)); -+ f->stat_failed ? "?" : umaxtostr (f->stat.st_nlink, hbuf)); - } - p += sizeof modebuf - 2 + any_has_acl + 1 + nlink_width + 1; - -+#ifdef WITH_SELINUX -+ -+ if ( print_scontext ) { -+ sprintf (p, "%-32s ", f->scontext ?: ""); -+ p += strlen (p); -+ } -+#endif -+ - DIRED_INDENT (); - - if (print_owner | print_group | print_author) -@@ -3313,18 +3453,19 @@ - DIRED_FPUTS (buf, stdout, p - buf); - - if (print_owner) -- format_user (f->stat.st_uid, owner_width); -+ format_user (f->stat.st_uid, owner_width, f->stat_failed); - - if (print_group) -- format_group (f->stat.st_gid, group_width); -+ format_group (f->stat.st_gid, group_width, f->stat_failed); - - if (print_author) -- format_user (f->stat.st_author, author_width); -+ format_user (f->stat.st_author, author_width, f->stat_failed); - - p = buf; - } - -- if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)) -+ if (!f->stat_failed -+ && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))) - { - char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)]; - char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)]; -@@ -3342,8 +3483,10 @@ - { - char hbuf[LONGEST_HUMAN_READABLE + 1]; - char const *size = -- human_readable (unsigned_file_size (f->stat.st_size), -- hbuf, human_output_opts, 1, file_output_block_size); -+ f->stat_failed -+ ? "?" -+ : human_readable (unsigned_file_size (f->stat.st_size), -+ hbuf, human_output_opts, 1, file_output_block_size); - int pad; - for (pad = file_size_width - mbswidth (size, 0); 0 < pad; pad--) - *p++ = ' '; -@@ -3356,7 +3499,7 @@ - s = 0; - *p = '\1'; - -- if (when_local) -+ if (!f->stat_failed && when_local) - { - time_t six_months_ago; - bool recent; -@@ -3403,15 +3546,17 @@ - print it as a huge integer number of seconds. */ - char hbuf[INT_BUFSIZE_BOUND (intmax_t)]; - sprintf (p, "%*s ", long_time_expected_width (), -- (TYPE_SIGNED (time_t) -- ? imaxtostr (when, hbuf) -- : umaxtostr (when, hbuf))); -+ f->stat_failed -+ ? "?" -+ : (TYPE_SIGNED (time_t) -+ ? imaxtostr (when, hbuf) -+ : umaxtostr (when, hbuf))); - p += strlen (p); - } - - DIRED_FPUTS (buf, stdout, p - buf); - print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, -- &dired_obstack); -+ f->stat_failed, &dired_obstack); - - if (f->filetype == symbolic_link) - { -@@ -3419,7 +3564,7 @@ - { - DIRED_FPUTS_LITERAL (" -> ", stdout); - print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1, -- NULL); -+ f->stat_failed, NULL); - if (indicator_style != none) - print_type_indicator (f->linkmode); - } -@@ -3601,10 +3746,10 @@ - - static void - print_name_with_quoting (const char *p, mode_t mode, int linkok, -- struct obstack *stack) -+ int stat_failed, struct obstack *stack) - { - if (print_with_color) -- print_color_indicator (p, mode, linkok); -+ print_color_indicator (p, mode, linkok, stat_failed); - - if (stack) - PUSH_CURRENT_DIRED_POS (stack); -@@ -3652,7 +3797,8 @@ - human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts, - ST_NBLOCKSIZE, output_block_size)); - -- print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, NULL); -+ print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, -+ f->stat_failed, NULL); - - if (indicator_style != none) - print_type_indicator (f->stat.st_mode); -@@ -3693,7 +3839,8 @@ - } - - static void --print_color_indicator (const char *name, mode_t mode, int linkok) -+print_color_indicator (const char *name, mode_t mode, int linkok, -+ int stat_failed) - { - int type = C_FILE; - struct color_ext_type *ext; /* Color extension */ -@@ -3732,6 +3879,8 @@ - type = C_CHR; - else if (S_ISDOOR (mode)) - type = C_DOOR; -+ else if (stat_failed) -+ type = C_ORPHAN; - - if (type == C_FILE) - { -@@ -4221,6 +4370,16 @@ - -X sort alphabetically by entry extension\n\ - -1 list one file per line\n\ - "), stdout); -+#ifdef WITH_SELINUX -+printf(_("\nSELINUX options:\n\n\ -+ --lcontext Display security context. Enable -l. Lines\n\ -+ will probably be too wide for most displays.\n\ -+ -Z, --context Display security context so it fits on most\n\ -+ displays. Displays only mode, user, group,\n\ -+ security context and file name.\n\ -+ --scontext Display only security context and file name.\n\ -+\n\n")); -+#endif - fputs (HELP_OPTION_DESCRIPTION, stdout); - fputs (VERSION_OPTION_DESCRIPTION, stdout); - fputs (_("\n\ -@@ -4244,3 +4403,70 @@ - } - exit (status); - } -+ -+#ifdef WITH_SELINUX -+ -+static void -+print_scontext_format (const struct fileinfo *f) -+{ -+ char modebuf[12]; -+ -+ /* 7 fields that may require LONGEST_HUMAN_READABLE bytes, -+ 1 10-byte mode string, -+ 9 spaces, one following each of these fields, and -+ 1 trailing NUL byte. */ -+ -+ char init_bigbuf[7 * LONGEST_HUMAN_READABLE + 10 + 9 + 1]; -+ char *buf = init_bigbuf; -+ size_t bufsize = sizeof (init_bigbuf); -+ size_t s; -+ char *p; -+ const char *fmt; -+ char *user_name; -+ char *group_name; -+ int rv; -+ char *scontext; -+ -+ p = buf; -+ -+ if ( print_scontext ) { /* zero means terse listing */ -+ mode_string (f->stat.st_mode, modebuf); -+ modebuf[10] = (FILE_HAS_ACL (f) ? '+' : ' '); -+ modebuf[11] = '\0'; -+ -+ /* print mode */ -+ -+ (void) sprintf (p, "%s ", modebuf); -+ p += strlen (p); -+ -+ /* print standard user and group */ -+ -+ DIRED_FPUTS (buf, stdout, p - buf); -+ format_user (f->stat.st_uid, owner_width, f->stat_failed); -+ format_group (f->stat.st_gid, group_width, f->stat_failed); -+ p = buf; -+ } -+ -+ (void) sprintf (p, "%-32s ", f->scontext ?: ""); -+ p += strlen (p); -+ -+ DIRED_INDENT (); -+ DIRED_FPUTS (buf, stdout, p - buf); -+ print_name_with_quoting (f->name, f->stat.st_mode, f->linkok, -+ f->stat_failed, &dired_obstack); -+ -+ if (f->filetype == symbolic_link) { -+ if (f->linkname) { -+ DIRED_FPUTS_LITERAL (" -> ", stdout); -+ print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1, -+ f->stat_failed, NULL); -+ if (indicator_style != none) -+ print_type_indicator (f->linkmode); -+ } -+ } -+ else { -+ if (indicator_style != none) -+ print_type_indicator (f->stat.st_mode); -+ } -+} -+#endif ---- coreutils-5.97/src/stat.c.selinux 2005-12-15 21:25:53.000000000 +0000 -+++ coreutils-5.97/src/stat.c 2006-11-23 17:33:50.000000000 +0000 -@@ -42,6 +42,13 @@ - # endif - #endif - -+#ifdef WITH_SELINUX -+#include -+#define SECURITY_ID_T security_context_t -+#else -+#define SECURITY_ID_T char * -+#endif -+ - #include "system.h" - - #include "error.h" -@@ -112,6 +119,7 @@ - }; - - static struct option const long_options[] = { -+ {"context", no_argument, 0, 'Z'}, - {"dereference", no_argument, NULL, 'L'}, - {"file-system", no_argument, NULL, 'f'}, - {"filesystem", no_argument, NULL, 'f'}, /* obsolete and undocumented alias */ -@@ -331,7 +339,7 @@ - /* print statfs info */ - static void - print_statfs (char *pformat, size_t buf_len, char m, char const *filename, -- void const *data) -+ void const *data, SECURITY_ID_T scontext) - { - STRUCT_STATVFS const *statfsbuf = data; - -@@ -403,7 +411,10 @@ - xstrcat (pformat, buf_len, PRIdMAX); - printf (pformat, (intmax_t) (statfsbuf->f_ffree)); - break; -- -+ case 'C': -+ strcat (pformat, "s"); -+ printf(scontext); -+ break; - default: - xstrcat (pformat, buf_len, "c"); - printf (pformat, m); -@@ -414,7 +425,7 @@ - /* print stat info */ - static void - print_stat (char *pformat, size_t buf_len, char m, -- char const *filename, void const *data) -+ char const *filename, void const *data, SECURITY_ID_T scontext) - { - struct stat *statbuf = (struct stat *) data; - struct passwd *pw_ent; -@@ -548,6 +559,10 @@ - xstrcat (pformat, buf_len, TYPE_SIGNED (time_t) ? "ld" : "lu"); - printf (pformat, (unsigned long int) statbuf->st_ctime); - break; -+ case 'C': -+ strcat (pformat, "s"); -+ printf(pformat,scontext); -+ break; - default: - xstrcat (pformat, buf_len, "c"); - printf (pformat, m); -@@ -595,8 +610,9 @@ - - static void - print_it (char const *format, char const *filename, -- void (*print_func) (char *, size_t, char, char const *, void const *), -- void const *data) -+ void (*print_func) (char *, size_t, char, char const *, void const *, -+ SECURITY_ID_T ), -+ void const *data, SECURITY_ID_T scontext) - { - /* Add 2 to accommodate our conversion of the stat `%s' format string - to the longer printf `%llu' one. */ -@@ -627,7 +643,7 @@ - putchar ('%'); - break; - default: -- print_func (dest, n_alloc, *fmt_char, filename, data); -+ print_func (dest, n_alloc, *fmt_char, filename, data, scontext); - break; - } - break; -@@ -690,9 +706,21 @@ - - /* Stat the file system and print what we find. */ - static bool --do_statfs (char const *filename, bool terse, char const *format) -+do_statfs (char const *filename, bool terse, bool secure, char const *format) - { - STRUCT_STATVFS statfsbuf; -+ SECURITY_ID_T scontext = NULL; -+#ifdef WITH_SELINUX -+ if(is_selinux_enabled()) { -+ if (getfilecon(filename,&scontext)<0) { -+ if (secure) { -+ perror (filename); -+ return false; -+ } -+ scontext = NULL; -+ } -+ } -+#endif - - if (STATFS (filename, &statfsbuf) != 0) - { -@@ -703,25 +731,46 @@ - - if (format == NULL) - { -- format = (terse -- ? "%n %i %l %t %s %S %b %f %a %c %d\n" -- : " File: \"%n\"\n" -- " ID: %-8i Namelen: %-7l Type: %T\n" -- "Block size: %-10s Fundamental block size: %S\n" -- "Blocks: Total: %-10b Free: %-10f Available: %a\n" -- "Inodes: Total: %-10c Free: %d\n"); -+ if (terse) -+ { -+ if (secure) -+ format = "%n %i %l %t %s %S %b %f %a %c %d %C\n"; -+ else -+ format = "%n %i %l %t %s %S %b %f %a %c %d\n"; -+ } -+ else -+ { -+ if (secure) -+ format = " File: \"%n\"\n" -+ " ID: %-8i Namelen: %-7l Type: %T\n" -+ "Block size: %-10s Fundamental block size: %S\n" -+ "Blocks: Total: %-10b Free: %-10f Available: %a\n" -+ "Inodes: Total: %-10c Free: %d\n" -+ " S_Context: %C\n"; -+ else -+ format = " File: \"%n\"\n" -+ " ID: %-8i Namelen: %-7l Type: %T\n" -+ "Block size: %-10s Fundamental block size: %S\n" -+ "Blocks: Total: %-10b Free: %-10f Available: %a\n" -+ "Inodes: Total: %-10c Free: %d\n"; -+ } - } - -- print_it (format, filename, print_statfs, &statfsbuf); -+ print_it (format, filename, print_statfs, &statfsbuf, scontext); -+#ifdef WITH_SELINUX -+ if (scontext != NULL) -+ freecon(scontext); -+#endif - return true; - } - - /* stat the file and print what we find */ - static bool --do_stat (char const *filename, bool follow_links, bool terse, -+do_stat (char const *filename, bool follow_links, bool terse, bool secure, - char const *format) - { - struct stat statbuf; -+ SECURITY_ID_T scontext = NULL; - - if ((follow_links ? stat : lstat) (filename, &statbuf) != 0) - { -@@ -729,11 +778,29 @@ - return false; - } - -+#ifdef WITH_SELINUX -+ if(is_selinux_enabled()) { -+ int i; -+ if (!follow_links) -+ i=lgetfilecon(filename, &scontext); -+ else -+ i=getfilecon(filename, &scontext); -+ if (i == -1 && secure) -+ { -+ perror (filename); -+ return false; -+ } -+ } -+#endif -+ - if (format == NULL) - { - if (terse) - { -- format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; -+ if (secure) -+ format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %C\n"; -+ else -+ format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; - } - else - { -@@ -751,16 +818,30 @@ - } - else - { -- format = -- " File: %N\n" -- " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" -- "Device: %Dh/%dd\tInode: %-10i Links: %h\n" -- "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" -- "Access: %x\n" "Modify: %y\n" "Change: %z\n"; -+ if (secure) -+ format = -+ " File: %N\n" -+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" -+ "Device: %Dh/%dd\tInode: %-10i Links: %-5h" -+ " Device type: %t,%T\n" -+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" -+ " S_Context: %C\n" -+ "Access: %x\n" "Modify: %y\n" "Change: %z\n"; -+ else -+ format = -+ " File: %N\n" -+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" -+ "Device: %Dh/%dd\tInode: %-10i Links: %h\n" -+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" -+ "Access: %x\n" "Modify: %y\n" "Change: %z\n"; - } - } - } -- print_it (format, filename, print_stat, &statbuf); -+ print_it (format, filename, print_stat, &statbuf, scontext); -+#ifdef WITH_SELINUX -+ if (scontext) -+ freecon(scontext); -+#endif - return true; - } - -@@ -777,6 +858,7 @@ - Display file or file system status.\n\ - \n\ - -L, --dereference follow links\n\ -+ -Z, --context print the security context \n\ - -f, --file-system display file system status instead of file status\n\ - "), stdout); - fputs (_("\ -@@ -836,6 +918,7 @@ - %c Total file nodes in file system\n\ - %d Free file nodes in file system\n\ - %f Free blocks in file system\n\ -+ %C - Security context in SELinux\n\ - "), stdout); - fputs (_("\ - %i File System ID in hex\n\ -@@ -860,6 +943,7 @@ - bool follow_links = false; - bool fs = false; - bool terse = false; -+ bool secure = false; - char *format = NULL; - bool ok = true; - -@@ -871,7 +955,7 @@ - - atexit (close_stdout); - -- while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1) -+ while ((c = getopt_long (argc, argv, "c:fLtZ", long_options, NULL)) != -1) - { - switch (c) - { -@@ -898,6 +982,14 @@ - case 't': - terse = true; - break; -+ case 'Z': -+ if((is_selinux_enabled()>0)) -+ secure = 1; -+ else { -+ error (0, 0, _("Kernel is not SELinux enabled")); -+ usage (EXIT_FAILURE); -+ } -+ break; - - case_GETOPT_HELP_CHAR; - -@@ -916,8 +1008,8 @@ - - for (i = optind; i < argc; i++) - ok &= (fs -- ? do_statfs (argv[i], terse, format) -- : do_stat (argv[i], follow_links, terse, format)); -+ ? do_statfs (argv[i], terse, secure, format) -+ : do_stat (argv[i], follow_links, terse, secure, format)); - - exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); - } ---- coreutils-5.97/src/mkfifo.c.selinux 2005-05-14 08:58:37.000000000 +0100 -+++ coreutils-5.97/src/mkfifo.c 2006-11-17 13:56:55.000000000 +0000 -@@ -32,11 +32,18 @@ - - #define AUTHORS "David MacKenzie" - -+#ifdef WITH_SELINUX -+#include /* for is_selinux_enabled() */ -+#endif -+ - /* The name this program was run with. */ - char *program_name; - - static struct option const longopts[] = - { -+#ifdef WITH_SELINUX -+ {"context", required_argument, NULL, 'Z'}, -+#endif - {"mode", required_argument, NULL, 'm'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, -@@ -57,6 +64,11 @@ - Create named pipes (FIFOs) with the given NAMEs.\n\ - \n\ - "), stdout); -+#ifdef WITH_SELINUX -+ fputs (_("\ -+ -Z, --context=CONTEXT set security context (quoted string)\n\ -+"), stdout); -+#endif - fputs (_("\ - Mandatory arguments to long options are mandatory for short options too.\n\ - "), stdout); -@@ -92,13 +104,30 @@ - #ifndef S_ISFIFO - error (EXIT_FAILURE, 0, _("fifo files not supported")); - #else -+#ifdef WITH_SELINUX -+ while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1) -+#else - while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) -+#endif - { - switch (optc) - { - case 'm': - specified_mode = optarg; - break; -+#ifdef WITH_SELINUX -+ case 'Z': -+ if( !(is_selinux_enabled()>0)) { -+ fprintf( stderr, "Sorry, --context (-Z) can be used only on " -+ "a selinux-enabled kernel.\n" ); -+ exit( 1 ); -+ } -+ if (setfscreatecon(optarg)) { -+ fprintf( stderr, "Sorry, cannot set default context to %s.\n", optarg); -+ exit( 1 ); -+ } -+ break; -+#endif - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: ---- coreutils-5.97/src/id.c 2006-11-23 17:05:07.000000000 +0000 -+++ coreutils-5.97/src/id.c 2006-11-24 18:29:34.000000000 +0000 -@@ -37,6 +37,20 @@ - - int getugroups (); - -+#ifdef WITH_SELINUX -+#include -+static void print_context (char* context); -+/* Print the SELinux context */ -+static void -+print_context(char *context) -+{ -+ printf ("%s", context); -+} -+ -+/* If nonzero, output only the SELinux context. -Z */ -+static int just_context = 0; -+ -+#endif - static void print_user (uid_t uid); - static void print_group (gid_t gid); - static void print_group_list (const char *username); -@@ -55,8 +69,14 @@ - /* True unless errors have been encountered. */ - static bool ok = true; - -+/* The SELinux context */ -+/* Set `context' to a known invalid value so print_full_info() will * -+ * know when `context' has not been set to a meaningful value. */ -+static security_context_t context=NULL; -+ - static struct option const longopts[] = - { -+ {"context", no_argument, NULL, 'Z'}, - {"group", no_argument, NULL, 'g'}, - {"groups", no_argument, NULL, 'G'}, - {"name", no_argument, NULL, 'n'}, -@@ -80,6 +100,7 @@ - Print information for USERNAME, or the current user.\n\ - \n\ - -a ignore, for compatibility with other versions\n\ -+ -Z, --context print only the context of the current process\n\ - -g, --group print only the effective group ID\n\ - -G, --groups print all group IDs\n\ - -n, --name print a name instead of a number, for -ugG\n\ -@@ -101,6 +122,7 @@ - main (int argc, char **argv) - { - int optc; -+ int selinux_enabled=(is_selinux_enabled()>0); - - /* If true, output the list of all group IDs. -G */ - bool just_group_list = false; -@@ -119,13 +141,24 @@ - - atexit (close_stdout); - -- while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1) -+ while ((optc = getopt_long (argc, argv, "agnruGZ", longopts, NULL)) != -1) - { - switch (optc) - { - case 'a': - /* Ignore -a, for compatibility with SVR4. */ - break; -+#ifdef WITH_SELINUX -+ case 'Z': -+ /* politely decline if we're not on a selinux-enabled kernel. */ -+ if( !selinux_enabled ) { -+ fprintf( stderr, "Sorry, --context (-Z) can be used only on " -+ "a selinux-enabled kernel.\n" ); -+ exit( 1 ); -+ } -+ just_context = 1; -+ break; -+#endif - case 'g': - just_group = true; - break; -@@ -148,8 +181,28 @@ - } - } - -- if (just_user + just_group + just_group_list > 1) -- error (EXIT_FAILURE, 0, _("cannot print only user and only group")); -+#ifdef WITH_SELINUX -+ if (argc - optind == 1) -+ if (just_context) error (1, 0, _("\ -+cannot print security context when user specified")); -+ -+ if( just_context && !selinux_enabled) -+ error (1, 0, _("\ -+cannot display context when selinux not enabled")); -+ -+ /* If we are on a selinux-enabled kernel, get our context. * -+ * Otherwise, leave the context variable alone - it has * -+ * been initialized known invalid value; if we see this invalid * -+ * value later, we will know we are on a non-selinux kernel. */ -+ if( selinux_enabled ) -+ { -+ if (getcon(&context) && just_context) -+ error (1, 0, "can't get process context"); -+ } -+#endif -+ -+ if (just_user + just_group + just_group_list + just_context > 1) -+ error (EXIT_FAILURE, 0, _("cannot print \"only\" of more than one choice")); - - if (just_user + just_group + just_group_list == 0 && (use_real | use_name)) - error (EXIT_FAILURE, 0, -@@ -183,6 +236,10 @@ - print_group (use_real ? rgid : egid); - else if (just_group_list) - print_group_list (argv[optind]); -+#ifdef WITH_SELINUX -+ else if (just_context) -+ print_context (context); -+#endif - else - print_full_info (argv[optind]); - putchar ('\n'); -@@ -409,2 +466,7 @@ - #endif /* HAVE_GETGROUPS */ -+#ifdef WITH_SELINUX -+ if ( context != NULL ) { -+ printf(" context=%s",context); -+ } -+#endif - } ---- coreutils-5.97/src/copy.c.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/src/copy.c 2006-11-17 13:56:55.000000000 +0000 -@@ -52,6 +52,11 @@ +--- coreutils-6.7/src/copy.c.selinux 2006-12-07 07:01:16.000000000 +0000 ++++ coreutils-6.7/src/copy.c 2007-01-09 18:24:58.000000000 +0000 +@@ -53,6 +53,11 @@ #include "xreadlink.h" #include "yesno.h" @@ -2279,12 +2006,12 @@ +extern int selinux_enabled; +#endif + - #ifndef HAVE_FCHMOD - # define HAVE_FCHMOD false - #endif -@@ -239,6 +244,30 @@ + #ifndef HAVE_FCHOWN + # define HAVE_FCHOWN false + # define fchown(fd, uid, gid) (-1) +@@ -301,6 +306,30 @@ { - dest_desc = open (dst_name, O_WRONLY | O_TRUNC | O_BINARY, dst_mode); + dest_desc = open (dst_name, O_WRONLY | O_TRUNC | O_BINARY); +#ifdef WITH_SELINUX + if (dest_desc >= 0 && selinux_enabled && @@ -2313,7 +2040,7 @@ if (dest_desc < 0 && x->unlink_dest_after_failed_open) { if (unlink (dst_name) != 0) -@@ -1411,6 +1440,32 @@ +@@ -1520,6 +1549,32 @@ In such cases, set this variable to zero. */ preserve_metadata = true; @@ -2346,7 +2073,7 @@ if (S_ISDIR (src_mode)) { struct dir_list *dir; -@@ -1481,7 +1536,13 @@ +@@ -1595,7 +1650,13 @@ /* Are we crossing a file system boundary? */ if (x->one_file_system && device != 0 && device != src_sb.st_dev) @@ -2361,7 +2088,7 @@ /* Copy the contents of the directory. */ -@@ -1617,6 +1678,11 @@ +@@ -1740,6 +1801,11 @@ } } @@ -2373,7 +2100,7 @@ /* There's no need to preserve timestamps or permissions. */ preserve_metadata = false; -@@ -1755,6 +1821,11 @@ +@@ -1873,6 +1939,11 @@ un_backup: @@ -2385,107 +2112,173 @@ /* We have failed to create the destination file. If we've just added a dev/ino entry via the remember_copied call above (i.e., unless we've just failed to create a hard link), ---- coreutils-5.97/src/mknod.c.selinux 2005-05-14 08:58:37.000000000 +0100 -+++ coreutils-5.97/src/mknod.c 2006-11-17 13:56:55.000000000 +0000 -@@ -36,8 +36,15 @@ - /* The name this program was run with. */ - char *program_name; +--- coreutils-6.7/src/install.c.selinux 2006-12-04 09:00:28.000000000 +0000 ++++ coreutils-6.7/src/install.c 2007-01-09 18:24:58.000000000 +0000 +@@ -49,6 +49,43 @@ + # include + #endif +#ifdef WITH_SELINUX -+#include ++#include /* for is_selinux_enabled() */ ++int selinux_enabled=0; ++static int use_default_selinux_context = 1; ++/* Modify file context to match the specified policy, ++ If an error occurs the file will remain with the default directory ++ context.*/ ++static void setdefaultfilecon(const char *path) { ++ struct stat st; ++ security_context_t scontext=NULL; ++ if (selinux_enabled != 1) { ++ /* Indicate no context found. */ ++ return; ++ } ++ if (lstat(path, &st) != 0) ++ return; ++ ++ /* If there's an error determining the context, or it has none, ++ return to allow default context */ ++ if ((matchpathcon(path, st.st_mode, &scontext) != 0) || ++ (strcmp(scontext, "<>") == 0)) { ++ if (scontext != NULL) { ++ freecon(scontext); ++ } ++ return; ++ } ++ if (lsetfilecon(path, scontext) < 0) { ++ if (errno != ENOTSUP) { ++ error (0, errno, ++ _("warning: failed to change context of %s to %s"), path, scontext); ++ } ++ } ++ freecon(scontext); ++ return; ++} +#endif + - static struct option const longopts[] = + #if ! HAVE_ENDGRENT + # define endgrent() ((void) 0) + #endif +@@ -124,12 +161,18 @@ + static struct option const long_options[] = { + {"backup", optional_argument, NULL, 'b'}, +#ifdef WITH_SELINUX + {"context", required_argument, NULL, 'Z'}, +#endif + {"directory", no_argument, NULL, 'd'}, + {"group", required_argument, NULL, 'g'}, {"mode", required_argument, NULL, 'm'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, -@@ -58,6 +65,11 @@ - Create the special file NAME of the given TYPE.\n\ - \n\ - "), stdout); + {"no-target-directory", no_argument, NULL, 'T'}, + {"owner", required_argument, NULL, 'o'}, + {"preserve-timestamps", no_argument, NULL, 'p'}, +#ifdef WITH_SELINUX -+ fputs(_("\ -+ -Z, --context=CONTEXT set security context (quoted string)\n\ -+"), stdout); ++ {"preserve_context", no_argument, NULL, 'P'}, +#endif - fputs (_("\ - Mandatory arguments to long options are mandatory for short options too.\n\ - "), stdout); -@@ -103,13 +115,31 @@ + {"strip", no_argument, NULL, 's'}, + {"suffix", required_argument, NULL, 'S'}, + {"target-directory", required_argument, NULL, 't'}, +@@ -169,6 +212,10 @@ + x->stdin_tty = false; - specified_mode = NULL; + x->update = false; ++#ifdef WITH_SELINUX ++ x->preserve_security_context = false; ++ x->set_security_context = false; ++#endif + x->verbose = false; + x->dest_info = NULL; + x->src_info = NULL; +@@ -222,6 +269,10 @@ + bool no_target_directory = false; + int n_files; + char **file; ++#ifdef WITH_SELINUX ++ /* set iff kernel has extra selinux system calls */ ++ selinux_enabled = (is_selinux_enabled()>0); ++#endif + + initialize_main (&argc, &argv); + program_name = argv[0]; +@@ -243,7 +294,11 @@ + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); +#ifdef WITH_SELINUX -+ while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1) ++ while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pPt:TvS:Z:", long_options, +#else - while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:", long_options, +#endif + NULL)) != -1) { switch (optc) - { - case 'm': - specified_mode = optarg; +@@ -305,6 +360,41 @@ + case 'T': + no_target_directory = true; break; +#ifdef WITH_SELINUX ++ case 'P': ++ /* politely decline if we're not on a selinux-enabled kernel. */ ++ if( !selinux_enabled ) { ++ fprintf( stderr, "Warning: ignoring --preserve_context (-P) " ++ "because the kernel is not selinux-enabled.\n" ); ++ break; ++ } ++ if ( x.set_security_context ) { ++ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]); ++ exit( 1 ); ++ } ++ x.preserve_security_context = true; ++ use_default_selinux_context = 0; ++ break ; + case 'Z': + /* politely decline if we're not on a selinux-enabled kernel. */ -+ if( !(is_selinux_enabled()>0)) { -+ fprintf( stderr, "Sorry, --context (-Z) can be used only on " -+ "a selinux-enabled kernel.\n" ); ++ if( !selinux_enabled) { ++ fprintf( stderr, "Warning: ignoring --context (-Z) " ++ "because the kernel is not selinux-enabled.\n" ); ++ break; ++ } ++ if ( x.preserve_security_context ) { ++ ++ (void) fprintf(stderr, "%s: cannot force target context == '%s' and preserve it\n", argv[0], optarg); + exit( 1 ); + } ++ use_default_selinux_context = 0; ++ x.set_security_context = true; + if (setfscreatecon(optarg)) { -+ fprintf( stderr, "Sorry, cannot set default context to %s.\n", optarg); -+ exit( 1 ); -+ } ++ (void) fprintf(stderr, "%s: cannot setup default context == '%s'\n", argv[0], optarg); ++ exit(1); ++ } + break; +#endif case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: ---- coreutils-5.97/README.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/README 2006-11-17 13:56:55.000000000 +0000 -@@ -8,11 +8,11 @@ - The programs that can be built with this package are: +@@ -523,6 +613,10 @@ + else + return true; - [ base64 -- basename cat chgrp chmod chown chroot cksum comm cp csplit cut date dd -+ basename cat chcon chgrp chmod chown chroot cksum comm cp csplit cut date dd - df dir dircolors dirname du echo env expand expr factor false fmt fold - ginstall groups head hostid hostname id join kill link ln logname ls - md5sum mkdir mkfifo mknod mv nice nl nohup od paste pathchk pinky pr -- printenv printf ptx pwd readlink rm rmdir runuser seq sha1sum sha224sum -+ printenv printf ptx pwd readlink rm rmdir runcon runuser seq sha1sum sha224sum - sha256sum sha384sum sha512sum shred sleep sort - split stat stty su sum sync tac tail tee test touch tr true tsort tty - uname unexpand uniq unlink uptime users vdir wc who whoami yes ---- coreutils-5.97/tests/help-version.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/tests/help-version 2006-11-17 13:56:55.000000000 +0000 -@@ -46,6 +46,8 @@ ++#ifdef WITH_SELINUX ++ if (use_default_selinux_context) ++ setdefaultfilecon(name); ++#endif + return false; + } - # Skip `test'; it doesn't accept --help or --version. - test $i = test && continue; -+ test $i = chcon && continue; -+ test $i = runcon && continue; - - # false fails even when invoked with --help or --version. - if test $i = false; then -@@ -162,7 +164,7 @@ - - for i in $all_programs; do - # Skip these. -- case $i in chroot|stty|tty|false) continue;; esac -+ case $i in chroot|stty|tty|false|chcon|runcon) continue;; esac - - rm -rf $tmp_in $tmp_in2 $tmp_dir $tmp_out - echo > $tmp_in ---- coreutils-5.97/configure.ac.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/configure.ac 2006-11-17 13:56:55.000000000 +0000 -@@ -34,6 +34,13 @@ +@@ -688,6 +782,11 @@ + -T, --no-target-directory treat DEST as a normal file\n\ + -v, --verbose print the name of each directory as it is created\n\ + "), stdout); ++ fputs (_("\ ++ -P, --preserve_context (SELinux) Preserve security context\n\ ++ -Z, --context=CONTEXT (SELinux) Set security context of files and directories\n\ ++"), stdout); ++ + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +--- coreutils-6.7/configure.ac.selinux 2007-01-09 18:24:55.000000000 +0000 ++++ coreutils-6.7/configure.ac 2007-01-09 18:24:58.000000000 +0000 +@@ -46,6 +46,13 @@ LIB_PAM="-ldl -lpam -lpam_misc" AC_SUBST(LIB_PAM)]) @@ -2496,164 +2289,11 @@ +LIB_SELINUX="-lselinux" +AC_SUBST(LIB_SELINUX)]) + - gl_DEFAULT_POSIX2_VERSION - gl_USE_SYSTEM_EXTENSIONS - gl_PERL ---- coreutils-5.97/config.hin.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/config.hin 2006-11-17 13:56:55.000000000 +0000 -@@ -411,10 +411,6 @@ - don't. */ - #undef HAVE_DECL_TTYNAME - --/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. -- */ --#undef HAVE_DECL_TZNAME -- - /* Define to 1 if you have the declaration of wcwidth(), and to 0 otherwise. - */ - #undef HAVE_DECL_WCWIDTH -@@ -519,6 +515,9 @@ - /* Define to 1 if you have the `getdelim' function. */ - #undef HAVE_GETDELIM - -+/* Define to 1 if you have the `getgrouplist' function. */ -+#undef HAVE_GETGROUPLIST -+ - /* Define to 1 if your system has a working `getgroups' function. */ - #undef HAVE_GETGROUPS - -@@ -613,9 +612,6 @@ - /* Define to 1 if you have the `lchown' function. */ - #undef HAVE_LCHOWN - --/* Define to 1 if you have the `acl' library (-lacl). */ --#undef HAVE_LIBACL -- - /* Define to 1 if you have the `dgc' library (-ldgc). */ - #undef HAVE_LIBDGC - -@@ -643,10 +639,6 @@ - /* Define if you have the 'long double' type. */ - #undef HAVE_LONG_DOUBLE - --/* Define to 1 if the type `long double' works and has more range or precision -- than `double'. */ --#undef HAVE_LONG_DOUBLE_WIDER -- - /* Define to 1 if you support file names longer than 14 characters. */ - #undef HAVE_LONG_FILE_NAMES - -@@ -1442,7 +1434,7 @@ - - /* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be -- automatically deduced at runtime. -+ automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -@@ -1529,17 +1521,17 @@ - /* Define to 1 if unlink (dir) cannot possibly succeed. */ - #undef UNLINK_CANNOT_UNLINK_DIR - --/* Define to 1 if you want getc etc. to use unlocked I/O if available. -- Unlocked I/O can improve performance in unithreaded apps, but it is not -- safe for multithreaded apps. */ --#undef USE_UNLOCKED_IO -- - /* Define if you want access control list support. */ - #undef USE_ACL - - /* Define if you want to use PAM */ - #undef USE_PAM - -+/* Define to 1 if you want getc etc. to use unlocked I/O if available. -+ Unlocked I/O can improve performance in unithreaded apps, but it is not -+ safe for multithreaded apps. */ -+#undef USE_UNLOCKED_IO -+ - /* Version number of package */ - #undef VERSION - -@@ -1549,6 +1541,9 @@ - /* Define if sys/ptem.h is required for struct winsize. */ - #undef WINSIZE_IN_PTEM - -+/* Define if you want to use SELINUX */ -+#undef WITH_SELINUX -+ - /* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ - #undef WORDS_BIGENDIAN -@@ -1694,7 +1689,7 @@ - /* Define to rpl_nanosleep if the replacement function should be used. */ - #undef nanosleep - --/* Define to `long int' if does not define. */ -+/* Define to `long' if does not define. */ - #undef off_t - - /* Define to `int' if does not define. */ -@@ -1761,7 +1756,7 @@ - /* Define to empty if the C compiler doesn't support this keyword. */ - #undef signed - --/* Define to `unsigned int' if does not define. */ -+/* Define to `unsigned' if does not define. */ - #undef size_t - - /* Map `socklen_t' to `int' if it is missing. */ ---- coreutils-5.97/man/ls.1.selinux 2006-06-01 08:33:14.000000000 +0100 -+++ coreutils-5.97/man/ls.1 2006-11-17 13:56:55.000000000 +0000 -@@ -201,6 +201,20 @@ - .TP - \fB\-1\fR - list one file per line -+.PP -+SELinux options: -+.TP -+\fB\-\-lcontext\fR -+Display security context. Enable \fB\-l\fR. Lines -+will probably be too wide for most displays. -+.TP -+\fB\-Z\fR, \fB\-\-context\fR -+Display security context so it fits on most -+displays. Displays only mode, user, group, -+security context and file name. -+.TP -+\fB\-\-scontext\fR -+Display only security context and file name. - .TP - \fB\-\-help\fR - display this help and exit ---- coreutils-5.97/man/install.1.selinux 2006-05-25 18:27:35.000000000 +0100 -+++ coreutils-5.97/man/install.1 2006-11-17 13:56:55.000000000 +0000 -@@ -65,6 +65,11 @@ - .TP - \fB\-v\fR, \fB\-\-verbose\fR - print the name of each directory as it is created -+.HP -+\fB\-P\fR, \fB\-\-preserve_context\fR (SELinux) Preserve security context -+.TP -+\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR -+(SELinux) Set security context of files and directories - .TP - \fB\-\-help\fR - display this help and exit ---- coreutils-5.97/man/id.1.selinux 2006-05-25 18:27:35.000000000 +0100 -+++ coreutils-5.97/man/id.1 2006-11-17 16:26:50.000000000 +0000 -@@ -13,6 +13,9 @@ - \fB\-a\fR - ignore, for compatibility with other versions - .TP -+\fB\-Z\fR, \fB\-\-context\fR -+print only the security context of the current process -+.TP - \fB\-g\fR, \fB\-\-group\fR - print only the effective group ID - .TP ---- coreutils-5.97/man/stat.1.selinux 2006-05-25 18:27:38.000000000 +0100 -+++ coreutils-5.97/man/stat.1 2006-11-17 13:56:55.000000000 +0000 + AC_CHECK_FUNCS(uname, + OPTIONAL_BIN_PROGS="$OPTIONAL_BIN_PROGS uname\$(EXEEXT)" + MAN="$MAN uname.1") +--- coreutils-6.7/man/stat.1.selinux 2006-12-07 22:45:45.000000000 +0000 ++++ coreutils-6.7/man/stat.1 2007-01-09 18:24:58.000000000 +0000 @@ -28,6 +28,9 @@ \fB\-t\fR, \fB\-\-terse\fR print the information in terse form @@ -2674,202 +2314,15 @@ %D Device number in hex .TP ---- /dev/null 2006-11-23 08:31:37.745607750 +0000 -+++ coreutils-5.97/man/runcon.1 2006-11-17 13:56:55.000000000 +0000 -@@ -0,0 +1,45 @@ -+.TH RUNCON "1" "February 2005" "runcon (coreutils) 5.0" "selinux" -+.SH NAME -+runcon \- run command with specified security context -+.SH SYNOPSIS -+.B runcon -+[\fI-c\fR] [\fI-t TYPE\fR] [\fI-l LEVEL\fR] [\fI-u USER\fR] [\fI-r ROLE\fR] \fICOMMAND\fR [\fIARGS...\fR] -+.PP -+or -+.PP -+.B runcon -+\fICONTEXT\fR \fICOMMAND\fR [\fIargs...\fR] -+.PP -+.br -+.SH DESCRIPTION -+.PP -+.\" Add any additional description here -+.PP -+Run COMMAND with completely-specified CONTEXT, or with current or -+transitioned security context modified by one or more of LEVEL, -+ROLE, TYPE, and USER. -+.TP -+\fB\-c\fR -+compute process transition before modifying context -+.TP -+\fB\-t\fR -+change current type to the specified type -+.TP -+\fB\-l\fR -+change current level range to the specified range -+.TP -+\fB\-r\fR -+change current role to the specified role -+.TP -+\fB\-u\fR -+change current user to the specified user -+.TP -+\fB\-\-\fR -+The \fB\-\-\fR flag indicates that \fBruncon\fR should stop processing command -+line arguments. Further arguments will be passed to COMMAND. -+.PP -+If none of \fI-c\fR, \fI-t\fR, \fI-u\fR, \fI-r\fR, or \fI-l\fR, is specified, -+the first argument is used as the complete context. -+.PP -+Note that only carefully-chosen contexts are likely to successfully -+run. ---- coreutils-5.97/man/Makefile.am.selinux 2006-11-17 13:56:55.000000000 +0000 -+++ coreutils-5.97/man/Makefile.am 2006-11-17 13:56:55.000000000 +0000 -@@ -11,7 +11,7 @@ - shred.1 sleep.1 sort.1 split.1 stat.1 stty.1 \ - su.1 sum.1 sync.1 tac.1 tail.1 tee.1 test.1 touch.1 tr.1 true.1 tsort.1 \ - tty.1 uname.1 unexpand.1 uniq.1 unlink.1 uptime.1 users.1 vdir.1 wc.1 \ -- who.1 whoami.1 yes.1 -+ who.1 whoami.1 yes.1 chcon.1 runcon.1 - - man_aux = $(dist_man_MANS:.1=.x) - -@@ -119,6 +119,8 @@ - who.1: $(common_dep) $(srcdir)/who.x ../src/who.c - whoami.1: $(common_dep) $(srcdir)/whoami.x ../src/whoami.c - yes.1: $(common_dep) $(srcdir)/yes.x ../src/yes.c -+chcon.1: $(common_dep) $(srcdir)/chcon.x ../src/chcon.c -+runcon.1: $(common_dep) $(srcdir)/runcon.x ../src/runcon.c - - SUFFIXES = .x .1 - ---- coreutils-5.97/man/cp.1.selinux 2006-05-25 18:27:33.000000000 +0100 -+++ coreutils-5.97/man/cp.1 2006-11-17 13:56:55.000000000 +0000 -@@ -57,7 +57,7 @@ - .TP - \fB\-\-preserve\fR[=\fIATTR_LIST\fR] - preserve the specified attributes (default: --mode,ownership,timestamps), if possible -+mode,ownership,timestamps) and security contexts, if possible - additional attributes: links, all - .TP - \fB\-\-no\-preserve\fR=\fIATTR_LIST\fR -@@ -105,6 +105,9 @@ - \fB\-\-help\fR - display this help and exit - .TP -+\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR -+set security context of copy to CONTEXT -+.TP - \fB\-\-version\fR - output version information and exit - .PP ---- coreutils-5.97/man/mkfifo.1.selinux 2006-05-25 18:27:36.000000000 +0100 -+++ coreutils-5.97/man/mkfifo.1 2006-11-17 13:56:55.000000000 +0000 -@@ -12,6 +12,9 @@ - .PP - Mandatory arguments to long options are mandatory for short options too. - .TP -+\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR -+set security context (quoted string) -+.TP - \fB\-m\fR, \fB\-\-mode\fR=\fIMODE\fR - set permission mode (as in chmod), not a=rw \- umask - .TP ---- coreutils-5.97/man/mknod.1.selinux 2006-05-25 18:27:36.000000000 +0100 -+++ coreutils-5.97/man/mknod.1 2006-11-17 13:56:55.000000000 +0000 -@@ -12,6 +12,9 @@ - .PP - Mandatory arguments to long options are mandatory for short options too. - .TP -+\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR -+set security context (quoted string) -+.TP - \fB\-m\fR, \fB\-\-mode\fR=\fIMODE\fR - set permission mode (as in chmod), not a=rw \- umask - .TP ---- coreutils-5.97/man/mkdir.1.selinux 2006-05-25 18:27:35.000000000 +0100 -+++ coreutils-5.97/man/mkdir.1 2006-11-17 13:56:55.000000000 +0000 -@@ -12,6 +12,8 @@ - .PP - Mandatory arguments to long options are mandatory for short options too. - .TP -+\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR (SELinux) set security context to CONTEXT -+.TP - \fB\-m\fR, \fB\-\-mode\fR=\fIMODE\fR - set permission mode (as in chmod), not rwxrwxrwx \- umask - .TP ---- coreutils-5.97/man/dir.1.selinux 2006-06-01 08:33:14.000000000 +0100 -+++ coreutils-5.97/man/dir.1 2006-11-17 13:56:55.000000000 +0000 -@@ -201,6 +201,20 @@ - .TP - \fB\-1\fR - list one file per line -+.PP -+SELINUX options: -+.TP -+\fB\-\-lcontext\fR -+Display security context. Enable \fB\-l\fR. Lines -+will probably be too wide for most displays. -+.TP -+\fB\-\-context\fR -+Display security context so it fits on most -+displays. Displays only mode, user, group, -+security context and file name. -+.TP -+\fB\-\-scontext\fR -+Display only security context and file name. - .TP - \fB\-\-help\fR - display this help and exit ---- /dev/null 2006-11-23 08:31:37.745607750 +0000 -+++ coreutils-5.97/man/runcon.x 2006-11-17 13:56:55.000000000 +0000 -@@ -0,0 +1,14 @@ -+[NAME] -+runcon \- run command with specified security context -+[DESCRIPTION] -+Run COMMAND with completely-specified CONTEXT, or with current or -+transitioned security context modified by one or more of LEVEL, -+ROLE, TYPE, and USER. -+.PP -+If none of \fI-c\fR, \fI-t\fR, \fI-u\fR, \fI-r\fR, or \fI-l\fR, is specified, -+the first argument is used as the complete context. Any additional -+arguments after \fICOMMAND\fR are interpreted as arguments to the -+command. -+.PP -+Note that only carefully-chosen contexts are likely to successfully -+run. ---- coreutils-5.97/man/vdir.1.selinux 2006-06-01 08:33:14.000000000 +0100 -+++ coreutils-5.97/man/vdir.1 2006-11-17 13:56:55.000000000 +0000 -@@ -201,6 +201,20 @@ - .TP - \fB\-1\fR - list one file per line -+.PP -+SELINUX options: -+.TP -+\fB\-\-lcontext\fR -+Display security context. Enable \fB\-l\fR. Lines -+will probably be too wide for most displays. -+.TP -+\fB\-\-context\fR -+Display security context so it fits on most -+displays. Displays only mode, user, group, -+security context and file name. -+.TP -+\fB\-\-scontext\fR -+Display only security context and file name. - .TP - \fB\-\-help\fR - display this help and exit ---- /dev/null 2006-11-23 08:31:37.745607750 +0000 -+++ coreutils-5.97/man/chcon.x 2006-11-17 13:56:55.000000000 +0000 +--- /dev/null 2007-01-09 12:27:07.480840763 +0000 ++++ coreutils-6.7/man/chcon.x 2007-01-09 18:24:58.000000000 +0000 @@ -0,0 +1,4 @@ +[NAME] +chcon \- change file security context +[DESCRIPTION] +.\" Add any additional description here ---- /dev/null 2006-11-23 08:31:37.745607750 +0000 -+++ coreutils-5.97/man/chcon.1 2006-11-17 13:56:55.000000000 +0000 +--- /dev/null 2007-01-09 12:27:07.480840763 +0000 ++++ coreutils-6.7/man/chcon.1 2007-01-09 18:24:58.000000000 +0000 @@ -0,0 +1,64 @@ +.TH CHCON 1 "July 2003" "chcon (coreutils) 5.0" "User Commands" +.SH NAME @@ -2935,3 +2388,255 @@ +.B info chcon +.PP +should give you access to the complete manual. +--- coreutils-6.7/man/dir.1.selinux 2006-12-07 22:45:41.000000000 +0000 ++++ coreutils-6.7/man/dir.1 2007-01-09 18:24:58.000000000 +0000 +@@ -204,6 +204,20 @@ + .TP + \fB\-1\fR + list one file per line ++.PP ++SELINUX options: ++.TP ++\fB\-\-lcontext\fR ++Display security context. Enable \fB\-l\fR. Lines ++will probably be too wide for most displays. ++.TP ++\fB\-\-context\fR ++Display security context so it fits on most ++displays. Displays only mode, user, group, ++security context and file name. ++.TP ++\fB\-\-scontext\fR ++Display only security context and file name. + .TP + \fB\-\-help\fR + display this help and exit +--- coreutils-6.7/man/mkfifo.1.selinux 2006-12-07 22:45:43.000000000 +0000 ++++ coreutils-6.7/man/mkfifo.1 2007-01-09 18:24:58.000000000 +0000 +@@ -12,6 +12,9 @@ + .PP + Mandatory arguments to long options are mandatory for short options too. + .TP ++\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR ++set security context (quoted string) ++.TP + \fB\-m\fR, \fB\-\-mode\fR=\fIMODE\fR + set file permission bits to MODE, not a=rw \- umask + .TP +--- coreutils-6.7/man/Makefile.am.selinux 2007-01-09 18:24:56.000000000 +0000 ++++ coreutils-6.7/man/Makefile.am 2007-01-09 18:24:58.000000000 +0000 +@@ -30,7 +30,7 @@ + shred.1 shuf.1 sleep.1 sort.1 split.1 stat.1 \ + su.1 sum.1 sync.1 tac.1 tail.1 tee.1 test.1 touch.1 tr.1 true.1 tsort.1 \ + tty.1 unexpand.1 uniq.1 unlink.1 vdir.1 wc.1 \ +- whoami.1 yes.1 $(MAN) ++ whoami.1 yes.1 chcon.1 runcon.1 $(MAN) + optional_mans = \ + chroot.1 hostid.1 nice.1 pinky.1 stty.1 uname.1 uptime.1 users.1 who.1 + +@@ -142,6 +142,8 @@ + who.1: $(common_dep) $(srcdir)/who.x ../src/who.c + whoami.1: $(common_dep) $(srcdir)/whoami.x ../src/whoami.c + yes.1: $(common_dep) $(srcdir)/yes.x ../src/yes.c ++chcon.1: $(common_dep) $(srcdir)/chcon.x ../src/chcon.c ++runcon.1: $(common_dep) $(srcdir)/runcon.x ../src/runcon.c + + SUFFIXES = .x .1 + +--- coreutils-6.7/man/cp.1.selinux 2006-12-07 22:45:41.000000000 +0000 ++++ coreutils-6.7/man/cp.1 2007-01-09 18:24:58.000000000 +0000 +@@ -57,7 +57,7 @@ + .TP + \fB\-\-preserve\fR[=\fIATTR_LIST\fR] + preserve the specified attributes (default: +-mode,ownership,timestamps), if possible ++mode,ownership,timestamps) and security contexts, if possible + additional attributes: links, all + .TP + \fB\-\-no\-preserve\fR=\fIATTR_LIST\fR +@@ -106,6 +106,9 @@ + \fB\-\-help\fR + display this help and exit + .TP ++\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR ++set security context of copy to CONTEXT ++.TP + \fB\-\-version\fR + output version information and exit + .PP +--- coreutils-6.7/man/id.1.selinux 2006-12-07 22:45:42.000000000 +0000 ++++ coreutils-6.7/man/id.1 2007-01-09 18:24:58.000000000 +0000 +@@ -13,6 +13,9 @@ + \fB\-a\fR + ignore, for compatibility with other versions + .TP ++\fB\-Z\fR, \fB\-\-context\fR ++print only the security context of the current process ++.TP + \fB\-g\fR, \fB\-\-group\fR + print only the effective group ID + .TP +--- /dev/null 2007-01-09 12:27:07.480840763 +0000 ++++ coreutils-6.7/man/runcon.x 2007-01-09 18:24:59.000000000 +0000 +@@ -0,0 +1,14 @@ ++[NAME] ++runcon \- run command with specified security context ++[DESCRIPTION] ++Run COMMAND with completely-specified CONTEXT, or with current or ++transitioned security context modified by one or more of LEVEL, ++ROLE, TYPE, and USER. ++.PP ++If none of \fI-c\fR, \fI-t\fR, \fI-u\fR, \fI-r\fR, or \fI-l\fR, is specified, ++the first argument is used as the complete context. Any additional ++arguments after \fICOMMAND\fR are interpreted as arguments to the ++command. ++.PP ++Note that only carefully-chosen contexts are likely to successfully ++run. +--- /dev/null 2007-01-09 12:27:07.480840763 +0000 ++++ coreutils-6.7/man/runcon.1 2007-01-09 18:24:59.000000000 +0000 +@@ -0,0 +1,45 @@ ++.TH RUNCON "1" "February 2005" "runcon (coreutils) 5.0" "selinux" ++.SH NAME ++runcon \- run command with specified security context ++.SH SYNOPSIS ++.B runcon ++[\fI-c\fR] [\fI-t TYPE\fR] [\fI-l LEVEL\fR] [\fI-u USER\fR] [\fI-r ROLE\fR] \fICOMMAND\fR [\fIARGS...\fR] ++.PP ++or ++.PP ++.B runcon ++\fICONTEXT\fR \fICOMMAND\fR [\fIargs...\fR] ++.PP ++.br ++.SH DESCRIPTION ++.PP ++.\" Add any additional description here ++.PP ++Run COMMAND with completely-specified CONTEXT, or with current or ++transitioned security context modified by one or more of LEVEL, ++ROLE, TYPE, and USER. ++.TP ++\fB\-c\fR ++compute process transition before modifying context ++.TP ++\fB\-t\fR ++change current type to the specified type ++.TP ++\fB\-l\fR ++change current level range to the specified range ++.TP ++\fB\-r\fR ++change current role to the specified role ++.TP ++\fB\-u\fR ++change current user to the specified user ++.TP ++\fB\-\-\fR ++The \fB\-\-\fR flag indicates that \fBruncon\fR should stop processing command ++line arguments. Further arguments will be passed to COMMAND. ++.PP ++If none of \fI-c\fR, \fI-t\fR, \fI-u\fR, \fI-r\fR, or \fI-l\fR, is specified, ++the first argument is used as the complete context. ++.PP ++Note that only carefully-chosen contexts are likely to successfully ++run. +--- coreutils-6.7/man/mknod.1.selinux 2006-12-07 22:45:43.000000000 +0000 ++++ coreutils-6.7/man/mknod.1 2007-01-09 18:24:59.000000000 +0000 +@@ -12,6 +12,9 @@ + .PP + Mandatory arguments to long options are mandatory for short options too. + .TP ++\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR ++set security context (quoted string) ++.TP + \fB\-m\fR, \fB\-\-mode\fR=\fIMODE\fR + set file permission bits to MODE, not a=rw \- umask + .TP +--- coreutils-6.7/man/ls.1.selinux 2006-12-07 22:45:42.000000000 +0000 ++++ coreutils-6.7/man/ls.1 2007-01-09 18:24:59.000000000 +0000 +@@ -204,6 +204,20 @@ + .TP + \fB\-1\fR + list one file per line ++.PP ++SELinux options: ++.TP ++\fB\-\-lcontext\fR ++Display security context. Enable \fB\-l\fR. Lines ++will probably be too wide for most displays. ++.TP ++\fB\-Z\fR, \fB\-\-context\fR ++Display security context so it fits on most ++displays. Displays only mode, user, group, ++security context and file name. ++.TP ++\fB\-\-scontext\fR ++Display only security context and file name. + .TP + \fB\-\-help\fR + display this help and exit +--- coreutils-6.7/man/mkdir.1.selinux 2006-12-07 22:45:43.000000000 +0000 ++++ coreutils-6.7/man/mkdir.1 2007-01-09 18:24:59.000000000 +0000 +@@ -12,6 +12,8 @@ + .PP + Mandatory arguments to long options are mandatory for short options too. + .TP ++\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR (SELinux) set security context to CONTEXT ++.TP + \fB\-m\fR, \fB\-\-mode\fR=\fIMODE\fR + set file mode (as in chmod), not a=rwx \- umask + .TP +--- coreutils-6.7/man/vdir.1.selinux 2006-12-07 22:45:46.000000000 +0000 ++++ coreutils-6.7/man/vdir.1 2007-01-09 18:24:59.000000000 +0000 +@@ -204,6 +204,20 @@ + .TP + \fB\-1\fR + list one file per line ++.PP ++SELINUX options: ++.TP ++\fB\-\-lcontext\fR ++Display security context. Enable \fB\-l\fR. Lines ++will probably be too wide for most displays. ++.TP ++\fB\-\-context\fR ++Display security context so it fits on most ++displays. Displays only mode, user, group, ++security context and file name. ++.TP ++\fB\-\-scontext\fR ++Display only security context and file name. + .TP + \fB\-\-help\fR + display this help and exit +--- coreutils-6.7/man/install.1.selinux 2006-12-07 22:45:42.000000000 +0000 ++++ coreutils-6.7/man/install.1 2007-01-09 18:24:59.000000000 +0000 +@@ -66,6 +66,11 @@ + .TP + \fB\-v\fR, \fB\-\-verbose\fR + print the name of each directory as it is created ++.HP ++\fB\-P\fR, \fB\-\-preserve_context\fR (SELinux) Preserve security context ++.TP ++\fB\-Z\fR, \fB\-\-context\fR=\fICONTEXT\fR ++(SELinux) Set security context of files and directories + .TP + \fB\-\-help\fR + display this help and exit +--- coreutils-6.7/README.selinux 2007-01-09 18:24:56.000000000 +0000 ++++ coreutils-6.7/README 2007-01-09 18:24:59.000000000 +0000 +@@ -7,11 +7,11 @@ + + The programs that can be built with this package are: + +- [ base64 basename cat chgrp chmod chown chroot cksum comm cp csplit cut date ++ [ base64 basename cat chcon chgrp chmod chown chroot cksum comm cp csplit cut date + dd df dir dircolors dirname du echo env expand expr factor false fmt fold + ginstall groups head hostid hostname id join kill link ln logname ls + md5sum mkdir mkfifo mknod mv nice nl nohup od paste pathchk pinky pr +- printenv printf ptx pwd readlink rm rmdir runuser seq sha1sum sha224sum sha256sum ++ printenv printf ptx pwd readlink rm rmdir runcon runuser seq sha1sum sha224sum sha256sum + sha384sum sha512sum shred shuf sleep sort split stat stty su sum sync tac + tail tee test touch tr true tsort tty uname unexpand uniq unlink uptime + users vdir wc who whoami yes diff --git a/coreutils-setsid.patch b/coreutils-setsid.patch index e0eec48..e54535f 100644 --- a/coreutils-setsid.patch +++ b/coreutils-setsid.patch @@ -1,6 +1,6 @@ ---- coreutils-5.97/src/su.c.setsid 2006-07-21 14:09:29.000000000 +0100 -+++ coreutils-5.97/src/su.c 2006-07-21 14:20:28.000000000 +0100 -@@ -199,9 +199,13 @@ +--- coreutils-6.7/src/su.c.setsid 2007-01-09 17:26:26.000000000 +0000 ++++ coreutils-6.7/src/su.c 2007-01-09 17:26:57.000000000 +0000 +@@ -176,9 +176,13 @@ /* If true, change some environment vars to indicate the user su'd to. */ static bool change_environment; @@ -14,7 +14,7 @@ {"fast", no_argument, NULL, 'f'}, {"login", no_argument, NULL, 'l'}, {"preserve-environment", no_argument, NULL, 'p'}, -@@ -497,6 +501,8 @@ +@@ -478,6 +482,8 @@ if (child == 0) { /* child shell */ change_identity (pw); pam_end(pamh, 0); @@ -23,7 +23,7 @@ #endif if (simulate_login) -@@ -551,13 +557,27 @@ +@@ -532,13 +538,27 @@ sigemptyset(&action.sa_mask); action.sa_flags = 0; sigemptyset(&ourset); @@ -55,16 +55,16 @@ } if (!caught) { do { -@@ -628,6 +648,8 @@ +@@ -609,6 +629,8 @@ \n\ -, -l, --login make the shell a login shell\n\ - -c, --commmand=COMMAND pass a single COMMAND to the shell with -c\n\ + -c, --command=COMMAND pass a single COMMAND to the shell with -c\n\ + --session-command=COMMAND pass a single COMMAND to the shell with -c\n\ + and do not create a new session\n\ -f, --fast pass -f to the shell (for csh or tcsh)\n\ -m, --preserve-environment do not reset environment variables\n\ -p same as -m\n\ -@@ -650,6 +672,7 @@ +@@ -631,6 +653,7 @@ int optc; const char *new_user = DEFAULT_USER; char *command = NULL; @@ -72,7 +72,7 @@ char *shell = NULL; struct passwd *pw; struct passwd pw_copy; -@@ -675,6 +698,11 @@ +@@ -656,6 +679,11 @@ command = optarg; break; @@ -84,7 +84,7 @@ case 'f': fast_startup = true; break; -@@ -744,6 +772,9 @@ +@@ -725,6 +753,9 @@ } #endif diff --git a/coreutils.spec b/coreutils.spec index d19a31f..4601e62 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,7 +1,7 @@ Summary: The GNU core utilities: a set of tools commonly used in shell scripts Name: coreutils -Version: 5.97 -Release: 16%{?dist} +Version: 6.7 +Release: 1%{?dist} License: GPL Group: System Environment/Base Url: http://www.gnu.org/software/coreutils/ @@ -20,15 +20,9 @@ Source202: su-l.pamd Source203: runuser-l.pamd # From upstream -Patch1: coreutils-sort-compatibility.patch -Patch2: coreutils-rename.patch -Patch10: coreutils-newhashes.patch # Our patches Patch100: coreutils-chgrp.patch -Patch107: fileutils-4.1.10-timestyle.patch -Patch182: coreutils-acl.patch -Patch183: coreutils-df-cifs.patch # sh-utils Patch703: sh-utils-2.0.11-dateman.patch @@ -47,8 +41,6 @@ Patch900: coreutils-setsid.patch Patch907: coreutils-5.2.1-runuser.patch Patch908: coreutils-getgrouplist.patch Patch912: coreutils-overflow.patch -Patch913: coreutils-afs.patch -Patch914: coreutils-autoconf.patch Patch915: coreutils-split-pam.patch #SELINUX Patch @@ -80,15 +72,9 @@ the old GNU fileutils, sh-utils, and textutils packages. %setup -q # From upstream -%patch1 -p1 -b .sort-compatibility -%patch2 -p1 -b .rename -%patch10 -p1 -b .newhashes # Our patches %patch100 -p1 -b .chgrp -%patch107 -p1 -b .timestyle -%patch182 -p1 -b .acl -%patch183 -p1 -b .df-cifs # sh-utils %patch703 -p1 -b .dateman @@ -105,8 +91,6 @@ the old GNU fileutils, sh-utils, and textutils packages. %patch907 -p1 -b .runuser %patch908 -p1 -b .getgrouplist %patch912 -p1 -b .overflow -%patch913 -p1 -b .afs -%patch914 -p1 -b .autoconf %patch915 -p1 -b .splitl #SELinux @@ -285,6 +269,10 @@ fi /sbin/runuser %changelog +* Tue Jan 9 2007 Tim Waugh 6.7-1 +- 6.7. No longer need sort-compatibility, rename, newhashes, timestyle, + acl, df-cifs, afs or autoconf patches. + * Tue Jan 2 2007 Tim Waugh - Prevent 'su --help' showing runuser-only options such as --group. diff --git a/sources b/sources index 15f2e7e..fafe9fd 100644 --- a/sources +++ b/sources @@ -1 +1,2 @@ 1537379b6264a1def443713988a78020 coreutils-5.97.tar.bz2 +a16465d0856cd011a1acc1c21040b7f4 coreutils-6.7.tar.bz2