diff --git a/.gitignore b/.gitignore index 46d0f92..a8d11c6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,10 @@ -/coreutils-[0-9.]*.tar.xz -/coreutils-[0-9.]*.tar.xz.sig +coreutils-5.2.1.tar.bz2 +coreutils-5.92.tar.bz2 +coreutils-5.93.tar.bz2 +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 +coreutils-6.8+-ss-2007-03-01.11.42.23+0.tar.gz +coreutils-6.9.tar.bz2 diff --git a/STAGE1-coreutils b/STAGE1-coreutils deleted file mode 100644 index bfe73b5..0000000 --- a/STAGE1-coreutils +++ /dev/null @@ -1,7 +0,0 @@ -srpm coreutils -mcd $BUILDDIR/$1 -(cd $SRC/${1}-*/ ; autoreconf -vif) -$SRC/${1}-*/configure $TCONFIGARGS --disable-pam -notparallel -make $J man1_MANS= V=1 -make $J man1_MANS= install DESTDIR=${ROOTFS} diff --git a/coreutils-4.5.3-langinfo.patch b/coreutils-4.5.3-langinfo.patch new file mode 100644 index 0000000..49a88aa --- /dev/null +++ b/coreutils-4.5.3-langinfo.patch @@ -0,0 +1,18 @@ +--- coreutils-5.92/src/date.c.langinfo 2005-09-16 09:06:57.000000000 +0100 ++++ coreutils-5.92/src/date.c 2005-10-24 18:09:16.000000000 +0100 +@@ -451,14 +451,7 @@ + format = DATE_FMT_LANGINFO (); + if (! *format) + { +- /* Do not wrap the following literal format string with _(...). +- For example, suppose LC_ALL is unset, LC_TIME="POSIX", +- and LANG="ko_KR". In that case, POSIX says that LC_TIME +- determines the format and contents of date and time strings +- written by date, which means "date" must generate output +- using the POSIX locale; but adding _() would cause "date" +- to use a Korean translation of the format. */ +- format = "%a %b %e %H:%M:%S %Z %Y"; ++ format = dcgettext(NULL, N_("%a %b %e %H:%M:%S %Z %Y"), LC_TIME); + } + } + diff --git a/coreutils-4.5.3-sysinfo.patch b/coreutils-4.5.3-sysinfo.patch new file mode 100644 index 0000000..cd22a2b --- /dev/null +++ b/coreutils-4.5.3-sysinfo.patch @@ -0,0 +1,72 @@ +--- coreutils-5.97/src/uname.c.sysinfo 2005-09-15 20:57:04.000000000 +0100 ++++ coreutils-5.97/src/uname.c 2006-08-24 17:15:56.000000000 +0100 +@@ -155,7 +155,7 @@ + main (int argc, char **argv) + { + int c; +- static char const unknown[] = "unknown"; ++ static char unknown[] = "unknown"; + + /* Mask indicating which elements to print. */ + unsigned int toprint = 0; +@@ -249,13 +249,35 @@ + + if (toprint & PRINT_PROCESSOR) + { +- char const *element = unknown; ++ char *element = unknown; + #if HAVE_SYSINFO && defined SI_ARCHITECTURE + { + static char processor[257]; + if (0 <= sysinfo (SI_ARCHITECTURE, processor, sizeof processor)) + element = processor; + } ++#else ++ { ++ struct utsname u; ++ uname(&u); ++ element = u.machine; ++#ifdef linux ++ if(!strcmp(element, "i686")) { /* Check for Athlon */ ++ char cinfo[1024]; ++ FILE *f=fopen("/proc/cpuinfo", "r"); ++ if(f) { ++ while(fgets(cinfo, 1024, f)) { ++ if(!strncmp(cinfo, "vendor_id", 9)) { ++ if(strstr(cinfo, "AuthenticAMD")) ++ element="athlon"; ++ break; ++ } ++ } ++ fclose(f); ++ } ++ } ++#endif ++ } + #endif + #ifdef UNAME_PROCESSOR + if (element == unknown) +@@ -293,7 +315,7 @@ + + if (toprint & PRINT_HARDWARE_PLATFORM) + { +- char const *element = unknown; ++ char *element = unknown; + #if HAVE_SYSINFO && defined SI_PLATFORM + { + static char hardware_platform[257]; +@@ -301,6 +323,14 @@ + hardware_platform, sizeof hardware_platform)) + element = hardware_platform; + } ++#else ++ { ++ struct utsname u; ++ uname(&u); ++ element = u.machine; ++ if(strlen(element)==4 && element[0]=='i' && element[2]=='8' && element[3]=='6') ++ element[1]='3'; ++ } + #endif + #ifdef UNAME_HARDWARE_PLATFORM + if (element == unknown) diff --git a/coreutils-5.2.1-runuser.patch b/coreutils-5.2.1-runuser.patch new file mode 100644 index 0000000..88b1db1 --- /dev/null +++ b/coreutils-5.2.1-runuser.patch @@ -0,0 +1,384 @@ +--- 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). */ ++#ifndef RUNUSER + #define PROGRAM_NAME "su" ++#else ++#define PROGRAM_NAME "runuser" ++#endif + ++#ifndef AUTHORS + #define AUTHORS "David MacKenzie" ++#endif + + #if HAVE_PATHS_H + # include +@@ -150,6 +156,10 @@ + #ifndef USE_PAM + char *crypt (); + #endif ++#ifndef CHECKPASSWD ++#define CHECKPASSWD 1 ++#endif ++ + char *getusershell (); + void endusershell (); + void setusershell (); +@@ -157,7 +167,11 @@ + extern char **environ; + + static void run_shell (char const *, char const *, char **, size_t, +- const struct passwd *) ++ const struct passwd * ++#ifdef RUNUSER ++ , gid_t *groups, int num_groups ++#endif ++ ) + #ifdef USE_PAM + ; + #else +@@ -187,6 +201,10 @@ + {"login", no_argument, NULL, 'l'}, + {"preserve-environment", no_argument, NULL, 'p'}, + {"shell", required_argument, NULL, 's'}, ++#ifdef RUNUSER ++ {"group", required_argument, NULL, 'g'}, ++ {"supp-group", required_argument, NULL, 'G'}, ++#endif + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +@@ -288,10 +306,12 @@ + retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh); + PAM_BAIL_P; + ++#ifndef RUNUSER + if (getuid() != 0 && !isatty(0)) { + fprintf(stderr, "standard in must be a tty\n"); + exit(1); + } ++#endif + + caller = getpwuid(getuid()); + if(caller != NULL && caller->pw_name != NULL) { +@@ -308,6 +328,11 @@ + retval = pam_set_item(pamh, PAM_TTY, tty_name); + PAM_BAIL_P; + } ++#ifdef RUNUSER ++ if (getuid() != geteuid()) ++ /* safety net: deny operation if we are suid by accident */ ++ error(EXIT_FAIL, 1, "runuser may not be setuid"); ++#else + retval = pam_authenticate(pamh, 0); + PAM_BAIL_P; + retval = pam_acct_mgmt(pamh, 0); +@@ -317,6 +342,7 @@ + PAM_BAIL_P; + } + PAM_BAIL_P; ++#endif + /* must be authenticated if this point was reached */ + return 1; + #else /* !USE_PAM */ +@@ -398,11 +424,22 @@ + /* Become the user and group(s) specified by PW. */ + + static void +-change_identity (const struct passwd *pw) ++change_identity (const struct passwd *pw ++#ifdef RUNUSER ++ , gid_t *groups, int num_groups ++#endif ++ ) + { + #ifdef HAVE_INITGROUPS ++ int rc = 0; + errno = 0; +- if (initgroups (pw->pw_name, pw->pw_gid) == -1) { ++#ifdef RUNUSER ++ if (num_groups) ++ rc = setgroups(num_groups, groups); ++ else ++#endif ++ rc = initgroups(pw->pw_name, pw->pw_gid); ++ if (rc == -1) { + #ifdef USE_PAM + pam_close_session(pamh, 0); + pam_end(pamh, PAM_ABORT); +@@ -449,7 +486,11 @@ + + static void + run_shell (char const *shell, char const *command, char **additional_args, +- size_t n_additional_args, const struct passwd *pw) ++ size_t n_additional_args, const struct passwd *pw ++#ifdef RUNUSER ++ , gid_t *groups, int num_groups ++#endif ++ ) + { + size_t n_args = 1 + fast_startup + 2 * !!command + n_additional_args + 1; + char const **args = xnmalloc (n_args, sizeof *args); +@@ -480,7 +521,11 @@ + + child = fork(); + if (child == 0) { /* child shell */ +- change_identity (pw); ++ change_identity (pw ++#ifdef RUNUSER ++ , groups, num_groups ++#endif ++ ); + pam_end(pamh, 0); + if (!same_session) + setsid (); +@@ -657,6 +702,12 @@ + char *shell = NULL; + struct passwd *pw; + struct passwd pw_copy; ++#ifdef RUNUSER ++ struct group *gr; ++ gid_t groups[NGROUPS_MAX]; ++ int num_supp_groups = 0; ++ int use_gid = 0; ++#endif + + initialize_main (&argc, &argv); + program_name = argv[0]; +@@ -671,7 +722,11 @@ + simulate_login = false; + change_environment = true; + +- while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, NULL)) != -1) ++ while ((optc = getopt_long (argc, argv, "c:flmps:" ++#ifdef RUNUSER ++ "g:G:" ++#endif ++ , longopts, NULL)) != -1) + { + switch (optc) + { +@@ -701,6 +756,28 @@ + shell = optarg; + break; + ++#ifdef RUNUSER ++ case 'g': ++ gr = getgrnam(optarg); ++ if (!gr) ++ error (EXIT_FAIL, 0, _("group %s does not exist"), optarg); ++ use_gid = 1; ++ groups[0] = gr->gr_gid; ++ break; ++ ++ case 'G': ++ num_supp_groups++; ++ if (num_supp_groups >= NGROUPS_MAX) ++ error (EXIT_FAIL, 0, ++ _("Can't specify more than %d supplemental groups"), ++ NGROUPS_MAX - 1); ++ gr = getgrnam(optarg); ++ if (!gr) ++ error (EXIT_FAIL, 0, _("group %s does not exist"), optarg); ++ groups[num_supp_groups] = gr->gr_gid; ++ break; ++#endif ++ + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); +@@ -739,7 +816,20 @@ + : DEFAULT_SHELL); + endpwent (); + +- if (!correct_password (pw)) ++#ifdef RUNUSER ++ if (num_supp_groups && !use_gid) ++ { ++ pw->pw_gid = groups[1]; ++ memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups); ++ } ++ else if (use_gid) ++ { ++ pw->pw_gid = groups[0]; ++ num_supp_groups++; ++ } ++#endif ++ ++ if (CHECKPASSWD && !correct_password (pw)) + { + #ifdef SYSLOG_FAILURE + log_su (pw, false); +@@ -771,8 +861,16 @@ + modify_environment (pw, shell); + + #ifndef USE_PAM +- change_identity (pw); ++ change_identity (pw ++#ifdef RUNUSER ++ , groups, num_supp_groups ++#endif ++ ); + #endif + +- run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw); ++ run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw ++#ifdef RUNUSER ++ , groups, num_supp_groups ++#endif ++ ); + } +--- 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. + +-EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who ++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 \ +@@ -112,6 +112,10 @@ + mv_LDADD += $(LIB_ACL) + ginstall_LDADD += $(LIB_ACL) + ++runuser_SOURCES = su.c ++runuser_CFLAGS = -DRUNUSER -DAUTHORS="\"David MacKenzie, Dan Walsh\"" ++runuser_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@ ++ + $(PROGRAMS): ../lib/libcoreutils.a + + SUFFIXES = .sh +@@ -126,7 +130,7 @@ + chmod +x $@-t + mv $@-t $@ + +-all-local: su$(EXEEXT) ++all-local: su$(EXEEXT) runuser + + installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` + +--- 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 + rmdir: David MacKenzie ++runuser: David MacKenzie, Dan Walsh + seq: Ulrich Drepper + sha1sum: Ulrich Drepper, Scott Miller, David Madore + sha224sum: Ulrich Drepper, Scott Miller, David Madore +--- 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 \ +--- /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 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" ++.SH NAME ++runuser \- run a shell with substitute user and group IDs, similar to su, but will not run PAM hooks ++.SH SYNOPSIS ++.B runuser ++[\fIOPTION\fR]... [\fI-\fR] [\fIUSER \fR[\fIARG\fR]...] ++.SH DESCRIPTION ++.\" Add any additional description here ++.PP ++Change the effective user id and group id to that of USER. No PAM hooks ++are run, and there will be no password prompt. This command is useful ++when run as the root user. If run as a non-root user without privilege ++to set user ID, the command will fail. ++.TP ++-, \fB\-l\fR, \fB\-\-login\fR ++make the shell a login shell, uses runuser-l PAM file instead of default one. ++.TP ++\fB\-c\fR, \fB\-\-commmand\fR=\fICOMMAND\fR ++pass a single COMMAND to the shell with \fB\-c\fR ++.TP ++\fB\-f\fR, \fB\-\-fast\fR ++pass \fB\-f\fR to the shell (for csh or tcsh) ++.TP ++\fB\-g\fR, \fB\-\-group\fR=\fIGROUP\fR ++specify the primary group ++.TP ++\fB\-G\fR, \fB\-\-supp-group\fR=\fIGROUP\fR ++specify a supplemental group ++.TP ++\fB\-m\fR, \fB\-\-preserve\-environment\fR ++do not reset environment variables ++.TP ++\fB\-p\fR ++same as \fB\-m\fR ++.TP ++\fB\-s\fR, \fB\-\-shell\fR=\fISHELL\fR ++run SHELL if /etc/shells allows it ++.TP ++\fB\-\-help\fR ++display this help and exit ++.TP ++\fB\-\-version\fR ++output version information and exit ++.PP ++A mere - implies \fB\-l\fR. If USER not given, assume root. ++.SH AUTHOR ++Written by David MacKenzie, Dan Walsh. ++.SH "REPORTING BUGS" ++Report bugs to . ++.SH COPYRIGHT ++Copyright \(co 2004 Free Software Foundation, Inc. ++.br ++This is free software; see the source for copying conditions. There is NO ++warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++.SH "SEE ALSO" ++Since this command is trimmed down version of su use you can use the su manual. ++The full documentation for ++.B su ++is maintained as a Texinfo manual. If the ++.B info ++and ++.B su ++programs are properly installed at your site, the command ++.IP ++.B info coreutils su ++.PP ++should give you access to the complete manual. 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-6.9-cp-i-u.patch b/coreutils-6.9-cp-i-u.patch new file mode 100644 index 0000000..167cacc --- /dev/null +++ b/coreutils-6.9-cp-i-u.patch @@ -0,0 +1,110 @@ +When "cp -i --update old new" would do nothing because "new" is +newer than "old", cp would nonetheless prompt for whether it is +ok to overwrite "new". Then, regardless of the response (because +of the --update option), cp would do nothing. + +The following patch eliminates the unnecessary prompt in that case. + +diff --git a/src/copy.c b/src/copy.c +index b7bf73b..0e549d2 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -1210,6 +1210,30 @@ copy_internal (char const *src_name, char const *dst_name, + return false; + } + ++ if (!S_ISDIR (src_mode) && x->update) ++ { ++ /* When preserving time stamps (but not moving within a file ++ system), don't worry if the destination time stamp is ++ less than the source merely because of time stamp ++ truncation. */ ++ int options = ((x->preserve_timestamps ++ && ! (x->move_mode ++ && dst_sb.st_dev == src_sb.st_dev)) ++ ? UTIMECMP_TRUNCATE_SOURCE ++ : 0); ++ ++ if (0 <= utimecmp (dst_name, &dst_sb, &src_sb, options)) ++ { ++ /* We're using --update and the destination is not older ++ than the source, so do not copy or move. Pretend the ++ rename succeeded, so the caller (if it's mv) doesn't ++ end up removing the source file. */ ++ if (rename_succeeded) ++ *rename_succeeded = true; ++ return true; ++ } ++ } ++ + /* When there is an existing destination file, we may end up + returning early, and hence not copying/moving the file. + This may be due to an interactive `negative' reply to the +@@ -1302,30 +1326,6 @@ copy_internal (char const *src_name, char const *dst_name, + return false; + } + } +- +- if (x->update) +- { +- /* When preserving time stamps (but not moving within a file +- system), don't worry if the destination time stamp is +- less than the source merely because of time stamp +- truncation. */ +- int options = ((x->preserve_timestamps +- && ! (x->move_mode +- && dst_sb.st_dev == src_sb.st_dev)) +- ? UTIMECMP_TRUNCATE_SOURCE +- : 0); +- +- if (0 <= utimecmp (dst_name, &dst_sb, &src_sb, options)) +- { +- /* We're using --update and the destination is not older +- than the source, so do not copy or move. Pretend the +- rename succeeded, so the caller (if it's mv) doesn't +- end up removing the source file. */ +- if (rename_succeeded) +- *rename_succeeded = true; +- return true; +- } +- } + } + + if (x->move_mode) +diff --git a/tests/mv/update b/tests/mv/update +index 0c06024..6c3d149 100755 +--- a/tests/mv/update ++++ b/tests/mv/update +@@ -1,7 +1,7 @@ + #!/bin/sh + # make sure --update works as advertised + +-# Copyright (C) 2001, 2004, 2006 Free Software Foundation, Inc. ++# Copyright (C) 2001, 2004, 2006-2007 Free Software Foundation, Inc. + + # This program is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -46,11 +46,16 @@ fi + + fail=0 + +-for cp_or_mv in cp mv; do +- # This is a no-op. +- $cp_or_mv --update old new || fail=1 +- case "`cat new`" in new) ;; *) fail=1 ;; esac +- case "`cat old`" in old) ;; *) fail=1 ;; esac ++for interactive in '' -i; do ++ for cp_or_mv in cp mv; do ++ # This is a no-op, with no prompt. ++ # With coreutils-6.9 and earlier, using --update with -i would ++ # mistakenly elicit a prompt. ++ $cp_or_mv $interactive --update old new < /dev/null > out 2>&1 || fail=1 ++ test -s out && fail=1 ++ case "`cat new`" in new) ;; *) fail=1 ;; esac ++ case "`cat old`" in old) ;; *) fail=1 ;; esac ++ done + done + + # This will actually perform the rename. +-- +1.5.3.rc1.16.g9d6f diff --git a/coreutils-6.9-du-ls-upstream.patch b/coreutils-6.9-du-ls-upstream.patch new file mode 100644 index 0000000..ff285f2 --- /dev/null +++ b/coreutils-6.9-du-ls-upstream.patch @@ -0,0 +1,98 @@ +Fixes some small bugs (merged upstream patches) +Fixed RedHat Bugzillas: 250089(fix by jplans@redhat.com), 239266 + +diff -Naurp coreutils-5.2.1/lib/fts.c coreutils-5.2.1.new/lib/fts.c +--- coreutils-5.2.1/lib/fts.c 2003-12-20 10:05:23.000000000 -0800 ++++ coreutils-5.2.1.new/lib/fts.c 2007-06-14 11:38:00.696001000 -0700 +@@ -685,7 +685,7 @@ fts_read(sp) + /* If fts_build's call to fts_safe_changedir failed + because it was not able to fchdir into a + subdirectory, tell the caller. */ +- if (p->fts_errno) ++ if (p->fts_errno && p->fts_info != FTS_DNR) + p->fts_info = FTS_ERR; + LEAVE_DIR (sp, p, "2"); + return (p); + } +diff -ur coreutils-6.9-orig/src/du.c coreutils-6.9/src/du.c +--- coreutils-6.9-orig/src/du.c ++++ coreutils-6.9/src/du.c + duinfo_add (&dulvl[level].ent, &dui); + + /* Even if this directory is unreadable or we can't chdir into it, +- do let its size contribute to the total, ... */ ++ do let its size contribute to the total. */ + duinfo_add (&tot_dui, &dui); + +- /* ... but don't print out a total for it, since without the size(s) +- of any potential entries, it could be very misleading. */ +- if (ent->fts_info == FTS_DNR) +- return ok; +- + /* If we're not counting an entry, e.g., because it's a hard link + to a file we've already counted (and --count-links), then don't + print a line for it. */ +diff -urNp coreutils-6.9-orig/src/dircolors.hin coreutils-6.9/src/dircolors.hin +--- coreutils-6.9-orig/src/dircolors.hin 2007-03-18 22:36:43.000000000 +0100 ++++ coreutils-6.9/src/dircolors.hin 2007-11-02 12:27:03.000000000 +0100 +@@ -27,6 +27,7 @@ TERM cons25 + TERM console + TERM cygwin + TERM dtterm ++TERM eterm-color + TERM gnome + TERM konsole + TERM kterm +@@ -40,6 +40,7 @@ TERM rxvt-cygwin + TERM rxvt-cygwin-native + TERM rxvt-unicode + TERM screen ++TERM screen-256color + TERM screen-bce + TERM screen-w + TERM screen.linux +@@ -46,7 +47,9 @@ TERM screen-w + TERM screen.linux + TERM vt100 + TERM xterm ++TERM xterm-16color + TERM xterm-256color ++TERM xterm-88color + TERM xterm-color + TERM xterm-debian + +diff -ur a/src/ls.c b/src/ls.c +--- a/src/ls.c ++++ b/src/ls.c +@@ -1168,7 +1168,7 @@ main (int argc, char **argv) + { + /* Avoid following symbolic links when possible. */ + if (is_colored (C_ORPHAN) +- || is_colored (C_EXEC) ++ || (is_colored (C_EXEC) && color_symlink_as_referent) + || (is_colored (C_MISSING) && format == long_format)) + check_symlink_color = true; + +@@ -2570,7 +2574,8 @@ gobble_file (char const *name, enum file + || ((print_inode || format_needs_type) + && (type == symbolic_link || type == unknown) + && (dereference == DEREF_ALWAYS +- || (command_line_arg && dereference != DEREF_NEVER))) ++ || (command_line_arg && dereference != DEREF_NEVER) ++ || color_symlink_as_referent || check_symlink_color)) + /* Command line dereferences are already taken care of by the above + assertion that the inode number is not yet known. */ + || (print_inode && inode == NOT_AN_INODE_NUMBER) +@@ -2713,6 +2713,12 @@ gobble_file (char const *name, enum filetype type, ino_t inode, + free (linkname); + } + ++ /* When not distinguishing types of symlinks, pretend we know that ++ it is stat'able, so that it will be colored as a regular symlink, ++ and not as an orphan. */ ++ if (S_ISLNK (f->stat.st_mode) && !check_symlink_color) ++ f->linkok = true; ++ + if (S_ISLNK (f->stat.st_mode)) + f->filetype = symbolic_link; + else if (S_ISDIR (f->stat.st_mode)) diff --git a/coreutils-6.9-longoptions.patch b/coreutils-6.9-longoptions.patch new file mode 100644 index 0000000..c3500a5 --- /dev/null +++ b/coreutils-6.9-longoptions.patch @@ -0,0 +1,13 @@ +diff -urp coreutils-6.9-orig/lib/long-options.c coreutils-6.9/lib/long-options.c +--- coreutils-6.9-orig/lib/long-options.c ++++ coreutils-6.9/lib/long-options.c +@@ -57,8 +57,7 @@ parse_long_options (int argc, + /* Don't print an error message for unrecognized options. */ + opterr = 0; + +- if (argc == 2 +- && (c = getopt_long (argc, argv, "+", long_options, NULL)) != -1) ++ while ((c = getopt_long (argc, argv, "+", long_options, NULL)) != -1) + { + switch (c) + { diff --git a/coreutils-6.9-requiresecuritycontext.patch b/coreutils-6.9-requiresecuritycontext.patch new file mode 100644 index 0000000..175a6ab --- /dev/null +++ b/coreutils-6.9-requiresecuritycontext.patch @@ -0,0 +1,160 @@ +diff -ur coreutils-6.9-orig/src/install.c coreutils-6.9/src/install.c +--- a/src/install.c 2007-10-30 12:34:07.000000000 +0100 ++++ b/src/install.c 2007-10-30 15:41:15.000000000 +0100 +@@ -174,6 +174,7 @@ + x->preserve_mode = false; + x->preserve_timestamps = false; + x->require_preserve = false; ++ x->require_preserve_context = false; + x->recursive = false; + x->sparse_mode = SPARSE_AUTO; + x->symbolic_link = false; +diff -ur coreutils-6.9-orig/src/mv.c coreutils-6.9/src/mv.c +--- a/src/mv.c 2007-10-30 12:34:07.000000000 +0100 ++++ b/src/mv.c 2007-10-30 15:34:37.000000000 +0100 +@@ -131,6 +131,7 @@ + x->preserve_timestamps = true; + x->preserve_security_context = selinux_enabled; + x->require_preserve = false; /* FIXME: maybe make this an option */ ++ x->require_preserve_context = false; + x->recursive = true; + x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */ + x->symbolic_link = false; +diff -ur coreutils-6.9-orig/src/copy.c coreutils-6.9/src/copy.c +--- coreutils-6.9-orig/src/copy.c 2007-10-30 12:34:07.000000000 +0100 ++++ coreutils-6.9/src/copy.c 2007-10-30 16:01:22.000000000 +0100 +@@ -306,25 +307,33 @@ + if (! *new_dst) + { + dest_desc = open (dst_name, O_WRONLY | O_TRUNC | O_BINARY); + + #ifdef WITH_SELINUX +- if (dest_desc >= 0 && selinux_enabled && +- (x->preserve_security_context || x->set_security_context)) ++ if (x->preserve_security_context && 0 <= dest_desc) + { +- security_context_t con; +- if(getfscreatecon(&con) == -1) ++ security_context_t con = NULL; ++ if(getfscreatecon(&con) < 0) + { +- return_val = false; +- goto close_src_desc; ++ if (x->require_preserve_context) ++ { ++ error(0, errno, _("failed to get file system create context")); ++ return_val = false; ++ goto close_src_desc; ++ } + } + + if (con) + { +- if(fsetfilecon(dest_desc, con) == -1) ++ if(fsetfilecon(dest_desc, con) < 0) + { +- return_val = false; +- freecon(con); +- goto close_src_desc; ++ if (x->require_preserve_context) ++ { ++ error(0, errno, _("failed to set security context of %s to %s"), ++ quote_n (0, dst_name), quote_n(1, con)); ++ return_val = false; ++ freecon(con); ++ goto close_src_desc; ++ } + } + freecon(con); + } +@@ -1577,10 +1587,10 @@ + { + if (setfscreatecon(con) < 0) + { +- error (0, errno, _("cannot set setfscreatecon %s"), quote (con)); +- if (x->require_preserve) { +- freecon(con); +- return 1; ++ error (0, errno, _("cannot set default file creation context to %s"), quote (con)); ++ if (x->require_preserve_context) { ++ freecon(con); ++ return false; + } + } + freecon(con); +@@ -1588,7 +1598,8 @@ + else { + if (( errno != ENOTSUP ) && ( errno != ENODATA )) { + error (0, errno, _("cannot lgetfilecon %s"), quote (src_name)); +- return 1; ++ if (x->require_preserve_context) ++ return false; + } + } + } +diff -ur coreutils-6.9-orig/src/copy.h coreutils-6.9/src/copy.h +--- coreutils-6.9-orig/src/copy.h 2007-10-30 12:34:07.000000000 +0100 ++++ coreutils-6.9/src/copy.h 2007-10-30 15:52:59.000000000 +0100 +@@ -150,6 +150,18 @@ + it be zero. */ + bool require_preserve; + ++ /* Useful only when preserve_security_context is true. ++ If true, a failed attempt to preserve a file's security context ++ propagates failure "out" to the caller. If false, a failure to ++ preserve a file's security context does not change the invoking ++ application's exit status. Give diagnostics for failed syscalls ++ regardless of this setting. For example, with "cp --preserve=context" ++ this flag is "true", while with "cp -a", it is false. That means ++ "cp -a" attempts to preserve any security context, but does not ++ fail if it is unable to do so. */ ++ bool require_preserve_context; ++ ++ + /* If true, copy directories recursively and copy special files + as themselves rather than copying their contents. */ + bool recursive; +diff -ur coreutils-6.9-orig/src/cp.c coreutils-6.9/src/cp.c +--- coreutils-6.9-orig/src/cp.c 2007-10-30 12:42:13.000000000 +0100 ++++ coreutils-6.9/src/cp.c 2007-10-30 16:00:33.000000000 +0100 +@@ -766,7 +766,7 @@ + x->preserve_security_context = false; + x->set_security_context = false; + #endif +- ++ x->require_preserve_context = false; + x->require_preserve = false; + x->recursive = false; + x->sparse_mode = SPARSE_AUTO; +@@ -844,6 +844,7 @@ + + case PRESERVE_CONTEXT: + x->preserve_security_context = on_off; ++ x->require_preserve_context = on_off; + break; + + case PRESERVE_ALL: +@@ -851,7 +834,10 @@ + x->preserve_timestamps = on_off; + x->preserve_ownership = on_off; + x->preserve_links = on_off; +- x->preserve_security_context = on_off; ++ if (selinux_enabled) { ++ x->preserve_security_context = on_off; ++ x->require_preserve_context = on_off; ++ } + break; + + default: +@@ -915,8 +916,9 @@ + x.preserve_ownership = true; + x.preserve_mode = true; + x.preserve_timestamps = true; +- x.preserve_security_context = true; +- x.require_preserve = true; ++ if (selinux_enabled) ++ x.preserve_security_context = true; ++ x.require_preserve = true; + x.recursive = true; + break; + diff --git a/coreutils-6.9-statsecuritycontext.patch b/coreutils-6.9-statsecuritycontext.patch new file mode 100644 index 0000000..062a95b --- /dev/null +++ b/coreutils-6.9-statsecuritycontext.patch @@ -0,0 +1,205 @@ +diff -urp coreutils-6.9-orig/src/stat.c coreutils-6.9/src/stat.c +--- coreutils-6.9-orig/src/stat.c 2007-12-04 16:26:39.000000000 +0100 ++++ coreutils-6.9/src/stat.c 2007-12-05 00:05:11.000000000 +0100 +@@ -55,12 +55,7 @@ + # include + #endif + +-#ifdef WITH_SELINUX + #include +-#define SECURITY_ID_T security_context_t +-#else +-#define SECURITY_ID_T char * +-#endif + + #include "system.h" + +@@ -179,6 +174,9 @@ static struct option const long_options[ + + char *program_name; + ++/* Whether to follow symbolic links; True for --dereference (-L). */ ++static bool follow_links = false; ++ + /* Whether to interpret backslash-escape sequences. + True for --printf=FMT, not for --format=FMT (-c). */ + static bool interpret_backslash_escapes; +@@ -402,10 +400,30 @@ out_uint_x (char *pformat, size_t prefix + printf (pformat, arg); + } + ++/* Very specialized function (modifies FORMAT), just so as to avoid ++ duplicating this code between both print_statfs and print_stat. */ ++static void ++out_file_context (char const *filename, char *pformat, size_t prefix_len) ++{ ++ char *scontext; ++ if ((follow_links ++ ? getfilecon (filename, &scontext) ++ : lgetfilecon (filename, &scontext)) < 0) ++ { ++ error (0, errno, _("failed to get security context of %s"), ++ quote (filename)); ++ scontext = NULL; ++ } ++ strcpy (pformat + prefix_len, "s"); ++ printf (pformat, (scontext ? scontext : "?")); ++ if (scontext) ++ freecon (scontext); ++} ++ + /* print statfs info */ + static void + print_statfs (char *pformat, size_t prefix_len, char m, char const *filename, +- void const *data, SECURITY_ID_T scontext) ++ void const *data) + { + STRUCT_STATVFS const *statfsbuf = data; + +@@ -481,8 +499,7 @@ print_statfs (char *pformat, size_t pref + out_int (pformat, prefix_len, statfsbuf->f_ffree); + break; + case 'C': +- strcat (pformat, "s"); +- printf(scontext); ++ out_file_context (filename, pformat, prefix_len); + break; + default: + fputc ('?', stdout); +@@ -493,7 +510,7 @@ print_statfs (char *pformat, size_t pref + /* print stat info */ + static void + print_stat (char *pformat, size_t prefix_len, char m, +- char const *filename, void const *data, SECURITY_ID_T scontext) ++ char const *filename, void const *data) + { + struct stat *statbuf = (struct stat *) data; + struct passwd *pw_ent; +@@ -607,8 +624,7 @@ print_stat (char *pformat, size_t prefix + out_uint (pformat, prefix_len, statbuf->st_ctime); + break; + case 'C': +- strcat (pformat, "s"); +- printf(pformat,scontext); ++ out_file_context(filename, pformat, prefix_len); + break; + default: + fputc ('?', stdout); +@@ -656,9 +672,8 @@ print_esc_char (char c) + + static void + print_it (char const *format, char const *filename, +- void (*print_func) (char *, size_t, char, char const *, void const *, +- SECURITY_ID_T ), +- void const *data, SECURITY_ID_T scontext) ++ void (*print_func) (char *, size_t, char, char const *, void const *), ++ void const *data) + { + /* Add 2 to accommodate our conversion of the stat `%s' format string + to the longer printf `%llu' one. */ +@@ -699,7 +714,7 @@ print_it (char const *format, char const + putchar ('%'); + break; + default: +- print_func (dest, len + 1, *fmt_char, filename, data, scontext); ++ print_func (dest, len + 1, *fmt_char, filename, data); + break; + } + break; +@@ -765,18 +780,6 @@ static bool + 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) + { +@@ -812,43 +815,23 @@ do_statfs (char const *filename, bool te + } + } + +- print_it (format, filename, print_statfs, &statfsbuf, scontext); +-#ifdef WITH_SELINUX +- if (scontext != NULL) +- freecon(scontext); +-#endif ++ print_it (format, filename, print_statfs, &statfsbuf); + return true; + } + + /* stat the file and print what we find */ + static bool +-do_stat (char const *filename, bool follow_links, bool terse, bool secure, ++do_stat (char const *filename, bool terse, bool secure, + char const *format) + { + struct stat statbuf; +- SECURITY_ID_T scontext = NULL; +- ++ + if ((follow_links ? stat : lstat) (filename, &statbuf) != 0) + { + error (0, errno, _("cannot stat %s"), quote (filename)); + 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) +@@ -893,11 +876,7 @@ do_stat (char const *filename, bool foll + } + } + } +- print_it (format, filename, print_stat, &statbuf, scontext); +-#ifdef WITH_SELINUX +- if (scontext) +- freecon(scontext); +-#endif ++ print_it (format, filename, print_stat, &statbuf); + return true; + } + +@@ -996,7 +975,6 @@ main (int argc, char *argv[]) + { + int c; + int i; +- bool follow_links = false; + bool fs = false; + bool terse = false; + bool secure = false; +@@ -1065,7 +1043,7 @@ main (int argc, char *argv[]) + for (i = optind; i < argc; i++) + ok &= (fs + ? do_statfs (argv[i], terse, secure, format) +- : do_stat (argv[i], follow_links, terse, secure, format)); ++ : do_stat (argv[i], terse, secure, format)); + + exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); + } + diff --git a/coreutils-6.9.tar.bz2.sig b/coreutils-6.9.tar.bz2.sig new file mode 100644 index 0000000..a39ac66 --- /dev/null +++ b/coreutils-6.9.tar.bz2.sig @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQBGAvc3/dLerNMzy6ERAnyfAKC4MPj62hCSRYNu0ysD9SahdQvZIACgsNl/ +CzQjwTNo5FUiiNm0FxtL5Ow= +=gl3O +-----END PGP SIGNATURE----- diff --git a/coreutils-8.26-selinuxenable.patch b/coreutils-8.26-selinuxenable.patch deleted file mode 100644 index d9b625a..0000000 --- a/coreutils-8.26-selinuxenable.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 6880c3dc9098b3337612850d1500b474aeb944ca Mon Sep 17 00:00:00 2001 -From: Kamil Dudka -Date: Tue, 29 Aug 2017 17:33:51 +0200 -Subject: [PATCH] require_selinux_(): use selinuxenabled(8) if available - ---- - init.cfg | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/init.cfg b/init.cfg -index af6b581..f887b3a 100644 ---- a/init.cfg -+++ b/init.cfg -@@ -114,6 +114,9 @@ require_selinux_() - grep 'selinuxfs$' /proc/filesystems > /dev/null \ - || skip_ "this system lacks SELinux support" - -+ # use the 'selinuxenabled' utility if available -+ selinuxenabled; [ $? = 1 ] && skip_ "SELinux is disabled" -+ - # Independent of whether SELinux is enabled system-wide, - # the current file system may lack SELinux support. - # Also the current build may have SELinux support disabled. --- -2.9.5 - diff --git a/coreutils-8.26-test-lock.patch b/coreutils-8.26-test-lock.patch deleted file mode 100644 index d66928c..0000000 --- a/coreutils-8.26-test-lock.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0d04ee8ddedb2bf33d64f148f246a3b7ec4fef21 Mon Sep 17 00:00:00 2001 -From: Kamil Dudka -Date: Mon, 23 Jan 2017 12:35:41 +0100 -Subject: [PATCH] test-lock: disable the rwlock test - -It hangs indefinitely if the system rwlock implementation does not -prevent writer starvation (and glibc does not implement it). - -Bug: http://www.mail-archive.com/bug-gnulib@gnu.org/msg33017.html ---- - gnulib-tests/test-lock.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/gnulib-tests/test-lock.c b/gnulib-tests/test-lock.c -index aa6de27..5af0a6c 100644 ---- a/gnulib-tests/test-lock.c -+++ b/gnulib-tests/test-lock.c -@@ -42,7 +42,7 @@ - Uncomment some of these, to verify that all tests crash if no locking - is enabled. */ - #define DO_TEST_LOCK 1 --#define DO_TEST_RWLOCK 1 -+#define DO_TEST_RWLOCK 0 - #define DO_TEST_RECURSIVE_LOCK 1 - #define DO_TEST_ONCE 1 - --- -2.7.4 - diff --git a/coreutils-8.32-DIR_COLORS.patch b/coreutils-8.32-DIR_COLORS.patch deleted file mode 100644 index 37ce3e6..0000000 --- a/coreutils-8.32-DIR_COLORS.patch +++ /dev/null @@ -1,100 +0,0 @@ -From bca11e30e8a6281a8cbddc9fb196dd86ab09c955 Mon Sep 17 00:00:00 2001 -From: Kamil Dudka -Date: Fri, 17 Jun 2016 16:58:18 +0200 -Subject: [PATCH] downstream changes to default DIR_COLORS - ---- - DIR_COLORS | 9 ++++++++- - DIR_COLORS.lightbgcolor | 21 +++++++++++++++------ - 2 files changed, 23 insertions(+), 7 deletions(-) - -diff --git a/DIR_COLORS b/DIR_COLORS -index 540f6cd..b4785b6 100644 ---- a/DIR_COLORS -+++ b/DIR_COLORS -@@ -1,3 +1,7 @@ -+# This file goes in the /etc directory, and must be world readable. -+# You can override the system defaults by making a copy of this file -+# as ~/.dir_colors -+ - # Configuration file for dircolors, a utility to help you set the - # LS_COLORS environment variable used by GNU ls with the --color option. - -@@ -11,6 +15,9 @@ - - # Global config options can be specified before TERM or COLORTERM entries - -+# For compatibility, the pattern "^COLOR.*none" is recognized as a way to -+# disable colorization. See https://bugzilla.redhat.com/1349579 for details. -+ - # =================================================================== - # Terminal filters - # =================================================================== -@@ -70,7 +77,7 @@ DOOR 01;35 # door - BLK 40;33;01 # block device driver - CHR 40;33;01 # character device driver - ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ... --MISSING 00 # ... and the files they point to -+MISSING 01;37;41 # ... and the files they point to - SETUID 37;41 # regular file that is setuid (u+s) - SETGID 30;43 # regular file that is setgid (g+s) - CAPABILITY 00 # regular file with capability (very expensive to lookup) -diff --git a/DIR_COLORS.lightbgcolor b/DIR_COLORS.lightbgcolor -index e3b0ec3..39a0a4c 100644 ---- a/DIR_COLORS.lightbgcolor -+++ b/DIR_COLORS.lightbgcolor -@@ -1,3 +1,9 @@ -+# Configuration file for the color ls utility - modified for lighter backgrounds -+ -+# This file goes in the /etc directory, and must be world readable. -+# You can override the system defaults by making a copy of this file -+# as ~/.dir_colors -+ - # Configuration file for dircolors, a utility to help you set the - # LS_COLORS environment variable used by GNU ls with the --color option. - -@@ -11,6 +17,9 @@ - - # Global config options can be specified before TERM or COLORTERM entries - -+# For compatibility, the pattern "^COLOR.*none" is recognized as a way to -+# disable colorization. See https://bugzilla.redhat.com/1349579 for details. -+ - # =================================================================== - # Terminal filters - # =================================================================== -@@ -60,17 +69,17 @@ TERM xterm* - #NORMAL 00 # no color code at all - #FILE 00 # regular file: use no color at all - RESET 0 # reset to "normal" color --DIR 01;34 # directory --LINK 01;36 # symbolic link. (If you set this to 'target' instead of a -+DIR 00;34 # directory -+LINK 00;36 # symbolic link. (If you set this to 'target' instead of a - # numerical value, the color is as for the file pointed to.) - MULTIHARDLINK 00 # regular file with more than one link - FIFO 40;33 # pipe --SOCK 01;35 # socket --DOOR 01;35 # door -+SOCK 00;35 # socket -+DOOR 00;35 # door - BLK 40;33;01 # block device driver - CHR 40;33;01 # character device driver - ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ... --MISSING 00 # ... and the files they point to -+MISSING 01;37;41 # ... and the files they point to - SETUID 37;41 # regular file that is setuid (u+s) - SETGID 30;43 # regular file that is setgid (g+s) - CAPABILITY 00 # regular file with capability (very expensive to lookup) -@@ -79,7 +88,7 @@ OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky - STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable - - # This is for regular files with execute permission: --EXEC 01;32 -+EXEC 00;32 - - # =================================================================== - # File extension attributes --- -2.49.0 - diff --git a/coreutils-9.9-fix-cut-test-aarch64.patch b/coreutils-9.9-fix-cut-test-aarch64.patch deleted file mode 100644 index 600f87b..0000000 --- a/coreutils-9.9-fix-cut-test-aarch64.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 95044cb5eaea83d02f768feb5ab79fcf5e6ad782 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?P=C3=A1draig=20Brady?= -Date: Mon, 22 Dec 2025 17:12:48 +0000 -Subject: [PATCH] tests: avoid false failure due to ulimit on aarch64 - -* tests/cut/cut-huge-range.sh: Add an extra 1MiB headroom, -which was seen with aarch64. -Reported at https://bugzilla.redhat.com/2424302 - -Cherry-picked-by: Lukáš Zaoral -Upstream-commit: 95044cb5eaea83d02f768feb5ab79fcf5e6ad782 ---- - tests/cut/cut-huge-range.sh | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/tests/cut/cut-huge-range.sh b/tests/cut/cut-huge-range.sh -index 4bd1b129d8..98d7e8f0b9 100755 ---- a/tests/cut/cut-huge-range.sh -+++ b/tests/cut/cut-huge-range.sh -@@ -22,6 +22,7 @@ getlimits_ - - vm=$(get_min_ulimit_v_ returns_ 0 cut -b1 /dev/null) \ - || skip_ 'shell lacks ulimit, or ASAN enabled' -+vm=$(($vm+1000)) # https://bugzilla.redhat.com/2424302 - - # Ensure we can cut up to our sentinel value. - # Don't use expr to subtract one, - diff --git a/coreutils-9.9-gnulib-c23.patch b/coreutils-9.9-gnulib-c23.patch deleted file mode 100644 index 82e3899..0000000 --- a/coreutils-9.9-gnulib-c23.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 891761bca1aa78336e5b18c121075b6e4696c5d4 Mon Sep 17 00:00:00 2001 -From: Paul Eggert -Date: Sun, 23 Nov 2025 00:50:40 -0800 -Subject: [PATCH] Port to C23 qualifier-generic fns like strchr -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This ports Gnulib to strict C23 platforms that reject code -like ‘char *q = strchr (P, 'x');’ when P is a pointer to const, -because in C23 strchr is a qualifier-generic function so -strchr (P, 'x') returns char const *. -This patch does not attempt to do the following two things, -which might be useful in the future: -1. When compiling on non-C23 platforms, check user code for -portability to platforms that define qualifier-generic functions. -2. Port Gnulib to platforms that have qualifier-generic functions -not listed in the C23 standard, e.g., strchrnul. I don’t know -of any such platforms. -* lib/mbschr.c (mbschr): -* lib/memchr2.c (memchr2): -Port to C23, where functions like strchr are qualifier-generic. -* lib/c++defs.h (_GL_FUNCDECL_SYS_NAME): New macro. -* lib/c++defs.h (_GL_FUNCDECL_SYS): -* lib/stdlib.in.h (bsearch): -Use it, to prevent C23 names like strchr from acting like macros. -* lib/string.in.h (memchr, strchr, strpbrk, strrchr): -Do not #undef when GNULIB_POSIXCHECK is defined, as this could -cause conforming C23 code to fail to conform. It’s not clear why -_GL_WARN_ON_USE_CXX; perhaps it was needed but isn’t any more? -But for now, limit the removal of #undef to these four functions -where #undeffing is clearly undesirable in C23. -* lib/wchar.in.h (wmemchr): Parenthesize function name in decl, -to prevent it from acting like a macro. - -Cherry-picked-by: Lukáš Zaoral -Upstream-commit: df17f4f37ed3ca373d23ad42eae51122bdb96626 ---- - lib/c++defs.h | 12 +++++++++++- - lib/mbschr.c | 2 +- - lib/memchr2.c | 2 +- - lib/stdlib.in.h | 6 +++--- - lib/string.in.h | 4 ---- - lib/wchar.in.h | 2 +- - 6 files changed, 17 insertions(+), 11 deletions(-) - -diff --git a/lib/c++defs.h b/lib/c++defs.h -index b77979a..7384457 100644 ---- a/lib/c++defs.h -+++ b/lib/c++defs.h -@@ -127,6 +127,16 @@ - #define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters,...) \ - _GL_EXTERN_C_FUNC __VA_ARGS__ rettype rpl_func parameters - -+/* _GL_FUNCDECL_SYS_NAME (func) expands to plain func if C++, and to -+ parenthsized func otherwise. Parenthesization is needed in C23 if -+ the function is like strchr and so is a qualifier-generic macro -+ that expands to something more complicated. */ -+#ifdef __cplusplus -+# define _GL_FUNCDECL_SYS_NAME(func) func -+#else -+# define _GL_FUNCDECL_SYS_NAME(func) (func) -+#endif -+ - /* _GL_FUNCDECL_SYS (func, rettype, parameters, [attributes]); - declares the system function, named func, with the given prototype, - consisting of return type, parameters, and attributes. -@@ -139,7 +149,7 @@ - _GL_FUNCDECL_SYS (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD); - */ - #define _GL_FUNCDECL_SYS(func,rettype,parameters,...) \ -- _GL_EXTERN_C_FUNC __VA_ARGS__ rettype func parameters -+ _GL_EXTERN_C_FUNC __VA_ARGS__ rettype _GL_FUNCDECL_SYS_NAME (func) parameters - - /* _GL_CXXALIAS_RPL (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func -diff --git a/lib/mbschr.c b/lib/mbschr.c -index c9e14b5..6582134 100644 ---- a/lib/mbschr.c -+++ b/lib/mbschr.c -@@ -65,5 +65,5 @@ mbschr (const char *string, int c) - return NULL; - } - else -- return strchr (string, c); -+ return (char *) strchr (string, c); - } -diff --git a/lib/memchr2.c b/lib/memchr2.c -index 7493823..d7724ae 100644 ---- a/lib/memchr2.c -+++ b/lib/memchr2.c -@@ -55,7 +55,7 @@ memchr2 (void const *s, int c1_in, int c2_in, size_t n) - c2 = (unsigned char) c2_in; - - if (c1 == c2) -- return memchr (s, c1, n); -+ return (void *) memchr (s, c1, n); - - /* Handle the first few bytes by reading one byte at a time. - Do this until VOID_PTR is aligned on a longword boundary. */ -diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h -index bef0aaa..fd0e1e0 100644 ---- a/lib/stdlib.in.h -+++ b/lib/stdlib.in.h -@@ -224,9 +224,9 @@ _GL_INLINE_HEADER_BEGIN - - /* Declarations for ISO C N3322. */ - #if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__ --_GL_EXTERN_C void *bsearch (const void *__key, -- const void *__base, size_t __nmemb, size_t __size, -- int (*__compare) (const void *, const void *)) -+_GL_EXTERN_C void *_GL_FUNCDECL_SYS_NAME (bsearch) -+ (const void *__key, const void *__base, size_t __nmemb, size_t __size, -+ int (*__compare) (const void *, const void *)) - _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3) _GL_ARG_NONNULL ((5)); - _GL_EXTERN_C void qsort (void *__base, size_t __nmemb, size_t __size, - int (*__compare) (const void *, const void *)) -diff --git a/lib/string.in.h b/lib/string.in.h -index fdcdd21..8b56acf 100644 ---- a/lib/string.in.h -+++ b/lib/string.in.h -@@ -409,7 +409,6 @@ _GL_CXXALIASWARN1 (memchr, void const *, - _GL_CXXALIASWARN (memchr); - # endif - #elif defined GNULIB_POSIXCHECK --# undef memchr - /* Assume memchr is always declared. */ - _GL_WARN_ON_USE (memchr, "memchr has platform-specific bugs - " - "use gnulib module memchr for portability" ); -@@ -674,7 +673,6 @@ _GL_WARN_ON_USE (stpncpy, "stpncpy is unportable - " - #if defined GNULIB_POSIXCHECK - /* strchr() does not work with multibyte strings if the locale encoding is - GB18030 and the character to be searched is a digit. */ --# undef strchr - /* Assume strchr is always declared. */ - _GL_WARN_ON_USE_CXX (strchr, - const char *, char *, (const char *, int), -@@ -981,7 +979,6 @@ _GL_CXXALIASWARN (strpbrk); - Even in this simple case, it does not work with multibyte strings if the - locale encoding is GB18030 and one of the characters to be searched is a - digit. */ --# undef strpbrk - _GL_WARN_ON_USE_CXX (strpbrk, - const char *, char *, (const char *, const char *), - "strpbrk cannot work correctly on character strings " -@@ -1011,7 +1008,6 @@ _GL_WARN_ON_USE (strspn, "strspn cannot work correctly on character strings " - #if defined GNULIB_POSIXCHECK - /* strrchr() does not work with multibyte strings if the locale encoding is - GB18030 and the character to be searched is a digit. */ --# undef strrchr - /* Assume strrchr is always declared. */ - _GL_WARN_ON_USE_CXX (strrchr, - const char *, char *, (const char *, int), -diff --git a/lib/wchar.in.h b/lib/wchar.in.h -index ab602a2..6be4515 100644 ---- a/lib/wchar.in.h -+++ b/lib/wchar.in.h -@@ -301,7 +301,7 @@ _GL_EXTERN_C int wcsncmp (const wchar_t *__s1, const wchar_t *__s2, size_t __n) - _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3) - _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3); - # ifndef __cplusplus --_GL_EXTERN_C wchar_t *wmemchr (const wchar_t *__s, wchar_t __wc, size_t __n) -+_GL_EXTERN_C wchar_t *(wmemchr) (const wchar_t *__s, wchar_t __wc, size_t __n) - _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3); - # endif - _GL_EXTERN_C wchar_t *wmemset (wchar_t *__s, wchar_t __wc, size_t __n) --- -2.52.0 - diff --git a/coreutils-DIR_COLORS b/coreutils-DIR_COLORS new file mode 100644 index 0000000..179b5e3 --- /dev/null +++ b/coreutils-DIR_COLORS @@ -0,0 +1,163 @@ +# Configuration file for the color ls utility +# This file goes in the /etc directory, and must be world readable. +# You can copy this file to .dir_colors in your $HOME directory to override +# the system defaults. + +# COLOR needs one of these arguments: 'tty' colorizes output to ttys, but not +# pipes. 'all' adds color characters to all output. 'none' shuts colorization +# off. +COLOR tty + +# Extra command line options for ls go here. +# Basically these ones are: +# -F = show '/' for dirs, '*' for executables, etc. +# -T 0 = don't trust tab spacing when formatting ls output. +OPTIONS -F -T 0 + +# Below, there should be one TERM entry for each termtype that is colorizable +TERM Eterm +TERM ansi +TERM color-xterm +TERM con132x25 +TERM con132x30 +TERM con132x43 +TERM con132x60 +TERM con80x25 +TERM con80x28 +TERM con80x30 +TERM con80x43 +TERM con80x50 +TERM con80x60 +TERM cons25 +TERM console +TERM cygwin +TERM dtterm +TERM eterm-color +TERM gnome +TERM konsole +TERM kterm +TERM linux +TERM linux-c +TERM mach-color +TERM mlterm +TERM putty +TERM rxvt +TERM rxvt-cygwin +TERM rxvt-cygwin-native +TERM rxvt-unicode +TERM screen +TERM screen-256color +TERM screen-bce +TERM screen-w +TERM screen.linux +TERM vt100 +TERM xterm +TERM xterm-16color +TERM xterm-256color +TERM xterm-88color +TERM xterm-color +TERM xterm-debian + +# EIGHTBIT, followed by '1' for on, '0' for off. (8-bit output) +EIGHTBIT 1 + +# Below are the color init strings for the basic file types. A color init +# string consists of one or more of the following numeric codes: +# Attribute codes: +# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed +# Text color codes: +# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white +# Background color codes: +# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white +NORMAL 00 # global default, although everything should be something. +FILE 00 # normal file +DIR 01;34 # directory +LINK 01;36 # symbolic link +FIFO 40;33 # pipe +SOCK 01;35 # socket +BLK 40;33;01 # block device driver +CHR 40;33;01 # character device driver +ORPHAN 01;05;37;41 # orphaned syminks +MISSING 01;05;37;41 # ... and the files they point to + +# This is for files with execute permission: +EXEC 01;32 + +# List any file extensions like '.gz' or '.tar' that you would like ls +# to colorize below. Put the extension, a space, and the color init string. +# (and any comments you want to add after a '#') +.cmd 01;32 # executables (bright green) +.exe 01;32 +.com 01;32 +.btm 01;32 +.bat 01;32 +.sh 01;32 +.csh 01;32 +# archives or compressed (bright red) +.tar 01;31 +.tgz 01;31 +.svgz 01;31 +.arj 01;31 +.taz 01;31 +.lzh 01;31 +.lzma 01;31 +.zip 01;31 +.z 01;31 +.Z 01;31 +.dz 01;31 +.gz 01;31 +.bz2 01;31 +.tbz2 01;31 +.bz 01;31 +.tz 01;31 +.deb 01;31 +.rpm 01;31 +.jar 01;31 +.rar 01;31 +.ace 01;31 +.zoo 01;31 +.cpio 01;31 +.7z 01;31 +.rz 01;31 +# image formats (magenta) +.jpg 01;35 +.jpeg 01;35 +.gif 01;35 +.bmp 01;35 +.pbm 01;35 +.pgm 01;35 +.ppm 01;35 +.tga 01;35 +.xbm 01;35 +.xpm 01;35 +.tif 01;35 +.tiff 01;35 +.png 01;35 +.mng 01;35 +.pcx 01;35 +.mov 01;35 +.mpg 01;35 +.mpeg 01;35 +.m2v 01;35 +.mkv 01;35 +.ogm 01;35 +.mp4 01;35 +.m4v 01;35 +.mp4v 01;35 +.vob 01;35 +.qt 01;35 +.nuv 01;35 +.wmv 01;35 +.asf 01;35 +.rm 01;35 +.rmvb 01;35 +.flc 01;35 +.avi 01;35 +.fli 01;35 +.gl 01;35 +.dl 01;35 +.xcf 01;35 +.xwd 01;35 +.yuv 01;35 +.svg 01;35 + diff --git a/coreutils-DIR_COLORS.xterm b/coreutils-DIR_COLORS.xterm new file mode 100644 index 0000000..ae0f386 --- /dev/null +++ b/coreutils-DIR_COLORS.xterm @@ -0,0 +1,144 @@ +# Configuration file for the color ls utility +# This file goes in the /etc directory, and must be world readable. +# You can copy this file to .dir_colors in your $HOME directory to override +# the system defaults. + +# COLOR needs one of these arguments: 'tty' colorizes output to ttys, but not +# pipes. 'all' adds color characters to all output. 'none' shuts colorization +# off. +COLOR tty + +# Extra command line options for ls go here. +# Basically these ones are: +# -F = show '/' for dirs, '*' for executables, etc. +# -T 0 = don't trust tab spacing when formatting ls output. +OPTIONS -F -T 0 + +# Below, there should be one TERM entry for each termtype that is colorizable +TERM linux +TERM console +TERM con132x25 +TERM con132x30 +TERM con132x43 +TERM con132x60 +TERM con80x25 +TERM con80x28 +TERM con80x30 +TERM con80x43 +TERM con80x50 +TERM con80x60 +TERM cons25 +TERM xterm +TERM xterm-16color +TERM xterm-88color +TERM xterm-256color +TERM rxvt +TERM rxvt-unicode +TERM xterm-color +TERM color-xterm +TERM vt100 +TERM dtterm +TERM color_xterm + +# EIGHTBIT, followed by '1' for on, '0' for off. (8-bit output) +EIGHTBIT 1 + +# Below are the color init strings for the basic file types. A color init +# string consists of one or more of the following numeric codes: +# Attribute codes: +# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed +# Text color codes: +# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white +# Background color codes: +# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white +NORMAL 00 # global default, although everything should be something. +FILE 00 # normal file +DIR 00;34 # directory +LINK 00;36 # symbolic link +FIFO 40;33 # pipe +SOCK 00;35 # socket +BLK 40;33;01 # block device driver +CHR 40;33;01 # character device driver +ORPHAN 01;05;37;41 # orphaned syminks +MISSING 01;05;37;41 # ... and the files they point to + +# This is for files with execute permission: +EXEC 00;32 + +# List any file extensions like '.gz' or '.tar' that you would like ls +# to colorize below. Put the extension, a space, and the color init string. +# (and any comments you want to add after a '#') +.cmd 00;32 # executables (green) +.exe 00;32 +.com 00;32 +.btm 00;32 +.bat 00;32 +.sh 00;32 +.csh 00;32 +# archives or compressed (red) +.tar 00;31 +.tgz 00;31 +.svgz 00;31 +.arj 00;31 +.taz 00;31 +.lzh 00;31 +.lzma 00;31 +.zip 00;31 +.z 00;31 +.Z 00;31 +.dz 00;31 +.gz 00;31 +.bz2 00;31 +.tbz2 00;31 +.bz 00;31 +.tz 00;31 +.deb 00;31 +.rpm 00;31 +.jar 00;31 +.rar 00;31 +.ace 00;31 +.zoo 00;31 +.cpio 00;31 +.7z 00;31 +.rz 00;31 +# image formats +.jpg 00;35 +.jpeg 00;35 +.gif 00;35 +.bmp 00;35 +.pbm 00;35 +.pgm 00;35 +.ppm 00;35 +.tga 00;35 +.xbm 00;35 +.xpm 00;35 +.tif 00;35 +.tiff 00;35 +.png 00;35 +.mng 00;35 +.pcx 00;35 +.mov 00;35 +.mpg 00;35 +.mpeg 00;35 +.m2v 00;35 +.mkv 00;35 +.ogm 00;35 +.mp4 00;35 +.m4v 00;35 +.mp4v 00;35 +.vob 00;35 +.qt 00;35 +.nuv 00;35 +.wmv 00;35 +.asf 00;35 +.rm 00;35 +.rmvb 00;35 +.flc 00;35 +.avi 00;35 +.fli 00;35 +.gl 00;35 +.dl 00;35 +.xcf 00;35 +.xwd 00;35 +.yuv 00;35 +.svg 00;35 diff --git a/coreutils-chgrp.patch b/coreutils-chgrp.patch new file mode 100644 index 0000000..a93e725 --- /dev/null +++ b/coreutils-chgrp.patch @@ -0,0 +1,14 @@ +--- coreutils-5.92/tests/group-names.chgrp 2005-10-28 09:20:12.000000000 +0100 ++++ coreutils-5.92/tests/group-names 2005-10-28 09:55:27.000000000 +0100 +@@ -18,3 +18,11 @@ + (exit 77); exit 77 + ;; + esac ++ ++set `id -Gn` ++if echo "$2" | grep -q '[^0-9]' ++then ++ exit 0 ++else ++ (exit 77); exit 77 ++fi diff --git a/coreutils-colorls.csh b/coreutils-colorls.csh index 66ec2fa..7a41d8f 100755 --- a/coreutils-colorls.csh +++ b/coreutils-colorls.csh @@ -1,61 +1,37 @@ -# skip everything for non-interactive shells -if (! $?prompt) exit - # color-ls initialization if ( $?USER_LS_COLORS ) then if ( "$USER_LS_COLORS" != "" ) then - #when USER_LS_COLORS defined do not override user - #specified LS_COLORS and use them + #When USER_LS_COLORS set, do not override user specified LS_COLORS but use them goto finish endif endif alias ll 'ls -l' alias l. 'ls -d .*' -set COLORS=/etc/DIR_COLORS +set COLORS=/etc/DIR_COLORS if ($?TERM) then - if ( -e "/etc/DIR_COLORS.$TERM" ) then - set COLORS="/etc/DIR_COLORS.$TERM" - endif + if ( -e "/etc/DIR_COLORS.$TERM" ) set COLORS="/etc/DIR_COLORS.$TERM" endif if ( -f ~/.dircolors ) set COLORS=~/.dircolors if ( -f ~/.dir_colors ) set COLORS=~/.dir_colors if ($?TERM) then - if ( -f ~/.dircolors."$TERM" ) set COLORS=~/.dircolors."$TERM" - if ( -f ~/.dir_colors."$TERM" ) set COLORS=~/.dir_colors."$TERM" + if ( -f ~/.dircolors."$TERM" ) set COLORS=~/.dircolors."$TERM" + if ( -f ~/.dir_colors."$TERM" ) set COLORS=~/.dir_colors."$TERM" endif -set INCLUDE="`/usr/bin/cat "$COLORS" | /usr/bin/grep '^INCLUDE' | /usr/bin/cut -d ' ' -f2-`" if ( ! -e "$COLORS" ) exit -set _tmp="`/usr/bin/mktemp .colorlsXXX -q --tmpdir=/tmp`" -#if mktemp fails, exit when include was active, otherwise use $COLORS file -if ( "$_tmp" == '' ) then - if ( "$INCLUDE" == '' ) then - eval "`/usr/bin/dircolors -c $COLORS`" - endif - goto cleanup -endif - -if ( "$INCLUDE" != '' ) /usr/bin/cat "$INCLUDE" >> $_tmp -/usr/bin/grep -v '^INCLUDE' "$COLORS" >> $_tmp - -eval "`/usr/bin/dircolors -c $_tmp`" - -/usr/bin/rm -f $_tmp +eval `dircolors -c $COLORS` if ( "$LS_COLORS" == '' ) exit -cleanup: -set color_none=`/usr/bin/sed -n '/^COLOR.*none/Ip' < $COLORS` -if ( "$color_none" != '' ) then + +set color_none=`sed -n '/^COLOR.*none/Ip' < $COLORS` +if ( "$color_none" != '' ) then unset color_none exit endif unset color_none -unset _tmp -unset INCLUDE -unset COLORS finish: alias ll 'ls -l --color=auto' diff --git a/coreutils-colorls.sh b/coreutils-colorls.sh index 5162f1e..dbb853c 100755 --- a/coreutils-colorls.sh +++ b/coreutils-colorls.sh @@ -1,53 +1,36 @@ # color-ls initialization -# Skip all for noninteractive shells. -[ ! -t 0 ] && return - -#when USER_LS_COLORS defined do not override user LS_COLORS, but use them. +#do not override user LS_COLORS, but use them when USER_LS_COLORS is set. if [ -z "$USER_LS_COLORS" ]; then - + alias ll='ls -l' 2>/dev/null alias l.='ls -d .*' 2>/dev/null - INCLUDE= + + # Skip the rest for noninteractive shells. + [ -z "$PS1" ] && return + COLORS= for colors in "$HOME/.dir_colors.$TERM" "$HOME/.dircolors.$TERM" \ "$HOME/.dir_colors" "$HOME/.dircolors"; do - [ -e "$colors" ] && COLORS="$colors" && \ - INCLUDE="`/usr/bin/cat "$COLORS" | /usr/bin/grep '^INCLUDE' | /usr/bin/cut -d ' ' -f2-`" && \ - break + [ -e "$colors" ] && COLORS="$colors" && break done - [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS.$TERM" ] && \ - COLORS="/etc/DIR_COLORS.$TERM" - - [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS" ] && \ - COLORS="/etc/DIR_COLORS" + if [ -z "$COLORS" ]; then + for colors in "/etc/DIR_COLORS.$TERM" "/etc/DIR_COLORS" ; do + [ -e "$colors" ] && COLORS="$colors" && break + done + fi # Existence of $COLORS already checked above. [ -n "$COLORS" ] || return - if [ -e "$INCLUDE" ]; - then - TMP="`/usr/bin/mktemp .colorlsXXX -q --tmpdir=/tmp`" - [ -z "$TMP" ] && return - - /usr/bin/cat "$INCLUDE" >> $TMP - /usr/bin/grep -v '^INCLUDE' "$COLORS" >> $TMP - - eval "`/usr/bin/dircolors --sh $TMP 2>/dev/null`" - /usr/bin/rm -f $TMP - else - eval "`/usr/bin/dircolors --sh $COLORS 2>/dev/null`" - fi - + eval `dircolors --sh "$COLORS" 2>/dev/null` [ -z "$LS_COLORS" ] && return - /usr/bin/grep -qi "^COLOR.*none" $COLORS >/dev/null 2>/dev/null && return + egrep -qi "^COLOR.*none" $COLORS >/dev/null 2>/dev/null && return fi -unset TMP COLORS INCLUDE - alias ll='ls -l --color=auto' 2>/dev/null alias l.='ls -d .* --color=auto' 2>/dev/null alias ls='ls --color=auto' 2>/dev/null diff --git a/coreutils-dddoubleclose.patch b/coreutils-dddoubleclose.patch new file mode 100644 index 0000000..3e37027 --- /dev/null +++ b/coreutils-dddoubleclose.patch @@ -0,0 +1,45 @@ +diff -urNp coreutils-6.9-orig/src/dd.c coreutils-6.9/src/dd.c +--- coreutils-6.9-orig/src/dd.c ++++ coreutils-6.9/src/dd.c +@@ -391,6 +391,25 @@ static char const ebcdic_to_ascii[] = + '\070', '\071', '\372', '\373', '\374', '\375', '\376', '\377' + }; + ++/* True if we need to close the standard output *stream*. */ ++static bool close_stdout_required = true; ++ ++/* The only reason to close the standard output *stream* is if ++ parse_long_options fails (as it does for --help or --version). ++ In any other case, dd uses only the STDOUT_FILENO file descriptor, ++ and the "cleanup" function calls "close (STDOUT_FILENO)". ++ Closing the file descriptor and then letting the usual atexit-run ++ close_stdout function call "fclose (stdout)" would result in a ++ harmless failure of the close syscall (with errno EBADF). ++ This function serves solely to avoid the unnecessary close_stdout ++ call, once parse_long_options has succeeded. */ ++static void ++maybe_close_stdout (void) ++{ ++ if (close_stdout_required) ++ close_stdout (); ++} ++ + void + usage (int status) + { +@@ -1639,12 +1658,14 @@ main (int argc, char **argv) + textdomain (PACKAGE); + + /* Arrange to close stdout if parse_long_options exits. */ +- atexit (close_stdout); ++ atexit (maybe_close_stdout); + + page_size = getpagesize (); + + parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, + usage, AUTHORS, (char const *) NULL); ++ close_stdout_required = false; ++ + if (getopt_long (argc, argv, "", NULL, NULL) != -1) + usage (EXIT_FAILURE); + diff --git a/coreutils-df-direct.patch b/coreutils-df-direct.patch deleted file mode 100644 index 341ee2c..0000000 --- a/coreutils-df-direct.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 91be1a584108a6a3d96f64382bbf206c4213b3db Mon Sep 17 00:00:00 2001 -From: Kamil Dudka -Date: Mon, 29 Mar 2010 17:20:34 +0000 -Subject: [PATCH] coreutils-df-direct.patch - ---- - doc/coreutils.texi | 7 ++++++ - src/df.c | 34 ++++++++++++++++++++++++++-- - tests/df/direct.sh | 55 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 94 insertions(+), 2 deletions(-) - create mode 100755 tests/df/direct.sh - -diff --git a/doc/coreutils.texi b/doc/coreutils.texi -index b420606..0ccb368 100644 ---- a/doc/coreutils.texi -+++ b/doc/coreutils.texi -@@ -12597,6 +12597,13 @@ some systems (notably Solaris), doing this yields more up to date results, - but in general this option makes @command{df} much slower, especially when - there are many or very busy file systems. - -+@item --direct -+@opindex --direct -+@cindex direct statfs for a file -+Do not resolve mount point and show statistics directly for a file. It can be -+especially useful for NFS mount points if there is a boundary between two -+storage policies behind the mount point. -+ - @item --total - @opindex --total - @cindex grand total of file system size, usage and available space -diff --git a/src/df.c b/src/df.c -index 75e638c..ef9f0a7 100644 ---- a/src/df.c -+++ b/src/df.c -@@ -121,6 +121,9 @@ static bool print_type; - /* If true, print a grand total at the end. */ - static bool print_grand_total; - -+/* If true, show statistics for a file instead of mount point. */ -+static bool direct_statfs; -+ - /* Grand total data. */ - static struct fs_usage grand_fsu; - -@@ -248,13 +251,15 @@ enum - NO_SYNC_OPTION = CHAR_MAX + 1, - SYNC_OPTION, - TOTAL_OPTION, -- OUTPUT_OPTION -+ OUTPUT_OPTION, -+ DIRECT_OPTION - }; - - static struct option const long_options[] = - { - {"all", no_argument, nullptr, 'a'}, - {"block-size", required_argument, nullptr, 'B'}, -+ {"direct", no_argument, nullptr, DIRECT_OPTION}, - {"inodes", no_argument, nullptr, 'i'}, - {"human-readable", no_argument, nullptr, 'h'}, - {"si", no_argument, nullptr, 'H'}, -@@ -571,7 +576,10 @@ get_header (void) - for (idx_t col = 0; col < ncolumns; col++) - { - char *cell; -- char const *header = _(columns[col]->caption); -+ char const *header = (columns[col]->field == TARGET_FIELD -+ && direct_statfs)? -+ _("File") : -+ _(columns[col]->caption); - - if (columns[col]->field == SIZE_FIELD - && (header_mode == DEFAULT_MODE -@@ -1446,6 +1454,17 @@ get_point (char const *point, const struct stat *statp) - static void - get_entry (char const *name, struct stat const *statp) - { -+ if (direct_statfs) -+ { -+ char *resolved = canonicalize_file_name (name); -+ if (resolved) -+ { -+ get_dev (NULL, resolved, name, NULL, NULL, false, false, NULL, false); -+ free (resolved); -+ return; -+ } -+ } -+ - if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode)) - && get_device (name)) - return; -@@ -1516,6 +1535,7 @@ or all file systems by default.\n\ - -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ - '-BM' prints sizes in units of 1,048,576 bytes;\n\ - see SIZE format below\n\ -+ --direct show statistics for a file instead of mount point\n\ - -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\ - -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\ - "), stdout); -@@ -1610,6 +1630,9 @@ main (int argc, char **argv) - xstrtol_fatal (e, oi, c, long_options, optarg); - } - break; -+ case DIRECT_OPTION: -+ direct_statfs = true; -+ break; - case 'i': - if (header_mode == OUTPUT_MODE) - { -@@ -1706,6 +1729,13 @@ main (int argc, char **argv) - } - } - -+ if (direct_statfs && show_local_fs) -+ { -+ error (0, 0, _("options --direct and --local (-l) are mutually " -+ "exclusive")); -+ usage (EXIT_FAILURE); -+ } -+ - if (human_output_opts == -1) - { - if (posix_format) -diff --git a/tests/df/direct.sh b/tests/df/direct.sh -new file mode 100755 -index 0000000..8e4cfb8 ---- /dev/null -+++ b/tests/df/direct.sh -@@ -0,0 +1,55 @@ -+#!/bin/sh -+# Ensure "df --direct" works as documented -+ -+# Copyright (C) 2010 Free Software Foundation, Inc. -+ -+# This program is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+ -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+ -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+ -+. "${srcdir=.}/init.sh"; path_prepend_ ../src -+print_ver_ df -+ -+df || skip_ "df fails" -+ -+DIR=`pwd` || framework_failure -+FILE="$DIR/file" -+touch "$FILE" || framework_failure -+echo "$FILE" > file_exp || framework_failure -+echo "Mounted on" > header_mounted_exp || framework_failure -+echo "File" > header_file_exp || framework_failure -+ -+fail=0 -+ -+df --portability "$FILE" > df_out || fail=1 -+df --portability --direct "$FILE" > df_direct_out || fail=1 -+df --portability --direct --local "$FILE" > /dev/null 2>&1 && fail=1 -+ -+# check df header -+$AWK '{ if (NR==1) print $6 " " $7; }' df_out > header_mounted_out \ -+ || framework_failure -+$AWK '{ if (NR==1) print $6; }' df_direct_out > header_file_out \ -+ || framework_failure -+compare header_mounted_out header_mounted_exp || fail=1 -+compare header_file_out header_file_exp || fail=1 -+ -+# check df output (without --direct) -+$AWK '{ if (NR==2) print $6; }' df_out > file_out \ -+ || framework_failure -+compare file_out file_exp && fail=1 -+ -+# check df output (with --direct) -+$AWK '{ if (NR==2) print $6; }' df_direct_out > file_out \ -+ || framework_failure -+compare file_out file_exp || fail=1 -+ -+Exit $fail --- -2.52.0 - diff --git a/coreutils-futimens.patch b/coreutils-futimens.patch new file mode 100644 index 0000000..bb08384 --- /dev/null +++ b/coreutils-futimens.patch @@ -0,0 +1,47 @@ +--- coreutils-6.9/lib/utimens.h.futimens 2007-02-23 18:25:21.000000000 +0000 ++++ coreutils-6.9/lib/utimens.h 2007-06-13 11:40:37.000000000 +0100 +@@ -1,3 +1,3 @@ + #include +-int futimens (int, char const *, struct timespec const [2]); ++int gl_futimens (int, char const *, struct timespec const [2]); + int utimens (char const *, struct timespec const [2]); +--- coreutils-6.9/lib/utimens.c.futimens 2007-01-18 08:33:34.000000000 +0000 ++++ coreutils-6.9/lib/utimens.c 2007-06-13 11:40:37.000000000 +0100 +@@ -75,7 +75,7 @@ struct utimbuf + Return 0 on success, -1 (setting errno) on failure. */ + + int +-futimens (int fd ATTRIBUTE_UNUSED, ++gl_futimens (int fd ATTRIBUTE_UNUSED, + char const *file, struct timespec const timespec[2]) + { + /* Some Linux-based NFS clients are buggy, and mishandle time stamps +@@ -185,5 +185,5 @@ futimens (int fd ATTRIBUTE_UNUSED, + int + utimens (char const *file, struct timespec const timespec[2]) + { +- return futimens (-1, file, timespec); ++ return gl_futimens (-1, file, timespec); + } +--- coreutils-6.9/src/copy.c.futimens 2007-06-13 11:56:44.000000000 +0100 ++++ coreutils-6.9/src/copy.c 2007-06-13 11:57:00.000000000 +0100 +@@ -547,7 +547,7 @@ copy_reg (char const *src_name, char con + timespec[0] = get_stat_atime (src_sb); + timespec[1] = get_stat_mtime (src_sb); + +- if (futimens (dest_desc, dst_name, timespec) != 0) ++ if (gl_futimens (dest_desc, dst_name, timespec) != 0) + { + error (0, errno, _("preserving times for %s"), quote (dst_name)); + if (x->require_preserve) +--- coreutils-6.9/src/touch.c.futimens 2007-06-13 11:58:00.000000000 +0100 ++++ coreutils-6.9/src/touch.c 2007-06-13 11:58:06.000000000 +0100 +@@ -182,7 +182,7 @@ touch (const char *file) + t = timespec; + } + +- ok = (futimens (fd, (fd == STDOUT_FILENO ? NULL : file), t) == 0); ++ ok = (gl_futimens (fd, (fd == STDOUT_FILENO ? NULL : file), t) == 0); + + if (fd == STDIN_FILENO) + { diff --git a/coreutils-getdateYYYYMMDD.patch b/coreutils-getdateYYYYMMDD.patch new file mode 100644 index 0000000..63cd449 --- /dev/null +++ b/coreutils-getdateYYYYMMDD.patch @@ -0,0 +1,124 @@ +diff -urNp coreutils-6.9.orig/lib/getdate.y coreutils-6.9/lib/getdate.y +--- coreutils-6.9.orig/lib/getdate.y 2007-02-23 19:25:21.000000000 +0100 ++++ coreutils-6.9/lib/getdate.y 2007-11-23 10:27:13.000000000 +0100 +@@ -199,6 +199,42 @@ static int yylex (union YYSTYPE *, parse + static int yyerror (parser_control const *, char const *); + static long int time_zone_hhmm (textint, long int); + ++static void ++digits_to_date_time (parser_control *pc, textint text_int) ++{ ++ if (pc->dates_seen && ! pc->year.digits ++ && ! pc->rels_seen && (pc->times_seen || 2 < text_int.digits)) ++ pc->year = text_int; ++ else ++ { ++ if (4 < text_int.digits) ++ { ++ pc->dates_seen++; ++ pc->day = text_int.value % 100; ++ pc->month = (text_int.value / 100) % 100; ++ pc->year.value = text_int.value / 10000; ++ pc->year.digits = text_int.digits - 4; ++ } ++ else ++ { ++ pc->times_seen++; ++ if (text_int.digits <= 2) ++ { ++ pc->hour = text_int.value; ++ pc->minutes = 0; ++ } ++ else ++ { ++ pc->hour = text_int.value / 100; ++ pc->minutes = text_int.value % 100; ++ } ++ pc->seconds.tv_sec = 0; ++ pc->seconds.tv_nsec = 0; ++ pc->meridian = MER24; ++ } ++ } ++} ++ + %} + + /* We want a reentrant parser, even if the TZ manipulation and the calls to +@@ -268,6 +304,7 @@ item: + | rel + { pc->rels_seen = true; } + | number ++ | hybrid + ; + + time: +@@ -543,38 +580,23 @@ unsigned_seconds: + + number: + tUNUMBER ++ { digits_to_date_time (pc, $1); } ++ ; ++ ++hybrid: ++ tUNUMBER relunit_snumber + { +- if (pc->dates_seen && ! pc->year.digits +- && ! pc->rels_seen && (pc->times_seen || 2 < $1.digits)) +- pc->year = $1; +- else +- { +- if (4 < $1.digits) +- { +- pc->dates_seen++; +- pc->day = $1.value % 100; +- pc->month = ($1.value / 100) % 100; +- pc->year.value = $1.value / 10000; +- pc->year.digits = $1.digits - 4; +- } +- else +- { +- pc->times_seen++; +- if ($1.digits <= 2) +- { +- pc->hour = $1.value; +- pc->minutes = 0; +- } +- else +- { +- pc->hour = $1.value / 100; +- pc->minutes = $1.value % 100; +- } +- pc->seconds.tv_sec = 0; +- pc->seconds.tv_nsec = 0; +- pc->meridian = MER24; +- } +- } ++ /* Hybrid all-digit and relative offset, so that we accept e.g., ++ "YYYYMMDD +N days" as well as "YYYYMMDD N days". */ ++ digits_to_date_time (pc, $1); ++ pc->rel.ns += $2.ns; ++ pc->rel.seconds += $2.seconds; ++ pc->rel.minutes += $2.minutes; ++ pc->rel.hour += $2.hour; ++ pc->rel.day += $2.day; ++ pc->rel.month += $2.month; ++ pc->rel.year += $2.year; ++ pc->rels_seen = true; + } + ; + +diff -urNp coreutils-6.9.orig/tests/misc/date coreutils-6.9/tests/misc/date +--- coreutils-6.9.orig/tests/misc/date 2007-03-18 22:36:43.000000000 +0100 ++++ coreutils-6.9/tests/misc/date 2007-11-23 10:14:19.000000000 +0100 +@@ -135,6 +135,11 @@ my @Tests = + ['next-mo', "-d '$d1 next month' '+%Y-%m-%d %T'", {OUT=>"$dm $t0"}], + ['next-y', "-d '$d1 next year' '+%Y-%m-%d %T'", {OUT=>"$dy $t0"}], + ++ # This has always worked, ... ++ ['rel-1', "-d '20050101 1 day' +%F", {OUT=>"2005-01-02"}], ++ # ...but up to coreutils-6.9, this was rejected due to the "+". ++ ['rel-1p', "-d '20050101 +1 day' +%F", {OUT=>"2005-01-02"}], ++ + ['utc-0', "-u -d '08/01/97 6:00' '+%D,%H:%M'", {OUT=>"08/01/97,06:00"}, + {ENV => 'TZ=UTC+4'}], + diff --git a/coreutils-getfacl-exit-code.patch b/coreutils-getfacl-exit-code.patch new file mode 100644 index 0000000..a6bccc3 --- /dev/null +++ b/coreutils-getfacl-exit-code.patch @@ -0,0 +1,23 @@ +--- coreutils-6.8+/tests/cp/acl.getfacl-exit-code 2007-03-01 16:48:29.000000000 +0000 ++++ coreutils-6.8+/tests/cp/acl 2007-03-01 16:49:35.000000000 +0000 +@@ -70,16 +70,16 @@ + # copy a file without preserving permissions + cp a/file b/ || fail=1 + +-acl2=`cd b && getfacl file` || framework_failure=1 ++acl2=`cd b && getfacl file` + test "$acl1" = "$acl2" || fail=1 + rm a/file || framework_failure=1 + + # copy a file, preserving permissions + touch a/file || framework_failure=1 +-setfacl -m user:bin:rw a/file || framework_failure=1 +-acl1=`cd a && getfacl file` || framework_failure=1 ++setfacl -m user:bin:rw a/file ++acl1=`cd a && getfacl file` + cp -p a/file b/ || fail=1 +-acl2=`cd b && getfacl file` || framework_failure=1 ++acl2=`cd b && getfacl file` + test "$acl1" = "$acl2" || fail=1 + + if test $framework_failure = 1; then diff --git a/coreutils-getgrouplist.patch b/coreutils-getgrouplist.patch new file mode 100644 index 0000000..0be83c0 --- /dev/null +++ b/coreutils-getgrouplist.patch @@ -0,0 +1,69 @@ +--- 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 ++ + #include + #include /* grp.h on alpha OSF1 V2.0 uses "FILE *". */ + #include +@@ -102,3 +105,4 @@ + + return count; + } ++#endif /* have getgrouplist */ +--- 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); + else +- max_n_groups = getugroups (0, NULL, username, gid); ++ { ++#ifdef HAVE_GETGROUPLIST ++ max_n_groups = 0; ++ getgrouplist (username, gid, NULL, &max_n_groups); ++#else ++ max_n_groups = getugroups (0, NULL, username, gid); ++#endif ++ } + + if (max_n_groups < 0) + ng = -1; +@@ -263,7 +270,22 @@ + if (!username) + ng = getgroups (max_n_groups, g); + else +- ng = getugroups (max_n_groups, g, username, gid); ++ { ++#ifdef HAVE_GETGROUPLIST ++ int e; ++ ng = max_n_groups; ++ while ((e = getgrouplist (username, gid, g, &ng)) == -1 ++ && ng > max_n_groups) ++ { ++ max_n_groups = ng; ++ g = xrealloc (g, max_n_groups * sizeof (GETGROUPS_T)); ++ } ++ if (e == -1) ++ ng = -1; ++#else ++ ng = getugroups (max_n_groups, g, username, gid); ++#endif ++ } + } + + 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 83579e9..108cbc3 100644 --- a/coreutils-i18n.patch +++ b/coreutils-i18n.patch @@ -1,92 +1,132 @@ -From a81b096084524e9aeef5e8b81fc829eb9efec581 Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Wed, 30 Aug 2023 17:19:58 +0200 -Subject: [PATCH] coreutils-i18n.patch - ---- - bootstrap.conf | 2 + - configure.ac | 6 + - lib/linebuffer.h | 8 + - lib/mbfile.c | 20 + - lib/mbfile.h | 283 +++++++++++++ - m4/mbfile.m4 | 16 + - src/cut.c | 508 +++++++++++++++++++++-- - src/expand-common.c | 114 ++++++ - src/expand-common.h | 12 + - src/expand.c | 90 +++- - src/local.mk | 4 +- - src/pr.c | 443 ++++++++++++++++++-- - src/sort.c | 791 +++++++++++++++++++++++++++++++++--- - src/unexpand.c | 101 ++++- - tests/Coreutils.pm | 3 + - tests/expand/mb.sh | 183 +++++++++ - tests/i18n/sort.sh | 29 ++ - tests/local.mk | 4 + - tests/misc/expand.pl | 42 ++ - tests/misc/sort-mb-tests.sh | 45 ++ - tests/misc/unexpand.pl | 39 ++ - tests/pr/pr-tests.pl | 49 +++ - tests/sort/sort-merge.pl | 42 ++ - tests/sort/sort.pl | 40 +- - tests/unexpand/mb.sh | 172 ++++++++ - 25 files changed, 2879 insertions(+), 167 deletions(-) - create mode 100644 lib/mbfile.c - create mode 100644 lib/mbfile.h - create mode 100644 m4/mbfile.m4 - create mode 100644 tests/expand/mb.sh - create mode 100644 tests/i18n/sort.sh - create mode 100644 tests/misc/sort-mb-tests.sh - create mode 100644 tests/unexpand/mb.sh - -diff --git a/bootstrap.conf b/bootstrap.conf -index ec68ac8..ec2fbbe 100644 ---- a/bootstrap.conf -+++ b/bootstrap.conf -@@ -171,6 +171,8 @@ gnulib_modules=" - malloc-gnu - manywarnings - mbbuf -+ mbchar -+ mbfile - mbrlen - mbrtoc32 - mbrtowc -diff --git a/configure.ac b/configure.ac -index 5e99ef3..ac07577 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -465,6 +465,12 @@ fi - # I'm leaving it here for now. This whole thing needs to be modernized... - gl_WINSIZE_IN_PTEM - -+gl_MBFILE -+dnl Do not use gl_MODULE_INDICATOR([mbfile]) here: we don't want 'struct mbchar' -+dnl to have a different size in lib/ than in tests/. -+AC_DEFINE([GNULIB_MBFILE], [1], -+ [Define to 1 if the gnulib module 'mbfile' is in use.]) +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/sort-mb-tests 2007-03-01 15:08:24.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 + - gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H ++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-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/mb2.I 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,4 @@ ++Apple@AA10@@20 ++Banana@AA5@@30 ++Citrus@AA20@@5 ++Cherry@AA30@@10 +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/mb2.X 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,4 @@ ++Citrus@AA20@@5 ++Cherry@AA30@@10 ++Apple@AA10@@20 ++Banana@AA5@@30 +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/mb1.I 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,4 @@ ++Apple@10 ++Banana@5 ++Citrus@20 ++Cherry@30 +--- /dev/null 2007-03-01 09:16:39.219409909 +0000 ++++ coreutils-6.8+/tests/sort/mb1.X 2007-03-01 15:08:24.000000000 +0000 +@@ -0,0 +1,4 @@ ++Banana@5 ++Apple@10 ++Citrus@20 ++Cherry@30 +--- coreutils-6.8+/tests/sort/Makefile.am.i18n 2007-01-24 07:47:37.000000000 +0000 ++++ coreutils-6.8+/tests/sort/Makefile.am 2007-03-01 15:09:59.000000000 +0000 +@@ -66,15 +66,17 @@ + bigfield.O bigfield.E + ##test-files-end - if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \ -diff --git a/lib/linebuffer.h b/lib/linebuffer.h -index ca56f80..509b7e6 100644 ---- a/lib/linebuffer.h -+++ b/lib/linebuffer.h -@@ -27,6 +27,11 @@ extern "C" { - #endif +-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 = \ + CU_TEST_NAME=`basename $(abs_srcdir)`,$$tst \ + 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.8+/lib/linebuffer.h.i18n 2005-05-14 07:44:24.000000000 +0100 ++++ coreutils-6.8+/lib/linebuffer.h 2007-03-01 15:08:24.000000000 +0000 +@@ -22,6 +22,11 @@ + + # include +/* Get mbstate_t. */ +# if HAVE_WCHAR_H +# include +# endif + - /* A 'struct linebuffer' holds a line of text. */ + /* A `struct linebuffer' holds a line of text. */ struct linebuffer -@@ -34,6 +39,9 @@ struct linebuffer - idx_t size; /* Allocated. */ - idx_t length; /* Used. */ +@@ -29,6 +34,9 @@ + size_t size; /* Allocated. */ + size_t length; /* Used. */ char *buffer; +# if HAVE_WCHAR_H + mbstate_t state; @@ -94,365 +134,1090 @@ index ca56f80..509b7e6 100644 }; /* Initialize linebuffer LINEBUFFER for use. */ -diff --git a/lib/mbfile.c b/lib/mbfile.c -new file mode 100644 -index 0000000..f4e3e77 ---- /dev/null -+++ b/lib/mbfile.c -@@ -0,0 +1,20 @@ -+/* Multibyte character I/O: macros for multi-byte encodings. -+ Copyright (C) 2012-2025 Free Software Foundation, Inc. -+ -+ This file is free software: you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation, either version 3 of the -+ License, or (at your option) any later version. -+ -+ This file is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public License -+ along with this program. If not, see . */ -+ -+#include -+ -+#define MBFILE_INLINE _GL_EXTERN_INLINE -+#include "mbfile.h" -diff --git a/lib/mbfile.h b/lib/mbfile.h -new file mode 100644 -index 0000000..c852f31 ---- /dev/null -+++ b/lib/mbfile.h -@@ -0,0 +1,283 @@ -+/* Multibyte character I/O: macros for multi-byte encodings. -+ Copyright (C) 2001, 2005, 2009-2025 Free Software Foundation, Inc. -+ -+ This file is free software: you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation, either version 3 of the -+ License, or (at your option) any later version. -+ -+ This file is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public License -+ along with this program. If not, see . */ -+ -+/* Written by Mitsuru Chinen -+ and Bruno Haible . */ -+ -+/* The macros in this file implement multi-byte character input from a -+ stream. -+ -+ mb_file_t -+ is the type for multibyte character input stream, usable for variable -+ declarations. -+ -+ mbf_char_t -+ is the type for multibyte character or EOF, usable for variable -+ declarations. -+ -+ mbf_init (mbf, stream) -+ initializes the MB_FILE for reading from stream. -+ -+ mbf_getc (mbc, mbf) -+ reads the next multibyte character from mbf and stores it in mbc. -+ -+ mb_iseof (mbc) -+ returns true if mbc represents the EOF value. -+ -+ Here are the function prototypes of the macros. -+ -+ extern void mbf_init (mb_file_t mbf, FILE *stream); -+ extern void mbf_getc (mbf_char_t mbc, mb_file_t mbf); -+ extern bool mb_iseof (const mbf_char_t mbc); -+ */ -+ -+#ifndef _MBFILE_H -+#define _MBFILE_H 1 -+ -+/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ -+#if !_GL_CONFIG_H_INCLUDED -+ #error "Please include config.h first." -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "mbchar.h" -+ -+_GL_INLINE_HEADER_BEGIN -+#ifndef MBFILE_INLINE -+# define MBFILE_INLINE _GL_INLINE -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/* Guarantee two characters of pushback. */ -+#define MBFILE_MAX_PUSHBACK 2 -+ -+struct mbfile_multi { -+ FILE *fp; -+ bool eof_seen; -+ unsigned int pushback_count; /* <= MBFILE_MAX_PUSHBACK */ -+ mbstate_t state; -+ unsigned int bufcount; -+ char buf[MBCHAR_BUF_SIZE]; -+ struct mbchar pushback[MBFILE_MAX_PUSHBACK]; -+}; -+ -+MBFILE_INLINE void -+mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf) -+{ -+ unsigned int new_bufcount; -+ size_t bytes; -+ -+ /* Return character pushed back, if there is one. */ -+ if (mbf->pushback_count > 0) -+ { -+ mb_copy (mbc, &mbf->pushback[mbf->pushback_count - 1]); -+ mbf->pushback_count--; -+ return; -+ } -+ -+ /* If EOF has already been seen, don't use getc. This matters if -+ mbf->fp is connected to an interactive tty. */ -+ if (mbf->eof_seen) -+ goto eof; -+ -+ new_bufcount = mbf->bufcount; -+ -+ /* If mbf->state is not in an initial state, some more 32-bit wide character -+ may be hiding in the state. We need to call mbrtoc32 again. */ -+ #if GNULIB_MBRTOC32_REGULAR -+ assert (mbsinit (&mbf->state)); -+ #else -+ if (mbsinit (&mbf->state)) -+ #endif -+ { -+ /* Before using mbrtoc32, we need at least one byte. */ -+ if (new_bufcount == 0) -+ { -+ int c = getc (mbf->fp); -+ if (c == EOF) -+ { -+ mbf->eof_seen = true; -+ goto eof; -+ } -+ mbf->buf[0] = (unsigned char) c; -+ new_bufcount++; -+ } -+ -+ /* Handle most ASCII characters quickly, without calling mbrtoc32(). */ -+ if (new_bufcount == 1 && is_basic (mbf->buf[0])) -+ { -+ /* These characters are part of the POSIX portable character set. -+ For most of them, namely those in the ISO C basic character set, -+ ISO C 99 guarantees that their wide character code is identical to -+ their char code. For the few other ones, this is the case as well, -+ in all locale encodings that are in use. The 32-bit wide character -+ code is the same as well. */ -+ mbc->wc = mbc->buf[0] = mbf->buf[0]; -+ mbc->wc_valid = true; -+ mbc->ptr = &mbc->buf[0]; -+ mbc->bytes = 1; -+ mbf->bufcount = 0; -+ return; -+ } -+ } -+ -+ /* Use mbrtoc32 on an increasing number of bytes. Read only as many bytes -+ from mbf->fp as needed. This is needed to give reasonable interactive -+ behaviour when mbf->fp is connected to an interactive tty. */ -+ for (;;) -+ { -+ /* Feed the bytes one by one into mbrtoc32. */ -+ bytes = mbrtoc32 (&mbc->wc, &mbf->buf[mbf->bufcount], new_bufcount - mbf->bufcount, &mbf->state); -+ -+ if (bytes == (size_t) -1) -+ { -+ /* An invalid multibyte sequence was encountered. */ -+ mbf->bufcount = new_bufcount; -+ /* Return a single byte. */ -+ bytes = 1; -+ mbc->wc_valid = false; -+ /* Allow the next invocation to continue from a sane state. */ -+ mbszero (&mbf->state); -+ break; -+ } -+ else if (bytes == (size_t) -2) -+ { -+ /* An incomplete multibyte character. */ -+ mbf->bufcount = new_bufcount; -+ if (mbf->bufcount == MBCHAR_BUF_SIZE) -+ { -+ /* An overlong incomplete multibyte sequence was encountered. */ -+ /* Return a single byte. */ -+ bytes = 1; -+ mbc->wc_valid = false; -+ break; -+ } -+ else -+ { -+ /* Read one more byte and retry mbrtoc32. */ -+ int c = getc (mbf->fp); -+ if (c == EOF) -+ { -+ /* An incomplete multibyte character at the end. */ -+ mbf->eof_seen = true; -+ bytes = new_bufcount; -+ mbc->wc_valid = false; -+ break; -+ } -+ mbf->buf[new_bufcount] = (unsigned char) c; -+ new_bufcount++; -+ } -+ } -+ else -+ { -+ #if !GNULIB_MBRTOC32_REGULAR -+ if (bytes == (size_t) -3) -+ { -+ /* The previous multibyte sequence produced an additional 32-bit -+ wide character. */ -+ mbf->bufcount = new_bufcount; -+ bytes = 0; -+ } -+ else -+ #endif -+ { -+ bytes = mbf->bufcount + bytes; -+ mbf->bufcount = new_bufcount; -+ if (bytes == 0) -+ { -+ /* A null 32-bit wide character was encountered. */ -+ bytes = 1; -+ assert (mbf->buf[0] == '\0'); -+ assert (mbc->wc == 0); -+ } -+ } -+ mbc->wc_valid = true; -+ break; -+ } -+ } -+ -+ /* Return the multibyte sequence mbf->buf[0..bytes-1]. */ -+ mbc->ptr = &mbc->buf[0]; -+ memcpy (&mbc->buf[0], &mbf->buf[0], bytes); -+ mbc->bytes = bytes; -+ -+ mbf->bufcount -= bytes; -+ if (mbf->bufcount > 0) -+ { -+ /* It's not worth calling memmove() for so few bytes. */ -+ unsigned int count = mbf->bufcount; -+ char *p = &mbf->buf[0]; -+ -+ do -+ { -+ *p = *(p + bytes); -+ p++; -+ } -+ while (--count > 0); -+ } -+ return; -+ -+eof: -+ /* An mbchar_t with bytes == 0 is used to indicate EOF. */ -+ mbc->ptr = NULL; -+ mbc->bytes = 0; -+ mbc->wc_valid = false; -+ return; -+} -+ -+MBFILE_INLINE void -+mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf) -+{ -+ if (mbf->pushback_count == MBFILE_MAX_PUSHBACK) -+ abort (); -+ mb_copy (&mbf->pushback[mbf->pushback_count], mbc); -+ mbf->pushback_count++; -+} -+ -+typedef struct mbfile_multi mb_file_t; -+ -+typedef mbchar_t mbf_char_t; -+ -+#define mbf_init(mbf, stream) \ -+ ((mbf).fp = (stream), \ -+ (mbf).eof_seen = false, \ -+ (mbf).pushback_count = 0, \ -+ mbszero (&(mbf).state), \ -+ (mbf).bufcount = 0) -+ -+#define mbf_getc(mbc, mbf) mbfile_multi_getc (&(mbc), &(mbf)) -+ -+#define mbf_ungetc(mbc, mbf) mbfile_multi_ungetc (&(mbc), &(mbf)) -+ -+#define mb_iseof(mbc) ((mbc).bytes == 0) -+ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+_GL_INLINE_HEADER_END -+ -+#endif /* _MBFILE_H */ -diff --git a/m4/mbfile.m4 b/m4/mbfile.m4 -new file mode 100644 -index 0000000..1d126e0 ---- /dev/null -+++ b/m4/mbfile.m4 -@@ -0,0 +1,16 @@ -+# mbfile.m4 -+# serial 7 -+dnl Copyright (C) 2005, 2008-2025 Free Software Foundation, Inc. -+dnl This file is free software; the Free Software Foundation -+dnl gives unlimited permission to copy and/or distribute it, -+dnl with or without modifications, as long as this notice is preserved. -+dnl This file is offered as-is, without any warranty. -+ -+dnl autoconf tests required for use of mbfile.h -+dnl From Bruno Haible. -+ -+AC_DEFUN([gl_MBFILE], -+[ -+ AC_REQUIRE([AC_TYPE_MBSTATE_T]) -+ : -+]) -diff --git a/src/cut.c b/src/cut.c -index f0effb9..36479d6 100644 ---- a/src/cut.c -+++ b/src/cut.c -@@ -27,6 +27,11 @@ +--- coreutils-6.8+/src/expand.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/expand.c 2007-03-01 15:08:24.000000000 +0000 +@@ -38,11 +38,28 @@ #include #include #include + -+/* Get mbstate_t, mbrtowc(). */ ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ +#if HAVE_WCHAR_H +# include +#endif ++ #include "system.h" - - #include "assure.h" -@@ -35,6 +40,18 @@ - - #include "set-fields.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. */ ++ 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 "expand" + +@@ -183,6 +200,7 @@ + stops = num_start + len - 1; + } + } ++ + else + { + error (0, 0, _("tab size contains invalid character(s): %s"), +@@ -365,6 +383,142 @@ + } + } + ++#if HAVE_MBRTOWC ++static void ++expand_multibyte (void) ++{ ++ FILE *fp; /* Input strem. */ ++ 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. */ ++ wchar_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character ++ which shows as same character as WC. */ ++ int tab_index = 0; /* Index in `tab_list' of next tabstop. */ ++ int column = 0; /* Column on screen of the next char. */ ++ int next_tab_column; /* Column the next tab stop is on. */ ++ int convert = 1; /* If nonzero, perform translations. */ ++ ++ fp = next_file ((FILE *) NULL); ++ if (fp == NULL) ++ return; ++ ++ memset (&o_state, '\0', sizeof(mbstate_t)); ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ ++ for (;;) ++ { ++ /* Refill the buffer BUF. */ ++ if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp)) ++ { ++ memmove (buf, bufpos, buflen); ++ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp); ++ bufpos = buf; ++ } ++ ++ /* No character is left in BUF. */ ++ if (buflen < 1) ++ { ++ fp = next_file (fp); ++ ++ if (fp == NULL) ++ break; /* No more files. */ ++ else ++ { ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ continue; ++ } ++ } ++ ++ /* Get a wide character. */ ++ i_state_bak = i_state; ++ mblength = mbrtowc (&wc, bufpos, buflen, &i_state); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: /* illegal byte sequence. */ ++ case (size_t)-2: ++ mblength = 1; ++ i_state = i_state_bak; ++ if (convert) ++ { ++ ++column; ++ if (convert_entire_line == 0) ++ convert = 0; ++ } ++ putchar (*bufpos); ++ break; ++ ++ case 0: /* null. */ ++ mblength = 1; ++ if (convert && convert_entire_line == 0) ++ convert = 0; ++ putchar ('\0'); ++ break; ++ ++ default: ++ if (wc == L'\n') /* LF. */ ++ { ++ tab_index = 0; ++ column = 0; ++ convert = 1; ++ putchar ('\n'); ++ } ++ else if (wc == L'\t' && convert) /* Tab. */ ++ { ++ 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) ++ next_tab_column = column + 1; ++ } ++ else ++ next_tab_column = column + tab_size - column % tab_size; ++ ++ while (column < next_tab_column) ++ { ++ putchar (' '); ++ ++column; ++ } ++ } ++ else /* Others. */ ++ { ++ 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; ++ } ++ } ++ fwrite (bufpos, sizeof(char), mblength, stdout); ++ } ++ } ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++} ++#endif ++ + int + main (int argc, char **argv) + { +@@ -429,7 +583,12 @@ + + file_list = (optind < argc ? &argv[optind] : stdin_argv); + +- expand (); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ expand_multibyte (); ++ else ++#endif ++ expand (); + + if (have_read_stdin && fclose (stdin) != 0) + error (EXIT_FAILURE, errno, "-"); +--- coreutils-6.8+/src/join.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/join.c 2007-03-01 15:08:24.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'); +@@ -859,20 +1090,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.8+/src/uniq.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/uniq.c 2007-03-01 15:08:24.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'}, +@@ -198,7 +224,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; +@@ -219,6 +245,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. +@@ -227,6 +330,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) +@@ -234,14 +339,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. +@@ -295,15 +478,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)) + { +@@ -322,17 +533,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)) +@@ -341,6 +561,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; + +@@ -373,6 +602,9 @@ + SWAP_LINES (prevline, thisline); + prevfield = thisfield; + prevlen = thislen; ++#if HAVE_MBRTOWC ++ prevstate = thisstate; ++#endif + if (!match) + match_count = 0; + } +@@ -417,6 +649,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.8+/src/fold.c.i18n 2007-02-23 12:01:47.000000000 +0000 ++++ coreutils-6.8+/src/fold.c 2007-03-01 15:08:24.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 @@ -463,965 +1228,1504 @@ index f0effb9..36479d6 100644 +# 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 "cut" + #define TAB_WIDTH 8 -@@ -51,6 +68,52 @@ - } \ - while (0) + /* The official name of this program (e.g., no `g' prefix). */ +@@ -35,23 +57,44 @@ -+/* Refill the buffer BUF to get a multibyte character. */ -+#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM) \ -+ do \ -+ { \ -+ if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM)) \ -+ { \ -+ memmove (BUF, BUFPOS, BUFLEN); \ -+ BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \ -+ BUFPOS = BUF; \ -+ } \ -+ } \ + #define AUTHORS "David MacKenzie" + ++#define FATAL_ERROR(Message) \ ++ do \ ++ { \ ++ error (0, 0, (Message)); \ ++ usage (2); \ ++ } \ + while (0) + -+/* Get wide character on BUFPOS. BUFPOS is not included after that. -+ If byte sequence is not valid as a character, CONVFAIL is true. Otherwise false. */ -+#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \ -+ do \ -+ { \ -+ mbstate_t state_bak; \ -+ \ -+ if (BUFLEN < 1) \ -+ { \ -+ WC = WEOF; \ -+ break; \ -+ } \ -+ \ -+ /* Get a wide character. */ \ -+ CONVFAIL = false; \ -+ state_bak = STATE; \ -+ MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE); \ -+ \ -+ switch (MBLENGTH) \ -+ { \ -+ case (size_t)-1: \ -+ case (size_t)-2: \ -+ CONVFAIL = true; \ -+ STATE = state_bak; \ -+ /* Fall througn. */ \ -+ \ -+ case 0: \ -+ MBLENGTH = 1; \ -+ break; \ -+ } \ -+ } \ -+ while (0) -+ - - /* Pointer inside RP. When checking if a byte or field is selected - by a finite range, we check if it is between CURRENT_RP.LO -@@ -58,6 +121,9 @@ - CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */ - static struct field_range_pair *current_rp; - -+/* Length of the delimiter given as argument to -d. */ -+size_t delimlen; -+ - /* This buffer is used to support the semantics of the -s option - (or lack of same) when the specified field list includes (does - not include) the first field. In both of those cases, the entire -@@ -70,6 +136,29 @@ static char *field_1_buffer; - /* The number of bytes allocated for FIELD_1_BUFFER. */ - static size_t field_1_bufsize; - +enum operating_mode -+ { -+ undefined_mode, ++{ ++ /* Fold texts by columns that are at the given positions. */ ++ column_mode, + -+ /* Output bytes that are at the given positions. */ -+ byte_mode, ++ /* Fold texts by bytes that are at the given positions. */ ++ byte_mode, + -+ /* Output characters that are at the given positions. */ -+ character_mode, -+ -+ /* Output the given delimiter-separated fields. */ -+ field_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, when in byte mode, don't split multibyte characters. */ -+static int byte_mode_character_aware; -+ -+/* If nonzero, the function for single byte locale is work -+ if this program runs on multibyte locale. */ -+static int force_singlebyte_mode; -+ - /* If true, do not output lines containing no delimiter characters. - Otherwise, all such lines are printed. This option is valid only - with field mode. */ -@@ -81,10 +170,16 @@ static bool complement; + /* If nonzero, try to break on whitespace. */ + static bool break_spaces; - /* The delimiter character for field mode. */ - static unsigned char delim; -+#if HAVE_WCHAR_H -+static wchar_t wcdelim; -+#endif - - /* The delimiter for each line/record. */ - static unsigned char line_delim = '\n'; - -+/* True if the --output-delimiter=STRING option was specified. */ -+static bool output_delimiter_specified; -+ - /* The length of output_delimiter_string. */ - static size_t output_delimiter_length; - -@@ -92,9 +187,6 @@ static size_t output_delimiter_length; - string consisting of the input delimiter. */ - static char *output_delimiter_string; - --/* The output delimiter string contents, if the default. */ --static char output_delimiter_default[1]; +-/* If nonzero, count bytes, not column positions. */ +-static bool count_bytes; - - /* True if we have ever read standard input. */ + /* If nonzero, at least one of the files we read was standard input. */ static bool have_read_stdin; -@@ -148,7 +240,7 @@ Print selected parts of lines from each FILE to standard output.\n\ - -f, --fields=LIST select only these fields; also print any line\n\ - that contains no delimiter character, unless\n\ - the -s option is specified\n\ -- -n (ignored)\n\ -+ -n with -b: don't split multibyte characters\n\ +-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 (_("\ - --complement complement the set of selected bytes, characters\n\ -@@ -252,7 +344,7 @@ cut_bytes (FILE *stream) - next_item (&byte_idx); - if (print_kth (byte_idx)) - { -- if (output_delimiter_string != output_delimiter_default) -+ if (output_delimiter_specified) - { - if (print_delimiter && is_range_start_index (byte_idx)) - { -@@ -271,6 +363,82 @@ cut_bytes (FILE *stream) + -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.8+/src/sort.c.i18n 2007-02-24 11:23:23.000000000 +0000 ++++ coreutils-6.8+/src/sort.c 2007-03-01 15:10:57.000000000 +0000 +@@ -23,10 +23,19 @@ + + #include + ++#include + #include + #include + #include + #include ++#if HAVE_WCHAR_H ++# include ++#endif ++/* Get isw* functions. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "argmatch.h" + #include "error.h" +@@ -116,14 +125,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 }; + +@@ -261,13 +294,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. */ +@@ -639,6 +670,44 @@ + update_proc (pid); + } + ++/* 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 +@@ -978,7 +1047,7 @@ + free (node); + } + +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + + static int + struct_month_cmp (const void *m1, const void *m2) +@@ -993,7 +1062,7 @@ + /* Initialize the character class tables. */ + + static void +-inittables (void) ++inittables_uni (void) + { + size_t i; + +@@ -1005,7 +1074,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) + { +@@ -1031,6 +1100,64 @@ + #endif } +#if HAVE_MBRTOWC -+/* This function is in use for the following case. -+ -+ 1. Read from the stream STREAM, printing to standard output any selected -+ characters. -+ -+ 2. Read from stream STREAM, printing to standard output any selected bytes, -+ without splitting multibyte characters. */ -+ +static void -+cut_characters_or_cut_bytes_no_split (FILE *stream) ++inittables_mb (void) +{ -+ uintmax_t idx; /* number of bytes or characters in the line so far. */ -+ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ -+ char *bufpos; /* Next read position of BUF. */ -+ size_t buflen; /* 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. */ -+ mbstate_t state; /* State of the stream. */ -+ bool convfail = false; /* true, when conversion failed. Otherwise false. */ -+ /* Whether to begin printing delimiters between ranges for the current line. -+ Set after we've begun printing data corresponding to the first range. */ -+ bool print_delimiter = false; ++ 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) +@@ -1241,7 +1368,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; +@@ -1251,10 +1378,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; +@@ -1282,11 +1409,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; + -+ idx = 0; -+ buflen = 0; -+ bufpos = buf; + memset (&state, '\0', sizeof(mbstate_t)); + -+ current_rp = frp; ++ 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; ++ } + -+ while (1) ++ if (key->skipsblanks) ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ ++ for (i = 0; i < schar; i++) + { -+ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); + -+ GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail); -+ (void) convfail; /* ignore unused */ -+ -+ if (wc == WEOF) -+ { -+ if (idx > 0) -+ putchar (line_delim); -+ break; -+ } -+ else if (wc == line_delim) -+ { -+ putchar (line_delim); -+ idx = 0; -+ print_delimiter = false; -+ current_rp = frp; -+ } ++ if (ptr + mblength > lim) ++ break; + else -+ { -+ next_item (&idx); -+ if (print_kth (idx)) -+ { -+ if (output_delimiter_specified) -+ { -+ if (print_delimiter && is_range_start_index (idx)) -+ { -+ fwrite (output_delimiter_string, sizeof (char), -+ output_delimiter_length, stdout); -+ } -+ print_delimiter = true; -+ } -+ fwrite (bufpos, mblength, sizeof(char), stdout); -+ } -+ } ++ 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; +@@ -1299,10 +1485,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; +@@ -1348,10 +1534,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; + } +@@ -1384,6 +1570,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 +@@ -1466,8 +1753,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; + } + } +@@ -1500,7 +1803,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++; +@@ -1510,6 +1813,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) + { +@@ -1543,7 +1865,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; +@@ -1698,11 +2020,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; + +@@ -1875,6 +2265,179 @@ + 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->random) ++ diff = compare_random (texta, lena, textb, lenb); ++ else 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. */ + +@@ -2744,7 +3305,7 @@ + initialize_exit_failure (SORT_FAILURE); + + hard_LC_COLLATE = hard_locale (LC_COLLATE); +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + hard_LC_TIME = hard_locale (LC_TIME); + #endif + +@@ -2765,6 +3326,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 (); + +@@ -3015,13 +3597,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 +@@ -3032,9 +3636,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.8+/src/unexpand.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/unexpand.c 2007-03-01 15:08:24.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 + - /* Read from stream STREAM, printing to standard output any selected fields. */ - - static void -@@ -433,11 +601,218 @@ cut_fields (FILE *stream) - } - } - --/* Process file FILE to standard output, using CUT_STREAM. -+#if HAVE_MBRTOWC -+static void -+cut_fields_mb (FILE *stream) -+{ -+ int c; -+ uintmax_t field_idx; -+ int found_any_selected_field; -+ int buffer_first_field; -+ int empty_input; -+ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ -+ char *bufpos; /* Next read position of BUF. */ -+ size_t buflen; /* The length of the byte sequence in buf. */ -+ wint_t wc = 0; /* 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 of the stream. */ -+ bool convfail = false; /* true, when conversion failed. Otherwise false. */ + -+ current_rp = frp; -+ -+ found_any_selected_field = 0; -+ field_idx = 1; -+ bufpos = buf; -+ buflen = 0; -+ memset (&state, '\0', sizeof(mbstate_t)); -+ -+ c = getc (stream); -+ empty_input = (c == EOF); -+ if (c != EOF) -+ { -+ ungetc (c, stream); -+ wc = 0; -+ } -+ else -+ wc = WEOF; -+ -+ /* To support the semantics of the -s flag, we may have to buffer -+ all of the first field to determine whether it is `delimited.' -+ But that is unnecessary if all non-delimited lines must be printed -+ and the first field has been selected, or if non-delimited lines -+ must be suppressed and the first field has *not* been selected. -+ That is because a non-delimited line has exactly one field. */ -+ buffer_first_field = (suppress_non_delimited ^ !print_kth (1)); -+ -+ while (1) -+ { -+ if (field_idx == 1 && buffer_first_field) -+ { -+ int len = 0; -+ -+ while (1) -+ { -+ REFILL_BUFFER (buf, bufpos, buflen, stream); -+ -+ GET_NEXT_WC_FROM_BUFFER -+ (wc, bufpos, buflen, mblength, state, convfail); -+ -+ if (wc == WEOF) -+ break; -+ -+ field_1_buffer = xrealloc (field_1_buffer, len + mblength); -+ memcpy (field_1_buffer + len, bufpos, mblength); -+ len += mblength; -+ buflen -= mblength; -+ bufpos += mblength; -+ -+ if (!convfail && (wc == line_delim || wc == wcdelim)) -+ break; -+ } -+ -+ if (len <= 0 && wc == WEOF) -+ break; -+ -+ /* If the first field extends to the end of line (it is not -+ delimited) and we are printing all non-delimited lines, -+ print this one. */ -+ if (convfail || (!convfail && wc != wcdelim)) -+ { -+ if (suppress_non_delimited) -+ { -+ /* Empty. */ -+ } -+ else -+ { -+ fwrite (field_1_buffer, sizeof (char), len, stdout); -+ /* Make sure the output line is newline terminated. */ -+ if (convfail || (!convfail && wc != line_delim)) -+ putchar (line_delim); -+ } -+ continue; -+ } -+ -+ if (print_kth (1)) -+ { -+ /* Print the field, but not the trailing delimiter. */ -+ fwrite (field_1_buffer, sizeof (char), len - 1, stdout); -+ found_any_selected_field = 1; -+ } -+ next_item (&field_idx); -+ } -+ -+ if (wc != WEOF) -+ { -+ if (print_kth (field_idx)) -+ { -+ if (found_any_selected_field) -+ { -+ fwrite (output_delimiter_string, sizeof (char), -+ output_delimiter_length, stdout); -+ } -+ found_any_selected_field = 1; -+ } -+ -+ while (1) -+ { -+ REFILL_BUFFER (buf, bufpos, buflen, stream); -+ -+ GET_NEXT_WC_FROM_BUFFER -+ (wc, bufpos, buflen, mblength, state, convfail); -+ -+ if (wc == WEOF) -+ break; -+ else if (!convfail && (wc == wcdelim || wc == line_delim)) -+ { -+ buflen -= mblength; -+ bufpos += mblength; -+ break; -+ } -+ -+ if (print_kth (field_idx)) -+ fwrite (bufpos, mblength, sizeof(char), stdout); -+ -+ buflen -= mblength; -+ bufpos += mblength; -+ } -+ } -+ -+ if ((!convfail || wc == line_delim) && buflen < 1) -+ wc = WEOF; -+ -+ if (!convfail && wc == wcdelim) -+ next_item (&field_idx); -+ else if (wc == WEOF || (!convfail && wc == line_delim)) -+ { -+ if (found_any_selected_field -+ || (!empty_input && !(suppress_non_delimited && field_idx == 1))) -+ putchar (line_delim); -+ if (wc == WEOF) -+ break; -+ field_idx = 1; -+ current_rp = frp; -+ found_any_selected_field = 0; -+ } -+ } -+} -+#endif -+ -+static void -+cut_stream (FILE *stream) -+{ -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) -+ { -+ switch (operating_mode) -+ { -+ case byte_mode: -+ if (byte_mode_character_aware) -+ cut_characters_or_cut_bytes_no_split (stream); -+ else -+ cut_bytes (stream); -+ break; -+ -+ case character_mode: -+ cut_characters_or_cut_bytes_no_split (stream); -+ break; -+ -+ case field_mode: -+ if (delimlen == 1) -+ { -+ /* Check if we have utf8 multibyte locale, so we can use this -+ optimization because of uniqueness of characters, which is -+ not true for e.g. SJIS */ -+ char * loc = setlocale(LC_CTYPE, NULL); -+ if (loc && (strstr (loc, "UTF-8") || strstr (loc, "utf-8") || -+ strstr (loc, "UTF8") || strstr (loc, "utf8"))) -+ { -+ cut_fields (stream); -+ break; -+ } -+ } -+ cut_fields_mb (stream); -+ break; -+ -+ default: -+ abort (); -+ } -+ } -+ else -+#endif -+ { -+ if (operating_mode == field_mode) -+ cut_fields (stream); -+ else -+ cut_bytes (stream); -+ } -+} -+ -+/* Process file FILE to standard output. - Return true if successful. */ - - static bool --cut_file (char const *file, void (*cut_stream) (FILE *)) -+cut_file (char const *file) + void + usage (int status) { - FILE *stream; +@@ -531,7 +750,12 @@ -@@ -482,8 +857,8 @@ main (int argc, char **argv) - int optc; - bool ok; - bool delim_specified = false; -- bool byte_mode = false; -- char *spec_list_string = nullptr; -+ char *spec_list_string IF_LINT ( = nullptr); -+ char mbdelim[MB_LEN_MAX + 1]; + file_list = (optind < argc ? &argv[optind] : stdin_argv); - initialize_main (&argc, &argv); - set_program_name (argv[0]); -@@ -493,6 +868,8 @@ main (int argc, char **argv) - - atexit (close_stdout); - -+ operating_mode = undefined_mode; -+ - /* By default, all non-delimited lines are printed. */ - suppress_non_delimited = false; - -@@ -505,35 +882,77 @@ main (int argc, char **argv) - switch (optc) - { - case 'b': -- case 'c': - /* Build the byte list. */ -- byte_mode = true; -- FALLTHROUGH; -+ if (operating_mode != undefined_mode) -+ FATAL_ERROR (_("only one type of list may be specified")); -+ operating_mode = byte_mode; -+ spec_list_string = optarg; -+ break; -+ -+ case 'c': -+ /* Build the character list. */ -+ if (operating_mode != undefined_mode) -+ FATAL_ERROR (_("only one type of list may be specified")); -+ operating_mode = character_mode; -+ spec_list_string = optarg; -+ break; -+ - case 'f': - /* Build the field list. */ -- if (spec_list_string) -- FATAL_ERROR (_("only one list may be specified")); -+ if (operating_mode != undefined_mode) -+ FATAL_ERROR (_("only one type of list may be specified")); -+ operating_mode = field_mode; - spec_list_string = optarg; - break; - - case 'd': - /* New delimiter. */ - /* Interpret -d '' to mean 'use the NUL byte as the delimiter.' */ -- if (optarg[0] != '\0' && optarg[1] != '\0') -- FATAL_ERROR (_("the delimiter must be a single character")); -- delim = optarg[0]; -- delim_specified = true; -+ { +- unexpand (); +#if HAVE_MBRTOWC -+ if(MB_CUR_MAX > 1) -+ { -+ mbstate_t state; -+ -+ memset (&state, '\0', sizeof(mbstate_t)); -+ delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state); -+ -+ if (delimlen == (size_t)-1 || delimlen == (size_t)-2) -+ ++force_singlebyte_mode; -+ else -+ { -+ delimlen = (delimlen < 1) ? 1 : delimlen; -+ if (wcdelim != L'\0' && *(optarg + delimlen) != '\0') -+ FATAL_ERROR (_("the delimiter must be a single character")); -+ memcpy (mbdelim, optarg, delimlen); -+ mbdelim[delimlen] = '\0'; -+ if (delimlen == 1) -+ delim = *optarg; -+ } -+ } -+ -+ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) -+#endif -+ { -+ if (optarg[0] != '\0' && optarg[1] != '\0') -+ FATAL_ERROR (_("the delimiter must be a single character")); -+ delim = (unsigned char) optarg[0]; -+ } -+ delim_specified = true; -+ } - break; - - case OUTPUT_DELIMITER_OPTION: -+ output_delimiter_specified = true; - /* Interpret --output-delimiter='' to mean - 'use the NUL byte as the delimiter.' */ - output_delimiter_length = (optarg[0] == '\0' - ? 1 : strlen (optarg)); -- output_delimiter_string = optarg; -+ output_delimiter_string = xstrdup (optarg); - break; - - case 'n': -+ byte_mode_character_aware = 1; - break; - - case 's': -@@ -555,40 +974,57 @@ main (int argc, char **argv) - } - } - -- if (!spec_list_string) -+ if (operating_mode == undefined_mode) - FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); - -- if (byte_mode) -- { -- if (delim_specified) -- FATAL_ERROR (_("an input delimiter may be specified only\ -+ if (delim_specified && operating_mode != field_mode) -+ FATAL_ERROR (_("an input delimiter may be specified only\ - when operating on fields")); - -- if (suppress_non_delimited) -- FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\ -+ if (suppress_non_delimited && operating_mode != field_mode) -+ FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\ - \tonly when operating on fields")); -- } - - set_fields (spec_list_string, -- ((byte_mode ? SETFLD_ERRMSG_USE_POS : 0) -- | (complement ? SETFLD_COMPLEMENT : 0))); -+ ( (operating_mode == field_mode) ? 0 : SETFLD_ERRMSG_USE_POS) -+ | (complement ? SETFLD_COMPLEMENT : 0) ); - - if (!delim_specified) -- delim = '\t'; -+ { -+ delim = '\t'; -+#ifdef HAVE_MBRTOWC -+ wcdelim = L'\t'; -+ mbdelim[0] = '\t'; -+ mbdelim[1] = '\0'; -+ delimlen = 1; -+#endif -+ } - - if (output_delimiter_string == nullptr) - { -- output_delimiter_default[0] = delim; -- output_delimiter_string = output_delimiter_default; -- output_delimiter_length = 1; -+#ifdef HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) -+ { -+ output_delimiter_string = xstrdup(mbdelim); -+ output_delimiter_length = delimlen; -+ } -+ -+ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) -+#endif -+ { -+ static char dummy[2]; -+ dummy[0] = delim; -+ dummy[1] = '\0'; -+ output_delimiter_string = dummy; -+ output_delimiter_length = 1; -+ } - } - -- void (*cut_stream) (FILE *) = byte_mode ? cut_bytes : cut_fields; - if (optind == argc) -- ok = cut_file ("-", cut_stream); -+ ok = cut_file ("-"); - else - for (ok = true; optind < argc; optind++) -- ok &= cut_file (argv[optind], cut_stream); -+ ok &= cut_file (argv[optind]); - - - if (have_read_stdin && fclose (stdin) == EOF) -diff --git a/src/expand-common.c b/src/expand-common.c -index 14dd804..0d8eaaa 100644 ---- a/src/expand-common.c -+++ b/src/expand-common.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include "system.h" - #include "c-ctype.h" - #include "fadvise.h" -@@ -132,6 +133,119 @@ set_increment_size (colno tabval) - return ok; - } - -+extern int -+set_utf_locale (void) -+{ -+ /*try using some predefined locale */ -+ const char* predef_locales[] = {"C.UTF8","en_US.UTF8","en_GB.UTF8"}; -+ -+ const int predef_locales_count=3; -+ for (int i=0;ibufcount=0; -+ if (c == 0xEF) -+ { -+ c=fgetc(fp); -+ } ++ if (MB_CUR_MAX > 1) ++ unexpand_multibyte (); + else -+ { -+ if (c != EOF) -+ { -+ ungetc(c,fp); -+ } -+ return false; -+ } -+ -+ if (c == 0xBB) -+ { -+ c=fgetc(fp); -+ } -+ else -+ { -+ if ( c!= EOF ) -+ { -+ mbf->buf[0]=(unsigned char) 0xEF; -+ mbf->bufcount=1; -+ ungetc(c,fp); -+ return false; -+ } -+ else -+ { -+ ungetc(0xEF,fp); -+ return false; -+ } -+ } -+ if (c == 0xBF) -+ { -+ mbf->bufcount=0; -+ return true; -+ } -+ else -+ { -+ if (c != EOF) -+ { -+ mbf->buf[0]=(unsigned char) 0xEF; -+ mbf->buf[1]=(unsigned char) 0xBB; -+ mbf->bufcount=2; -+ ungetc(c,fp); -+ return false; -+ } -+ else -+ { -+ mbf->buf[0]=(unsigned char) 0xEF; -+ mbf->bufcount=1; -+ ungetc(0xBB,fp); -+ return false; -+ } -+ } -+ return false; -+} -+ -+extern void -+print_bom(void) -+{ -+ putc (0xEF, stdout); -+ putc (0xBB, stdout); -+ putc (0xBF, stdout); -+} -+ - /* Add the comma or blank separated list of tab stops STOPS - to the list of tab stops. */ - extern void -diff --git a/src/expand-common.h b/src/expand-common.h -index 46ef4e3..e19469b 100644 ---- a/src/expand-common.h -+++ b/src/expand-common.h -@@ -29,6 +29,18 @@ extern idx_t max_column_width; - /* The desired exit status. */ - extern int exit_status; ++#endif ++ unexpand (); -+extern int -+set_utf_locale (void); -+ -+extern bool -+check_utf_locale(void); -+ -+extern bool -+check_bom(FILE* fp, mb_file_t *mbf); -+ -+extern void -+print_bom(void); -+ - /* Add tab stop TABVAL to the end of 'tab_list'. */ - extern void - add_tab_stop (colno tabval); -diff --git a/src/expand.c b/src/expand.c -index 5ec7ce9..65ac315 100644 ---- a/src/expand.c -+++ b/src/expand.c -@@ -38,6 +38,9 @@ - #include - #include - #include -+ -+#include -+ - #include "system.h" - #include "expand-common.h" + if (have_read_stdin && fclose (stdin) != 0) + error (EXIT_FAILURE, errno, "-"); +--- coreutils-6.8+/src/pr.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/pr.c 2007-03-01 15:08:24.000000000 +0000 +@@ -313,6 +313,32 @@ -@@ -96,19 +99,41 @@ expand (void) - { - /* Input stream. */ - FILE *fp = next_file (nullptr); -+ mb_file_t mbf; -+ mbf_char_t c; -+ /* True if the starting locale is utf8. */ -+ bool using_utf_locale; -+ -+ /* True if the first file contains BOM header. */ -+ bool found_bom; -+ using_utf_locale=check_utf_locale(); - - if (!fp) - return; -+ mbf_init (mbf, fp); -+ found_bom=check_bom(fp,&mbf); - -- while (true) -+ if (using_utf_locale == false && found_bom == true) -+ { -+ /*try using some predefined locale */ -+ -+ if (set_utf_locale () != 0) - { -- /* Input character, or EOF. */ -- int c; -+ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); -+ } -+ } -+ -+ -+ if (found_bom == true) -+ { -+ print_bom(); -+ } - -+ while (true) -+ { - /* If true, perform translations. */ - bool convert = true; - -- - /* The following variables have valid values only when CONVERT - is true: */ - -@@ -118,17 +143,48 @@ expand (void) - /* Index in TAB_LIST of next tab stop to examine. */ - idx_t tab_index = 0; - -- - /* Convert a line of text. */ - - do - { -- while ((c = getc (fp)) < 0 && (fp = next_file (fp))) -- continue; -+ while (true) { -+ mbf_getc (c, mbf); -+ if ((mb_iseof (c)) && (fp = next_file (fp))) -+ { -+ mbf_init (mbf, fp); -+ if (fp!=NULL) -+ { -+ if (check_bom(fp,&mbf)==true) -+ { -+ /*Not the first file - check BOM header*/ -+ if (using_utf_locale==false && found_bom==false) -+ { -+ /*BOM header in subsequent file but not in the first one. */ -+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); -+ } -+ } -+ else -+ { -+ if(using_utf_locale==false && found_bom==true) -+ { -+ /*First file conatined BOM header - locale was switched to UTF -+ *all subsequent files should contain BOM. */ -+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); -+ } -+ } -+ } -+ continue; -+ } -+ else -+ { -+ break; -+ } -+ } -+ - - if (convert) - { -- if (c == '\t') -+ if (mb_iseq (c, '\t')) - { - /* Column the next input tab stop is on. */ - bool last_tab; -@@ -139,31 +195,33 @@ expand (void) - if (putchar (' ') < 0) - write_error (); - -- c = ' '; -+ mb_setascii (&c, ' '); - } -- else if (c == '\b') -+ else if (mb_iseq (c, '\b')) - { - /* Go back one column, and force recalculation of the - next tab stop. */ - column -= !!column; - tab_index -= !!tab_index; - } -- else -+ /* A leading control character could make us trip over. */ -+ else if (!mb_iscntrl (c)) - { -- if (ckd_add (&column, column, 1)) -+ if (ckd_add (&column, column, mb_width (c))) - error (EXIT_FAILURE, 0, _("input line is too long")); - } - -- convert &= convert_entire_line || !! isblank (c); -+ convert &= convert_entire_line || !! mb_isblank (c); - } - -- if (c < 0) -+ if (mb_iseof (c)) - return; - -- if (putchar (c) < 0) -+ mb_putc (c, stdout); -+ if (ferror (stdout)) - write_error (); - } -- while (c != '\n'); -+ while (!mb_iseq (c, '\n')); - } - } - -diff --git a/src/local.mk b/src/local.mk -index a8ad6b4..b0e61ec 100644 ---- a/src/local.mk -+++ b/src/local.mk -@@ -490,8 +490,8 @@ src_base32_CPPFLAGS = -DBASE_TYPE=32 $(AM_CPPFLAGS) - src_basenc_SOURCES = src/basenc.c - src_basenc_CPPFLAGS = -DBASE_TYPE=42 $(AM_CPPFLAGS) - --src_expand_SOURCES = src/expand.c src/expand-common.c --src_unexpand_SOURCES = src/unexpand.c src/expand-common.c -+src_expand_SOURCES = src/expand.c src/expand-common.c lib/mbfile.c lib/mbchar.c -+src_unexpand_SOURCES = src/unexpand.c src/expand-common.c lib/mbfile.c lib/mbchar.c - - src_wc_SOURCES = src/wc.c - if USE_AVX512_WC_LINECOUNT -diff --git a/src/pr.c b/src/pr.c -index 10b8c52..079c86c 100644 ---- a/src/pr.c -+++ b/src/pr.c -@@ -312,6 +312,24 @@ - #include #include #include + @@ -1441,13 +2745,21 @@ index 10b8c52..079c86c 100644 +#if HAVE_WCHAR_H +# include +#endif ++ ++/* Get iswprint(). -- for wcwidth(). */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++#if !defined iswprint && !HAVE_ISWPRINT ++# define iswprint(wc) 1 ++#endif + #include "system.h" - #include "c-ctype.h" - #include "fadvise.h" -@@ -325,6 +343,18 @@ - #include "xstrtol-error.h" - #include "xdectoint.h" + #include "error.h" + #include "hard-locale.h" +@@ -324,6 +350,18 @@ + #include "strftime.h" + #include "xstrtol.h" +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HAVE_MBRTOWC && defined mbstate_t @@ -1461,12 +2773,12 @@ index 10b8c52..079c86c 100644 +extern int wcwidth (); +#endif + - /* The official name of this program (e.g., no 'g' prefix). */ + /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "pr" -@@ -417,7 +447,20 @@ struct COLUMN +@@ -416,7 +454,20 @@ - typedef struct COLUMN COLUMN; + #define NULLCOL (COLUMN *)0 -static int char_to_clump (char c); +/* Funtion pointers to switch functions for single byte locale or for @@ -1486,23 +2798,23 @@ index 10b8c52..079c86c 100644 static bool read_line (COLUMN *p); static bool print_page (void); static bool print_stored (COLUMN *p); -@@ -428,6 +471,7 @@ static void pad_across_to (int position); +@@ -426,6 +477,7 @@ + static void pad_across_to (int position); static void add_line_number (COLUMN *p); - static int getoptnum (char const *n_str, int min, char const *errfmt); static void getoptarg (char *arg, char switch_char, char *character, -+ int *character_length, int *character_width, - int *number); ++ int *character_length, int *character_width, + int *number); + void usage (int status); static void print_files (int number_of_files, char **av); - static void init_parameters (int number_of_files); -@@ -441,7 +485,6 @@ static void store_char (char c); - static void pad_down (unsigned int lines); +@@ -440,7 +492,6 @@ + static void pad_down (int lines); static void read_rest_of_line (COLUMN *p); static void skip_read (COLUMN *p, int column_number); -static void print_char (char c); static void cleanup (void); static void print_sep_string (void); - static void separator_string (char const *optarg_S); -@@ -453,7 +496,7 @@ static COLUMN *column_vector; + static void separator_string (const char *optarg_S); +@@ -455,7 +506,7 @@ we store the leftmost columns contiguously in buff. To print a line from buff, get the index of the first character from line_vector[i], and print up to line_vector[i + 1]. */ @@ -1511,7 +2823,7 @@ index 10b8c52..079c86c 100644 /* Index of the position in buff where the next character will be stored. */ -@@ -557,7 +600,7 @@ static int chars_per_column; +@@ -559,7 +610,7 @@ static bool untabify_input = false; /* (-e) The input tab character. */ @@ -1520,7 +2832,7 @@ index 10b8c52..079c86c 100644 /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ... where the leftmost column is 1. */ -@@ -567,7 +610,10 @@ static int chars_per_input_tab = 8; +@@ -569,7 +620,10 @@ static bool tabify_output = false; /* (-i) The output tab character. */ @@ -1532,7 +2844,7 @@ index 10b8c52..079c86c 100644 /* (-i) The width of the output tab. */ static int chars_per_output_tab = 8; -@@ -637,7 +683,13 @@ static int line_number; +@@ -643,7 +697,13 @@ static bool numbered_lines = false; /* (-n) Character which follows each line number. */ @@ -1547,18 +2859,18 @@ index 10b8c52..079c86c 100644 /* (-n) line counting starts with 1st line of input file (not with 1st line of 1st page printed). */ -@@ -690,6 +742,7 @@ static bool use_col_separator = false; - -a|COLUMN|-m is a 'space' and with the -J option a 'tab'. */ - static char const *col_sep_string = ""; +@@ -696,6 +756,7 @@ + -a|COLUMN|-m is a `space' and with the -J option a `tab'. */ + static char *col_sep_string = ""; static int col_sep_length = 0; +static int col_sep_width = 0; - static char *column_separator = (char *) " "; - static char *line_separator = (char *) "\t"; + static char *column_separator = " "; + static char *line_separator = "\t"; -@@ -852,6 +905,13 @@ separator_string (char const *optarg_S) - integer_overflow (); - col_sep_length = len; - col_sep_string = optarg_S; +@@ -852,6 +913,13 @@ + col_sep_length = (int) strlen (optarg_S); + col_sep_string = xmalloc (col_sep_length + 1); + strcpy (col_sep_string, optarg_S); + +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) @@ -1569,7 +2881,7 @@ index 10b8c52..079c86c 100644 } int -@@ -876,6 +936,21 @@ main (int argc, char **argv) +@@ -877,6 +945,21 @@ atexit (close_stdout); @@ -1590,163 +2902,138 @@ index 10b8c52..079c86c 100644 + n_files = 0; file_names = (argc > 1 - ? xnmalloc (argc - 1, sizeof (char *)) -@@ -952,8 +1027,12 @@ main (int argc, char **argv) - break; - case 'e': - if (optarg) -- getoptarg (optarg, 'e', &input_tab_char, -- &chars_per_input_tab); -+ { -+ int dummy_length, dummy_width; + ? xmalloc ((argc - 1) * sizeof (char *)) +@@ -949,8 +1032,12 @@ + break; + case 'e': + if (optarg) +- getoptarg (optarg, 'e', &input_tab_char, +- &chars_per_input_tab); ++ { ++ int dummy_length, dummy_width; + -+ getoptarg (optarg, 'e', input_tab_char, &dummy_length, -+ &dummy_width, &chars_per_input_tab); -+ } - /* Could check tab width > 0. */ - untabify_input = true; - break; -@@ -966,8 +1045,12 @@ main (int argc, char **argv) - break; - case 'i': - if (optarg) -- getoptarg (optarg, 'i', &output_tab_char, -- &chars_per_output_tab); -+ { -+ int dummy_width; ++ getoptarg (optarg, 'e', input_tab_char, &dummy_length, ++ &dummy_width, &chars_per_input_tab); ++ } + /* Could check tab width > 0. */ + untabify_input = true; + break; +@@ -963,8 +1050,12 @@ + break; + case 'i': + if (optarg) +- getoptarg (optarg, 'i', &output_tab_char, +- &chars_per_output_tab); ++ { ++ int dummy_width; + -+ getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length, -+ &dummy_width, &chars_per_output_tab); -+ } - /* Could check tab width > 0. */ - tabify_output = true; - break; -@@ -986,8 +1069,8 @@ main (int argc, char **argv) - case 'n': - numbered_lines = true; - if (optarg) -- getoptarg (optarg, 'n', &number_separator, -- &chars_per_number); -+ getoptarg (optarg, 'n', number_separator, &number_separator_length, -+ &number_separator_width, &chars_per_number); - break; - case 'N': - skip_count = false; -@@ -1013,6 +1096,7 @@ main (int argc, char **argv) - /* Reset an additional input of -s, -S dominates -s */ - col_sep_string = ""; - col_sep_length = 0; -+ col_sep_width = 0; - use_col_separator = true; - if (optarg) - separator_string (optarg); -@@ -1168,7 +1252,8 @@ getoptnum (char const *n_str, int min, char const *err) ++ getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length, ++ &dummy_width, &chars_per_output_tab); ++ } + /* Could check tab width > 0. */ + tabify_output = true; + break; +@@ -991,8 +1082,8 @@ + case 'n': + numbered_lines = true; + if (optarg) +- getoptarg (optarg, 'n', &number_separator, +- &chars_per_number); ++ getoptarg (optarg, 'n', number_separator, &number_separator_length, ++ &number_separator_width, &chars_per_number); + break; + case 'N': + skip_count = false; +@@ -1031,7 +1122,7 @@ + old_s = false; + /* Reset an additional input of -s, -S dominates -s */ + col_sep_string = ""; +- col_sep_length = 0; ++ col_sep_length = col_sep_width = 0; + use_col_separator = true; + if (optarg) + separator_string (optarg); +@@ -1188,10 +1279,45 @@ a number. */ static void -getoptarg (char *arg, char switch_char, char *character, int *number) +getoptarg (char *arg, char switch_char, char *character, int *character_length, -+ int *character_width, int *number) ++ int *character_width, int *number) { - if (!*arg) - { -@@ -1177,7 +1262,41 @@ getoptarg (char *arg, char switch_char, char *character, int *number) - } - - if (!c_isdigit (*arg)) + if (!ISDIGIT (*arg)) - *character = *arg++; + { +#ifdef HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) /* for multibyte locale. */ -+ { -+ wchar_t wc; -+ size_t mblength; -+ int width; -+ mbstate_t state = {'\0'}; ++ if (MB_CUR_MAX > 1) /* for multibyte locale. */ ++ { ++ wchar_t wc; ++ size_t mblength; ++ int width; ++ mbstate_t state = {'\0'}; + -+ mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state); ++ mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state); + -+ if (mblength == (size_t)-1 || mblength == (size_t)-2) -+ { -+ *character_length = 1; -+ *character_width = 1; -+ } -+ else -+ { -+ *character_length = (mblength < 1) ? 1 : mblength; -+ width = wcwidth (wc); -+ *character_width = (width < 0) ? 0 : width; -+ } ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ *character_length = 1; ++ *character_width = 1; ++ } ++ else ++ { ++ *character_length = (mblength < 1) ? 1 : mblength; ++ width = wcwidth (wc); ++ *character_width = (width < 0) ? 0 : width; ++ } + -+ strncpy (character, arg, *character_length); -+ arg += *character_length; -+ } -+ else /* for single byte locale. */ ++ strncpy (character, arg, *character_length); ++ arg += *character_length; ++ } ++ else /* for single byte locale. */ +#endif -+ { -+ *character = *arg++; -+ *character_length = 1; -+ *character_width = 1; -+ } ++ { ++ *character = *arg++; ++ *character_length = 1; ++ *character_width = 1; ++ } + } + if (*arg) { long int tmp_long; -@@ -1206,6 +1325,11 @@ static void - init_parameters (int number_of_files) - { - int chars_used_by_number = 0; -+ int mb_len = 1; -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ mb_len = MB_LEN_MAX; -+#endif +@@ -1256,7 +1382,7 @@ + else + col_sep_string = column_separator; - lines_per_body = lines_per_page - lines_per_header - lines_per_footer; - if (lines_per_body <= 0) -@@ -1243,7 +1367,7 @@ init_parameters (int number_of_files) - else - col_sep_string = column_separator; - -- col_sep_length = 1; -+ col_sep_length = col_sep_width = 1; - use_col_separator = true; - } +- col_sep_length = 1; ++ col_sep_length = col_sep_width = 1; + use_col_separator = true; + } /* It's rather pointless to define a TAB separator with column -@@ -1275,11 +1399,11 @@ init_parameters (int number_of_files) - + TAB_WIDTH (chars_per_input_tab, chars_per_number); */ +@@ -1288,11 +1414,11 @@ + TAB_WIDTH (chars_per_input_tab, chars_per_number); */ /* Estimate chars_per_text without any margin and keep it constant. */ - if (number_separator == '\t') + if (number_separator[0] == '\t') - number_width = (chars_per_number - + TAB_WIDTH (chars_per_default_tab, chars_per_number)); + number_width = chars_per_number + + TAB_WIDTH (chars_per_default_tab, chars_per_number); else -- number_width = chars_per_number + 1; -+ number_width = chars_per_number + number_separator_width; +- number_width = chars_per_number + 1; ++ number_width = chars_per_number + number_separator_width; /* The number is part of the column width unless we are - printing files in parallel. */ -@@ -1288,7 +1412,7 @@ init_parameters (int number_of_files) + printing files in parallel. */ +@@ -1307,7 +1433,7 @@ } - int sep_chars, useful_chars; -- if (ckd_mul (&sep_chars, columns - 1, col_sep_length)) -+ if (ckd_mul (&sep_chars, columns - 1, col_sep_width)) - sep_chars = INT_MAX; - if (ckd_sub (&useful_chars, chars_per_line - chars_used_by_number, - sep_chars)) -@@ -1311,7 +1435,7 @@ init_parameters (int number_of_files) - We've to use 8 as the lower limit, if we use chars_per_default_tab = 8 - to expand a tab which is not an input_tab-char. */ - free (clump_buff); -- clump_buff = xmalloc (MAX (8, chars_per_input_tab)); -+ clump_buff = xmalloc (mb_len * MAX (8, chars_per_input_tab)); - } + chars_per_column = (chars_per_line - chars_used_by_number - +- (columns - 1) * col_sep_length) / columns; ++ (columns - 1) * col_sep_width) / columns; - /* Open the necessary files, -@@ -1417,7 +1541,7 @@ init_funcs (void) + if (chars_per_column < 1) + error (EXIT_FAILURE, 0, _("page width too narrow")); +@@ -1432,7 +1558,7 @@ /* Enlarge p->start_position of first column to use the same form of padding_not_printed with all columns. */ @@ -1755,30 +3042,30 @@ index 10b8c52..079c86c 100644 /* This loop takes care of all but the rightmost column. */ -@@ -1451,7 +1575,7 @@ init_funcs (void) - } +@@ -1466,7 +1592,7 @@ + } else - { -- h = h_next + col_sep_length; -+ h = h_next + col_sep_width; - h_next = h + chars_per_column; - } + { +- h = h_next + col_sep_length; ++ h = h_next + col_sep_width; + h_next = h + chars_per_column; + } } -@@ -1751,9 +1875,9 @@ static void +@@ -1756,9 +1882,9 @@ align_column (COLUMN *p) { padding_not_printed = p->start_position; -- if (col_sep_length < padding_not_printed) -+ if (col_sep_width < padding_not_printed) +- if (padding_not_printed - col_sep_length > 0) ++ if (padding_not_printed - col_sep_width > 0) { - pad_across_to (padding_not_printed - col_sep_length); + pad_across_to (padding_not_printed - col_sep_width); padding_not_printed = ANYWHERE; } -@@ -2030,13 +2154,13 @@ store_char (char c) +@@ -2029,13 +2155,13 @@ /* May be too generous. */ - buff = xpalloc (buff, &buff_allocated, 1, -1, sizeof *buff); + buff = X2REALLOC (buff, &buff_allocated); } - buff[buff_current++] = c; + buff[buff_current++] = (unsigned char) c; @@ -1790,23 +3077,23 @@ index 10b8c52..079c86c 100644 - int i; + int i, j; char *s; - int num_width; + int left_cut; -@@ -2053,22 +2177,24 @@ add_line_number (COLUMN *p) +@@ -2058,22 +2184,24 @@ /* Tabification is assumed for multiple columns, also for n-separators, - but 'default n-separator = TAB' hasn't been given priority over - equal column_width also specified by POSIX. */ + but `default n-separator = TAB' hasn't been given priority over + equal column_width also specified by POSIX. */ - if (number_separator == '\t') + if (number_separator[0] == '\t') { i = number_width - chars_per_number; while (i-- > 0) - (p->char_func) (' '); + (p->char_func) (' '); } else - (p->char_func) (number_separator); -+ for (j = 0; j < number_separator_length; j++) -+ (p->char_func) (number_separator[j]); ++ for (j = 0; j < number_separator_length; j++) ++ (p->char_func) (number_separator[j]); } else /* To comply with POSIX, we avoid any expansion of default TAB @@ -1816,54 +3103,54 @@ index 10b8c52..079c86c 100644 - (p->char_func) (number_separator); - if (number_separator == '\t') + for (j = 0; j < number_separator_length; j++) -+ (p->char_func) (number_separator[j]); ++ (p->char_func) (number_separator[j]); + if (number_separator[0] == '\t') output_position = POS_AFTER_TAB (chars_per_output_tab, - output_position); + output_position); } -@@ -2227,7 +2353,7 @@ print_white_space (void) +@@ -2234,7 +2362,7 @@ while (goal - h_old > 1 - && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) + && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) { - putchar (output_tab_char); + fwrite (output_tab_char, sizeof(char), output_tab_char_length, stdout); h_old = h_new; } while (++h_old <= goal) -@@ -2247,6 +2373,7 @@ print_sep_string (void) +@@ -2254,6 +2382,7 @@ { - char const *s = col_sep_string; + char *s; int l = col_sep_length; + int not_space_flag; - if (separators_not_printed <= 0) - { -@@ -2258,6 +2385,7 @@ print_sep_string (void) + s = col_sep_string; + +@@ -2267,6 +2396,7 @@ { for (; separators_not_printed > 0; --separators_not_printed) - { -+ not_space_flag = 0; - while (l-- > 0) - { - /* 3 types of sep_strings: spaces only, spaces and chars, -@@ -2271,12 +2399,15 @@ print_sep_string (void) - } - else - { -+ not_space_flag = 1; - if (spaces_not_printed > 0) - print_white_space (); - putchar (*s++); -- ++output_position; - } - } -+ if (not_space_flag) -+ output_position += col_sep_width; + { ++ not_space_flag = 0; + while (l-- > 0) + { + /* 3 types of sep_strings: spaces only, spaces and chars, +@@ -2280,12 +2410,15 @@ + } + else + { ++ not_space_flag = 1; + if (spaces_not_printed > 0) + print_white_space (); + putchar (*s++); +- ++output_position; + } + } ++ if (not_space_flag) ++ output_position += col_sep_width; + /* sep_string ends with some spaces */ - if (spaces_not_printed > 0) - print_white_space (); -@@ -2307,7 +2438,7 @@ print_clump (COLUMN *p, int n, char *clump) + if (spaces_not_printed > 0) + print_white_space (); +@@ -2313,7 +2446,7 @@ required number of tabs and spaces. */ static void @@ -1872,7 +3159,7 @@ index 10b8c52..079c86c 100644 { if (tabify_output) { -@@ -2331,6 +2462,74 @@ print_char (char c) +@@ -2337,6 +2470,74 @@ putchar (c); } @@ -1895,49 +3182,49 @@ index 10b8c52..079c86c 100644 + mblength = mbrtowc (&wc, mbc, mbc_pos, &state); + + while (mbc_pos > 0) -+ { -+ switch (mblength) -+ { -+ case (size_t)-2: -+ state = state_bak; -+ return; ++ { ++ switch (mblength) ++ { ++ case (size_t)-2: ++ state = state_bak; ++ return; + -+ case (size_t)-1: -+ state = state_bak; -+ ++output_position; -+ putchar (mbc[0]); -+ memmove (mbc, mbc + 1, MB_CUR_MAX - 1); -+ --mbc_pos; -+ break; ++ case (size_t)-1: ++ state = state_bak; ++ ++output_position; ++ putchar (mbc[0]); ++ memmove (mbc, mbc + 1, MB_CUR_MAX - 1); ++ --mbc_pos; ++ break; + -+ case 0: -+ mblength = 1; ++ case 0: ++ mblength = 1; + -+ default: -+ if (wc == L' ') -+ { -+ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); -+ --mbc_pos; -+ ++spaces_not_printed; -+ return; -+ } -+ else if (spaces_not_printed > 0) -+ print_white_space (); ++ default: ++ if (wc == L' ') ++ { ++ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); ++ --mbc_pos; ++ ++spaces_not_printed; ++ return; ++ } ++ else if (spaces_not_printed > 0) ++ print_white_space (); + -+ /* Nonprintables are assumed to have width 0, except L'\b'. */ -+ if ((width = wcwidth (wc)) < 1) -+ { -+ if (wc == L'\b') -+ --output_position; -+ } -+ else -+ output_position += width; ++ /* Nonprintables are assumed to have width 0, except L'\b'. */ ++ if ((width = wcwidth (wc)) < 1) ++ { ++ if (wc == L'\b') ++ --output_position; ++ } ++ else ++ output_position += width; + -+ fwrite (mbc, sizeof(char), mblength, stdout); -+ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); -+ mbc_pos -= mblength; -+ } -+ } ++ fwrite (mbc, sizeof(char), mblength, stdout); ++ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); ++ mbc_pos -= mblength; ++ } ++ } + return; + } + putchar (c); @@ -1947,60 +3234,42 @@ index 10b8c52..079c86c 100644 /* Skip to page PAGE before printing. PAGE may be larger than total number of pages. */ -@@ -2507,9 +2706,9 @@ read_line (COLUMN *p) - align_empty_cols = false; - } +@@ -2517,9 +2718,9 @@ + align_empty_cols = false; + } -- if (col_sep_length < padding_not_printed) -+ if (col_sep_width < padding_not_printed) - { -- pad_across_to (padding_not_printed - col_sep_length); -+ pad_across_to (padding_not_printed - col_sep_width); - padding_not_printed = ANYWHERE; - } +- if (padding_not_printed - col_sep_length > 0) ++ if (padding_not_printed - col_sep_width > 0) + { +- pad_across_to (padding_not_printed - col_sep_length); ++ pad_across_to (padding_not_printed - col_sep_width); + padding_not_printed = ANYWHERE; + } -@@ -2578,7 +2777,7 @@ print_stored (COLUMN *p) - COLUMN *q; - - int line = p->current_line++; -- char *first = &buff[line_vector[line]]; -+ unsigned char *first = &buff[line_vector[line]]; - /* FIXME - UMR: Uninitialized memory read: - * This is occurring while in: -@@ -2590,7 +2789,7 @@ print_stored (COLUMN *p) - xmalloc [xmalloc.c:94] - init_store_cols [pr.c:1648] - */ -- char *last = &buff[line_vector[line + 1]]; -+ unsigned char *last = &buff[line_vector[line + 1]]; - - pad_vertically = true; - -@@ -2610,9 +2809,9 @@ print_stored (COLUMN *p) - } +@@ -2620,9 +2821,9 @@ + } } -- if (col_sep_length < padding_not_printed) -+ if (col_sep_width < padding_not_printed) +- if (padding_not_printed - col_sep_length > 0) ++ if (padding_not_printed - col_sep_width > 0) { - pad_across_to (padding_not_printed - col_sep_length); + pad_across_to (padding_not_printed - col_sep_width); padding_not_printed = ANYWHERE; } -@@ -2625,8 +2824,8 @@ print_stored (COLUMN *p) +@@ -2635,8 +2836,8 @@ if (spaces_not_printed == 0) { output_position = p->start_position + end_vector[line]; - if (p->start_position - col_sep_length == chars_per_margin) -- output_position -= col_sep_length; +- output_position -= col_sep_length; + if (p->start_position - col_sep_width == chars_per_margin) -+ output_position -= col_sep_width; ++ output_position -= col_sep_width; } return true; -@@ -2645,7 +2844,7 @@ print_stored (COLUMN *p) +@@ -2655,7 +2856,7 @@ number of characters is 1.) */ static int @@ -2009,7 +3278,7 @@ index 10b8c52..079c86c 100644 { unsigned char uc = c; char *s = clump_buff; -@@ -2655,10 +2854,10 @@ char_to_clump (char c) +@@ -2665,10 +2866,10 @@ int chars; int chars_per_c = 8; @@ -2022,7 +3291,7 @@ index 10b8c52..079c86c 100644 { width = TAB_WIDTH (chars_per_c, input_position); -@@ -2739,6 +2938,164 @@ char_to_clump (char c) +@@ -2739,6 +2940,154 @@ return chars; } @@ -2053,133 +3322,123 @@ index 10b8c52..079c86c 100644 + while (mbc_pos > 0) + { + switch (mblength) -+ { -+ case (size_t)-2: -+ state = state_bak; -+ return 0; ++ { ++ case (size_t)-2: ++ state = state_bak; ++ return 0; + -+ case (size_t)-1: -+ state = state_bak; -+ mblength = 1; ++ case (size_t)-1: ++ state = state_bak; ++ mblength = 1; + -+ if (use_esc_sequence || use_cntrl_prefix) -+ { -+ width = +4; -+ chars = +4; -+ *s++ = '\\'; -+ sprintf (esc_buff, "%03o", (unsigned char) mbc[0]); -+ for (i = 0; i <= 2; ++i) -+ *s++ = (int) esc_buff[i]; -+ } -+ else -+ { -+ width += 1; -+ chars += 1; -+ *s++ = mbc[0]; -+ } -+ break; ++ if (use_esc_sequence || use_cntrl_prefix) ++ { ++ width = +4; ++ chars = +4; ++ *s++ = '\\'; ++ sprintf (esc_buff, "%03o", mbc[0]); ++ for (i = 0; i <= 2; ++i) ++ *s++ = (int) esc_buff[i]; ++ } ++ else ++ { ++ width += 1; ++ chars += 1; ++ *s++ = mbc[0]; ++ } ++ break; + -+ case 0: -+ mblength = 1; -+ /* Fall through */ ++ case 0: ++ mblength = 1; ++ /* Fall through */ + -+ default: -+ if (memcmp (mbc, input_tab_char, mblength) == 0) -+ chars_per_c = chars_per_input_tab; ++ default: ++ if (memcmp (mbc, input_tab_char, mblength) == 0) ++ chars_per_c = chars_per_input_tab; + -+ if (memcmp (mbc, input_tab_char, mblength) == 0 || c == '\t') -+ { -+ int width_inc; ++ if (memcmp (mbc, input_tab_char, mblength) == 0 || c == '\t') ++ { ++ int width_inc; + -+ width_inc = TAB_WIDTH (chars_per_c, input_position); -+ width += width_inc; ++ width_inc = TAB_WIDTH (chars_per_c, input_position); ++ width += width_inc; + -+ if (untabify_input) -+ { -+ for (i = width_inc; i; --i) -+ *s++ = ' '; -+ chars += width_inc; -+ } -+ else -+ { -+ for (i = 0; i < mblength; i++) -+ *s++ = mbc[i]; -+ chars += mblength; -+ } -+ } -+ else if ((wc_width = wcwidth (wc)) < 1) -+ { -+ if (use_esc_sequence) -+ { -+ for (i = 0; i < mblength; i++) -+ { -+ width += 4; -+ chars += 4; -+ *s++ = '\\'; -+ sprintf (esc_buff, "%03o", (unsigned char) mbc[i]); -+ for (j = 0; j <= 2; ++j) -+ *s++ = (int) esc_buff[j]; -+ } -+ } -+ else if (use_cntrl_prefix) -+ { -+ if (wc < 0200) -+ { -+ width += 2; -+ chars += 2; -+ *s++ = '^'; -+ *s++ = wc ^ 0100; -+ } -+ else -+ { -+ for (i = 0; i < mblength; i++) -+ { -+ width += 4; -+ chars += 4; -+ *s++ = '\\'; -+ sprintf (esc_buff, "%03o", (unsigned char) mbc[i]); -+ for (j = 0; j <= 2; ++j) -+ *s++ = (int) esc_buff[j]; -+ } -+ } -+ } -+ else if (wc == L'\b') -+ { -+ width += -1; -+ chars += 1; -+ *s++ = c; -+ } -+ else -+ { -+ width += 0; -+ chars += mblength; -+ for (i = 0; i < mblength; i++) -+ *s++ = mbc[i]; -+ } -+ } -+ else -+ { -+ width += wc_width; -+ chars += mblength; -+ for (i = 0; i < mblength; i++) -+ *s++ = mbc[i]; -+ } -+ } ++ if (untabify_input) ++ { ++ for (i = width_inc; i; --i) ++ *s++ = ' '; ++ chars += width_inc; ++ } ++ else ++ { ++ for (i = 0; i < mblength; i++) ++ *s++ = mbc[i]; ++ chars += mblength; ++ } ++ } ++ else if ((wc_width = wcwidth (wc)) < 1) ++ { ++ if (use_esc_sequence) ++ { ++ for (i = 0; i < mblength; i++) ++ { ++ width += 4; ++ chars += 4; ++ *s++ = '\\'; ++ sprintf (esc_buff, "%03o", c); ++ for (j = 0; j <= 2; ++j) ++ *s++ = (int) esc_buff[j]; ++ } ++ } ++ else if (use_cntrl_prefix) ++ { ++ if (wc < 0200) ++ { ++ width += 2; ++ chars += 2; ++ *s++ = '^'; ++ *s++ = wc ^ 0100; ++ } ++ else ++ { ++ for (i = 0; i < mblength; i++) ++ { ++ width += 4; ++ chars += 4; ++ *s++ = '\\'; ++ sprintf (esc_buff, "%03o", c); ++ for (j = 0; j <= 2; ++j) ++ *s++ = (int) esc_buff[j]; ++ } ++ } ++ } ++ else if (wc == L'\b') ++ { ++ width += -1; ++ chars += 1; ++ *s++ = c; ++ } ++ else ++ { ++ width += 0; ++ chars += mblength; ++ for (i = 0; i < mblength; i++) ++ *s++ = mbc[i]; ++ } ++ } ++ else ++ { ++ width += wc_width; ++ chars += mblength; ++ for (i = 0; i < mblength; i++) ++ *s++ = mbc[i]; ++ } ++ } + memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); + mbc_pos -= mblength; + } + -+ /* Too many backspaces must put us in position 0 -- never negative. */ -+ if (width < 0 && input_position == 0) -+ { -+ chars = 0; -+ input_position = 0; -+ } -+ else if (width < 0 && input_position <= -width) -+ input_position = 0; -+ else -+ input_position += width; -+ ++ input_position += width; + return chars; +} +#endif @@ -2187,2097 +3446,596 @@ index 10b8c52..079c86c 100644 /* We've just printed some files and need to clean up things before looking for more options and printing the next batch of files. -diff --git a/src/sort.c b/src/sort.c -index 05d00cc..eb51f20 100644 ---- a/src/sort.c -+++ b/src/sort.c -@@ -30,6 +30,15 @@ - #include - #include - #include -+ -+#if HAVE_WCHAR_H -+# include -+#endif -+/* Get isw* functions. */ -+#if HAVE_WCTYPE_H -+# include -+#endif -+ - #include "system.h" - #include "argmatch.h" - #include "assure.h" -@@ -160,14 +169,39 @@ static int thousands_sep; - /* We currently ignore multi-byte grouping chars. */ - static bool thousands_sep_ignored; - -+/* True if -f is specified. */ -+static bool folding; -+ - /* 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 }; - -@@ -344,13 +378,11 @@ static bool stable; - /* An int value outside char range. */ - enum { NON_CHAR = CHAR_MAX + 1 }; - --/* 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. */ -@@ -386,6 +418,46 @@ struct tempnode - 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 void -+(*skipblanks) (char **ptr, char *lim); -+static int -+(*getmonth) (char const *, size_t, char **); -+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) || wc == '\n'; -+} -+#endif -+ - /* Clean up any remaining temporary files. */ - - static void -@@ -1343,7 +1415,7 @@ zaptemp (char const *name) - free (node); - } - --#if HAVE_NL_LANGINFO -+#if HAVE_LANGINFO_CODESET - - static int - struct_month_cmp (void const *m1, void const *m2) -@@ -1358,7 +1430,7 @@ struct_month_cmp (void const *m1, void const *m2) - /* Initialize the character class tables. */ - - static void --inittables (void) -+inittables_uni (void) - { - size_t i; - -@@ -1370,7 +1442,7 @@ inittables (void) - 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) - { -@@ -1450,6 +1522,84 @@ specify_nmerge (int oi, char c, char const *s) - xstrtol_fatal (e, oi, c, long_options, s); - } - -+#if HAVE_MBRTOWC -+static void -+inittables_mb (void) -+{ -+ int i, j, k, l; -+ char *name, *s, *lc_time, *lc_ctype; -+ size_t s_len, mblength; -+ char mbc[MB_LEN_MAX]; -+ wchar_t wc, pwc; -+ mbstate_t state_mb, state_wc; -+ -+ lc_time = setlocale (LC_TIME, ""); -+ if (lc_time) -+ lc_time = xstrdup (lc_time); -+ -+ lc_ctype = setlocale (LC_CTYPE, ""); -+ if (lc_ctype) -+ lc_ctype = xstrdup (lc_ctype); -+ -+ if (lc_time && lc_ctype) -+ /* temporarily set LC_CTYPE to match LC_TIME, so that we can convert -+ * the names of months to upper case */ -+ setlocale (LC_CTYPE, lc_time); -+ -+ 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); -+ -+ if (lc_time && lc_ctype) -+ /* restore the original locales */ -+ setlocale (LC_CTYPE, lc_ctype); -+ -+ free (lc_ctype); -+ free (lc_time); -+} -+#endif -+ - /* Specify the amount of main memory to use when sorting. */ - static void - specify_sort_size (int oi, char c, char const *s) -@@ -1676,7 +1826,7 @@ buffer_linelim (struct buffer const *buf) - by KEY in LINE. */ - - static char * --begfield (struct line const *line, struct keyfield const *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; -@@ -1685,10 +1835,10 @@ begfield (struct line const *line, struct keyfield const *key) - /* 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; -@@ -1718,12 +1868,71 @@ begfield (struct line const *line, struct keyfield const *key) - 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. */ - - ATTRIBUTE_PURE - static char * --limfield (struct line const *line, struct keyfield const *key) -+limfield_uni (struct line const *line, struct keyfield const *key) - { - char *ptr = line->text, *lim = ptr + line->length - 1; - size_t eword = key->eword, echar = key->echar; -@@ -1738,10 +1947,10 @@ limfield (struct line const *line, struct keyfield const *key) - '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; -@@ -1787,10 +1996,10 @@ limfield (struct line const *line, struct keyfield const *key) - */ - - /* 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; - } -@@ -1825,6 +2034,130 @@ limfield (struct line const *line, struct keyfield const *key) - return ptr; - } - -+#if HAVE_MBRTOWC -+static char * _GL_ATTRIBUTE_PURE -+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; -+ -+ if (echar == 0) -+ eword++; /* skip all of end field. */ -+ -+ 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 (echar != 0) -+ { -+ /* If we're skipping leading blanks, don't start counting characters -+ * until after skipping past any leading blanks. */ -+ if (key->skipeblanks) -+ 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 -+ -+static void -+skipblanks_uni (char **ptr, char *lim) -+{ -+ while (*ptr < lim && blanks[to_uchar (**ptr)]) -+ ++(*ptr); -+} -+ -+#if HAVE_MBRTOWC -+static void -+skipblanks_mb (char **ptr, char *lim) -+{ -+ size_t mblength; -+ while (*ptr < lim && ismbblank (*ptr, lim - *ptr, &mblength)) -+ (*ptr) += mblength; -+} -+#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 -@@ -1911,8 +2244,22 @@ fillbuf (struct buffer *buf, FILE *fp, char const *file) - else - { - if (key->skipsblanks) -- while (blanks[to_uchar (*line_start)]) -- line_start++; -+ { -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ size_t mblength; -+ 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; - } - } -@@ -2050,12 +2397,10 @@ find_unit_order (char const *number) - - ATTRIBUTE_PURE - static int --human_numcompare (char const *a, char const *b) -+human_numcompare (char *a, char *b) - { -- while (blanks[to_uchar (*a)]) -- a++; -- while (blanks[to_uchar (*b)]) -- b++; -+ skipblanks(&a, a + strlen(a)); -+ skipblanks(&b, b + strlen(b)); - - int diff = find_unit_order (a) - find_unit_order (b); - return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep)); -@@ -2067,7 +2412,7 @@ human_numcompare (char const *a, char const *b) - - ATTRIBUTE_PURE - static int --numcompare (char const *a, char const *b) -+numcompare_uni (const char *a, const char *b) - { - while (blanks[to_uchar (*a)]) - a++; -@@ -2077,6 +2422,25 @@ numcompare (char const *a, char const *b) - 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 - nan_compare (long double a, long double b) - { -@@ -2118,7 +2482,7 @@ general_numcompare (char const *sa, char const *sb) - Return 0 if the name in S is not recognized. */ - - static int --getmonth (char const *month, char **ea) -+getmonth_uni (char const *month, size_t len, char **ea) - { - size_t lo = 0; - size_t hi = MONTHS_PER_YEAR; -@@ -2457,15 +2821,14 @@ debug_key (struct line const *line, struct keyfield const *key) - char saved = *lim; - *lim = '\0'; - -- while (blanks[to_uchar (*beg)]) -- beg++; -+ skipblanks (&beg, lim); - - char *tighter_lim = beg; - - if (lim < beg) - tighter_lim = lim; - else if (key->month) -- getmonth (beg, &tighter_lim); -+ getmonth (beg, lim-beg, &tighter_lim); - else if (key->general_numeric) - ignore_value (strtold (beg, &tighter_lim)); - else if (key->numeric || key->human_numeric) -@@ -2611,7 +2974,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) - /* Warn about significant leading blanks. */ - bool implicit_skip = key_numeric (key) || key->month; - bool line_offset = key->eword == 0 && key->echar != 0; /* -k1.x,1.y */ -- if (!zero_width && !gkey_only && tab == TAB_DEFAULT && !line_offset -+ if (!zero_width && !gkey_only && !tab_length && !line_offset - && ((!key->skipsblanks && !implicit_skip) - || (!key->skipsblanks && key->schar) - || (!key->skipeblanks && key->echar))) -@@ -2659,9 +3022,9 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) - bool number_locale_warned = false; - if (basic_numeric_field_span) - { -- if (tab == TAB_DEFAULT -- ? thousands_sep != NON_CHAR && (isblank (to_uchar (thousands_sep))) -- : tab == thousands_sep) -+ if (tab_length -+ ? tab[0] == thousands_sep -+ : thousands_sep != NON_CHAR && (isblank (to_uchar (thousands_sep)))) - { - error (0, 0, - _("field separator %s is treated as a " -@@ -2672,9 +3035,9 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) - } - if (basic_numeric_field_span || general_numeric_field_span) - { -- if (tab == TAB_DEFAULT -- ? thousands_sep != NON_CHAR && (isblank (to_uchar (decimal_point))) -- : tab == decimal_point) -+ if (tab_length -+ ? tab[0] == decimal_point -+ : thousands_sep != NON_CHAR && (isblank (to_uchar (decimal_point)))) - { - error (0, 0, - _("field separator %s is treated as a " -@@ -2682,19 +3045,19 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) - quote (((char []) {decimal_point, 0}))); - number_locale_warned = true; - } -- else if (tab == '-') -+ else if (tab_length && tab[0] == '-') - { - error (0, 0, - _("field separator %s is treated as a " - "minus sign in numbers"), -- quote (((char []) {tab, 0}))); -+ quote (((char []) {tab[0], 0}))); - } -- else if (general_numeric_field_span && tab == '+') -+ else if (general_numeric_field_span && tab_length && tab[0] == '+') - { - error (0, 0, - _("field separator %s is treated as a " - "plus sign in numbers"), -- quote (((char []) {tab, 0}))); -+ quote (((char []) {tab[0], 0}))); - } - } - -@@ -2746,11 +3109,87 @@ diff_reversed (int diff, bool reversed) - return reversed ? _GL_CMP (0, diff) : diff; - } - -+#if HAVE_MBRTOWC -+static int -+getmonth_mb (const char *s, size_t len, char **ea) -+{ -+ 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; -+ -+ if (SIZE_MAX - len < 1) -+ xalloc_die (); -+ -+ month = (char *) xnmalloc (len + 1, MB_CUR_MAX); -+ -+ pp = tmp = (char *) xnmalloc (len + 1, MB_CUR_MAX); -+ memcpy (tmp, s, len); -+ tmp[len] = '\0'; -+ wpp = month_wcs = (wchar_t *) xnmalloc (len + 1, sizeof (wchar_t)); -+ memset (&state, '\0', sizeof (mbstate_t)); -+ -+ wclength = mbsrtowcs (month_wcs, &pp, len + 1, &state); -+ if (wclength == (size_t)-1 || pp != NULL) -+ error (SORT_FAILURE, 0, _("Invalid multibyte input %s."), quote(s)); -+ -+ for (i = 0; i < wclength; i++) -+ { -+ month_wcs[i] = towupper(month_wcs[i]); -+ if (iswblank (month_wcs[i])) -+ { -+ month_wcs[i] = L'\0'; -+ break; -+ } -+ } -+ -+ mblength = wcsrtombs (month, &wpp, (len + 1) * MB_CUR_MAX, &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); -+ -+ if (ea && result) -+ *ea = (char*) s + strlen (monthtab[lo].name); -+ -+ free (month); -+ free (tmp); -+ free (month_wcs); -+ -+ 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 (struct line const *a, struct line const *b) -+keycompare_uni (const struct line *a, const struct line *b) - { - struct keyfield *key = keylist; - -@@ -2831,7 +3270,7 @@ keycompare (struct line const *a, struct line const *b) - else if (key->human_numeric) - diff = human_numcompare (ta, tb); - else if (key->month) -- diff = getmonth (ta, nullptr) - getmonth (tb, nullptr); -+ diff = getmonth (ta, tlena, nullptr) - getmonth (tb, tlenb, nullptr); - else if (key->random) - diff = compare_random (ta, tlena, tb, tlenb); - else if (key->version) -@@ -2941,6 +3380,211 @@ keycompare (struct line const *a, struct line const *b) - return diff_reversed (diff, key->reverse); - } - -+#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 = 0; -+ -+ memset (&state_a, '\0', sizeof(mbstate_t)); -+ memset (&state_b, '\0', sizeof(mbstate_t)); -+ /* Ignore keys with start after end. */ -+ if (a->keybeg - a->keylim > 0) -+ return 0; -+ -+ -+ /* 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]; \ -+ 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) -+ -+ /* Actually compare the fields. */ -+ -+ for (;;) -+ { -+ /* Find the lengths. */ -+ size_t lena = lima <= texta ? 0 : lima - texta; -+ size_t lenb = limb <= textb ? 0 : limb - textb; -+ -+ char enda IF_LINT (= 0); -+ char endb IF_LINT (= 0); -+ -+ char const *translate = key->translate; -+ bool const *ignore = key->ignore; -+ -+ if (ignore || translate) -+ { -+ if (SIZE_MAX - lenb - 2 < lena) -+ xalloc_die (); -+ char *copy_a = (char *) xnmalloc (lena + lenb + 2, MB_CUR_MAX); -+ char *copy_b = copy_a + lena * MB_CUR_MAX + 1; -+ size_t new_len_a, new_len_b; -+ size_t i, j; -+ -+ 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); -+ texta = copy_a; textb = copy_b; -+ lena = new_len_a; lenb = new_len_b; -+ } -+ else -+ { -+ /* Use the keys in-place, temporarily null-terminated. */ -+ enda = texta[lena]; texta[lena] = '\0'; -+ endb = textb[lenb]; textb[lenb] = '\0'; -+ } -+ -+ if (key->random) -+ diff = compare_random (texta, lena, textb, lenb); -+ else if (key->numeric | key->general_numeric | key->human_numeric) -+ { -+ char savea = *lima, saveb = *limb; -+ -+ *lima = *limb = '\0'; -+ diff = (key->numeric ? numcompare (texta, textb) -+ : key->general_numeric ? general_numcompare (texta, textb) -+ : human_numcompare (texta, textb)); -+ *lima = savea, *limb = saveb; -+ } -+ else if (key->version) -+ diff = filevercmp (texta, textb); -+ else if (key->month) -+ diff = getmonth (texta, lena, NULL) - getmonth (textb, lenb, NULL); -+ else if (lena == 0) -+ diff = - NONZERO (lenb); -+ else if (lenb == 0) -+ diff = 1; -+ else if (hard_LC_COLLATE && !folding) -+ { -+ diff = xmemcoll0 (texta, lena + 1, textb, lenb + 1); -+ } -+ else -+ { -+ diff = memcmp (texta, textb, MIN (lena, lenb)); -+ if (diff == 0) -+ diff = lena < lenb ? -1 : lena != lenb; -+ } -+ -+ if (ignore || translate) -+ free (texta); -+ else -+ { -+ texta[lena] = enda; -+ textb[lenb] = endb; -+ } -+ -+ 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; -+ } -+ } -+ } -+ -+not_equal: -+ if (key && key->reverse) -+ return -diff; -+ else -+ return 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. */ - -@@ -2968,7 +3612,7 @@ compare (struct line const *a, struct line const *b) - diff = - NONZERO (blen); - else if (blen == 0) - diff = 1; -- else if (hard_LC_COLLATE) -+ else if (hard_LC_COLLATE && !folding) - { - /* xmemcoll0 is a performance enhancement as - it will not unconditionally write '\0' after the -@@ -4340,6 +4984,7 @@ set_ordering (char const *s, struct keyfield *key, enum blanktype blanktype) - break; - case 'f': - key->translate = fold_toupper; -+ folding = true; - break; - case 'g': - key->general_numeric = true; -@@ -4419,7 +5064,7 @@ main (int argc, char **argv) - initialize_exit_failure (SORT_FAILURE); - - hard_LC_COLLATE = hard_locale (LC_COLLATE); --#if HAVE_NL_LANGINFO -+#if HAVE_LANGINFO_CODESET - hard_LC_TIME = hard_locale (LC_TIME); - #endif - -@@ -4442,6 +5087,29 @@ main (int argc, char **argv) - thousands_sep = NON_CHAR; - } - -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ inittables = inittables_mb; -+ begfield = begfield_mb; -+ limfield = limfield_mb; -+ skipblanks = skipblanks_mb; -+ getmonth = getmonth_mb; -+ keycompare = keycompare_mb; -+ numcompare = numcompare_mb; -+ } -+ else -+#endif -+ { -+ inittables = inittables_uni; -+ begfield = begfield_uni; -+ limfield = limfield_uni; -+ skipblanks = skipblanks_uni; -+ getmonth = getmonth_uni; -+ keycompare = keycompare_uni; -+ numcompare = numcompare_uni; -+ } -+ - have_read_stdin = false; - inittables (); - -@@ -4717,13 +5385,34 @@ main (int argc, char **argv) - - 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; -+ -+ 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 -@@ -4734,9 +5423,11 @@ main (int argc, char **argv) - 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; - -diff --git a/src/unexpand.c b/src/unexpand.c -index ff234d7..7c36ef6 100644 ---- a/src/unexpand.c -+++ b/src/unexpand.c -@@ -39,6 +39,9 @@ - #include +--- coreutils-6.8+/src/cut.c.i18n 2007-01-14 15:41:28.000000000 +0000 ++++ coreutils-6.8+/src/cut.c 2007-03-01 15:08:24.000000000 +0000 +@@ -29,6 +29,11 @@ + #include #include #include + -+#include -+ ++/* Get mbstate_t, mbrtowc(). */ ++#if HAVE_WCHAR_H ++# include ++#endif #include "system.h" - #include "expand-common.h" -@@ -105,24 +108,46 @@ unexpand (void) - { - /* Input stream. */ - FILE *fp = next_file (nullptr); -+ mb_file_t mbf; + #include "error.h" +@@ -37,6 +42,18 @@ + #include "quote.h" + #include "xstrndup.h" - /* The array of pending blanks. In non-POSIX locales, blanks can - include characters other than spaces, so the blanks must be - stored, not merely counted. */ -- char *pending_blank; -+ mbf_char_t *pending_blank; -+ /* True if the starting locale is utf8. */ -+ bool using_utf_locale; ++/* 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 + -+ /* True if the first file contains BOM header. */ -+ bool found_bom; -+ using_utf_locale=check_utf_locale(); - - if (!fp) - return; - -+ mbf_init (mbf, fp); -+ found_bom=check_bom(fp,&mbf); ++/* 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 + -+ if (using_utf_locale == false && found_bom == true) -+ { -+ /* Try using some predefined locale */ -+ if (set_utf_locale () != 0) -+ { -+ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); -+ } -+ } + /* The official name of this program (e.g., no `g' prefix). */ + #define PROGRAM_NAME "cut" + +@@ -67,6 +84,52 @@ + } \ + while (0) + ++/* Refill the buffer BUF to get a multibyte character. */ ++#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM) \ ++ do \ ++ { \ ++ if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM)) \ ++ { \ ++ memmove (BUF, BUFPOS, BUFLEN); \ ++ BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \ ++ BUFPOS = BUF; \ ++ } \ ++ } \ ++ while (0) + - /* The worst case is a non-blank character, then one blank, then a - tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so - allocate MAX_COLUMN_WIDTH bytes to store the blanks. */ -- pending_blank = ximalloc (max_column_width); -+ pending_blank = ximalloc (max_column_width * sizeof (mbf_char_t)); ++/* Get wide character on BUFPOS. BUFPOS is not included after that. ++ If byte sequence is not valid as a character, CONVFAIL is 1. Otherwise 0. */ ++#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \ ++ do \ ++ { \ ++ mbstate_t state_bak; \ ++ \ ++ if (BUFLEN < 1) \ ++ { \ ++ WC = WEOF; \ ++ 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 througn. */ \ ++ \ ++ case 0: \ ++ MBLENGTH = 1; \ ++ break; \ ++ } \ ++ } \ ++ while (0) + -+ if (found_bom == true) -+ print_bom(); + struct range_pair + { + size_t lo; +@@ -85,7 +148,7 @@ + /* The number of bytes allocated for FIELD_1_BUFFER. */ + static size_t field_1_bufsize; - while (true) - { - /* Input character, or EOF. */ -- int c; -+ mbf_char_t c; +-/* The largest field or byte index used as an endpoint of a closed ++/* The largest byte, character or field index used as an endpoint of a closed + or degenerate range specification; this doesn't include the starting + index of right-open-ended ranges. For example, with either range spec + `2-5,9-', `2-3,5,9-' this variable would be set to 5. */ +@@ -97,10 +160,11 @@ - /* If true, perform translations. */ - bool convert = true; -@@ -156,12 +181,44 @@ unexpand (void) + /* This is a bit vector. + In byte mode, which bytes to output. ++ In character mode, which characters to output. + In field mode, which DELIM-separated fields to output. +- Both bytes and fields are numbered starting with 1, ++ Bytes, characters and fields are numbered starting with 1, + so the zeroth bit of this array is unused. +- A field or byte K has been selected if ++ A byte, character or field K has been selected if + (K <= MAX_RANGE_ENDPOINT and is_printable_field(K)) + || (EOL_RANGE_START > 0 && K >= EOL_RANGE_START). */ + static unsigned char *printable_field; +@@ -109,9 +173,12 @@ + { + undefined_mode, - do - { -- while ((c = getc (fp)) < 0 && (fp = next_file (fp))) -- continue; -+ while (true) { -+ mbf_getc (c, mbf); -+ if ((mb_iseof (c)) && (fp = next_file (fp))) -+ { -+ mbf_init (mbf, fp); -+ if (fp!=NULL) -+ { -+ if (check_bom(fp,&mbf)==true) -+ { -+ /*Not the first file - check BOM header*/ -+ if (using_utf_locale==false && found_bom==false) -+ { -+ /*BOM header in subsequent file but not in the first one. */ -+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); -+ } -+ } -+ else -+ { -+ if(using_utf_locale==false && found_bom==true) -+ { -+ /*First file conatined BOM header - locale was switched to UTF -+ *all subsequent files should contain BOM. */ -+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); -+ } -+ } -+ } -+ continue; -+ } -+ else -+ { -+ break; -+ } -+ } +- /* Output characters that are in the given bytes. */ ++ /* Output bytes that are at the given positions. */ + byte_mode, + ++ /* Output characters that are at the given positions. */ ++ character_mode, + + /* Output the given delimeter-separated fields. */ + field_mode + }; +@@ -121,6 +188,13 @@ - if (convert) - { -- bool blank = !! isblank (c); -+ bool blank = mb_isblank (c); + static enum operating_mode operating_mode; - if (blank) - { -@@ -175,16 +232,16 @@ unexpand (void) - - if (convert) - { -- if (c == '\t') -+ if (mb_iseq (c, '\t')) - { - column = next_tab_column; - - if (pending) -- pending_blank[0] = '\t'; -+ mb_setascii (&pending_blank[0], '\t'); - } - else - { -- column++; -+ column += mb_width (c); - - if (! (prev_blank && column == next_tab_column)) - { -@@ -192,13 +249,14 @@ unexpand (void) - will be replaced by tabs. */ - if (column == next_tab_column) - one_blank_before_tab_stop = true; -- pending_blank[pending++] = c; -+ mb_copy (&pending_blank[pending++], &c); - prev_blank = true; - continue; - } - - /* Replace the pending blanks by a tab or two. */ -- pending_blank[0] = c = '\t'; -+ mb_setascii (&c, '\t'); -+ mb_setascii (&pending_blank[0], '\t'); - } - - /* Discard pending blanks, unless it was a single -@@ -206,7 +264,7 @@ unexpand (void) - pending = one_blank_before_tab_stop; - } - } -- else if (c == '\b') -+ else if (mb_iseq (c, '\b')) - { - /* Go back one column, and force recalculation of the - next tab stop. */ -@@ -216,16 +274,20 @@ unexpand (void) - } - else - { -- column++; -- if (!column) -+ const uintmax_t orig_column = column; -+ column += mb_width (c); -+ if (column < orig_column) - error (EXIT_FAILURE, 0, _("input line is too long")); - } - - if (pending) - { - if (pending > 1 && one_blank_before_tab_stop) -- pending_blank[0] = '\t'; -- if (fwrite (pending_blank, 1, pending, stdout) != pending) -+ mb_setascii (&pending_blank[0], '\t'); ++/* If nonzero, when in byte mode, don't split multibyte characters. */ ++static int byte_mode_character_aware; + -+ for (int n = 0; n < pending; ++n) -+ mb_putc (pending_blank[n], stdout); -+ if (ferror (stdout)) - write_error (); - pending = 0; - one_blank_before_tab_stop = false; -@@ -235,16 +297,17 @@ unexpand (void) - convert &= convert_entire_line || blank; - } ++/* If nonzero, the function for single byte locale is work ++ if this program runs on multibyte locale. */ ++static int force_singlebyte_mode; ++ + /* If true do not output lines containing no delimeter characters. + Otherwise, all such lines are printed. This option is valid only + with field mode. */ +@@ -132,6 +206,9 @@ -- if (c < 0) -+ if (mb_iseof (c)) - { - free (pending_blank); - return; - } + /* The delimeter character for field mode. */ + static unsigned char delim; ++#if HAVE_WCHAR_H ++static wchar_t wcdelim; ++#endif -- if (putchar (c) < 0) -+ mb_putc (c, stdout); -+ if (ferror (stdout)) - write_error (); - } -- while (c != '\n'); -+ while (!mb_iseq (c, '\n')); + /* True if the --output-delimiter=STRING option was specified. */ + static bool output_delimiter_specified; +@@ -205,7 +282,7 @@ + -f, --fields=LIST select only these fields; also print any line\n\ + that contains no delimiter character, unless\n\ + the -s option is specified\n\ +- -n (ignored)\n\ ++ -n with -b: don't split multibyte characters\n\ + "), stdout); + fputs (_("\ + --complement complement the set of selected bytes, characters\n\ +@@ -362,7 +439,7 @@ + in_digits = false; + /* Starting a range. */ + if (dash_found) +- FATAL_ERROR (_("invalid byte or field list")); ++ FATAL_ERROR (_("invalid byte, character or field list")); + dash_found = true; + fieldstr++; + +@@ -387,14 +464,16 @@ + if (value == 0) + { + /* `n-'. From `initial' to end of line. */ +- eol_range_start = initial; ++ if (eol_range_start == 0 || ++ (eol_range_start != 0 && eol_range_start > initial)) ++ eol_range_start = initial; + field_found = true; + } + else + { + /* `m-n' or `-n' (1-n). */ + if (value < initial) +- FATAL_ERROR (_("invalid byte or field list")); ++ FATAL_ERROR (_("invalid byte, character or field list")); + + /* Is there already a range going to end of line? */ + if (eol_range_start != 0) +@@ -467,6 +546,9 @@ + if (operating_mode == byte_mode) + error (0, 0, + _("byte offset %s is too large"), quote (bad_num)); ++ else if (operating_mode == character_mode) ++ error (0, 0, ++ _("character offset %s is too large"), quote (bad_num)); + else + error (0, 0, + _("field number %s is too large"), quote (bad_num)); +@@ -477,7 +559,7 @@ + fieldstr++; + } + else +- FATAL_ERROR (_("invalid byte or field list")); ++ FATAL_ERROR (_("invalid byte, character or field list")); + } + + max_range_endpoint = 0; +@@ -570,6 +652,63 @@ } } -diff --git a/tests/Coreutils.pm b/tests/Coreutils.pm -index b55fb9d..ac80f49 100644 ---- a/tests/Coreutils.pm -+++ b/tests/Coreutils.pm -@@ -269,6 +269,9 @@ sub run_tests ($$$$$) - # Yes, this is an arbitrary limit. If it causes trouble, - # consider removing it. - my $max = 30; -+ # The downstream i18n multi-byte tests have a "-mb" suffix. -+ # Therefore add 3 to the maximum test name length. -+ $max += 3; - if ($max < length $test_name) - { - warn "$program_name: $test_name: test name is too long (> $max)\n"; -diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh -new file mode 100644 -index 0000000..dd6007c ---- /dev/null -+++ b/tests/expand/mb.sh -@@ -0,0 +1,183 @@ -+#!/bin/sh ++#if HAVE_MBRTOWC ++/* This function is in use for the following case. + -+# Copyright (C) 2012-2015 Free Software Foundation, Inc. ++ 1. Read from the stream STREAM, printing to standard output any selected ++ characters. + -+# This program is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. ++ 2. Read from stream STREAM, printing to standard output any selected bytes, ++ without splitting multibyte characters. */ ++ ++static void ++cut_characters_or_cut_bytes_no_split (FILE *stream) ++{ ++ int idx; /* number of bytes or characters in the line so far. */ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen; /* 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. */ ++ mbstate_t state; /* State of the stream. */ ++ int convfail; /* 1, when conversion is failed. Otherwise 0. */ + -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. ++ idx = 0; ++ buflen = 0; ++ bufpos = buf; ++ memset (&state, '\0', sizeof(mbstate_t)); + -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); + -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src -+print_ver_ expand ++ GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail); + -+export LC_ALL=en_US.UTF-8 ++ if (wc == WEOF) ++ { ++ if (idx > 0) ++ putchar ('\n'); ++ break; ++ } ++ else if (wc == L'\n') ++ { ++ putchar ('\n'); ++ idx = 0; ++ } ++ else ++ { ++ idx += (operating_mode == byte_mode) ? mblength : 1; ++ if (print_kth (idx, NULL)) ++ fwrite (bufpos, mblength, sizeof(char), stdout); ++ } + -+#input containing multibyte characters -+cat <<\EOF > in || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+EOF -+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ -+ -+cat <<\EOF > exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#multiple files as an input -+cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+expand ./in ./in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#test characters with display widths != 1 -+env printf '12345678 -+e\t|ascii(1) -+\u00E9\t|composed(1) -+e\u0301\t|decomposed(1) -+\u3000\t|ideo-space(2) -+\uFF0D\t|full-hypen(2) -+' > in || framework_failure_ -+ -+env printf '12345678 -+e |ascii(1) -+\u00E9 |composed(1) -+e\u0301 |decomposed(1) -+\u3000 |ideo-space(2) -+\uFF0D |full-hypen(2) -+' > exp || framework_failure_ -+ -+expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#shouldn't fail with "input line too long" -+#when a line starts with a control character -+env printf '\n' > in || framework_failure_ -+ -+expand < in > out || fail=1 -+compare in out > /dev/null 2>&1 || fail=1 -+ -+#non-Unicode characters interspersed between Unicode ones -+env printf '12345678 -+\t\xFF| -+\xFF\t| -+\t\xFFä| -+ä\xFF\t| -+\tä\xFF| -+\xFF\tä| -+äbcdef\xFF\t| -+' > in || framework_failure_ -+ -+env printf '12345678 -+ \xFF| -+\xFF | -+ \xFFä| -+ä\xFF | -+ ä\xFF| -+\xFF ä| -+äbcdef\xFF | -+' > exp || framework_failure_ -+ -+expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+ -+ -+#BOM header test 1 -+printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+EOF -+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ -+ -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+ -+expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LANG=C expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LC_ALL=C expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+ -+printf '\xEF\xBB\xBF' > in1; cat <<\EOF >> in1 || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+EOF -+env printf ' äöü\t. öüä. \tä xx\n' >> in1 || framework_failure_ -+ -+ -+printf '\xEF\xBB\xBF' > exp; cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+expand in1 in1 > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LANG=C expand in1 in1 > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LC_ALL=C expand in1 in1 > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+exit $fail -diff --git a/tests/i18n/sort.sh b/tests/i18n/sort.sh -new file mode 100644 -index 0000000..26c95de ---- /dev/null -+++ b/tests/i18n/sort.sh -@@ -0,0 +1,29 @@ -+#!/bin/sh -+# Verify sort's multi-byte support. -+ -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src -+print_ver_ sort -+ -+export LC_ALL=en_US.UTF-8 -+locale -k LC_CTYPE | grep -q "charmap.*UTF-8" \ -+ || skip_ "No UTF-8 locale available" -+ -+# Enable heap consistency checkng on older systems -+export MALLOC_CHECK_=2 -+ -+ -+# check buffer overflow issue due to -+# expanding multi-byte representation due to case conversion -+# https://bugzilla.suse.com/show_bug.cgi?id=928749 -+cat < exp -+. -+ɑ -+EOF -+cat < out || fail=1 -+. -+ɑ -+EOF -+compare exp out || { fail=1; cat out; } -+ -+ -+Exit $fail -diff --git a/tests/local.mk b/tests/local.mk -index 53fc53e..0148422 100644 ---- a/tests/local.mk -+++ b/tests/local.mk -@@ -412,6 +412,8 @@ all_tests = \ - tests/sort/sort-field-limit.sh \ - tests/sort/sort-files0-from.pl \ - tests/sort/sort-float.sh \ -+ tests/misc/sort-mb-tests.sh \ -+ tests/i18n/sort.sh \ - tests/sort/sort-h-thousands-sep.sh \ - tests/sort/sort-merge.pl \ - tests/sort/sort-merge-fdlimit.sh \ -@@ -618,6 +620,7 @@ all_tests = \ - tests/du/threshold.sh \ - tests/du/trailing-slash.sh \ - tests/du/two-args.sh \ -+ tests/expand/mb.sh \ - tests/id/gnu-zero-uids.sh \ - tests/id/no-context.sh \ - tests/id/context.sh \ -@@ -774,6 +777,7 @@ all_tests = \ - tests/touch/read-only.sh \ - tests/touch/relative.sh \ - tests/touch/trailing-slash.sh \ -+ tests/unexpand/mb.sh \ - $(all_root_tests) ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++} ++#endif ++ + /* Read from stream STREAM, printing to standard output any selected fields. */ - # See tests/factor/create-test.sh. -diff --git a/tests/misc/expand.pl b/tests/misc/expand.pl -index 4b07210..68b9ea1 100755 ---- a/tests/misc/expand.pl -+++ b/tests/misc/expand.pl -@@ -27,6 +27,15 @@ my $prog = 'expand'; - # Turn off localization of executable's output. - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + static void +@@ -692,13 +831,192 @@ + } + } -+#comment out next line to disable multibyte tests -+my $mb_locale = $ENV{LOCALE_FR_UTF8}; -+! defined $mb_locale || $mb_locale eq 'none' -+ and $mb_locale = 'C'; ++#if HAVE_MBRTOWC ++static void ++cut_fields_mb (FILE *stream) ++{ ++ int c; ++ unsigned int field_idx; ++ int found_any_selected_field; ++ int buffer_first_field; ++ int empty_input; ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen; /* The length of the byte sequence in buf. */ ++ wint_t wc = 0; /* 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 of the stream. */ ++ int convfail; /* 1, when conversion is failed. Otherwise 0. */ + -+my $prog = 'expand'; -+my $try = "Try \`$prog --help' for more information.\n"; -+my $inval = "$prog: invalid byte, character or field list\n$try"; ++ found_any_selected_field = 0; ++ field_idx = 1; ++ bufpos = buf; ++ buflen = 0; ++ memset (&state, '\0', sizeof(mbstate_t)); + - my @Tests = - ( - ['t1', '--tabs=3', {IN=>"a\tb"}, {OUT=>"a b"}], -@@ -168,6 +177,8 @@ my @Tests = ++ c = getc (stream); ++ empty_input = (c == EOF); ++ if (c != EOF) ++ ungetc (c, stream); ++ else ++ wc = WEOF; ++ ++ /* To support the semantics of the -s flag, we may have to buffer ++ all of the first field to determine whether it is `delimited.' ++ But that is unnecessary if all non-delimited lines must be printed ++ and the first field has been selected, or if non-delimited lines ++ must be suppressed and the first field has *not* been selected. ++ That is because a non-delimited line has exactly one field. */ ++ buffer_first_field = (suppress_non_delimited ^ !print_kth (1, NULL)); ++ ++ while (1) ++ { ++ if (field_idx == 1 && buffer_first_field) ++ { ++ int len = 0; ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER ++ (wc, bufpos, buflen, mblength, state, convfail); ++ ++ if (wc == WEOF) ++ break; ++ ++ field_1_buffer = xrealloc (field_1_buffer, len + mblength); ++ memcpy (field_1_buffer + len, bufpos, mblength); ++ len += mblength; ++ buflen -= mblength; ++ bufpos += mblength; ++ ++ if (!convfail && (wc == L'\n' || wc == wcdelim)) ++ break; ++ } ++ ++ if (wc == WEOF) ++ break; ++ ++ /* If the first field extends to the end of line (it is not ++ delimited) and we are printing all non-delimited lines, ++ print this one. */ ++ if (convfail || (!convfail && wc != wcdelim)) ++ { ++ if (suppress_non_delimited) ++ { ++ /* Empty. */ ++ } ++ else ++ { ++ fwrite (field_1_buffer, sizeof (char), len, stdout); ++ /* Make sure the output line is newline terminated. */ ++ if (convfail || (!convfail && wc != L'\n')) ++ putchar ('\n'); ++ } ++ continue; ++ } ++ ++ if (print_kth (1, NULL)) ++ { ++ /* Print the field, but not the trailing delimiter. */ ++ fwrite (field_1_buffer, sizeof (char), len - 1, stdout); ++ found_any_selected_field = 1; ++ } ++ ++field_idx; ++ } ++ ++ if (wc != WEOF) ++ { ++ if (print_kth (field_idx, NULL)) ++ { ++ if (found_any_selected_field) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ found_any_selected_field = 1; ++ } ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER ++ (wc, bufpos, buflen, mblength, state, convfail); ++ ++ if (wc == WEOF) ++ break; ++ else if (!convfail && (wc == wcdelim || wc == L'\n')) ++ { ++ buflen -= mblength; ++ bufpos += mblength; ++ break; ++ } ++ ++ if (print_kth (field_idx, NULL)) ++ fwrite (bufpos, mblength, sizeof(char), stdout); ++ ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++ } ++ ++ if ((!convfail || wc == L'\n') && buflen < 1) ++ wc = WEOF; ++ ++ if (!convfail && wc == wcdelim) ++ ++field_idx; ++ else if (wc == WEOF || (!convfail && wc == L'\n')) ++ { ++ if (found_any_selected_field ++ || (!empty_input && !(suppress_non_delimited && field_idx == 1))) ++ putchar ('\n'); ++ if (wc == WEOF) ++ break; ++ field_idx = 1; ++ found_any_selected_field = 0; ++ } ++ } ++} ++#endif ++ + static void + cut_stream (FILE *stream) + { +- if (operating_mode == byte_mode) +- cut_bytes (stream); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) ++ { ++ switch (operating_mode) ++ { ++ case byte_mode: ++ if (byte_mode_character_aware) ++ cut_characters_or_cut_bytes_no_split (stream); ++ else ++ cut_bytes (stream); ++ break; ++ ++ case character_mode: ++ cut_characters_or_cut_bytes_no_split (stream); ++ break; ++ ++ case field_mode: ++ cut_fields_mb (stream); ++ break; ++ ++ default: ++ abort (); ++ } ++ } + else +- cut_fields (stream); ++#endif ++ { ++ if (operating_mode == field_mode) ++ cut_fields (stream); ++ else ++ cut_bytes (stream); ++ } + } + /* Process file FILE to standard output. +@@ -748,6 +1066,8 @@ + bool ok; + bool delim_specified = false; + char *spec_list_string IF_LINT(= NULL); ++ char mbdelim[MB_LEN_MAX + 1]; ++ size_t delimlen = 0; - # Test errors -+ # FIXME: The following tests contain ‘quoting’ specific to LC_MESSAGES -+ # So we force LC_MESSAGES=C to make them pass. - ['e1', '--tabs="a"', {IN=>''}, {OUT=>''}, {EXIT=>1}, - {ERR => "$prog: tab size contains invalid character(s): 'a'\n"}], - ['e2', "-t $UINTMAX_OFLOW", {IN=>''}, {OUT=>''}, {EXIT=>1}, -@@ -184,6 +195,37 @@ my @Tests = - {ERR => "$prog: '/' specifier not at start of number: '/'\n"}], - ); + initialize_main (&argc, &argv); + program_name = argv[0]; +@@ -770,7 +1090,6 @@ + switch (optc) + { + case 'b': +- case 'c': + /* Build the byte list. */ + if (operating_mode != undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); +@@ -778,6 +1097,14 @@ + spec_list_string = optarg; + break; -+if ($mb_locale ne 'C') -+ { -+ # Duplicate each test vector, appending "-mb" to the test name and -+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we -+ # provide coverage for the distro-added multi-byte code paths. -+ my @new; -+ foreach my $t (@Tests) -+ { -+ my @new_t = @$t; -+ my $test_name = shift @new_t; ++ case 'c': ++ /* Build the character list. */ ++ if (operating_mode != undefined_mode) ++ FATAL_ERROR (_("only one type of list may be specified")); ++ operating_mode = character_mode; ++ spec_list_string = optarg; ++ break; + -+ # Depending on whether expand is multi-byte-patched, -+ # it emits different diagnostics: -+ # non-MB: invalid byte or field list -+ # MB: invalid byte, character or field list -+ # Adjust the expected error output accordingly. -+ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} -+ (@new_t)) -+ { -+ my $sub = {ERR_SUBST => 's/, character//'}; -+ push @new_t, $sub; -+ push @$t, $sub; -+ } -+ push @new, ["$test_name-mb", @new_t, {ENV => "LANG=$mb_locale LC_MESSAGES=C"}]; -+ } -+ push @Tests, @new; -+ } + case 'f': + /* Build the field list. */ + if (operating_mode != undefined_mode) +@@ -789,10 +1116,35 @@ + case 'd': + /* New delimiter. */ + /* Interpret -d '' to mean `use the NUL byte as the delimiter.' */ +- if (optarg[0] != '\0' && optarg[1] != '\0') +- FATAL_ERROR (_("the delimiter must be a single character")); +- delim = optarg[0]; +- delim_specified = true; ++#if HAVE_MBRTOWC ++ { ++ if(MB_CUR_MAX > 1) ++ { ++ mbstate_t state; + ++ memset (&state, '\0', sizeof(mbstate_t)); ++ delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state); + -+@Tests = triple_test \@Tests; ++ if (delimlen == (size_t)-1 || delimlen == (size_t)-2) ++ ++force_singlebyte_mode; ++ else ++ { ++ delimlen = (delimlen < 1) ? 1 : delimlen; ++ if (wcdelim != L'\0' && *(optarg + delimlen) != '\0') ++ FATAL_ERROR (_("the delimiter must be a single character")); ++ memcpy (mbdelim, optarg, delimlen); ++ } ++ } + - my $save_temps = $ENV{DEBUG}; - my $verbose = $ENV{VERBOSE}; ++ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) ++#endif ++ { ++ if (optarg[0] != '\0' && optarg[1] != '\0') ++ FATAL_ERROR (_("the delimiter must be a single character")); ++ delim = (unsigned char) optarg[0]; ++ } ++ delim_specified = true; ++ } + break; -diff --git a/tests/misc/sort-mb-tests.sh b/tests/misc/sort-mb-tests.sh -new file mode 100644 -index 0000000..11836ba ---- /dev/null -+++ b/tests/misc/sort-mb-tests.sh -@@ -0,0 +1,45 @@ -+#!/bin/sh -+# Verify sort's multi-byte support. -+ -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src -+print_ver_ sort -+ -+export LC_ALL=en_US.UTF-8 -+locale -k LC_CTYPE | grep -q "charmap.*UTF-8" \ -+ || skip_ "No UTF-8 locale available" -+ -+ -+cat < exp -+Banana@5 -+Apple@10 -+Citrus@20 -+Cherry@30 -+EOF -+ -+cat < out || fail=1 -+Apple@10 -+Banana@5 -+Citrus@20 -+Cherry@30 -+EOF -+ -+compare exp out || { fail=1; cat out; } -+ -+ -+cat < exp -+Citrus@AA20@@5 -+Cherry@AA30@@10 -+Apple@AA10@@20 -+Banana@AA5@@30 -+EOF -+ -+cat < out || fail=1 -+Apple@AA10@@20 -+Banana@AA5@@30 -+Citrus@AA20@@5 -+Cherry@AA30@@10 -+EOF -+ -+compare exp out || { fail=1; cat out; } -+ -+Exit $fail -diff --git a/tests/misc/unexpand.pl b/tests/misc/unexpand.pl -index bb7469c..c1dec95 100755 ---- a/tests/misc/unexpand.pl -+++ b/tests/misc/unexpand.pl -@@ -27,6 +27,14 @@ my $limits = getlimits (); + case OUTPUT_DELIMITER_OPTION: +@@ -805,6 +1157,7 @@ + break; - my $prog = 'unexpand'; + case 'n': ++ byte_mode_character_aware = 1; + break; -+# comment out next line to disable multibyte tests -+my $mb_locale = $ENV{LOCALE_FR_UTF8}; -+! defined $mb_locale || $mb_locale eq 'none' -+ and $mb_locale = 'C'; -+ -+my $try = "Try \`$prog --help' for more information.\n"; -+my $inval = "$prog: invalid byte, character or field list\n$try"; -+ - my @Tests = - ( - ['a1', {IN=> ' 'x 1 ."y\n"}, {OUT=> ' 'x 1 ."y\n"}], -@@ -132,6 +140,37 @@ my @Tests = - ['ts2', '-t5,8', {IN=>"x\t \t y\n"}, {OUT=>"x\t\t y\n"}], - ); + case 's': +@@ -827,7 +1180,7 @@ + if (operating_mode == undefined_mode) + FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); -+if ($mb_locale ne 'C') -+ { -+ # Duplicate each test vector, appending "-mb" to the test name and -+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we -+ # provide coverage for the distro-added multi-byte code paths. -+ my @new; -+ foreach my $t (@Tests) -+ { -+ my @new_t = @$t; -+ my $test_name = shift @new_t; -+ -+ # Depending on whether unexpand is multi-byte-patched, -+ # it emits different diagnostics: -+ # non-MB: invalid byte or field list -+ # MB: invalid byte, character or field list -+ # Adjust the expected error output accordingly. -+ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} -+ (@new_t)) -+ { -+ my $sub = {ERR_SUBST => 's/, character//'}; -+ push @new_t, $sub; -+ push @$t, $sub; -+ } -+ next if ($test_name =~ 'b-1'); -+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; -+ } -+ push @Tests, @new; -+ } -+ -+@Tests = triple_test \@Tests; -+ - my $save_temps = $ENV{DEBUG}; - my $verbose = $ENV{VERBOSE}; +- if (delim != '\0' && operating_mode != field_mode) ++ if (delim_specified && operating_mode != field_mode) + FATAL_ERROR (_("an input delimiter may be specified only\ + when operating on fields")); -diff --git a/tests/pr/pr-tests.pl b/tests/pr/pr-tests.pl -index 60e6106..3c64a08 100755 ---- a/tests/pr/pr-tests.pl -+++ b/tests/pr/pr-tests.pl -@@ -24,6 +24,15 @@ use strict; - my $prog = 'pr'; - my $normalize_strerror = "s/': .*/'/"; +@@ -854,15 +1207,34 @@ + } -+my $mb_locale; -+#Uncomment the following line to enable multibyte tests -+$mb_locale = $ENV{LOCALE_FR_UTF8}; -+! defined $mb_locale || $mb_locale eq 'none' -+ and $mb_locale = 'C'; -+ -+my $try = "Try \`$prog --help' for more information.\n"; -+my $inval = "$prog: invalid byte, character or field list\n$try"; -+ - my @tv = ( + if (!delim_specified) +- delim = '\t'; ++ { ++ delim = '\t'; ++#ifdef HAVE_MBRTOWC ++ wcdelim = L'\t'; ++ mbdelim[0] = '\t'; ++ mbdelim[1] = '\0'; ++ delimlen = 1; ++#endif ++ } - # -b option is no longer an official option. But it's still working to -@@ -515,8 +524,48 @@ push @Tests, - {IN=>"x\tx\tx\tx\tx\nx\tx\tx\tx\tx\n"}, - {OUT=>"x\tx\tx\tx\tx\tx\tx\tx\tx\tx\n"} ]; + if (output_delimiter_string == NULL) + { +- static char dummy[2]; +- dummy[0] = delim; +- dummy[1] = '\0'; +- output_delimiter_string = dummy; +- output_delimiter_length = 1; ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) ++ { ++ output_delimiter_string = xstrdup(mbdelim); ++ output_delimiter_length = delimlen; ++ } ++ ++ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) ++#endif ++ { ++ static char dummy[2]; ++ dummy[0] = delim; ++ dummy[1] = '\0'; ++ output_delimiter_string = dummy; ++ output_delimiter_length = 1; ++ } + } -+# Add _POSIX2_VERSION=199209 to the environment of each test -+# that uses an old-style option like +1. -+if ($mb_locale ne 'C') -+ { -+ # Duplicate each test vector, appending "-mb" to the test name and -+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we -+ # provide coverage for the distro-added multi-byte code paths. -+ my @new; -+ foreach my $t (@Tests) -+ { -+ my @new_t = @$t; -+ my $test_name = shift @new_t; -+ -+ # Depending on whether pr is multi-byte-patched, -+ # it emits different diagnostics: -+ # non-MB: invalid byte or field list -+ # MB: invalid byte, character or field list -+ # Adjust the expected error output accordingly. -+ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} -+ (@new_t)) -+ { -+ my $sub = {ERR_SUBST => 's/, character//'}; -+ push @new_t, $sub; -+ push @$t, $sub; -+ } -+ #temporarily skip some failing tests -+ next if ($test_name =~ "col-0" or $test_name =~ "col-inval" or $test_name =~ "asan1"); -+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; -+ } -+ push @Tests, @new; -+ } -+ - @Tests = triple_test \@Tests; - -+# Remember that triple_test creates from each test with exactly one "IN" -+# file two more tests (.p and .r suffix on name) corresponding to reading -+# input from a file and from a pipe. The pipe-reading test would fail -+# due to a race condition about 1 in 20 times. -+# Remove the IN_PIPE version of the "output-is-input" test above. -+# The others aren't susceptible because they have three inputs each. -+@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; -+ - my $save_temps = $ENV{DEBUG}; - my $verbose = $ENV{VERBOSE}; - -diff --git a/tests/sort/sort-merge.pl b/tests/sort/sort-merge.pl -index a3204d3..40942a5 100755 ---- a/tests/sort/sort-merge.pl -+++ b/tests/sort/sort-merge.pl -@@ -26,6 +26,15 @@ my $prog = 'sort'; - # Turn off localization of executable's output. - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; - -+my $mb_locale; -+# uncommented according to upstream commit enabling multibyte paths -+$mb_locale = $ENV{LOCALE_FR_UTF8}; -+! defined $mb_locale || $mb_locale eq 'none' -+ and $mb_locale = 'C'; -+ -+my $try = "Try \`$prog --help' for more information.\n"; -+my $inval = "$prog: invalid byte, character or field list\n$try"; -+ - # three empty files and one that says 'foo' - my @inputs = (+(map{{IN=> {"empty$_"=> ''}}}1..3), {IN=> {foo=> "foo\n"}}); - -@@ -77,6 +86,39 @@ my @Tests = - {OUT=>$big_input}], - ); - -+# Add _POSIX2_VERSION=199209 to the environment of each test -+# that uses an old-style option like +1. -+if ($mb_locale ne 'C') -+ { -+ # Duplicate each test vector, appending "-mb" to the test name and -+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we -+ # provide coverage for the distro-added multi-byte code paths. -+ my @new; -+ foreach my $t (@Tests) -+ { -+ my @new_t = @$t; -+ my $test_name = shift @new_t; -+ -+ # Depending on whether sort is multi-byte-patched, -+ # it emits different diagnostics: -+ # non-MB: invalid byte or field list -+ # MB: invalid byte, character or field list -+ # Adjust the expected error output accordingly. -+ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} -+ (@new_t)) -+ { -+ my $sub = {ERR_SUBST => 's/, character//'}; -+ push @new_t, $sub; -+ push @$t, $sub; -+ } -+ next if ($test_name =~ "nmerge-."); -+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; -+ } -+ push @Tests, @new; -+ } -+ -+@Tests = triple_test \@Tests; -+ - my $save_temps = $ENV{DEBUG}; - my $verbose = $ENV{VERBOSE}; - -diff --git a/tests/sort/sort.pl b/tests/sort/sort.pl -index 5fa9d52..a66952a 100755 ---- a/tests/sort/sort.pl -+++ b/tests/sort/sort.pl -@@ -24,10 +24,15 @@ my $prog = 'sort'; - # Turn off localization of executable's output. - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; - --my $mb_locale = $ENV{LOCALE_FR_UTF8}; -+my $mb_locale; -+#Comment out next line to disable multibyte tests -+$mb_locale = $ENV{LOCALE_FR_UTF8}; - ! defined $mb_locale || $mb_locale eq 'none' - and $mb_locale = 'C'; - -+my $try = "Try \`$prog --help' for more information.\n"; -+my $inval = "$prog: invalid byte, character or field list\n$try"; -+ - # Since each test is run with a file name and with redirected stdin, - # the name in the diagnostic is either the file name or "-". - # Normalize each diagnostic to use '-'. -@@ -428,6 +433,38 @@ foreach my $t (@Tests) - } - } - -+if ($mb_locale ne 'C') -+ { -+ # Duplicate each test vector, appending "-mb" to the test name and -+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we -+ # provide coverage for the distro-added multi-byte code paths. -+ my @new; -+ foreach my $t (@Tests) -+ { -+ my @new_t = @$t; -+ my $test_name = shift @new_t; -+ -+ # Depending on whether sort is multi-byte-patched, -+ # it emits different diagnostics: -+ # non-MB: invalid byte or field list -+ # MB: invalid byte, character or field list -+ # Adjust the expected error output accordingly. -+ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} -+ (@new_t)) -+ { -+ my $sub = {ERR_SUBST => 's/, character//'}; -+ push @new_t, $sub; -+ push @$t, $sub; -+ } -+ #disable several failing tests until investigation, disable all tests with envvars set -+ next if (grep {ref $_ eq 'HASH' && exists $_->{ENV}} (@new_t)); -+ next if ($test_name =~ "18g" or $test_name =~ "sort-numeric" or $test_name =~ "08[ab]" or $test_name =~ "03[def]" or $test_name =~ "h4" or $test_name =~ "n1" or $test_name =~ "2[01]a"); -+ next if ($test_name =~ "11[ab]"); # avoid FP: expected result differs to MB result due to collation rules. -+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; -+ } -+ push @Tests, @new; -+ } -+ - @Tests = triple_test \@Tests; - - # Remember that triple_test creates from each test with exactly one "IN" -@@ -437,6 +474,7 @@ foreach my $t (@Tests) - # Remove the IN_PIPE version of the "output-is-input" test above. - # The others aren't susceptible because they have three inputs each. - @Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; -+@Tests = grep {$_->[0] ne 'output-is-input-mb.p'} @Tests; - - my $save_temps = $ENV{DEBUG}; - my $verbose = $ENV{VERBOSE}; -diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh -new file mode 100644 -index 0000000..8a82d74 ---- /dev/null -+++ b/tests/unexpand/mb.sh -@@ -0,0 +1,172 @@ -+#!/bin/sh -+ -+# Copyright (C) 2012-2015 Free Software Foundation, Inc. -+ -+# This program is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+ -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+ -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+ -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src -+print_ver_ unexpand -+ -+export LC_ALL=en_US.UTF-8 -+ -+#input containing multibyte characters -+cat > in <<\EOF -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+cat > exp <<\EOF -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+unexpand -a < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+ -+#multiple files as an input -+cat >> exp <<\EOF -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+ -+unexpand -a ./in ./in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#test characters with a display width larger than 1 -+ -+env printf '12345678 -+e |ascii(1) -+\u00E9 |composed(1) -+e\u0301 |decomposed(1) -+\u3000 |ideo-space(2) -+\uFF0D |full-hypen(2) -+' > in || framework_failure_ -+ -+env printf '12345678 -+e\t|ascii(1) -+\u00E9\t|composed(1) -+e\u0301\t|decomposed(1) -+\u3000\t|ideo-space(2) -+\uFF0D\t|full-hypen(2) -+' > exp || framework_failure_ -+ -+unexpand -a < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#test input where a blank of width > 1 is not being substituted -+in="$(LC_ALL=en_US.UTF-8 printf ' \u3000 ö ü ß')" -+exp='   ö ü ß' -+ -+unexpand -a < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#non-Unicode characters interspersed between Unicode ones -+env printf '12345678 -+ \xFF| -+\xFF | -+ \xFFä| -+ä\xFF | -+ ä\xFF| -+\xFF ä| -+äbcdef\xFF | -+' > in || framework_failure_ -+ -+env printf '12345678 -+\t\xFF| -+\xFF\t| -+\t\xFFä| -+ä\xFF\t| -+\tä\xFF| -+\xFF\tä| -+äbcdef\xFF\t| -+' > exp || framework_failure_ -+ -+unexpand -a < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#BOM header test 1 -+printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ -+ -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+unexpand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LANG=C unexpand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LC_ALL=C unexpand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+ -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+ -+unexpand in in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LANG=C unexpand in in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LC_ALL=C unexpand in in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 --- -2.52.0 - + if (optind == argc) diff --git a/coreutils-keyring.gpg b/coreutils-keyring.gpg deleted file mode 100644 index 003a885..0000000 --- a/coreutils-keyring.gpg +++ /dev/null @@ -1,312 +0,0 @@ -Release GPG keyring of coreutils group. - ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -ELphkzjc6eM3CaOZ73u4GVXotheeUabUHQ== -=drvb ------END PGP PUBLIC KEY BLOCK----- \ No newline at end of file diff --git a/coreutils-ls-x.patch b/coreutils-ls-x.patch new file mode 100644 index 0000000..de1de02 --- /dev/null +++ b/coreutils-ls-x.patch @@ -0,0 +1,109 @@ +--- coreutils-6.9/src/ls.c.ls-x 2007-06-13 14:27:36.000000000 +0100 ++++ coreutils-6.9/src/ls.c 2007-06-13 14:28:42.000000000 +0100 +@@ -4151,16 +4151,16 @@ + size_t pos = 0; + size_t cols = calculate_columns (false); + struct column_info const *line_fmt = &column_info[cols - 1]; +- size_t name_length = length_of_file_name_and_frills (cwd_file); ++ struct fileinfo const *f = sorted_file[0]; ++ size_t name_length = length_of_file_name_and_frills (f); + size_t max_name_length = line_fmt->col_arr[0]; + + /* Print first entry. */ +- print_file_name_and_frills (cwd_file); ++ print_file_name_and_frills (f); + + /* Now the rest. */ + for (filesno = 1; filesno < cwd_n_used; ++filesno) + { +- struct fileinfo const *f; + size_t col = filesno % cols; + + if (col == 0) +--- coreutils-6.9/tests/ls/Makefile.am.ls-x 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/tests/ls/Makefile.am 2007-06-13 14:28:42.000000000 +0100 +@@ -24,7 +24,7 @@ + stat-dtype \ + inode dangle file-type recursive dired infloop \ + rt-1 time-1 symlink-slash follow-slink no-arg m-option \ +- stat-vs-dirent ++ stat-vs-dirent x-option + + EXTRA_DIST = $(TESTS) + TESTS_ENVIRONMENT = \ +--- /dev/null 2007-06-13 08:43:51.993263382 +0100 ++++ coreutils-6.9/tests/ls/x-option 2007-06-13 14:28:42.000000000 +0100 +@@ -0,0 +1,59 @@ ++#!/bin/sh ++# Exercise the -x option. ++ ++# Copyright (C) 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++# 02110-1301, USA. ++ ++if test "$VERBOSE" = yes; then ++ set -x ++ ls --version ++fi ++ ++. $srcdir/../envvar-check ++. $srcdir/../lang-default ++ ++pwd=`pwd` ++t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ ++trap 'status=$?; cd "$pwd" && chmod -R u+rwx $t0 && rm -rf $t0 && exit $status' 0 ++trap '(exit $?); exit $?' 1 2 13 15 ++ ++framework_failure=0 ++mkdir -p $tmp || framework_failure=1 ++cd $tmp || framework_failure=1 ++mkdir subdir || framework_failure=1 ++touch subdir/b || framework_failure=1 ++touch subdir/a || framework_failure=1 ++ ++if test $framework_failure = 1; then ++ echo "$0: failure in testing framework" 1>&2 ++ (exit 1); exit 1 ++fi ++ ++fail=0 ++ ++# Coreutils 6.8 and 6.9 would output this in the wrong order. ++ls -x subdir > out || fail=1 ++ls -rx subdir >> out || fail=1 ++cat <<\EOF > exp || fail=1 ++a b ++b a ++EOF ++ ++cmp out exp || fail=1 ++test $fail = 1 && diff out exp 2> /dev/null ++ ++(exit $fail); exit $fail +--- coreutils-6.9/NEWS.ls-x 2007-03-22 21:19:45.000000000 +0000 ++++ coreutils-6.9/NEWS 2007-06-13 14:28:42.000000000 +0100 +@@ -13,6 +13,11 @@ + Using pr -m -s (i.e. merging files, with TAB as the output separator) + no longer inserts extraneous spaces between output columns. + ++** Bug fixes ++ ++ ls -x DIR would sometimes output the wrong string in place of the ++ first entry. [introduced in coreutils-6.8] ++ + + * Noteworthy changes in release 6.8 (2007-02-24) [not-unstable] + diff --git a/coreutils-mvatomic.patch b/coreutils-mvatomic.patch new file mode 100644 index 0000000..aa9fb2f --- /dev/null +++ b/coreutils-mvatomic.patch @@ -0,0 +1,117 @@ + src/copy.c | 5 +++-- + tests/mv/Makefile.am | 4 ++-- + tests/mv/atomic2 | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 69 insertions(+), 4 deletions(-) + create mode 100755 tests/mv/atomic2 + +diff --git a/src/copy.c b/src/copy.c +index fd31b5c..208a674 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -1339,10 +1339,11 @@ copy_internal (char const *src_name, char const *dst_name, + new_dst = true; + } + else if (! S_ISDIR (dst_sb.st_mode) ++ /* Never unlink dst_name when in move mode. */ ++ && ! x->move_mode + && (x->unlink_dest_before_opening + || (x->preserve_links && 1 < dst_sb.st_nlink) +- || (!x->move_mode +- && x->dereference == DEREF_NEVER ++ || (x->dereference == DEREF_NEVER + && S_ISLNK (src_sb.st_mode)) + )) + { +diff --git a/tests/mv/Makefile.am b/tests/mv/Makefile.am +index c121911..92ec68e 100644 +--- a/tests/mv/Makefile.am ++++ b/tests/mv/Makefile.am +@@ -1,7 +1,6 @@ + # Make coreutils tests for "mv". -*-Makefile-*- + +-# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 +-# Free Software Foundation, Inc. ++# Copyright (C) 1998-2008 Free Software Foundation, Inc. + + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -17,6 +16,7 @@ + # along with this program. If not, see . + + TESTS = \ ++ atomic2 \ + hard-verbose \ + backup-dir \ + dir2dir \ +diff --git a/tests/mv/atomic2 b/tests/mv/atomic2 +new file mode 100755 +index 0000000..d1029aa +--- /dev/null ++++ b/tests/mv/atomic2 +@@ -0,0 +1,64 @@ ++#!/bin/sh ++# ensure that mv doesn't first unlink a multi-hard-linked destination ++ ++# Copyright (C) 2008 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++if test "$VERBOSE" = yes; then ++ set -x ++ mv --version ++fi ++ ++pwd=`pwd` ++t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ ++trap 'status=$?; cd "$pwd" && chmod -R u+rwx $t0 && rm -rf $t0 && exit $status' 0 ++trap '(exit $?); exit $?' 1 2 13 15 ++ ++# Before the fix, mv would unnecessarily unlink the destination symlink: ++# $ rm -f a b b2; touch a b; ln b b2; strace -e unlink /p/bin/mv a b ++# unlink("b") = 0 ++# ++# With the fix, it doesn't call unlink: ++# $ rm -f a b b2; touch a b; ln b b2; strace -e unlink ./mv a b ++# $ ++ ++framework_failure=0 ++touch a b || framework_failure=1 ++ln b b2 || framework_failure=1 ++if test $framework_failure = 1; then ++ echo "$0: failure in testing framework" 1>&2 ++ (exit 1); exit 1 ++fi ++ ++# Skip this test on systems without strace. ++strace -V < /dev/null > ver 2>&1 || skip=1 ++if test "$skip" = 1; then ++ echo "$0: no strace program, so skipping this test" 1>&2 ++ (exit 77); exit 77 ++fi ++ ++fail=0 ++ ++strace -qe unlink mv a b > out 2>&1 || fail=1 ++$EGREP 'unlink.*"b"' out && fail=1 ++ ++# Ensure that the source, "a", is gone. ++ls -dl a > /dev/null 2>&1 && fail=1 ++ ++# Ensure that the destination, "b", has link count 1. ++n_links=`stat --printf=%h b` || fail=1 ++test "$n_links" = 1 || fail=1 ++ ++(exit $fail); exit $fail +-- +1.5.5.rc0.7.g57e83 diff --git a/coreutils-overflow.patch b/coreutils-overflow.patch new file mode 100644 index 0000000..81592cc --- /dev/null +++ b/coreutils-overflow.patch @@ -0,0 +1,11 @@ +--- coreutils-5.2.1/src/who.c.overflow 2005-05-25 09:59:06.000000000 +0100 ++++ coreutils-5.2.1/src/who.c 2005-05-25 10:00:31.000000000 +0100 +@@ -75,7 +75,7 @@ + # define NEW_TIME 0 + #endif + +-#define IDLESTR_LEN 6 ++#define IDLESTR_LEN 10 + + #if HAVE_STRUCT_XTMP_UT_PID + # define PIDSTR_DECL_AND_INIT(Var, Utmp_ent) \ diff --git a/coreutils-pam.patch b/coreutils-pam.patch new file mode 100644 index 0000000..a0fe36b --- /dev/null +++ b/coreutils-pam.patch @@ -0,0 +1,413 @@ +--- 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) + +-su_LDADD = $(LDADD) $(LIB_CRYPT) ++su_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@ + + 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. + ++#ifdef USE_PAM ++ ++ Actually, with PAM, su has nothing to do with whether or not a ++ wheel group is enforced by su. RMS tries to restrict your access ++ to a su which implements the wheel group, but PAM considers that ++ to be fascist, and gives the user/sysadmin the opportunity to ++ enforce a wheel group by proper editing of /etc/pam.conf ++ ++#endif ++ + 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_ + ++#ifdef USE_PAM ++# include ++# include ++# include ++# include ++# include ++# include ++#endif /* USE_PAM */ ++ + #include "system.h" + #include "getpass.h" + +@@ -128,15 +147,22 @@ + /* The user to become if none is specified. */ + #define DEFAULT_USER "root" + ++#ifndef USE_PAM + char *crypt (); ++#endif + char *getusershell (); + void endusershell (); + void setusershell (); + + extern char **environ; + +-static void run_shell (char const *, char const *, char **, size_t) ++static void run_shell (char const *, char const *, char **, size_t, ++ const struct passwd *) ++#ifdef USE_PAM ++ ; ++#else + ATTRIBUTE_NORETURN; ++#endif + + /* The name this program was run with. */ + char *program_name; +@@ -225,7 +251,26 @@ + } + #endif + ++#ifdef USE_PAM ++static pam_handle_t *pamh = NULL; ++static int retval; ++static struct pam_conv conv = { ++ misc_conv, ++ NULL ++}; ++ ++#define PAM_BAIL_P if (retval) { \ ++ pam_end(pamh, PAM_SUCCESS); \ ++ return 0; \ ++} ++#define PAM_BAIL_P_VOID if (retval) { \ ++ pam_end(pamh, PAM_SUCCESS); \ ++return; \ ++} ++#endif ++ + /* Ask the user for a password. ++ If PAM is in use, let PAM ask for the password if necessary. + 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. */ +@@ -233,6 +278,44 @@ + static bool + correct_password (const struct passwd *pw) + { ++#ifdef USE_PAM ++ struct passwd *caller; ++ char *tty_name, *ttyn; ++ retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh); ++ PAM_BAIL_P; ++ ++ if (getuid() != 0 && !isatty(0)) { ++ fprintf(stderr, "standard in must be a tty\n"); ++ exit(1); ++ } ++ ++ caller = getpwuid(getuid()); ++ if(caller != NULL && caller->pw_name != NULL) { ++ retval = pam_set_item(pamh, PAM_RUSER, caller->pw_name); ++ PAM_BAIL_P; ++ } ++ ++ ttyn = ttyname(0); ++ if (ttyn) { ++ if (strncmp(ttyn, "/dev/", 5) == 0) ++ tty_name = ttyn+5; ++ else ++ tty_name = ttyn; ++ retval = pam_set_item(pamh, PAM_TTY, tty_name); ++ PAM_BAIL_P; ++ } ++ retval = pam_authenticate(pamh, 0); ++ PAM_BAIL_P; ++ retval = pam_acct_mgmt(pamh, 0); ++ if (retval == PAM_NEW_AUTHTOK_REQD) { ++ /* password has expired. Offer option to change it. */ ++ retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); ++ PAM_BAIL_P; ++ } ++ PAM_BAIL_P; ++ /* must be authenticated if this point was reached */ ++ return 1; ++#else /* !USE_PAM */ + char *unencrypted, *encrypted, *correct; + #if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP + /* Shadow passwd stuff for SVR3 and maybe other systems. */ +@@ -257,6 +340,7 @@ + encrypted = crypt (unencrypted, correct); + memset (unencrypted, 0, strlen (unencrypted)); + return STREQ (encrypted, correct); ++#endif /* !USE_PAM */ + } + + /* Update `environ' for the new shell based on PW, with SHELL being +@@ -270,12 +354,18 @@ + /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. + Unset all other environment variables. */ + char const *term = getenv ("TERM"); ++ char const *display = getenv ("DISPLAY"); ++ char const *xauthority = getenv ("XAUTHORITY"); + if (term) + term = xstrdup (term); + environ = xmalloc ((6 + !!term) * sizeof (char *)); + environ[0] = NULL; + if (term) + xsetenv ("TERM", term); ++ if (display) ++ xsetenv ("DISPLAY", display); ++ if (xauthority) ++ xsetenv ("XAUTHORITY", xauthority); + xsetenv ("HOME", pw->pw_dir); + xsetenv ("SHELL", shell); + xsetenv ("USER", pw->pw_name); +@@ -308,8 +398,13 @@ + { + #ifdef HAVE_INITGROUPS + errno = 0; +- if (initgroups (pw->pw_name, pw->pw_gid) == -1) ++ if (initgroups (pw->pw_name, pw->pw_gid) == -1) { ++#ifdef USE_PAM ++ pam_close_session(pamh, 0); ++ pam_end(pamh, PAM_ABORT); ++#endif + error (EXIT_FAIL, errno, _("cannot set groups")); ++ } + endgrent (); + #endif + if (setgid (pw->pw_gid)) +@@ -318,6 +413,31 @@ + error (EXIT_FAIL, errno, _("cannot set user id")); + } + ++#ifdef USE_PAM ++static int caught=0; ++/* Signal handler for parent process later */ ++static void su_catch_sig(int sig) ++{ ++ ++caught; ++} ++ ++int ++pam_copyenv (pam_handle_t *pamh) ++{ ++ char **env; ++ ++ env = pam_getenvlist(pamh); ++ if(env) { ++ while(*env) { ++ if (putenv (*env)) ++ xalloc_die (); ++ env++; ++ } ++ } ++ return(0); ++} ++#endif ++ + /* 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 +@@ -325,17 +445,49 @@ + + static void + run_shell (char const *shell, char const *command, char **additional_args, +- size_t n_additional_args) ++ size_t n_additional_args, const struct passwd *pw) + { + size_t n_args = 1 + fast_startup + 2 * !!command + n_additional_args + 1; + char const **args = xnmalloc (n_args, sizeof *args); + size_t argno = 1; ++#ifdef USE_PAM ++ int child; ++ sigset_t ourset; ++ int status; ++ ++ retval = pam_open_session(pamh,0); ++ if (retval != PAM_SUCCESS) { ++ fprintf (stderr, "could not open session\n"); ++ exit (1); ++ } ++ ++/* do this at the last possible moment, because environment variables may ++ be passed even in the session phase ++*/ ++ if(pam_copyenv(pamh) != PAM_SUCCESS) ++ fprintf (stderr, "error copying PAM environment\n"); ++ ++ /* Credentials should be set in the parent */ ++ if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) { ++ pam_close_session(pamh, 0); ++ fprintf(stderr, "could not set PAM credentials\n"); ++ exit(1); ++ } ++ ++ child = fork(); ++ if (child == 0) { /* child shell */ ++ change_identity (pw); ++ pam_end(pamh, 0); ++#endif + + if (simulate_login) + { + char *arg0; + char *shell_basename; + ++ if(chdir(pw->pw_dir)) ++ error(0, errno, _("warning: cannot change directory to %s"), pw->pw_dir); ++ + shell_basename = last_component (shell); + arg0 = xmalloc (strlen (shell_basename) + 2); + arg0[0] = '-'; +@@ -360,6 +512,66 @@ + error (0, errno, "%s", shell); + exit (exit_status); + } ++#ifdef USE_PAM ++ } else if (child == -1) { ++ fprintf(stderr, "can not fork user shell: %s", strerror(errno)); ++ pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT); ++ pam_close_session(pamh, 0); ++ pam_end(pamh, PAM_ABORT); ++ exit(1); ++ } ++ /* parent only */ ++ sigfillset(&ourset); ++ if (sigprocmask(SIG_BLOCK, &ourset, NULL)) { ++ fprintf(stderr, "%s: signal malfunction\n", PROGRAM_NAME); ++ caught = 1; ++ } ++ if (!caught) { ++ struct sigaction action; ++ action.sa_handler = su_catch_sig; ++ sigemptyset(&action.sa_mask); ++ action.sa_flags = 0; ++ sigemptyset(&ourset); ++ if (sigaddset(&ourset, SIGTERM) ++ || sigaddset(&ourset, SIGALRM) ++ || sigaction(SIGTERM, &action, NULL) ++ || sigprocmask(SIG_UNBLOCK, &ourset, NULL)) { ++ fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME); ++ caught = 1; ++ } ++ } ++ if (!caught) { ++ do { ++ int pid; ++ ++ pid = waitpid(-1, &status, WUNTRACED); ++ ++ if (WIFSTOPPED(status)) { ++ kill(getpid(), SIGSTOP); ++ /* once we get here, we must have resumed */ ++ kill(pid, SIGCONT); ++ } ++ } while (WIFSTOPPED(status)); ++ } ++ ++ if (caught) { ++ fprintf(stderr, "\nSession terminated, killing shell..."); ++ kill (child, SIGTERM); ++ } ++ /* Not checking retval on this because we need to call close session */ ++ pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT); ++ retval = pam_close_session(pamh, 0); ++ PAM_BAIL_P_VOID; ++ retval = pam_end(pamh, PAM_SUCCESS); ++ PAM_BAIL_P_VOID; ++ if (caught) { ++ sleep(2); ++ kill(child, SIGKILL); ++ fprintf(stderr, " ...killed.\n"); ++ exit(-1); ++ } ++ exit (WEXITSTATUS(status)); ++#endif /* USE_PAM */ + } + + /* Return true if SHELL is a restricted shell (one not returned by +@@ -527,9 +739,9 @@ + shell = xstrdup (shell ? shell : pw->pw_shell); + modify_environment (pw, shell); + ++#ifndef USE_PAM + change_identity (pw); +- if (simulate_login && chdir (pw->pw_dir) != 0) +- error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir); ++#endif + +- run_shell (shell, command, argv + optind, MAX (0, argc - optind)); ++ run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw); + } +--- 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. + + The program accepts the following options. Also see @ref{Common options}. + +@@ -13477,33 +13480,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-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 ++[ --enable-pam Enable use of the PAM libraries], ++[AC_DEFINE(USE_PAM, 1, [Define if you want to use PAM]) ++LIB_PAM="-ldl -lpam -lpam_misc" ++AC_SUBST(LIB_PAM)]) ++ + AC_CHECK_FUNCS(uname, + OPTIONAL_BIN_PROGS="$OPTIONAL_BIN_PROGS uname\$(EXEEXT)" + MAN="$MAN uname.1") diff --git a/coreutils-python3.patch b/coreutils-python3.patch deleted file mode 100644 index 447fdbc..0000000 --- a/coreutils-python3.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 8927d505ecb5334f09c48ef98ef1f464f581d0f7 Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Tue, 2 Apr 2024 14:11:26 +0100 -Subject: [PATCH] coreutils-python3.patch - ---- - init.cfg | 4 ++-- - tests/d_type-check | 2 +- - tests/du/move-dir-while-traversing.sh | 6 +++--- - 3 files changed, 6 insertions(+), 6 deletions(-) - -diff --git a/init.cfg b/init.cfg -index ac05f7b..26d9516 100644 ---- a/init.cfg -+++ b/init.cfg -@@ -601,10 +601,10 @@ seek_data_capable_() - # Skip the current test if "." lacks d_type support. - require_dirent_d_type_() - { -- python < /dev/null \ -+ python3 < /dev/null \ - || skip_ python missing: assuming no d_type support - -- python "$abs_srcdir"/tests/d_type-check \ -+ python3 "$abs_srcdir"/tests/d_type-check \ - || skip_ requires d_type support - } - -diff --git a/tests/d_type-check b/tests/d_type-check -index 1a2f76f..42d3924 100644 ---- a/tests/d_type-check -+++ b/tests/d_type-check -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # Exit 0 if "." and "./tempfile" have useful d_type information, else 1. - # Intended to exit 0 only on Linux/GNU systems. - import os -diff --git a/tests/du/move-dir-while-traversing.sh b/tests/du/move-dir-while-traversing.sh -index adf482b..cf9214a 100755 ---- a/tests/du/move-dir-while-traversing.sh -+++ b/tests/du/move-dir-while-traversing.sh -@@ -21,8 +21,8 @@ print_ver_ du - require_trap_signame_ - - # We use a python-inotify script, so... --python -m pyinotify -h > /dev/null \ -- || skip_ 'python inotify package not installed' -+python3 -m pyinotify -h > /dev/null \ -+ || skip_ 'python3 inotify package not installed' - - # Move a directory "up" while du is processing its sub-directories. - # While du is processing a hierarchy .../B/C/D/... this script -@@ -33,7 +33,7 @@ python -m pyinotify -h > /dev/null \ - # rename syscall before du finishes processing the subtree under D/. - - cat <<'EOF' > inotify-watch-for-dir-access.py --#!/usr/bin/env python -+#!/usr/bin/env python3 - import pyinotify as pn - import os,sys - --- -2.51.0 - diff --git a/coreutils-runuser-l.pamd b/coreutils-runuser-l.pamd new file mode 100644 index 0000000..fa1e4d8 --- /dev/null +++ b/coreutils-runuser-l.pamd @@ -0,0 +1,4 @@ +#%PAM-1.0 +auth include runuser +session optional pam_keyinit.so force revoke +session include runuser diff --git a/coreutils-runuser.pamd b/coreutils-runuser.pamd new file mode 100644 index 0000000..37f0e84 --- /dev/null +++ b/coreutils-runuser.pamd @@ -0,0 +1,5 @@ +#%PAM-1.0 +auth sufficient pam_rootok.so +session optional pam_keyinit.so revoke +session required pam_limits.so +session required pam_unix.so diff --git a/coreutils-selinux.patch b/coreutils-selinux.patch new file mode 100644 index 0000000..c221d1e --- /dev/null +++ b/coreutils-selinux.patch @@ -0,0 +1,2627 @@ +--- coreutils-6.9/tests/help-version.selinux 2007-03-23 11:59:21.000000000 +0000 ++++ coreutils-6.9/tests/help-version 2007-03-23 11:59:21.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.9/src/ls.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/ls.c 2007-03-23 11:59:21.000000000 +0000 +@@ -111,6 +111,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 + +@@ -133,7 +145,8 @@ + symbolic_link, + sock, + whiteout, +- arg_directory ++ arg_directory, ++ command_line + }; + + /* Display letters and indicators for each filetype. +@@ -177,6 +190,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 +@@ -247,6 +264,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; +@@ -360,7 +380,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; +@@ -741,6 +765,11 @@ + SHOW_CONTROL_CHARS_OPTION, + SI_OPTION, + SORT_OPTION, ++#ifdef WITH_SELINUX ++ CONTEXT_OPTION, ++ LCONTEXT_OPTION, ++ SCONTEXT_OPTION, ++#endif + TIME_OPTION, + TIME_STYLE_OPTION + }; +@@ -787,6 +816,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}, +@@ -796,12 +830,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); + +@@ -1246,6 +1287,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 +@@ -1276,7 +1320,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 (cwd_n_used) +@@ -1439,6 +1483,9 @@ + ignore_mode = IGNORE_DEFAULT; + ignore_patterns = NULL; + hide_patterns = NULL; ++#ifdef WITH_SELINUX ++ print_scontext = 0; ++#endif + + /* FIXME: put this in a function. */ + { +@@ -1514,7 +1561,7 @@ + } + + while ((c = getopt_long (argc, argv, +- "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1", ++ "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1Z", + long_options, NULL)) != -1) + { + switch (c) +@@ -1637,6 +1684,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; +@@ -1817,6 +1871,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); + } +@@ -2514,6 +2587,13 @@ + for (i = 0; i < cwd_n_used; i++) + { + struct fileinfo *f = sorted_file[i]; ++#ifdef WITH_SELINUX ++ if (f->scontext) ++ { ++ freecon (f->scontext); ++ f->scontext = NULL; ++ } ++#endif /* SELINUX */ + free (f->name); + free (f->linkname); + } +@@ -2558,6 +2638,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 +@@ -2606,6 +2689,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: +@@ -2614,6 +2702,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; +@@ -2632,6 +2725,11 @@ + + 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; + } + +@@ -2654,7 +2752,11 @@ + 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); +@@ -3207,6 +3309,16 @@ + DIRED_PUTCHAR ('\n'); + } + break; ++ ++#ifdef WITH_SELINUX ++ case security_format: ++ for (i = 0; i < cwd_n_used; i++) ++ { ++ print_scontext_format (sorted_file[i]); ++ DIRED_PUTCHAR ('\n'); ++ } ++ break; ++#endif + } + } + +@@ -3461,6 +3573,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) +@@ -4405,6 +4526,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\ +@@ -4428,3 +4559,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.9/src/cp.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/cp.c 2007-03-23 11:59:21.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); +@@ -750,6 +762,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; +@@ -777,18 +794,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); + +@@ -824,11 +842,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: +@@ -853,6 +876,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]; +@@ -868,7 +894,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) + { +@@ -879,12 +909,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; +@@ -959,6 +990,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.9/src/Makefile.am.selinux 2007-03-23 11:59:21.000000000 +0000 ++++ coreutils-6.9/src/Makefile.am 2007-03-23 11:59:21.000000000 +0000 +@@ -19,14 +19,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) +@@ -60,9 +60,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) +@@ -71,12 +71,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.9/src/copy.h.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/copy.h 2007-03-23 11:59:21.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-03-23 08:54:03.819414923 +0000 ++++ coreutils-6.9/src/chcon.c 2007-03-23 11:59:21.000000000 +0000 +@@ -0,0 +1,421 @@ ++/* chcontext -- change security context of a pathname */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "system.h" ++#include "error.h" ++#include "savedir.h" ++#include "group-member.h" ++ ++enum Change_status ++{ ++ CH_SUCCEEDED, ++ CH_FAILED, ++ CH_NO_CHANGE_REQUESTED ++}; ++ ++enum Verbosity ++{ ++ /* Print a message for each file that is processed. */ ++ V_high, ++ ++ /* Print a message for each file whose attributes we change. */ ++ V_changes_only, ++ ++ /* Do not be verbose. This is the default. */ ++ V_off ++}; ++ ++static int change_dir_context (const char *dir, const struct stat *statp); ++ ++/* The name the program was run with. */ ++char *program_name; ++ ++/* If nonzero, and the systems has support for it, change the context ++ of symbolic links rather than any files they point to. */ ++static int change_symlinks; ++ ++/* If nonzero, change the context of directories recursively. */ ++static int recurse; ++ ++/* If nonzero, force silence (no error messages). */ ++static int force_silent; ++ ++/* Level of verbosity. */ ++static enum Verbosity verbosity = V_off; ++ ++/* The name of the context file is being given. */ ++static const char *specified_context; ++ ++/* Specific components of the context */ ++static const char *specified_user; ++static const char *specified_role; ++static const char *specified_range; ++static const char *specified_type; ++ ++/* The argument to the --reference option. Use the context of this file. ++ This file must exist. */ ++static char *reference_file; ++ ++/* If nonzero, display usage information and exit. */ ++static int show_help; ++ ++/* If nonzero, print the version on standard output and exit. */ ++static int show_version; ++ ++static struct option const long_options[] = ++{ ++ {"recursive", no_argument, 0, 'R'}, ++ {"changes", no_argument, 0, 'c'}, ++ {"no-dereference", no_argument, 0, 'h'}, ++ {"silent", no_argument, 0, 'f'}, ++ {"quiet", no_argument, 0, 'f'}, ++ {"reference", required_argument, 0, CHAR_MAX + 1}, ++ {"context", required_argument, 0, CHAR_MAX + 2}, ++ {"user", required_argument, 0, 'u'}, ++ {"role", required_argument, 0, 'r'}, ++ {"type", required_argument, 0, 't'}, ++ {"range", required_argument, 0, 'l'}, ++ {"verbose", no_argument, 0, 'v'}, ++ {"help", no_argument, &show_help, 1}, ++ {"version", no_argument, &show_version, 1}, ++ {0, 0, 0, 0} ++}; ++ ++/* Tell the user how/if the context of FILE has been changed. ++ CHANGED describes what (if anything) has happened. */ ++ ++static void ++describe_change (const char *file, security_context_t newcontext, enum Change_status changed) ++{ ++ const char *fmt; ++ switch (changed) ++ { ++ case CH_SUCCEEDED: ++ fmt = _("context of %s changed to %s\n"); ++ break; ++ case CH_FAILED: ++ fmt = _("failed to change context of %s to %s\n"); ++ break; ++ case CH_NO_CHANGE_REQUESTED: ++ fmt = _("context of %s retained as %s\n"); ++ break; ++ default: ++ abort (); ++ } ++ printf (fmt, file, newcontext); ++} ++ ++static int ++compute_context_from_mask (security_context_t context, context_t *ret) ++{ ++ context_t newcontext = context_new (context); ++ if (!newcontext) ++ return 1; ++#define SETCOMPONENT(comp) \ ++ do { \ ++ if (specified_ ## comp) \ ++ if (context_ ## comp ## _set (newcontext, specified_ ## comp)) \ ++ goto lose; \ ++ } while (0) ++ ++ SETCOMPONENT(user); ++ SETCOMPONENT(range); ++ SETCOMPONENT(role); ++ SETCOMPONENT(type); ++#undef SETCOMPONENT ++ ++ *ret = newcontext; ++ return 0; ++ lose: ++ context_free (newcontext); ++ return 1; ++} ++ ++/* Change the context of FILE, using specified components. ++ If it is a directory and -R is given, recurse. ++ Return 0 if successful, 1 if errors occurred. */ ++ ++static int ++change_file_context (const char *file) ++{ ++ struct stat file_stats; ++ security_context_t file_context=NULL; ++ context_t context; ++ security_context_t context_string; ++ int errors = 0; ++ int status = 0; ++ ++ if (change_symlinks) ++ status = lgetfilecon(file, &file_context); ++ else ++ status = getfilecon(file, &file_context); ++ ++ if ((status < 0) && (errno != ENODATA)) ++ { ++ if (force_silent == 0) ++ error (0, errno, "%s", file); ++ return 1; ++ } ++ ++ /* If the file doesn't have a context, and we're not setting all of ++ the context components, there isn't really an obvious default. ++ Thus, we just give up. */ ++ if (file_context == NULL && specified_context == NULL) ++ { ++ error (0, 0, _("can't apply partial context to unlabeled file %s"), file); ++ return 1; ++ } ++ ++ if (specified_context == NULL) ++ { ++ if (compute_context_from_mask (file_context, &context)) ++ { ++ error (0, 0, _("couldn't compute security context from %s"), file_context); ++ return 1; ++ } ++ } ++ else ++ { ++ context = context_new (specified_context); ++ if (!context) ++ error (1, 0,_("invalid context: %s"),specified_context); ++ } ++ ++ context_string = context_str (context); ++ ++ if (file_context == NULL || strcmp(context_string,file_context)!=0) ++ { ++ int fail; ++ ++ if (change_symlinks) ++ fail = lsetfilecon (file, context_string); ++ else ++ fail = setfilecon (file, context_string); ++ ++ if (verbosity == V_high || (verbosity == V_changes_only && !fail)) ++ describe_change (file, context_string, (fail ? CH_FAILED : CH_SUCCEEDED)); ++ ++ if (fail) ++ { ++ errors = 1; ++ if (force_silent == 0) ++ { ++ error (0, errno, _("failed to change context of %s to %s"), file, context_string); ++ } ++ } ++ } ++ else if (verbosity == V_high) ++ { ++ describe_change (file, context_string, CH_NO_CHANGE_REQUESTED); ++ } ++ ++ context_free(context); ++ freecon(file_context); ++ ++ if (recurse) { ++ if (lstat(file, &file_stats)==0) ++ if (S_ISDIR (file_stats.st_mode)) ++ errors |= change_dir_context (file, &file_stats); ++ } ++ return errors; ++} ++ ++/* Recursively change context of the files in directory DIR ++ using specified context components. ++ STATP points to the results of lstat on DIR. ++ Return 0 if successful, 1 if errors occurred. */ ++ ++static int ++change_dir_context (const char *dir, const struct stat *statp) ++{ ++ char *name_space, *namep; ++ char *path; /* Full path of each entry to process. */ ++ unsigned dirlength; /* Length of `dir' and '\0'. */ ++ unsigned filelength; /* Length of each pathname to process. */ ++ unsigned pathlength; /* Bytes allocated for `path'. */ ++ int errors = 0; ++ ++ errno = 0; ++ name_space = savedir (dir); ++ if (name_space == NULL) ++ { ++ if (errno) ++ { ++ if (force_silent == 0) ++ error (0, errno, "%s", dir); ++ return 1; ++ } ++ else ++ error (1, 0, _("virtual memory exhausted")); ++ } ++ ++ dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */ ++ pathlength = dirlength + 1; ++ /* Give `path' a dummy value; it will be reallocated before first use. */ ++ path = xmalloc (pathlength); ++ strcpy (path, dir); ++ path[dirlength - 1] = '/'; ++ ++ for (namep = name_space; *namep; namep += filelength - dirlength) ++ { ++ filelength = dirlength + strlen (namep) + 1; ++ if (filelength > pathlength) ++ { ++ pathlength = filelength * 2; ++ path = xrealloc (path, pathlength); ++ } ++ strcpy (path + dirlength, namep); ++ errors |= change_file_context (path); ++ } ++ free (path); ++ free (name_space); ++ return errors; ++} ++ ++static void ++usage (int status) ++{ ++ if (status != 0) ++ fprintf (stderr, _("Try `%s --help' for more information.\n"), ++ program_name); ++ else ++ { ++ printf (_("\ ++Usage: %s [OPTION]... CONTEXT FILE...\n\ ++ or: %s [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE...\n\ ++ or: %s [OPTION]... --reference=RFILE FILE...\n\ ++"), ++ program_name, program_name, program_name); ++ printf (_("\ ++Change the security context of each FILE to CONTEXT.\n\ ++\n\ ++ -c, --changes like verbose but report only when a change is made\n\ ++ -h, --no-dereference affect symbolic links instead of any referenced file\n\ ++ (available only on systems with lchown system call)\n\ ++ -f, --silent, --quiet suppress most error messages\n\ ++ --reference=RFILE use RFILE's group instead of using a CONTEXT value\n\ ++ -u, --user=USER set user USER in the target security context\n\ ++ -r, --role=ROLE set role ROLE in the target security context\n\ ++ -t, --type=TYPE set type TYPE in the target security context\n\ ++ -l, --range=RANGE set range RANGE in the target security context\n\ ++ -R, --recursive change files and directories recursively\n\ ++ -v, --verbose output a diagnostic for every file processed\n\ ++ --help display this help and exit\n\ ++ --version output version information and exit\n\ ++")); ++ close_stdout (); ++ } ++ exit (status); ++} ++ ++int ++main (int argc, char **argv) ++{ ++ security_context_t ref_context = NULL; ++ int errors = 0; ++ int optc; ++ int component_specified = 0; ++ ++ program_name = argv[0]; ++ setlocale (LC_ALL, ""); ++ bindtextdomain (PACKAGE, LOCALEDIR); ++ textdomain (PACKAGE); ++ ++ recurse = force_silent = 0; ++ ++ while ((optc = getopt_long (argc, argv, "Rcfhvu:r:t:l:", long_options, NULL)) != -1) ++ { ++ switch (optc) ++ { ++ case 0: ++ break; ++ case 'u': ++ specified_user = optarg; ++ component_specified = 1; ++ break; ++ case 'r': ++ specified_role = optarg; ++ component_specified = 1; ++ break; ++ case 't': ++ specified_type = optarg; ++ component_specified = 1; ++ break; ++ case 'l': ++ specified_range = optarg; ++ component_specified = 1; ++ break; ++ case CHAR_MAX + 1: ++ reference_file = optarg; ++ break; ++ case 'R': ++ recurse = 1; ++ break; ++ case 'c': ++ verbosity = V_changes_only; ++ break; ++ case 'f': ++ force_silent = 1; ++ break; ++ case 'h': ++ change_symlinks = 1; ++ break; ++ case 'v': ++ verbosity = V_high; ++ break; ++ default: ++ usage (1); ++ } ++ } ++ ++ if (show_version) ++ { ++ printf ("chcon (%s) %s\n", GNU_PACKAGE, VERSION); ++ close_stdout (); ++ exit (0); ++ } ++ ++ if (show_help) ++ usage (0); ++ ++ ++ if (reference_file && component_specified) ++ { ++ error (0, 0, _("conflicting security context specifiers given")); ++ usage (1); ++ } ++ ++ if (!(((reference_file || component_specified) ++ && (argc - optind > 0)) ++ || (argc - optind > 1))) ++ { ++ error (0, 0, _("too few arguments")); ++ usage (1); ++ } ++ ++ if (reference_file) ++ { ++ if (getfilecon (reference_file, &ref_context)<0) ++ error (1, errno, "%s", reference_file); ++ ++ specified_context = ref_context; ++ } ++ else if (!component_specified) { ++ specified_context = argv[optind++]; ++ } ++ for (; optind < argc; ++optind) ++ errors |= change_file_context (argv[optind]); ++ ++ if (verbosity != V_off) ++ close_stdout (); ++ if (ref_context != NULL) ++ freecon(ref_context); ++ exit (errors); ++} +--- coreutils-6.9/src/mkdir.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/mkdir.c 2007-03-23 11:59:21.000000000 +0000 +@@ -35,11 +35,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'}, + {"parents", no_argument, NULL, 'p'}, + {"verbose", no_argument, NULL, 'v'}, +@@ -61,6 +68,11 @@ + Create the DIRECTORY(ies), if they do not already exist.\n\ + \n\ + "), stdout); ++#ifdef WITH_SELINUX ++ printf (_("\ ++ -Z, --context=CONTEXT (SELinux) set security context to CONTEXT\n\ ++")); ++#endif + fputs (_("\ + Mandatory arguments to long options are mandatory for short options too.\n\ + "), stdout); +@@ -154,7 +166,11 @@ + + atexit (close_stdout); + ++#ifdef WITH_SELINUX ++ while ((optc = getopt_long (argc, argv, "pm:vZ:", longopts, NULL)) != -1) ++#else + while ((optc = getopt_long (argc, argv, "pm:v", longopts, NULL)) != -1) ++#endif + { + switch (optc) + { +@@ -167,6 +183,20 @@ + case 'v': /* --verbose */ + options.created_directory_format = _("created directory %s"); + 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.9/src/stat.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/stat.c 2007-03-23 11:59:21.000000000 +0000 +@@ -55,6 +55,13 @@ + # include + #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" +@@ -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 ++ if(is_selinux_enabled()) { ++ if (getfilecon(filename,&scontext)<0) { ++ if (secure) { ++ perror (filename); ++ return false; ++ } ++ scontext = NULL; ++ } ++ } ++#endif + + 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 (_("\ +@@ -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); + 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; + +@@ -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) + { + switch (c) + { +@@ -954,6 +1038,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; + +@@ -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.9/src/mkfifo.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/mkfifo.c 2007-03-23 11:59:21.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}, +@@ -56,6 +63,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); +@@ -85,13 +97,32 @@ + + atexit (close_stdout); + +- while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) ++ while ((optc = getopt_long (argc, argv, "m:" ++#ifdef WITH_SELINUX ++ "Z:" ++#endif ++ , longopts, NULL)) != -1) + { + 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-6.9/src/mknod.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/mknod.c 2007-03-23 11:59:21.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.9/src/id.c.selinux 2007-03-23 11:59:21.000000000 +0000 ++++ coreutils-6.9/src/id.c 2007-03-23 11:59:21.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'); +@@ -407,4 +464,9 @@ + free (groups); + } + #endif /* HAVE_GETGROUPS */ ++#ifdef WITH_SELINUX ++ if ( context != NULL ) { ++ printf(" context=%s",context); ++ } ++#endif + } +--- coreutils-6.9/src/mv.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/mv.c 2007-03-23 11:59:21.000000000 +0000 +@@ -33,6 +33,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" + +@@ -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 @@ + + 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"); +--- /dev/null 2007-03-23 08:54:03.819414923 +0000 ++++ coreutils-6.9/src/runcon.c 2007-03-23 11:59:21.000000000 +0000 +@@ -0,0 +1,252 @@ ++/* ++ * runcon [ context | ++ * ( [ -c ] [ -r role ] [-t type] [ -u user ] [ -l levelrange ] ) ++ * command [arg1 [arg2 ...] ] ++ * ++ * attempt to run the specified command with the specified context. ++ * ++ * -r role : use the current context with the specified role ++ * -t type : use the current context with the specified type ++ * -u user : use the current context with the specified user ++ * -l level : use the current context with the specified level range ++ * -c : compute process transition context before modifying ++ * ++ * Contexts are interpreted as follows: ++ * ++ * Number of MLS ++ * components system? ++ * ++ * 1 - type ++ * 2 - role:type ++ * 3 Y role:type:range ++ * 3 N user:role:type ++ * 4 Y user:role:type:range ++ * 4 N error ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "system.h" ++extern int errno; ++ ++/* The name the program was run with. */ ++char *program_name; ++ ++/* If nonzero, display usage information and exit. */ ++static int show_help; ++ ++/* If nonzero, print the version on standard output and exit. */ ++static int show_version; ++ ++void ++usage(int status) ++{ ++ printf(_("Usage: %s CONTEXT COMMAND [args]\n" ++ " or: %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n" ++ "Run a program in a different security context.\n\n" ++ " CONTEXT Complete security context\n" ++ " -c, --compute compute process transition context before modifying\n" ++ " -t, --type=TYPE type (for same role as parent)\n" ++ " -u, --user=USER user identity\n" ++ " -r, --role=ROLE role\n" ++ " -l, --range=RANGE levelrange\n" ++ " --help display this help and exit\n" ++ " --version output version information and exit\n"), ++ program_name, program_name); ++ exit(status); ++} ++ ++int ++main(int argc,char **argv,char **envp ) ++{ ++ char *role = 0; ++ char *range = 0; ++ char *user = 0; ++ char *type = 0; ++ char *context = NULL; ++ security_context_t cur_context = NULL; ++ security_context_t file_context = NULL; ++ security_context_t new_context = NULL; ++ int compute_trans = 0; ++ ++ context_t con; ++ ++ program_name = argv[0]; ++ setlocale (LC_ALL, ""); ++ bindtextdomain (PACKAGE, LOCALEDIR); ++ textdomain (PACKAGE); ++ ++ while (1) { ++ int this_option_optind = optind ? optind : 1; ++ int option_index = 0; ++ static struct option long_options[] = { ++ { "role", 1, 0, 'r' }, ++ { "type", 1, 0, 't' }, ++ { "user", 1, 0, 'u' }, ++ { "range", 1, 0, 'l' }, ++ { "compute", 0, 0, 'c' }, ++ { "help", 0, &show_help, 1 }, ++ { "version", 0, &show_version, 1 }, ++ { 0, 0, 0, 0 } ++ }; ++ int c = getopt_long(argc, argv, "+r:t:u:l:c", long_options, &option_index); ++ if ( c == -1 ) { ++ break; ++ } ++ switch ( c ) { ++ case 0: ++ break; ++ case 'r': ++ if ( role ) { ++ fprintf(stderr,_("multiple roles\n")); ++ exit(1); ++ } ++ role = optarg; ++ break; ++ case 't': ++ if ( type ) { ++ fprintf(stderr,_("multiple types\n")); ++ exit(1); ++ } ++ type = optarg; ++ break; ++ case 'u': ++ if ( user ) { ++ fprintf(stderr,_("multiple users\n")); ++ exit(1); ++ } ++ user = optarg; ++ break; ++ case 'l': ++ if ( range ) { ++ fprintf(stderr,_("multiple levelranges\n")); ++ exit(1); ++ } ++ range = optarg; ++ break; ++ case 'c': ++ compute_trans = 1; ++ break; ++ default: ++ usage(1); ++ break; ++ } ++ } ++ ++ if (show_version) { ++ printf("runcon (%s) %s\n", GNU_PACKAGE, VERSION); ++ exit(0); ++ } ++ ++ if (show_help) ++ usage(0); ++ ++ if ( !(user || role || type || range || compute_trans)) { ++ if ( optind >= argc ) { ++ fprintf(stderr,_("must specify -c, -t, -u, -l, -r, or context\n")); ++ usage(1); ++ } ++ context = argv[optind++]; ++ } ++ ++ if ( optind >= argc ) { ++ fprintf(stderr,_("no command found\n")); ++ usage(1); ++ } ++ ++ if( is_selinux_enabled() != 1 ) { ++ fprintf( stderr, ++ _("runcon may be used only on a SELinux kernel.\n") ); ++ exit(-1); ++ } ++ ++ if ( context ) { ++ con = context_new(context); ++ if (!con) { ++ fprintf(stderr,_("%s is not a valid context\n"), context); ++ exit(1); ++ } ++ } ++ else { ++ if (getcon(&cur_context) < 0) { ++ fprintf(stderr,_("Couldn't get current context.\n")); ++ exit(1); ++ } ++ ++ /* We will generate context based on process transition */ ++ if ( compute_trans ) { ++ /* Get context of file to be executed */ ++ if (getfilecon(argv[optind], &file_context) == -1) { ++ fprintf(stderr,_("unable to retrieve attributes of %s\n"), ++ argv[optind]); ++ exit(1); ++ } ++ /* compute result of process transition */ ++ if (security_compute_create(cur_context, file_context, ++ SECCLASS_PROCESS, &new_context) != 0) { ++ fprintf(stderr,_("unable to compute a new context\n")); ++ exit(1); ++ } ++ /* free contexts */ ++ freecon(file_context); ++ freecon(cur_context); ++ ++ /* set cur_context equal to new_context */ ++ cur_context = new_context; ++ } ++ ++ con = context_new(cur_context); ++ if (!con) { ++ fprintf(stderr,_("%s is not a valid context\n"), cur_context); ++ exit(1); ++ } ++ if ( user ) { ++ if ( context_user_set(con,user)) { ++ fprintf(stderr,_("failed to set new user %s\n"),user); ++ exit(1); ++ } ++ } ++ if ( type ) { ++ if ( context_type_set(con,type)) { ++ fprintf(stderr,_("failed to set new type %s\n"),type); ++ exit(1); ++ } ++ } ++ if ( range ) { ++ if ( context_range_set(con,range)) { ++ fprintf(stderr,_("failed to set new range %s\n"),range); ++ exit(1); ++ } ++ } ++ if ( role ) { ++ if (context_role_set(con,role)) { ++ fprintf(stderr,_("failed to set new role %s\n"),role); ++ exit(1); ++ } ++ } ++ } ++ ++ if (security_check_context(context_str(con)) < 0) { ++ fprintf(stderr, _("%s is not a valid context\n"), context_str(con)); ++ exit(1); ++ } ++ ++ if (setexeccon(context_str(con))!=0) { ++ fprintf(stderr,_("unable to setup security context %s\n"), context_str(con)); ++ exit(1); ++ } ++ if (cur_context!=NULL) ++ freecon(cur_context); ++ ++ if ( execvp(argv[optind],argv+optind) ) { ++ perror("execvp"); ++ exit(1); ++ } ++ return 1; /* can't reach this statement.... */ ++} +--- coreutils-6.9/src/copy.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/copy.c 2007-03-23 12:00:30.000000000 +0000 +@@ -54,6 +54,11 @@ + #include "xreadlink.h" + #include "yesno.h" + ++#ifdef WITH_SELINUX ++#include /* for is_selinux_enabled() */ ++extern int selinux_enabled; ++#endif ++ + #ifndef HAVE_FCHOWN + # define HAVE_FCHOWN false + # define fchown(fd, uid, gid) (-1) +@@ -302,6 +307,30 @@ + { + dest_desc = open (dst_name, O_WRONLY | O_TRUNC | O_BINARY); + ++#ifdef WITH_SELINUX ++ if (dest_desc >= 0 && selinux_enabled && ++ (x->preserve_security_context || x->set_security_context)) ++ { ++ security_context_t con; ++ if(getfscreatecon(&con) == -1) ++ { ++ return_val = false; ++ goto close_src_desc; ++ } ++ ++ if (con) ++ { ++ if(fsetfilecon(dest_desc, con) == -1) ++ { ++ return_val = false; ++ freecon(con); ++ goto close_src_desc; ++ } ++ freecon(con); ++ } ++ } ++#endif ++ + if (dest_desc < 0 && x->unlink_dest_after_failed_open) + { + if (unlink (dst_name) != 0) +@@ -1539,6 +1568,32 @@ + In such cases, set this variable to zero. */ + preserve_metadata = true; + ++#ifdef WITH_SELINUX ++ if (x->preserve_security_context && selinux_enabled) ++ { ++ security_context_t con; ++ ++ if (lgetfilecon (src_name, &con) >= 0) ++ { ++ if (setfscreatecon(con) < 0) ++ { ++ error (0, errno, _("cannot set setfscreatecon %s"), quote (con)); ++ if (x->require_preserve) { ++ freecon(con); ++ return 1; ++ } ++ } ++ freecon(con); ++ } ++ else { ++ if (( errno != ENOTSUP ) && ( errno != ENODATA )) { ++ error (0, errno, _("cannot lgetfilecon %s"), quote (src_name)); ++ return 1; ++ } ++ } ++ } ++#endif ++ + if (S_ISDIR (src_mode)) + { + struct dir_list *dir; +@@ -1614,6 +1669,10 @@ + { + /* Here, we are crossing a file system boundary and cp's -x option + is in effect: so don't copy the contents of this directory. */ ++#ifdef WITH_SELINUX ++ if (x->preserve_security_context && selinux_enabled) ++ setfscreatecon(NULL); ++#endif + } + else + { +@@ -1762,6 +1821,11 @@ + } + } + ++#ifdef WITH_SELINUX ++ if (x->preserve_security_context && selinux_enabled) ++ setfscreatecon(NULL); ++#endif ++ + /* There's no need to preserve timestamps or permissions. */ + preserve_metadata = false; + +@@ -1895,6 +1959,11 @@ + + un_backup: + ++#ifdef WITH_SELINUX ++ if (x->preserve_security_context && selinux_enabled) ++ setfscreatecon(NULL); ++#endif ++ + /* 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-6.9/src/install.c.selinux 2007-03-18 21:36:43.000000000 +0000 ++++ coreutils-6.9/src/install.c 2007-03-23 11:59:21.000000000 +0000 +@@ -49,6 +49,43 @@ + # include + #endif + ++#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 +@@ -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'}, + {"no-target-directory", no_argument, NULL, 'T'}, + {"owner", required_argument, NULL, 'o'}, + {"preserve-timestamps", no_argument, NULL, 'p'}, ++#ifdef WITH_SELINUX ++ {"preserve_context", no_argument, NULL, 'P'}, ++#endif + {"strip", no_argument, NULL, 's'}, + {"suffix", required_argument, NULL, 'S'}, + {"target-directory", required_argument, NULL, 't'}, +@@ -169,6 +212,10 @@ + x->stdin_tty = false; + + 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, "bcsDdg:m:o:pPt:TvS:Z:", long_options, ++#else + while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:", long_options, ++#endif + NULL)) != -1) + { + switch (optc) +@@ -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( !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); ++ } ++ break; ++#endif + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: +@@ -503,6 +591,7 @@ + static bool + change_attributes (char const *name) + { ++ bool ok = false; + /* chown must precede chmod because on some systems, + chown clears the set[ug]id bits for non-superusers, + resulting in incorrect permissions. +@@ -521,9 +610,14 @@ + else if (chmod (name, mode) != 0) + error (0, errno, _("cannot change permissions of %s"), quote (name)); + else +- return true; ++ ok = true; ++ ++#ifdef WITH_SELINUX ++ if (use_default_selinux_context) ++ setdefaultfilecon (name); ++#endif + +- return false; ++ return ok; + } + + /* Set the timestamps of file TO to match those of file FROM. +@@ -687,6 +781,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.9/configure.ac.selinux 2007-03-23 11:59:21.000000000 +0000 ++++ coreutils-6.9/configure.ac 2007-03-23 11:59:21.000000000 +0000 +@@ -48,6 +48,13 @@ + LIB_PAM="-ldl -lpam -lpam_misc" + AC_SUBST(LIB_PAM)]) + ++dnl Give the chance to enable SELINUX ++AC_ARG_ENABLE(selinux, dnl ++[ --enable-selinux Enable use of the SELINUX libraries], ++[AC_DEFINE(WITH_SELINUX, 1, [Define if you want to use SELINUX]) ++LIB_SELINUX="-lselinux" ++AC_SUBST(LIB_SELINUX)]) ++ + AC_CHECK_FUNCS(uname, + OPTIONAL_BIN_PROGS="$OPTIONAL_BIN_PROGS uname\$(EXEEXT)" + MAN="$MAN uname.1") +--- coreutils-6.9/man/stat.1.selinux 2007-03-22 21:21:53.000000000 +0000 ++++ coreutils-6.9/man/stat.1 2007-03-23 11:59:21.000000000 +0000 +@@ -28,6 +28,9 @@ + \fB\-t\fR, \fB\-\-terse\fR + print the information in terse form + .TP ++\fB\-Z\fR, \fB\-\-context\fR ++print security context information for SELinux if available. ++.TP + \fB\-\-help\fR + display this help and exit + .TP +@@ -51,6 +54,9 @@ + %d + Device number in decimal + .TP ++%C ++SELinux security context ++.TP + %D + Device number in hex + .TP +--- /dev/null 2007-03-23 08:54:03.819414923 +0000 ++++ coreutils-6.9/man/chcon.x 2007-03-23 11:59:21.000000000 +0000 +@@ -0,0 +1,4 @@ ++[NAME] ++chcon \- change file security context ++[DESCRIPTION] ++.\" Add any additional description here +--- /dev/null 2007-03-23 08:54:03.819414923 +0000 ++++ coreutils-6.9/man/chcon.1 2007-03-23 11:59:21.000000000 +0000 +@@ -0,0 +1,64 @@ ++.TH CHCON 1 "July 2003" "chcon (coreutils) 5.0" "User Commands" ++.SH NAME ++chcon \- change SELinux security context ++.SH SYNOPSIS ++.B chcon ++[\fIOPTION\fR]...\fI CONTEXT FILE\fR... ++.br ++.B chcon ++[\fIOPTION\fR]...\fI --reference=RFILE FILE\fR... ++.SH DESCRIPTION ++.PP ++." Add any additional description here ++.PP ++Change the security context of each FILE to CONTEXT. ++.TP ++\fB\-c\fR, \fB\-\-changes\fR ++like verbose but report only when a change is made ++.TP ++\fB\-h\fR, \fB\-\-no\-dereference\fR ++affect symbolic links instead of any referenced file (available only on systems with lchown system call) ++.TP ++\fB\-f\fR, \fB\-\-silent\fR, \fB\-\-quiet\fR ++suppress most error messages ++.TP ++\fB\-l\fR, \fB\-\-range\fR ++set range RANGE in the target security context ++.TP ++\fB\-\-reference\fR=\fIRFILE\fR ++use RFILE's context instead of using a CONTEXT value ++.TP ++\fB\-R\fR, \fB\-\-recursive\fR ++change files and directories recursively ++.TP ++\fB\-r\fR, \fB\-\-role\fR ++set role ROLE in the target security context ++.TP ++\fB\-t\fR, \fB\-\-type\fR ++set type TYPE in the target security context ++.TP ++\fB\-u\fR, \fB\-\-user\fR ++set user USER in the target security context ++.TP ++\fB\-v\fR, \fB\-\-verbose\fR ++output a diagnostic for every file processed ++.TP ++\fB\-\-help\fR ++display this help and exit ++.TP ++\fB\-\-version\fR ++output version information and exit ++.SH "REPORTING BUGS" ++Report bugs to . ++.SH "SEE ALSO" ++The full documentation for ++.B chcon ++is maintained as a Texinfo manual. If the ++.B info ++and ++.B chcon ++programs are properly installed at your site, the command ++.IP ++.B info chcon ++.PP ++should give you access to the complete manual. +--- coreutils-6.9/man/dir.1.selinux 2007-03-22 21:21:48.000000000 +0000 ++++ coreutils-6.9/man/dir.1 2007-03-23 11:59:21.000000000 +0000 +@@ -205,6 +205,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.9/man/mkfifo.1.selinux 2007-03-22 21:21:51.000000000 +0000 ++++ coreutils-6.9/man/mkfifo.1 2007-03-23 11:59:21.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.9/man/Makefile.am.selinux 2007-03-23 11:59:21.000000000 +0000 ++++ coreutils-6.9/man/Makefile.am 2007-03-23 11:59:21.000000000 +0000 +@@ -29,7 +29,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 + +@@ -141,6 +141,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.9/man/cp.1.selinux 2007-03-22 21:21:47.000000000 +0000 ++++ coreutils-6.9/man/cp.1 2007-03-23 11:59:21.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.9/man/id.1.selinux 2007-03-22 21:21:50.000000000 +0000 ++++ coreutils-6.9/man/id.1 2007-03-23 11:59:21.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-03-23 08:54:03.819414923 +0000 ++++ coreutils-6.9/man/runcon.x 2007-03-23 11:59:21.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-03-23 08:54:03.819414923 +0000 ++++ coreutils-6.9/man/runcon.1 2007-03-23 11:59:21.000000000 +0000 +@@ -0,0 +1,45 @@ ++.TH RUNCON "1" "February 2005" "runcon (coreutils) 5.0" "selinux" ++.SH NAME ++runcon \- run command with specified SELinux 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.9/man/mknod.1.selinux 2007-03-22 21:21:51.000000000 +0000 ++++ coreutils-6.9/man/mknod.1 2007-03-23 11:59:21.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.9/man/ls.1.selinux 2007-03-22 21:21:51.000000000 +0000 ++++ coreutils-6.9/man/ls.1 2007-03-23 11:59:21.000000000 +0000 +@@ -205,6 +205,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.9/man/mkdir.1.selinux 2007-03-22 21:21:51.000000000 +0000 ++++ coreutils-6.9/man/mkdir.1 2007-03-23 11:59:21.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.9/man/vdir.1.selinux 2007-03-22 21:21:55.000000000 +0000 ++++ coreutils-6.9/man/vdir.1 2007-03-23 11:59:21.000000000 +0000 +@@ -205,6 +205,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.9/man/install.1.selinux 2007-03-22 21:21:50.000000000 +0000 ++++ coreutils-6.9/man/install.1 2007-03-23 11:59:21.000000000 +0000 +@@ -67,6 +67,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.9/README.selinux 2007-03-23 11:59:21.000000000 +0000 ++++ coreutils-6.9/README 2007-03-23 11:59:21.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 new file mode 100644 index 0000000..e54535f --- /dev/null +++ b/coreutils-setsid.patch @@ -0,0 +1,96 @@ +--- 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; + ++/* If true, then don't call setsid() with a command. */ ++int same_session = 0; ++ + static struct option const longopts[] = + { + {"command", required_argument, NULL, 'c'}, ++ {"session-command", required_argument, NULL, 'C'}, + {"fast", no_argument, NULL, 'f'}, + {"login", no_argument, NULL, 'l'}, + {"preserve-environment", no_argument, NULL, 'p'}, +@@ -478,6 +482,8 @@ + if (child == 0) { /* child shell */ + change_identity (pw); + pam_end(pamh, 0); ++ if (!same_session) ++ setsid (); + #endif + + if (simulate_login) +@@ -532,13 +538,27 @@ + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + sigemptyset(&ourset); +- if (sigaddset(&ourset, SIGTERM) +- || sigaddset(&ourset, SIGALRM) +- || sigaction(SIGTERM, &action, NULL) +- || sigprocmask(SIG_UNBLOCK, &ourset, NULL)) { ++ if (!same_session) ++ { ++ if (sigaddset(&ourset, SIGINT) || sigaddset(&ourset, SIGQUIT)) ++ { ++ fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME); ++ caught = 1; ++ } ++ } ++ if (!caught && (sigaddset(&ourset, SIGTERM) ++ || sigaddset(&ourset, SIGALRM) ++ || sigaction(SIGTERM, &action, NULL) ++ || sigprocmask(SIG_UNBLOCK, &ourset, NULL))) { + fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME); + caught = 1; + } ++ if (!caught && !same_session && (sigaction(SIGINT, &action, NULL) ++ || sigaction(SIGQUIT, &action, NULL))) ++ { ++ fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME); ++ caught = 1; ++ } + } + if (!caught) { + do { +@@ -609,6 +629,8 @@ + \n\ + -, -l, --login make the shell a login shell\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\ +@@ -631,6 +653,7 @@ + int optc; + const char *new_user = DEFAULT_USER; + char *command = NULL; ++ int request_same_session = 0; + char *shell = NULL; + struct passwd *pw; + struct passwd pw_copy; +@@ -656,6 +679,11 @@ + command = optarg; + break; + ++ case 'C': ++ command = optarg; ++ request_same_session = 1; ++ break; ++ + case 'f': + fast_startup = true; + break; +@@ -725,6 +753,9 @@ + } + #endif + ++ if (request_same_session || !command || !pw->pw_uid) ++ same_session = 1; ++ + if (!shell && !change_environment) + shell = getenv ("SHELL"); + if (shell && getuid () != 0 && restricted_shell (pw->pw_shell)) diff --git a/coreutils-split-pam.patch b/coreutils-split-pam.patch new file mode 100644 index 0000000..f8596b4 --- /dev/null +++ b/coreutils-split-pam.patch @@ -0,0 +1,57 @@ +diff -uNrp -x '*~' coreutils-5.97-orig/src/su.c coreutils-5.97/src/su.c +--- coreutils-5.97-orig/src/su.c 2006-07-13 12:14:40.000000000 +0100 ++++ coreutils-5.97/src/su.c 2006-07-13 12:24:33.000000000 +0100 +@@ -131,11 +131,15 @@ + + #include "error.h" + +-/* The official name of this program (e.g., no `g' prefix). */ ++/* The official name of this program (e.g., no `g' prefix). ++ * - Add a "-l" to the name passed to PAM if this is a login simulation ++ */ + #ifndef RUNUSER + #define PROGRAM_NAME "su" ++#define PROGRAM_NAME_L "su-l" + #else + #define PROGRAM_NAME "runuser" ++#define PROGRAM_NAME_L "runuser-l" + #endif + + #ifndef AUTHORS +@@ -310,7 +314,8 @@ correct_password (const struct passwd *p + #ifdef USE_PAM + struct passwd *caller; + char *tty_name, *ttyn; +- retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh); ++ retval = pam_start(simulate_login ? PROGRAM_NAME_L : PROGRAM_NAME, ++ pw->pw_name, &conv, &pamh); + PAM_BAIL_P; + + #ifndef RUNUSER +diff -urp coreutils-6.9-orig/doc/coreutils.info coreutils-6.10/doc/coreutils.info +--- coreutils-6.9-orig/doc/coreutils.info ++++ coreutils-6.9/doc/coreutils.info +@@ -11006,7 +11006,8 @@ options::. + set, even for the super-user, as described above), and set `PATH' + to a compiled-in default value. Change to USER's home directory. + Prepend `-' to the shell's name, intended to make it read its +- login startup file(s). ++ login startup file(s). When this option is given, /etc/pam.d/su-l ++ PAM file is used instead of the default one. + + `-m' + `-p' +diff -urp coreutils-6.10-orig/doc/coreutils.texi coreutils-6.10/doc/coreutils.texi +--- coreutils-6.9-orig/doc/coreutils.texi ++++ coreutils-6.9/doc/coreutils.texi +@@ -13670,7 +13670,9 @@ the exit status of @var{command} otherwi + + @command{su} allows one user to temporarily become another user. It runs a + command (often an interactive shell) with the real and effective user +-ID, group ID, and supplemental groups of a given @var{user}. Synopsis: ++ID, group ID, and supplemental groups of a given @var{user}. When the -l ++option is given, the su-l PAM file is used instead of the default su PAM file. ++Synopsis: + + @example + su [@var{option}]@dots{} [@var{user} [@var{arg}]@dots{}] diff --git a/coreutils-su-l.pamd b/coreutils-su-l.pamd new file mode 100644 index 0000000..656a139 --- /dev/null +++ b/coreutils-su-l.pamd @@ -0,0 +1,6 @@ +#%PAM-1.0 +auth include su +account include su +password include su +session optional pam_keyinit.so force revoke +session include su diff --git a/coreutils-su.pamd b/coreutils-su.pamd new file mode 100644 index 0000000..85e67a8 --- /dev/null +++ b/coreutils-su.pamd @@ -0,0 +1,12 @@ +#%PAM-1.0 +auth sufficient pam_rootok.so +# Uncomment the following line to implicitly trust users in the "wheel" group. +#auth sufficient pam_wheel.so trust use_uid +# Uncomment the following line to require a user to be in the "wheel" group. +#auth required pam_wheel.so use_uid +auth include system-auth +account sufficient pam_succeed_if.so uid = 0 use_uid quiet +account include system-auth +password include system-auth +session include system-auth +session optional pam_xauth.so diff --git a/coreutils.spec b/coreutils.spec index 6712263..ddcb85c 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,1758 +1,342 @@ -Summary: A set of basic GNU tools commonly used in shell scripts +Summary: The GNU core utilities: a set of tools commonly used in shell scripts Name: coreutils -Version: 9.9 -Release: 2%{?dist} -# some used parts of gnulib are under various variants of LGPL -License: GPL-3.0-or-later AND GFDL-1.3-no-invariants-or-later AND LGPL-2.1-or-later AND LGPL-3.0-or-later -Url: https://www.gnu.org/software/coreutils/ -Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz -Source1: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz.sig -# From https://savannah.gnu.org/project/release-gpgkeys.php?group=coreutils&download=1 -# which is linked as project keyring on https://savannah.gnu.org/projects/coreutils -Source2: coreutils-keyring.gpg -Source50: supported_utils +Version: 6.9 +Release: 9%{?dist} +License: GPLv2+ +Group: System Environment/Base +Url: http://www.gnu.org/software/coreutils/ +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Source0: ftp://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.bz2 +Source101: coreutils-DIR_COLORS +Source102: coreutils-DIR_COLORS.xterm Source105: coreutils-colorls.sh Source106: coreutils-colorls.csh +Source200: coreutils-su.pamd +Source201: coreutils-runuser.pamd +Source202: coreutils-su-l.pamd +Source203: coreutils-runuser-l.pamd -# do not make coreutils-single depend on /usr/bin/coreutils -%global __requires_exclude ^%{_bindir}/coreutils$ +# From upstream +Patch1: coreutils-futimens.patch +Patch2: coreutils-ls-x.patch +Patch3: coreutils-6.9-cp-i-u.patch +Patch4: coreutils-6.9-du-ls-upstream.patch +Patch5: coreutils-dddoubleclose.patch +Patch6: coreutils-mvatomic.patch -# disable the test-lock gnulib test prone to deadlock -Patch100: coreutils-8.26-test-lock.patch +# Our patches +Patch100: coreutils-chgrp.patch +Patch101: coreutils-getdateYYYYMMDD.patch +#Patch102: coreutils-6.9-longoptions.patch -# require_selinux_(): use selinuxenabled(8) if available -Patch101: coreutils-8.26-selinuxenable.patch +# sh-utils +Patch703: sh-utils-2.0.11-dateman.patch +Patch704: sh-utils-1.16-paths.patch +# RMS will never accept the PAM patch because it removes his historical +# rant about Twenex and the wheel group, so we'll continue to maintain +# it here indefinitely. +Patch706: coreutils-pam.patch +Patch713: coreutils-4.5.3-langinfo.patch +Patch715: coreutils-4.5.3-sysinfo.patch -# downstream changes to default DIR_COLORS -Patch102: coreutils-8.32-DIR_COLORS.patch - -# use python3 in tests -Patch103: coreutils-python3.patch - -# df --direct -Patch104: coreutils-df-direct.patch - -# gnulib C23 support -# https://github.com/coreutils/gnulib/commit/df17f4f37ed3ca373d23ad42eae51122bdb96626 -Patch105: coreutils-9.9-gnulib-c23.patch - -# fix cut test failure on aarch64 rawhide (rhbz#2424302) -# https://github.com/coreutils/coreutils/commit/95044cb5eaea83d02f768feb5ab79fcf5e6ad782 -Patch106: coreutils-9.9-fix-cut-test-aarch64.patch - -# (sb) lin18nux/lsb compliance - multibyte functionality patch +# (sb) lin18nux/lsb compliance Patch800: coreutils-i18n.patch -Conflicts: filesystem < 3 +Patch900: coreutils-setsid.patch +Patch907: coreutils-5.2.1-runuser.patch +Patch908: coreutils-getgrouplist.patch +Patch912: coreutils-overflow.patch +Patch915: coreutils-split-pam.patch +Patch916: coreutils-getfacl-exit-code.patch -# To avoid clobbering installs -Conflicts: coreutils-single +#SELINUX Patch +Patch950: coreutils-selinux.patch +#SELINUX Patch fix to allow cp -a rewrite file on different filesystem +Patch951: coreutils-6.9-requiresecuritycontext.patch +Patch952: coreutils-6.9-statsecuritycontext.patch -BuildRequires: attr -BuildRequires: autoconf -BuildRequires: automake -BuildRequires: gcc -BuildRequires: gettext-devel -BuildRequires: gmp-devel -BuildRequires: hostname + +BuildRequires: libselinux-devel >= 1.25.6-1 BuildRequires: libacl-devel -BuildRequires: libattr-devel -BuildRequires: libcap-devel -BuildRequires: libselinux-devel -BuildRequires: libselinux-utils -BuildRequires: make -BuildRequires: openssl-devel -BuildRequires: strace -BuildRequires: systemd-devel -BuildRequires: texinfo +BuildRequires: gettext bison +BuildRequires: texinfo >= 4.3 +BuildRequires: autoconf >= 2.58, automake >= 1.8 +%{?!nopam:BuildRequires: pam-devel} -# For gpg verification of source tarball -BuildRequires: gnupg2 +Requires(post): libselinux >= 1.25.6-1 +Requires(pre): /sbin/install-info +Requires(preun): /sbin/install-info +Requires(post): /sbin/install-info +Requires(post): grep +%{?!nopam:Requires: pam >= 0.66-12} -# test-only dependencies -BuildRequires: acl -BuildRequires: gdb -BuildRequires: perl-interpreter -BuildRequires: perl(FileHandle) -BuildRequires: python3 -BuildRequires: tzdata -%ifarch %valgrind_arches -BuildRequires: valgrind -%endif +# Require a C library that doesn't put LC_TIME files in our way. +Conflicts: glibc < 2.2 -%if 0%{?fedora} -BuildRequires: perl(Expect) -BuildRequires: python3-inotify -%endif +Provides: fileutils = %{version}-%{release} +Provides: sh-utils = %{version}-%{release} +Provides: stat = %{version}-%{release} +Provides: textutils = %{version}-%{release} +Obsoletes: fileutils <= 4.1.9 +Obsoletes: sh-utils <= 2.0.12 +Obsoletes: stat <= 3.3 +Obsoletes: textutils <= 2.0.21 -%if 23 < 0%{?fedora} || 7 < 0%{?rhel} -# needed by i18n test-cases -BuildRequires: glibc-langpack-en -BuildRequires: glibc-langpack-fr -BuildRequires: glibc-langpack-ko -BuildRequires: glibc-langpack-sv -%endif - -Requires: %{name}-common = %{version}-%{release} - -Provides: coreutils-full = %{version}-%{release} -Provides: bundled(gnulib) -Obsoletes: %{name} < 8.24-100 +# readlink(1) moved here from tetex. +Conflicts: tetex < 1.0.7-66 %description These are the GNU core utilities. This package is the combination of the old GNU fileutils, sh-utils, and textutils packages. -%package single -Summary: coreutils multicall binary -Suggests: coreutils-common -Provides: coreutils = %{version}-%{release} -Provides: coreutils%{?_isa} = %{version}-%{release} -Provides: bundled(gnulib) -# To avoid clobbering installs -Conflicts: coreutils < 8.24-100 -# Note RPM doesn't support separate buildroots for %files -# http://rpm.org/ticket/874 so use RemovePathPostfixes -# (new in rpm 4.13) to support separate file sets. -RemovePathPostfixes: .single -%description single -These are the GNU core utilities, -packaged as a single multicall binary. - - -%package common -# yum obsoleting rules explained at: -# https://bugzilla.redhat.com/show_bug.cgi?id=1107973#c7 -Obsoletes: %{name} < 8.24-100 - -# Gnulib translations are maintained seprately since coreutils 9.6 (#2393892) -Requires: gnulib-l10n - -# info doc refers to "Specifying the Time Zone" from glibc-doc (#959597) -Suggests: glibc-doc - -Summary: coreutils common optional components -%description common -Optional though recommended components, -including documentation and translations. - %prep -%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' -%autosetup -N +%setup -q -# will be regenerated in the build directories -rm -f src/fs.h +# From upstream +%patch1 -p1 -b .futimens +%patch2 -p1 -b .ls-x +%patch3 -p1 -b .cp-i-u +%patch4 -p1 -b .du-ls +%patch5 -p1 -b .doubleclose +%patch6 -p1 -b .mvatomic -# will be further modified by coreutils-8.32-DIR_COLORS.patch -sed src/dircolors.hin \ - -e 's| 00;36$| 01;36|' \ - > DIR_COLORS -sed src/dircolors.hin \ - -e 's| 01;31$| 00;31|' \ - -e 's| 01;35$| 00;35|' \ - > DIR_COLORS.lightbgcolor +# Our patches +%patch100 -p1 -b .chgrp +%patch101 -p1 -b .getdate +#%patch102 -p1 -b .longopts -# git add DIR_COLORS{,.lightbgcolor} -# git commit -m "clone DIR_COLORS before patching" +# sh-utils +%patch703 -p1 -b .dateman +%patch704 -p1 -b .paths +%patch706 -p1 -b .pam +%patch713 -p1 -b .langinfo +%patch715 -p1 -b .sysinfo -# apply all patches -%autopatch -p1 +# li18nux/lsb +%patch800 -p1 -b .i18n -(echo ">>> Fixing permissions on tests") 2>/dev/null -find tests -name '*.sh' -perm 0644 -print -exec chmod 0755 '{}' '+' -(echo "<<< done") 2>/dev/null +# Coreutils +%patch900 -p1 -b .setsid +%patch907 -p1 -b .runuser +%patch908 -p1 -b .getgrouplist +%patch912 -p1 -b .overflow +%patch915 -p1 -b .splitl +%patch916 -p1 -b .getfacl-exit-code -# FIXME: Force a newer gettext version to workaround `autoreconf -i` errors -# with coreutils 9.6 and bundled gettext 0.19.2 from gettext-common-devel. -sed -i "s/0.19.2/$(rpm -q --queryformat '%%{VERSION}\n' gettext-devel)/" bootstrap.conf configure.ac +#SELinux +%patch950 -p1 -b .selinux +%patch951 -p1 -b .require-preserve +%patch952 -p1 -b .statsecuritycontext -autoreconf -fiv +# Don't run basic-1 test, since it breaks when run in the background +# (bug #102033). +sed -i -e 's/basic-1//g' tests/stty/Makefile* + +chmod a+x tests/sort/sort-mb-tests +chmod a+x tests/ls/x-option +chmod a+x tests/mv/atomic2 %build -export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing -fpic" - -# Upstream suggests to build with -Dlint for static analyzers: -# https://lists.gnu.org/archive/html/coreutils/2018-06/msg00110.html -# ... and even for production binary RPMs: -# https://lists.gnu.org/archive/html/bug-gnulib/2020-05/msg00130.html -# There is currently no measurable performance drop or other known downside. -CFLAGS="$CFLAGS -Dlint" - -# make mknod work again in chroot without /proc being mounted (#1811038) -export ac_cv_func_lchmod="no" - -# needed for out-of-tree build -%global _configure ../configure - +%ifarch s390 s390x +# Build at -O1 for the moment (bug #196369). +export CFLAGS="$RPM_OPT_FLAGS -fPIC -O1" +%else +export CFLAGS="$RPM_OPT_FLAGS -fpic" +%endif %{expand:%%global optflags %{optflags} -D_GNU_SOURCE=1} -for type in separate single; do - mkdir -p $type && \ - (cd $type || exit $? - if test $type = 'single'; then - config_single='--enable-single-binary' - config_single="$config_single --without-openssl" # smaller/slower sha*sum - config_single="$config_single --without-libgmp" # expr/factor machine ints - else - config_single='--with-openssl' # faster sha*sum - fi - %configure $config_single \ - --cache-file=../config.cache \ - --enable-install-program=arch \ - --enable-no-install-program=kill,uptime \ - --enable-systemd \ - --with-tty-group \ - DEFAULT_POSIX2_VERSION=200112 alternative=199209 || : - %make_build all V=1 +touch aclocal.m4 configure config.hin Makefile.in */Makefile.in */*/Makefile.in +aclocal -I m4 +autoconf --force +automake --copy --add-missing +%configure --enable-largefile --with-afs %{?!nopam:--enable-pam} \ + --enable-selinux \ + DEFAULT_POSIX2_VERSION=200112 alternative=199209 || : +make all %{?_smp_mflags} \ + %{?!nopam:CPPFLAGS="-DUSE_PAM"} \ + su_LDFLAGS="-pie %{?!nopam:-lpam -lpam_misc}" - # make sure that parse-datetime.{c,y} ends up in debuginfo (#1555079) - ln -fv ../lib/parse-datetime.{c,y} . - ) -done - -# Get the list of supported utilities -cp %SOURCE50 . +# XXX docs should say /var/run/[uw]tmp not /etc/[uw]tmp +sed -i -e 's,/etc/utmp,/var/run/utmp,g;s,/etc/wtmp,/var/run/wtmp,g' doc/coreutils.texi %check -for type in separate single; do - test $type = 'single' && subdirs='SUBDIRS=.' # Only check gnulib once - (cd $type && make check %{?_smp_mflags} $subdirs) -done +make check %install -for type in separate single; do - install=install - if test $type = 'single'; then - subdir=%{_libexecdir}/%{name}; install=install-exec - fi - (cd $type && make DESTDIR=$RPM_BUILD_ROOT/$subdir $install) +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install -%if "%{_sbindir}" != "%{_bindir}" - # chroot was in /usr/sbin : - mkdir -p $RPM_BUILD_ROOT/$subdir/%_sbindir - mv $RPM_BUILD_ROOT/$subdir/{%_bindir,%_sbindir}/chroot -%endif +# man pages are not installed with make install +make mandir=$RPM_BUILD_ROOT%{_mandir} install-man - # Move multicall variants to *.single. - # RemovePathPostfixes will strip that later. - if test $type = 'single'; then - for dir in %{_bindir} \ -%if "%{_sbindir}" != "%{_bindir}" -%{_sbindir} \ -%endif -%{_libexecdir}/%{name}; do - for bin in $RPM_BUILD_ROOT/%{_libexecdir}/%{name}/$dir/*; do - basebin=$(basename $bin) - mv $bin $RPM_BUILD_ROOT/$dir/$basebin.single - done - done - fi +# fix japanese catalog file +if [ -d $RPM_BUILD_ROOT%{_datadir}/locale/ja_JP.EUC/LC_MESSAGES ]; then + mkdir -p $RPM_BUILD_ROOT%{_datadir}/locale/ja/LC_MESSAGES + mv $RPM_BUILD_ROOT%{_datadir}/locale/ja_JP.EUC/LC_MESSAGES/*mo \ + $RPM_BUILD_ROOT%{_datadir}/locale/ja/LC_MESSAGES + rm -rf $RPM_BUILD_ROOT%{_datadir}/locale/ja_JP.EUC +fi + +bzip2 -9f ChangeLog + +# let be compatible with old fileutils, sh-utils and textutils packages : +mkdir -p $RPM_BUILD_ROOT{/bin,%_bindir,%_sbindir,/sbin} +%{?!nopam:mkdir -p $RPM_BUILD_ROOT%_sysconfdir/pam.d} +for f in basename cat chgrp chmod chown cp cut date dd df echo env false link ln ls mkdir mknod mv nice pwd rm rmdir sleep sort stty sync touch true uname unlink +do + mv $RPM_BUILD_ROOT{%_bindir,/bin}/$f done +# chroot was in /usr/sbin : +mv $RPM_BUILD_ROOT{%_bindir,%_sbindir}/chroot +# {cat,sort,cut} were previously moved from bin to /usr/bin and linked into +for i in env cut; do ln -sf ../../bin/$i $RPM_BUILD_ROOT/usr/bin; done + mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/profile.d -install -p -c -m644 DIR_COLORS{,.lightbgcolor} $RPM_BUILD_ROOT%{_sysconfdir} +install -p -c -m644 %SOURCE101 $RPM_BUILD_ROOT%{_sysconfdir}/DIR_COLORS +install -p -c -m644 %SOURCE102 $RPM_BUILD_ROOT%{_sysconfdir}/DIR_COLORS.xterm install -p -c -m644 %SOURCE105 $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/colorls.sh install -p -c -m644 %SOURCE106 $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/colorls.csh +# su +install -m 4755 src/su $RPM_BUILD_ROOT/bin +install -m 755 src/runuser $RPM_BUILD_ROOT/sbin + +# These come from util-linux and/or procps. +for i in hostname uptime kill ; do + rm $RPM_BUILD_ROOT{%_bindir/$i,%_mandir/man1/$i.1} +done + +%{?!nopam:install -p -m 644 %SOURCE200 $RPM_BUILD_ROOT%_sysconfdir/pam.d/su} +%{?!nopam:install -p -m 644 %SOURCE202 $RPM_BUILD_ROOT%_sysconfdir/pam.d/su-l} +%{?!nopam:install -p -m 644 %SOURCE201 $RPM_BUILD_ROOT%_sysconfdir/pam.d/runuser} +%{?!nopam:install -p -m 644 %SOURCE203 $RPM_BUILD_ROOT%_sysconfdir/pam.d/runuser-l} + +# Compress ChangeLogs from before the fileutils/textutils/etc merge +bzip2 -f9 old/*/C* + %find_lang %name -# Add the %%lang(xyz) ownership for the LC_TIME dirs as well... -grep LC_TIME %name.lang | cut -d'/' -f1-6 | sed -e 's/) /) %%dir /g' >>%name.lang # (sb) Deal with Installed (but unpackaged) file(s) found rm -f $RPM_BUILD_ROOT%{_infodir}/dir -%files -f supported_utils -%exclude %{_bindir}/*.single -%dir %{_libexecdir}/coreutils -%{_libexecdir}/coreutils/*.so +%clean +rm -rf $RPM_BUILD_ROOT -%files single -%{_bindir}/*.single -%if "%{_sbindir}" != "%{_bindir}" -%{_sbindir}/chroot.single -%endif -%dir %{_libexecdir}/coreutils -%{_libexecdir}/coreutils/*.so.single -# duplicate the license because coreutils-common does not need to be installed -%{!?_licensedir:%global license %%doc} -%license COPYING +%pre +# We must deinstall these info files since they're merged in +# coreutils.info. else their postun'll be run too late +# and install-info will fail badly because of duplicates +for file in sh-utils textutils fileutils; do + /sbin/install-info --delete %{_infodir}/$file.info --dir=%{_infodir}/dir &> /dev/null || : +done -%files common -f %{name}.lang +%preun +if [ $1 = 0 ]; then + /sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || : +fi + +%post +/bin/grep -v '(sh-utils)\|(fileutils)\|(textutils)' %{_infodir}/dir > \ + %{_infodir}/dir.rpmmodify || exit 0 + /bin/mv -f %{_infodir}/dir.rpmmodify %{_infodir}/dir +/sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || : + +%files -f %{name}.lang +%defattr(-,root,root,-) +%dir %{_datadir}/locale/*/LC_TIME %config(noreplace) %{_sysconfdir}/DIR_COLORS* -%config(noreplace) %{_sysconfdir}/profile.d/* -%{_infodir}/coreutils* -%{_mandir}/man*/* -# The following go to /usr/share/doc/coreutils-common -%doc ABOUT-NLS NEWS README THANKS TODO -%license COPYING +%{_sysconfdir}/profile.d/* +%{?!nopam:%config(noreplace) %{_sysconfdir}/pam.d/su} +%{?!nopam:%config(noreplace) %{_sysconfdir}/pam.d/su-l} +%{?!nopam:%config(noreplace) %{_sysconfdir}/pam.d/runuser} +%{?!nopam:%config(noreplace) %{_sysconfdir}/pam.d/runuser-l} +%doc COPYING ABOUT-NLS ChangeLog.bz2 NEWS README THANKS TODO old/* +/bin/basename +/bin/cat +/bin/chgrp +/bin/chmod +/bin/chown +/bin/cp +/bin/cut +/bin/date +/bin/dd +/bin/df +/bin/echo +/bin/env +/bin/false +/bin/link +/bin/ln +/bin/ls +/bin/mkdir +/bin/mknod +/bin/mv +/bin/nice +/bin/pwd +/bin/rm +/bin/rmdir +/bin/sleep +/bin/sort +/bin/stty +%attr(4755,root,root) /bin/su +/bin/sync +/bin/touch +/bin/true +/bin/uname +/bin/unlink +%_bindir/* +%_infodir/coreutils* +%_mandir/man*/* +%_sbindir/chroot +/sbin/runuser %changelog -* Tue Jan 13 2026 Lukáš Zaoral - 9.9-2 -- fix cut test failure on aarch64 rawhide (rhbz#2424302) - -* Wed Nov 26 2025 Lukáš Zaoral - 9.9-1 -- rebase to latest upstream release (rhbz#2413803) - -* Mon Sep 29 2025 Lukáš Zaoral - 9.8-3 -- require gnulib-l10n for translations of gnulib messages (rhbz#2393892) - -* Thu Sep 25 2025 Lukáš Zaoral - 9.8-2 -- tail: fix tailing larger number of lines in regular files (rhbz#2398008) - -* Wed Sep 24 2025 Lukáš Zaoral - 9.8-1 -- rebase to latest upstream release (rhbz#2397467) -- remove downstream patch for selinux options deprecated since 2009 - -* Wed Jul 23 2025 Fedora Release Engineering - 9.7-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Mon Jun 30 2025 Lukáš Zaoral - 9.7-4 -- stty: add support for arbitrary baud rates (rhbz#2375439) - -* Wed May 28 2025 Lukáš Zaoral - 9.7-3 -- sort: fix buffer under-read (CVE-2025-5278) - -* Mon May 19 2025 Lukáš Zaoral - 9.7-2 -- cp/mv: do not fail when copying of trivial NFSv4 ACLs fails (rhbz#2363149) - -* Wed Apr 09 2025 Lukáš Zaoral - 9.7-1 -- rebase to latest upstream release (rhbz#2358624) - -* Tue Feb 25 2025 Lukáš Zaoral - 9.6-2 -- fix 'who -m' with guessed tty names (rhbz#2343998) - -* Mon Jan 20 2025 Lukáš Zaoral - 9.6-1 -- rebase to latest upstream version (rhbz#2338620) -- sync i18n patch with SUSE (Kudos to Berny Völker!) - -* Thu Jan 16 2025 Fedora Release Engineering - 9.5-13 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Sun Jan 12 2025 Zbigniew Jędrzejewski-Szmek - 9.5-12 -- Rebuilt for the bin-sbin merge (2nd attempt) - -* Wed Nov 13 2024 Florian Weimer - 9.5-11 -- Affinity mask handling in nproc for large CPU counts (rhbz#2325167) - -* Fri Sep 27 2024 Lukáš Zaoral - 9.5-10 -- fix fold -b with UTF8 locale (RHEL-60295) - -* Tue Aug 27 2024 Lukáš Zaoral - 9.5-9 -- show web sessions in who output (rhbz#2307847) - -* Wed Aug 21 2024 Lukáš Zaoral - 9.5-8 -- add missing systemd-devel buildrequires - -* Wed Jul 17 2024 Fedora Release Engineering - 9.5-7 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - -* Mon Jul 15 2024 Lukáš Zaoral - 9.5-6 -- Rebuilt for the bin-sbin merge - -* Mon Jul 15 2024 Sohum Mendon - 9.5-5 -- fix incorrect exit status when fold is called with a non-existent file - -* Tue Jul 09 2024 Zbigniew Jędrzejewski-Szmek - 9.5-4 -- Rebuilt for the bin-sbin merge - -* Thu Jul 04 2024 Lukáš Zaoral - 9.5-3 -- do not buildrequire perl(Expect) on ELN - -* Tue Jun 04 2024 Lukáš Zaoral - 9.5-2 -- enable LTO on ppc64le - -* Tue Apr 02 2024 Lukáš Zaoral - 9.5-1 -- rebase to latest upstream version (rhbz#2272063) -- sync i18n patch with SUSE (Kudos to Berny Völker!) -- add some test dependencies to execute additional part of the upstream test-suite - -* Mon Jan 29 2024 Lukáš Zaoral - 9.4-6 -- fix tail on kernels with 64k page sizes (RHEL-22866) - -* Wed Jan 24 2024 Fedora Release Engineering - 9.4-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Fri Jan 19 2024 Fedora Release Engineering - 9.4-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Thu Jan 18 2024 Lukáš Zaoral - 9.4-3 -- fix compilation on i686 - -* Thu Jan 18 2024 Lukáš Zaoral - 9.4-2 -- fix buffer overflow in split (CVE-2024-0684) - -* Fri Sep 15 2023 Lukáš Zaoral - 9.4-1 -- new upstream release 9.4 (#2235759) -- enable integration with systemd -- fix the license field - -* Wed Jul 19 2023 Fedora Release Engineering - 9.3-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild - -* Tue Apr 18 2023 Kamil Dudka - 9.3-1 -- remove obsolete Provides for absolute paths -- new upstream release 9.3 - -* Tue Apr 11 2023 Lukáš Zaoral - 9.2-4 -- migrate to SPDX license format - -* Fri Mar 24 2023 Kamil Dudka - 9.2-3 -- copy: fix --reflink=auto to fallback in more cases (#2180056) -- cksum: fix reporting of failed checks (#2180056) - -* Wed Mar 22 2023 Kamil Dudka - 9.2-2 -- coreutils-getgrouplist.patch: drop a patch no longer needed - -* Wed Mar 22 2023 Kamil Dudka - 9.2-1 -- new upstream release 9.2 - -* Thu Jan 19 2023 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild - -* Mon Jan 02 2023 Kamil Dudka - 9.1-10 -- drop obsolete downstream-only extension of date(1) man page -- undocument downstream SELinux options deprecated since 2009 - -* Mon Jan 02 2023 Kamil Dudka - 9.1-9 -- basic support for checking NFSv4 ACLs (#2137866) - -* Mon Sep 19 2022 Kamil Dudka - 9.1-8 -- remove obsolete extension of mkdir(1) info documentation - -* Tue Aug 23 2022 Kamil Dudka - 9.1-7 -- remove non-upstream patch for uname -i/-p (#548834) - -* Mon Aug 08 2022 Kamil Dudka - 9.1-6 -- improve wording of a comment in /etc/DIR_COLORS (#2112593) - -* Mon Aug 08 2022 Kamil Dudka - 9.1-5 -- improve handling of control characters in unexpand (#2112870) - -* Mon Aug 01 2022 Kamil Dudka - 9.1-4 -- prevent unexpand from failing on control characters (#2112870) - -* Wed Jul 20 2022 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild - -* Sat Apr 23 2022 Pádraig Brady - 9.1-2 -- make simple backups in correct dir; broken in 9.1 - -* Tue Apr 19 2022 Kamil Dudka - 9.1-1 -- new upstream release 9.1 - -* Mon Mar 21 2022 Kamil Dudka - 9.0-5 -- ls, stat: avoid triggering automounts (#2044981) - -* Tue Mar 01 2022 Kamil Dudka - 9.0-4 -- make `df --direct` work again (#2058686) - -* Wed Jan 19 2022 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild - -* Mon Oct 04 2021 Kamil Dudka - 9.0-2 -- chmod: fix exit status when ignoring symlinks - -* Sun Sep 26 2021 Kamil Dudka - 9.0-1 -- new upstream release 9.0 - -* Tue Sep 14 2021 Sahana Prasad -- Rebuilt with OpenSSL 3.0.0 - -* Wed Jul 21 2021 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild - -* Wed Jul 07 2021 Kamil Dudka - 8.32-30 -- df: fix duplicated remote entries due to bind mounts (#1979814) - -* Thu Jul 01 2021 Kamil Dudka - 8.32-28 -- tail: fix stack out-of-bounds write with --follow - -* Tue Jun 08 2021 Kamil Dudka - 8.32-27 -- mountlist: recognize fuse.portal as dummy file system (#1913358) - -* Mon May 17 2021 Kamil Dudka - 8.32-26 -- cp: pick additional copy_file_range()-related fixes from upstream - -* Mon May 03 2021 Kamil Dudka - 8.32-24 -- copy: ensure we enforce --reflink=never (#1956080) - -* Tue Apr 27 2021 Kamil Dudka - 8.32-23 -- copy: do not refuse to copy a swap file - -* Fri Apr 09 2021 Kamil Dudka - 8.32-22 -- weaken the dependency on glibc-doc to reduce minimal installations -- drop the last use of ncurses no longer needed (#1830318) -- utimens: fix confusing arg type in internal func - -* Fri Mar 26 2021 Kamil Dudka - 8.32-21 -- hostname,ln: fix memory leaks detected by Coverity - -* Wed Mar 24 2021 Kamil Dudka - 8.32-20 -- cp: use copy_file_range if available - -* Thu Feb 18 2021 Kamil Dudka - 8.32-19 -- stat: add support for the exfat file system (#1921427) - -* Wed Feb 03 2021 Kamil Dudka - 8.32-18 -- make coreutils-common recommend glibc-doc for info doc refs (#959597) - -* Tue Feb 02 2021 Kamil Dudka - 8.32-17 -- ls: fix crash printing SELinux context for unstatable files (#1921249) -- split: fix --number=K/N to output correct part of file (#1921246) -- expr: fix invalid read with unmatched \(...\) (#1919775) - -* Tue Jan 26 2021 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild - -* Tue Dec 08 2020 Kamil Dudka - 8.32-15 -- rm: do not skip files upon failure to remove an empty dir (#1905481) - -* Tue Nov 03 2020 Kamil Dudka - 8.32-14 -- df,stat,tail: recognize more file system types - -* Wed Oct 14 2020 Kamil Dudka - 8.32-13 -- make the %%build section idempotent - -* Mon Aug 17 2020 Kamil Dudka - 8.32-12 -- do not install /etc/DIR_COLORS.256color (#1830318) - -* Thu Jul 30 2020 Kamil Dudka - 8.32-11 -- cp: default to --reflink=auto (#1861108) - -* Mon Jul 27 2020 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild - -* Fri Jul 24 2020 Kamil Dudka - 8.32-9 -- disable -flto on ppc64le to make test-float pass (#1789115) - -* Mon Jul 13 2020 Tom Stellard - 8.32-8 -- Use make macros -- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro - -* Fri Jun 26 2020 James Cassell - 8.32-7 -- move ncurses to -common package since it's needed for colorls.sh -- make ncurses optional - -* Fri May 15 2020 Kamil Dudka - 8.32-6 -- compile with -Dlint to enable optional initialization and cleanup code - -* Thu Apr 23 2020 Kamil Dudka - 8.32-5 -- du: simplify leaf optimization for XFS (#1823247) - -* Fri Apr 17 2020 Tom Stellard - 8.32-4 -- Fix missing inline function definition - -* Wed Mar 11 2020 Kamil Dudka - 8.32-3 -- uniq: remove collation handling as required by newer POSIX - -* Mon Mar 09 2020 Kamil Dudka - 8.32-2 -- make mknod work again in chroot without /proc being mounted (#1811038) -- ls: restore 8.31 behavior on removed directories - -* Thu Mar 05 2020 Kamil Dudka - 8.32-1 -- new upstream release 8.32 - -* Tue Feb 11 2020 Kamil Dudka - 8.31-10 -- make upstream test-suite work with root privileges (#1800597) - -* Wed Feb 05 2020 Kamil Dudka - 8.31-9 -- use upstream fix the cp/proc-short-read test - -* Thu Jan 30 2020 Kamil Dudka - 8.31-8 -- skip a test that relies on /proc/kallsyms having immutable content - -* Tue Jan 28 2020 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild - -* Thu Oct 17 2019 Kamil Dudka - 8.31-6 -- temporarily disable the use of statx (#1760300) - -* Fri Oct 11 2019 Kamil Dudka - 8.31-5 -- use statx instead of stat when available (#1760300) - -* Wed Jul 24 2019 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild - -* Tue Jul 16 2019 Kamil Dudka - 8.31-3 -- disable flashing in ls colors for broken symbolic links (#1728986) - -* Mon Mar 18 2019 Kamil Dudka - 8.31-2 -- fix formatting of sha512sum(1) man page (#1688740) - -* Mon Mar 11 2019 Kamil Dudka - 8.31-1 -- new upstream release 8.31 - -* Thu Jan 31 2019 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild - -* Wed Nov 07 2018 Kamil Dudka - 8.30-8 -- sync: fix open() fallback bug -- fix implicit declaration warning in coreutils-getgrouplist.patch - -* Sat Nov 03 2018 Kevin Fenzi - 8.30-7 -- Also remove Requires pre/post used by info scriptlets. - -* Sat Nov 03 2018 Kevin Fenzi - 8.30-6 -- Remove no longer needed info scriptlets - -* Thu Oct 11 2018 Kamil Dudka - 8.30-5 -- fix heap-based buffer overflow in vasnprintf() (CVE-2018-17942) - -* Thu Jul 12 2018 Fedora Release Engineering - 8.30-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild - -* Tue Jul 10 2018 Kamil Dudka - 8.30-3 -- rename gnulib's renameat2 to renameatu to avoid clash with glibc (#1598518) - -* Wed Jul 04 2018 Kamil Dudka - 8.30-2 -- sync i18n patches with Suse (patch by Bernhard Voelker) - -* Mon Jul 02 2018 Kamil Dudka - 8.30-1 -- new upstream release 8.30 - -* Wed May 30 2018 Kamil Dudka - 8.29-12 -- add provides to coreutils-single to make it a drop-in replacement - -* Mon May 28 2018 Kamil Dudka - 8.29-11 -- ls: increase the allowed abmon width from 5 to 12 (#1577872) -- date, ls: pick strftime fixes from glibc to improve locale support (#1577872) - -* Fri Apr 20 2018 Kamil Dudka - 8.29-10 -- fix crash caused by mistakenly enabled leaf optimization (#1558249) - -* Fri Mar 23 2018 Kamil Dudka - 8.29-9 -- make it possible to install the latest available Adobe Reader RPM for Linux - -* Mon Mar 19 2018 Kamil Dudka - 8.29-8 -- drop BR for bison, which is not used during the build - -* Fri Mar 16 2018 Kamil Dudka - 8.29-7 -- make sure that parse-datetime.{c,y} ends up in debuginfo (#1555079) - -* Tue Mar 06 2018 Kamil Dudka - 8.29-6 -- fix build failure with glibc-2.28 - -* Mon Feb 26 2018 Igor Gnatenko - 8.29-5 -- Remove /bin/* Provides - -* Mon Feb 19 2018 Kamil Dudka - 8.29-4 -- add explicit BR for the gcc compiler - -* Wed Feb 07 2018 Fedora Release Engineering - 8.29-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild - -* Tue Jan 23 2018 Kamil Dudka - 8.29-2 -- doc: warn about following symlinks recursively in chown/chgrp (CVE-2017-18018) -- mv -n: do not overwrite the destination - -* Tue Jan 02 2018 Kamil Dudka - 8.29-1 -- new upstream release 8.29 - -* Tue Nov 07 2017 Igor Gnatenko - 8.28-2 -- Remove very old Provides (mktemp, sh-utils, textwrap, fileutils, stat) - -* Mon Sep 04 2017 Kamil Dudka - 8.28-1 -- new upstream release 8.28 - -* Tue Aug 22 2017 Ville Skyttä - 8.27-16 -- Own the %%{_libexecdir}/coreutils dir - -* Fri Aug 18 2017 Kamil Dudka - 8.27-15 -- ptx: fix a possible crash caused by integer overflow (#1482445) - -* Wed Aug 02 2017 Fedora Release Engineering - 8.27-14 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild - -* Fri Jul 28 2017 Igor Gnatenko - 8.27-13 -- Enable separate debuginfo back - -* Wed Jul 26 2017 Kamil Dudka - 8.27-12 -- avoid build failure caused broken RPM code that produces debuginfo packages - -* Wed Jul 26 2017 Fedora Release Engineering - 8.27-11 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild - -* Tue May 30 2017 Sebastian Kisela - 8.27-10 -- doc: mention `setpriv --no-new-privs` feature in runcon info - -* Tue May 16 2017 Kamil Dudka - 8.27-9 -- add coreutils-full provides for coreutils to make it explicitly installable - -* Wed May 03 2017 Kamil Dudka - 8.27-8 -- drop coreutils-overflow.patch no longer needed (#158405) - -* Wed May 03 2017 Kamil Dudka - 8.27-7 -- drop workaround for already fixed rpm-build bug (#1306559) - -* Wed May 03 2017 Kamil Dudka - 8.27-6 -- do not mention a deprecated option in localized man pages -- drop workaround no longer needed for 10 years old rpm-build bug (#246729) -- drop unnecessary uses of %%defattr - -* Fri Apr 28 2017 Sebastian Kisela - 8.27-5 -- tail: revert to polling if a followed directory is replaced (#1283760) - -* Thu Apr 27 2017 Kamil Dudka - 8.27-4 -- date, touch: fix out-of-bounds write via large TZ variable (CVE-2017-7476) - -* Tue Apr 25 2017 Kamil Dudka - 8.27-3 -- do not obsolete coreutils-single, so it can be installed by DNF2 (#1444802) - -* Wed Mar 15 2017 Kamil Dudka - 8.27-2 -- fix spurious build failure caused by the misc/date-debug test - -* Thu Mar 09 2017 Kamil Dudka - 8.27-1 -- new upstream release 8.27 - -* Fri Feb 10 2017 Fedora Release Engineering - 8.26-7 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild - -* Fri Feb 03 2017 Kamil Dudka - 8.26-6 -- fold: preserve new-lines in mutlibyte text (#1418505) - -* Mon Jan 23 2017 Kamil Dudka - 8.26-5 -- date: fix TZ= regression (patch by Pádraig Brady) - -* Mon Jan 02 2017 Kamil Dudka - 8.26-4 -- use upstream patch for gnulib's test-lock (instead of disabling it) - -* Thu Dec 15 2016 Kamil Dudka - 8.26-3 -- drop build fixes no longer needed - -* Fri Dec 02 2016 Kamil Dudka - 8.26-2 -- apply patches automatically to ease maintenance - -* Thu Dec 01 2016 Kamil Dudka - 8.26-1 -- new upstream release 8.26 - -* Mon Oct 31 2016 Kamil Dudka - 8.25-17 -- md5sum,sha*sum: fix --ignore-missing with checksums starting with 00 - -* Tue Oct 11 2016 Tomáš Mráz - 8.25-16 -- rebuild with OpenSSL 1.1.0 - -* Wed Sep 07 2016 Kamil Dudka - 8.25-15 -- ls: allow interruption when reading slow directories (#1365933) - -* Tue Jul 19 2016 Kamil Dudka - 8.25-14 -- run autoreconf in %%prep -- drop post-install fix for Japanese locales that no longer applies -- fix 'sort -h -k' in locales that use blank as thousands separator (#1355780) - -* Thu Jul 14 2016 Kamil Dudka - 8.25-13 -- make 'sort -h' work for arbitrary column even when using UTF-8 locales - -* Mon Jul 11 2016 Kamil Dudka - 8.25-12 -- install -Z now sets default SELinux context for created directories (#1339135) -- drop the %%pre scriptlet, which is no longer needed (#1354078) -- clarify recognition of "^COLOR.*none" in /etc/DIR_COLORS (#1349579) - -* Thu Jul 07 2016 Jakub Martisko - 8.25-11 -- switch to UTF8 locale when (un)expand input contains BOM header - (#1158494) -- fixed regression where (un)expand would end with "long input line" - error when BOM header is present - -* Fri Jun 24 2016 Ondrej Vasik - 8.25-10 -- change way of detection of interactive shell in colorls.sh script - (#1321648) - -* Mon Jun 20 2016 Kamil Dudka - 8.25-9 -- add BR for glibc-langpack-en to prevent the expand/mb test from failing -- do not use /bin/mv in %%post to avoid a circular dependency (#1348043) - -* Fri Jun 17 2016 Kamil Dudka - 8.25-8 -- sync /etc/DIR_COLORS with latest upstream (#1335320) - -* Wed Jun 15 2016 Kamil Dudka - 8.25-7 -- handle info doc in RPM scriptlets of coreutils-common, which provides it -- make sure that the license file is installed, even if coreutils-common is not - -* Thu Jun 09 2016 Jakub Martisko - 8.25-6 -- (un)expand: fix regression in handling input files, where only - the first file was processed. - -* Sat Mar 05 2016 Ondrej Vasik - 8.25-5 -- cut: move back to the old i18n implementation (#1314722) - -* Mon Feb 15 2016 Ondrej Vasik - 8.25-4 -- cut: fix regression in handling fields for lines wider - than 64 chars (#1304839) - -* Thu Feb 11 2016 Lubomir Rintel - 8.25-3 -- Fix a regression in unexpand empty line handling - -* Thu Jan 21 2016 Ondrej Vasik - 8.25-2 -- Adjust the i18n patch for coreutils-8.25 -- add new base32 binary - -* Wed Jan 20 2016 Ondrej Vasik - 8.25-1 -- new upstream release(#1300282) - -* Fri Jan 15 2016 Ondrej Oprala - 8.24-108 -- cut: be MB for ALL archs - -* Fri Jan 15 2016 Ondrej Oprala - 8.24-107 -- Use the new i18n implementation for the cut utility - -* Wed Jan 13 2016 Ondrej Vasik - 8.24-106 -- mv: prevent dataloss when source dir is specified multiple - times (#1297464, by P.Brady) - -* Mon Dec 14 2015 Pádraig Brady - 8.24-105 -- Give explicit priority to coreutils over coreutils-single - -* Thu Dec 03 2015 Pádraig Brady - 8.24-104 -- Avoid libgmp and libcrypto dependencies from coreutils-single - -* Thu Dec 03 2015 Pádraig Brady - 8.24-103 -- Remove erroneous /usr/bin/kill from coreutils-single - -* Tue Dec 01 2015 Ondrej Oprala - 8.24-102 -- Use the new i18n implementation for expand/unexpand - -* Mon Nov 30 2015 Ondrej Vasik - 8.24-101 -- coreutils-single should provide versioned coreutils (#1286338) - -* Wed Nov 18 2015 Pádraig Brady - 8.24-100 -- Split package to more easily support smaller installs - -* Wed Sep 16 2015 Kamil Dudka - 8.24-4 -- fix memory leak in sort/I18N (patches written by Pádraig, #1259942) - -* Sat Sep 12 2015 Ondrej Vasik 8.24-3 -- fix one still existing occurance of non-full path in colorls.sh - -* Thu Jul 16 2015 Ondrej Vasik 8.24-2 -- use newer version of sort/I18N fix for CVE-2015-4041 - and CVE-2015-4042 - -* Sun Jul 05 2015 Ondrej Vasik 8.24-1 -- new upstream release 8.24 - -* Sat Jul 4 2015 Peter Robinson 8.23-14 -- Disable failing test-update-copyright to fix FTBFS - -* Wed Jun 17 2015 Fedora Release Engineering - 8.23-13 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild - -* Thu Jun 04 2015 Ondrej Vasik - 8.23-12 -- call utilities in colorls.* scripts with full path (#1222140) - -* Thu May 14 2015 Kamil Dudka - 8.23-11 -- run 'make check' in parallel to speed up the build - -* Wed May 13 2015 Ondrej Oprala - 8.23-10 -- sort - fix buffer overflow in some case conversions - - patch by Pádraig Brady - -* Mon Apr 20 2015 Pádraig Brady - 8.23-9 -- Adjust LS_COLORS in 256 color mode; brighten some, remove hardlink colors (#1196642) - -* Sun Mar 22 2015 Peter Robinson 8.23-8 -- Drop large ancient docs - -* Sat Feb 21 2015 Till Maas - 8.23-7 -- Rebuilt for Fedora 23 Change - https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code - -* Mon Dec 01 2014 Ondrej Vasik - 8.23-6 -- have the LC_TIME subdirs with lang macro (#1169027) - -* Wed Oct 15 2014 Ondrej Vasik - 8.23-5 -- handle situation with ro /tmp in colorls scripts (#1149761) - -* Wed Oct 01 2014 Ondrej Vasik - 8.23-4 -- fix the sorting in multibyte locales (NUL-terminate sort keys) - - patch by Andreas Schwab (#1146185) - -* Sat Aug 16 2014 Fedora Release Engineering - 8.23-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild - -* Tue Aug 05 2014 Ondrej Vasik - 8.23-2 -- enable smp_flags again (by B.Voelker) -- fix regression in chroot - -* Tue Jul 22 2014 Ondrej Vasik - 8.23-1 -- new upstream release 8.23 -- synchronize the old differences in ls SELinux options - with upstream -- skip df/skip-duplicates.sh test for now (passing locally, failing in koji) - -* Fri Jul 11 2014 Tom Callaway - 8.22-17 -- fix license handling - -* Mon Jun 23 2014 Jakub Čajka - 8.22-16 -- fix failed tests on ppc(backport from gnulib upstream) - -* Sat Jun 07 2014 Fedora Release Engineering - 8.22-15 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild - -* Sat Apr 12 2014 Ondrej Vasik 8.22-14 -- fix dd sparse test failure on xfs filesystem(#1085727, - by P.Brady) - -* Wed Mar 05 2014 Ondrej Vasik 8.22-13 -- drop the util-linux requirements (smaller docker images), - drop ancient obsoletes of -libs subpackage - -* Sun Mar 02 2014 Ondrej Vasik 8.22-12 -- fix the date crash or infloop in TZ="" parsing (#1069657) - -* Mon Jan 13 2014 Ondrej Vasik 8.22-11 -- cp/mv/install: do not crash when getfscreatecon() is - returning a NULL context - -* Mon Jan 13 2014 Ondrej Vasik 8.22-10 -- unset the unnecessary envvars after colorls scripts(#1051703) -- improve the limitation (check for both utf8 and utf-8) - -* Fri Jan 10 2014 Ondrej Oprala 8.22-9 -- Limit the cut optimizations to UTF-8 locales only - -* Wed Jan 08 2014 Ondrej Oprala 8.22-8 -- Don't use cut mb path if not necessary (#1021403, #499220) -- several i18n patch improvements merged from OpenSUSE (fixed - compilation warnings, simplify mb handling in uniq) - -* Mon Jan 06 2014 Ondrej Oprala 8.22-7 -- Fix sorting by non-first field (#1003544) - -* Fri Jan 03 2014 Ondrej Vasik 8.22-6 -- do not modify SELinux contexts of existing parent - directories when copying files (fix by P.Brady, #1045122) - -* Thu Jan 02 2014 Ondrej Oprala 8.22-5 -- reverted an old change and constricted it's condition -- turned off two multibyte tests (wrong strcoll return value) - -* Mon Dec 23 2013 Ondrej Vasik 8.22-4 -- skip even the ls aliases in noninteractive mode - (suggested by T. Cordes, #988152) - -* Sun Dec 22 2013 Ondrej Vasik 8.22-3 -- reset buffer before copying to prevent some rare cases of - invalid output in join and uniq(#1036289) - -* Sat Dec 14 2013 Ondrej Vasik 8.22-1 -- new upstream version 8.22 -- temporarily disable multibyte cut.pl part and df symlink - tests - -* Thu Dec 12 2013 Ondrej Vasik 8.21-23 -- skip output-is-input-mb.p test - failing on armv7l (reported - by B.Voelker) - -* Mon Dec 9 2013 Peter Robinson 8.21-22 -- Add upstream patch to fix test failures on aarch64 - -* Thu Nov 28 2013 Ondrej Vasik 8.21-21 -- turn on the multibyte path in the testsuite to cover - i18n regressions - -* Wed Nov 06 2013 Ondrej Vasik 8.21-20 -- fix possible colorls.csh script errors for tcsh with - noclobber set and entered include file (#1027279) - -* Mon Oct 14 2013 Ondrej Vasik 8.21-19 -- cp: correct error message for invalid arguments - of '--no-preserve' (#1018206) - -* Thu Aug 15 2013 Ondrej Vasik 8.21-18 -- pr -e, with a mix of backspaces and TABs, could corrupt the heap - in multibyte locales (analyzed by J.Koncicky) - -* Wed Aug 14 2013 Ondrej Oprala 8.21-17 -- Fix sort multibyte incompatibilities - -* Sat Aug 03 2013 Fedora Release Engineering - 8.21-16 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild - -* Wed Jul 17 2013 Ondrej Oprala 8.21-15 -- change the TMP variable name in colorls.csh to _tmp (#981373) - -* Fri May 17 2013 Ondrej Vasik 8.21-10 -- DIR_COLORS.$TERM should have higher priority than - DIR_COLORS.256color (#921651) - -* Mon Mar 11 2013 Ondrej Oprala 8.21-9 -- add support for INCLUDE in colorls scripts (#818069) - -* Mon Mar 04 2013 Ondrej Vasik 8.21-8 -- fix factor on AArch64 (M.Salter, #917735) - -* Fri Mar 01 2013 Ondrej Vasik 8.21-7 -- ls: colorize several new archive/compressed types (#868510) - -* Sat Feb 23 2013 Ondrej Vasik 8.21-6 -- install: do proper cleanup when strip fails - (O.Oprala, B.Voekler, #632444) - -* Wed Feb 20 2013 Ondrej Vasik 8.21-5 -- fix multibyte issue in unexpand(by R.Kollar, #821262) - -* Mon Feb 18 2013 Ondrej Oprala 8.21-4 -- fix sort-mb-tests.sh test (B.Voelker) - -* Mon Feb 18 2013 Mark Wielaard 8.21-3 -- fix coreutils-i18n.patch to terminate mbdelim string (#911929) - -* Mon Feb 18 2013 Ondrej Vasik 8.21-2 -- remove unnecessary powerpc factor patch - -* Fri Feb 15 2013 Ondrej Vasik 8.21-1 -- new upstream release 8.21, update patches - -* Thu Feb 07 2013 Ondrej Oprala 8.20-8 -- add missing sort-mb-tests.sh to local.mk - -* Tue Feb 05 2013 Ondrej Vasik 8.20-7 -- add support for DTR/DSR control flow in stty(#445213) - -* Wed Jan 23 2013 Ondrej Vasik 8.20-6 -- fix multiple segmantation faults in i18n patch (by SUSE) - (#869442, #902917) - -* Thu Dec 20 2012 Ondrej Vasik 8.20-5 -- seq: fix newline output when -s specified (upstream) - -* Mon Dec 10 2012 Ondrej Vasik 8.20-4 -- fix showing duplicates in df (#709351, O.Oprala, B.Voelker) - -* Thu Dec 06 2012 Ondrej Vasik 8.20-3 -- fix factor on 32bit powerpc (upstream, #884715) - -* Mon Nov 05 2012 Ondrej Vasik 8.20-2 -- disable the temporary O_SYNC fix (glibc is fixed - #872366) - -* Sat Oct 27 2012 Ondrej Vasik 8.20-1 -- new upstream release 8.20 -- Temporarily require util-linux >= 2.22.1-3 (to prevent missing - su/runuser on system) - -* Mon Aug 20 2012 Ondrej Vasik 8.19-1 -- new upstream release 8.19 -- fix multibyte issues in cut and expand (M.Briza, #821260) - -* Sun Aug 12 2012 Ondrej Vasik 8.18-1 -- new upstream release 8.18 -- su/runuser moved to util-linux - -* Wed Jul 18 2012 Fedora Release Engineering - 8.17-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild - -* Tue May 15 2012 Ondrej Vasik 8.17-3 -- add virtual provides for bundled(gnulib) copylib (#821748) - -* Fri May 11 2012 Ondrej Vasik 8.17-2 -- ls: upstream fix - correctly show symlinks in / - -* Fri May 11 2012 Ondrej Vasik 8.17-1 -- new upstream release 8.17 - -* Fri May 04 2012 Ondrej Vasik 8.16-3 -- add .htm and .shtml to colorized DIR_COLORS document - type (#817218) - -* Mon Apr 16 2012 Ondrej Vasik 8.16-2 -- fix the tcsh colorls.csh behaviour in non-interactive - mode (#804604) - -* Mon Mar 26 2012 Ondrej Vasik 8.16-1 -- new upstream release 8.16 -- defuzz patches, remove already applied patches - -* Thu Mar 08 2012 Ondrej Vasik 8.15-8 -- fix regression in du -x with nondir argument (by J.Meyering) - -* Wed Mar 07 2012 Ondrej Vasik 8.15-7 -- fix sort segfault with multibyte locales (by P.Brady) - -* Fri Feb 10 2012 Harald Hoyer 8.15-6 -- turn on testsuite again - -* Wed Jan 25 2012 Harald Hoyer 8.15-5 -- add filesystem guard - -* Wed Jan 25 2012 Harald Hoyer 8.15-4 -- add missing provides for the /usr-move - -* Wed Jan 25 2012 Harald Hoyer 8.15-3 -- install everything in /usr - https://fedoraproject.org/wiki/Features/UsrMove - -* Mon Jan 16 2012 Kamil Dudka - 8.15-2 -- fix stack smashing, buffer overflow, and invalid output of pr (#772172) - -* Sat Jan 07 2012 Ondrej Vasik - 8.15-1 -- new upstream release 8.15 - -* Thu Jan 05 2012 Ondrej Vasik - 8.14-6 -- do not use shebang in sourced colorls.csh - -* Thu Jan 05 2012 Ondrej Vasik - 8.14-5 -- fix pr -c and pr -v segfault with multibyte locales - -* Mon Oct 31 2011 Rex Dieter 8.14-4 -- rebuild (gmp), last time, I promise - -* Mon Oct 24 2011 Ondrej Vasik - 8.14-3 -- require at least pam 1.1.3-7 (#748215) - -* Thu Oct 20 2011 Ondrej Vasik - 8.14-2 -- rebuild for gmp - -* Wed Oct 12 2011 Ondrej Vasik - 8.14-1 -- new upstream release 8.14 - -* Mon Sep 26 2011 Peter Schiffer - 8.13-2.2 -- rebuild with new gmp - -* Mon Sep 12 2011 Ondrej Vasik - 8.13-2 -- Obsolete coreutils-libs (#737287) - -* Fri Sep 09 2011 Ondrej Vasik - 8.13-1 -- new upstream release 8.13 -- temporarily disable recently added multibyte checks in - misc/cut test -- fix the SUSE fix for cut output-delimiter -- drop coreutils-libs subpackage, no longer needed - -* Mon Sep 05 2011 Ondrej Vasik - 8.12-7 -- incorporate some i18n patch fixes from OpenSUSE: - - fix cut output-delimiter option - - prevent infinite loop in sort when ignoring chars - - prevent using unitialized variable in cut - -* Tue Aug 23 2011 Ondrej Vasik - 8.12-6 -- su: fix shell suspend in tcsh (#597928) - -* Thu Aug 18 2011 Ondrej Vasik - 8.12-5 -- variable "u" should be static in uname processor type patch - -* Thu Aug 11 2011 Ondrej Vasik - 8.12-4 -- deprecate non-upstream cp -Z/--context (install should be - used instead of it), make it working if destination exists - (#715557) - -* Fri Jul 29 2011 Ondrej Vasik - 8.12-3 -- use acl_extended_file_nofollow() if available (#692823) - -* Fri Jul 15 2011 Ondrej Vasik - 8.12-2 -- support ecryptfs mount of Private (postlogin into su.pamd) - (#722323) - -* Wed Apr 27 2011 Ondrej Vasik - 8.12-1 -- new upstream release 8.12 - -* Thu Apr 14 2011 Ondrej Vasik - 8.11-2 -- fix issue with df --direct(extra new line) - -* Thu Apr 14 2011 Ondrej Vasik - 8.11-1 -- new upstream release 8.11, defuzz patches - -* Tue Mar 22 2011 Ondrej Vasik - 8.10-7 -- add note about mkdir mode behaviour into info - documentation (#610559) - -* Mon Mar 14 2011 Ondrej Vasik - 8.10-6 -- fix possible uninitalized variables usage caused by i18n - patch(#683799) - -* Fri Mar 4 2011 Ondrej Vasik - 8.10-5 -- make coreutils build even without patches (with - nopam, norunuser and noselinux variables) - -* Thu Feb 17 2011 Ondrej Vasik - 8.10-4 -- colorize documents by DIR_COLORS files(brown like mc) - -* Thu Feb 17 2011 Ondrej Vasik - 8.10-3 -- add several new TERMs to DIR_COLORS files(#678147) - -* Tue Feb 08 2011 Fedora Release Engineering - 8.10-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild - -* Fri Feb 04 2011 Ondrej Vasik - 8.10-1 -- new upstream release coreutils-8.10 - -* Sat Jan 08 2011 Dennis Gilmore - 8.9-2 -- drop no longer needed mkstemp patch for sparc - -* Tue Jan 04 2011 Ondrej Vasik - 8.9-1 -- new upstream release coreutils-8.9 - -* Fri Dec 31 2010 Ondrej Vasik - 8.8-2 -- The suffix length was dependent on the number of bytes - or lines per file (#666293) - -* Thu Dec 23 2010 Ondrej Vasik - 8.8-1 -- fix parallel sorting issue (#655096) -- new upstream release coreutils-8.8 (#665164) - -* Thu Nov 18 2010 Ondrej Vasik - 8.7-2 -- don't prompt for password with runuser(#654367) - -* Mon Nov 15 2010 Ondrej Vasik - 8.7-1 -- new upstream release coreutils-8.7 -- pam support in su consolidation with SUSE(#622700) - -* Wed Nov 03 2010 Kamil Dudka - 8.6-3 -- prevent sort from assertion failure in case LC_CTYPE does not match LC_TIME - (#647938) - -* Tue Oct 26 2010 Kamil Dudka - 8.6-2 -- improve i18n support in sort (debug-keys test is now back) - -* Wed Oct 20 2010 Ondrej Vasik - 8.6-1 -- new upstream release 8.6 -- remove applied patches, temporarily disable sort - debug-keys test for multibyte locales (failing - because of i18n patch) - -* Thu Sep 30 2010 Ondrej Vasik - 8.5-10 -- various fixes for case conversion in tr(#611274) - -* Wed Sep 29 2010 jkeating - 8.5-9 -- Rebuilt for gcc bug 634757 - -* Mon Sep 20 2010 Ondrej Vasik - 8.5-8 -- change assertion failure for invalid multibyte input - in sort to less confusing error message(#591352) - -* Wed Sep 08 2010 Ondrej Vasik - 8.5-7 -- add RELRO protection to su as well (#630017) - -* Mon Sep 06 2010 Ondrej Vasik - 8.5-6 -- compile su with pie again (#630017) - -* Mon Aug 30 2010 Ondrej Vasik - 8.5-5 -- fix double free abort in tac (#628213) - -* Thu Jul 22 2010 Ondrej Vasik - 8.5-4 -- Add .ear, .war, .sar , for Java jar-like archives to - dircolors (#616497) - -* Fri Jul 2 2010 Dan Horák - 8.5-3 -- rebuilt with the updated configuration patch -- drop the old -O1 exception for s390(x) -- updated the getgrouplist patch (Kamil Dudka) - -* Tue Apr 27 2010 Ondrej Vasik - 8.5-2 -- doublequote LS_COLORS in colorls.*sh scripts to speedup - shell start(#586029) -- add patch for mkstemp on sparc64(Dennis Gilmore) -- update /etc/DIR_COLORS* files - -* Mon Apr 26 2010 Ondrej Vasik - 8.5-1 -- new upstream release 8.5 - -* Thu Apr 15 2010 Ondrej Vasik - 8.4-8 -- move readlink from /usr/bin to bin, keep symlink in - /usr/bin(#580682) - -* Mon Mar 29 2010 Kamil Dudka - 8.4-7 -- a new option df --direct - -* Sat Mar 20 2010 Ondrej Vasik - 8.4-6 -- run tput colors in colorls profile.d scripts only - in the interactive mode(#450424) - -* Fri Feb 12 2010 Ondrej Vasik - 8.4-5 -- fix exit status of terminated child processes in su with - pam(#559098) - -* Fri Feb 05 2010 Ondrej Vasik - 8.4-4 -- do not depend on selinux patch application in - _require_selinux tests(#556350) - -* Fri Jan 29 2010 Ondrej Vasik - 8.4-3 -- do not fail tests if there are no loopdevices left - (#558898) - -* Tue Jan 26 2010 Ondrej Vasik - 8.4-2 -- who doesn't determine user's message status correctly - (#454261) - -* Thu Jan 14 2010 Ondrej Vasik - 8.4-1 -- new upstream release 8.4 - -* Fri Jan 08 2010 Ondrej Vasik - 8.3-1 -- new upstream release 8.3 - -* Wed Jan 06 2010 Ondrej Vasik - 8.2-6 -- require gmp-devel/gmp for large numbers support(#552846) - -* Sun Dec 27 2009 Ondrej Vasik - 8.2-5 -- fix misc/selinux root-only test(#550494) - -* Sat Dec 19 2009 Ondrej Vasik - 8.2-4 -- bring back uname -p/-i functionality except of the - athlon hack(#548834) -- comment patches - -* Wed Dec 16 2009 Ondrej Vasik - 8.2-3 -- use grep instead of deprecated egrep in colorls.sh script - (#548174) -- remove unnecessary versioned requires/conflicts -- remove non-upstream hack for uname -p - -* Wed Dec 16 2009 Ondrej Vasik - 8.2-2 -- fix DIR_COLORS.256color file - -* Fri Dec 11 2009 Ondrej Vasik - 8.2-1 -- new upstream release 8.2 -- removed applied patches, temporarily do not run dup_cloexec() - dependent gnulib tests failing in koji - -* Fri Nov 27 2009 Ondrej Vasik - 8.1-1 -- new upstream release 8.1 -- fix build under koji (no test failures with underlying - RHEL-5 XEN kernel due to unsearchable path and lack of - futimens functionality) - -* Wed Oct 07 2009 Ondrej Vasik - 8.0-2 -- update /etc/DIR_COLORS* files - -* Wed Oct 07 2009 Ondrej Vasik - 8.0-1 -- New upstream release 8.0 (beta), defuzz patches, - remove applied patches - -* Mon Oct 05 2009 Ondrej Vasik - 7.6-7 -- chcon no longer aborts on a selinux disabled system - (#527142) - -* Fri Oct 02 2009 Ondrej Vasik - 7.6-6 -- ls -LR exits with status 2, not 0, when it encounters - a cycle(#525402) -- ls: print "?", not "0" as inode of dereferenced dangling - symlink(#525400) -- call the install-info on .gz info files - -* Tue Sep 22 2009 Ondrej Vasik - 7.6-5 -- improve and correct runuser documentation (#524805) - -* Mon Sep 21 2009 Ondrej Vasik - 7.6-4 -- add dircolors color for GNU lzip (#516897) - -* Fri Sep 18 2009 Ondrej Vasik - 7.6-3 -- fixed typo in DIR_COLORS.256color causing no color for - multihardlink - -* Wed Sep 16 2009 Ondrej Vasik - 7.6-2 -- fix copying of extended attributes for read only source - files - -* Sat Sep 12 2009 Ondrej Vasik - 7.6-1 -- new upstream bugfix release 7.6, removed applied patches, - defuzzed the rest - -* Thu Sep 10 2009 Ondrej Vasik - 7.5-6 -- fix double free error in fold for singlebyte locales - (caused by multibyte patch) - -* Tue Sep 08 2009 Ondrej Vasik - 7.5-5 -- fix sort -h for multibyte locales (reported via - http://bugs.archlinux.org/task/16022) - -* Thu Sep 03 2009 Ondrej Vasik - 7.5-4 -- fixed regression where df -l as regular user - cause "Permission denied" (#520630, introduced by fix for - rhbz #497830) - -* Fri Aug 28 2009 Ondrej Vasik - 7.5-3 -- ls -i: print consistent inode numbers also for mount points - (#453709) - -* Mon Aug 24 2009 Ondrej Vasik - 7.5-2 -- Better fix than workaround the koji insufficient utimensat - support issue to prevent failures in other packages - -* Fri Aug 21 2009 Ondrej Vasik - 7.5-1 -- New upstream release 7.5, remove already applied patches, - defuzz few others, xz in default set(by dependencies), - so no explicit br required -- skip two new tests on system with insufficient utimensat - support(e.g. koji) -- libstdbuf.so in separate coreutils-libs subpackage -- update /etc/DIRCOLORS* - -* Thu Aug 06 2009 Ondrej Vasik - 7.4-6 -- do process install-info only with info files present(#515970) -- BuildRequires for xz, use xz tarball - -* Wed Aug 05 2009 Kamil Dudka - 7.4-5 -- ls -1U with two or more arguments (or with -R or -s) works properly again -- install runs faster again with SELinux enabled (#479502) - -* Fri Jul 24 2009 Fedora Release Engineering - 7.4-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild - -* Mon Jul 06 2009 Ondrej Vasik 7.4-3 -- do not ignore sort's version sort for multibyte locales - (#509688) - -* Thu Jun 18 2009 Ondrej Vasik 7.4-2 -- temporarily workaround probable kernel issue with - TCSADRAIN(#504798) - -* Mon May 25 2009 Ondrej Vasik 7.4-1 -- new upstream release 7.4, removed applied patches - -* Thu Apr 23 2009 Ondrej Vasik 7.2-3 -- fix segfaults in join (i18n patch) when using multibyte - locales(#497368) - -* Fri Apr 17 2009 Ondrej Vasik 7.2-2 -- make mv xattr support failures silent (as is done for - cp -a) - #496142 - -* Tue Mar 31 2009 Ondrej Vasik 7.2-1 -- New upstream bugfix release 7.2 -- removed applied patches -- temporarily disable strverscmp failing gnulib test - -* Thu Mar 19 2009 Ondrej Vasik 7.1-7 -- do not ship /etc/DIR_COLORS.xterm - as many terminals - use TERM xterm and black background as default - making - ls color output unreadable -- shipping /etc/DIR_COLORS.lightbgcolor instead of it for - light(white/gray) backgrounds -- try to preserve xattrs in cp -a when possible - -* Mon Mar 02 2009 Ondrej Vasik 7.1-6 -- fix sort bugs (including #485715) for multibyte locales - as well - -* Fri Feb 27 2009 Ondrej Vasik 7.1-5 -- fix infinite loop in recursive cp (upstream, introduced - by 7.1) - -* Thu Feb 26 2009 Ondrej Vasik 7.1-4 -- fix showing ACL's for ls -Z (#487374), fix automatic - column width for it as well - -* Wed Feb 25 2009 Ondrej Vasik 7.1-3 -- fix couple of bugs (including #485715) in sort with - determining end of fields(upstream) - -* Wed Feb 25 2009 Ondrej Vasik 7.1-2 -- workaround libcap issue with broken headers (#483548) -- fix gnulib testsuite failure (4x77 (skip) is not - 77(skip) ;) ) - -* Tue Feb 24 2009 Ondrej Vasik - 7.1-1 -- New upstream release 7.1 (temporarily using tar.gz tarball - as there are no xz utils in Fedora), removed applied - patches, amended patches and LS_COLORS files - -* Tue Feb 24 2009 Fedora Release Engineering - 7.0-8 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild - -* Wed Jan 28 2009 Kamil Dudka - 7.0-7 -- added BuildRequires for libattr-devel and attr - -* Wed Jan 28 2009 Kamil Dudka - 7.0-6 -- cp/mv: add --no-clobber (-n) option to not overwrite target -- cp/mv: add xattr support (#202823) - -* Thu Dec 04 2008 Ondrej Vasik - 7.0-5 -- fix info documentation for expr command as well(#474434) - -* Thu Dec 04 2008 Ondrej Vasik - 7.0-4 -- fixed syntax error w/ "expr" command using negative - string/integer as first (i.e expr -125) - due to - complexity of changes used diff against upstream git-head - (#474434) -- enable total-awk test again (and skip it when df not working) - -* Tue Nov 25 2008 Ondrej Vasik - 7.0-3 -- package summary tuning - -* Fri Nov 21 2008 Ondrej Vasik - 7.0-2 -- added requirements for util-linux-ng >= 2.14 - because of file conflict in update from F-8/F-9(#472445) -- some sed cleanup, df totaltests patch changes (not working - correctly yet :( ) - -* Wed Nov 12 2008 Ondrej Vasik - 7.0-1 -- new upstream release -- modification/removal of related patches -- use automake 1.10.1 instead of 1.10a -- temporarily skip df --total tests (failures), - timeout-paramaters (failure on ppc64) - -* Mon Nov 03 2008 Ondrej Vasik - 6.12-17 -- Requires: ncurses (#469277) - -* Wed Oct 22 2008 Ondrej Vasik - 6.12-16 -- make possible to disable capability in ls due to - performance impact when not cached(#467508) -- do not patch generated manpages - generate them at build - time -- do not mistakenly display -g and -G runuser option in su - --help output - -* Mon Oct 13 2008 Ondrej Vasik - 6.12-15 -- fix several date issues(e.g. countable dayshifts, ignoring - some cases of relative offset, locales conversions...) -- clarify ls exit statuses documentation (#446294) - -* Sun Oct 12 2008 Ondrej Vasik - 6.12-14 -- cp -Z now correctly separated in man page (#466646) -- cp -Z works again (#466653) -- make preservation of SELinux CTX non-mandatory for - preserve=all cp option - -* Wed Oct 08 2008 Ondrej Vasik - 6.12-13 -- remove unimplemented (never accepted by upstream) option - for chcon changes only. Removed from help and man. -- remove ugly lzma hack as lzma is now supported by setup - macro - -* Mon Oct 06 2008 Jarod Wilson - 6.12-12 -- fix up potential test failures when building in certain - slightly quirky environments (part of bz#442352) - -* Mon Oct 06 2008 Ondrej Vasik - 6.12-11 -- added requires for libattr (#465569) - -* Mon Sep 29 2008 Ondrej Vasik - 6.12-10 -- seq should no longer fail to display final number of some - float usages of seq with utf8 locales(#463556) - -* Wed Aug 13 2008 Ondrej Vasik - 6.12-9 -- mention that DISPLAY and XAUTHORITY envvars are preserved - for pam_xauth in su -l (#450505) - -* Mon Aug 04 2008 Kamil Dudka - 6.12-8 -- ls -U1 now uses constant memory - -* Wed Jul 23 2008 Kamil Dudka - 6.12-7 -- dd: iflag=fullblock now read full blocks if possible - (#431997, #449263) -- ls: --color now highlights files with capabilities (#449985) - -* Wed Jul 16 2008 Ondrej Vasik - 6.12-6 -- Get rid off fuzz in patches - -* Fri Jul 04 2008 Ondrej Vasik - 6.12-5 -- fix authors for basename and echo -- fix who info pages, print last runlevel only for printable - chars - -* Mon Jun 16 2008 Ondrej Vasik - 6.12-4 -- print verbose output of chcon with newline after each - message (#451478) - -* Fri Jun 06 2008 Ondrej Vasik - 6.12-3 -- workaround for koji failures(#449910, #442352) now - preserves timestamps correctly - fallback to supported - functions, added test case -- runuser binary is no longer doubled in /usr/bin/runuser - -* Wed Jun 04 2008 Ondrej Vasik - 6.12-2 -- workaround for strange koji failures(#449910,#442352) -- fixed ls -ZC segfault(#449866, introduced by 6.10-1 - SELinux patch reworking) - -* Mon Jun 02 2008 Ondrej Vasik - 6.12-1 -- New upstream release 6.12, adapted patches - -* Thu May 29 2008 Tom "spot" Callaway - 6.11-5 -- fix SHA256/SHA512 to work on sparc - -* Tue May 20 2008 Ondrej Vasik - 6.11-4 -- fixed a HUGE memory leak in install binary(#447410) - -* Mon May 19 2008 Ondrej Vasik - 6.11-3 -- added arch utility (from util-linux-ng) -- do not show executable file types without executable bit - in colored ls as executable - -* Wed Apr 23 2008 Ondrej Vasik - 6.11-2 -- Do not show misleading scontext in id command when user - is specified (#443485) -- Avoid possible test failures on non-english locales - -* Mon Apr 21 2008 Ondrej Vasik - 6.11-1 -- New upstream release 6.11 -- removed accepted patches + few minor patch changes - -* Fri Apr 18 2008 Ondrej Vasik - 6.10-21 -- fix wrong checksum line handling in sha1sum -c - command(#439531) - -* Tue Apr 15 2008 Ondrej Vasik - 6.10-20 -- fix possible segfault in sha1sum/md5sum command - -* Mon Apr 14 2008 Ondrej Vasik - 6.10-19 -- fix possible build-failure typo in i18n patch(#442205) - -* Mon Apr 7 2008 Ondrej Vasik - 6.10-18 -- fix colorls.sh syntax with Zsh (#440652) -- mention that cp -a includes -c option + mention cp -c - option in manpages (#440056) -- fix typo in runuser manpages (#439410) - -* Sat Mar 29 2008 Ondrej Vasik - 6.10-17 -- better workaround of glibc getoptc change(factor test) -- don't segfault mknod, mkfifo with invalid-selinux-context - -* Thu Mar 27 2008 Ondrej Vasik - 6.10-16 -- keep LS_COLORS when USER_LS_COLORS defined -- someupstream fixes: -- mkdir -Z invalid-selinux-context dir no longer segfaults -- ptx with odd number of backslashes no longer leads to buffer - overflow -- paste -d'\' file" no longer ovveruns memory - -* Wed Mar 26 2008 Ondrej Vasik - 6.10-15 -- covered correct handling for some test conditions failures - e.g. root build+selinux active and not running mcstrans(d) - or selinux enforcing (#436717) - -* Wed Mar 19 2008 Ondrej Vasik - 6.10-14 +* Tue Mar 25 2008 Ondrej Vasik 6.9-9 - mv: never unlink a destination file before calling rename (upstream, #438076) +- defer usage of longoptions patch until final upstream + version (#43105) -* Mon Mar 17 2008 Ondrej Vasik - 6.10-13 -- disable echo option separator behavior(added by #431005, - request for removal #437653 + upstream) -- temporarily disabled longoptions change until full - clarification upstreamery (#431005) +* Tue Mar 11 2008 Ondrej Vasik 6.9-8 +- other way to keep user defined LS_COLORS(#430827) +- fixed harmless double close stdout in dd(#436368) -* Tue Mar 11 2008 Ondrej Vasik - 6.10-12 -- fixed harmless double close of stdout in dd(#436368) - -* Thu Mar 6 2008 Ondrej Vasik - 6.10-11 -- fixed broken order of params in stat(#435669) - -* Tue Mar 4 2008 Ondrej Vasik - 6.10-10 -- colorls.csh missing doublequotes (#435789) -- fixed possibility to localize verbose outputs - -* Mon Mar 3 2008 Ondrej Vasik - 6.10-9 -- consolidation of verbose output to stdout (upstream) - -* Mon Feb 18 2008 Ondrej Vasik - 6.10-8 -- use default security context in install - broken by - coreutils-6.10 update(#319231) -- some sh/csh scripts optimalizations(by ville.skytta@iki.fi, - - #433189, #433190) - -* Mon Feb 11 2008 Ondrej Vasik - 6.10-7 -- keep old csh/sh usermodified colorls shell scripts - but use the new ones(#432154) - -* Thu Feb 7 2008 Ondrej Vasik - 6.10-6 -- better 256-color support in colorls shell scripts -- color tuning(based on feedback in #429121) - -* Mon Feb 4 2008 Ondrej Vasik - 6.10-5 -- enabled 256-color support in colorls shell scripts(#429121) -- fixed syntax error in csh script(#431315) - -* Thu Jan 31 2008 Ondrej Vasik - 6.10-4 -- forgotten return in colorls.sh change - -* Thu Jan 31 2008 Ondrej Vasik - 6.10-3 -- fix unability of echo to display certain strings(added -- - separator, #431005) -- do not require only one long_opt for certain commands - e.g. sleep, yes - but use first usable (#431005) -- do not override userspecified LS_COLORS variable, but - use it for colored ls(#430827) -- discard errors from dircolors to /dev/null + some tuning - of lscolor sh/csh scripts(#430823) -- do not consider files with SELinux security context as - files having ACL in ls long format(#430779) - -* Mon Jan 28 2008 Ondrej Vasik - 6.10-2 -- some manpages improvements(#406981,#284881) -- fix non-versioned obsoletes of mktemp(#430407) - -* Fri Jan 25 2008 Ondrej Vasik - 6.10-1 -- New upstream release(changed %%prep because of lack of lzma - support in %%setup macro) -- License GPLv3+ -- removed patches cp-i-u,du-ls-upstream,statsecuritycontext, - futimens,getdateYYYYMMDD,ls-x -- modified patches to be compilable after upstream changes -- selinux patch reworked to have backward compatibility with - F8(cp,ls and stat behaviour differ from upstream in SELinux - options) +* Tue Mar 04 2008 Ondrej Vasik 6.9-7 - su-l/runuser-l pam file usage a bit documented(#368721) -- more TERMs for DIR_COLORS, added colors for audio files, - more image/compress file types(taken from upstream - dircolors.hin) -- new file DIR_COLORS.256color which takes advantage from - 256color term types-not really used yet(#429121) +- added several missing colored TERMS(#239266) +- added several missing image/compressed file extensions +- some optimalizations of colorls.sh + (#430813, #430827, #430823, #430189, #433190) +- fix unability of echo to display certain strings( + added -- separator, #431005) , do not require only one + long_opt for certain commands like sleep, yes - but + use first usable (#431005) +- keep old csh/sh usermodified colorls shell scripts + (#432154) -* Wed Jan 16 2008 Ondrej Vasik - 6.9-17 -- added several missing colored TERMs(including rxvt-unicode, - screen-256color and xterm-256color) to DIR_COLORS and - DIR_COLORS.xterm(#239266) - -* Wed Dec 05 2007 Ondrej Vasik - 6.9-16 -- fix displaying of security context in stat(#411181) - -* Thu Nov 29 2007 Ondrej Vasik - 6.9-15 -- completed fix of wrong colored broken symlinks in ls(#404511) - -* Fri Nov 23 2007 Ondrej Vasik - 6.9-14 +* Wed Dec 05 2007 Ondrej Vasik 6.9-6 - fixed bug in handling YYYYMMDD date format with relative signed offset(#377821) - -* Tue Nov 13 2007 Ondrej Vasik - 6.9-13 - fixed bug in selinux patch which caused bad preserving of security context in install(#319231) - -* Fri Nov 02 2007 Ondrej Vasik - 6.9-12 - added some upstream supported dircolors TERMs(#239266) - fixed du output for unaccesible dirs(#250089) -- a bit of upstream tunning for symlinks +- fix for wrong colored (broken) symlinks(#404511,#246567) +- fix for displaying of security context in stat(#41181) -* Tue Oct 30 2007 Ondrej Vasik - 6.9-11 +* Tue Oct 30 2007 Ondrej Vasik 6.9-5 - allow cp -a to rewrite file on different filesystem(#219900) (based on upstream patch) - -* Mon Oct 29 2007 Ondrej Vasik - 6.9-10 - modified coreutils-i18n.patch because of sort -R in a non C locales(fix by Andreas Schwab) (#249315) - -* Mon Oct 29 2007 Ondrej Vasik - 6.9-9 - applied upstream patch for runuser to coreutils-selinux.patch(#232652) - License tag to GPLv2+ -* Thu Oct 25 2007 Ondrej Vasik - 6.9-8 -- applied upstream patch for cp and mv(#248591) -* Thu Aug 23 2007 Pete Graner - 6.9-7 -- Fix typo in spec file. (CVS merge conflict leftovers) - -* Thu Aug 23 2007 Pete Graner - 6.9-6 -- Remove --all-name from spec file its now provided in the upstream rpm's find-lang.sh -- Rebuild - -* Tue Aug 14 2007 Tim Waugh 6.9-5 +* Thu Oct 25 2007 Ondrej Vasik 6.9-4 +- applied upstream patch for cp and mv(bug #248591) - Don't generate runuser.1 since we ship a complete manpage for it (bug #241662). -* Wed Jul 4 2007 Tim Waugh 6.9-4 -- Use hard links instead of symbolic links for LC_TIME files (bug #246729). - * Wed Jun 13 2007 Tim Waugh 6.9-3 - Fixed 'ls -x' output (bug #240298). - Disambiguate futimens() from the glibc implementation (bug #242321). @@ -1941,11 +525,11 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir - Parametrize SELinux (bug #174067). - Fix runuser.pamd (bug #173807). -* Thu Nov 24 2005 Tim Waugh 5.93-4 +* Thu Nov 25 2005 Tim Waugh 5.93-4 - Rebuild to pick up new glibc *at functions. - Apply runuser PAM patch from bug #173807. Ship runuser PAM file. -* Tue Nov 15 2005 Dan Walsh 5.93-3 +* Tue Nov 14 2005 Dan Walsh 5.93-3 - Remove multiple from su.pamd * Mon Nov 14 2005 Tim Waugh 5.93-2 @@ -1985,7 +569,7 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir - Allow id to run even when SELinux security context can not be run - Change chcon to use raw functions. -* Tue Jun 28 2005 Tim Waugh +* Thu Jun 28 2005 Tim Waugh - Corrected comments in DIR_COLORS.xterm (bug #161711). * Wed Jun 22 2005 Tim Waugh 5.2.1-52 @@ -2023,7 +607,7 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir * Thu Mar 24 2005 Tim Waugh 5.2.1-43 - Removed patch that adds -C option to install(1). -* Wed Mar 16 2005 Tim Waugh 5.2.1-42 +* Wed Mar 14 2005 Tim Waugh 5.2.1-42 - Fixed pam patch. - Fixed broken configure test. - Fixed build with GCC 4 (bug #151045). @@ -2040,7 +624,7 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir * Thu Jan 13 2005 Tim Waugh 5.2.1-37 - Fixed zh_CN translation (bug #144845). Patch from Mitrophan Chin. -* Tue Dec 28 2004 Dan Walsh 5.2.1-36 +* Mon Dec 28 2004 Dan Walsh 5.2.1-36 - Fix to only setdefaultfilecon if not overridden by command line * Mon Dec 27 2004 Dan Walsh 5.2.1-35 @@ -2336,7 +920,7 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir * Mon Jul 28 2003 Tim Waugh 5.0-8 - Actually use the ACL patch (bug #100519). -* Wed Jul 16 2003 Dan Walsh 5.0-7 +* Wed Jul 18 2003 Dan Walsh 5.0-7 - Convert to SELinux * Mon Jun 9 2003 Tim Waugh diff --git a/sh-utils-1.16-paths.patch b/sh-utils-1.16-paths.patch new file mode 100644 index 0000000..444d563 --- /dev/null +++ b/sh-utils-1.16-paths.patch @@ -0,0 +1,18 @@ +--- sh-utils-1.16/src/su.c.badpaths Mon Apr 14 14:26:55 1997 ++++ sh-utils-1.16/src/su.c Sun Aug 17 14:11:31 EDT 2003 +@@ -147,6 +147,15 @@ + #define DEFAULT_ROOT_LOGIN_PATH "/usr/ucb:/bin:/usr/bin:/etc" + #endif + ++/* The default paths which get set are both bogus and oddly influenced ++ by and -D on the commands line. Just to be clear, we'll set ++ these explicitly. -ewt */ ++#undef DEFAULT_LOGIN_PATH ++#undef DEFAULT_ROOT_LOGIN_PATH ++#define DEFAULT_LOGIN_PATH "/usr/local/bin:/bin:/usr/bin" ++#define DEFAULT_ROOT_LOGIN_PATH \ ++ "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" ++ + /* The shell to run if none is given in the user's passwd entry. */ + #define DEFAULT_SHELL "/bin/sh" + diff --git a/sh-utils-2.0.11-dateman.patch b/sh-utils-2.0.11-dateman.patch new file mode 100644 index 0000000..ff9ca67 --- /dev/null +++ b/sh-utils-2.0.11-dateman.patch @@ -0,0 +1,14 @@ +--- coreutils-5.92/man/date.1.dateman 2005-10-22 19:14:46.000000000 +0100 ++++ coreutils-5.92/man/date.1 2005-10-24 17:57:38.000000000 +0100 +@@ -188,6 +188,11 @@ + then an optional modifier, which is either + E to use the locale's alternate representations if available, or + O to use the locale's alternate numeric symbols if available. ++.SH ENVIRONMENT ++.TP ++TZ ++Specifies the timezone, unless overridden by command line parameters. ++If neither is specified, the setting from /etc/localtime is used. + .SH AUTHOR + Written by David MacKenzie. + .SH "REPORTING BUGS" diff --git a/sources b/sources index 0952ab1..4739176 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ -SHA512 (coreutils-9.9.tar.xz.sig) = 0a3dfdfa6b4234e2e1d42142269f959bdf3cf8f6605a50270a27eff84dd22588f182121f7dd3eeb04be45f5109d02690215065b3d3b43882874d0e165a1435d0 -SHA512 (coreutils-9.9.tar.xz) = e7b0e59f7732d2c098ea4934014f470248bd5c4764210e9200a698010a8e3b95bbb26e543f0cd73ed5a4b8e1f8cda932c73f39954d68175e4deaa47526610c65 +c9607d8495f16e98906e7ed2d9751a06 coreutils-6.9.tar.bz2 diff --git a/supported_utils b/supported_utils deleted file mode 100644 index 6db4fb5..0000000 --- a/supported_utils +++ /dev/null @@ -1,105 +0,0 @@ -%{_bindir}/arch -%{_bindir}/b2sum -%{_bindir}/basename -%{_bindir}/basenc -%{_bindir}/cat -%{_bindir}/chgrp -%{_bindir}/chmod -%{_bindir}/chown -%{_bindir}/cp -%{_bindir}/cut -%{_bindir}/date -%{_bindir}/dd -%{_bindir}/df -%{_bindir}/echo -%{_bindir}/env -%{_bindir}/false -%{_bindir}/link -%{_bindir}/ln -%{_bindir}/ls -%{_bindir}/mkdir -%{_bindir}/mknod -%{_bindir}/mv -%{_bindir}/nice -%{_bindir}/pwd -%{_bindir}/readlink -%{_bindir}/rm -%{_bindir}/rmdir -%{_bindir}/sleep -%{_bindir}/sort -%{_bindir}/stty -%{_bindir}/sync -%{_bindir}/mktemp -%{_bindir}/touch -%{_bindir}/true -%{_bindir}/uname -%{_bindir}/unlink -%{_bindir}/[ -%{_bindir}/base32 -%{_bindir}/base64 -%{_bindir}/chcon -%{_bindir}/cksum -%{_bindir}/comm -%{_bindir}/csplit -%{_bindir}/dir -%{_bindir}/dircolors -%{_bindir}/dirname -%{_bindir}/du -%{_bindir}/expand -%{_bindir}/expr -%{_bindir}/factor -%{_bindir}/fmt -%{_bindir}/fold -%{_bindir}/groups -%{_bindir}/head -%{_bindir}/hostid -%{_bindir}/id -%{_bindir}/install -%{_bindir}/join -%{_bindir}/logname -%{_bindir}/md5sum -%{_bindir}/mkfifo -%{_bindir}/nl -%{_bindir}/nohup -%{_bindir}/nproc -%{_bindir}/numfmt -%{_bindir}/od -%{_bindir}/paste -%{_bindir}/pathchk -%{_bindir}/pinky -%{_bindir}/pr -%{_bindir}/printenv -%{_bindir}/printf -%{_bindir}/ptx -%{_bindir}/realpath -%{_bindir}/runcon -%{_bindir}/seq -%{_bindir}/sha1sum -%{_bindir}/sha224sum -%{_bindir}/sha256sum -%{_bindir}/sha384sum -%{_bindir}/sha512sum -%{_bindir}/shred -%{_bindir}/shuf -%{_bindir}/split -%{_bindir}/stat -%{_bindir}/stdbuf -%{_bindir}/sum -%{_bindir}/tac -%{_bindir}/tail -%{_bindir}/tee -%{_bindir}/test -%{_bindir}/timeout -%{_bindir}/tr -%{_bindir}/truncate -%{_bindir}/tsort -%{_bindir}/tty -%{_bindir}/unexpand -%{_bindir}/uniq -%{_bindir}/users -%{_bindir}/vdir -%{_bindir}/wc -%{_bindir}/who -%{_bindir}/whoami -%{_bindir}/yes -%{_sbindir}/chroot diff --git a/upstream-key.gpg b/upstream-key.gpg new file mode 100644 index 0000000..dc6dc1d --- /dev/null +++ b/upstream-key.gpg @@ -0,0 +1,123 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.6 (GNU/Linux) + +mQGiBDftyYoRBACvICTt5AWe7kdbRtJ37IZ+ED5tBA/IbISfqUPO+HmL/J9JSfkV +QHbdQR5dj5mrU6BY5YOY7L4KOS6lH3AgvsZ/NhkDBraBPgnMkpDqFb7z4keCIebb +AmlcBL2VQNTo0Lczo319YoZ+UaNH53OddlBY944qBTa0AlcJuS1SgEp7pwCg+CUj +4SjVzqZh5lgPTS0bnYvF/n0D/iItZ7WAm37KW+9UjArWZD6NO+mVMNq4GWmhcSBD +uyJOZFxFQWXdFRdM9sNO7lkWYVCxpXyFzmQcBzdrAt+zx/3QadEbduGAqEKAROQU +gSDlMITWGK97/Cadn1YRSDcGKNlJX9jlJvt5Q/xh+CnJ8HTwO0PF9A5N/phFuMMB +UH0pA/0e5eIBsr2Wvxy39+nGnNv5b+5tHkGXSSHKyI7+zOdIBTtRQO7lwTG9ioKg +/yMqb9NCSf4GdyZiFJsQ+TWoSyk1bvFHt7YUOhTeii7Zgbk7Due2q+b9KzzyH/r2 +kf+fLh0lgiy/LfBhvsfO8M9dji3XDyZpBLRO6gda9M9NqzEfgbQfSmltIE1leWVy +aW5nIDxqaW1AbWV5ZXJpbmcubmV0PohGBBARAgAGBQI9TvsUAAoJENoowjp5/0R0 +NTIAn2qpRF9QVupw/gz4UN5d5MKurlOMAKDNXKfXzWClHRq5ufCdwZead3WMMYhG +BBARAgAGBQJCk1gpAAoJEIvYLm8wuUtcqlIAn0KbOC5YSkgqhfhM1uRlHnvHB74A +AJ4qbzrkw7iitd1CH1eoMoFiP5CI14hGBBARAgAGBQJDYmg2AAoJELk/YMa1xM4T +ct0AoJIkdqI6dhTUDOVwiZRxaCKVYaoNAJsG8I+OPhhRhe7ZgN5iN3xlRfkhTohG +BBARAgAGBQJECHuEAAoJEFQUZr6xLcGbUyQAnRmg070gGrZ5E4ZPJRqL/DUoB7hN +AKCj7uAIpcRdrBAQW8PKiOWcPRvxjohGBBIRAgAGBQI/bJ2IAAoJEA6nVrUUSEP1 +QXoAoJ6dMlvbJUep2l5N8G0XFmRyxTrIAJ0bn5IYu7RMxqI0vv6DHn2VgEQLeohG +BBIRAgAGBQI/vFVMAAoJENKUXDvBNlC2gtYAn1zlWvzZaC2lxRXuW7fMWpB/5uVJ +AJ9RFEFFzl8BktsnskYJUIvrx5zVL4hGBBMRAgAGBQI/UFjyAAoJEDhZwDsuI25H +z80An0G2Xm22lMc7ThGGgKeovGP0GzPIAKCHFH2aY2Dv6XOYomNB1yvW7MU0ZIhG +BBMRAgAGBQI/cfsiAAoJEA3cqjJ41SZOmcoAoKulkHQ6TUVORoSN77UYtrdCKy0I +AKC5qT7peM0Jd6I9wPLwc7Fc65xraIhGBBMRAgAGBQJAmOELAAoJEAu1FKXQbtaf +ysgAoL7Zl3BSH+/F9ouPCXkduzIywdx9AJ9OevRoJwxpER+SwSiLnw9Q7fVmcYhX +BBMRAgAXBQI66oJOBQsHCgMEAxUDAgMWAgECF4AACgkQ/dLerNMzy6HlawCg5UXJ +LGWj9P0SuJKcGm+mqKb1J2MAn3YrgB3duqFNs/yS4mvxM74TzI5miFoEExECABoF +CwcKAwQDFQMCAxYCAQIXgAIZAQUCOuqCTwAKCRD90t6s0zPLoaVVAJ0UZOyi+B+q +cNTEDSDrc3Oc1MzZrQCg0UONeu4Dv4N5ZLI6lZBMZETaCmKIXwQTEQIAFwUCOuqC +TgULBwoDBAMVAwIDFgIBAheAABIJEP3S3qzTM8uhB2VHUEcAAQHlawCg5UXJLGWj +9P0SuJKcGm+mqKb1J2MAn3YrgB3duqFNs/yS4mvxM74TzI5miGIEExECABoFCwcK +AwQDFQMCAxYCAQIXgAIZAQUCOuqCTwASCRD90t6s0zPLoQdlR1BHAAEBpVUAnRRk +7KL4H6pw1MQNIOtzc5zUzNmtAKDRQ4167gO/g3lksjqVkExkRNoKYrQfSmltIE1l +eWVyaW5nIDxtZXllcmluZ0BnbnUub3JnPohGBBARAgAGBQJCk1gsAAoJEIvYLm8w +uUtcHS0AoIO9LsaLdn6aH3fskRVZ4qhpRBXbAJ0drV2s3abBKhkhUui7kpF87MTD ++4hGBBARAgAGBQJDYmg8AAoJELk/YMa1xM4TdT4Ani/0ORxwCzqGT0+BG2thzbO7 +aFkuAKCoKP+u6WhYYOBdEcaM6T5QLN56H4hGBBARAgAGBQJECHuHAAoJEFQUZr6x +LcGbrKEAoLef0BqLLpNGhAFJKSAvWEWOiGcxAJ9w7F7MtsDoegKeQ44yYiPX5jEu +5ohGBBIRAgAGBQI/bJ2IAAoJEA6nVrUUSEP13sUAn3IWX1RWnH50v+DZKcqzCaSA +oqHbAKCVvtirU/A3FJLnuyIBv+lguddi2IhGBBIRAgAGBQI/vFVRAAoJENKUXDvB +NlC2D68AnAzm1iw0YSQ1GuPaU3lG8n72p5EBAJ4pNBP+RFWjvZSfcUYhZAFhq8CB +QYhGBBMRAgAGBQI/cfslAAoJEA3cqjJ41SZO8asAnRsJcSER+vpIIzM/et8PakIC +ZJxsAJ9LjdnHkb+Zr9YDXzKXu6OTiJvIh4hGBBMRAgAGBQJAmOEOAAoJEAu1FKXQ +btafLL8AoJask7aB+OfOQgS/kMlKXAA25Hl3AKC/3XJeRRR0ze508VcIhx7EhYVV +84heBBMRAgAeBQI/UFjBAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEP3S3qzT +M8uh8gwAoLfqQt7QgzavHlD44LxmAXovm5t0AJ4m8EQC+N9oJyODmpLbfQKNL6pq +zohmBBMRAgAeBQI/UFjBAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAABIJEP3S3qzT +M8uhB2VHUEcAAQHyDACgt+pC3tCDNq8eUPjgvGYBei+bm3QAnibwRAL432gnI4Oa +ktt9Ao0vqmrOtCFKaW0gTWV5ZXJpbmcgPG1leWVyaW5nQHBvYm94LmNvbT6IRgQQ +EQIABgUCQpNYLAAKCRCL2C5vMLlLXP7FAKCodISH72q8e30TxLwdoOh7hDjehACf +U97FCEOWICQaEI2BvOzGzn6yrO6IRgQQEQIABgUCQ2JoPAAKCRC5P2DGtcTOE0Gk +AJ43felw+/nxzJ7DVJYZ0tbASZ3BcACeNf2nXMkqkwrBZZ9DDMUGQ6tIB3GIRgQQ +EQIABgUCRAh7hwAKCRBUFGa+sS3Bm1nUAJ0foaMmGWqugETz37RZ2XpCfdQIlQCe +N50WxYPBxrGGmhhGOVbji1uhVSmIRgQSEQIABgUCP2ydiAAKCRAOp1a1FEhD9T73 +AJ4/51C6L0lHrX77DFXVJrB02yybsACgi/9TewF7HaF3x8fdMEZxsRK1HR+IRgQS +EQIABgUCP7xVUQAKCRDSlFw7wTZQtvjnAJ9FM83LyrTs2Dk/T7kOcSFTfjXqegCe +OlpOQ/sB4EtoHxrTSCy3OhToVsmIRgQTEQIABgUCP1BY+wAKCRA4WcA7LiNuR5yI +AJ9F3RsjjwtYX2rSx+j5o4+y4Dyl9wCfVR9uTBDLDP3kOaDrTT/H9XHTf6uIRgQT +EQIABgUCP3H7JQAKCRAN3KoyeNUmTv4eAJ9rCBUUXWYFUrjUayOenPULMW1BhACg +ncwdeTN+SGy8lX3zoo1vdNv+vTKIRgQTEQIABgUCQJjhDgAKCRALtRSl0G7WnyNP +AJ9Gn9yRup0zePUPMex36fX94o+i8wCggdDgtpKjzcaQ83o8VBiemFeiss+IXAQT +EQIAHAUCPjpzhwIbAwQLBwMCAxUCAwMWAgECHgECF4AACgkQ/dLerNMzy6FG5gCg +99D5pDqSRuZP2QJAT8LNiCZlRGgAn25OTXbNlHkM+gYFj0fyo+Ikj+T5iGQEExEC +ABwFAj46c4cCGwMECwcDAgMVAgMDFgIBAh4BAheAABIJEP3S3qzTM8uhB2VHUEcA +AQFG5gCg99D5pDqSRuZP2QJAT8LNiCZlRGgAn25OTXbNlHkM+gYFj0fyo+Ikj+T5 +tCJKaW0gTWV5ZXJpbmcgPG1leWVyaW5nQGFzY2VuZC5jb20+iEYEEBECAAYFAkKT +WCwACgkQi9gubzC5S1zwAQCgnPUCCl1g6eJdI5ZViACDiaaULAAAn19sIyQmkiaU +45QVcDtYuQTNSh/QiEYEEBECAAYFAkNiaDwACgkQuT9gxrXEzhP+igCfc526l8n/ +q8zVhIe9NonG+jVlrEoAnRXKebriKwmvVSdqbY8khlbJjB/ziEYEEBECAAYFAkQI +e4cACgkQVBRmvrEtwZs2owCgwzEOLdyXa2JGA/xkpBluqa8/UyMAnjZyxESMAj/A +2rUg3IvgtBmaetE4iEYEEhECAAYFAj+8VVEACgkQ0pRcO8E2ULaqIQCfQlbRoDOL +Hv+9YVxPgD8yhwFB850AnRTmAG4Z57YD92s4o1ne9sgaufmdiEYEExECAAYFAj9Q +WPsACgkQOFnAOy4jbkfOoQCgwfC1mkANwR+vv9TVlYkmoZ6wNL8An0dql+uy5ic1 +YpyKfV7g7MMuEMDwiEYEExECAAYFAj9x+yUACgkQDdyqMnjVJk6QCwCglS7PPvFR +HoOZxl7XgpVbAK6vZQgAniVxncBgSu06lmsDNHiJpiDMIZkkiEYEExECAAYFAkCY +4Q4ACgkQC7UUpdBu1p+QqwCeNzsozeUjiCFQBBiR+gCBnvZhQqgAnj4ImXyp45hs +fc3dZHP3qB1Ws5UjiFUEExECABUFAjftyYoDCwoDAxUDAgMWAgECF4AACgkQ/dLe +rNMzy6HnugCePkbs7JcEo0837WNqdoGf2WXL3vIAoK0cStFCa4zj4FV/SoG9cDZP +JOzfiF0EExECABUFAjftyYoDCwoDAxUDAgMWAgECF4AAEgkQ/dLerNMzy6EHZUdQ +RwABAee6AJ4+RuzslwSjTzftY2p2gZ/ZZcve8gCgrRxK0UJrjOPgVX9Kgb1wNk8k +7N+0IkppbSBNZXllcmluZyA8bWV5ZXJpbmdAbHVjZW50LmNvbT6IRQQTEQIABgUC +QJjhDgAKCRALtRSl0G7Wn/YLAJdAhf8twtaImmHzRT7eaUIf0b4+AJ9hRfAjWrRp +UF5cW5AzZsVwEW7Vc4hGBBARAgAGBQJCk1gsAAoJEIvYLm8wuUtceyMAoJGYrqPm +T+ThNBRLt5aIq/p3yBHmAJ0V0tEMjdIafWlY6IDZkst2VXBPFohGBBARAgAGBQJD +Ymg8AAoJELk/YMa1xM4TTxEAnAtkRTdyDNdPn5kW3HMKcQp9S02vAJ9wiBJbBeaB +jGcQ4zoafo0vw8ZMi4hGBBARAgAGBQJECHuHAAoJEFQUZr6xLcGbZi4AoK2Th3Pi +pC+CWdYDCA9qNa+uUkHsAKCHUU/oOSEqvjEHoYs22RZzVGbbVohGBBIRAgAGBQI/ +vFVRAAoJENKUXDvBNlC2qQ0An3hiEeuqRgzbuY6YLqiA9FH0GHEEAJ4j2O8AjZFq +Vc8RL32KA6nuwfJ28ohGBBMRAgAGBQI/UFj7AAoJEDhZwDsuI25HPicAoJOlcGaT +t5dvksbBg00BNCyZl8odAJ0UCIFlFzzB/x050scZKMrvquc2T4hGBBMRAgAGBQI/ +cfslAAoJEA3cqjJ41SZO5mQAoLTvGtjJxspvgEg3z3T/q6iI/FdxAJ4wgnqQjRvm +AHAWMibcDupPA10u+ohVBBMRAgAVBQI37e/HAwsKAwMVAwIDFgIBAheAAAoJEP3S +3qzTM8uh8vAAn23cUtWPdFr4wIwUNo9bsY1CUHMNAKCoHS3nayqM/WUfihcZJoOs +kQA22ohdBBMRAgAVBQI37e/HAwsKAwMVAwIDFgIBAheAABIJEP3S3qzTM8uhB2VH +UEcAAQHy8ACfbdxS1Y90WvjAjBQ2j1uxjUJQcw0AoKgdLedrKoz9ZR+KFxkmg6yR +ADbatCdKaW0gTWV5ZXJpbmcgPG1leWVyaW5nQG5hLW5ldC5vcm5sLmdvdj6IRgQQ +EQIABgUCPU77FAAKCRDaKMI6ef9EdBjQAJ41hqQaE3W2dHgN9otb7fL0n6U1YACg +kI9DvFQ1YmpLI8jdGwbDxDodAeOIRgQQEQIABgUCQpNYLAAKCRCL2C5vMLlLXMrg +AJ90LwV+nd+U4GEvzYixFvksHvtFGgCggD3NDeGXlgUhPB+nqyBq2QKfZxKIRgQQ +EQIABgUCQ2JoPAAKCRC5P2DGtcTOE4WfAJ4uxTyLyO4NCBk/IlTM0NAKLFHJgwCc +DP0YQC0oDm5uJ8/ZIkl0MUrzKXGIRgQQEQIABgUCRAh7hwAKCRBUFGa+sS3BmyTW +AJ4+X1CGNorq+Nme5tTIVskgYKH7wQCcD7UpPt2+r+NcGSYftkKk3O8R8TKIRgQS +EQIABgUCP7xVUQAKCRDSlFw7wTZQtolWAJ98yLyyC6jzrF/YG5kqeGqHSNdKtQCd +EdCDkGG09QJX8gFfZ/r8lWlflj+IRgQTEQIABgUCP1BY+wAKCRA4WcA7LiNuR4mz +AKC/1XBB9cBCs8X/KvoLLQP75q0i2QCbBb0UoVSUYgsdETzujbTwg+0HLseIRgQT +EQIABgUCP3H7JQAKCRAN3KoyeNUmTql1AJsEhcfoOC2U4JjHR6rWzqinaIxcNgCg +lmdHMQ3L8zCfNzD7lehquPy2P0eIRgQTEQIABgUCQJjhDgAKCRALtRSl0G7Wn+1r +AJ4nUVrAEtL+XBp2UU1QmVCxa7lcSwCfT8ds7xZ++aZomPK2Xvz230WnUsGIVQQT +EQIAFQUCN+3v9gMLCgMDFQMCAxYCAQIXgAAKCRD90t6s0zPLocAwAKCJ4wBEND4W +mzs6Sp47mWBsp96HRACfTH+SGkDfLqgkZ7JgEgzSDKGl4TyIXQQTEQIAFQUCN+3v +9gMLCgMDFQMCAxYCAQIXgAASCRD90t6s0zPLoQdlR1BHAAEBwDAAoInjAEQ0Phab +OzpKnjuZYGyn3odEAJ9Mf5IaQN8uqCRnsmASDNIMoaXhPLkBDQQ37cmSEAQAx3xz +BZlJikWJaiZGru3cEKYYnRFp8No2b4jhBwY9nKn8UIxuY5aQN4ka/k81wqjlC6cT +wn5R7kg2ha8eGXpwYhKGwn5MGvIxqfoj2tsQ76uluTowHA4seoavi7RGEDzm4Vpt +8Nua8krrZ2QPtLA86gkzL1QG5Bbv/o2Ldx8HHNcAAwcEAKcK2tj2X8RPgUarczXv +rdXMteeSFnI7fagbLpEfaTI2xa1ADLg5UO4M9Erz9m6k6xV6loxcBB9H5Ljm9GWf +el4T4p1lwzi3Lu5hKzIiFs+5vsy+fyEai4e5f6v9Ww3Q3Ec6UZpPZGyN+PDPlZxe +rf3ZIMogSGrrEBhprhLHReudiE4EGBECAAYFAjftyZIAEgkQ/dLerNMzy6EHZUdQ +RwABAQXiAKCilmALgD6mhccl4ISaUB5LfW74BQCgqd7wIfbV2+NKqf1Yuj75sryW +Ke4= +=zRdO +-----END PGP PUBLIC KEY BLOCK-----