diff --git a/coreutils-i18n.patch b/coreutils-i18n.patch index 2d56736..731ca3f 100644 --- a/coreutils-i18n.patch +++ b/coreutils-i18n.patch @@ -23,63 +23,6 @@ diff -urNp coreutils-8.0-orig/lib/linebuffer.h coreutils-8.0/lib/linebuffer.h }; /* Initialize linebuffer LINEBUFFER for use. */ -diff -urNp coreutils-8.0-orig/lib/linebuffer.h.orig coreutils-8.0/lib/linebuffer.h.orig ---- coreutils-8.0-orig/lib/linebuffer.h.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/lib/linebuffer.h.orig 2009-10-06 10:59:48.000000000 +0200 -@@ -0,0 +1,53 @@ -+/* linebuffer.h -- declarations for reading arbitrarily long lines -+ -+ Copyright (C) 1986, 1991, 1998, 1999, 2002, 2003, 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 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 !defined LINEBUFFER_H -+# define LINEBUFFER_H -+ -+# include -+ -+/* A `struct linebuffer' holds a line of text. */ -+ -+struct linebuffer -+{ -+ size_t size; /* Allocated. */ -+ size_t length; /* Used. */ -+ char *buffer; -+}; -+ -+/* Initialize linebuffer LINEBUFFER for use. */ -+void initbuffer (struct linebuffer *linebuffer); -+ -+/* Read an arbitrarily long line of text from STREAM into LINEBUFFER. -+ Consider lines to be terminated by DELIMITER. -+ Keep the delimiter; append DELIMITER if we reach EOF and it wasn't -+ the last character in the file. Do not NUL-terminate. -+ Return LINEBUFFER, except at end of file return NULL. */ -+struct linebuffer *readlinebuffer_delim (struct linebuffer *linebuffer, -+ FILE *stream, char delimiter); -+ -+/* Read an arbitrarily long line of text from STREAM into LINEBUFFER. -+ Keep the newline; append a newline if it's the last line of a file -+ that ends in a non-newline character. Do not NUL-terminate. -+ Return LINEBUFFER, except at end of file return NULL. */ -+struct linebuffer *readlinebuffer (struct linebuffer *linebuffer, FILE *stream); -+ -+/* Free linebuffer LINEBUFFER and its data, all allocated with malloc. */ -+void freebuffer (struct linebuffer *); -+ -+#endif /* LINEBUFFER_H */ diff -urNp coreutils-8.0-orig/src/cut.c coreutils-8.0/src/cut.c --- coreutils-8.0-orig/src/cut.c 2009-09-23 10:25:44.000000000 +0200 +++ coreutils-8.0/src/cut.c 2009-10-07 10:07:16.000000000 +0200 @@ -673,12266 +616,2671 @@ diff -urNp coreutils-8.0-orig/src/cut.c coreutils-8.0/src/cut.c } if (optind == argc) -diff -urNp coreutils-8.0-orig/src/cut.c.orig coreutils-8.0/src/cut.c.orig ---- coreutils-8.0-orig/src/cut.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/cut.c.orig 2009-09-23 10:25:44.000000000 +0200 -@@ -0,0 +1,893 @@ -+/* cut - remove parts of lines of files -+ Copyright (C) 1997-2009 Free Software Foundation, Inc. -+ Copyright (C) 1984 David M. Ihnat -+ -+ 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 . */ -+ -+/* Written by David Ihnat. */ -+ -+/* POSIX changes, bug fixes, long-named options, and cleanup -+ by David MacKenzie . +diff -urNp coreutils-8.0-orig/src/expand.c coreutils-8.0/src/expand.c +--- coreutils-8.0-orig/src/expand.c 2009-09-29 15:27:54.000000000 +0200 ++++ coreutils-8.0/src/expand.c 2009-10-07 10:07:16.000000000 +0200 +@@ -37,11 +37,28 @@ + #include + #include + #include + -+ Rewrite cut_fields and cut_bytes -- Jim Meyering. */ ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif + -+#include + #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 + -+#include -+#include -+#include -+#include -+#include "system.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 + -+#include "error.h" -+#include "getndelim2.h" -+#include "hash.h" -+#include "quote.h" -+#include "xstrndup.h" + /* The official name of this program (e.g., no `g' prefix). */ + #define PROGRAM_NAME "expand" + +@@ -357,6 +374,142 @@ expand (void) + } + } + ++#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. */ + -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "cut" ++ fp = next_file ((FILE *) NULL); ++ if (fp == NULL) ++ return; + -+#define AUTHORS \ -+ proper_name ("David M. Ihnat"), \ -+ proper_name ("David MacKenzie"), \ -+ proper_name ("Jim Meyering") ++ memset (&o_state, '\0', sizeof(mbstate_t)); ++ memset (&i_state, '\0', sizeof(mbstate_t)); + -+#define FATAL_ERROR(Message) \ -+ do \ -+ { \ -+ error (0, 0, (Message)); \ -+ usage (EXIT_FAILURE); \ -+ } \ -+ while (0) ++ 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; ++ } + -+/* Append LOW, HIGH to the list RP of range pairs, allocating additional -+ space if necessary. Update local variable N_RP. When allocating, -+ update global variable N_RP_ALLOCATED. */ -+ -+#define ADD_RANGE_PAIR(rp, low, high) \ -+ do \ -+ { \ -+ if (low == 0 || high == 0) \ -+ FATAL_ERROR (_("fields and positions are numbered from 1")); \ -+ if (n_rp >= n_rp_allocated) \ -+ { \ -+ (rp) = X2NREALLOC (rp, &n_rp_allocated); \ -+ } \ -+ rp[n_rp].lo = (low); \ -+ rp[n_rp].hi = (high); \ -+ ++n_rp; \ -+ } \ -+ while (0) ++ /* No character is left in BUF. */ ++ if (buflen < 1) ++ { ++ fp = next_file (fp); + -+struct range_pair -+ { -+ size_t lo; -+ size_t hi; -+ }; -+ -+/* 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 -+ first field must be read into this buffer to determine whether it -+ is followed by a delimiter or a newline before any of it may be -+ output. Otherwise, cut_fields can do the job without using this -+ buffer. */ -+static char *field_1_buffer; -+ -+/* The number of bytes allocated for FIELD_1_BUFFER. */ -+static size_t field_1_bufsize; -+ -+/* The largest field or byte 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. */ -+static size_t max_range_endpoint; -+ -+/* If nonzero, this is the index of the first field in a range that goes -+ to end of line. */ -+static size_t eol_range_start; -+ -+/* This is a bit vector. -+ In byte mode, which bytes to output. -+ In field mode, which DELIM-separated fields to output. -+ Both bytes 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 -+ (K <= MAX_RANGE_ENDPOINT and is_printable_field(K)) -+ || (EOL_RANGE_START > 0 && K >= EOL_RANGE_START). */ -+static unsigned char *printable_field; ++ if (fp == NULL) ++ break; /* No more files. */ ++ else ++ { ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ continue; ++ } ++ } + -+enum operating_mode -+ { -+ undefined_mode, ++ /* Get a wide character. */ ++ i_state_bak = i_state; ++ mblength = mbrtowc (&wc, bufpos, buflen, &i_state); + -+ /* Output characters that are in the given bytes. */ -+ byte_mode, ++ 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; + -+ /* Output the given delimeter-separated fields. */ -+ field_mode -+ }; ++ case 0: /* null. */ ++ mblength = 1; ++ if (convert && convert_entire_line == 0) ++ convert = 0; ++ putchar ('\0'); ++ break; + -+static enum operating_mode operating_mode; ++ 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; + -+/* If true do not output lines containing no delimeter characters. -+ Otherwise, all such lines are printed. This option is valid only -+ with field mode. */ -+static bool suppress_non_delimited; ++ 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. */ + -+/* If nonzero, print all bytes, characters, or fields _except_ -+ those that were specified. */ -+static bool complement; ++ 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 + -+/* The delimeter character for field mode. */ -+static unsigned char delim; + int + main (int argc, char **argv) + { +@@ -421,7 +574,12 @@ main (int argc, char **argv) + + 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, "-"); +diff -urNp coreutils-8.0-orig/src/fold.c coreutils-8.0/src/fold.c +--- coreutils-8.0-orig/src/fold.c 2009-09-23 10:25:44.000000000 +0200 ++++ coreutils-8.0/src/fold.c 2009-10-07 10:07:16.000000000 +0200 +@@ -22,11 +22,33 @@ + #include + #include + ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif + -+/* True if the --output-delimiter=STRING option was specified. */ -+static bool output_delimiter_specified; ++/* Get iswprint(), iswblank(), wcwidth(). */ ++#if HAVE_WCTYPE_H ++# include ++#endif + -+/* The length of output_delimiter_string. */ -+static size_t output_delimiter_length; + #include "system.h" + #include "error.h" + #include "quote.h" + #include "xstrtol.h" + ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# undef MB_LEN_MAX ++# define MB_LEN_MAX 16 ++#endif + -+/* The output field separator string. Defaults to the 1-character -+ string consisting of the input delimiter. */ -+static char *output_delimiter_string; ++/* 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 + -+/* True if we have ever read standard input. */ -+static bool have_read_stdin; + #define TAB_WIDTH 8 + + /* The official name of this program (e.g., no `g' prefix). */ +@@ -34,20 +56,41 @@ + + #define AUTHORS proper_name ("David MacKenzie") + ++#define FATAL_ERROR(Message) \ ++ do \ ++ { \ ++ error (0, 0, (Message)); \ ++ usage (2); \ ++ } \ ++ while (0) + -+#define HT_RANGE_START_INDEX_INITIAL_CAPACITY 31 ++enum operating_mode ++{ ++ /* Fold texts by columns that are at the given positions. */ ++ column_mode, + -+/* The set of range-start indices. For example, given a range-spec list like -+ `-b1,3-5,4-9,15-', the following indices will be recorded here: 1, 3, 15. -+ Note that although `4' looks like a range-start index, it is in the middle -+ of the `3-5' range, so it doesn't count. -+ This table is created/used IFF output_delimiter_specified is set. */ -+static Hash_table *range_start_ht; ++ /* Fold texts by bytes that are at the given positions. */ ++ byte_mode, + -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ OUTPUT_DELIMITER_OPTION = CHAR_MAX + 1, -+ COMPLEMENT_OPTION ++ /* Fold texts by characters that are at the given positions. */ ++ character_mode, +}; + -+static struct option const longopts[] = -+{ -+ {"bytes", required_argument, NULL, 'b'}, -+ {"characters", required_argument, NULL, 'c'}, -+ {"fields", required_argument, NULL, 'f'}, -+ {"delimiter", required_argument, NULL, 'd'}, -+ {"only-delimited", no_argument, NULL, 's'}, -+ {"output-delimiter", required_argument, NULL, OUTPUT_DELIMITER_OPTION}, -+ {"complement", no_argument, NULL, COMPLEMENT_OPTION}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s OPTION... [FILE]...\n\ -+"), -+ program_name); -+ fputs (_("\ -+Print selected parts of lines from each FILE to standard output.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ -b, --bytes=LIST select only these bytes\n\ -+ -c, --characters=LIST select only these characters\n\ -+ -d, --delimiter=DELIM use DELIM instead of TAB for field delimiter\n\ -+"), stdout); -+ fputs (_("\ -+ -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\ -+"), stdout); -+ fputs (_("\ -+ --complement complement the set of selected bytes, characters\n\ -+ or fields\n\ -+"), stdout); -+ fputs (_("\ -+ -s, --only-delimited do not print lines not containing delimiters\n\ -+ --output-delimiter=STRING use STRING as the output delimiter\n\ -+ the default is to use the input delimiter\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+Use one, and only one of -b, -c or -f. Each LIST is made up of one\n\ -+range, or many ranges separated by commas. Selected input is written\n\ -+in the same order that it is read, and is written exactly once.\n\ -+"), stdout); -+ fputs (_("\ -+Each range is one of:\n\ -+\n\ -+ N N'th byte, character or field, counted from 1\n\ -+ N- from N'th byte, character or field, to end of line\n\ -+ N-M from N'th to M'th (included) byte, character or field\n\ -+ -M from first to M'th (included) byte, character or field\n\ -+\n\ -+With no FILE, or when FILE is -, read standard input.\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+static inline void -+mark_range_start (size_t i) -+{ -+ /* Record the fact that `i' is a range-start index. */ -+ void *ent_from_table = hash_insert (range_start_ht, (void*) i); -+ if (ent_from_table == NULL) -+ { -+ /* Insertion failed due to lack of memory. */ -+ xalloc_die (); -+ } -+ assert ((size_t) ent_from_table == i); -+} ++/* The argument shows current mode. (Default: column_mode) */ ++static enum operating_mode operating_mode; + -+static inline void -+mark_printable_field (size_t i) -+{ -+ size_t n = i / CHAR_BIT; -+ printable_field[n] |= (1 << (i % CHAR_BIT)); -+} + /* If nonzero, try to break on whitespace. */ + static bool break_spaces; + +-/* If nonzero, count bytes, not column positions. */ +-static bool count_bytes; +- + /* If nonzero, at least one of the files we read was standard input. */ + static bool have_read_stdin; + +-static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::"; ++static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::"; + + static struct option const longopts[] = + { + {"bytes", no_argument, NULL, 'b'}, ++ {"characters", no_argument, NULL, 'c'}, + {"spaces", no_argument, NULL, 's'}, + {"width", required_argument, NULL, 'w'}, + {GETOPT_HELP_OPTION_DECL}, +@@ -77,6 +120,7 @@ Mandatory arguments to long options are + "), stdout); + fputs (_("\ + -b, --bytes count bytes rather than columns\n\ ++ -c, --characters count characters rather than columns\n\ + -s, --spaces break at spaces\n\ + -w, --width=WIDTH use WIDTH columns instead of 80\n\ + "), stdout); +@@ -94,7 +138,7 @@ Mandatory arguments to long options are + static size_t + adjust_column (size_t column, char c) + { +- if (!count_bytes) ++ if (operating_mode != byte_mode) + { + if (c == '\b') + { +@@ -117,30 +161,14 @@ adjust_column (size_t column, char c) + 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) + { +@@ -168,6 +196,15 @@ fold_file (char const *filename, size_t + 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; ++ } + -+static inline bool -+is_printable_field (size_t i) -+{ -+ size_t n = i / CHAR_BIT; -+ return (printable_field[n] >> (i % CHAR_BIT)) & 1; + /* Look for the last blank. */ + while (logical_end) + { +@@ -214,11 +251,222 @@ fold_file (char const *filename, size_t + line_out[offset_out++] = c; + } + +- saved_errno = errno; ++ *saved_errno = errno; + + if (offset_out) + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + +} + -+static size_t -+hash_int (const void *x, size_t tablesize) ++#if HAVE_MBRTOWC ++static void ++fold_multibyte_text (FILE *istream, size_t width, int *saved_errno) +{ -+#ifdef UINTPTR_MAX -+ uintptr_t y = (uintptr_t) x; -+#else -+ size_t y = (size_t) x; -+#endif -+ return y % tablesize; -+} ++ 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 = NULL; /* 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. */ + -+static bool -+hash_compare_ints (void const *x, void const *y) -+{ -+ return (x == y) ? true : false; -+} ++ static char *line_out = NULL; ++ size_t offset_out = 0; /* Index in `line_out' for next char. */ ++ static size_t allocated_out = 0; + -+static bool -+is_range_start_index (size_t i) -+{ -+ return hash_lookup (range_start_ht, (void *) i) ? true : false; -+} ++ int increment; ++ size_t column = 0; + -+/* Return nonzero if the K'th field or byte is printable. -+ When returning nonzero, if RANGE_START is non-NULL, -+ set *RANGE_START to true if K is the beginning of a range, and to -+ false otherwise. */ ++ size_t last_blank_pos; ++ size_t last_blank_column; ++ int is_blank_seen; ++ int last_blank_increment = 0; ++ int is_bs_following_last_blank; ++ size_t bs_following_last_blank_num; ++ int is_cr_after_last_blank; + -+static bool -+print_kth (size_t k, bool *range_start) -+{ -+ bool k_selected -+ = ((0 < eol_range_start && eol_range_start <= k) -+ || (k <= max_range_endpoint && is_printable_field (k))); ++#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) + -+ bool is_selected = k_selected ^ complement; -+ if (range_start && is_selected) -+ *range_start = is_range_start_index (k); ++#define START_NEW_LINE \ ++ do \ ++ { \ ++ putchar ('\n'); \ ++ column = 0; \ ++ offset_out = 0; \ ++ CLEAR_FLAGS; \ ++ } \ ++ while (0) + -+ return is_selected; -+} ++ CLEAR_FLAGS; ++ memset (&state, '\0', sizeof(mbstate_t)); + -+/* Comparison function for qsort to order the list of -+ struct range_pairs. */ -+static int -+compare_ranges (const void *a, const void *b) -+{ -+ int a_start = ((const struct range_pair *) a)->lo; -+ int b_start = ((const struct range_pair *) b)->lo; -+ return a_start < b_start ? -1 : a_start > b_start; -+} ++ 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; ++ } + -+/* Given the list of field or byte range specifications FIELDSTR, set -+ MAX_RANGE_ENDPOINT and allocate and initialize the PRINTABLE_FIELD -+ array. If there is a right-open-ended range, set EOL_RANGE_START -+ to its starting index. FIELDSTR should be composed of one or more -+ numbers or ranges of numbers, separated by blanks or commas. -+ Incomplete ranges may be given: `-m' means `1-m'; `n-' means `n' -+ through end of line. Return true if FIELDSTR contains at least -+ one field specification, false otherwise. */ -+ -+/* FIXME-someday: What if the user wants to cut out the 1,000,000-th -+ field of some huge input file? This function shouldn't have to -+ allocate a table of a million bits just so we can test every -+ field < 10^6 with an array dereference. Instead, consider using -+ an adaptive approach: if the range of selected fields is too large, -+ but only a few fields/byte-offsets are actually selected, use a -+ hash table. If the range of selected fields is too large, and -+ too many are selected, then resort to using the range-pairs (the -+ `rp' array) directly. */ ++ if (buflen < 1) ++ break; + -+static bool -+set_fields (const char *fieldstr) -+{ -+ size_t initial = 1; /* Value of first number in a range. */ -+ size_t value = 0; /* If nonzero, a number being accumulated. */ -+ bool lhs_specified = false; -+ bool rhs_specified = false; -+ bool dash_found = false; /* True if a '-' is found in this field. */ -+ bool field_found = false; /* True if at least one field spec -+ has been processed. */ -+ -+ struct range_pair *rp = NULL; -+ size_t n_rp = 0; -+ size_t n_rp_allocated = 0; -+ size_t i; -+ bool in_digits = false; -+ -+ /* Collect and store in RP the range end points. -+ It also sets EOL_RANGE_START if appropriate. */ ++ /* Get a wide character. */ ++ convfail = 0; ++ state_bak = state; ++ mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state); + -+ for (;;) -+ { -+ if (*fieldstr == '-') ++ switch (mblength) + { -+ in_digits = false; -+ /* Starting a range. */ -+ if (dash_found) -+ FATAL_ERROR (_("invalid byte or field list")); -+ dash_found = true; -+ fieldstr++; -+ -+ initial = (lhs_specified ? value : 1); -+ value = 0; ++ case (size_t)-1: ++ case (size_t)-2: ++ convfail++; ++ state = state_bak; ++ /* Fall through. */ ++ ++ case 0: ++ mblength = 1; ++ break; + } -+ else if (*fieldstr == ',' || -+ isblank (to_uchar (*fieldstr)) || *fieldstr == '\0') ++ ++rescan: ++ if (operating_mode == byte_mode) /* byte mode */ ++ increment = mblength; ++ else if (operating_mode == character_mode) /* character mode */ ++ increment = 1; ++ else /* column mode */ + { -+ in_digits = false; -+ /* Ending the string, or this field/byte sublist. */ -+ if (dash_found) ++ if (convfail) ++ increment = 1; ++ else + { -+ dash_found = false; -+ -+ if (!lhs_specified && !rhs_specified) -+ FATAL_ERROR (_("invalid range with no endpoint: -")); -+ -+ /* A range. Possibilities: -n, m-n, n-. -+ In any case, `initial' contains the start of the range. */ -+ if (!rhs_specified) -+ { -+ /* `n-'. From `initial' to end of line. */ -+ eol_range_start = initial; -+ field_found = true; -+ } -+ else ++ switch (wc) + { -+ /* `m-n' or `-n' (1-n). */ -+ if (value < initial) -+ FATAL_ERROR (_("invalid decreasing range")); ++ case L'\n': ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ continue; ++ ++ case L'\b': ++ increment = (column > 0) ? -1 : 0; ++ break; + -+ /* Is there already a range going to end of line? */ -+ if (eol_range_start != 0) -+ { -+ /* Yes. Is the new sequence already contained -+ in the old one? If so, no processing is -+ necessary. */ -+ if (initial < eol_range_start) -+ { -+ /* No, the new sequence starts before the -+ old. Does the old range going to end of line -+ extend into the new range? */ -+ if (eol_range_start <= value) -+ { -+ /* Yes. Simply move the end of line marker. */ -+ eol_range_start = initial; -+ } -+ else -+ { -+ /* No. A simple range, before and disjoint from -+ the range going to end of line. Fill it. */ -+ ADD_RANGE_PAIR (rp, initial, value); -+ } ++ case L'\r': ++ increment = -1 * column; ++ break; + -+ /* In any case, some fields were selected. */ -+ field_found = true; -+ } -+ } -+ else -+ { -+ /* There is no range going to end of line. */ -+ ADD_RANGE_PAIR (rp, initial, value); -+ field_found = true; -+ } -+ value = 0; -+ } -+ } -+ else -+ { -+ /* A simple field number, not a range. */ -+ ADD_RANGE_PAIR (rp, value, value); -+ value = 0; -+ field_found = true; -+ } ++ case L'\t': ++ increment = 8 - column % 8; ++ break; + -+ if (*fieldstr == '\0') -+ { -+ break; ++ default: ++ increment = wcwidth (wc); ++ increment = (increment < 0) ? 0 : increment; ++ } + } -+ -+ fieldstr++; -+ lhs_specified = false; -+ rhs_specified = false; + } -+ else if (ISDIGIT (*fieldstr)) -+ { -+ /* Record beginning of digit string, in case we have to -+ complain about it. */ -+ static char const *num_start; -+ if (!in_digits || !num_start) -+ num_start = fieldstr; -+ in_digits = true; -+ -+ if (dash_found) -+ rhs_specified = 1; -+ else -+ lhs_specified = 1; + -+ /* Detect overflow. */ -+ if (!DECIMAL_DIGIT_ACCUMULATE (value, *fieldstr - '0', size_t)) -+ { -+ /* In case the user specified -c$(echo 2^64|bc),22, -+ complain only about the first number. */ -+ /* Determine the length of the offending number. */ -+ size_t len = strspn (num_start, "0123456789"); -+ char *bad_num = xstrndup (num_start, len); -+ if (operating_mode == byte_mode) -+ error (0, 0, -+ _("byte offset %s is too large"), quote (bad_num)); -+ else -+ error (0, 0, -+ _("field number %s is too large"), quote (bad_num)); -+ free (bad_num); -+ exit (EXIT_FAILURE); -+ } -+ -+ fieldstr++; -+ } -+ else -+ FATAL_ERROR (_("invalid byte or field list")); -+ } -+ -+ max_range_endpoint = 0; -+ for (i = 0; i < n_rp; i++) -+ { -+ if (rp[i].hi > max_range_endpoint) -+ max_range_endpoint = rp[i].hi; -+ } -+ -+ /* Allocate an array large enough so that it may be indexed by -+ the field numbers corresponding to all finite ranges -+ (i.e. `2-6' or `-4', but not `5-') in FIELDSTR. */ -+ -+ printable_field = xzalloc (max_range_endpoint / CHAR_BIT + 1); -+ -+ qsort (rp, n_rp, sizeof (rp[0]), compare_ranges); -+ -+ /* Set the array entries corresponding to integers in the ranges of RP. */ -+ for (i = 0; i < n_rp; i++) -+ { -+ size_t j; -+ size_t rsi_candidate; -+ -+ /* Record the range-start indices, i.e., record each start -+ index that is not part of any other (lo..hi] range. */ -+ rsi_candidate = complement ? rp[i].hi + 1 : rp[i].lo; -+ if (output_delimiter_specified -+ && !is_printable_field (rsi_candidate)) -+ mark_range_start (rsi_candidate); -+ -+ for (j = rp[i].lo; j <= rp[i].hi; j++) -+ mark_printable_field (j); -+ } -+ -+ if (output_delimiter_specified -+ && !complement -+ && eol_range_start && !is_printable_field (eol_range_start)) -+ mark_range_start (eol_range_start); -+ -+ free (rp); -+ -+ return field_found; -+} -+ -+/* Read from stream STREAM, printing to standard output any selected bytes. */ -+ -+static void -+cut_bytes (FILE *stream) -+{ -+ size_t byte_idx; /* Number of bytes in the line so far. */ -+ /* 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; -+ -+ byte_idx = 0; -+ print_delimiter = false; -+ while (1) -+ { -+ int c; /* Each character from the file. */ -+ -+ c = getc (stream); -+ -+ if (c == '\n') ++ if (column + increment > width && break_spaces && last_blank_pos) + { ++ fwrite (line_out, sizeof(char), last_blank_pos, stdout); + putchar ('\n'); -+ byte_idx = 0; -+ print_delimiter = false; -+ } -+ else if (c == EOF) -+ { -+ if (byte_idx > 0) -+ putchar ('\n'); -+ break; ++ ++ 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; + } -+ else ++ ++ if (column + increment > width && column != 0) + { -+ bool range_start; -+ bool *rs = output_delimiter_specified ? &range_start : NULL; -+ if (print_kth (++byte_idx, rs)) -+ { -+ if (rs && *rs && print_delimiter) -+ { -+ fwrite (output_delimiter_string, sizeof (char), -+ output_delimiter_length, stdout); -+ } -+ print_delimiter = true; -+ putchar (c); -+ } ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ goto rescan; + } -+ } -+} -+ -+/* Read from stream STREAM, printing to standard output any selected fields. */ -+ -+static void -+cut_fields (FILE *stream) -+{ -+ int c; -+ size_t field_idx = 1; -+ bool found_any_selected_field = false; -+ bool buffer_first_field; -+ -+ c = getc (stream); -+ if (c == EOF) -+ return; -+ -+ ungetc (c, stream); -+ -+ /* 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) ++ if (allocated_out < offset_out + mblength) + { -+ ssize_t len; -+ size_t n_bytes; -+ -+ len = getndelim2 (&field_1_buffer, &field_1_bufsize, 0, -+ GETNLINE_NO_LIMIT, delim, '\n', stream); -+ if (len < 0) -+ { -+ free (field_1_buffer); -+ field_1_buffer = NULL; -+ if (ferror (stream) || feof (stream)) -+ break; -+ xalloc_die (); -+ } -+ -+ n_bytes = len; -+ assert (n_bytes != 0); -+ -+ /* 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 (to_uchar (field_1_buffer[n_bytes - 1]) != delim) -+ { -+ if (suppress_non_delimited) -+ { -+ /* Empty. */ -+ } -+ else -+ { -+ fwrite (field_1_buffer, sizeof (char), n_bytes, stdout); -+ /* Make sure the output line is newline terminated. */ -+ if (field_1_buffer[n_bytes - 1] != '\n') -+ putchar ('\n'); -+ } -+ continue; -+ } -+ if (print_kth (1, NULL)) -+ { -+ /* Print the field, but not the trailing delimiter. */ -+ fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout); -+ found_any_selected_field = true; -+ } -+ ++field_idx; ++ line_out = X2REALLOC (line_out, &allocated_out); + } + -+ if (c != EOF) -+ { -+ 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 = true; ++ memcpy (line_out + offset_out, bufpos, mblength); ++ offset_out += mblength; ++ column += increment; + -+ while ((c = getc (stream)) != delim && c != '\n' && c != EOF) -+ { -+ putchar (c); -+ } -+ } -+ else -+ { -+ while ((c = getc (stream)) != delim && c != '\n' && c != EOF) -+ { -+ /* Empty. */ -+ } -+ } -+ } ++ if (is_blank_seen && !convfail && wc == L'\r') ++ is_cr_after_last_blank = 1; + -+ if (c == '\n') -+ { -+ c = getc (stream); -+ if (c != EOF) -+ { -+ ungetc (c, stream); -+ c = '\n'; -+ } -+ } ++ if (is_bs_following_last_blank && !convfail && wc == L'\b') ++ ++bs_following_last_blank_num; ++ else ++ is_bs_following_last_blank = 0; + -+ if (c == delim) -+ ++field_idx; -+ else if (c == '\n' || c == EOF) ++ if (break_spaces && !convfail && iswblank (wc)) + { -+ if (found_any_selected_field -+ || !(suppress_non_delimited && field_idx == 1)) -+ putchar ('\n'); -+ if (c == EOF) -+ break; -+ field_idx = 1; -+ found_any_selected_field = false; ++ 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; + } + } -+} + -+static void -+cut_stream (FILE *stream) -+{ -+ if (operating_mode == byte_mode) -+ cut_bytes (stream); -+ else -+ cut_fields (stream); ++ *saved_errno = errno; ++ ++ if (offset_out) ++ fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); ++ +} ++#endif + -+/* Process file FILE to standard output. -+ Return true if successful. */ ++/* 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 -+cut_file (char const *file) ++fold_file (char *filename, size_t width) +{ -+ FILE *stream; ++ FILE *istream; ++ int saved_errno; + -+ if (STREQ (file, "-")) ++ if (STREQ (filename, "-")) + { -+ have_read_stdin = true; -+ stream = stdin; ++ istream = stdin; ++ have_read_stdin = 1; + } + else -+ { -+ stream = fopen (file, "r"); -+ if (stream == NULL) -+ { -+ error (0, errno, "%s", file); -+ return false; -+ } -+ } -+ -+ cut_stream (stream); ++ istream = fopen (filename, "r"); + -+ if (ferror (stream)) -+ { -+ error (0, errno, "%s", file); -+ return false; -+ } -+ if (STREQ (file, "-")) -+ clearerr (stream); /* Also clear EOF. */ -+ else if (fclose (stream) == EOF) ++ if (istream == NULL) + { -+ error (0, errno, "%s", file); -+ return false; ++ error (0, errno, "%s", filename); ++ return 1; + } -+ return true; -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int optc; -+ bool ok; -+ bool delim_specified = false; -+ char *spec_list_string IF_LINT(= NULL); -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdout); -+ -+ operating_mode = undefined_mode; -+ -+ /* By default, all non-delimited lines are printed. */ -+ suppress_non_delimited = false; + -+ delim = '\0'; -+ have_read_stdin = false; ++ /* 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); + -+ while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, NULL)) != -1) -+ { -+ 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")); + if (ferror (istream)) + { + error (0, saved_errno, "%s", filename); +@@ -251,7 +499,8 @@ main (int argc, char **argv) + + 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) + { +@@ -260,7 +509,15 @@ main (int argc, char **argv) + 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; -+ spec_list_string = optarg; -+ break; -+ -+ case 'f': -+ /* Build the field list. */ -+ 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; + 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 = xstrdup (optarg); -+ break; -+ -+ case 'n': -+ break; -+ -+ case 's': -+ suppress_non_delimited = true; -+ break; -+ -+ case COMPLEMENT_OPTION: -+ complement = true; -+ break; -+ -+ case_GETOPT_HELP_CHAR; ++ 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. */ +diff -urNp coreutils-8.0-orig/src/join.c coreutils-8.0/src/join.c +--- coreutils-8.0-orig/src/join.c 2009-09-23 10:25:44.000000000 +0200 ++++ coreutils-8.0/src/join.c 2009-10-07 10:07:16.000000000 +0200 +@@ -22,17 +22,31 @@ + #include + #include + ++/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif + -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ if (operating_mode == undefined_mode) -+ FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); -+ -+ if (delim != '\0' && operating_mode != field_mode) -+ FATAL_ERROR (_("an input delimiter may be specified only\ -+ when operating on fields")); -+ -+ if (suppress_non_delimited && operating_mode != field_mode) -+ FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\ -+\tonly when operating on fields")); -+ -+ if (output_delimiter_specified) -+ { -+ range_start_ht = hash_initialize (HT_RANGE_START_INDEX_INITIAL_CAPACITY, -+ NULL, hash_int, -+ hash_compare_ints, NULL); -+ if (range_start_ht == NULL) -+ xalloc_die (); -+ -+ } -+ -+ if (! set_fields (spec_list_string)) -+ { -+ if (operating_mode == field_mode) -+ FATAL_ERROR (_("missing list of fields")); -+ else -+ FATAL_ERROR (_("missing list of positions")); -+ } -+ -+ if (!delim_specified) -+ delim = '\t'; -+ -+ if (output_delimiter_string == NULL) -+ { -+ static char dummy[2]; -+ dummy[0] = delim; -+ dummy[1] = '\0'; -+ output_delimiter_string = dummy; -+ output_delimiter_length = 1; -+ } -+ -+ if (optind == argc) -+ ok = cut_file ("-"); -+ else -+ for (ok = true; optind < argc; optind++) -+ ok &= cut_file (argv[optind]); -+ -+ if (range_start_ht) -+ hash_free (range_start_ht); -+ -+ if (have_read_stdin && fclose (stdin) == EOF) -+ { -+ error (0, errno, "-"); -+ ok = false; -+ } -+ -+ exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); -+} -diff -urNp coreutils-8.0-orig/src/expand.c coreutils-8.0/src/expand.c ---- coreutils-8.0-orig/src/expand.c 2009-09-29 15:27:54.000000000 +0200 -+++ coreutils-8.0/src/expand.c 2009-10-07 10:07:16.000000000 +0200 -@@ -37,11 +37,28 @@ - #include - #include - #include -+ -+/* Get mbstate_t, 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 "xstrndup.h" + #include "stdio--.h" + #include "xmemcoll.h" + #include "xstrtol.h" + #include "argmatch.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 "expand" + #define PROGRAM_NAME "join" -@@ -357,6 +374,142 @@ expand (void) +@@ -121,10 +135,12 @@ static struct outlist outlist_head; + /* 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; + + /* If nonzero, check that the input is correctly ordered. */ + static enum +@@ -239,10 +255,11 @@ xfields (struct line *line) + 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 +@@ -269,6 +286,148 @@ xfields (struct line *line) + extract_field (line, ptr, lim - ptr); } +#if HAVE_MBRTOWC +static void -+expand_multibyte (void) ++xfields_multibyte (struct line *line) +{ -+ 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. */ ++ 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; + -+ fp = next_file ((FILE *) NULL); -+ if (fp == NULL) -+ return; ++ memset (&state, 0, sizeof (mbstate_t)); + -+ memset (&o_state, '\0', sizeof(mbstate_t)); -+ memset (&i_state, '\0', sizeof(mbstate_t)); ++ if (ptr >= lim) ++ return; + -+ for (;;) ++ if (tab != NULL) + { -+ /* Refill the buffer BUF. */ -+ if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp)) ++ unsigned char t = tab[0]; ++ char *sep = ptr; ++ for (; ptr < lim; ptr = sep + mblength) + { -+ memmove (buf, bufpos, buflen); -+ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp); -+ bufpos = buf; -+ } ++ sep = ptr; ++ while (sep < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); + -+ /* No character is left in BUF. */ -+ if (buflen < 1) -+ { -+ fp = next_file (fp); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; + -+ if (fp == NULL) -+ break; /* No more files. */ -+ else -+ { -+ memset (&i_state, '\0', sizeof(mbstate_t)); -+ continue; ++ 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); + -+ /* Get a wide character. */ -+ i_state_bak = i_state; -+ mblength = mbrtowc (&wc, bufpos, buflen, &i_state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; + -+ switch (mblength) ++ if (!iswblank(wc)) ++ break; ++ ptr += mblength; ++ } ++ ++ do + { -+ case (size_t)-1: /* illegal byte sequence. */ -+ case (size_t)-2: -+ mblength = 1; -+ i_state = i_state_bak; -+ if (convert) ++ char *sep; ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) + { -+ ++column; -+ if (convert_entire_line == 0) -+ convert = 0; ++ mblength = 1; ++ state = state_bak; ++ break; + } -+ putchar (*bufpos); -+ break; -+ -+ case 0: /* null. */ -+ mblength = 1; -+ if (convert && convert_entire_line == 0) -+ convert = 0; -+ putchar ('\0'); -+ break; ++ mblength = (mblength < 1) ? 1 : mblength; + -+ default: -+ if (wc == L'\n') /* LF. */ -+ { -+ tab_index = 0; -+ column = 0; -+ convert = 1; -+ putchar ('\n'); -+ } -+ else if (wc == L'\t' && convert) /* Tab. */ ++ sep = ptr + mblength; ++ while (sep < lim) + { -+ if (tab_size == 0) ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) + { -+ /* 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; ++ mblength = 1; ++ state = state_bak; ++ break; + } -+ else -+ next_tab_column = column + tab_size - column % tab_size; ++ mblength = (mblength < 1) ? 1 : mblength; + -+ while (column < next_tab_column) -+ { -+ putchar (' '); -+ ++column; -+ } ++ if (iswblank (wc)) ++ break; ++ ++ sep += mblength; + } -+ 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; -+ } ++ 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; + } -+ fwrite (bufpos, sizeof(char), mblength, stdout); ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank (wc)) ++ break; ++ ++ ptr += mblength; + } + } -+ buflen -= mblength; -+ bufpos += mblength; ++ while (ptr < lim); + } ++ ++ extract_field (line, ptr, lim - ptr); +} +#endif -+ - int - main (int argc, char **argv) ++ + static void + freeline (struct line *line) { -@@ -421,7 +574,12 @@ main (int argc, char **argv) +@@ -287,56 +446,115 @@ keycmp (struct line const *line1, struct + size_t jf_1, size_t jf_2) + { + /* 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; - file_list = (optind < argc ? &argv[optind] : stdin_argv); + if (jf_1 < line1->nfields) + { +- beg1 = line1->fields[jf_1].beg; +- len1 = line1->fields[jf_1].len; ++ beg[0] = line1->fields[jf_1].beg; ++ len[0] = line1->fields[jf_1].len; + } + else + { +- beg1 = NULL; +- len1 = 0; ++ beg[0] = NULL; ++ len[0] = 0; + } -- expand (); -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ expand_multibyte (); -+ else -+#endif -+ expand (); + if (jf_2 < line2->nfields) + { +- beg2 = line2->fields[jf_2].beg; +- len2 = line2->fields[jf_2].len; ++ beg[1] = line2->fields[jf_2].beg; ++ len[1] = line2->fields[jf_2].len; + } + else + { +- beg2 = NULL; +- len2 = 0; ++ beg[1] = NULL; ++ len[1] = 0; + } - if (have_read_stdin && fclose (stdin) != 0) - error (EXIT_FAILURE, errno, "-"); -diff -urNp coreutils-8.0-orig/src/expand.c.orig coreutils-8.0/src/expand.c.orig ---- coreutils-8.0-orig/src/expand.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/expand.c.orig 2009-09-29 15:27:54.000000000 +0200 -@@ -0,0 +1,430 @@ -+/* expand - convert tabs to spaces -+ Copyright (C) 89, 91, 1995-2006, 2008-2009 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 . */ -+ -+/* By default, convert all tabs to spaces. -+ Preserves backspace characters in the output; they decrement the -+ column count for tab calculations. -+ The default action is equivalent to -8. -+ -+ Options: -+ --tabs=tab1[,tab2[,...]] -+ -t tab1[,tab2[,...]] -+ -tab1[,tab2[,...]] If only one tab stop is given, set the tabs tab1 -+ columns apart instead of the default 8. Otherwise, -+ set the tabs at columns tab1, tab2, etc. (numbered from -+ 0); replace any tabs beyond the tab stops given with -+ single spaces. -+ --initial -+ -i Only convert initial tabs on each line to spaces. -+ -+ David MacKenzie */ -+ -+#include -+ -+#include -+#include -+#include -+#include "system.h" -+#include "error.h" -+#include "quote.h" -+#include "xstrndup.h" -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "expand" -+ -+#define AUTHORS proper_name ("David MacKenzie") -+ -+/* If true, convert blanks even after nonblank characters have been -+ read on the line. */ -+static bool convert_entire_line; -+ -+/* If nonzero, the size of all tab stops. If zero, use `tab_list' instead. */ -+static uintmax_t tab_size; -+ -+/* Array of the explicit column numbers of the tab stops; -+ after `tab_list' is exhausted, each additional tab is replaced -+ by a space. The first column is column 0. */ -+static uintmax_t *tab_list; -+ -+/* The number of allocated entries in `tab_list'. */ -+static size_t n_tabs_allocated; -+ -+/* The index of the first invalid element of `tab_list', -+ where the next element can be added. */ -+static size_t first_free_tab; -+ -+/* Null-terminated array of input filenames. */ -+static char **file_list; -+ -+/* Default for `file_list' if no files are given on the command line. */ -+static char *stdin_argv[] = -+{ -+ (char *) "-", NULL -+}; -+ -+/* True if we have ever read standard input. */ -+static bool have_read_stdin; -+ -+/* The desired exit status. */ -+static int exit_status; -+ -+static char const shortopts[] = "it:0::1::2::3::4::5::6::7::8::9::"; -+ -+static struct option const longopts[] = -+{ -+ {"tabs", required_argument, NULL, 't'}, -+ {"initial", no_argument, NULL, 'i'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 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; + -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [FILE]...\n\ -+"), -+ program_name); -+ fputs (_("\ -+Convert tabs in each FILE to spaces, writing to standard output.\n\ -+With no FILE, or when FILE is -, read standard input.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ -i, --initial do not convert tabs after non blanks\n\ -+ -t, --tabs=NUMBER have tabs NUMBER characters apart, not 8\n\ -+"), stdout); -+ fputs (_("\ -+ -t, --tabs=LIST use comma separated list of explicit tab positions\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} ++ memset (&state, '\0', sizeof (mbstate_t)); + -+/* Add tab stop TABVAL to the end of `tab_list'. */ ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = alloca (len[i] + 1); + -+static void -+add_tab_stop (uintmax_t tabval) -+{ -+ if (first_free_tab == n_tabs_allocated) -+ tab_list = X2NREALLOC (tab_list, &n_tabs_allocated); -+ tab_list[first_free_tab++] = tabval; -+} ++ for (j = 0; j < MIN (len[0], len[1]);) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state); + -+/* Add the comma or blank separated list of tab stops STOPS -+ to the list of tab stops. */ ++ switch (mblength) ++ { ++ case (size_t) -1: ++ case (size_t) -2: ++ state = state_bak; ++ /* Fall through */ ++ case 0: ++ mblength = 1; ++ break; + -+static void -+parse_tab_stops (char const *stops) -+{ -+ bool have_tabval = false; -+ uintmax_t tabval IF_LINT (= 0); -+ char const *num_start IF_LINT (= NULL); -+ bool ok = true; ++ default: ++ uwc = towupper (wc); + -+ for (; *stops; stops++) -+ { -+ if (*stops == ',' || isblank (to_uchar (*stops))) -+ { -+ if (have_tabval) -+ add_tab_stop (tabval); -+ have_tabval = false; -+ } -+ else if (ISDIGIT (*stops)) -+ { -+ if (!have_tabval) -+ { -+ tabval = 0; -+ have_tabval = true; -+ num_start = stops; -+ } ++ if (uwc != wc) ++ { ++ mbstate_t state_wc; + -+ /* Detect overflow. */ -+ if (!DECIMAL_DIGIT_ACCUMULATE (tabval, *stops - '0', uintmax_t)) -+ { -+ size_t len = strspn (num_start, "0123456789"); -+ char *bad_num = xstrndup (num_start, len); -+ error (0, 0, _("tab stop is too large %s"), quote (bad_num)); -+ free (bad_num); -+ ok = false; -+ stops = num_start + len - 1; -+ } -+ } ++ 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 -+ { -+ error (0, 0, _("tab size contains invalid character(s): %s"), -+ quote (stops)); -+ ok = false; -+ break; -+ } -+ } -+ -+ if (!ok) -+ exit (EXIT_FAILURE); -+ -+ if (have_tabval) -+ add_tab_stop (tabval); -+} -+ -+/* Check that the list of tab stops TABS, with ENTRIES entries, -+ contains only nonzero, ascending values. */ ++#endif ++ { ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = alloca (len[i] + 1); + -+static void -+validate_tab_stops (uintmax_t const *tabs, size_t entries) -+{ -+ uintmax_t prev_tab = 0; -+ size_t i; ++ for (j = 0; j < MIN (len[0], len[1]); j++) ++ copy[i][j] = toupper (beg[i][j]); + -+ for (i = 0; i < entries; i++) -+ { -+ if (tabs[i] == 0) -+ error (EXIT_FAILURE, 0, _("tab size cannot be 0")); -+ if (tabs[i] <= prev_tab) -+ error (EXIT_FAILURE, 0, _("tab sizes must be ascending")); -+ prev_tab = tabs[i]; -+ } -+} ++ 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])); + -+/* Close the old stream pointer FP if it is non-NULL, -+ and return a new one opened to read the next input file. -+ Open a filename of `-' as the standard input. -+ Return NULL if there are no more input files. */ + -+static FILE * -+next_file (FILE *fp) -+{ -+ static char *prev_file; -+ char *file; + if (diff) + return diff; +- return len1 < len2 ? -1 : len1 != len2; ++ return len[0] - len[1]; + } + + /* Check that successive input lines PREV and CURRENT from input file +@@ -417,6 +635,11 @@ get_line (FILE *fp, struct line **linep, + return false; + } + ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ xfields_multibyte (line); ++ else ++#endif + xfields (line); + + if (prevline[which - 1]) +@@ -518,11 +741,18 @@ prfield (size_t n, struct line const *li + + /* Print the join of LINE1 and LINE2. */ + ++#define PUT_TAB_CHAR \ ++ do \ ++ { \ ++ (tab != NULL) ? \ ++ fwrite(tab, sizeof(char), tablen, stdout) : putchar (' '); \ ++ } \ ++ while (0) + -+ if (fp) -+ { -+ if (ferror (fp)) -+ { -+ error (0, errno, "%s", prev_file); -+ exit_status = EXIT_FAILURE; -+ } -+ if (STREQ (prev_file, "-")) -+ clearerr (fp); /* Also clear EOF. */ -+ else if (fclose (fp) != 0) -+ { -+ error (0, errno, "%s", prev_file); -+ exit_status = EXIT_FAILURE; -+ } -+ } -+ -+ while ((file = *file_list++) != NULL) -+ { -+ if (STREQ (file, "-")) -+ { -+ have_read_stdin = true; -+ prev_file = file; -+ return stdin; -+ } -+ fp = fopen (file, "r"); -+ if (fp) -+ { -+ prev_file = file; -+ return fp; -+ } -+ error (0, errno, "%s", file); -+ exit_status = EXIT_FAILURE; -+ } -+ return NULL; -+} -+ -+/* Change tabs to spaces, writing to stdout. -+ Read each file in `file_list', in order. */ -+ -+static void -+expand (void) -+{ -+ /* Input stream. */ -+ FILE *fp = next_file (NULL); -+ -+ if (!fp) -+ return; -+ -+ for (;;) -+ { -+ /* Input character, or EOF. */ -+ int c; -+ -+ /* If true, perform translations. */ -+ bool convert = true; -+ -+ -+ /* The following variables have valid values only when CONVERT -+ is true: */ -+ -+ /* Column of next input character. */ -+ uintmax_t column = 0; -+ -+ /* Index in TAB_LIST of next tab stop to examine. */ -+ size_t tab_index = 0; -+ -+ -+ /* Convert a line of text. */ -+ -+ do -+ { -+ while ((c = getc (fp)) < 0 && (fp = next_file (fp))) -+ continue; -+ -+ if (convert) -+ { -+ if (c == '\t') -+ { -+ /* Column the next input tab stop is on. */ -+ uintmax_t next_tab_column; -+ -+ if (tab_size) -+ next_tab_column = column + (tab_size - column % tab_size); -+ else -+ for (;;) -+ if (tab_index == first_free_tab) -+ { -+ next_tab_column = column + 1; -+ break; -+ } -+ else -+ { -+ uintmax_t tab = tab_list[tab_index++]; -+ if (column < tab) -+ { -+ next_tab_column = tab; -+ break; -+ } -+ } -+ -+ if (next_tab_column < column) -+ error (EXIT_FAILURE, 0, _("input line is too long")); -+ -+ while (++column < next_tab_column) -+ if (putchar (' ') < 0) -+ error (EXIT_FAILURE, errno, _("write error")); -+ -+ c = ' '; -+ } -+ else if (c == '\b') -+ { -+ /* Go back one column, and force recalculation of the -+ next tab stop. */ -+ column -= !!column; -+ tab_index -= !!tab_index; -+ } -+ else -+ { -+ column++; -+ if (!column) -+ error (EXIT_FAILURE, 0, _("input line is too long")); -+ } -+ -+ convert &= convert_entire_line || !! isblank (c); -+ } -+ -+ if (c < 0) -+ return; -+ -+ if (putchar (c) < 0) -+ error (EXIT_FAILURE, errno, _("write error")); -+ } -+ while (c != '\n'); -+ } -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int c; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdout); -+ -+ have_read_stdin = false; -+ exit_status = EXIT_SUCCESS; -+ convert_entire_line = true; -+ tab_list = NULL; -+ first_free_tab = 0; -+ -+ while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) -+ { -+ switch (c) -+ { -+ case 'i': -+ convert_entire_line = false; -+ break; -+ -+ case 't': -+ parse_tab_stops (optarg); -+ break; -+ -+ case '0': case '1': case '2': case '3': case '4': -+ case '5': case '6': case '7': case '8': case '9': -+ if (optarg) -+ parse_tab_stops (optarg - 1); -+ else -+ { -+ char tab_stop[2]; -+ tab_stop[0] = c; -+ tab_stop[1] = '\0'; -+ parse_tab_stops (tab_stop); -+ } -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ validate_tab_stops (tab_list, first_free_tab); -+ -+ if (first_free_tab == 0) -+ tab_size = 8; -+ else if (first_free_tab == 1) -+ tab_size = tab_list[0]; -+ else -+ tab_size = 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) +@@ -557,7 +787,7 @@ prjoin (struct line const *line1, struct + o = o->next; + if (o == NULL) + break; +- putchar (output_separator); ++ PUT_TAB_CHAR; + } + putchar ('\n'); + } +@@ -575,23 +805,23 @@ prjoin (struct line const *line1, struct + 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'); +@@ -1022,20 +1252,41 @@ main (int argc, char **argv) + + 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; + -+ file_list = (optind < argc ? &argv[optind] : stdin_argv); ++ 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; + +diff -urNp coreutils-8.0-orig/src/pr.c coreutils-8.0/src/pr.c +--- coreutils-8.0-orig/src/pr.c 2009-09-29 15:27:54.000000000 +0200 ++++ coreutils-8.0/src/pr.c 2009-10-07 10:07:16.000000000 +0200 +@@ -312,6 +312,32 @@ + + #include + #include + -+ expand (); ++/* Get MB_LEN_MAX. */ ++#include ++/* 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 == 1 ++# define MB_LEN_MAX 16 ++#endif + -+ if (have_read_stdin && fclose (stdin) != 0) -+ error (EXIT_FAILURE, errno, "-"); ++/* Get MB_CUR_MAX. */ ++#include + -+ exit (exit_status); -+} -diff -urNp coreutils-8.0-orig/src/fold.c coreutils-8.0/src/fold.c ---- coreutils-8.0-orig/src/fold.c 2009-09-23 10:25:44.000000000 +0200 -+++ coreutils-8.0/src/fold.c 2009-10-07 10:07:16.000000000 +0200 -@@ -22,11 +22,33 @@ - #include - #include - ++/* Solaris 2.5 has a bug: must be included before . */ +/* Get mbstate_t, mbrtowc(), wcwidth(). */ +#if HAVE_WCHAR_H +# include +#endif + -+/* Get iswprint(), iswblank(), wcwidth(). */ ++/* Get iswprint(). -- for wcwidth(). */ +#if HAVE_WCTYPE_H +# include +#endif ++#if !defined iswprint && !HAVE_ISWPRINT ++# define iswprint(wc) 1 ++#endif + #include "system.h" #include "error.h" - #include "quote.h" + #include "hard-locale.h" +@@ -322,6 +348,18 @@ + #include "strftime.h" #include "xstrtol.h" -+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC -+ installation; work around this configuration error. */ -+#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 -+# undef MB_LEN_MAX -+# define MB_LEN_MAX 16 -+#endif -+ +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HAVE_MBRTOWC && defined mbstate_t +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +#endif + - #define TAB_WIDTH 8 - ++#ifndef HAVE_DECL_WCWIDTH ++"this configure-time declaration test was not run" ++#endif ++#if !HAVE_DECL_WCWIDTH ++extern int wcwidth (); ++#endif ++ /* The official name of this program (e.g., no `g' prefix). */ -@@ -34,20 +56,41 @@ + #define PROGRAM_NAME "pr" - #define AUTHORS proper_name ("David MacKenzie") +@@ -414,7 +452,20 @@ struct COLUMN -+#define FATAL_ERROR(Message) \ -+ do \ -+ { \ -+ error (0, 0, (Message)); \ -+ usage (2); \ -+ } \ -+ while (0) + typedef struct COLUMN COLUMN; + +-static int char_to_clump (char c); ++/* Funtion pointers to switch functions for single byte locale or for ++ multibyte locale. If multibyte functions do not exist in your sysytem, ++ these pointers always point the function for single byte locale. */ ++static void (*print_char) (char c); ++static int (*char_to_clump) (char c); + -+enum operating_mode -+{ -+ /* Fold texts by columns that are at the given positions. */ -+ column_mode, ++/* Functions for single byte locale. */ ++static void print_char_single (char c); ++static int char_to_clump_single (char c); + -+ /* Fold texts by bytes that are at the given positions. */ -+ byte_mode, -+ -+ /* Fold texts by characters that are at the given positions. */ -+ character_mode, -+}; -+ -+/* The argument shows current mode. (Default: column_mode) */ -+static enum operating_mode operating_mode; ++/* Functions for multibyte locale. */ ++static void print_char_multi (char c); ++static int char_to_clump_multi (char c); + - /* If nonzero, try to break on whitespace. */ - static bool break_spaces; + static bool read_line (COLUMN *p); + static bool print_page (void); + static bool print_stored (COLUMN *p); +@@ -424,6 +475,7 @@ static void print_header (void); + static void pad_across_to (int position); + static void add_line_number (COLUMN *p); + static void getoptarg (char *arg, char switch_char, char *character, ++ int *character_length, int *character_width, + int *number); + void usage (int status); + static void print_files (int number_of_files, char **av); +@@ -438,7 +490,6 @@ static void store_char (char c); + 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 (const char *optarg_S); +@@ -450,7 +501,7 @@ static COLUMN *column_vector; + 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]. */ +-static char *buff; ++static unsigned char *buff; --/* If nonzero, count bytes, not column positions. */ --static bool count_bytes; -- - /* If nonzero, at least one of the files we read was standard input. */ - static bool have_read_stdin; + /* Index of the position in buff where the next character + will be stored. */ +@@ -554,7 +605,7 @@ static int chars_per_column; + static bool untabify_input = false; --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::"; + /* (-e) The input tab character. */ +-static char input_tab_char = '\t'; ++static char input_tab_char[MB_LEN_MAX] = "\t"; - 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}, -@@ -77,6 +120,7 @@ Mandatory arguments to long options are - "), stdout); - fputs (_("\ - -b, --bytes count bytes rather than columns\n\ -+ -c, --characters count characters rather than columns\n\ - -s, --spaces break at spaces\n\ - -w, --width=WIDTH use WIDTH columns instead of 80\n\ - "), stdout); -@@ -94,7 +138,7 @@ Mandatory arguments to long options are - static size_t - adjust_column (size_t column, char c) - { -- if (!count_bytes) -+ if (operating_mode != byte_mode) - { - if (c == '\b') - { -@@ -117,30 +161,14 @@ adjust_column (size_t column, char c) - to stdout, with maximum line length WIDTH. - Return true if successful. */ + /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ... + where the leftmost column is 1. */ +@@ -564,7 +615,10 @@ static int chars_per_input_tab = 8; + static bool tabify_output = false; --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; -- } + /* (-i) The output tab character. */ +-static char output_tab_char = '\t'; ++static char output_tab_char[MB_LEN_MAX] = "\t"; ++ ++/* (-i) The byte length of output tab character. */ ++static int output_tab_char_length = 1; - while ((c = getc (istream)) != EOF) - { -@@ -168,6 +196,15 @@ fold_file (char const *filename, size_t - bool found_blank = false; - size_t logical_end = offset_out; + /* (-i) The width of the output tab. */ + static int chars_per_output_tab = 8; +@@ -638,7 +692,13 @@ static int power_10; + static bool numbered_lines = false; -+ /* 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; -+ } + /* (-n) Character which follows each line number. */ +-static char number_separator = '\t'; ++static char number_separator[MB_LEN_MAX] = "\t"; + - /* Look for the last blank. */ - while (logical_end) - { -@@ -214,11 +251,222 @@ fold_file (char const *filename, size_t - line_out[offset_out++] = c; - } - -- saved_errno = errno; -+ *saved_errno = errno; ++/* (-n) The byte length of the character which follows each line number. */ ++static int number_separator_length = 1; ++ ++/* (-n) The character width of the character which follows each line number. */ ++static int number_separator_width = 0; - if (offset_out) - fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + /* (-n) line counting starts with 1st line of input file (not with 1st + line of 1st page printed). */ +@@ -691,6 +751,7 @@ static bool use_col_separator = false; + -a|COLUMN|-m is a `space' and with the -J option a `tab'. */ + static char *col_sep_string = (char *) ""; + static int col_sep_length = 0; ++static int col_sep_width = 0; + static char *column_separator = (char *) " "; + static char *line_separator = (char *) "\t"; -+} +@@ -847,6 +908,13 @@ separator_string (const char *optarg_S) + col_sep_length = (int) strlen (optarg_S); + col_sep_string = xmalloc (col_sep_length + 1); + strcpy (col_sep_string, optarg_S); + +#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 = NULL; /* 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. */ -+ -+ static char *line_out = NULL; -+ size_t offset_out = 0; /* Index in `line_out' for next char. */ -+ static size_t allocated_out = 0; -+ -+ int increment; -+ size_t column = 0; ++ if (MB_CUR_MAX > 1) ++ col_sep_width = mbswidth (col_sep_string, 0); ++ else ++#endif ++ col_sep_width = col_sep_length; + } + + int +@@ -871,6 +939,21 @@ main (int argc, char **argv) + + atexit (close_stdout); + ++/* Define which functions are used, the ones for single byte locale or the ones ++ for multibyte locale. */ ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ print_char = print_char_multi; ++ char_to_clump = char_to_clump_multi; ++ } ++ else ++#endif ++ { ++ print_char = print_char_single; ++ char_to_clump = char_to_clump_single; ++ } + -+ size_t last_blank_pos; -+ size_t last_blank_column; -+ int is_blank_seen; -+ int last_blank_increment = 0; -+ int is_bs_following_last_blank; -+ size_t bs_following_last_blank_num; -+ int is_cr_after_last_blank; + n_files = 0; + file_names = (argc > 1 + ? xmalloc ((argc - 1) * sizeof (char *)) +@@ -947,8 +1030,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; + -+#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) ++ getoptarg (optarg, 'e', input_tab_char, &dummy_length, ++ &dummy_width, &chars_per_input_tab); ++ } + /* Could check tab width > 0. */ + untabify_input = true; + break; +@@ -961,8 +1048,12 @@ main (int argc, char **argv) + break; + case 'i': + if (optarg) +- getoptarg (optarg, 'i', &output_tab_char, +- &chars_per_output_tab); ++ { ++ int dummy_width; + -+#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) ++ 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; +@@ -989,8 +1080,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; +@@ -1029,7 +1120,7 @@ main (int argc, char **argv) + old_s = false; + /* Reset an additional input of -s, -S dominates -s */ + col_sep_string = bad_cast (""); +- col_sep_length = 0; ++ col_sep_length = col_sep_width = 0; + use_col_separator = true; + if (optarg) + separator_string (optarg); +@@ -1186,10 +1277,45 @@ main (int argc, char **argv) + 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) + { + if (!ISDIGIT (*arg)) +- *character = *arg++; + { -+ 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) ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) /* for multibyte locale. */ + { -+ case (size_t)-1: -+ case (size_t)-2: -+ convfail++; -+ state = state_bak; -+ /* Fall through. */ ++ wchar_t wc; ++ size_t mblength; ++ int width; ++ mbstate_t state = {'\0'}; + -+ case 0: -+ mblength = 1; -+ break; -+ } ++ mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state); + -+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; ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ *character_length = 1; ++ *character_width = 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; -+ } ++ *character_length = (mblength < 1) ? 1 : mblength; ++ width = wcwidth (wc); ++ *character_width = (width < 0) ? 0 : width; + } -+ } -+ -+ 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) -+ { -+ line_out = X2REALLOC (line_out, &allocated_out); ++ strncpy (character, arg, *character_length); ++ arg += *character_length; + } -+ -+ 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)) ++ else /* for single byte locale. */ ++#endif + { -+ 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; ++ *character = *arg++; ++ *character_length = 1; ++ *character_width = 1; + } + } + -+ *saved_errno = errno; -+ -+ if (offset_out) -+ fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); -+ -+} -+#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)) + if (*arg) { - error (0, saved_errno, "%s", filename); -@@ -251,7 +499,8 @@ main (int argc, char **argv) - - atexit (close_stdout); + long int tmp_long; +@@ -1248,7 +1374,7 @@ init_parameters (int number_of_files) + else + col_sep_string = column_separator; -- break_spaces = count_bytes = have_read_stdin = false; -+ operating_mode = column_mode; -+ break_spaces = have_read_stdin = false; +- 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 +@@ -1279,11 +1405,11 @@ init_parameters (int number_of_files) + TAB_WIDTH (chars_per_input_tab, chars_per_number); */ - while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) - { -@@ -260,7 +509,15 @@ main (int argc, char **argv) - 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; + /* 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); + else +- number_width = chars_per_number + 1; ++ number_width = chars_per_number + number_separator_width; - case 's': /* Break at word boundaries. */ -diff -urNp coreutils-8.0-orig/src/fold.c.orig coreutils-8.0/src/fold.c.orig ---- coreutils-8.0-orig/src/fold.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/fold.c.orig 2009-09-23 10:25:44.000000000 +0200 -@@ -0,0 +1,314 @@ -+/* fold -- wrap each input line to fit in specified width. -+ Copyright (C) 91, 1995-2006, 2008-2009 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 . */ -+ -+/* Written by David MacKenzie, djm@gnu.ai.mit.edu. */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include "system.h" -+#include "error.h" -+#include "quote.h" -+#include "xstrtol.h" -+ -+#define TAB_WIDTH 8 -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "fold" -+ -+#define AUTHORS proper_name ("David MacKenzie") -+ -+/* If nonzero, try to break on whitespace. */ -+static bool break_spaces; -+ -+/* If nonzero, count bytes, not column positions. */ -+static bool count_bytes; -+ -+/* If nonzero, at least one of the files we read was standard input. */ -+static bool have_read_stdin; -+ -+static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::"; -+ -+static struct option const longopts[] = -+{ -+ {"bytes", no_argument, NULL, 'b'}, -+ {"spaces", no_argument, NULL, 's'}, -+ {"width", required_argument, NULL, 'w'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [FILE]...\n\ -+"), -+ program_name); -+ fputs (_("\ -+Wrap input lines in each FILE (standard input by default), writing to\n\ -+standard output.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ -b, --bytes count bytes rather than columns\n\ -+ -s, --spaces break at spaces\n\ -+ -w, --width=WIDTH use WIDTH columns instead of 80\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+/* Assuming the current column is COLUMN, return the column that -+ printing C will move the cursor to. -+ The first column is 0. */ -+ -+static size_t -+adjust_column (size_t column, char c) -+{ -+ if (!count_bytes) -+ { -+ if (c == '\b') -+ { -+ if (column > 0) -+ column--; -+ } -+ else if (c == '\r') -+ column = 0; -+ else if (c == '\t') -+ column += TAB_WIDTH - column % TAB_WIDTH; -+ else /* if (isprint (c)) */ -+ column++; -+ } -+ else -+ column++; -+ return column; -+} -+ -+/* Fold file FILENAME, or standard input if FILENAME is "-", -+ to stdout, with maximum line length WIDTH. -+ Return true if successful. */ -+ -+static bool -+fold_file (char const *filename, size_t width) -+{ -+ FILE *istream; -+ int c; -+ size_t column = 0; /* Screen column where next char will go. */ -+ size_t offset_out = 0; /* Index in `line_out' for next char. */ -+ static char *line_out = NULL; -+ static size_t allocated_out = 0; -+ int saved_errno; -+ -+ if (STREQ (filename, "-")) -+ { -+ istream = stdin; -+ have_read_stdin = true; -+ } -+ else -+ istream = fopen (filename, "r"); -+ -+ if (istream == NULL) -+ { -+ error (0, errno, "%s", filename); -+ return false; -+ } -+ -+ while ((c = getc (istream)) != EOF) -+ { -+ if (offset_out + 1 >= allocated_out) -+ line_out = X2REALLOC (line_out, &allocated_out); -+ -+ if (c == '\n') -+ { -+ line_out[offset_out++] = c; -+ fwrite (line_out, sizeof (char), offset_out, stdout); -+ column = offset_out = 0; -+ continue; -+ } -+ -+ rescan: -+ column = adjust_column (column, c); -+ -+ if (column > width) -+ { -+ /* This character would make the line too long. -+ Print the line plus a newline, and make this character -+ start the next line. */ -+ if (break_spaces) -+ { -+ bool found_blank = false; -+ size_t logical_end = offset_out; -+ -+ /* Look for the last blank. */ -+ while (logical_end) -+ { -+ --logical_end; -+ if (isblank (to_uchar (line_out[logical_end]))) -+ { -+ found_blank = true; -+ break; -+ } -+ } -+ -+ if (found_blank) -+ { -+ size_t i; -+ -+ /* Found a blank. Don't output the part after it. */ -+ logical_end++; -+ fwrite (line_out, sizeof (char), (size_t) logical_end, -+ stdout); -+ putchar ('\n'); -+ /* Move the remainder to the beginning of the next line. -+ The areas being copied here might overlap. */ -+ memmove (line_out, line_out + logical_end, -+ offset_out - logical_end); -+ offset_out -= logical_end; -+ for (column = i = 0; i < offset_out; i++) -+ column = adjust_column (column, line_out[i]); -+ goto rescan; -+ } -+ } -+ -+ if (offset_out == 0) -+ { -+ line_out[offset_out++] = c; -+ continue; -+ } -+ -+ line_out[offset_out++] = '\n'; -+ fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); -+ column = offset_out = 0; -+ goto rescan; -+ } -+ -+ line_out[offset_out++] = c; -+ } -+ -+ saved_errno = errno; -+ -+ if (offset_out) -+ fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); -+ -+ if (ferror (istream)) -+ { -+ error (0, saved_errno, "%s", filename); -+ if (!STREQ (filename, "-")) -+ fclose (istream); -+ return false; -+ } -+ if (!STREQ (filename, "-") && fclose (istream) == EOF) -+ { -+ error (0, errno, "%s", filename); -+ return false; -+ } -+ -+ return true; -+} -+ -+int -+main (int argc, char **argv) -+{ -+ size_t width = 80; -+ int i; -+ int optc; -+ bool ok; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdout); -+ -+ break_spaces = count_bytes = have_read_stdin = false; -+ -+ while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) -+ { -+ char optargbuf[2]; -+ -+ switch (optc) -+ { -+ case 'b': /* Count bytes rather than columns. */ -+ count_bytes = true; -+ break; -+ -+ case 's': /* Break at word boundaries. */ -+ break_spaces = true; -+ break; -+ -+ case '0': case '1': case '2': case '3': case '4': -+ case '5': case '6': case '7': case '8': case '9': -+ if (optarg) -+ optarg--; -+ else -+ { -+ optargbuf[0] = optc; -+ optargbuf[1] = '\0'; -+ optarg = optargbuf; -+ } -+ /* Fall through. */ -+ case 'w': /* Line width. */ -+ { -+ unsigned long int tmp_ulong; -+ if (! (xstrtoul (optarg, NULL, 10, &tmp_ulong, "") == LONGINT_OK -+ && 0 < tmp_ulong && tmp_ulong < SIZE_MAX - TAB_WIDTH)) -+ error (EXIT_FAILURE, 0, -+ _("invalid number of columns: %s"), quote (optarg)); -+ width = tmp_ulong; -+ } -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ if (argc == optind) -+ ok = fold_file ("-", width); -+ else -+ { -+ ok = true; -+ for (i = optind; i < argc; i++) -+ ok &= fold_file (argv[i], width); -+ } -+ -+ if (have_read_stdin && fclose (stdin) == EOF) -+ error (EXIT_FAILURE, errno, "-"); -+ -+ exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); -+} -diff -urNp coreutils-8.0-orig/src/join.c coreutils-8.0/src/join.c ---- coreutils-8.0-orig/src/join.c 2009-09-23 10:25:44.000000000 +0200 -+++ coreutils-8.0/src/join.c 2009-10-07 10:07:16.000000000 +0200 -@@ -22,17 +22,31 @@ - #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" - #include "argmatch.h" + /* The number is part of the column width unless we are + printing files in parallel. */ +@@ -1298,7 +1424,7 @@ init_parameters (int number_of_files) + } -+/* 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" + chars_per_column = (chars_per_line - chars_used_by_number - +- (columns - 1) * col_sep_length) / columns; ++ (columns - 1) * col_sep_width) / columns; -@@ -121,10 +135,12 @@ static struct outlist outlist_head; - /* Last element in `outlist', where a new element can be added. */ - static struct outlist *outlist_end = &outlist_head; + if (chars_per_column < 1) + error (EXIT_FAILURE, 0, _("page width too narrow")); +@@ -1423,7 +1549,7 @@ init_funcs (void) --/* 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; + /* Enlarge p->start_position of first column to use the same form of + padding_not_printed with all columns. */ +- h = h + col_sep_length; ++ h = h + col_sep_width; - /* If nonzero, check that the input is correctly ordered. */ - static enum -@@ -239,10 +255,11 @@ xfields (struct line *line) - if (ptr == lim) - return; + /* This loop takes care of all but the rightmost column. */ -- if (0 <= tab) -+ if (tab != NULL) +@@ -1457,7 +1583,7 @@ init_funcs (void) + } + else + { +- h = h_next + col_sep_length; ++ h = h_next + col_sep_width; + h_next = h + chars_per_column; + } + } +@@ -1747,9 +1873,9 @@ static void + align_column (COLUMN *p) + { + padding_not_printed = p->start_position; +- if (padding_not_printed - col_sep_length > 0) ++ if (padding_not_printed - col_sep_width > 0) { -+ 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); +- pad_across_to (padding_not_printed - col_sep_length); ++ pad_across_to (padding_not_printed - col_sep_width); + padding_not_printed = ANYWHERE; } - else -@@ -269,6 +286,148 @@ xfields (struct line *line) - extract_field (line, ptr, lim - ptr); + +@@ -2020,13 +2146,13 @@ store_char (char c) + /* May be too generous. */ + buff = X2REALLOC (buff, &buff_allocated); + } +- buff[buff_current++] = c; ++ buff[buff_current++] = (unsigned char) c; } -+#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 -+ static void - freeline (struct line *line) - { -@@ -287,56 +446,115 @@ keycmp (struct line const *line1, struct - size_t jf_1, size_t jf_2) + add_line_number (COLUMN *p) { - /* 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; + int i, j; + char *s; + int left_cut; - if (jf_1 < line1->nfields) - { -- beg1 = line1->fields[jf_1].beg; -- len1 = line1->fields[jf_1].len; -+ beg[0] = line1->fields[jf_1].beg; -+ len[0] = line1->fields[jf_1].len; +@@ -2049,22 +2175,24 @@ add_line_number (COLUMN *p) + /* 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. */ +- if (number_separator == '\t') ++ if (number_separator[0] == '\t') + { + i = number_width - chars_per_number; + while (i-- > 0) + (p->char_func) (' '); + } + else +- (p->char_func) (number_separator); ++ 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 + separator with a single column output. No column_width requirement + has to be considered. */ { -- beg1 = NULL; -- len1 = 0; -+ beg[0] = NULL; -+ len[0] = 0; - } - - if (jf_2 < line2->nfields) - { -- beg2 = line2->fields[jf_2].beg; -- len2 = line2->fields[jf_2].len; -+ beg[1] = line2->fields[jf_2].beg; -+ len[1] = line2->fields[jf_2].len; +- (p->char_func) (number_separator); +- if (number_separator == '\t') ++ for (j = 0; j < number_separator_length; j++) ++ (p->char_func) (number_separator[j]); ++ if (number_separator[0] == '\t') + output_position = POS_AFTER_TAB (chars_per_output_tab, + output_position); } - else +@@ -2225,7 +2353,7 @@ print_white_space (void) + while (goal - h_old > 1 + && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) { -- beg2 = NULL; -- len2 = 0; -+ beg[1] = NULL; -+ len[1] = 0; +- putchar (output_tab_char); ++ fwrite (output_tab_char, sizeof(char), output_tab_char_length, stdout); + h_old = h_new; } + while (++h_old <= goal) +@@ -2245,6 +2373,7 @@ print_sep_string (void) + { + char *s; + int l = col_sep_length; ++ int not_space_flag; -- 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; + s = col_sep_string; - if (ignore_case) +@@ -2258,6 +2387,7 @@ print_sep_string (void) { -- /* 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]; - } - - /* Check that successive input lines PREV and CURRENT from input file -@@ -417,6 +635,11 @@ get_line (FILE *fp, struct line **linep, - return false; - } - -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ xfields_multibyte (line); -+ else -+#endif - xfields (line); - - if (prevline[which - 1]) -@@ -518,11 +741,18 @@ prfield (size_t n, struct line const *li - - /* 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) -@@ -557,7 +787,7 @@ prjoin (struct line const *line1, struct - o = o->next; - if (o == NULL) - break; -- putchar (output_separator); -+ PUT_TAB_CHAR; - } - putchar ('\n'); - } -@@ -575,23 +805,23 @@ prjoin (struct line const *line1, struct - 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) + for (; separators_not_printed > 0; --separators_not_printed) { -- putchar (output_separator); -+ PUT_TAB_CHAR; - prfield (i, line2); - } - putchar ('\n'); -@@ -1022,20 +1252,41 @@ main (int argc, char **argv) - - 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; - -diff -urNp coreutils-8.0-orig/src/join.c.orig coreutils-8.0/src/join.c.orig ---- coreutils-8.0-orig/src/join.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/join.c.orig 2009-10-07 10:07:16.000000000 +0200 -@@ -0,0 +1,1360 @@ -+/* join - join lines of two files on a common field -+ Copyright (C) 91, 1995-2006, 2008-2009 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 . -+ -+ Written by Mike Haertel, mike@gnu.ai.mit.edu. */ -+ -+#include -+ -+#include -+#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 "quote.h" -+#include "stdio--.h" -+#include "xmemcoll.h" -+#include "xstrtol.h" -+#include "argmatch.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" -+ -+#define AUTHORS proper_name ("Mike Haertel") -+ -+#define join system_join -+ -+#define SWAPLINES(a, b) do { \ -+ struct line *tmp = a; \ -+ a = b; \ -+ b = tmp; \ -+} while (0); -+ -+/* An element of the list identifying which fields to print for each -+ output line. */ -+struct outlist -+ { -+ /* File number: 0, 1, or 2. 0 means use the join field. -+ 1 means use the first file argument, 2 the second. */ -+ int file; -+ -+ /* Field index (zero-based), specified only when FILE is 1 or 2. */ -+ size_t field; -+ -+ struct outlist *next; -+ }; -+ -+/* A field of a line. */ -+struct field -+ { -+ char *beg; /* First character in field. */ -+ size_t len; /* The length of the field. */ -+ }; -+ -+/* A line read from an input file. */ -+struct line -+ { -+ struct linebuffer buf; /* The line itself. */ -+ size_t nfields; /* Number of elements in `fields'. */ -+ size_t nfields_allocated; /* Number of elements allocated for `fields'. */ -+ struct field *fields; -+ }; -+ -+/* One or more consecutive lines read from a file that all have the -+ same join field value. */ -+struct seq -+ { -+ size_t count; /* Elements used in `lines'. */ -+ size_t alloc; /* Elements allocated in `lines'. */ -+ struct line **lines; -+ }; -+ -+/* The previous line read from each file. */ -+static struct line *prevline[2] = {NULL, NULL}; -+ -+/* This provides an extra line buffer for each file. We need these if we -+ try to read two consecutive lines into the same buffer, since we don't -+ want to overwrite the previous buffer before we check order. */ -+static struct line *spareline[2] = {NULL, NULL}; -+ -+/* True if the LC_COLLATE locale is hard. */ -+static bool hard_LC_COLLATE; -+ -+/* If nonzero, print unpairable lines in file 1 or 2. */ -+static bool print_unpairables_1, print_unpairables_2; -+ -+/* If nonzero, print pairable lines. */ -+static bool print_pairables; -+ -+/* If nonzero, we have seen at least one unpairable line. */ -+static bool seen_unpairable; -+ -+/* If nonzero, we have warned about disorder in that file. */ -+static bool issued_disorder_warning[2]; -+ -+/* Empty output field filler. */ -+static char const *empty_filler; -+ -+/* Field to join on; SIZE_MAX means they haven't been determined yet. */ -+static size_t join_field_1 = SIZE_MAX; -+static size_t join_field_2 = SIZE_MAX; -+ -+/* List of fields to print. */ -+static struct outlist outlist_head; -+ -+/* Last element in `outlist', where a new element can be added. */ -+static struct outlist *outlist_end = &outlist_head; -+ -+/* 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; -+ -+/* If nonzero, check that the input is correctly ordered. */ -+static enum -+ { -+ CHECK_ORDER_DEFAULT, -+ CHECK_ORDER_ENABLED, -+ CHECK_ORDER_DISABLED -+ } check_input_order; -+ -+enum -+{ -+ CHECK_ORDER_OPTION = CHAR_MAX + 1, -+ NOCHECK_ORDER_OPTION -+}; -+ -+ -+static struct option const longopts[] = -+{ -+ {"ignore-case", no_argument, NULL, 'i'}, -+ {"check-order", no_argument, NULL, CHECK_ORDER_OPTION}, -+ {"nocheck-order", no_argument, NULL, NOCHECK_ORDER_OPTION}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+/* Used to print non-joining lines */ -+static struct line uni_blank; -+ -+/* If nonzero, ignore case when comparing join fields. */ -+static bool ignore_case; -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... FILE1 FILE2\n\ -+"), -+ program_name); -+ fputs (_("\ -+For each pair of input lines with identical join fields, write a line to\n\ -+standard output. The default join field is the first, delimited\n\ -+by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.\n\ -+\n\ -+ -a FILENUM print unpairable lines coming from file FILENUM, where\n\ -+ FILENUM is 1 or 2, corresponding to FILE1 or FILE2\n\ -+ -e EMPTY replace missing input fields with EMPTY\n\ -+"), stdout); -+ fputs (_("\ -+ -i, --ignore-case ignore differences in case when comparing fields\n\ -+ -j FIELD equivalent to `-1 FIELD -2 FIELD'\n\ -+ -o FORMAT obey FORMAT while constructing output line\n\ -+ -t CHAR use CHAR as input and output field separator\n\ -+"), stdout); -+ fputs (_("\ -+ -v FILENUM like -a FILENUM, but suppress joined output lines\n\ -+ -1 FIELD join on this FIELD of file 1\n\ -+ -2 FIELD join on this FIELD of file 2\n\ -+ --check-order check that the input is correctly sorted, even\n\ -+ if all input lines are pairable\n\ -+ --nocheck-order do not check that the input is correctly sorted\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+Unless -t CHAR is given, leading blanks separate fields and are ignored,\n\ -+else fields are separated by CHAR. Any FIELD is a field number counted\n\ -+from 1. FORMAT is one or more comma or blank separated specifications,\n\ -+each being `FILENUM.FIELD' or `0'. Default FORMAT outputs the join field,\n\ -+the remaining fields from FILE1, the remaining fields from FILE2, all\n\ -+separated by CHAR.\n\ -+\n\ -+Important: FILE1 and FILE2 must be sorted on the join fields.\n\ -+E.g., use `sort -k 1b,1' if `join' has no options.\n\ -+Note, comparisons honor the rules specified by `LC_COLLATE'.\n\ -+If the input is not sorted and some lines cannot be joined, a\n\ -+warning message will be given.\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+/* Record a field in LINE, with location FIELD and size LEN. */ -+ -+static void -+extract_field (struct line *line, char *field, size_t len) -+{ -+ if (line->nfields >= line->nfields_allocated) -+ { -+ line->fields = X2NREALLOC (line->fields, &line->nfields_allocated); -+ } -+ line->fields[line->nfields].beg = field; -+ line->fields[line->nfields].len = len; -+ ++(line->nfields); -+} -+ -+/* Fill in the `fields' structure in LINE. */ -+ -+static void -+xfields (struct line *line) -+{ -+ char *ptr = line->buf.buffer; -+ char const *lim = ptr + line->buf.length - 1; -+ -+ if (ptr == lim) -+ return; -+ -+ if (tab != NULL) -+ { -+ unsigned char t = tab[0]; -+ char *sep; -+ for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1) -+ extract_field (line, ptr, sep - ptr); -+ } -+ else -+ { -+ /* Skip leading blanks before the first field. */ -+ while (isblank (to_uchar (*ptr))) -+ if (++ptr == lim) -+ return; -+ -+ do -+ { -+ char *sep; -+ for (sep = ptr + 1; sep != lim && ! isblank (to_uchar (*sep)); sep++) -+ continue; -+ extract_field (line, ptr, sep - ptr); -+ if (sep == lim) -+ return; -+ for (ptr = sep + 1; ptr != lim && isblank (to_uchar (*ptr)); ptr++) -+ continue; -+ } -+ while (ptr != lim); -+ } -+ -+ 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 -+ -+static void -+freeline (struct line *line) -+{ -+ free (line->fields); -+ free (line->buf.buffer); -+ line->buf.buffer = NULL; -+} -+ -+/* Return <0 if the join field in LINE1 compares less than the one in LINE2; -+ >0 if it compares greater; 0 if it compares equal. -+ Report an error and exit if the comparison fails. -+ Use join fields JF_1 and JF_2 respectively. */ -+ -+static int -+keycmp (struct line const *line1, struct line const *line2, -+ size_t jf_1, size_t jf_2) -+{ -+ /* Start of field to compare in each file. */ -+ char *beg[2]; -+ char *copy[2]; -+ size_t len[2]; /* Length of fields to compare. */ -+ int diff; -+ int i, j; -+ -+ if (jf_1 < line1->nfields) -+ { -+ beg[0] = line1->fields[jf_1].beg; -+ len[0] = line1->fields[jf_1].len; -+ } -+ else -+ { -+ beg[0] = NULL; -+ len[0] = 0; -+ } -+ -+ if (jf_2 < line2->nfields) -+ { -+ beg[1] = line2->fields[jf_2].beg; -+ len[1] = line2->fields[jf_2].len; -+ } -+ else -+ { -+ beg[1] = NULL; -+ len[1] = 0; -+ } -+ -+ if (len[0] == 0) -+ return len[1] == 0 ? 0 : -1; -+ if (len[1] == 0) -+ return 1; -+ -+ if (ignore_case) -+ { -+#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 -+ { -+ 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 len[0] - len[1]; -+} -+ -+/* Check that successive input lines PREV and CURRENT from input file -+ WHATFILE are presented in order, unless the user may be relying on -+ the GNU extension that input lines may be out of order if no input -+ lines are unpairable. -+ -+ If the user specified --nocheck-order, the check is not made. -+ If the user specified --check-order, the problem is fatal. -+ Otherwise (the default), the message is simply a warning. -+ -+ A message is printed at most once per input file. */ -+ -+static void -+check_order (const struct line *prev, -+ const struct line *current, -+ int whatfile) -+{ -+ if (check_input_order != CHECK_ORDER_DISABLED -+ && ((check_input_order == CHECK_ORDER_ENABLED) || seen_unpairable)) -+ { -+ if (!issued_disorder_warning[whatfile-1]) -+ { -+ size_t join_field = whatfile == 1 ? join_field_1 : join_field_2; -+ if (keycmp (prev, current, join_field, join_field) > 0) -+ { -+ error ((check_input_order == CHECK_ORDER_ENABLED -+ ? EXIT_FAILURE : 0), -+ 0, _("file %d is not in sorted order"), whatfile); -+ -+ /* If we get to here, the message was just a warning, but we -+ want only to issue it once. */ -+ issued_disorder_warning[whatfile-1] = true; -+ } -+ } -+ } -+} -+ -+static inline void -+reset_line (struct line *line) -+{ -+ line->nfields = 0; -+} -+ -+static struct line * -+init_linep (struct line **linep) -+{ -+ struct line *line = xmalloc (sizeof *line); -+ memset (line, '\0', sizeof *line); -+ *linep = line; -+ return line; -+} -+ -+/* Read a line from FP into LINE and split it into fields. -+ Return true if successful. */ -+ -+static bool -+get_line (FILE *fp, struct line **linep, int which) -+{ -+ struct line *line = *linep; -+ -+ if (line == prevline[which - 1]) -+ { -+ SWAPLINES (line, spareline[which - 1]); -+ *linep = line; -+ } -+ -+ if (line) -+ reset_line (line); -+ else -+ line = init_linep (linep); -+ -+ if (! readlinebuffer (&line->buf, fp)) -+ { -+ if (ferror (fp)) -+ error (EXIT_FAILURE, errno, _("read error")); -+ freeline (line); -+ return false; -+ } -+ -+ xfields (line); -+ -+ if (prevline[which - 1]) -+ check_order (prevline[which - 1], line, which); -+ -+ prevline[which - 1] = line; -+ return true; -+} -+ -+static void -+free_spareline (void) -+{ -+ size_t i; -+ -+ for (i = 0; i < ARRAY_CARDINALITY (spareline); i++) -+ { -+ if (spareline[i]) -+ { -+ freeline (spareline[i]); -+ free (spareline[i]); -+ } -+ } -+} -+ -+static void -+initseq (struct seq *seq) -+{ -+ seq->count = 0; -+ seq->alloc = 0; -+ seq->lines = NULL; -+} -+ -+/* Read a line from FP and add it to SEQ. Return true if successful. */ -+ -+static bool -+getseq (FILE *fp, struct seq *seq, int whichfile) -+{ -+ if (seq->count == seq->alloc) -+ { -+ size_t i; -+ seq->lines = X2NREALLOC (seq->lines, &seq->alloc); -+ for (i = seq->count; i < seq->alloc; i++) -+ seq->lines[i] = NULL; -+ } -+ -+ if (get_line (fp, &seq->lines[seq->count], whichfile)) -+ { -+ ++seq->count; -+ return true; -+ } -+ return false; -+} -+ -+/* Read a line from FP and add it to SEQ, as the first item if FIRST is -+ true, else as the next. */ -+static bool -+advance_seq (FILE *fp, struct seq *seq, bool first, int whichfile) -+{ -+ if (first) -+ seq->count = 0; -+ -+ return getseq (fp, seq, whichfile); -+} -+ -+static void -+delseq (struct seq *seq) -+{ -+ size_t i; -+ for (i = 0; i < seq->alloc; i++) -+ if (seq->lines[i]) -+ { -+ if (seq->lines[i]->buf.buffer) -+ freeline (seq->lines[i]); -+ free (seq->lines[i]); -+ } -+ free (seq->lines); -+} -+ -+ -+/* Print field N of LINE if it exists and is nonempty, otherwise -+ `empty_filler' if it is nonempty. */ -+ -+static void -+prfield (size_t n, struct line const *line) -+{ -+ size_t len; -+ -+ if (n < line->nfields) -+ { -+ len = line->fields[n].len; -+ if (len) -+ fwrite (line->fields[n].beg, 1, len, stdout); -+ else if (empty_filler) -+ fputs (empty_filler, stdout); -+ } -+ else if (empty_filler) -+ fputs (empty_filler, stdout); -+} -+ -+/* 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; -+ -+ outlist = outlist_head.next; -+ if (outlist) -+ { -+ const struct outlist *o; -+ -+ o = outlist; -+ while (1) -+ { -+ size_t field; -+ struct line const *line; -+ -+ if (o->file == 0) -+ { -+ if (line1 == &uni_blank) -+ { -+ line = line2; -+ field = join_field_2; -+ } -+ else -+ { -+ line = line1; -+ field = join_field_1; -+ } -+ } -+ else -+ { -+ line = (o->file == 1 ? line1 : line2); -+ field = o->field; -+ } -+ prfield (field, line); -+ o = o->next; -+ if (o == NULL) -+ break; -+ PUT_TAB_CHAR; -+ } -+ putchar ('\n'); -+ } -+ else -+ { -+ size_t i; -+ -+ if (line1 == &uni_blank) -+ { -+ struct line const *t; -+ t = line1; -+ line1 = line2; -+ line2 = t; -+ } -+ prfield (join_field_1, line1); -+ for (i = 0; i < join_field_1 && i < line1->nfields; ++i) -+ { -+ PUT_TAB_CHAR; -+ prfield (i, line1); -+ } -+ for (i = join_field_1 + 1; i < line1->nfields; ++i) -+ { -+ PUT_TAB_CHAR; -+ prfield (i, line1); -+ } -+ -+ for (i = 0; i < join_field_2 && i < line2->nfields; ++i) -+ { -+ PUT_TAB_CHAR; -+ prfield (i, line2); -+ } -+ for (i = join_field_2 + 1; i < line2->nfields; ++i) -+ { -+ PUT_TAB_CHAR; -+ prfield (i, line2); -+ } -+ putchar ('\n'); -+ } -+} -+ -+/* Print the join of the files in FP1 and FP2. */ -+ -+static void -+join (FILE *fp1, FILE *fp2) -+{ -+ struct seq seq1, seq2; -+ struct line **linep = xmalloc (sizeof *linep); -+ int diff; -+ bool eof1, eof2, checktail; -+ -+ *linep = NULL; -+ -+ /* Read the first line of each file. */ -+ initseq (&seq1); -+ getseq (fp1, &seq1, 1); -+ initseq (&seq2); -+ getseq (fp2, &seq2, 2); -+ -+ while (seq1.count && seq2.count) -+ { -+ size_t i; -+ diff = keycmp (seq1.lines[0], seq2.lines[0], -+ join_field_1, join_field_2); -+ if (diff < 0) -+ { -+ if (print_unpairables_1) -+ prjoin (seq1.lines[0], &uni_blank); -+ advance_seq (fp1, &seq1, true, 1); -+ seen_unpairable = true; -+ continue; -+ } -+ if (diff > 0) -+ { -+ if (print_unpairables_2) -+ prjoin (&uni_blank, seq2.lines[0]); -+ advance_seq (fp2, &seq2, true, 2); -+ seen_unpairable = true; -+ continue; -+ } -+ -+ /* Keep reading lines from file1 as long as they continue to -+ match the current line from file2. */ -+ eof1 = false; -+ do -+ if (!advance_seq (fp1, &seq1, false, 1)) -+ { -+ eof1 = true; -+ ++seq1.count; -+ break; -+ } -+ while (!keycmp (seq1.lines[seq1.count - 1], seq2.lines[0], -+ join_field_1, join_field_2)); -+ -+ /* Keep reading lines from file2 as long as they continue to -+ match the current line from file1. */ -+ eof2 = false; -+ do -+ if (!advance_seq (fp2, &seq2, false, 2)) -+ { -+ eof2 = true; -+ ++seq2.count; -+ break; -+ } -+ while (!keycmp (seq1.lines[0], seq2.lines[seq2.count - 1], -+ join_field_1, join_field_2)); -+ -+ if (print_pairables) -+ { -+ for (i = 0; i < seq1.count - 1; ++i) -+ { -+ size_t j; -+ for (j = 0; j < seq2.count - 1; ++j) -+ prjoin (seq1.lines[i], seq2.lines[j]); -+ } -+ } -+ -+ if (!eof1) -+ { -+ SWAPLINES (seq1.lines[0], seq1.lines[seq1.count - 1]); -+ seq1.count = 1; -+ } -+ else -+ seq1.count = 0; -+ -+ if (!eof2) -+ { -+ SWAPLINES (seq2.lines[0], seq2.lines[seq2.count - 1]); -+ seq2.count = 1; -+ } -+ else -+ seq2.count = 0; -+ } -+ -+ /* If the user did not specify --check-order, and the we read the -+ tail ends of both inputs to verify that they are in order. We -+ skip the rest of the tail once we have issued a warning for that -+ file, unless we actually need to print the unpairable lines. */ -+ if (check_input_order != CHECK_ORDER_DISABLED -+ && !(issued_disorder_warning[0] && issued_disorder_warning[1])) -+ checktail = true; -+ else -+ checktail = false; -+ -+ if ((print_unpairables_1 || checktail) && seq1.count) -+ { -+ if (print_unpairables_1) -+ prjoin (seq1.lines[0], &uni_blank); -+ seen_unpairable = true; -+ while (get_line (fp1, linep, 1)) -+ { -+ if (print_unpairables_1) -+ prjoin (*linep, &uni_blank); -+ if (issued_disorder_warning[0] && !print_unpairables_1) -+ break; -+ } -+ } -+ -+ if ((print_unpairables_2 || checktail) && seq2.count) -+ { -+ if (print_unpairables_2) -+ prjoin (&uni_blank, seq2.lines[0]); -+ seen_unpairable = true; -+ while (get_line (fp2, linep, 2)) -+ { -+ if (print_unpairables_2) -+ prjoin (&uni_blank, *linep); -+ if (issued_disorder_warning[1] && !print_unpairables_2) -+ break; -+ } -+ } -+ -+ free (*linep); -+ -+ free (linep); -+ delseq (&seq1); -+ delseq (&seq2); -+} -+ -+/* Add a field spec for field FIELD of file FILE to `outlist'. */ -+ -+static void -+add_field (int file, size_t field) -+{ -+ struct outlist *o; -+ -+ assert (file == 0 || file == 1 || file == 2); -+ assert (file != 0 || field == 0); -+ -+ o = xmalloc (sizeof *o); -+ o->file = file; -+ o->field = field; -+ o->next = NULL; -+ -+ /* Add to the end of the list so the fields are in the right order. */ -+ outlist_end->next = o; -+ outlist_end = o; -+} -+ -+/* Convert a string of decimal digits, STR (the 1-based join field number), -+ to an integral value. Upon successful conversion, return one less -+ (the zero-based field number). Silently convert too-large values -+ to SIZE_MAX - 1. Otherwise, if a value cannot be converted, give a -+ diagnostic and exit. */ -+ -+static size_t -+string_to_join_field (char const *str) -+{ -+ size_t result; -+ unsigned long int val; -+ verify (SIZE_MAX <= ULONG_MAX); -+ -+ strtol_error s_err = xstrtoul (str, NULL, 10, &val, ""); -+ if (s_err == LONGINT_OVERFLOW || (s_err == LONGINT_OK && SIZE_MAX < val)) -+ val = SIZE_MAX; -+ else if (s_err != LONGINT_OK || val == 0) -+ error (EXIT_FAILURE, 0, _("invalid field number: %s"), quote (str)); -+ -+ result = val - 1; -+ -+ return result; -+} -+ -+/* Convert a single field specifier string, S, to a *FILE_INDEX, *FIELD_INDEX -+ pair. In S, the field index string is 1-based; *FIELD_INDEX is zero-based. -+ If S is valid, return true. Otherwise, give a diagnostic and exit. */ -+ -+static void -+decode_field_spec (const char *s, int *file_index, size_t *field_index) -+{ -+ /* The first character must be 0, 1, or 2. */ -+ switch (s[0]) -+ { -+ case '0': -+ if (s[1]) -+ { -+ /* `0' must be all alone -- no `.FIELD'. */ -+ error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s)); -+ } -+ *file_index = 0; -+ *field_index = 0; -+ break; -+ -+ case '1': -+ case '2': -+ if (s[1] != '.') -+ error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s)); -+ *file_index = s[0] - '0'; -+ *field_index = string_to_join_field (s + 2); -+ break; -+ -+ default: -+ error (EXIT_FAILURE, 0, -+ _("invalid file number in field spec: %s"), quote (s)); -+ -+ /* Tell gcc -W -Wall that we can't get beyond this point. -+ This avoids a warning (otherwise legit) that the caller's copies -+ of *file_index and *field_index might be used uninitialized. */ -+ abort (); -+ -+ break; -+ } -+} -+ -+/* Add the comma or blank separated field spec(s) in STR to `outlist'. */ -+ -+static void -+add_field_list (char *str) -+{ -+ char *p = str; -+ -+ do -+ { -+ int file_index; -+ size_t field_index; -+ char const *spec_item = p; -+ -+ p = strpbrk (p, ", \t"); -+ if (p) -+ *p++ = '\0'; -+ decode_field_spec (spec_item, &file_index, &field_index); -+ add_field (file_index, field_index); -+ } -+ while (p); -+} -+ -+/* Set the join field *VAR to VAL, but report an error if *VAR is set -+ more than once to incompatible values. */ -+ -+static void -+set_join_field (size_t *var, size_t val) -+{ -+ if (*var != SIZE_MAX && *var != val) -+ { -+ unsigned long int var1 = *var + 1; -+ unsigned long int val1 = val + 1; -+ error (EXIT_FAILURE, 0, _("incompatible join fields %lu, %lu"), -+ var1, val1); -+ } -+ *var = val; -+} -+ -+/* Status of command-line arguments. */ -+ -+enum operand_status -+ { -+ /* This argument must be an operand, i.e., one of the files to be -+ joined. */ -+ MUST_BE_OPERAND, -+ -+ /* This might be the argument of the preceding -j1 or -j2 option, -+ or it might be an operand. */ -+ MIGHT_BE_J1_ARG, -+ MIGHT_BE_J2_ARG, -+ -+ /* This might be the argument of the preceding -o option, or it might be -+ an operand. */ -+ MIGHT_BE_O_ARG -+ }; -+ -+/* Add NAME to the array of input file NAMES with operand statuses -+ OPERAND_STATUS; currently there are NFILES names in the list. */ -+ -+static void -+add_file_name (char *name, char *names[2], -+ int operand_status[2], int joption_count[2], int *nfiles, -+ int *prev_optc_status, int *optc_status) -+{ -+ int n = *nfiles; -+ -+ if (n == 2) -+ { -+ bool op0 = (operand_status[0] == MUST_BE_OPERAND); -+ char *arg = names[op0]; -+ switch (operand_status[op0]) -+ { -+ case MUST_BE_OPERAND: -+ error (0, 0, _("extra operand %s"), quote (name)); -+ usage (EXIT_FAILURE); -+ -+ case MIGHT_BE_J1_ARG: -+ joption_count[0]--; -+ set_join_field (&join_field_1, string_to_join_field (arg)); -+ break; -+ -+ case MIGHT_BE_J2_ARG: -+ joption_count[1]--; -+ set_join_field (&join_field_2, string_to_join_field (arg)); -+ break; -+ -+ case MIGHT_BE_O_ARG: -+ add_field_list (arg); -+ break; -+ } -+ if (!op0) -+ { -+ operand_status[0] = operand_status[1]; -+ names[0] = names[1]; -+ } -+ n = 1; -+ } -+ -+ operand_status[n] = *prev_optc_status; -+ names[n] = name; -+ *nfiles = n + 1; -+ if (*prev_optc_status == MIGHT_BE_O_ARG) -+ *optc_status = MIGHT_BE_O_ARG; -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int optc_status; -+ int prev_optc_status = MUST_BE_OPERAND; -+ int operand_status[2]; -+ int joption_count[2] = { 0, 0 }; -+ char *names[2]; -+ FILE *fp1, *fp2; -+ int optc; -+ int nfiles = 0; -+ int i; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ hard_LC_COLLATE = hard_locale (LC_COLLATE); -+ -+ atexit (close_stdout); -+ atexit (free_spareline); -+ -+ print_pairables = true; -+ seen_unpairable = false; -+ issued_disorder_warning[0] = issued_disorder_warning[1] = false; -+ check_input_order = CHECK_ORDER_DEFAULT; -+ -+ while ((optc = getopt_long (argc, argv, "-a:e:i1:2:j:o:t:v:", -+ longopts, NULL)) -+ != -1) -+ { -+ optc_status = MUST_BE_OPERAND; -+ -+ switch (optc) -+ { -+ case 'v': -+ print_pairables = false; -+ /* Fall through. */ -+ -+ case 'a': -+ { -+ unsigned long int val; -+ if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK -+ || (val != 1 && val != 2)) -+ error (EXIT_FAILURE, 0, -+ _("invalid field number: %s"), quote (optarg)); -+ if (val == 1) -+ print_unpairables_1 = true; -+ else -+ print_unpairables_2 = true; -+ } -+ break; -+ -+ case 'e': -+ if (empty_filler && ! STREQ (empty_filler, optarg)) -+ error (EXIT_FAILURE, 0, -+ _("conflicting empty-field replacement strings")); -+ empty_filler = optarg; -+ break; -+ -+ case 'i': -+ ignore_case = true; -+ break; -+ -+ case '1': -+ set_join_field (&join_field_1, string_to_join_field (optarg)); -+ break; -+ -+ case '2': -+ set_join_field (&join_field_2, string_to_join_field (optarg)); -+ break; -+ -+ case 'j': -+ if ((optarg[0] == '1' || optarg[0] == '2') && !optarg[1] -+ && optarg == argv[optind - 1] + 2) -+ { -+ /* The argument was either "-j1" or "-j2". */ -+ bool is_j2 = (optarg[0] == '2'); -+ joption_count[is_j2]++; -+ optc_status = MIGHT_BE_J1_ARG + is_j2; -+ } -+ else -+ { -+ set_join_field (&join_field_1, string_to_join_field (optarg)); -+ set_join_field (&join_field_2, join_field_1); -+ } -+ break; -+ -+ case 'o': -+ add_field_list (optarg); -+ optc_status = MIGHT_BE_O_ARG; -+ break; -+ -+ case 't': -+ { -+ char *newtab; -+ size_t newtablen; -+ if (! optarg[0]) -+ error (EXIT_FAILURE, 0, _("empty tab")); -+ 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)) -+ { -+ free (newtab); -+ error (EXIT_FAILURE, 0, _("incompatible tabs")); -+ } -+ tab = newtab; -+ tablen = newtablen; -+ } -+ break; -+ -+ case NOCHECK_ORDER_OPTION: -+ check_input_order = CHECK_ORDER_DISABLED; -+ break; -+ -+ case CHECK_ORDER_OPTION: -+ check_input_order = CHECK_ORDER_ENABLED; -+ break; -+ -+ case 1: /* Non-option argument. */ -+ add_file_name (optarg, names, operand_status, joption_count, -+ &nfiles, &prev_optc_status, &optc_status); -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (EXIT_FAILURE); -+ } -+ -+ prev_optc_status = optc_status; -+ } -+ -+ /* Process any operands after "--". */ -+ prev_optc_status = MUST_BE_OPERAND; -+ while (optind < argc) -+ add_file_name (argv[optind++], names, operand_status, joption_count, -+ &nfiles, &prev_optc_status, &optc_status); -+ -+ if (nfiles != 2) -+ { -+ if (nfiles == 0) -+ error (0, 0, _("missing operand")); -+ else -+ error (0, 0, _("missing operand after %s"), quote (argv[argc - 1])); -+ usage (EXIT_FAILURE); -+ } -+ -+ /* If "-j1" was specified and it turns out not to have had an argument, -+ treat it as "-j 1". Likewise for -j2. */ -+ for (i = 0; i < 2; i++) -+ if (joption_count[i] != 0) -+ { -+ set_join_field (&join_field_1, i); -+ set_join_field (&join_field_2, i); -+ } -+ -+ if (join_field_1 == SIZE_MAX) -+ join_field_1 = 0; -+ if (join_field_2 == SIZE_MAX) -+ join_field_2 = 0; -+ -+ fp1 = STREQ (names[0], "-") ? stdin : fopen (names[0], "r"); -+ if (!fp1) -+ error (EXIT_FAILURE, errno, "%s", names[0]); -+ fp2 = STREQ (names[1], "-") ? stdin : fopen (names[1], "r"); -+ if (!fp2) -+ error (EXIT_FAILURE, errno, "%s", names[1]); -+ if (fp1 == fp2) -+ error (EXIT_FAILURE, errno, _("both files cannot be standard input")); -+ join (fp1, fp2); -+ -+ if (fclose (fp1) != 0) -+ error (EXIT_FAILURE, errno, "%s", names[0]); -+ if (fclose (fp2) != 0) -+ error (EXIT_FAILURE, errno, "%s", names[1]); -+ -+ if (issued_disorder_warning[0] || issued_disorder_warning[1]) -+ exit (EXIT_FAILURE); -+ else -+ exit (EXIT_SUCCESS); -+} -diff -urNp coreutils-8.0-orig/src/pr.c coreutils-8.0/src/pr.c ---- coreutils-8.0-orig/src/pr.c 2009-09-29 15:27:54.000000000 +0200 -+++ coreutils-8.0/src/pr.c 2009-10-07 10:07:16.000000000 +0200 -@@ -312,6 +312,32 @@ - - #include - #include -+ -+/* Get MB_LEN_MAX. */ -+#include -+/* 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 == 1 -+# define MB_LEN_MAX 16 -+#endif -+ -+/* Get MB_CUR_MAX. */ -+#include -+ -+/* Solaris 2.5 has a bug: must be included before . */ -+/* Get mbstate_t, mbrtowc(), wcwidth(). */ -+#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 "error.h" - #include "hard-locale.h" -@@ -322,6 +348,18 @@ - #include "strftime.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 -+ -+#ifndef HAVE_DECL_WCWIDTH -+"this configure-time declaration test was not run" -+#endif -+#if !HAVE_DECL_WCWIDTH -+extern int wcwidth (); -+#endif -+ - /* The official name of this program (e.g., no `g' prefix). */ - #define PROGRAM_NAME "pr" - -@@ -414,7 +452,20 @@ struct COLUMN - - typedef struct COLUMN COLUMN; - --static int char_to_clump (char c); -+/* Funtion pointers to switch functions for single byte locale or for -+ multibyte locale. If multibyte functions do not exist in your sysytem, -+ these pointers always point the function for single byte locale. */ -+static void (*print_char) (char c); -+static int (*char_to_clump) (char c); -+ -+/* Functions for single byte locale. */ -+static void print_char_single (char c); -+static int char_to_clump_single (char c); -+ -+/* Functions for multibyte locale. */ -+static void print_char_multi (char c); -+static int char_to_clump_multi (char c); -+ - static bool read_line (COLUMN *p); - static bool print_page (void); - static bool print_stored (COLUMN *p); -@@ -424,6 +475,7 @@ static void print_header (void); - static void pad_across_to (int position); - static void add_line_number (COLUMN *p); - static void getoptarg (char *arg, char switch_char, char *character, -+ int *character_length, int *character_width, - int *number); - void usage (int status); - static void print_files (int number_of_files, char **av); -@@ -438,7 +490,6 @@ static void store_char (char c); - 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 (const char *optarg_S); -@@ -450,7 +501,7 @@ static COLUMN *column_vector; - 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]. */ --static char *buff; -+static unsigned char *buff; - - /* Index of the position in buff where the next character - will be stored. */ -@@ -554,7 +605,7 @@ static int chars_per_column; - static bool untabify_input = false; - - /* (-e) The input tab character. */ --static char input_tab_char = '\t'; -+static char input_tab_char[MB_LEN_MAX] = "\t"; - - /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ... - where the leftmost column is 1. */ -@@ -564,7 +615,10 @@ static int chars_per_input_tab = 8; - static bool tabify_output = false; - - /* (-i) The output tab character. */ --static char output_tab_char = '\t'; -+static char output_tab_char[MB_LEN_MAX] = "\t"; -+ -+/* (-i) The byte length of output tab character. */ -+static int output_tab_char_length = 1; - - /* (-i) The width of the output tab. */ - static int chars_per_output_tab = 8; -@@ -638,7 +692,13 @@ static int power_10; - static bool numbered_lines = false; - - /* (-n) Character which follows each line number. */ --static char number_separator = '\t'; -+static char number_separator[MB_LEN_MAX] = "\t"; -+ -+/* (-n) The byte length of the character which follows each line number. */ -+static int number_separator_length = 1; -+ -+/* (-n) The character width of the character which follows each line number. */ -+static int number_separator_width = 0; - - /* (-n) line counting starts with 1st line of input file (not with 1st - line of 1st page printed). */ -@@ -691,6 +751,7 @@ static bool use_col_separator = false; - -a|COLUMN|-m is a `space' and with the -J option a `tab'. */ - static char *col_sep_string = (char *) ""; - static int col_sep_length = 0; -+static int col_sep_width = 0; - static char *column_separator = (char *) " "; - static char *line_separator = (char *) "\t"; - -@@ -847,6 +908,13 @@ separator_string (const char *optarg_S) - 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) -+ col_sep_width = mbswidth (col_sep_string, 0); -+ else -+#endif -+ col_sep_width = col_sep_length; - } - - int -@@ -871,6 +939,21 @@ main (int argc, char **argv) - - atexit (close_stdout); - -+/* Define which functions are used, the ones for single byte locale or the ones -+ for multibyte locale. */ -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ { -+ print_char = print_char_multi; -+ char_to_clump = char_to_clump_multi; -+ } -+ else -+#endif -+ { -+ print_char = print_char_single; -+ char_to_clump = char_to_clump_single; -+ } -+ - n_files = 0; - file_names = (argc > 1 - ? xmalloc ((argc - 1) * sizeof (char *)) -@@ -947,8 +1030,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; -+ -+ getoptarg (optarg, 'e', input_tab_char, &dummy_length, -+ &dummy_width, &chars_per_input_tab); -+ } - /* Could check tab width > 0. */ - untabify_input = true; - break; -@@ -961,8 +1048,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, 'i', output_tab_char, &output_tab_char_length, -+ &dummy_width, &chars_per_output_tab); -+ } - /* Could check tab width > 0. */ - tabify_output = true; - break; -@@ -989,8 +1080,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; -@@ -1029,7 +1120,7 @@ main (int argc, char **argv) - old_s = false; - /* Reset an additional input of -s, -S dominates -s */ - col_sep_string = bad_cast (""); -- col_sep_length = 0; -+ col_sep_length = col_sep_width = 0; - use_col_separator = true; - if (optarg) - separator_string (optarg); -@@ -1186,10 +1277,45 @@ main (int argc, char **argv) - 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) - { - 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'}; -+ -+ 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; -+ } -+ -+ strncpy (character, arg, *character_length); -+ arg += *character_length; -+ } -+ else /* for single byte locale. */ -+#endif -+ { -+ *character = *arg++; -+ *character_length = 1; -+ *character_width = 1; -+ } -+ } -+ - if (*arg) - { - long int tmp_long; -@@ -1248,7 +1374,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; - } - /* It's rather pointless to define a TAB separator with column -@@ -1279,11 +1405,11 @@ init_parameters (int number_of_files) - 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); - else -- 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. */ -@@ -1298,7 +1424,7 @@ init_parameters (int number_of_files) - } - - chars_per_column = (chars_per_line - chars_used_by_number - -- (columns - 1) * col_sep_length) / columns; -+ (columns - 1) * col_sep_width) / columns; - - if (chars_per_column < 1) - error (EXIT_FAILURE, 0, _("page width too narrow")); -@@ -1423,7 +1549,7 @@ init_funcs (void) - - /* Enlarge p->start_position of first column to use the same form of - padding_not_printed with all columns. */ -- h = h + col_sep_length; -+ h = h + col_sep_width; - - /* This loop takes care of all but the rightmost column. */ - -@@ -1457,7 +1583,7 @@ init_funcs (void) - } - else - { -- h = h_next + col_sep_length; -+ h = h_next + col_sep_width; - h_next = h + chars_per_column; - } - } -@@ -1747,9 +1873,9 @@ static void - align_column (COLUMN *p) - { - padding_not_printed = p->start_position; -- 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; - } - -@@ -2020,13 +2146,13 @@ store_char (char c) - /* May be too generous. */ - buff = X2REALLOC (buff, &buff_allocated); - } -- buff[buff_current++] = c; -+ buff[buff_current++] = (unsigned char) c; - } - - static void - add_line_number (COLUMN *p) - { -- int i; -+ int i, j; - char *s; - int left_cut; - -@@ -2049,22 +2175,24 @@ add_line_number (COLUMN *p) - /* 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. */ -- if (number_separator == '\t') -+ if (number_separator[0] == '\t') - { - i = number_width - chars_per_number; - while (i-- > 0) - (p->char_func) (' '); - } - else -- (p->char_func) (number_separator); -+ 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 - separator with a single column output. No column_width requirement - has to be considered. */ - { -- (p->char_func) (number_separator); -- if (number_separator == '\t') -+ for (j = 0; j < number_separator_length; j++) -+ (p->char_func) (number_separator[j]); -+ if (number_separator[0] == '\t') - output_position = POS_AFTER_TAB (chars_per_output_tab, - output_position); - } -@@ -2225,7 +2353,7 @@ print_white_space (void) - while (goal - h_old > 1 - && (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) -@@ -2245,6 +2373,7 @@ print_sep_string (void) - { - char *s; - int l = col_sep_length; -+ int not_space_flag; - - s = col_sep_string; - -@@ -2258,6 +2387,7 @@ print_sep_string (void) - { - 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 +2401,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; -+ - /* sep_string ends with some spaces */ - if (spaces_not_printed > 0) - print_white_space (); -@@ -2304,7 +2437,7 @@ print_clump (COLUMN *p, int n, char *clu - required number of tabs and spaces. */ - - static void --print_char (char c) -+print_char_single (char c) - { - if (tabify_output) - { -@@ -2328,6 +2461,74 @@ print_char (char c) - putchar (c); - } - -+#ifdef HAVE_MBRTOWC -+static void -+print_char_multi (char c) -+{ -+ static size_t mbc_pos = 0; -+ static char mbc[MB_LEN_MAX] = {'\0'}; -+ static mbstate_t state = {'\0'}; -+ mbstate_t state_bak; -+ wchar_t wc; -+ size_t mblength; -+ int width; -+ -+ if (tabify_output) -+ { -+ state_bak = state; -+ mbc[mbc_pos++] = c; -+ mblength = mbrtowc (&wc, mbc, mbc_pos, &state); -+ -+ while (mbc_pos > 0) -+ { -+ 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 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 (); -+ -+ /* 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; -+ } -+ } -+ return; -+ } -+ putchar (c); -+} -+#endif -+ - /* Skip to page PAGE before printing. - PAGE may be larger than total number of pages. */ - -@@ -2507,9 +2708,9 @@ read_line (COLUMN *p) - align_empty_cols = false; - } - -- 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; - } - -@@ -2610,9 +2811,9 @@ print_stored (COLUMN *p) - } - } - -- 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 +2826,8 @@ print_stored (COLUMN *p) - 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; -+ if (p->start_position - col_sep_width == chars_per_margin) -+ output_position -= col_sep_width; - } - - return true; -@@ -2645,7 +2846,7 @@ print_stored (COLUMN *p) - number of characters is 1.) */ - - static int --char_to_clump (char c) -+char_to_clump_single (char c) - { - unsigned char uc = c; - char *s = clump_buff; -@@ -2655,10 +2856,10 @@ char_to_clump (char c) - int chars; - int chars_per_c = 8; - -- if (c == input_tab_char) -+ if (c == input_tab_char[0]) - chars_per_c = chars_per_input_tab; - -- if (c == input_tab_char || c == '\t') -+ if (c == input_tab_char[0] || c == '\t') - { - width = TAB_WIDTH (chars_per_c, input_position); - -@@ -2739,6 +2940,154 @@ char_to_clump (char c) - return chars; - } - -+#ifdef HAVE_MBRTOWC -+static int -+char_to_clump_multi (char c) -+{ -+ static size_t mbc_pos = 0; -+ static char mbc[MB_LEN_MAX] = {'\0'}; -+ static mbstate_t state = {'\0'}; -+ mbstate_t state_bak; -+ wchar_t wc; -+ size_t mblength; -+ int wc_width; -+ register char *s = clump_buff; -+ register int i, j; -+ char esc_buff[4]; -+ int width; -+ int chars; -+ int chars_per_c = 8; -+ -+ state_bak = state; -+ mbc[mbc_pos++] = c; -+ mblength = mbrtowc (&wc, mbc, mbc_pos, &state); -+ -+ width = 0; -+ chars = 0; -+ while (mbc_pos > 0) -+ { -+ switch (mblength) -+ { -+ case (size_t)-2: -+ state = state_bak; -+ return 0; -+ -+ 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", 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 */ -+ -+ 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; -+ -+ 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", 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; -+ } -+ -+ input_position += width; -+ return chars; -+} -+#endif -+ - /* 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 -urNp coreutils-8.0-orig/src/pr.c.orig coreutils-8.0/src/pr.c.orig ---- coreutils-8.0-orig/src/pr.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/pr.c.orig 2009-09-29 15:27:54.000000000 +0200 -@@ -0,0 +1,2877 @@ -+/* pr -- convert text files for printing. -+ Copyright (C) 88, 91, 1995-2009 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 . */ -+ -+/* By Pete TerMaat, with considerable refinement by Roland Huebner. */ -+ -+/* Things to watch: Sys V screws up on ... -+ pr -n -3 -s: /usr/dict/words -+ pr -m -o10 -n /usr/dict/words{,,,} -+ pr -6 -a -n -o5 /usr/dict/words -+ -+ Ideas: -+ -+ Keep a things_to_do list of functions to call when we know we have -+ something to print. Cleaner than current series of checks. -+ -+ Improve the printing of control prefixes. -+ -+ Expand the file name in the centered header line to a full file name. -+ -+ -+ Concept: -+ -+ If the input_tab_char differs from the default value TAB -+ (`-e[CHAR[...]]' is used), any input text tab is expanded to the -+ default width of 8 spaces (compare char_to_clump). - Same as SunOS -+ does. -+ -+ The treatment of the number_separator (compare add_line_number): -+ The default value TAB of the number_separator (`-n[SEP[...]]') doesn't -+ be thought to be an input character. An optional `-e'-input has no -+ effect. -+ - With single column output -+ only one POSIX requirement has to be met: -+ The default n-separator should be a TAB. The consequence is a -+ different width between the number and the text if the output position -+ of the separator changes, i.e. it depends upon the left margin used. -+ That's not nice but easy-to-use together with the defaults of other -+ utilities, e.g. sort or cut. - Same as SunOS does. -+ - With multicolumn output -+ two conflicting POSIX requirements exist: -+ First `default n-separator is TAB', second `output text columns shall -+ be of equal width'. Moreover POSIX specifies the number+separator a -+ part of the column, together with `-COLUMN' and `-a -COLUMN'. -+ (With -m output the number shall occupy each line only once. Exactly -+ the same situation as single column output exists.) -+ GNU pr gives priority to the 2nd requirement and observes POSIX -+ column definition. The n-separator TAB is expanded to the same number -+ of spaces in each column using the default value 8. Tabification is -+ only performed if it is compatible with the output position. -+ Consequence: The output text columns are of equal width. The layout -+ of a page does not change if the left margin varies. - Looks better -+ than the SunOS approach. -+ SunOS pr gives priority to the 1st requirement. n-separator TAB -+ width varies with each column. Only the width of text part of the -+ column is fixed. -+ Consequence: The output text columns don't have equal width. The -+ widths and the layout of the whole page varies with the left margin. -+ An overflow of the line length (without margin) over the input value -+ PAGE_WIDTH may occur. -+ -+ The interference of the POSIX-compliant small letter options -w and -s: -+ (`interference' means `setting a _separator_ with -s switches off the -+ column structure and the default - not generally - page_width, -+ acts on -w option') -+ options: text form / separator: equivalent new options: -+ -w l -s[x] -+ -------------------------------------------------------------------- -+ 1. -- -- columns / space -- -+ trunc. to page_width = 72 -+ 2. -- -s[:] full lines / TAB[:] -J --sep-string[=""|:] -+ no truncation -+ 3. -w l -- columns / space -W l -+ trunc. to page_width = l -+ 4. -w l -s[:] columns / no sep.[:] -W l --sep-string[=:] -+ trunc. to page_width = l -+ -------------------------------------------------------------------- -+ -+ -+ Options: -+ -+ Including version 1.22i: -+ Some SMALL LETTER options have been redefined with the object of a -+ better POSIX compliance. The output of some further cases has been -+ adapted to other UNIXes. A violation of downward compatibility has to -+ be accepted. -+ Some NEW CAPITAL LETTER options ( -J, -S, -W) has been introduced to -+ turn off unexpected interferences of small letter options (-s and -w -+ together with the three column options). -+ -N option and the second argument LAST_PAGE of +FIRST_PAGE offer more -+ flexibility; The detailed handling of form feeds set in the input -+ files requires -T option. -+ -+ Capital letter options dominate small letter ones. -+ -+ Some of the option-arguments cannot be specified as separate arguments -+ from the preceding option letter (already stated in POSIX specification). -+ -+ Form feeds in the input cause page breaks in the output. Multiple -+ form feeds produce empty pages. -+ -+ +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE] -+ begin [stop] printing with page FIRST_[LAST_]PAGE -+ -+ -COLUMN, --columns=COLUMN -+ Produce output that is COLUMN columns wide and -+ print columns down, unless -a is used. Balance number of -+ lines in the columns on each page. -+ -+ -a, --across Print columns across rather than down, used -+ together with -COLUMN. The input -+ one -+ two -+ three -+ four -+ will be printed with `-a -3' as -+ one two three -+ four -+ -+ -b Balance columns on the last page. -+ -b is no longer an independent option. It's always used -+ together with -COLUMN (unless -a is used) to get a -+ consistent formulation with "FF set by hand" in input -+ files. Each formfeed found terminates the number of lines -+ to be read with the actual page. The situation for -+ printing columns down is equivalent to that on the last -+ page. So we need a balancing. -+ -+ Keeping -b as an underground option guarantees some -+ downward compatibility. Utilities using pr with -b -+ (a most frequently used form) still work as usual. -+ -+ -c, --show-control-chars -+ Print unprintable characters as control prefixes. -+ Control-g is printed as ^G (use hat notation) and -+ octal backslash notation. -+ -+ -d, --double-space Double space the output. -+ -+ -D FORMAT, --date-format=FORMAT Use FORMAT for the header date. -+ -+ -e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]] -+ Expand tabs to spaces on input. Optional argument CHAR -+ is the input TAB character. (Default is TAB). Optional -+ argument WIDTH is the input TAB character's width. -+ (Default is 8.) -+ -+ -F, -f, --form-feed Use formfeeds instead of newlines to separate -+ pages. A three line HEADER is used, no TRAILER with -F, -+ without -F both HEADER and TRAILER are made of five lines. -+ -+ -h HEADER, --header=HEADER -+ Replace the filename in the header with the string HEADER. -+ A centered header is used. -+ -+ -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]] -+ Replace spaces with tabs on output. Optional argument -+ CHAR is the output TAB character. (Default is TAB). -+ Optional argument WIDTH is the output TAB character's -+ width. (Default is 8) -+ -+ -J, --join-lines Merge lines of full length, turns off -W/-w -+ line truncation, no column alignment, --sep-string[=STRING] -+ sets separators, works with all column options -+ (-COLUMN | -a -COLUMN | -m). -+ -J has been introduced (together with -W and --sep-string) to -+ disentangle the old (POSIX compliant) options -w, -s -+ along with the 3 column options. -+ -+ -l PAGE_LENGTH, --length=PAGE_LENGTH -+ Set the page length to PAGE_LENGTH lines. Default is 66, -+ including 5 lines of HEADER and 5 lines of TRAILER -+ without -F, but only 3 lines of HEADER and no TRAILER -+ with -F (i.e the number of text lines defaults to 56 or -+ 63 respectively). -+ -+ -m, --merge Print files in parallel; pad_across_to align -+ columns; truncate lines and print separator strings; -+ Do it also with empty columns to get a continuous line -+ numbering and column marking by separators throughout -+ the whole merged file. -+ -+ Empty pages in some input files produce empty columns -+ [marked by separators] in the merged pages. Completely -+ empty merged pages show no column separators at all. -+ -+ The layout of a merged page is ruled by the largest form -+ feed distance of the single pages at that page. Shorter -+ columns will be filled up with empty lines. -+ -+ Together with -J option join lines of full length and -+ set separators when -S option is used. -+ -+ -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]] -+ Provide DIGITS digit line numbering (default for DIGITS -+ is 5). With multicolumn output the number occupies the -+ first DIGITS column positions of each text column or only -+ each line of -m output. -+ With single column output the number precedes each line -+ just as -m output. -+ Optional argument SEP is the character appended to the -+ line number to separate it from the text followed. -+ The default separator is a TAB. In a strict sense a TAB -+ is always printed with single column output only. The -+ TAB-width varies with the TAB-position, e.g. with the -+ left margin specified by -o option. -+ With multicolumn output priority is given to `equal width -+ of output columns' (a POSIX specification). The TAB-width -+ is fixed to the value of the 1st column and does not -+ change with different values of left margin. That means a -+ fixed number of spaces is always printed in the place of -+ a TAB. The tabification depends upon the output -+ position. -+ -+ Default counting of the line numbers starts with 1st -+ line of the input file (not the 1st line printed, -+ compare the --page option and -N option). -+ -+ -N NUMBER, --first-line-number=NUMBER -+ Start line counting with the number NUMBER at the 1st -+ line of first page printed (mostly not the 1st line of -+ the input file). -+ -+ -o MARGIN, --indent=MARGIN -+ Offset each line with a margin MARGIN spaces wide. -+ Total page width is the size of the margin plus the -+ PAGE_WIDTH set with -W/-w option. -+ -+ -r, --no-file-warnings -+ Omit warning when a file cannot be opened. -+ -+ -s[CHAR], --separator[=CHAR] -+ Separate columns by a single character CHAR, default for -+ CHAR is the TAB character without -w and 'no char' with -w. -+ Without `-s' default separator `space' is set. -+ -s[CHAR] turns off line truncation of all 3 column options -+ (-COLUMN|-a -COLUMN|-m) except -w is set. That is a POSIX -+ compliant formulation. The source code translates -s into -+ the new options -S and -J, also -W if required. -+ -+ -S STRING, --sep-string[=STRING] -+ Separate columns by any string STRING. The -S option -+ doesn't react upon the -W/-w option (unlike -s option -+ does). It defines a separator nothing else. -+ Without -S: Default separator TAB is used with -J and -+ `space' otherwise (same as -S" "). -+ With -S "": No separator is used. -+ Quotes should be used with blanks and some shell active -+ characters. -+ -S is problematic because in its obsolete form you -+ cannot use -S "STRING", but in its standard form you -+ must use -S "STRING" if STRING is empty. Use -+ --sep-string to avoid the ambiguity. -+ -+ -t, --omit-header Do not print headers or footers but retain form -+ feeds set in the input files. -+ -+ -T, --omit-pagination -+ Do not print headers or footers, eliminate any pagination -+ by form feeds set in the input files. -+ -+ -v, --show-nonprinting -+ Print unprintable characters as escape sequences. Use -+ octal backslash notation. Control-G becomes \007. -+ -+ -w PAGE_WIDTH, --width=PAGE_WIDTH -+ Set page width to PAGE_WIDTH characters for multiple -+ text-column output only (default for PAGE_WIDTH is 72). -+ -s[CHAR] turns off the default page width and any line -+ truncation. Lines of full length will be merged, -+ regardless of the column options set. A POSIX compliant -+ formulation. -+ -+ -W PAGE_WIDTH, --page-width=PAGE_WIDTH -+ Set the page width to PAGE_WIDTH characters. That's valid -+ with and without a column option. Text lines will be -+ truncated, unless -J is used. Together with one of the -+ column options (-COLUMN| -a -COLUMN| -m) column alignment -+ is always used. -+ Default is 72 characters. -+ Without -W PAGE_WIDTH -+ - but with one of the column options default truncation of -+ 72 characters is used (to keep downward compatibility -+ and to simplify most frequently met column tasks). -+ Column alignment and column separators are used. -+ - and without any of the column options NO line truncation -+ is used (to keep downward compatibility and to meet most -+ frequent tasks). That's equivalent to -W 72 -J . -+ -+ With/without -W PAGE_WIDTH the header line is always -+ truncated to avoid line overflow. -+ -+ (In pr versions newer than 1.14 -S option does no longer -+ affect -W option.) -+ -+*/ -+ -+ -+#include -+ -+#include -+#include -+#include "system.h" -+#include "error.h" -+#include "hard-locale.h" -+#include "mbswidth.h" -+#include "quote.h" -+#include "stat-time.h" -+#include "stdio--.h" -+#include "strftime.h" -+#include "xstrtol.h" -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "pr" -+ -+#define AUTHORS \ -+ proper_name ("Pete TerMaat"), \ -+ proper_name ("Roland Huebner") -+ -+/* Used with start_position in the struct COLUMN described below. -+ If start_position == ANYWHERE, we aren't truncating columns and -+ can begin printing a column anywhere. Otherwise we must pad to -+ the horizontal position start_position. */ -+#define ANYWHERE 0 -+ -+/* Each column has one of these structures allocated for it. -+ If we're only dealing with one file, fp is the same for all -+ columns. -+ -+ The general strategy is to spend time setting up these column -+ structures (storing columns if necessary), after which printing -+ is a matter of flitting from column to column and calling -+ print_func. -+ -+ Parallel files, single files printing across in multiple -+ columns, and single files printing down in multiple columns all -+ fit the same printing loop. -+ -+ print_func Function used to print lines in this column. -+ If we're storing this column it will be -+ print_stored(), Otherwise it will be read_line(). -+ -+ char_func Function used to process characters in this column. -+ If we're storing this column it will be store_char(), -+ otherwise it will be print_char(). -+ -+ current_line Index of the current entry in line_vector, which -+ contains the index of the first character of the -+ current line in buff[]. -+ -+ lines_stored Number of lines in this column which are stored in -+ buff. -+ -+ lines_to_print If we're storing this column, lines_to_print is -+ the number of stored_lines which remain to be -+ printed. Otherwise it is the number of lines -+ we can print without exceeding lines_per_body. -+ -+ start_position The horizontal position we want to be in before we -+ print the first character in this column. -+ -+ numbered True means precede this column with a line number. */ -+ -+/* FIXME: There are many unchecked integer overflows in this file, -+ that will cause this command to misbehave given large inputs or -+ options. Many of the "int" values below should be "size_t" or -+ something else like that. */ -+ -+struct COLUMN; -+struct COLUMN -+ { -+ FILE *fp; /* Input stream for this column. */ -+ char const *name; /* File name. */ -+ enum -+ { -+ OPEN, -+ FF_FOUND, /* used with -b option, set with \f, changed -+ to ON_HOLD after print_header */ -+ ON_HOLD, /* Hit a form feed. */ -+ CLOSED -+ } -+ status; /* Status of the file pointer. */ -+ -+ /* Func to print lines in this col. */ -+ bool (*print_func) (struct COLUMN *); -+ -+ /* Func to print/store chars in this col. */ -+ void (*char_func) (char); -+ -+ int current_line; /* Index of current place in line_vector. */ -+ int lines_stored; /* Number of lines stored in buff. */ -+ int lines_to_print; /* No. lines stored or space left on page. */ -+ int start_position; /* Horizontal position of first char. */ -+ bool numbered; -+ bool full_page_printed; /* True means printed without a FF found. */ -+ -+ /* p->full_page_printed controls a special case of "FF set by hand": -+ True means a full page has been printed without FF found. To avoid an -+ additional empty page we have to ignore a FF immediately following in -+ the next line. */ -+ }; -+ -+typedef struct COLUMN COLUMN; -+ -+static int char_to_clump (char c); -+static bool read_line (COLUMN *p); -+static bool print_page (void); -+static bool print_stored (COLUMN *p); -+static bool open_file (char *name, COLUMN *p); -+static bool skip_to_page (uintmax_t page); -+static void print_header (void); -+static void pad_across_to (int position); -+static void add_line_number (COLUMN *p); -+static void getoptarg (char *arg, char switch_char, char *character, -+ int *number); -+void usage (int status); -+static void print_files (int number_of_files, char **av); -+static void init_parameters (int number_of_files); -+static void init_header (char const *filename, int desc); -+static bool init_fps (int number_of_files, char **av); -+static void init_funcs (void); -+static void init_store_cols (void); -+static void store_columns (void); -+static void balance (int total_stored); -+static void store_char (char c); -+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 (const char *optarg_S); -+ -+/* All of the columns to print. */ -+static COLUMN *column_vector; -+ -+/* When printing a single file in multiple downward columns, -+ 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]. */ -+static char *buff; -+ -+/* Index of the position in buff where the next character -+ will be stored. */ -+static unsigned int buff_current; -+ -+/* The number of characters in buff. -+ Used for allocation of buff and to detect overflow of buff. */ -+static size_t buff_allocated; -+ -+/* Array of indices into buff. -+ Each entry is an index of the first character of a line. -+ This is used when storing lines to facilitate shuffling when -+ we do column balancing on the last page. */ -+static int *line_vector; -+ -+/* Array of horizonal positions. -+ For each line in line_vector, end_vector[line] is the horizontal -+ position we are in after printing that line. We keep track of this -+ so that we know how much we need to pad to prepare for the next -+ column. */ -+static int *end_vector; -+ -+/* (-m) True means we're printing multiple files in parallel. */ -+static bool parallel_files = false; -+ -+/* (-m) True means a line starts with some empty columns (some files -+ already CLOSED or ON_HOLD) which we have to align. */ -+static bool align_empty_cols; -+ -+/* (-m) True means we have not yet found any printable column in a line. -+ align_empty_cols = true has to be maintained. */ -+static bool empty_line; -+ -+/* (-m) False means printable column output precedes a form feed found. -+ Column alignment is done only once. No additional action with that form -+ feed. -+ True means we found only a form feed in a column. Maybe we have to do -+ some column alignment with that form feed. */ -+static bool FF_only; -+ -+/* (-[0-9]+) True means we're given an option explicitly specifying -+ number of columns. Used to detect when this option is used with -m -+ and when translating old options to new/long options. */ -+static bool explicit_columns = false; -+ -+/* (-t|-T) False means we aren't printing headers and footers. */ -+static bool extremities = true; -+ -+/* (-t) True means we retain all FF set by hand in input files. -+ False is set with -T option. */ -+static bool keep_FF = false; -+static bool print_a_FF = false; -+ -+/* True means we need to print a header as soon as we know we've got input -+ to print after it. */ -+static bool print_a_header; -+ -+/* (-f) True means use formfeeds instead of newlines to separate pages. */ -+static bool use_form_feed = false; -+ -+/* True means we have read the standard input. */ -+static bool have_read_stdin = false; -+ -+/* True means the -a flag has been given. */ -+static bool print_across_flag = false; -+ -+/* True means we're printing one file in multiple (>1) downward columns. */ -+static bool storing_columns = true; -+ -+/* (-b) True means balance columns on the last page as Sys V does. */ -+/* That's no longer an independent option. With storing_columns = true -+ balance_columns = true is used too (s. function init_parameters). -+ We get a consistent formulation with "FF set by hand" in input files. */ -+static bool balance_columns = false; -+ -+/* (-l) Number of lines on a page, including header and footer lines. */ -+static int lines_per_page = 66; -+ -+/* Number of lines in the header and footer can be reset to 0 using -+ the -t flag. */ -+enum { lines_per_header = 5 }; -+static int lines_per_body; -+enum { lines_per_footer = 5 }; -+ -+/* (-w|-W) Width in characters of the page. Does not include the width of -+ the margin. */ -+static int chars_per_line = 72; -+ -+/* (-w|W) True means we truncate lines longer than chars_per_column. */ -+static bool truncate_lines = false; -+ -+/* (-J) True means we join lines without any line truncation. -J -+ dominates -w option. */ -+static bool join_lines = false; -+ -+/* Number of characters in a column. Based on col_sep_length and -+ page width. */ -+static int chars_per_column; -+ -+/* (-e) True means convert tabs to spaces on input. */ -+static bool untabify_input = false; -+ -+/* (-e) The input tab character. */ -+static char input_tab_char = '\t'; -+ -+/* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ... -+ where the leftmost column is 1. */ -+static int chars_per_input_tab = 8; -+ -+/* (-i) True means convert spaces to tabs on output. */ -+static bool tabify_output = false; -+ -+/* (-i) The output tab character. */ -+static char output_tab_char = '\t'; -+ -+/* (-i) The width of the output tab. */ -+static int chars_per_output_tab = 8; -+ -+/* Keeps track of pending white space. When we hit a nonspace -+ character after some whitespace, we print whitespace, tabbing -+ if necessary to get to output_position + spaces_not_printed. */ -+static int spaces_not_printed; -+ -+/* (-o) Number of spaces in the left margin (tabs used when possible). */ -+static int chars_per_margin = 0; -+ -+/* Position where the next character will fall. -+ Leftmost position is 0 + chars_per_margin. -+ Rightmost position is chars_per_margin + chars_per_line - 1. -+ This is important for converting spaces to tabs on output. */ -+static int output_position; -+ -+/* Horizontal position relative to the current file. -+ (output_position depends on where we are on the page; -+ input_position depends on where we are in the file.) -+ Important for converting tabs to spaces on input. */ -+static int input_position; -+ -+/* True if there were any failed opens so we can exit with nonzero -+ status. */ -+static bool failed_opens = false; -+ -+/* The number of spaces taken up if we print a tab character with width -+ c_ from position h_. */ -+#define TAB_WIDTH(c_, h_) ((c_) - ((h_) % (c_))) -+ -+/* The horizontal position we'll be at after printing a tab character -+ of width c_ from the position h_. */ -+#define POS_AFTER_TAB(c_, h_) ((h_) + TAB_WIDTH (c_, h_)) -+ -+/* (-NNN) Number of columns of text to print. */ -+static int columns = 1; -+ -+/* (+NNN:MMM) Page numbers on which to begin and stop printing. -+ first_page_number = 0 will be used to check input only. */ -+static uintmax_t first_page_number = 0; -+static uintmax_t last_page_number = UINTMAX_MAX; -+ -+/* Number of files open (not closed, not on hold). */ -+static int files_ready_to_read = 0; -+ -+/* Current page number. Displayed in header. */ -+static uintmax_t page_number; -+ -+/* Current line number. Displayed when -n flag is specified. -+ -+ When printing files in parallel (-m flag), line numbering is as follows: -+ 1 foo goo moo -+ 2 hoo too zoo -+ -+ When printing files across (-a flag), ... -+ 1 foo 2 moo 3 goo -+ 4 hoo 5 too 6 zoo -+ -+ Otherwise, line numbering is as follows: -+ 1 foo 3 goo 5 too -+ 2 moo 4 hoo 6 zoo */ -+static int line_number; -+ -+/* With line_number overflow, we use power_10 to cut off the higher-order -+ digits of the line_number */ -+static int power_10; -+ -+/* (-n) True means lines should be preceded by numbers. */ -+static bool numbered_lines = false; -+ -+/* (-n) Character which follows each line number. */ -+static char number_separator = '\t'; -+ -+/* (-n) line counting starts with 1st line of input file (not with 1st -+ line of 1st page printed). */ -+static int line_count = 1; -+ -+/* (-n) True means counting of skipped lines starts with 1st line of -+ input file. False means -N option is used in addition, counting of -+ skipped lines not required. */ -+static bool skip_count = true; -+ -+/* (-N) Counting starts with start_line_number = NUMBER at 1st line of -+ first page printed, usually not 1st page of input file. */ -+static int start_line_num = 1; -+ -+/* (-n) Width in characters of a line number. */ -+static int chars_per_number = 5; -+ -+/* Used when widening the first column to accommodate numbers -- only -+ needed when printing files in parallel. Includes width of both the -+ number and the number_separator. */ -+static int number_width; -+ -+/* Buffer sprintf uses to format a line number. */ -+static char *number_buff; -+ -+/* (-v) True means unprintable characters are printed as escape sequences. -+ control-g becomes \007. */ -+static bool use_esc_sequence = false; -+ -+/* (-c) True means unprintable characters are printed as control prefixes. -+ control-g becomes ^G. */ -+static bool use_cntrl_prefix = false; -+ -+/* (-d) True means output is double spaced. */ -+static bool double_space = false; -+ -+/* Number of files opened initially in init_files. Should be 1 -+ unless we're printing multiple files in parallel. */ -+static int total_files = 0; -+ -+/* (-r) True means don't complain if we can't open a file. */ -+static bool ignore_failed_opens = false; -+ -+/* (-S) True means we separate columns with a specified string. -+ -S option does not affect line truncation nor column alignment. */ -+static bool use_col_separator = false; -+ -+/* String used to separate columns if the -S option has been specified. -+ Default without -S but together with one of the column options -+ -a|COLUMN|-m is a `space' and with the -J option a `tab'. */ -+static char *col_sep_string = (char *) ""; -+static int col_sep_length = 0; -+static char *column_separator = (char *) " "; -+static char *line_separator = (char *) "\t"; -+ -+/* Number of separator characters waiting to be printed as soon as we -+ know that we have any input remaining to be printed. */ -+static int separators_not_printed; -+ -+/* Position we need to pad to, as soon as we know that we have input -+ remaining to be printed. */ -+static int padding_not_printed; -+ -+/* True means we should pad the end of the page. Remains false until we -+ know we have a page to print. */ -+static bool pad_vertically; -+ -+/* (-h) String of characters used in place of the filename in the header. */ -+static char *custom_header; -+ -+/* (-D) Date format for the header. */ -+static char const *date_format; -+ -+/* Date and file name for the header. */ -+static char *date_text; -+static char const *file_text; -+ -+/* Output columns available, not counting the date and file name. */ -+static int header_width_available; -+ -+static char *clump_buff; -+ -+/* True means we read the line no. lines_per_body in skip_read -+ called by skip_to_page. That variable controls the coincidence of a -+ "FF set by hand" and "full_page_printed", see above the definition of -+ structure COLUMN. */ -+static bool last_line = false; -+ -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ COLUMNS_OPTION = CHAR_MAX + 1, -+ PAGES_OPTION -+}; -+ -+static char const short_options[] = -+ "-0123456789D:FJN:S::TW:abcde::fh:i::l:mn::o:rs::tvw:"; -+ -+static struct option const long_options[] = -+{ -+ {"pages", required_argument, NULL, PAGES_OPTION}, -+ {"columns", required_argument, NULL, COLUMNS_OPTION}, -+ {"across", no_argument, NULL, 'a'}, -+ {"show-control-chars", no_argument, NULL, 'c'}, -+ {"double-space", no_argument, NULL, 'd'}, -+ {"date-format", required_argument, NULL, 'D'}, -+ {"expand-tabs", optional_argument, NULL, 'e'}, -+ {"form-feed", no_argument, NULL, 'f'}, -+ {"header", required_argument, NULL, 'h'}, -+ {"output-tabs", optional_argument, NULL, 'i'}, -+ {"join-lines", no_argument, NULL, 'J'}, -+ {"length", required_argument, NULL, 'l'}, -+ {"merge", no_argument, NULL, 'm'}, -+ {"number-lines", optional_argument, NULL, 'n'}, -+ {"first-line-number", required_argument, NULL, 'N'}, -+ {"indent", required_argument, NULL, 'o'}, -+ {"no-file-warnings", no_argument, NULL, 'r'}, -+ {"separator", optional_argument, NULL, 's'}, -+ {"sep-string", optional_argument, NULL, 'S'}, -+ {"omit-header", no_argument, NULL, 't'}, -+ {"omit-pagination", no_argument, NULL, 'T'}, -+ {"show-nonprinting", no_argument, NULL, 'v'}, -+ {"width", required_argument, NULL, 'w'}, -+ {"page-width", required_argument, NULL, 'W'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+/* Return the number of columns that have either an open file or -+ stored lines. */ -+ -+static int -+cols_ready_to_print (void) -+{ -+ COLUMN *q; -+ int i; -+ int n; -+ -+ n = 0; -+ for (q = column_vector, i = 0; i < columns; ++q, ++i) -+ if (q->status == OPEN || -+ q->status == FF_FOUND || /* With -b: To print a header only */ -+ (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0)) -+ ++n; -+ return n; -+} -+ -+/* Estimate first_ / last_page_number -+ using option +FIRST_PAGE:LAST_PAGE */ -+ -+static bool -+first_last_page (int oi, char c, char const *pages) -+{ -+ char *p; -+ uintmax_t first; -+ uintmax_t last = UINTMAX_MAX; -+ strtol_error err = xstrtoumax (pages, &p, 10, &first, ""); -+ if (err != LONGINT_OK && err != LONGINT_INVALID_SUFFIX_CHAR) -+ xstrtol_fatal (err, oi, c, long_options, pages); -+ -+ if (p == pages || !first) -+ return false; -+ -+ if (*p == ':') -+ { -+ char const *p1 = p + 1; -+ err = xstrtoumax (p1, &p, 10, &last, ""); -+ if (err != LONGINT_OK) -+ xstrtol_fatal (err, oi, c, long_options, pages); -+ if (p1 == p || last < first) -+ return false; -+ } -+ -+ if (*p) -+ return false; -+ -+ first_page_number = first; -+ last_page_number = last; -+ return true; -+} -+ -+/* Parse column count string S, and if it's valid (1 or larger and -+ within range of the type of `columns') set the global variables -+ columns and explicit_columns and return true. -+ Otherwise, exit with a diagnostic. */ -+static void -+parse_column_count (char const *s) -+{ -+ long int tmp_long; -+ if (xstrtol (s, NULL, 10, &tmp_long, "") != LONGINT_OK -+ || !(1 <= tmp_long && tmp_long <= INT_MAX)) -+ error (EXIT_FAILURE, 0, -+ _("invalid number of columns: %s"), quote (s)); -+ -+ columns = tmp_long; -+ explicit_columns = true; -+} -+ -+/* Estimate length of col_sep_string with option -S. */ -+ -+static void -+separator_string (const char *optarg_S) -+{ -+ col_sep_length = (int) strlen (optarg_S); -+ col_sep_string = xmalloc (col_sep_length + 1); -+ strcpy (col_sep_string, optarg_S); -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int n_files; -+ bool old_options = false; -+ bool old_w = false; -+ bool old_s = false; -+ char **file_names; -+ -+ /* Accumulate the digits of old-style options like -99. */ -+ char *column_count_string = NULL; -+ size_t n_digits = 0; -+ size_t n_alloc = 0; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdout); -+ -+ n_files = 0; -+ file_names = (argc > 1 -+ ? xmalloc ((argc - 1) * sizeof (char *)) -+ : NULL); -+ -+ for (;;) -+ { -+ int oi = -1; -+ int c = getopt_long (argc, argv, short_options, long_options, &oi); -+ if (c == -1) -+ break; -+ -+ if (ISDIGIT (c)) -+ { -+ /* Accumulate column-count digits specified via old-style options. */ -+ if (n_digits + 1 >= n_alloc) -+ column_count_string -+ = X2REALLOC (column_count_string, &n_alloc); -+ column_count_string[n_digits++] = c; -+ column_count_string[n_digits] = '\0'; -+ continue; -+ } -+ -+ n_digits = 0; -+ -+ switch (c) -+ { -+ case 1: /* Non-option argument. */ -+ /* long option --page dominates old `+FIRST_PAGE ...'. */ -+ if (! (first_page_number == 0 -+ && *optarg == '+' && first_last_page (-2, '+', optarg + 1))) -+ file_names[n_files++] = optarg; -+ break; -+ -+ case PAGES_OPTION: /* --pages=FIRST_PAGE[:LAST_PAGE] */ -+ { /* dominates old opt +... */ -+ if (! optarg) -+ error (EXIT_FAILURE, 0, -+ _("`--pages=FIRST_PAGE[:LAST_PAGE]' missing argument")); -+ else if (! first_last_page (oi, 0, optarg)) -+ error (EXIT_FAILURE, 0, _("invalid page range %s"), -+ quote (optarg)); -+ break; -+ } -+ -+ case COLUMNS_OPTION: /* --columns=COLUMN */ -+ { -+ parse_column_count (optarg); -+ -+ /* If there was a prior column count specified via the -+ short-named option syntax, e.g., -9, ensure that this -+ long-name-specified value overrides it. */ -+ free (column_count_string); -+ column_count_string = NULL; -+ n_alloc = 0; -+ break; -+ } -+ -+ case 'a': -+ print_across_flag = true; -+ storing_columns = false; -+ break; -+ case 'b': -+ balance_columns = true; -+ break; -+ case 'c': -+ use_cntrl_prefix = true; -+ break; -+ case 'd': -+ double_space = true; -+ break; -+ case 'D': -+ date_format = optarg; -+ break; -+ case 'e': -+ if (optarg) -+ getoptarg (optarg, 'e', &input_tab_char, -+ &chars_per_input_tab); -+ /* Could check tab width > 0. */ -+ untabify_input = true; -+ break; -+ case 'f': -+ case 'F': -+ use_form_feed = true; -+ break; -+ case 'h': -+ custom_header = optarg; -+ break; -+ case 'i': -+ if (optarg) -+ getoptarg (optarg, 'i', &output_tab_char, -+ &chars_per_output_tab); -+ /* Could check tab width > 0. */ -+ tabify_output = true; -+ break; -+ case 'J': -+ join_lines = true; -+ break; -+ case 'l': -+ { -+ long int tmp_long; -+ if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK -+ || tmp_long <= 0 || tmp_long > INT_MAX) -+ { -+ error (EXIT_FAILURE, 0, -+ _("`-l PAGE_LENGTH' invalid number of lines: %s"), -+ quote (optarg)); -+ } -+ lines_per_page = tmp_long; -+ break; -+ } -+ case 'm': -+ parallel_files = true; -+ storing_columns = false; -+ break; -+ case 'n': -+ numbered_lines = true; -+ if (optarg) -+ getoptarg (optarg, 'n', &number_separator, -+ &chars_per_number); -+ break; -+ case 'N': -+ skip_count = false; -+ { -+ long int tmp_long; -+ if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK -+ || tmp_long > INT_MAX) -+ { -+ error (EXIT_FAILURE, 0, -+ _("`-N NUMBER' invalid starting line number: %s"), -+ quote (optarg)); -+ } -+ start_line_num = tmp_long; -+ break; -+ } -+ case 'o': -+ { -+ long int tmp_long; -+ if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK -+ || tmp_long < 0 || tmp_long > INT_MAX) -+ error (EXIT_FAILURE, 0, -+ _("`-o MARGIN' invalid line offset: %s"), quote (optarg)); -+ chars_per_margin = tmp_long; -+ break; -+ } -+ case 'r': -+ ignore_failed_opens = true; -+ break; -+ case 's': -+ old_options = true; -+ old_s = true; -+ if (!use_col_separator && optarg) -+ separator_string (optarg); -+ break; -+ case 'S': -+ old_s = false; -+ /* Reset an additional input of -s, -S dominates -s */ -+ col_sep_string = bad_cast (""); -+ col_sep_length = 0; -+ use_col_separator = true; -+ if (optarg) -+ separator_string (optarg); -+ break; -+ case 't': -+ extremities = false; -+ keep_FF = true; -+ break; -+ case 'T': -+ extremities = false; -+ keep_FF = false; -+ break; -+ case 'v': -+ use_esc_sequence = true; -+ break; -+ case 'w': -+ old_options = true; -+ old_w = true; -+ { -+ long int tmp_long; -+ if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK -+ || tmp_long <= 0 || tmp_long > INT_MAX) -+ error (EXIT_FAILURE, 0, -+ _("`-w PAGE_WIDTH' invalid number of characters: %s"), -+ quote (optarg)); -+ if (!truncate_lines) -+ chars_per_line = tmp_long; -+ break; -+ } -+ case 'W': -+ old_w = false; /* dominates -w */ -+ truncate_lines = true; -+ { -+ long int tmp_long; -+ if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK -+ || tmp_long <= 0 || tmp_long > INT_MAX) -+ error (EXIT_FAILURE, 0, -+ _("`-W PAGE_WIDTH' invalid number of characters: %s"), -+ quote (optarg)); -+ chars_per_line = tmp_long; -+ break; -+ } -+ case_GETOPT_HELP_CHAR; -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ default: -+ usage (EXIT_FAILURE); -+ break; -+ } -+ } -+ -+ if (column_count_string) -+ { -+ parse_column_count (column_count_string); -+ free (column_count_string); -+ } -+ -+ if (! date_format) -+ date_format = (getenv ("POSIXLY_CORRECT") && !hard_locale (LC_TIME) -+ ? "%b %e %H:%M %Y" -+ : "%Y-%m-%d %H:%M"); -+ -+ /* Now we can set a reasonable initial value: */ -+ if (first_page_number == 0) -+ first_page_number = 1; -+ -+ if (parallel_files && explicit_columns) -+ error (EXIT_FAILURE, 0, -+ _("cannot specify number of columns when printing in parallel")); -+ -+ if (parallel_files && print_across_flag) -+ error (EXIT_FAILURE, 0, -+ _("cannot specify both printing across and printing in parallel")); -+ -+/* Translate some old short options to new/long options. -+ To meet downward compatibility with other UNIX pr utilities -+ and some POSIX specifications. */ -+ -+ if (old_options) -+ { -+ if (old_w) -+ { -+ if (parallel_files || explicit_columns) -+ { -+ /* activate -W */ -+ truncate_lines = true; -+ if (old_s) -+ /* adapt HP-UX and SunOS: -s = no separator; -+ activate -S */ -+ use_col_separator = true; -+ } -+ else -+ /* old -w sets width with columns only -+ activate -J */ -+ join_lines = true; -+ } -+ else if (!use_col_separator) -+ { -+ /* No -S option read */ -+ if (old_s && (parallel_files || explicit_columns)) -+ { -+ if (!truncate_lines) -+ { -+ /* old -s (without -w and -W) annuls column alignment, -+ uses fields, activate -J */ -+ join_lines = true; -+ if (col_sep_length > 0) -+ /* activate -S */ -+ use_col_separator = true; -+ } -+ else -+ /* with -W */ -+ /* adapt HP-UX and SunOS: -s = no separator; -+ activate -S */ -+ use_col_separator = true; -+ } -+ } -+ } -+ -+ for (; optind < argc; optind++) -+ { -+ file_names[n_files++] = argv[optind]; -+ } -+ -+ if (n_files == 0) -+ { -+ /* No file arguments specified; read from standard input. */ -+ print_files (0, NULL); -+ } -+ else -+ { -+ if (parallel_files) -+ print_files (n_files, file_names); -+ else -+ { -+ int i; -+ for (i = 0; i < n_files; i++) -+ print_files (1, &file_names[i]); -+ } -+ } -+ -+ cleanup (); -+ -+ if (have_read_stdin && fclose (stdin) == EOF) -+ error (EXIT_FAILURE, errno, _("standard input")); -+ if (failed_opens) -+ exit (EXIT_FAILURE); -+ exit (EXIT_SUCCESS); -+} -+ -+/* Parse options of the form -scNNN. -+ -+ Example: -nck, where 'n' is the option, c is the optional number -+ separator, and k is the optional width of the field used when printing -+ a number. */ -+ -+static void -+getoptarg (char *arg, char switch_char, char *character, int *number) -+{ -+ if (!ISDIGIT (*arg)) -+ *character = *arg++; -+ if (*arg) -+ { -+ long int tmp_long; -+ if (xstrtol (arg, NULL, 10, &tmp_long, "") != LONGINT_OK -+ || tmp_long <= 0 || tmp_long > INT_MAX) -+ { -+ error (0, 0, -+ _("`-%c' extra characters or invalid number in the argument: %s"), -+ switch_char, quote (arg)); -+ usage (EXIT_FAILURE); -+ } -+ *number = tmp_long; -+ } -+} -+ -+/* Set parameters related to formatting. */ -+ -+static void -+init_parameters (int number_of_files) -+{ -+ int chars_used_by_number = 0; -+ -+ lines_per_body = lines_per_page - lines_per_header - lines_per_footer; -+ if (lines_per_body <= 0) -+ { -+ extremities = false; -+ keep_FF = true; -+ } -+ if (extremities == false) -+ lines_per_body = lines_per_page; -+ -+ if (double_space) -+ lines_per_body = lines_per_body / 2; -+ -+ /* If input is stdin, cannot print parallel files. BSD dumps core -+ on this. */ -+ if (number_of_files == 0) -+ parallel_files = false; -+ -+ if (parallel_files) -+ columns = number_of_files; -+ -+ /* One file, multi columns down: -b option is set to get a consistent -+ formulation with "FF set by hand" in input files. */ -+ if (storing_columns) -+ balance_columns = true; -+ -+ /* Tabification is assumed for multiple columns. */ -+ if (columns > 1) -+ { -+ if (!use_col_separator) -+ { -+ /* Use default separator */ -+ if (join_lines) -+ col_sep_string = line_separator; -+ else -+ col_sep_string = column_separator; -+ -+ col_sep_length = 1; -+ use_col_separator = true; -+ } -+ /* It's rather pointless to define a TAB separator with column -+ alignment */ -+ else if (!join_lines && *col_sep_string == '\t') -+ col_sep_string = column_separator; -+ -+ truncate_lines = true; -+ tabify_output = true; -+ } -+ else -+ storing_columns = false; -+ -+ /* -J dominates -w in any case */ -+ if (join_lines) -+ truncate_lines = false; -+ -+ if (numbered_lines) -+ { -+ int tmp_i; -+ int chars_per_default_tab = 8; -+ -+ line_count = start_line_num; -+ -+ /* To allow input tab-expansion (-e sensitive) use: -+ if (number_separator == input_tab_char) -+ number_width = chars_per_number + -+ TAB_WIDTH (chars_per_input_tab, chars_per_number); */ -+ -+ /* Estimate chars_per_text without any margin and keep it constant. */ -+ if (number_separator == '\t') -+ number_width = chars_per_number + -+ TAB_WIDTH (chars_per_default_tab, chars_per_number); -+ else -+ number_width = chars_per_number + 1; -+ -+ /* The number is part of the column width unless we are -+ printing files in parallel. */ -+ if (parallel_files) -+ chars_used_by_number = number_width; -+ -+ /* We use power_10 to cut off the higher-order digits of the -+ line_number in function add_line_number */ -+ tmp_i = chars_per_number; -+ for (power_10 = 1; tmp_i > 0; --tmp_i) -+ power_10 = 10 * power_10; -+ } -+ -+ chars_per_column = (chars_per_line - chars_used_by_number - -+ (columns - 1) * col_sep_length) / columns; -+ -+ if (chars_per_column < 1) -+ error (EXIT_FAILURE, 0, _("page width too narrow")); -+ -+ if (numbered_lines) -+ { -+ free (number_buff); -+ number_buff = xmalloc (2 * chars_per_number); -+ } -+ -+ /* Pick the maximum between the tab width and the width of an -+ escape sequence. -+ The width of an escape sequence (4) isn't the lower limit any longer. -+ 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)); -+} -+ -+/* Open the necessary files, -+ maintaining a COLUMN structure for each column. -+ -+ With multiple files, each column p has a different p->fp. -+ With single files, each column p has the same p->fp. -+ Return false if (number_of_files > 0) and no files can be opened, -+ true otherwise. -+ -+ With each column/file p, p->full_page_printed is initialized, -+ see also open_file. */ -+ -+static bool -+init_fps (int number_of_files, char **av) -+{ -+ int i, files_left; -+ COLUMN *p; -+ FILE *firstfp; -+ char const *firstname; -+ -+ total_files = 0; -+ -+ free (column_vector); -+ column_vector = xnmalloc (columns, sizeof (COLUMN)); -+ -+ if (parallel_files) -+ { -+ files_left = number_of_files; -+ for (p = column_vector; files_left--; ++p, ++av) -+ { -+ if (! open_file (*av, p)) -+ { -+ --p; -+ --columns; -+ } -+ } -+ if (columns == 0) -+ return false; -+ init_header ("", -1); -+ } -+ else -+ { -+ p = column_vector; -+ if (number_of_files > 0) -+ { -+ if (! open_file (*av, p)) -+ return false; -+ init_header (*av, fileno (p->fp)); -+ p->lines_stored = 0; -+ } -+ else -+ { -+ p->name = _("standard input"); -+ p->fp = stdin; -+ have_read_stdin = true; -+ p->status = OPEN; -+ p->full_page_printed = false; -+ ++total_files; -+ init_header ("", -1); -+ p->lines_stored = 0; -+ } -+ -+ firstname = p->name; -+ firstfp = p->fp; -+ for (i = columns - 1, ++p; i; --i, ++p) -+ { -+ p->name = firstname; -+ p->fp = firstfp; -+ p->status = OPEN; -+ p->full_page_printed = false; -+ p->lines_stored = 0; -+ } -+ } -+ files_ready_to_read = total_files; -+ return true; -+} -+ -+/* Determine print_func and char_func, the functions -+ used by each column for printing and/or storing. -+ -+ Determine the horizontal position desired when we begin -+ printing a column (p->start_position). */ -+ -+static void -+init_funcs (void) -+{ -+ int i, h, h_next; -+ COLUMN *p; -+ -+ h = chars_per_margin; -+ -+ if (!truncate_lines) -+ h_next = ANYWHERE; -+ else -+ { -+ /* When numbering lines of parallel files, we enlarge the -+ first column to accomodate the number. Looks better than -+ the Sys V approach. */ -+ if (parallel_files && numbered_lines) -+ h_next = h + chars_per_column + number_width; -+ else -+ h_next = h + chars_per_column; -+ } -+ -+ /* Enlarge p->start_position of first column to use the same form of -+ padding_not_printed with all columns. */ -+ h = h + col_sep_length; -+ -+ /* This loop takes care of all but the rightmost column. */ -+ -+ for (p = column_vector, i = 1; i < columns; ++p, ++i) -+ { -+ if (storing_columns) /* One file, multi columns down. */ -+ { -+ p->char_func = store_char; -+ p->print_func = print_stored; -+ } -+ else -+ /* One file, multi columns across; or parallel files. */ -+ { -+ p->char_func = print_char; -+ p->print_func = read_line; -+ } -+ -+ /* Number only the first column when printing files in -+ parallel. */ -+ p->numbered = numbered_lines && (!parallel_files || i == 1); -+ p->start_position = h; -+ -+ /* If we don't truncate lines, all start_positions are -+ ANYWHERE, except the first column's start_position when -+ using a margin. */ -+ -+ if (!truncate_lines) -+ { -+ h = ANYWHERE; -+ h_next = ANYWHERE; -+ } -+ else -+ { -+ h = h_next + col_sep_length; -+ h_next = h + chars_per_column; -+ } -+ } -+ -+ /* The rightmost column. -+ -+ Doesn't need to be stored unless we intend to balance -+ columns on the last page. */ -+ if (storing_columns && balance_columns) -+ { -+ p->char_func = store_char; -+ p->print_func = print_stored; -+ } -+ else -+ { -+ p->char_func = print_char; -+ p->print_func = read_line; -+ } -+ -+ p->numbered = numbered_lines && (!parallel_files || i == 1); -+ p->start_position = h; -+} -+ -+/* Open a file. Return true if successful. -+ -+ With each file p, p->full_page_printed is initialized, -+ see also init_fps. */ -+ -+static bool -+open_file (char *name, COLUMN *p) -+{ -+ if (STREQ (name, "-")) -+ { -+ p->name = _("standard input"); -+ p->fp = stdin; -+ have_read_stdin = true; -+ } -+ else -+ { -+ p->name = name; -+ p->fp = fopen (name, "r"); -+ } -+ if (p->fp == NULL) -+ { -+ failed_opens = true; -+ if (!ignore_failed_opens) -+ error (0, errno, "%s", name); -+ return false; -+ } -+ p->status = OPEN; -+ p->full_page_printed = false; -+ ++total_files; -+ return true; -+} -+ -+/* Close the file in P. -+ -+ If we aren't dealing with multiple files in parallel, we change -+ the status of all columns in the column list to reflect the close. */ -+ -+static void -+close_file (COLUMN *p) -+{ -+ COLUMN *q; -+ int i; -+ -+ if (p->status == CLOSED) -+ return; -+ if (ferror (p->fp)) -+ error (EXIT_FAILURE, errno, "%s", p->name); -+ if (fileno (p->fp) != STDIN_FILENO && fclose (p->fp) != 0) -+ error (EXIT_FAILURE, errno, "%s", p->name); -+ -+ if (!parallel_files) -+ { -+ for (q = column_vector, i = columns; i; ++q, --i) -+ { -+ q->status = CLOSED; -+ if (q->lines_stored == 0) -+ { -+ q->lines_to_print = 0; -+ } -+ } -+ } -+ else -+ { -+ p->status = CLOSED; -+ p->lines_to_print = 0; -+ } -+ -+ --files_ready_to_read; -+} -+ -+/* Put a file on hold until we start a new page, -+ since we've hit a form feed. -+ -+ If we aren't dealing with parallel files, we must change the -+ status of all columns in the column list. */ -+ -+static void -+hold_file (COLUMN *p) -+{ -+ COLUMN *q; -+ int i; -+ -+ if (!parallel_files) -+ for (q = column_vector, i = columns; i; ++q, --i) -+ { -+ if (storing_columns) -+ q->status = FF_FOUND; -+ else -+ q->status = ON_HOLD; -+ } -+ else -+ p->status = ON_HOLD; -+ -+ p->lines_to_print = 0; -+ --files_ready_to_read; -+} -+ -+/* Undo hold_file -- go through the column list and change any -+ ON_HOLD columns to OPEN. Used at the end of each page. */ -+ -+static void -+reset_status (void) -+{ -+ int i = columns; -+ COLUMN *p; -+ -+ for (p = column_vector; i; --i, ++p) -+ if (p->status == ON_HOLD) -+ { -+ p->status = OPEN; -+ files_ready_to_read++; -+ } -+ -+ if (storing_columns) -+ { -+ if (column_vector->status == CLOSED) -+ /* We use the info to output an error message in skip_to_page. */ -+ files_ready_to_read = 0; -+ else -+ files_ready_to_read = 1; -+ } -+} -+ -+/* Print a single file, or multiple files in parallel. -+ -+ Set up the list of columns, opening the necessary files. -+ Allocate space for storing columns, if necessary. -+ Skip to first_page_number, if user has asked to skip leading pages. -+ Determine which functions are appropriate to store/print lines -+ in each column. -+ Print the file(s). */ -+ -+static void -+print_files (int number_of_files, char **av) -+{ -+ init_parameters (number_of_files); -+ if (! init_fps (number_of_files, av)) -+ return; -+ if (storing_columns) -+ init_store_cols (); -+ -+ if (first_page_number > 1) -+ { -+ if (!skip_to_page (first_page_number)) -+ return; -+ else -+ page_number = first_page_number; -+ } -+ else -+ page_number = 1; -+ -+ init_funcs (); -+ -+ line_number = line_count; -+ while (print_page ()) -+ ; -+} -+ -+/* Initialize header information. -+ If DESC is non-negative, it is a file descriptor open to -+ FILENAME for reading. */ -+ -+static void -+init_header (char const *filename, int desc) -+{ -+ char *buf = NULL; -+ struct stat st; -+ struct timespec t; -+ int ns; -+ struct tm *tm; -+ -+ /* If parallel files or standard input, use current date. */ -+ if (STREQ (filename, "-")) -+ desc = -1; -+ if (0 <= desc && fstat (desc, &st) == 0) -+ t = get_stat_mtime (&st); -+ else -+ { -+ static struct timespec timespec; -+ if (! timespec.tv_sec) -+ gettime (×pec); -+ t = timespec; -+ } -+ -+ ns = t.tv_nsec; -+ tm = localtime (&t.tv_sec); -+ if (tm == NULL) -+ { -+ buf = xmalloc (INT_BUFSIZE_BOUND (long int) -+ + MAX (10, INT_BUFSIZE_BOUND (int))); -+ sprintf (buf, "%ld.%09d", (long int) t.tv_sec, ns); -+ } -+ else -+ { -+ size_t bufsize = nstrftime (NULL, SIZE_MAX, date_format, tm, 0, ns) + 1; -+ buf = xmalloc (bufsize); -+ nstrftime (buf, bufsize, date_format, tm, 0, ns); -+ } -+ -+ free (date_text); -+ date_text = buf; -+ file_text = custom_header ? custom_header : desc < 0 ? "" : filename; -+ header_width_available = (chars_per_line -+ - mbswidth (date_text, 0) -+ - mbswidth (file_text, 0)); -+} -+ -+/* Set things up for printing a page -+ -+ Scan through the columns ... -+ Determine which are ready to print -+ (i.e., which have lines stored or open files) -+ Set p->lines_to_print appropriately -+ (to p->lines_stored if we're storing, or lines_per_body -+ if we're reading straight from the file) -+ Keep track of this total so we know when to stop printing */ -+ -+static void -+init_page (void) -+{ -+ int j; -+ COLUMN *p; -+ -+ if (storing_columns) -+ { -+ store_columns (); -+ for (j = columns - 1, p = column_vector; j; --j, ++p) -+ { -+ p->lines_to_print = p->lines_stored; -+ } -+ -+ /* Last column. */ -+ if (balance_columns) -+ { -+ p->lines_to_print = p->lines_stored; -+ } -+ /* Since we're not balancing columns, we don't need to store -+ the rightmost column. Read it straight from the file. */ -+ else -+ { -+ if (p->status == OPEN) -+ { -+ p->lines_to_print = lines_per_body; -+ } -+ else -+ p->lines_to_print = 0; -+ } -+ } -+ else -+ for (j = columns, p = column_vector; j; --j, ++p) -+ if (p->status == OPEN) -+ { -+ p->lines_to_print = lines_per_body; -+ } -+ else -+ p->lines_to_print = 0; -+} -+ -+/* Align empty columns and print separators. -+ Empty columns will be formed by files with status ON_HOLD or CLOSED -+ when printing multiple files in parallel. */ -+ -+static void -+align_column (COLUMN *p) -+{ -+ padding_not_printed = p->start_position; -+ if (padding_not_printed - col_sep_length > 0) -+ { -+ pad_across_to (padding_not_printed - col_sep_length); -+ padding_not_printed = ANYWHERE; -+ } -+ -+ if (use_col_separator) -+ print_sep_string (); -+ -+ if (p->numbered) -+ add_line_number (p); -+} -+ -+/* Print one page. -+ -+ As long as there are lines left on the page and columns ready to print, -+ Scan across the column list -+ if the column has stored lines or the file is open -+ pad to the appropriate spot -+ print the column -+ pad the remainder of the page with \n or \f as requested -+ reset the status of all files -- any files which where on hold because -+ of formfeeds are now put back into the lineup. */ -+ -+static bool -+print_page (void) -+{ -+ int j; -+ int lines_left_on_page; -+ COLUMN *p; -+ -+ /* Used as an accumulator (with | operator) of successive values of -+ pad_vertically. The trick is to set pad_vertically -+ to false before each run through the inner loop, then after that -+ loop, it tells us whether a line was actually printed (whether a -+ newline needs to be output -- or two for double spacing). But those -+ values have to be accumulated (in pv) so we can invoke pad_down -+ properly after the outer loop completes. */ -+ bool pv; -+ -+ init_page (); -+ -+ if (cols_ready_to_print () == 0) -+ return false; -+ -+ if (extremities) -+ print_a_header = true; -+ -+ /* Don't pad unless we know a page was printed. */ -+ pad_vertically = false; -+ pv = false; -+ -+ lines_left_on_page = lines_per_body; -+ if (double_space) -+ lines_left_on_page *= 2; -+ -+ while (lines_left_on_page > 0 && cols_ready_to_print () > 0) -+ { -+ output_position = 0; -+ spaces_not_printed = 0; -+ separators_not_printed = 0; -+ pad_vertically = false; -+ align_empty_cols = false; -+ empty_line = true; -+ -+ for (j = 1, p = column_vector; j <= columns; ++j, ++p) -+ { -+ input_position = 0; -+ if (p->lines_to_print > 0 || p->status == FF_FOUND) -+ { -+ FF_only = false; -+ padding_not_printed = p->start_position; -+ if (!(p->print_func) (p)) -+ read_rest_of_line (p); -+ pv |= pad_vertically; -+ -+ --p->lines_to_print; -+ if (p->lines_to_print <= 0) -+ { -+ if (cols_ready_to_print () <= 0) -+ break; -+ } -+ -+ /* File p changed its status to ON_HOLD or CLOSED */ -+ if (parallel_files && p->status != OPEN) -+ { -+ if (empty_line) -+ align_empty_cols = true; -+ else if (p->status == CLOSED || -+ (p->status == ON_HOLD && FF_only)) -+ align_column (p); -+ } -+ } -+ else if (parallel_files) -+ { -+ /* File status ON_HOLD or CLOSED */ -+ if (empty_line) -+ align_empty_cols = true; -+ else -+ align_column (p); -+ } -+ -+ /* We need it also with an empty column */ -+ if (use_col_separator) -+ ++separators_not_printed; -+ } -+ -+ if (pad_vertically) -+ { -+ putchar ('\n'); -+ --lines_left_on_page; -+ } -+ -+ if (cols_ready_to_print () <= 0 && !extremities) -+ break; -+ -+ if (double_space && pv) -+ { -+ putchar ('\n'); -+ --lines_left_on_page; -+ } -+ } -+ -+ if (lines_left_on_page == 0) -+ for (j = 1, p = column_vector; j <= columns; ++j, ++p) -+ if (p->status == OPEN) -+ p->full_page_printed = true; -+ -+ pad_vertically = pv; -+ -+ if (pad_vertically && extremities) -+ pad_down (lines_left_on_page + lines_per_footer); -+ else if (keep_FF && print_a_FF) -+ { -+ putchar ('\f'); -+ print_a_FF = false; -+ } -+ -+ if (last_page_number < page_number) -+ return false; /* Stop printing with LAST_PAGE */ -+ -+ reset_status (); /* Change ON_HOLD to OPEN. */ -+ -+ return true; /* More pages to go. */ -+} -+ -+/* Allocate space for storing columns. -+ -+ This is necessary when printing multiple columns from a single file. -+ Lines are stored consecutively in buff, separated by '\0'. -+ -+ The following doesn't apply any longer - any tuning possible? -+ (We can't use a fixed offset since with the '-s' flag lines aren't -+ truncated.) -+ -+ We maintain a list (line_vector) of pointers to the beginnings -+ of lines in buff. We allocate one more than the number of lines -+ because the last entry tells us the index of the last character, -+ which we need to know in order to print the last line in buff. */ -+ -+static void -+init_store_cols (void) -+{ -+ int total_lines = lines_per_body * columns; -+ int chars_if_truncate = total_lines * (chars_per_column + 1); -+ -+ free (line_vector); -+ /* FIXME: here's where it was allocated. */ -+ line_vector = xmalloc ((total_lines + 1) * sizeof (int *)); -+ -+ free (end_vector); -+ end_vector = xmalloc (total_lines * sizeof (int *)); -+ -+ free (buff); -+ buff_allocated = (use_col_separator -+ ? 2 * chars_if_truncate -+ : chars_if_truncate); /* Tune this. */ -+ buff = xmalloc (buff_allocated); -+} -+ -+/* Store all but the rightmost column. -+ (Used when printing a single file in multiple downward columns) -+ -+ For each column -+ set p->current_line to be the index in line_vector of the -+ first line in the column -+ For each line in the column -+ store the line in buff -+ add to line_vector the index of the line's first char -+ buff_start is the index in buff of the first character in the -+ current line. */ -+ -+static void -+store_columns (void) -+{ -+ int i, j; -+ unsigned int line = 0; -+ unsigned int buff_start; -+ int last_col; /* The rightmost column which will be saved in buff */ -+ COLUMN *p; -+ -+ buff_current = 0; -+ buff_start = 0; -+ -+ if (balance_columns) -+ last_col = columns; -+ else -+ last_col = columns - 1; -+ -+ for (i = 1, p = column_vector; i <= last_col; ++i, ++p) -+ p->lines_stored = 0; -+ -+ for (i = 1, p = column_vector; i <= last_col && files_ready_to_read; -+ ++i, ++p) -+ { -+ p->current_line = line; -+ for (j = lines_per_body; j && files_ready_to_read; --j) -+ -+ if (p->status == OPEN) /* Redundant. Clean up. */ -+ { -+ input_position = 0; -+ -+ if (!read_line (p)) -+ read_rest_of_line (p); -+ -+ if (p->status == OPEN -+ || buff_start != buff_current) -+ { -+ ++p->lines_stored; -+ line_vector[line] = buff_start; -+ end_vector[line++] = input_position; -+ buff_start = buff_current; -+ } -+ } -+ } -+ -+ /* Keep track of the location of the last char in buff. */ -+ line_vector[line] = buff_start; -+ -+ if (balance_columns) -+ balance (line); -+} -+ -+static void -+balance (int total_stored) -+{ -+ COLUMN *p; -+ int i, lines; -+ int first_line = 0; -+ -+ for (i = 1, p = column_vector; i <= columns; ++i, ++p) -+ { -+ lines = total_stored / columns; -+ if (i <= total_stored % columns) -+ ++lines; -+ -+ p->lines_stored = lines; -+ p->current_line = first_line; -+ -+ first_line += lines; -+ } -+} -+ -+/* Store a character in the buffer. */ -+ -+static void -+store_char (char c) -+{ -+ if (buff_current >= buff_allocated) -+ { -+ /* May be too generous. */ -+ buff = X2REALLOC (buff, &buff_allocated); -+ } -+ buff[buff_current++] = c; -+} -+ -+static void -+add_line_number (COLUMN *p) -+{ -+ int i; -+ char *s; -+ int left_cut; -+ -+ /* Cutting off the higher-order digits is more informative than -+ lower-order cut off*/ -+ if (line_number < power_10) -+ sprintf (number_buff, "%*d", chars_per_number, line_number); -+ else -+ { -+ left_cut = line_number % power_10; -+ sprintf (number_buff, "%0*d", chars_per_number, left_cut); -+ } -+ line_number++; -+ s = number_buff; -+ for (i = chars_per_number; i > 0; i--) -+ (p->char_func) (*s++); -+ -+ if (columns > 1) -+ { -+ /* 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. */ -+ if (number_separator == '\t') -+ { -+ i = number_width - chars_per_number; -+ while (i-- > 0) -+ (p->char_func) (' '); -+ } -+ else -+ (p->char_func) (number_separator); -+ } -+ else -+ /* To comply with POSIX, we avoid any expansion of default TAB -+ separator with a single column output. No column_width requirement -+ has to be considered. */ -+ { -+ (p->char_func) (number_separator); -+ if (number_separator == '\t') -+ output_position = POS_AFTER_TAB (chars_per_output_tab, -+ output_position); -+ } -+ -+ if (truncate_lines && !parallel_files) -+ input_position += number_width; -+} -+ -+/* Print (or store) padding until the current horizontal position -+ is position. */ -+ -+static void -+pad_across_to (int position) -+{ -+ int h = output_position; -+ -+ if (tabify_output) -+ spaces_not_printed = position - output_position; -+ else -+ { -+ while (++h <= position) -+ putchar (' '); -+ output_position = position; -+ } -+} -+ -+/* Pad to the bottom of the page. -+ -+ If the user has requested a formfeed, use one. -+ Otherwise, use newlines. */ -+ -+static void -+pad_down (int lines) -+{ -+ int i; -+ -+ if (use_form_feed) -+ putchar ('\f'); -+ else -+ for (i = lines; i; --i) -+ putchar ('\n'); -+} -+ -+/* Read the rest of the line. -+ -+ Read from the current column's file until an end of line is -+ hit. Used when we've truncated a line and we no longer need -+ to print or store its characters. */ -+ -+static void -+read_rest_of_line (COLUMN *p) -+{ -+ int c; -+ FILE *f = p->fp; -+ -+ while ((c = getc (f)) != '\n') -+ { -+ if (c == '\f') -+ { -+ if ((c = getc (f)) != '\n') -+ ungetc (c, f); -+ if (keep_FF) -+ print_a_FF = true; -+ hold_file (p); -+ break; -+ } -+ else if (c == EOF) -+ { -+ close_file (p); -+ break; -+ } -+ } -+} -+ -+/* Read a line with skip_to_page. -+ -+ Read from the current column's file until an end of line is -+ hit. Used when we read full lines to skip pages. -+ With skip_to_page we have to check for FF-coincidence which is done -+ in function read_line otherwise. -+ Count lines of skipped pages to find the line number of 1st page -+ printed relative to 1st line of input file (start_line_num). */ -+ -+static void -+skip_read (COLUMN *p, int column_number) -+{ -+ int c; -+ FILE *f = p->fp; -+ int i; -+ bool single_ff = false; -+ COLUMN *q; -+ -+ /* Read 1st character in a line or any character succeeding a FF */ -+ if ((c = getc (f)) == '\f' && p->full_page_printed) -+ /* A FF-coincidence with a previous full_page_printed. -+ To avoid an additional empty page, eliminate the FF */ -+ if ((c = getc (f)) == '\n') -+ c = getc (f); -+ -+ p->full_page_printed = false; -+ -+ /* 1st character a FF means a single FF without any printable -+ characters. Don't count it as a line with -n option. */ -+ if (c == '\f') -+ single_ff = true; -+ -+ /* Preparing for a FF-coincidence: Maybe we finish that page -+ without a FF found */ -+ if (last_line) -+ p->full_page_printed = true; -+ -+ while (c != '\n') -+ { -+ if (c == '\f') -+ { -+ /* No FF-coincidence possible, -+ no catching up of a FF-coincidence with next page */ -+ if (last_line) -+ { -+ if (!parallel_files) -+ for (q = column_vector, i = columns; i; ++q, --i) -+ q->full_page_printed = false; -+ else -+ p->full_page_printed = false; -+ } -+ -+ if ((c = getc (f)) != '\n') -+ ungetc (c, f); -+ hold_file (p); -+ break; -+ } -+ else if (c == EOF) -+ { -+ close_file (p); -+ break; -+ } -+ c = getc (f); -+ } -+ -+ if (skip_count) -+ if ((!parallel_files || column_number == 1) && !single_ff) -+ ++line_count; -+} -+ -+/* If we're tabifying output, -+ -+ When print_char encounters white space it keeps track -+ of our desired horizontal position and delays printing -+ until this function is called. */ -+ -+static void -+print_white_space (void) -+{ -+ int h_new; -+ int h_old = output_position; -+ int goal = h_old + spaces_not_printed; -+ -+ while (goal - h_old > 1 -+ && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) -+ { -+ putchar (output_tab_char); -+ h_old = h_new; -+ } -+ while (++h_old <= goal) -+ putchar (' '); -+ -+ output_position = goal; -+ spaces_not_printed = 0; -+} -+ -+/* Print column separators. -+ -+ We keep a count until we know that we'll be printing a line, -+ then print_sep_string() is called. */ -+ -+static void -+print_sep_string (void) -+{ -+ char *s; -+ int l = col_sep_length; -+ -+ s = col_sep_string; -+ -+ if (separators_not_printed <= 0) -+ { -+ /* We'll be starting a line with chars_per_margin, anything else? */ -+ if (spaces_not_printed > 0) -+ print_white_space (); -+ } -+ else -+ { -+ for (; separators_not_printed > 0; --separators_not_printed) -+ { -+ while (l-- > 0) -+ { -+ /* 3 types of sep_strings: spaces only, spaces and chars, -+ chars only */ -+ if (*s == ' ') -+ { -+ /* We're tabifying output; consecutive spaces in -+ sep_string may have to be converted to tabs */ -+ s++; -+ ++spaces_not_printed; -+ } -+ else -+ { -+ if (spaces_not_printed > 0) -+ print_white_space (); -+ putchar (*s++); -+ ++output_position; -+ } -+ } -+ /* sep_string ends with some spaces */ -+ if (spaces_not_printed > 0) -+ print_white_space (); -+ } -+ } -+} -+ -+/* Print (or store, depending on p->char_func) a clump of N -+ characters. */ -+ -+static void -+print_clump (COLUMN *p, int n, char *clump) -+{ -+ while (n--) -+ (p->char_func) (*clump++); -+} -+ -+/* Print a character. -+ -+ Update the following comment: process-char hasn't been used any -+ longer. -+ If we're tabifying, all tabs have been converted to spaces by -+ process_char(). Keep a count of consecutive spaces, and when -+ a nonspace is encountered, call print_white_space() to print the -+ required number of tabs and spaces. */ -+ -+static void -+print_char (char c) -+{ -+ if (tabify_output) -+ { -+ if (c == ' ') -+ { -+ ++spaces_not_printed; -+ return; -+ } -+ else if (spaces_not_printed > 0) -+ print_white_space (); -+ -+ /* Nonprintables are assumed to have width 0, except '\b'. */ -+ if (! isprint (to_uchar (c))) -+ { -+ if (c == '\b') -+ --output_position; -+ } -+ else -+ ++output_position; -+ } -+ putchar (c); -+} -+ -+/* Skip to page PAGE before printing. -+ PAGE may be larger than total number of pages. */ -+ -+static bool -+skip_to_page (uintmax_t page) -+{ -+ uintmax_t n; -+ int i; -+ int j; -+ COLUMN *p; -+ -+ for (n = 1; n < page; ++n) -+ { -+ for (i = 1; i < lines_per_body; ++i) -+ { -+ for (j = 1, p = column_vector; j <= columns; ++j, ++p) -+ if (p->status == OPEN) -+ skip_read (p, j); -+ } -+ last_line = true; -+ for (j = 1, p = column_vector; j <= columns; ++j, ++p) -+ if (p->status == OPEN) -+ skip_read (p, j); -+ -+ if (storing_columns) /* change FF_FOUND to ON_HOLD */ -+ for (j = 1, p = column_vector; j <= columns; ++j, ++p) -+ if (p->status != CLOSED) -+ p->status = ON_HOLD; -+ -+ reset_status (); -+ last_line = false; -+ -+ if (files_ready_to_read < 1) -+ { -+ /* It's very helpful, normally the total number of pages is -+ not known in advance. */ -+ error (0, 0, -+ _("starting page number %"PRIuMAX -+ " exceeds page count %"PRIuMAX), -+ page, n); -+ break; -+ } -+ } -+ return files_ready_to_read > 0; -+} -+ -+/* Print a header. -+ -+ Formfeeds are assumed to use up two lines at the beginning of -+ the page. */ -+ -+static void -+print_header (void) -+{ -+ char page_text[256 + INT_STRLEN_BOUND (page_number)]; -+ int available_width; -+ int lhs_spaces; -+ int rhs_spaces; -+ -+ output_position = 0; -+ pad_across_to (chars_per_margin); -+ print_white_space (); -+ -+ if (page_number == 0) -+ error (EXIT_FAILURE, 0, _("page number overflow")); -+ -+ /* The translator must ensure that formatting the translation of -+ "Page %"PRIuMAX does not generate more than (sizeof page_text - 1) -+ bytes. */ -+ sprintf (page_text, _("Page %"PRIuMAX), page_number++); -+ available_width = header_width_available - mbswidth (page_text, 0); -+ available_width = MAX (0, available_width); -+ lhs_spaces = available_width >> 1; -+ rhs_spaces = available_width - lhs_spaces; -+ -+ printf ("\n\n%*.*s%s%*.*s%s%*.*s%s\n\n\n", -+ chars_per_margin, chars_per_margin, " ", -+ date_text, lhs_spaces, lhs_spaces, " ", -+ file_text, rhs_spaces, rhs_spaces, " ", page_text); -+ -+ print_a_header = false; -+ output_position = 0; -+} -+ -+/* Print (or store, if p->char_func is store_char()) a line. -+ -+ Read a character to determine whether we have a line or not. -+ (We may hit EOF, \n, or \f) -+ -+ Once we know we have a line, -+ set pad_vertically = true, meaning it's safe -+ to pad down at the end of the page, since we do have a page. -+ print a header if needed. -+ pad across to padding_not_printed if needed. -+ print any separators which need to be printed. -+ print a line number if it needs to be printed. -+ -+ Print the clump which corresponds to the first character. -+ -+ Enter a loop and keep printing until an end of line condition -+ exists, or until we exceed chars_per_column. -+ -+ Return false if we exceed chars_per_column before reading -+ an end of line character, true otherwise. */ -+ -+static bool -+read_line (COLUMN *p) -+{ -+ int c; -+ int chars IF_LINT (= 0); -+ int last_input_position; -+ int j, k; -+ COLUMN *q; -+ -+ /* read 1st character in each line or any character succeeding a FF: */ -+ c = getc (p->fp); -+ -+ last_input_position = input_position; -+ -+ if (c == '\f' && p->full_page_printed) -+ if ((c = getc (p->fp)) == '\n') -+ c = getc (p->fp); -+ p->full_page_printed = false; -+ -+ switch (c) -+ { -+ case '\f': -+ if ((c = getc (p->fp)) != '\n') -+ ungetc (c, p->fp); -+ FF_only = true; -+ if (print_a_header && !storing_columns) -+ { -+ pad_vertically = true; -+ print_header (); -+ } -+ else if (keep_FF) -+ print_a_FF = true; -+ hold_file (p); -+ return true; -+ case EOF: -+ close_file (p); -+ return true; -+ case '\n': -+ break; -+ default: -+ chars = char_to_clump (c); -+ } -+ -+ if (truncate_lines && input_position > chars_per_column) -+ { -+ input_position = last_input_position; -+ return false; -+ } -+ -+ if (p->char_func != store_char) -+ { -+ pad_vertically = true; -+ -+ if (print_a_header && !storing_columns) -+ print_header (); -+ -+ if (parallel_files && align_empty_cols) -+ { -+ /* We have to align empty columns at the beginning of a line. */ -+ k = separators_not_printed; -+ separators_not_printed = 0; -+ for (j = 1, q = column_vector; j <= k; ++j, ++q) -+ { -+ align_column (q); -+ separators_not_printed += 1; -+ } -+ padding_not_printed = p->start_position; -+ if (truncate_lines) -+ spaces_not_printed = chars_per_column; -+ else -+ spaces_not_printed = 0; -+ align_empty_cols = false; -+ } -+ -+ if (padding_not_printed - col_sep_length > 0) -+ { -+ pad_across_to (padding_not_printed - col_sep_length); -+ padding_not_printed = ANYWHERE; -+ } -+ -+ if (use_col_separator) -+ print_sep_string (); -+ } -+ -+ if (p->numbered) -+ add_line_number (p); -+ -+ empty_line = false; -+ if (c == '\n') -+ return true; -+ -+ print_clump (p, chars, clump_buff); -+ -+ for (;;) -+ { -+ c = getc (p->fp); -+ -+ switch (c) -+ { -+ case '\n': -+ return true; -+ case '\f': -+ if ((c = getc (p->fp)) != '\n') -+ ungetc (c, p->fp); -+ if (keep_FF) -+ print_a_FF = true; -+ hold_file (p); -+ return true; -+ case EOF: -+ close_file (p); -+ return true; -+ } -+ -+ last_input_position = input_position; -+ chars = char_to_clump (c); -+ if (truncate_lines && input_position > chars_per_column) -+ { -+ input_position = last_input_position; -+ return false; -+ } -+ -+ print_clump (p, chars, clump_buff); -+ } -+} -+ -+/* Print a line from buff. -+ -+ If this function has been called, we know we have "something to -+ print". But it remains to be seen whether we have a real text page -+ or an empty page (a single form feed) with/without a header only. -+ Therefore first we set pad_vertically to true and print a header -+ if necessary. -+ If FF_FOUND and we are using -t|-T option we omit any newline by -+ setting pad_vertically to false (see print_page). -+ Otherwise we pad across if necessary, print separators if necessary -+ and text of COLUMN *p. -+ -+ Return true, meaning there is no need to call read_rest_of_line. */ -+ -+static bool -+print_stored (COLUMN *p) -+{ -+ COLUMN *q; -+ int i; -+ -+ int line = p->current_line++; -+ char *first = &buff[line_vector[line]]; -+ /* FIXME -+ UMR: Uninitialized memory read: -+ * This is occurring while in: -+ print_stored [pr.c:2239] -+ * Reading 4 bytes from 0x5148c in the heap. -+ * Address 0x5148c is 4 bytes into a malloc'd block at 0x51488 of 676 bytes -+ * This block was allocated from: -+ malloc [rtlib.o] -+ xmalloc [xmalloc.c:94] -+ init_store_cols [pr.c:1648] -+ */ -+ char *last = &buff[line_vector[line + 1]]; -+ -+ pad_vertically = true; -+ -+ if (print_a_header) -+ print_header (); -+ -+ if (p->status == FF_FOUND) -+ { -+ for (i = 1, q = column_vector; i <= columns; ++i, ++q) -+ q->status = ON_HOLD; -+ if (column_vector->lines_to_print <= 0) -+ { -+ if (!extremities) -+ pad_vertically = false; -+ return true; /* print a header only */ -+ } -+ } -+ -+ if (padding_not_printed - col_sep_length > 0) -+ { -+ pad_across_to (padding_not_printed - col_sep_length); -+ padding_not_printed = ANYWHERE; -+ } -+ -+ if (use_col_separator) -+ print_sep_string (); -+ -+ while (first != last) -+ print_char (*first++); -+ -+ 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; -+ } -+ -+ return true; -+} -+ -+/* Convert a character to the proper format and return the number of -+ characters in the resulting clump. Increment input_position by -+ the width of the clump. -+ -+ Tabs are converted to clumps of spaces. -+ Nonprintable characters may be converted to clumps of escape -+ sequences or control prefixes. -+ -+ Note: the width of a clump is not necessarily equal to the number of -+ characters in clump_buff. (e.g, the width of '\b' is -1, while the -+ number of characters is 1.) */ -+ -+static int -+char_to_clump (char c) -+{ -+ unsigned char uc = c; -+ char *s = clump_buff; -+ int i; -+ char esc_buff[4]; -+ int width; -+ int chars; -+ int chars_per_c = 8; -+ -+ if (c == input_tab_char) -+ chars_per_c = chars_per_input_tab; -+ -+ if (c == input_tab_char || c == '\t') -+ { -+ width = TAB_WIDTH (chars_per_c, input_position); -+ -+ if (untabify_input) -+ { -+ for (i = width; i; --i) -+ *s++ = ' '; -+ chars = width; -+ } -+ else -+ { -+ *s = c; -+ chars = 1; -+ } -+ -+ } -+ else if (! isprint (uc)) -+ { -+ if (use_esc_sequence) -+ { -+ width = 4; -+ chars = 4; -+ *s++ = '\\'; -+ sprintf (esc_buff, "%03o", uc); -+ for (i = 0; i <= 2; ++i) -+ *s++ = esc_buff[i]; -+ } -+ else if (use_cntrl_prefix) -+ { -+ if (uc < 0200) -+ { -+ width = 2; -+ chars = 2; -+ *s++ = '^'; -+ *s++ = c ^ 0100; -+ } -+ else -+ { -+ width = 4; -+ chars = 4; -+ *s++ = '\\'; -+ sprintf (esc_buff, "%03o", uc); -+ for (i = 0; i <= 2; ++i) -+ *s++ = esc_buff[i]; -+ } -+ } -+ else if (c == '\b') -+ { -+ width = -1; -+ chars = 1; -+ *s = c; -+ } -+ else -+ { -+ width = 0; -+ chars = 1; -+ *s = c; -+ } -+ } -+ else -+ { -+ width = 1; -+ chars = 1; -+ *s = c; -+ } -+ -+ /* 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; -+ -+ return chars; -+} -+ -+/* We've just printed some files and need to clean up things before -+ looking for more options and printing the next batch of files. -+ -+ Free everything we've xmalloc'ed, except `header'. */ -+ -+static void -+cleanup (void) -+{ -+ free (number_buff); -+ free (clump_buff); -+ free (column_vector); -+ free (line_vector); -+ free (end_vector); -+ free (buff); -+} -+ -+/* Complain, print a usage message, and die. */ -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [FILE]...\n\ -+"), -+ program_name); -+ -+ fputs (_("\ -+Paginate or columnate FILE(s) for printing.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE]\n\ -+ begin [stop] printing with page FIRST_[LAST_]PAGE\n\ -+ -COLUMN, --columns=COLUMN\n\ -+ output COLUMN columns and print columns down,\n\ -+ unless -a is used. Balance number of lines in the\n\ -+ columns on each page.\n\ -+"), stdout); -+ fputs (_("\ -+ -a, --across print columns across rather than down, used together\n\ -+ with -COLUMN\n\ -+ -c, --show-control-chars\n\ -+ use hat notation (^G) and octal backslash notation\n\ -+ -d, --double-space\n\ -+ double space the output\n\ -+"), stdout); -+ fputs (_("\ -+ -D, --date-format=FORMAT\n\ -+ use FORMAT for the header date\n\ -+ -e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]]\n\ -+ expand input CHARs (TABs) to tab WIDTH (8)\n\ -+ -F, -f, --form-feed\n\ -+ use form feeds instead of newlines to separate pages\n\ -+ (by a 3-line page header with -F or a 5-line header\n\ -+ and trailer without -F)\n\ -+"), stdout); -+ fputs (_("\ -+ -h, --header=HEADER\n\ -+ use a centered HEADER instead of filename in page header,\n\ -+ -h \"\" prints a blank line, don't use -h\"\"\n\ -+ -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]]\n\ -+ replace spaces with CHARs (TABs) to tab WIDTH (8)\n\ -+ -J, --join-lines merge full lines, turns off -W line truncation, no column\n\ -+ alignment, --sep-string[=STRING] sets separators\n\ -+"), stdout); -+ fputs (_("\ -+ -l, --length=PAGE_LENGTH\n\ -+ set the page length to PAGE_LENGTH (66) lines\n\ -+ (default number of lines of text 56, and with -F 63)\n\ -+ -m, --merge print all files in parallel, one in each column,\n\ -+ truncate lines, but join lines of full length with -J\n\ -+"), stdout); -+ fputs (_("\ -+ -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]]\n\ -+ number lines, use DIGITS (5) digits, then SEP (TAB),\n\ -+ default counting starts with 1st line of input file\n\ -+ -N, --first-line-number=NUMBER\n\ -+ start counting with NUMBER at 1st line of first\n\ -+ page printed (see +FIRST_PAGE)\n\ -+"), stdout); -+ fputs (_("\ -+ -o, --indent=MARGIN\n\ -+ offset each line with MARGIN (zero) spaces, do not\n\ -+ affect -w or -W, MARGIN will be added to PAGE_WIDTH\n\ -+ -r, --no-file-warnings\n\ -+ omit warning when a file cannot be opened\n\ -+"), stdout); -+ fputs (_("\ -+ -s[CHAR],--separator[=CHAR]\n\ -+ separate columns by a single character, default for CHAR\n\ -+ is the character without -w and \'no char\' with -w\n\ -+ -s[CHAR] turns off line truncation of all 3 column\n\ -+ options (-COLUMN|-a -COLUMN|-m) except -w is set\n\ -+"), stdout); -+ fputs (_("\ -+ -SSTRING, --sep-string[=STRING]\n\ -+ separate columns by STRING,\n\ -+ without -S: Default separator with -J and \n\ -+ otherwise (same as -S\" \"), no effect on column options\n\ -+ -t, --omit-header omit page headers and trailers\n\ -+"), stdout); -+ fputs (_("\ -+ -T, --omit-pagination\n\ -+ omit page headers and trailers, eliminate any pagination\n\ -+ by form feeds set in input files\n\ -+ -v, --show-nonprinting\n\ -+ use octal backslash notation\n\ -+ -w, --width=PAGE_WIDTH\n\ -+ set page width to PAGE_WIDTH (72) characters for\n\ -+ multiple text-column output only, -s[char] turns off (72)\n\ -+"), stdout); -+ fputs (_("\ -+ -W, --page-width=PAGE_WIDTH\n\ -+ set page width to PAGE_WIDTH (72) characters always,\n\ -+ truncate lines, except -J option is set, no interference\n\ -+ with -S or -s\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+-t is implied if PAGE_LENGTH <= 10. With no FILE, or when\n\ -+FILE is -, read standard input.\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -diff -urNp coreutils-8.0-orig/src/sort.c coreutils-8.0/src/sort.c ---- coreutils-8.0-orig/src/sort.c 2009-09-29 15:27:54.000000000 +0200 -+++ coreutils-8.0/src/sort.c 2009-10-07 10:07:16.000000000 +0200 -@@ -22,10 +22,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" -@@ -122,14 +131,38 @@ static int decimal_point; - /* 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 }; - -@@ -268,13 +301,11 @@ static bool reverse; - 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. */ -@@ -712,6 +743,44 @@ reap_some (void) - 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 -@@ -1093,7 +1162,7 @@ zaptemp (const char *name) - free (node); - } - --#if HAVE_NL_LANGINFO -+#if HAVE_LANGINFO_CODESET - - static int - struct_month_cmp (const void *m1, const void *m2) -@@ -1108,7 +1177,7 @@ struct_month_cmp (const void *m1, const - /* Initialize the character class tables. */ - - static void --inittables (void) -+inittables_uni (void) - { - size_t i; - -@@ -1120,7 +1189,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) - { -@@ -1202,6 +1271,64 @@ specify_nmerge (int oi, char c, char con - xstrtol_fatal (e, oi, c, long_options, s); - } - -+#if HAVE_MBRTOWC -+static void -+inittables_mb (void) -+{ -+ int i, j, k, l; -+ char *name, *s; -+ size_t s_len, mblength; -+ char mbc[MB_LEN_MAX]; -+ wchar_t wc, pwc; -+ mbstate_t state_mb, state_wc; -+ -+ for (i = 0; i < MONTHS_PER_YEAR; i++) -+ { -+ s = (char *) nl_langinfo (ABMON_1 + i); -+ s_len = strlen (s); -+ monthtab[i].name = name = (char *) xmalloc (s_len + 1); -+ monthtab[i].val = i + 1; -+ -+ memset (&state_mb, '\0', sizeof (mbstate_t)); -+ memset (&state_wc, '\0', sizeof (mbstate_t)); -+ -+ for (j = 0; j < s_len;) -+ { -+ if (!ismbblank (s + j, s_len - j, &mblength)) -+ break; -+ j += mblength; -+ } -+ -+ for (k = 0; j < s_len;) -+ { -+ mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb); -+ assert (mblength != (size_t)-1 && mblength != (size_t)-2); -+ if (mblength == 0) -+ break; -+ -+ pwc = towupper (wc); -+ if (pwc == wc) -+ { -+ memcpy (mbc, s + j, mblength); -+ j += mblength; -+ } -+ else -+ { -+ j += mblength; -+ mblength = wcrtomb (mbc, pwc, &state_wc); -+ assert (mblength != (size_t)0 && mblength != (size_t)-1); -+ } -+ -+ for (l = 0; l < mblength; l++) -+ name[k++] = mbc[l]; -+ } -+ name[k] = '\0'; -+ } -+ qsort ((void *) monthtab, MONTHS_PER_YEAR, -+ sizeof (struct month), struct_month_cmp); -+} -+#endif -+ - /* Specify the amount of main memory to use when sorting. */ - static void - specify_sort_size (int oi, char c, char const *s) -@@ -1412,7 +1539,7 @@ buffer_linelim (struct buffer const *buf - 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; -@@ -1421,10 +1548,10 @@ begfield (const struct line *line, const - /* 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; -@@ -1450,11 +1577,70 @@ begfield (const struct line *line, const - return ptr; - } - -+#if HAVE_MBRTOWC -+static char * -+begfield_mb (const struct line *line, const struct keyfield *key) -+{ -+ int i; -+ char *ptr = line->text, *lim = ptr + line->length - 1; -+ size_t sword = key->sword; -+ size_t schar = key->schar; -+ size_t mblength; -+ mbstate_t state; -+ -+ memset (&state, '\0', sizeof(mbstate_t)); -+ -+ if (tab_length) -+ while (ptr < lim && sword--) -+ { -+ while (ptr < lim && memcmp (ptr, tab, tab_length) != 0) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ if (ptr < lim) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ } -+ else -+ while (ptr < lim && sword--) -+ { -+ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ if (ptr < lim) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ ptr += mblength; -+ } -+ while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ } -+ -+ if (key->skipsblanks) -+ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) -+ ptr += mblength; -+ -+ for (i = 0; i < schar; i++) -+ { -+ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); -+ -+ if (ptr + mblength > lim) -+ break; -+ else -+ ptr += mblength; -+ } -+ -+ return ptr; -+} -+#endif -+ - /* Return the limit of (a pointer to the first character after) the field - in LINE specified by KEY. */ - - static char * --limfield (const struct line *line, const struct keyfield *key) -+limfield_uni (const struct line *line, const struct keyfield *key) - { - char *ptr = line->text, *lim = ptr + line->length - 1; - size_t eword = key->eword, echar = key->echar; -@@ -1469,10 +1655,10 @@ limfield (const struct line *line, const - `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; -@@ -1518,10 +1704,10 @@ limfield (const struct line *line, const - */ - - /* 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; - } -@@ -1552,6 +1738,113 @@ limfield (const struct line *line, const - 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; -+ -+ 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->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 -@@ -1634,8 +1927,24 @@ fillbuf (struct buffer *buf, FILE *fp, c - 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; - } - } -@@ -1673,7 +1982,7 @@ fillbuf (struct buffer *buf, FILE *fp, c - 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++; -@@ -1782,6 +2091,25 @@ human_numcompare (const char *a, const c - : 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) - { -@@ -1815,7 +2143,7 @@ general_numcompare (const char *sa, cons - 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; -@@ -1996,11 +2324,79 @@ compare_version (char *restrict texta, s - 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 *key = keylist; - -@@ -2180,6 +2576,179 @@ keycompare (const struct line *a, const - 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 (;;) -+ { -+ char const *translate = 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 | 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, key)); -+ *lima = savea, *limb = saveb; -+ } -+ else if (key->version) -+ diff = compare_version (texta, lena, textb, lenb); -+ 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. */ - -@@ -3178,7 +3747,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 - -@@ -3199,6 +3768,27 @@ main (int argc, char **argv) - 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 (); - -@@ -3459,13 +4049,35 @@ 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; -+ 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 -@@ -3476,9 +4088,12 @@ 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 -urNp coreutils-8.0-orig/src/sort.c.orig coreutils-8.0/src/sort.c.orig ---- coreutils-8.0-orig/src/sort.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/sort.c.orig 2009-09-29 15:27:54.000000000 +0200 -@@ -0,0 +1,3697 @@ -+/* sort - sort lines of text (with all kinds of options). -+ Copyright (C) 1988, 1991-2009 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 . -+ -+ Written December 1988 by Mike Haertel. -+ The author may be reached (Email) at the address mike@gnu.ai.mit.edu, -+ or (US mail) as Mike Haertel c/o Free Software Foundation. -+ -+ Ørn E. Hansen added NLS support in 1997. */ -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include "system.h" -+#include "argmatch.h" -+#include "error.h" -+#include "filevercmp.h" -+#include "hard-locale.h" -+#include "hash.h" -+#include "md5.h" -+#include "physmem.h" -+#include "posixver.h" -+#include "quote.h" -+#include "quotearg.h" -+#include "randread.h" -+#include "readtokens0.h" -+#include "stdio--.h" -+#include "stdlib--.h" -+#include "strnumcmp.h" -+#include "xmemcoll.h" -+#include "xmemxfrm.h" -+#include "xstrtol.h" -+ -+#if HAVE_SYS_RESOURCE_H -+# include -+#endif -+#ifndef RLIMIT_DATA -+struct rlimit { size_t rlim_cur; }; -+# define getrlimit(Resource, Rlp) (-1) -+#endif -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "sort" -+ -+#define AUTHORS \ -+ proper_name ("Mike Haertel"), \ -+ proper_name ("Paul Eggert") -+ -+#if HAVE_LANGINFO_CODESET -+# include -+#endif -+ -+/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is -+ present. */ -+#ifndef SA_NOCLDSTOP -+# define SA_NOCLDSTOP 0 -+/* No sigprocmask. Always 'return' zero. */ -+# define sigprocmask(How, Set, Oset) (0) -+# define sigset_t int -+# if ! HAVE_SIGINTERRUPT -+# define siginterrupt(sig, flag) /* empty */ -+# endif -+#endif -+ -+#if !defined OPEN_MAX && defined NR_OPEN -+# define OPEN_MAX NR_OPEN -+#endif -+#if !defined OPEN_MAX -+# define OPEN_MAX 20 -+#endif -+ -+#define UCHAR_LIM (UCHAR_MAX + 1) -+ -+#ifndef DEFAULT_TMPDIR -+# define DEFAULT_TMPDIR "/tmp" -+#endif -+ -+/* Exit statuses. */ -+enum -+ { -+ /* POSIX says to exit with status 1 if invoked with -c and the -+ input is not properly sorted. */ -+ SORT_OUT_OF_ORDER = 1, -+ -+ /* POSIX says any other irregular exit must exit with a status -+ code greater than 1. */ -+ SORT_FAILURE = 2 -+ }; -+ -+enum -+ { -+ /* The number of times we should try to fork a compression process -+ (we retry if the fork call fails). We don't _need_ to compress -+ temp files, this is just to reduce disk access, so this number -+ can be small. */ -+ MAX_FORK_TRIES_COMPRESS = 2, -+ -+ /* The number of times we should try to fork a decompression process. -+ If we can't fork a decompression process, we can't sort, so this -+ number should be big. */ -+ MAX_FORK_TRIES_DECOMPRESS = 8 -+ }; -+ -+/* The representation of the decimal point in the current locale. */ -+static int decimal_point; -+ -+/* Thousands separator; if -1, then there isn't one. */ -+static int thousands_sep; -+ -+/* Nonzero if the corresponding locales are hard. */ -+static bool hard_LC_COLLATE; -+#if HAVE_NL_LANGINFO -+static bool hard_LC_TIME; -+#endif -+ -+#define NONZERO(x) ((x) != 0) -+ -+/* The kind of blanks for '-b' to skip in various options. */ -+enum blanktype { bl_start, bl_end, bl_both }; -+ -+/* The character marking end of line. Default to \n. */ -+static char eolchar = '\n'; -+ -+/* Lines are held in core as counted strings. */ -+struct line -+{ -+ char *text; /* Text of the line. */ -+ size_t length; /* Length including final newline. */ -+ char *keybeg; /* Start of first key. */ -+ char *keylim; /* Limit of first key. */ -+}; -+ -+/* Input buffers. */ -+struct buffer -+{ -+ char *buf; /* Dynamically allocated buffer, -+ partitioned into 3 regions: -+ - input data; -+ - unused area; -+ - an array of lines, in reverse order. */ -+ size_t used; /* Number of bytes used for input data. */ -+ size_t nlines; /* Number of lines in the line array. */ -+ size_t alloc; /* Number of bytes allocated. */ -+ size_t left; /* Number of bytes left from previous reads. */ -+ size_t line_bytes; /* Number of bytes to reserve for each line. */ -+ bool eof; /* An EOF has been read. */ -+}; -+ -+struct keyfield -+{ -+ size_t sword; /* Zero-origin 'word' to start at. */ -+ size_t schar; /* Additional characters to skip. */ -+ size_t eword; /* Zero-origin first word after field. */ -+ size_t echar; /* Additional characters in field. */ -+ bool const *ignore; /* Boolean array of characters to ignore. */ -+ char const *translate; /* Translation applied to characters. */ -+ bool skipsblanks; /* Skip leading blanks when finding start. */ -+ bool skipeblanks; /* Skip leading blanks when finding end. */ -+ bool numeric; /* Flag for numeric comparison. Handle -+ strings of digits with optional decimal -+ point, but no exponential notation. */ -+ bool random; /* Sort by random hash of key. */ -+ bool general_numeric; /* Flag for general, numeric comparison. -+ Handle numbers in exponential notation. */ -+ bool human_numeric; /* Flag for sorting by human readable -+ units with either SI xor IEC prefixes. */ -+ int si_present; /* Flag for checking for mixed SI and IEC. */ -+ bool month; /* Flag for comparison by month name. */ -+ bool reverse; /* Reverse the sense of comparison. */ -+ bool version; /* sort by version number */ -+ struct keyfield *next; /* Next keyfield to try. */ -+}; -+ -+struct month -+{ -+ char const *name; -+ int val; -+}; -+ -+/* FIXME: None of these tables work with multibyte character sets. -+ Also, there are many other bugs when handling multibyte characters. -+ One way to fix this is to rewrite `sort' to use wide characters -+ internally, but doing this with good performance is a bit -+ tricky. */ -+ -+/* Table of blanks. */ -+static bool blanks[UCHAR_LIM]; -+ -+/* Table of non-printing characters. */ -+static bool nonprinting[UCHAR_LIM]; -+ -+/* Table of non-dictionary characters (not letters, digits, or blanks). */ -+static bool nondictionary[UCHAR_LIM]; -+ -+/* Translation table folding lower case to upper. */ -+static char fold_toupper[UCHAR_LIM]; -+ -+#define MONTHS_PER_YEAR 12 -+ -+/* Table mapping month names to integers. -+ Alphabetic order allows binary search. */ -+static struct month monthtab[] = -+{ -+ {"APR", 4}, -+ {"AUG", 8}, -+ {"DEC", 12}, -+ {"FEB", 2}, -+ {"JAN", 1}, -+ {"JUL", 7}, -+ {"JUN", 6}, -+ {"MAR", 3}, -+ {"MAY", 5}, -+ {"NOV", 11}, -+ {"OCT", 10}, -+ {"SEP", 9} -+}; -+ -+/* During the merge phase, the number of files to merge at once. */ -+#define NMERGE_DEFAULT 16 -+ -+/* Minimum size for a merge or check buffer. */ -+#define MIN_MERGE_BUFFER_SIZE (2 + sizeof (struct line)) -+ -+/* Minimum sort size; the code might not work with smaller sizes. */ -+#define MIN_SORT_SIZE (nmerge * MIN_MERGE_BUFFER_SIZE) -+ -+/* The number of bytes needed for a merge or check buffer, which can -+ function relatively efficiently even if it holds only one line. If -+ a longer line is seen, this value is increased. */ -+static size_t merge_buffer_size = MAX (MIN_MERGE_BUFFER_SIZE, 256 * 1024); -+ -+/* The approximate maximum number of bytes of main memory to use, as -+ specified by the user. Zero if the user has not specified a size. */ -+static size_t sort_size; -+ -+/* The guessed size for non-regular files. */ -+#define INPUT_FILE_SIZE_GUESS (1024 * 1024) -+ -+/* Array of directory names in which any temporary files are to be created. */ -+static char const **temp_dirs; -+ -+/* Number of temporary directory names used. */ -+static size_t temp_dir_count; -+ -+/* Number of allocated slots in temp_dirs. */ -+static size_t temp_dir_alloc; -+ -+/* Flag to reverse the order of all comparisons. */ -+static bool reverse; -+ -+/* Flag for stable sort. This turns off the last ditch bytewise -+ comparison of lines, and instead leaves lines in the same order -+ 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 -+ separated by the empty string between a non-blank character and a blank -+ character. */ -+static int tab = TAB_DEFAULT; -+ -+/* Flag to remove consecutive duplicate lines from the output. -+ Only the last of a sequence of equal lines will be output. */ -+static bool unique; -+ -+/* Nonzero if any of the input files are the standard input. */ -+static bool have_read_stdin; -+ -+/* List of key field comparisons to be tried. */ -+static struct keyfield *keylist; -+ -+/* Program used to (de)compress temp files. Must accept -d. */ -+static char const *compress_program; -+ -+/* Maximum number of files to merge in one go. If more than this -+ number are present, temp files will be used. */ -+static unsigned int nmerge = NMERGE_DEFAULT; -+ -+static void sortlines_temp (struct line *, size_t, struct line *); -+ -+/* Report MESSAGE for FILE, then clean up and exit. -+ If FILE is null, it represents standard output. */ -+ -+static void die (char const *, char const *) ATTRIBUTE_NORETURN; -+static void -+die (char const *message, char const *file) -+{ -+ error (0, errno, "%s: %s", message, file ? file : _("standard output")); -+ exit (SORT_FAILURE); -+} -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [FILE]...\n\ -+ or: %s [OPTION]... --files0-from=F\n\ -+"), -+ program_name, program_name); -+ fputs (_("\ -+Write sorted concatenation of all FILE(s) to standard output.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+Ordering options:\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+ -b, --ignore-leading-blanks ignore leading blanks\n\ -+ -d, --dictionary-order consider only blanks and alphanumeric characters\n\ -+ -f, --ignore-case fold lower case to upper case characters\n\ -+"), stdout); -+ fputs (_("\ -+ -g, --general-numeric-sort compare according to general numerical value\n\ -+ -i, --ignore-nonprinting consider only printable characters\n\ -+ -M, --month-sort compare (unknown) < `JAN' < ... < `DEC'\n\ -+"), stdout); -+ fputs (_("\ -+ -h, --human-numeric-sort compare human readable numbers (e.g., 2K 1G)\n\ -+"), stdout); -+ fputs (_("\ -+ -n, --numeric-sort compare according to string numerical value\n\ -+ -R, --random-sort sort by random hash of keys\n\ -+ --random-source=FILE get random bytes from FILE\n\ -+ -r, --reverse reverse the result of comparisons\n\ -+"), stdout); -+ fputs (_("\ -+ --sort=WORD sort according to WORD:\n\ -+ general-numeric -g, human-numeric -h, month -M,\n\ -+ numeric -n, random -R, version -V\n\ -+ -V, --version-sort natural sort of (version) numbers within text\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Other options:\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+ --batch-size=NMERGE merge at most NMERGE inputs at once;\n\ -+ for more use temp files\n\ -+"), stdout); -+ fputs (_("\ -+ -c, --check, --check=diagnose-first check for sorted input; do not sort\n\ -+ -C, --check=quiet, --check=silent like -c, but do not report first bad line\n\ -+ --compress-program=PROG compress temporaries with PROG;\n\ -+ decompress them with PROG -d\n\ -+ --files0-from=F read input from the files specified by\n\ -+ NUL-terminated names in file F;\n\ -+ If F is - then read names from standard input\n\ -+"), stdout); -+ fputs (_("\ -+ -k, --key=POS1[,POS2] start a key at POS1 (origin 1), end it at POS2\n\ -+ (default end of line)\n\ -+ -m, --merge merge already sorted files; do not sort\n\ -+"), stdout); -+ fputs (_("\ -+ -o, --output=FILE write result to FILE instead of standard output\n\ -+ -s, --stable stabilize sort by disabling last-resort comparison\n\ -+ -S, --buffer-size=SIZE use SIZE for main memory buffer\n\ -+"), stdout); -+ printf (_("\ -+ -t, --field-separator=SEP use SEP instead of non-blank to blank transition\n\ -+ -T, --temporary-directory=DIR use DIR for temporaries, not $TMPDIR or %s;\n\ -+ multiple options specify multiple directories\n\ -+ -u, --unique with -c, check for strict ordering;\n\ -+ without -c, output only the first of an equal run\n\ -+"), DEFAULT_TMPDIR); -+ fputs (_("\ -+ -z, --zero-terminated end lines with 0 byte, not newline\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+POS is F[.C][OPTS], where F is the field number and C the character position\n\ -+in the field; both are origin 1. If neither -t nor -b is in effect, characters\n\ -+in a field are counted from the beginning of the preceding whitespace. OPTS is\n\ -+one or more single-letter ordering options, which override global ordering\n\ -+options for that key. If no key is given, use the entire line as the key.\n\ -+\n\ -+SIZE may be followed by the following multiplicative suffixes:\n\ -+"), stdout); -+ fputs (_("\ -+% 1% of memory, b 1, K 1024 (default), and so on for M, G, T, P, E, Z, Y.\n\ -+\n\ -+With no FILE, or when FILE is -, read standard input.\n\ -+\n\ -+*** WARNING ***\n\ -+The locale specified by the environment affects sort order.\n\ -+Set LC_ALL=C to get the traditional sort order that uses\n\ -+native byte values.\n\ -+"), stdout ); -+ emit_ancillary_info (); -+ } -+ -+ exit (status); -+} -+ -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ CHECK_OPTION = CHAR_MAX + 1, -+ COMPRESS_PROGRAM_OPTION, -+ FILES0_FROM_OPTION, -+ NMERGE_OPTION, -+ RANDOM_SOURCE_OPTION, -+ SORT_OPTION -+}; -+ -+static char const short_options[] = "-bcCdfghik:mMno:rRsS:t:T:uVy:z"; -+ -+static struct option const long_options[] = -+{ -+ {"ignore-leading-blanks", no_argument, NULL, 'b'}, -+ {"check", optional_argument, NULL, CHECK_OPTION}, -+ {"compress-program", required_argument, NULL, COMPRESS_PROGRAM_OPTION}, -+ {"dictionary-order", no_argument, NULL, 'd'}, -+ {"ignore-case", no_argument, NULL, 'f'}, -+ {"files0-from", required_argument, NULL, FILES0_FROM_OPTION}, -+ {"general-numeric-sort", no_argument, NULL, 'g'}, -+ {"ignore-nonprinting", no_argument, NULL, 'i'}, -+ {"key", required_argument, NULL, 'k'}, -+ {"merge", no_argument, NULL, 'm'}, -+ {"month-sort", no_argument, NULL, 'M'}, -+ {"numeric-sort", no_argument, NULL, 'n'}, -+ {"human-numeric-sort", no_argument, NULL, 'h'}, -+ {"version-sort", no_argument, NULL, 'V'}, -+ {"random-sort", no_argument, NULL, 'R'}, -+ {"random-source", required_argument, NULL, RANDOM_SOURCE_OPTION}, -+ {"sort", required_argument, NULL, SORT_OPTION}, -+ {"output", required_argument, NULL, 'o'}, -+ {"reverse", no_argument, NULL, 'r'}, -+ {"stable", no_argument, NULL, 's'}, -+ {"batch-size", required_argument, NULL, NMERGE_OPTION}, -+ {"buffer-size", required_argument, NULL, 'S'}, -+ {"field-separator", required_argument, NULL, 't'}, -+ {"temporary-directory", required_argument, NULL, 'T'}, -+ {"unique", no_argument, NULL, 'u'}, -+ {"zero-terminated", no_argument, NULL, 'z'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0}, -+}; -+ -+#define CHECK_TABLE \ -+ _ct_("quiet", 'C') \ -+ _ct_("silent", 'C') \ -+ _ct_("diagnose-first", 'c') -+ -+static char const *const check_args[] = -+{ -+#define _ct_(_s, _c) _s, -+ CHECK_TABLE NULL -+#undef _ct_ -+}; -+static char const check_types[] = -+{ -+#define _ct_(_s, _c) _c, -+ CHECK_TABLE -+#undef _ct_ -+}; -+ -+#define SORT_TABLE \ -+ _st_("general-numeric", 'g') \ -+ _st_("human-numeric", 'h') \ -+ _st_("month", 'M') \ -+ _st_("numeric", 'n') \ -+ _st_("random", 'R') \ -+ _st_("version", 'V') -+ -+static char const *const sort_args[] = -+{ -+#define _st_(_s, _c) _s, -+ SORT_TABLE NULL -+#undef _st_ -+}; -+static char const sort_types[] = -+{ -+#define _st_(_s, _c) _c, -+ SORT_TABLE -+#undef _st_ -+}; -+ -+/* The set of signals that are caught. */ -+static sigset_t caught_signals; -+ -+/* Critical section status. */ -+struct cs_status -+{ -+ bool valid; -+ sigset_t sigs; -+}; -+ -+/* Enter a critical section. */ -+static struct cs_status -+cs_enter (void) -+{ -+ struct cs_status status; -+ status.valid = (sigprocmask (SIG_BLOCK, &caught_signals, &status.sigs) == 0); -+ return status; -+} -+ -+/* Leave a critical section. */ -+static void -+cs_leave (struct cs_status status) -+{ -+ if (status.valid) -+ { -+ /* Ignore failure when restoring the signal mask. */ -+ sigprocmask (SIG_SETMASK, &status.sigs, NULL); -+ } -+} -+ -+/* The list of temporary files. */ -+struct tempnode -+{ -+ struct tempnode *volatile next; -+ pid_t pid; /* If compressed, the pid of compressor, else zero */ -+ char name[1]; /* Actual size is 1 + file name length. */ -+}; -+static struct tempnode *volatile temphead; -+static struct tempnode *volatile *temptail = &temphead; -+ -+struct sortfile -+{ -+ char const *name; -+ pid_t pid; /* If compressed, the pid of compressor, else zero */ -+}; -+ -+/* A table where we store compression process states. We clean up all -+ processes in a timely manner so as not to exhaust system resources, -+ so we store the info on whether the process is still running, or has -+ been reaped here. */ -+static Hash_table *proctab; -+ -+enum { INIT_PROCTAB_SIZE = 47 }; -+ -+enum procstate { ALIVE, ZOMBIE }; -+ -+/* A proctab entry. The COUNT field is there in case we fork a new -+ compression process that has the same PID as an old zombie process -+ that is still in the table (because the process to decompress the -+ temp file it was associated with hasn't started yet). */ -+struct procnode -+{ -+ pid_t pid; -+ enum procstate state; -+ size_t count; -+}; -+ -+static size_t -+proctab_hasher (const void *entry, size_t tabsize) -+{ -+ const struct procnode *node = entry; -+ return node->pid % tabsize; -+} -+ -+static bool -+proctab_comparator (const void *e1, const void *e2) -+{ -+ const struct procnode *n1 = e1, *n2 = e2; -+ return n1->pid == n2->pid; -+} -+ -+/* The total number of forked processes (compressors and decompressors) -+ that have not been reaped yet. */ -+static size_t nprocs; -+ -+/* The number of child processes we'll allow before we try to reap some. */ -+enum { MAX_PROCS_BEFORE_REAP = 2 }; -+ -+/* If 0 < PID, wait for the child process with that PID to exit. -+ If PID is -1, clean up a random child process which has finished and -+ return the process ID of that child. If PID is -1 and no processes -+ have quit yet, return 0 without waiting. */ -+ -+static pid_t -+reap (pid_t pid) -+{ -+ int status; -+ pid_t cpid = waitpid (pid, &status, pid < 0 ? WNOHANG : 0); -+ -+ if (cpid < 0) -+ error (SORT_FAILURE, errno, _("waiting for %s [-d]"), -+ compress_program); -+ else if (0 < cpid) -+ { -+ if (! WIFEXITED (status) || WEXITSTATUS (status)) -+ error (SORT_FAILURE, 0, _("%s [-d] terminated abnormally"), -+ compress_program); -+ --nprocs; -+ } -+ -+ return cpid; -+} -+ -+/* Add the PID of a running compression process to proctab, or update -+ the entry COUNT and STATE fields if it's already there. This also -+ creates the table for us the first time it's called. */ -+ -+static void -+register_proc (pid_t pid) -+{ -+ struct procnode test, *node; -+ -+ if (! proctab) -+ { -+ proctab = hash_initialize (INIT_PROCTAB_SIZE, NULL, -+ proctab_hasher, -+ proctab_comparator, -+ free); -+ if (! proctab) -+ xalloc_die (); -+ } -+ -+ test.pid = pid; -+ node = hash_lookup (proctab, &test); -+ if (node) -+ { -+ node->state = ALIVE; -+ ++node->count; -+ } -+ else -+ { -+ node = xmalloc (sizeof *node); -+ node->pid = pid; -+ node->state = ALIVE; -+ node->count = 1; -+ if (hash_insert (proctab, node) == NULL) -+ xalloc_die (); -+ } -+} -+ -+/* This is called when we reap a random process. We don't know -+ whether we have reaped a compression process or a decompression -+ process until we look in the table. If there's an ALIVE entry for -+ it, then we have reaped a compression process, so change the state -+ to ZOMBIE. Otherwise, it's a decompression processes, so ignore it. */ -+ -+static void -+update_proc (pid_t pid) -+{ -+ struct procnode test, *node; -+ -+ test.pid = pid; -+ node = hash_lookup (proctab, &test); -+ if (node) -+ node->state = ZOMBIE; -+} -+ -+/* This is for when we need to wait for a compression process to exit. -+ If it has a ZOMBIE entry in the table then it's already dead and has -+ been reaped. Note that if there's an ALIVE entry for it, it still may -+ already have died and been reaped if a second process was created with -+ the same PID. This is probably exceedingly rare, but to be on the safe -+ side we will have to wait for any compression process with this PID. */ -+ -+static void -+wait_proc (pid_t pid) -+{ -+ struct procnode test, *node; -+ -+ test.pid = pid; -+ node = hash_lookup (proctab, &test); -+ if (node->state == ALIVE) -+ reap (pid); -+ -+ node->state = ZOMBIE; -+ if (! --node->count) -+ { -+ hash_delete (proctab, node); -+ free (node); -+ } -+} -+ -+/* Keep reaping finished children as long as there are more to reap. -+ This doesn't block waiting for any of them, it only reaps those -+ that are already dead. */ -+ -+static void -+reap_some (void) -+{ -+ pid_t pid; -+ -+ while (0 < nprocs && (pid = reap (-1))) -+ update_proc (pid); -+} -+ -+/* Clean up any remaining temporary files. */ -+ -+static void -+cleanup (void) -+{ -+ struct tempnode const *node; -+ -+ for (node = temphead; node; node = node->next) -+ unlink (node->name); -+ temphead = NULL; -+} -+ -+/* Cleanup actions to take when exiting. */ -+ -+static void -+exit_cleanup (void) -+{ -+ if (temphead) -+ { -+ /* Clean up any remaining temporary files in a critical section so -+ that a signal handler does not try to clean them too. */ -+ struct cs_status cs = cs_enter (); -+ cleanup (); -+ cs_leave (cs); -+ } -+ -+ close_stdout (); -+} -+ -+/* Create a new temporary file, returning its newly allocated tempnode. -+ Store into *PFD the file descriptor open for writing. -+ If the creation fails, return NULL and store -1 into *PFD if the -+ failure is due to file descriptor exhaustion and -+ SURVIVE_FD_EXHAUSTION; otherwise, die. */ -+ -+static struct tempnode * -+create_temp_file (int *pfd, bool survive_fd_exhaustion) -+{ -+ static char const slashbase[] = "/sortXXXXXX"; -+ static size_t temp_dir_index; -+ int fd; -+ int saved_errno; -+ char const *temp_dir = temp_dirs[temp_dir_index]; -+ size_t len = strlen (temp_dir); -+ struct tempnode *node = -+ xmalloc (offsetof (struct tempnode, name) + len + sizeof slashbase); -+ char *file = node->name; -+ struct cs_status cs; -+ -+ memcpy (file, temp_dir, len); -+ memcpy (file + len, slashbase, sizeof slashbase); -+ node->next = NULL; -+ node->pid = 0; -+ if (++temp_dir_index == temp_dir_count) -+ temp_dir_index = 0; -+ -+ /* Create the temporary file in a critical section, to avoid races. */ -+ cs = cs_enter (); -+ fd = mkstemp (file); -+ if (0 <= fd) -+ { -+ *temptail = node; -+ temptail = &node->next; -+ } -+ saved_errno = errno; -+ cs_leave (cs); -+ errno = saved_errno; -+ -+ if (fd < 0) -+ { -+ if (! (survive_fd_exhaustion && errno == EMFILE)) -+ error (SORT_FAILURE, errno, _("cannot create temporary file in %s"), -+ quote (temp_dir)); -+ free (node); -+ node = NULL; -+ } -+ -+ *pfd = fd; -+ return node; -+} -+ -+/* Return a stream for FILE, opened with mode HOW. A null FILE means -+ standard output; HOW should be "w". When opening for input, "-" -+ means standard input. To avoid confusion, do not return file -+ descriptors STDIN_FILENO, STDOUT_FILENO, or STDERR_FILENO when -+ opening an ordinary FILE. Return NULL if unsuccessful. */ -+ -+static FILE * -+stream_open (const char *file, const char *how) -+{ -+ if (!file) -+ return stdout; -+ if (STREQ (file, "-") && *how == 'r') -+ { -+ have_read_stdin = true; -+ return stdin; -+ } -+ return fopen (file, how); -+} -+ -+/* Same as stream_open, except always return a non-null value; die on -+ failure. */ -+ -+static FILE * -+xfopen (const char *file, const char *how) -+ { -+ FILE *fp = stream_open (file, how); -+ if (!fp) -+ die (_("open failed"), file); -+ return fp; -+} -+ -+/* Close FP, whose name is FILE, and report any errors. */ -+ -+static void -+xfclose (FILE *fp, char const *file) -+{ -+ switch (fileno (fp)) -+ { -+ case STDIN_FILENO: -+ /* Allow reading stdin from tty more than once. */ -+ if (feof (fp)) -+ clearerr (fp); -+ break; -+ -+ case STDOUT_FILENO: -+ /* Don't close stdout just yet. close_stdout does that. */ -+ if (fflush (fp) != 0) -+ die (_("fflush failed"), file); -+ break; -+ -+ default: -+ if (fclose (fp) != 0) -+ die (_("close failed"), file); -+ break; -+ } -+} -+ -+static void -+dup2_or_die (int oldfd, int newfd) -+{ -+ if (dup2 (oldfd, newfd) < 0) -+ error (SORT_FAILURE, errno, _("dup2 failed")); -+} -+ -+/* Fork a child process for piping to and do common cleanup. The -+ TRIES parameter tells us how many times to try to fork before -+ giving up. Return the PID of the child, or -1 (setting errno) -+ on failure. */ -+ -+static pid_t -+pipe_fork (int pipefds[2], size_t tries) -+{ -+#if HAVE_WORKING_FORK -+ struct tempnode *saved_temphead; -+ int saved_errno; -+ unsigned int wait_retry = 1; -+ pid_t pid IF_LINT (= -1); -+ struct cs_status cs; -+ -+ if (pipe (pipefds) < 0) -+ return -1; -+ -+ while (tries--) -+ { -+ /* This is so the child process won't delete our temp files -+ if it receives a signal before exec-ing. */ -+ cs = cs_enter (); -+ saved_temphead = temphead; -+ temphead = NULL; -+ -+ pid = fork (); -+ saved_errno = errno; -+ if (pid) -+ temphead = saved_temphead; -+ -+ cs_leave (cs); -+ errno = saved_errno; -+ -+ if (0 <= pid || errno != EAGAIN) -+ break; -+ else -+ { -+ sleep (wait_retry); -+ wait_retry *= 2; -+ reap_some (); -+ } -+ } -+ -+ if (pid < 0) -+ { -+ saved_errno = errno; -+ close (pipefds[0]); -+ close (pipefds[1]); -+ errno = saved_errno; -+ } -+ else if (pid == 0) -+ { -+ close (STDIN_FILENO); -+ close (STDOUT_FILENO); -+ } -+ else -+ ++nprocs; -+ -+ return pid; -+ -+#else /* ! HAVE_WORKING_FORK */ -+ return -1; -+#endif -+} -+ -+/* Create a temporary file and start a compression program to filter output -+ to that file. Set *PFP to the file handle and if PPID is non-NULL, -+ set *PPID to the PID of the newly-created process. If the creation -+ fails, return NULL if the failure is due to file descriptor -+ exhaustion and SURVIVE_FD_EXHAUSTION; otherwise, die. */ -+ -+static char * -+maybe_create_temp (FILE **pfp, pid_t *ppid, bool survive_fd_exhaustion) -+{ -+ int tempfd; -+ struct tempnode *node = create_temp_file (&tempfd, survive_fd_exhaustion); -+ char *name; -+ -+ if (! node) -+ return NULL; -+ -+ name = node->name; -+ -+ if (compress_program) -+ { -+ int pipefds[2]; -+ -+ node->pid = pipe_fork (pipefds, MAX_FORK_TRIES_COMPRESS); -+ if (0 < node->pid) -+ { -+ close (tempfd); -+ close (pipefds[0]); -+ tempfd = pipefds[1]; -+ -+ register_proc (node->pid); -+ } -+ else if (node->pid == 0) -+ { -+ close (pipefds[1]); -+ dup2_or_die (tempfd, STDOUT_FILENO); -+ close (tempfd); -+ dup2_or_die (pipefds[0], STDIN_FILENO); -+ close (pipefds[0]); -+ -+ if (execlp (compress_program, compress_program, (char *) NULL) < 0) -+ error (SORT_FAILURE, errno, _("couldn't execute %s"), -+ compress_program); -+ } -+ else -+ node->pid = 0; -+ } -+ -+ *pfp = fdopen (tempfd, "w"); -+ if (! *pfp) -+ die (_("couldn't create temporary file"), name); -+ -+ if (ppid) -+ *ppid = node->pid; -+ -+ return name; -+} -+ -+/* Create a temporary file and start a compression program to filter output -+ to that file. Set *PFP to the file handle and if *PPID is non-NULL, -+ set it to the PID of the newly-created process. Die on failure. */ -+ -+static char * -+create_temp (FILE **pfp, pid_t *ppid) -+{ -+ return maybe_create_temp (pfp, ppid, false); -+} -+ -+/* Open a compressed temp file and start a decompression process through -+ which to filter the input. PID must be the valid processes ID of the -+ process used to compress the file. Return NULL (setting errno to -+ EMFILE) if we ran out of file descriptors, and die on any other -+ kind of failure. */ -+ -+static FILE * -+open_temp (const char *name, pid_t pid) -+{ -+ int tempfd, pipefds[2]; -+ FILE *fp = NULL; -+ -+ wait_proc (pid); -+ -+ tempfd = open (name, O_RDONLY); -+ if (tempfd < 0) -+ return NULL; -+ -+ switch (pipe_fork (pipefds, MAX_FORK_TRIES_DECOMPRESS)) -+ { -+ case -1: -+ if (errno != EMFILE) -+ error (SORT_FAILURE, errno, _("couldn't create process for %s -d"), -+ compress_program); -+ close (tempfd); -+ errno = EMFILE; -+ break; -+ -+ case 0: -+ close (pipefds[0]); -+ dup2_or_die (tempfd, STDIN_FILENO); -+ close (tempfd); -+ dup2_or_die (pipefds[1], STDOUT_FILENO); -+ close (pipefds[1]); -+ -+ execlp (compress_program, compress_program, "-d", (char *) NULL); -+ error (SORT_FAILURE, errno, _("couldn't execute %s -d"), -+ compress_program); -+ -+ default: -+ close (tempfd); -+ close (pipefds[1]); -+ -+ fp = fdopen (pipefds[0], "r"); -+ if (! fp) -+ { -+ int saved_errno = errno; -+ close (pipefds[0]); -+ errno = saved_errno; -+ } -+ break; -+ } -+ -+ return fp; -+} -+ -+static void -+write_bytes (const char *buf, size_t n_bytes, FILE *fp, const char *output_file) -+{ -+ if (fwrite (buf, 1, n_bytes, fp) != n_bytes) -+ die (_("write failed"), output_file); -+} -+ -+/* Append DIR to the array of temporary directory names. */ -+static void -+add_temp_dir (char const *dir) -+{ -+ if (temp_dir_count == temp_dir_alloc) -+ temp_dirs = X2NREALLOC (temp_dirs, &temp_dir_alloc); -+ -+ temp_dirs[temp_dir_count++] = dir; -+} -+ -+/* Remove NAME from the list of temporary files. */ -+ -+static void -+zaptemp (const char *name) -+{ -+ struct tempnode *volatile *pnode; -+ struct tempnode *node; -+ struct tempnode *next; -+ int unlink_status; -+ int unlink_errno = 0; -+ struct cs_status cs; -+ -+ for (pnode = &temphead; (node = *pnode)->name != name; pnode = &node->next) -+ continue; -+ -+ /* Unlink the temporary file in a critical section to avoid races. */ -+ next = node->next; -+ cs = cs_enter (); -+ unlink_status = unlink (name); -+ unlink_errno = errno; -+ *pnode = next; -+ cs_leave (cs); -+ -+ if (unlink_status != 0) -+ error (0, unlink_errno, _("warning: cannot remove: %s"), name); -+ if (! next) -+ temptail = pnode; -+ free (node); -+} -+ -+#if HAVE_NL_LANGINFO -+ -+static int -+struct_month_cmp (const void *m1, const void *m2) -+{ -+ struct month const *month1 = m1; -+ struct month const *month2 = m2; -+ return strcmp (month1->name, month2->name); -+} -+ -+#endif -+ -+/* Initialize the character class tables. */ -+ -+static void -+inittables (void) -+{ -+ size_t i; -+ -+ for (i = 0; i < UCHAR_LIM; ++i) -+ { -+ blanks[i] = !! isblank (i); -+ nonprinting[i] = ! isprint (i); -+ nondictionary[i] = ! isalnum (i) && ! isblank (i); -+ fold_toupper[i] = toupper (i); -+ } -+ -+#if HAVE_NL_LANGINFO -+ /* If we're not in the "C" locale, read different names for months. */ -+ if (hard_LC_TIME) -+ { -+ for (i = 0; i < MONTHS_PER_YEAR; i++) -+ { -+ char const *s; -+ size_t s_len; -+ size_t j; -+ char *name; -+ -+ s = (char *) nl_langinfo (ABMON_1 + i); -+ s_len = strlen (s); -+ monthtab[i].name = name = xmalloc (s_len + 1); -+ monthtab[i].val = i + 1; -+ -+ for (j = 0; j < s_len; j++) -+ name[j] = fold_toupper[to_uchar (s[j])]; -+ name[j] = '\0'; -+ } -+ qsort ((void *) monthtab, MONTHS_PER_YEAR, -+ sizeof *monthtab, struct_month_cmp); -+ } -+#endif -+} -+ -+/* Specify how many inputs may be merged at once. -+ This may be set on the command-line with the -+ --batch-size option. */ -+static void -+specify_nmerge (int oi, char c, char const *s) -+{ -+ uintmax_t n; -+ struct rlimit rlimit; -+ enum strtol_error e = xstrtoumax (s, NULL, 10, &n, NULL); -+ -+ /* Try to find out how many file descriptors we'll be able -+ to open. We need at least nmerge + 3 (STDIN_FILENO, -+ STDOUT_FILENO and STDERR_FILENO). */ -+ unsigned int max_nmerge = ((getrlimit (RLIMIT_NOFILE, &rlimit) == 0 -+ ? rlimit.rlim_cur -+ : OPEN_MAX) -+ - 3); -+ -+ if (e == LONGINT_OK) -+ { -+ nmerge = n; -+ if (nmerge != n) -+ e = LONGINT_OVERFLOW; -+ else -+ { -+ if (nmerge < 2) -+ { -+ error (0, 0, _("invalid --%s argument %s"), -+ long_options[oi].name, quote(s)); -+ error (SORT_FAILURE, 0, -+ _("minimum --%s argument is %s"), -+ long_options[oi].name, quote("2")); -+ } -+ else if (max_nmerge < nmerge) -+ { -+ e = LONGINT_OVERFLOW; -+ } -+ else -+ return; -+ } -+ } -+ -+ if (e == LONGINT_OVERFLOW) -+ { -+ char max_nmerge_buf[INT_BUFSIZE_BOUND (unsigned int)]; -+ error (0, 0, _("--%s argument %s too large"), -+ long_options[oi].name, quote(s)); -+ error (SORT_FAILURE, 0, -+ _("maximum --%s argument with current rlimit is %s"), -+ long_options[oi].name, -+ uinttostr (max_nmerge, max_nmerge_buf)); -+ } -+ else -+ xstrtol_fatal (e, oi, c, long_options, s); -+} -+ -+/* Specify the amount of main memory to use when sorting. */ -+static void -+specify_sort_size (int oi, char c, char const *s) -+{ -+ uintmax_t n; -+ char *suffix; -+ enum strtol_error e = xstrtoumax (s, &suffix, 10, &n, "EgGkKmMPtTYZ"); -+ -+ /* The default unit is KiB. */ -+ if (e == LONGINT_OK && ISDIGIT (suffix[-1])) -+ { -+ if (n <= UINTMAX_MAX / 1024) -+ n *= 1024; -+ else -+ e = LONGINT_OVERFLOW; -+ } -+ -+ /* A 'b' suffix means bytes; a '%' suffix means percent of memory. */ -+ if (e == LONGINT_INVALID_SUFFIX_CHAR && ISDIGIT (suffix[-1]) && ! suffix[1]) -+ switch (suffix[0]) -+ { -+ case 'b': -+ e = LONGINT_OK; -+ break; -+ -+ case '%': -+ { -+ double mem = physmem_total () * n / 100; -+ -+ /* Use "<", not "<=", to avoid problems with rounding. */ -+ if (mem < UINTMAX_MAX) -+ { -+ n = mem; -+ e = LONGINT_OK; -+ } -+ else -+ e = LONGINT_OVERFLOW; -+ } -+ break; -+ } -+ -+ if (e == LONGINT_OK) -+ { -+ /* If multiple sort sizes are specified, take the maximum, so -+ that option order does not matter. */ -+ if (n < sort_size) -+ return; -+ -+ sort_size = n; -+ if (sort_size == n) -+ { -+ sort_size = MAX (sort_size, MIN_SORT_SIZE); -+ return; -+ } -+ -+ e = LONGINT_OVERFLOW; -+ } -+ -+ xstrtol_fatal (e, oi, c, long_options, s); -+} -+ -+/* Return the default sort size. */ -+static size_t -+default_sort_size (void) -+{ -+ /* Let MEM be available memory or 1/8 of total memory, whichever -+ is greater. */ -+ double avail = physmem_available (); -+ double total = physmem_total (); -+ double mem = MAX (avail, total / 8); -+ struct rlimit rlimit; -+ -+ /* Let SIZE be MEM, but no more than the maximum object size or -+ system resource limits. Avoid the MIN macro here, as it is not -+ quite right when only one argument is floating point. Don't -+ bother to check for values like RLIM_INFINITY since in practice -+ they are not much less than SIZE_MAX. */ -+ size_t size = SIZE_MAX; -+ if (mem < size) -+ size = mem; -+ if (getrlimit (RLIMIT_DATA, &rlimit) == 0 && rlimit.rlim_cur < size) -+ size = rlimit.rlim_cur; -+#ifdef RLIMIT_AS -+ if (getrlimit (RLIMIT_AS, &rlimit) == 0 && rlimit.rlim_cur < size) -+ size = rlimit.rlim_cur; -+#endif -+ -+ /* Leave a large safety margin for the above limits, as failure can -+ occur when they are exceeded. */ -+ size /= 2; -+ -+#ifdef RLIMIT_RSS -+ /* Leave a 1/16 margin for RSS to leave room for code, stack, etc. -+ Exceeding RSS is not fatal, but can be quite slow. */ -+ if (getrlimit (RLIMIT_RSS, &rlimit) == 0 && rlimit.rlim_cur / 16 * 15 < size) -+ size = rlimit.rlim_cur / 16 * 15; -+#endif -+ -+ /* Use no less than the minimum. */ -+ return MAX (size, MIN_SORT_SIZE); -+} -+ -+/* Return the sort buffer size to use with the input files identified -+ by FPS and FILES, which are alternate names of the same files. -+ NFILES gives the number of input files; NFPS may be less. Assume -+ that each input line requires LINE_BYTES extra bytes' worth of line -+ information. Do not exceed the size bound specified by the user -+ (or a default size bound, if the user does not specify one). */ -+ -+static size_t -+sort_buffer_size (FILE *const *fps, size_t nfps, -+ char *const *files, size_t nfiles, -+ size_t line_bytes) -+{ -+ /* A bound on the input size. If zero, the bound hasn't been -+ determined yet. */ -+ static size_t size_bound; -+ -+ /* In the worst case, each input byte is a newline. */ -+ size_t worst_case_per_input_byte = line_bytes + 1; -+ -+ /* Keep enough room for one extra input line and an extra byte. -+ This extra room might be needed when preparing to read EOF. */ -+ size_t size = worst_case_per_input_byte + 1; -+ -+ size_t i; -+ -+ for (i = 0; i < nfiles; i++) -+ { -+ struct stat st; -+ off_t file_size; -+ size_t worst_case; -+ -+ if ((i < nfps ? fstat (fileno (fps[i]), &st) -+ : STREQ (files[i], "-") ? fstat (STDIN_FILENO, &st) -+ : stat (files[i], &st)) -+ != 0) -+ die (_("stat failed"), files[i]); -+ -+ if (S_ISREG (st.st_mode)) -+ file_size = st.st_size; -+ else -+ { -+ /* The file has unknown size. If the user specified a sort -+ buffer size, use that; otherwise, guess the size. */ -+ if (sort_size) -+ return sort_size; -+ file_size = INPUT_FILE_SIZE_GUESS; -+ } -+ -+ if (! size_bound) -+ { -+ size_bound = sort_size; -+ if (! size_bound) -+ size_bound = default_sort_size (); -+ } -+ -+ /* Add the amount of memory needed to represent the worst case -+ where the input consists entirely of newlines followed by a -+ single non-newline. Check for overflow. */ -+ worst_case = file_size * worst_case_per_input_byte + 1; -+ if (file_size != worst_case / worst_case_per_input_byte -+ || size_bound - size <= worst_case) -+ return size_bound; -+ size += worst_case; -+ } -+ -+ return size; -+} -+ -+/* Initialize BUF. Reserve LINE_BYTES bytes for each line; LINE_BYTES -+ must be at least sizeof (struct line). Allocate ALLOC bytes -+ initially. */ -+ -+static void -+initbuf (struct buffer *buf, size_t line_bytes, size_t alloc) -+{ -+ /* Ensure that the line array is properly aligned. If the desired -+ size cannot be allocated, repeatedly halve it until allocation -+ succeeds. The smaller allocation may hurt overall performance, -+ but that's better than failing. */ -+ for (;;) -+ { -+ alloc += sizeof (struct line) - alloc % sizeof (struct line); -+ buf->buf = malloc (alloc); -+ if (buf->buf) -+ break; -+ alloc /= 2; -+ if (alloc <= line_bytes + 1) -+ xalloc_die (); -+ } -+ -+ buf->line_bytes = line_bytes; -+ buf->alloc = alloc; -+ buf->used = buf->left = buf->nlines = 0; -+ buf->eof = false; -+} -+ -+/* Return one past the limit of the line array. */ -+ -+static inline struct line * -+buffer_linelim (struct buffer const *buf) -+{ -+ return (struct line *) (buf->buf + buf->alloc); -+} -+ -+/* Return a pointer to the first character of the field specified -+ by KEY in LINE. */ -+ -+static char * -+begfield (const struct line *line, const struct keyfield *key) -+{ -+ char *ptr = line->text, *lim = ptr + line->length - 1; -+ size_t sword = key->sword; -+ size_t schar = key->schar; -+ -+ /* The leading field separator itself is included in a field when -t -+ is absent. */ -+ -+ if (tab != TAB_DEFAULT) -+ while (ptr < lim && sword--) -+ { -+ while (ptr < lim && *ptr != tab) -+ ++ptr; -+ if (ptr < lim) -+ ++ptr; -+ } -+ else -+ while (ptr < lim && sword--) -+ { -+ while (ptr < lim && blanks[to_uchar (*ptr)]) -+ ++ptr; -+ while (ptr < lim && !blanks[to_uchar (*ptr)]) -+ ++ptr; -+ } -+ -+ /* If we're ignoring leading blanks when computing the Start -+ of the field, skip past them here. */ -+ if (key->skipsblanks) -+ while (ptr < lim && blanks[to_uchar (*ptr)]) -+ ++ptr; -+ -+ /* Advance PTR by SCHAR (if possible), but no further than LIM. */ -+ ptr = MIN (lim, ptr + schar); -+ -+ return ptr; -+} -+ -+/* 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) -+{ -+ char *ptr = line->text, *lim = ptr + line->length - 1; -+ size_t eword = key->eword, echar = key->echar; -+ -+ if (echar == 0) -+ eword++; /* Skip all of end field. */ -+ -+ /* Move PTR past EWORD fields or to one past the last byte on LINE, -+ whichever comes first. If there are more than EWORD fields, leave -+ PTR pointing at the beginning of the field having zero-based index, -+ EWORD. If a delimiter character was specified (via -t), then that -+ `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) -+ while (ptr < lim && eword--) -+ { -+ while (ptr < lim && *ptr != tab) -+ ++ptr; -+ if (ptr < lim && (eword || echar)) -+ ++ptr; -+ } -+ else -+ while (ptr < lim && eword--) -+ { -+ while (ptr < lim && blanks[to_uchar (*ptr)]) -+ ++ptr; -+ while (ptr < lim && !blanks[to_uchar (*ptr)]) -+ ++ptr; -+ } -+ -+#ifdef POSIX_UNSPECIFIED -+ /* The following block of code makes GNU sort incompatible with -+ standard Unix sort, so it's ifdef'd out for now. -+ The POSIX spec isn't clear on how to interpret this. -+ FIXME: request clarification. -+ -+ From: kwzh@gnu.ai.mit.edu (Karl Heuer) -+ Date: Thu, 30 May 96 12:20:41 -0400 -+ [Translated to POSIX 1003.1-2001 terminology by Paul Eggert.] -+ -+ [...]I believe I've found another bug in `sort'. -+ -+ $ cat /tmp/sort.in -+ a b c 2 d -+ pq rs 1 t -+ $ textutils-1.15/src/sort -k1.7,1.7 skipeblanks) -+ while (ptr < lim && blanks[to_uchar (*ptr)]) -+ ++ptr; -+ -+ /* Advance PTR by ECHAR (if possible), but no further than LIM. */ -+ ptr = MIN (lim, ptr + echar); -+ } -+ -+ return ptr; -+} -+ -+/* 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 -+ table too. FILE is the name of the file corresponding to FP. -+ Return true if some input was read. */ -+ -+static bool -+fillbuf (struct buffer *buf, FILE *fp, char const *file) -+{ -+ struct keyfield const *key = keylist; -+ char eol = eolchar; -+ size_t line_bytes = buf->line_bytes; -+ size_t mergesize = merge_buffer_size - MIN_MERGE_BUFFER_SIZE; -+ -+ if (buf->eof) -+ return false; -+ -+ if (buf->used != buf->left) -+ { -+ memmove (buf->buf, buf->buf + buf->used - buf->left, buf->left); -+ buf->used = buf->left; -+ buf->nlines = 0; -+ } -+ -+ for (;;) -+ { -+ char *ptr = buf->buf + buf->used; -+ struct line *linelim = buffer_linelim (buf); -+ struct line *line = linelim - buf->nlines; -+ size_t avail = (char *) linelim - buf->nlines * line_bytes - ptr; -+ char *line_start = buf->nlines ? line->text + line->length : buf->buf; -+ -+ while (line_bytes + 1 < avail) -+ { -+ /* Read as many bytes as possible, but do not read so many -+ bytes that there might not be enough room for the -+ corresponding line array. The worst case is when the -+ rest of the input file consists entirely of newlines, -+ except that the last byte is not a newline. */ -+ size_t readsize = (avail - 1) / (line_bytes + 1); -+ size_t bytes_read = fread (ptr, 1, readsize, fp); -+ char *ptrlim = ptr + bytes_read; -+ char *p; -+ avail -= bytes_read; -+ -+ if (bytes_read != readsize) -+ { -+ if (ferror (fp)) -+ die (_("read failed"), file); -+ if (feof (fp)) -+ { -+ buf->eof = true; -+ if (buf->buf == ptrlim) -+ return false; -+ if (ptrlim[-1] != eol) -+ *ptrlim++ = eol; -+ } -+ } -+ -+ /* Find and record each line in the just-read input. */ -+ while ((p = memchr (ptr, eol, ptrlim - ptr))) -+ { -+ ptr = p + 1; -+ line--; -+ line->text = line_start; -+ line->length = ptr - line_start; -+ mergesize = MAX (mergesize, line->length); -+ avail -= line_bytes; -+ -+ if (key) -+ { -+ /* Precompute the position of the first key for -+ efficiency. */ -+ line->keylim = (key->eword == SIZE_MAX -+ ? p -+ : limfield (line, key)); -+ -+ if (key->sword != SIZE_MAX) -+ line->keybeg = begfield (line, key); -+ else -+ { -+ if (key->skipsblanks) -+ while (blanks[to_uchar (*line_start)]) -+ line_start++; -+ line->keybeg = line_start; -+ } -+ } -+ -+ line_start = ptr; -+ } -+ -+ ptr = ptrlim; -+ if (buf->eof) -+ break; -+ } -+ -+ buf->used = ptr - buf->buf; -+ buf->nlines = buffer_linelim (buf) - line; -+ if (buf->nlines != 0) -+ { -+ buf->left = ptr - line_start; -+ merge_buffer_size = mergesize + MIN_MERGE_BUFFER_SIZE; -+ return true; -+ } -+ -+ { -+ /* The current input line is too long to fit in the buffer. -+ Double the buffer size and try again, keeping it properly -+ aligned. */ -+ size_t line_alloc = buf->alloc / sizeof (struct line); -+ buf->buf = x2nrealloc (buf->buf, &line_alloc, sizeof (struct line)); -+ buf->alloc = line_alloc * sizeof (struct line); -+ } -+ } -+} -+ -+/* Compare strings A and B as numbers without explicitly converting them to -+ machine numbers. Comparatively slow for short strings, but asymptotically -+ hideously fast. */ -+ -+static int -+numcompare (const char *a, const char *b) -+{ -+ while (blanks[to_uchar (*a)]) -+ a++; -+ while (blanks[to_uchar (*b)]) -+ b++; -+ -+ return strnumcmp (a, b, decimal_point, thousands_sep); -+} -+ -+/* Exit with an error if a mixture of SI and IEC units detected. */ -+ -+static void -+check_mixed_SI_IEC (char prefix, struct keyfield *key) -+{ -+ int si_present = prefix == 'i'; -+ if (key->si_present != -1 && si_present != key->si_present) -+ error (SORT_FAILURE, 0, _("both SI and IEC prefixes present on units")); -+ key->si_present = si_present; -+} -+ -+/* Return an integer which represents the order of magnitude of -+ the unit following the number. NUMBER can contain thousands separators -+ or a decimal point, but not have preceeding blanks. -+ Negative numbers return a negative unit order. */ -+ -+static int -+find_unit_order (const char *number, struct keyfield *key) -+{ -+ static const char orders [UCHAR_LIM] = -+ { -+#if SOME_DAY_WE_WILL_REQUIRE_C99 -+ ['K']=1, ['M']=2, ['G']=3, ['T']=4, ['P']=5, ['E']=6, ['Z']=7, ['Y']=8, -+ ['k']=1, -+#else -+ /* Generate the following table with this command: -+ perl -e 'my %a=(k=>1, K=>1, M=>2, G=>3, T=>4, P=>5, E=>6, Z=>7, Y=>8); -+ foreach my $i (0..255) {my $c=chr($i); $a{$c} ||= 0;print "$a{$c}, "}'\ -+ |fmt */ -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, -+ 0, 0, 0, 1, 0, 2, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 0, 8, 7, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -+#endif -+ }; -+ -+ const unsigned char *p = number; -+ -+ int sign = 1; -+ -+ if (*p == '-') -+ { -+ sign = -1; -+ p++; -+ } -+ -+ /* Scan to end of number. -+ Decimals or separators not followed by digits stop the scan. -+ Numbers ending in decimals or separators are thus considered -+ to be lacking in units. -+ FIXME: add support for multibyte thousands_sep and decimal_point. */ -+ -+ while (ISDIGIT (*p)) -+ { -+ p++; -+ -+ if (*p == decimal_point && ISDIGIT (*(p + 1))) -+ p += 2; -+ else if (*p == thousands_sep && ISDIGIT (*(p + 1))) -+ p += 2; -+ } -+ -+ int order = orders[*p]; -+ -+ /* For valid units check for MiB vs MB etc. */ -+ if (order) -+ check_mixed_SI_IEC (*(p + 1), key); -+ -+ return sign * order; -+} -+ -+/* Compare numbers ending in units with SI xor IEC prefixes -+ < K/k < M < G < T < P < E < Z < Y -+ Assume that numbers are properly abbreviated. -+ i.e. input will never have both 6000K and 5M. */ -+ -+static int -+human_numcompare (const char *a, const char *b, struct keyfield *key) -+{ -+ while (blanks[to_uchar (*a)]) -+ a++; -+ while (blanks[to_uchar (*b)]) -+ b++; -+ -+ int order_a = find_unit_order (a, key); -+ int order_b = find_unit_order (b, key); -+ -+ return (order_a > order_b ? 1 -+ : order_a < order_b ? -1 -+ : strnumcmp (a, b, decimal_point, thousands_sep)); -+} -+ -+static int -+general_numcompare (const char *sa, const char *sb) -+{ -+ /* FIXME: add option to warn about failed conversions. */ -+ /* FIXME: maybe add option to try expensive FP conversion -+ only if A and B can't be compared more cheaply/accurately. */ -+ -+ char *ea; -+ char *eb; -+ double a = strtod (sa, &ea); -+ double b = strtod (sb, &eb); -+ -+ /* Put conversion errors at the start of the collating sequence. */ -+ if (sa == ea) -+ return sb == eb ? 0 : -1; -+ if (sb == eb) -+ return 1; -+ -+ /* Sort numbers in the usual way, where -0 == +0. Put NaNs after -+ conversion errors but before numbers; sort them by internal -+ bit-pattern, for lack of a more portable alternative. */ -+ return (a < b ? -1 -+ : a > b ? 1 -+ : a == b ? 0 -+ : b == b ? -1 -+ : a == a ? 1 -+ : memcmp ((char *) &a, (char *) &b, sizeof a)); -+} -+ -+/* Return an integer in 1..12 of the month name MONTH with length LEN. -+ Return 0 if the name in S is not recognized. */ -+ -+static int -+getmonth (char const *month, size_t len) -+{ -+ size_t lo = 0; -+ size_t hi = MONTHS_PER_YEAR; -+ char const *monthlim = month + len; -+ -+ for (;;) -+ { -+ if (month == monthlim) -+ return 0; -+ if (!blanks[to_uchar (*month)]) -+ break; -+ ++month; -+ } -+ -+ do -+ { -+ size_t ix = (lo + hi) / 2; -+ char const *m = month; -+ char const *n = monthtab[ix].name; -+ -+ for (;; m++, n++) -+ { -+ if (!*n) -+ return monthtab[ix].val; -+ if (m == monthlim || fold_toupper[to_uchar (*m)] < to_uchar (*n)) -+ { -+ hi = ix; -+ break; -+ } -+ else if (fold_toupper[to_uchar (*m)] > to_uchar (*n)) -+ { -+ lo = ix + 1; -+ break; -+ } -+ } -+ } -+ while (lo < hi); -+ -+ return 0; -+} -+ -+/* A source of random data. */ -+static struct randread_source *randread_source; -+ -+/* Return the Ith randomly-generated state. The caller must invoke -+ random_state (H) for all H less than I before invoking random_state -+ (I). */ -+ -+static struct md5_ctx -+random_state (size_t i) -+{ -+ /* An array of states resulting from the random data, and counts of -+ its used and allocated members. */ -+ static struct md5_ctx *state; -+ static size_t used; -+ static size_t allocated; -+ -+ struct md5_ctx *s = &state[i]; -+ -+ if (used <= i) -+ { -+ unsigned char buf[MD5_DIGEST_SIZE]; -+ -+ used++; -+ -+ if (allocated <= i) -+ { -+ state = X2NREALLOC (state, &allocated); -+ s = &state[i]; -+ } -+ -+ randread (randread_source, buf, sizeof buf); -+ md5_init_ctx (s); -+ md5_process_bytes (buf, sizeof buf, s); -+ } -+ -+ return *s; -+} -+ -+/* Compare the hashes of TEXTA with length LENGTHA to those of TEXTB -+ with length LENGTHB. Return negative if less, zero if equal, -+ positive if greater. */ -+ -+static int -+cmp_hashes (char const *texta, size_t lena, -+ char const *textb, size_t lenb) -+{ -+ /* Try random hashes until a pair of hashes disagree. But if the -+ first pair of random hashes agree, check whether the keys are -+ identical and if so report no difference. */ -+ int diff; -+ size_t i; -+ for (i = 0; ; i++) -+ { -+ uint32_t dig[2][MD5_DIGEST_SIZE / sizeof (uint32_t)]; -+ struct md5_ctx s[2]; -+ s[0] = s[1] = random_state (i); -+ md5_process_bytes (texta, lena, &s[0]); md5_finish_ctx (&s[0], dig[0]); -+ md5_process_bytes (textb, lenb, &s[1]); md5_finish_ctx (&s[1], dig[1]); -+ diff = memcmp (dig[0], dig[1], sizeof dig[0]); -+ if (diff != 0) -+ break; -+ if (i == 0 && lena == lenb && memcmp (texta, textb, lena) == 0) -+ break; -+ } -+ -+ return diff; -+} -+ -+/* Compare the keys TEXTA (of length LENA) and TEXTB (of length LENB) -+ using one or more random hash functions. */ -+ -+static int -+compare_random (char *restrict texta, size_t lena, -+ char *restrict textb, size_t lenb) -+{ -+ int diff; -+ -+ if (! hard_LC_COLLATE) -+ diff = cmp_hashes (texta, lena, textb, lenb); -+ else -+ { -+ /* Transform the text into the basis of comparison, so that byte -+ strings that would otherwise considered to be equal are -+ considered equal here even if their bytes differ. */ -+ -+ char *buf = NULL; -+ char stackbuf[4000]; -+ size_t tlena = xmemxfrm (stackbuf, sizeof stackbuf, texta, lena); -+ bool a_fits = tlena <= sizeof stackbuf; -+ size_t tlenb = xmemxfrm ((a_fits ? stackbuf + tlena : NULL), -+ (a_fits ? sizeof stackbuf - tlena : 0), -+ textb, lenb); -+ -+ if (a_fits && tlena + tlenb <= sizeof stackbuf) -+ buf = stackbuf; -+ else -+ { -+ /* Adding 1 to the buffer size lets xmemxfrm run a bit -+ faster by avoiding the need for an extra buffer copy. */ -+ buf = xmalloc (tlena + tlenb + 1); -+ xmemxfrm (buf, tlena + 1, texta, lena); -+ xmemxfrm (buf + tlena, tlenb + 1, textb, lenb); -+ } -+ -+ diff = cmp_hashes (buf, tlena, buf + tlena, tlenb); -+ -+ if (buf != stackbuf) -+ free (buf); -+ } -+ -+ return diff; -+} -+ -+/* Compare the keys TEXTA (of length LENA) and TEXTB (of length LENB) -+ using filevercmp. See lib/filevercmp.h for function description. */ -+ -+static int -+compare_version (char *restrict texta, size_t lena, -+ char *restrict textb, size_t lenb) -+{ -+ int diff; -+ -+ /* It is necessary to save the character after the end of the field. -+ "filevercmp" works with NUL terminated strings. Our blocks of -+ text are not necessarily terminated with a NUL byte. */ -+ char sv_a = texta[lena]; -+ char sv_b = textb[lenb]; -+ -+ texta[lena] = '\0'; -+ textb[lenb] = '\0'; -+ -+ diff = filevercmp (texta, textb); -+ -+ texta[lena] = sv_a; -+ textb[lenb] = sv_b; -+ -+ return diff; -+} -+ -+/* 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) -+{ -+ 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; -+ -+ int diff; -+ -+ for (;;) -+ { -+ char const *translate = key->translate; -+ bool const *ignore = key->ignore; -+ -+ /* Treat field ends before field starts as empty fields. */ -+ lima = MAX (texta, lima); -+ limb = MAX (textb, limb); -+ -+ /* Find the lengths. */ -+ size_t lena = lima - texta; -+ size_t lenb = limb - textb; -+ -+ /* Actually compare the fields. */ -+ -+ 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, key)); -+ *lima = savea, *limb = saveb; -+ } -+ else if (key->version) -+ diff = compare_version (texta, lena, textb, lenb); -+ else if (key->month) -+ diff = getmonth (texta, lena) - getmonth (textb, lenb); -+ /* Sorting like this may become slow, so in a simple locale the user -+ can select a faster sort that is similar to ascii sort. */ -+ else if (hard_LC_COLLATE) -+ { -+ if (ignore || translate) -+ { -+ char buf[4000]; -+ size_t size = lena + 1 + lenb + 1; -+ char *copy_a = (size <= sizeof buf ? buf : xmalloc (size)); -+ char *copy_b = copy_a + lena + 1; -+ size_t new_len_a, new_len_b, i; -+ -+ /* Ignore and/or translate chars before comparing. */ -+ for (new_len_a = new_len_b = i = 0; i < MAX (lena, lenb); i++) -+ { -+ if (i < lena) -+ { -+ copy_a[new_len_a] = (translate -+ ? translate[to_uchar (texta[i])] -+ : texta[i]); -+ if (!ignore || !ignore[to_uchar (texta[i])]) -+ ++new_len_a; -+ } -+ if (i < lenb) -+ { -+ copy_b[new_len_b] = (translate -+ ? translate[to_uchar (textb[i])] -+ : textb [i]); -+ if (!ignore || !ignore[to_uchar (textb[i])]) -+ ++new_len_b; -+ } -+ } -+ -+ diff = xmemcoll (copy_a, new_len_a, copy_b, new_len_b); -+ -+ if (sizeof buf < size) -+ free (copy_a); -+ } -+ else if (lena == 0) -+ diff = - NONZERO (lenb); -+ else if (lenb == 0) -+ goto greater; -+ else -+ diff = xmemcoll (texta, lena, textb, lenb); -+ } -+ else if (ignore) -+ { -+#define CMP_WITH_IGNORE(A, B) \ -+ do \ -+ { \ -+ for (;;) \ -+ { \ -+ while (texta < lima && ignore[to_uchar (*texta)]) \ -+ ++texta; \ -+ while (textb < limb && ignore[to_uchar (*textb)]) \ -+ ++textb; \ -+ if (! (texta < lima && textb < limb)) \ -+ break; \ -+ diff = to_uchar (A) - to_uchar (B); \ -+ if (diff) \ -+ goto not_equal; \ -+ ++texta; \ -+ ++textb; \ -+ } \ -+ \ -+ diff = (texta < lima) - (textb < limb); \ -+ } \ -+ while (0) -+ -+ if (translate) -+ CMP_WITH_IGNORE (translate[to_uchar (*texta)], -+ translate[to_uchar (*textb)]); -+ else -+ CMP_WITH_IGNORE (*texta, *textb); -+ } -+ else if (lena == 0) -+ diff = - NONZERO (lenb); -+ else if (lenb == 0) -+ goto greater; -+ else -+ { -+ if (translate) -+ { -+ while (texta < lima && textb < limb) -+ { -+ diff = (to_uchar (translate[to_uchar (*texta++)]) -+ - to_uchar (translate[to_uchar (*textb++)])); -+ if (diff) -+ goto not_equal; -+ } -+ } -+ else -+ { -+ diff = memcmp (texta, textb, MIN (lena, lenb)); -+ if (diff) -+ goto not_equal; -+ } -+ diff = lena < lenb ? -1 : lena != lenb; -+ } -+ -+ if (diff) -+ goto not_equal; -+ -+ key = key->next; -+ if (! key) -+ break; -+ -+ /* Find the beginning and limit of the next field. */ -+ if (key->eword != SIZE_MAX) -+ lima = limfield (a, key), limb = limfield (b, key); -+ else -+ lima = a->text + a->length - 1, limb = b->text + b->length - 1; -+ -+ if (key->sword != SIZE_MAX) -+ texta = begfield (a, key), textb = begfield (b, key); -+ else -+ { -+ texta = a->text, textb = b->text; -+ if (key->skipsblanks) -+ { -+ while (texta < lima && blanks[to_uchar (*texta)]) -+ ++texta; -+ while (textb < limb && blanks[to_uchar (*textb)]) -+ ++textb; -+ } -+ } -+ } -+ -+ return 0; -+ -+ greater: -+ diff = 1; -+ not_equal: -+ return key->reverse ? -diff : diff; -+} -+ -+/* Compare two lines A and B, returning negative, zero, or positive -+ depending on whether A compares less than, equal to, or greater than B. */ -+ -+static int -+compare (const struct line *a, const struct line *b) -+{ -+ int diff; -+ size_t alen, blen; -+ -+ /* First try to compare on the specified keys (if any). -+ The only two cases with no key at all are unadorned sort, -+ and unadorned sort -r. */ -+ if (keylist) -+ { -+ diff = keycompare (a, b); -+ if (diff || unique || stable) -+ return diff; -+ } -+ -+ /* If the keys all compare equal (or no keys were specified) -+ fall through to the default comparison. */ -+ alen = a->length - 1, blen = b->length - 1; -+ -+ if (alen == 0) -+ diff = - NONZERO (blen); -+ else if (blen == 0) -+ diff = 1; -+ else if (hard_LC_COLLATE) -+ diff = xmemcoll (a->text, alen, b->text, blen); -+ else if (! (diff = memcmp (a->text, b->text, MIN (alen, blen)))) -+ diff = alen < blen ? -1 : alen != blen; -+ -+ return reverse ? -diff : diff; -+} -+ -+/* Check that the lines read from FILE_NAME come in order. Return -+ true if they are in order. If CHECKONLY == 'c', also print a -+ diagnostic (FILE_NAME, line number, contents of line) to stderr if -+ they are not in order. */ ++ not_space_flag = 0; + while (l-- > 0) + { + /* 3 types of sep_strings: spaces only, spaces and chars, +@@ -2271,12 +2401,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; + -+static bool -+check (char const *file_name, char checkonly) + /* sep_string ends with some spaces */ + if (spaces_not_printed > 0) + print_white_space (); +@@ -2304,7 +2437,7 @@ print_clump (COLUMN *p, int n, char *clu + required number of tabs and spaces. */ + + static void +-print_char (char c) ++print_char_single (char c) + { + if (tabify_output) + { +@@ -2328,6 +2461,74 @@ print_char (char c) + putchar (c); + } + ++#ifdef HAVE_MBRTOWC ++static void ++print_char_multi (char c) +{ -+ FILE *fp = xfopen (file_name, "r"); -+ struct buffer buf; /* Input buffer. */ -+ struct line temp; /* Copy of previous line. */ -+ size_t alloc = 0; -+ uintmax_t line_number = 0; -+ struct keyfield const *key = keylist; -+ bool nonunique = ! unique; -+ bool ordered = true; -+ -+ initbuf (&buf, sizeof (struct line), -+ MAX (merge_buffer_size, sort_size)); -+ temp.text = NULL; -+ -+ while (fillbuf (&buf, fp, file_name)) ++ static size_t mbc_pos = 0; ++ static char mbc[MB_LEN_MAX] = {'\0'}; ++ static mbstate_t state = {'\0'}; ++ mbstate_t state_bak; ++ wchar_t wc; ++ size_t mblength; ++ int width; ++ ++ if (tabify_output) + { -+ struct line const *line = buffer_linelim (&buf); -+ struct line const *linebase = line - buf.nlines; ++ state_bak = state; ++ mbc[mbc_pos++] = c; ++ mblength = mbrtowc (&wc, mbc, mbc_pos, &state); + -+ /* Make sure the line saved from the old buffer contents is -+ less than or equal to the first line of the new buffer. */ -+ if (alloc && nonunique <= compare (&temp, line - 1)) ++ while (mbc_pos > 0) + { -+ found_disorder: -+ { -+ if (checkonly == 'c') -+ { -+ struct line const *disorder_line = line - 1; -+ uintmax_t disorder_line_number = -+ buffer_linelim (&buf) - disorder_line + line_number; -+ char hr_buf[INT_BUFSIZE_BOUND (uintmax_t)]; -+ fprintf (stderr, _("%s: %s:%s: disorder: "), -+ program_name, file_name, -+ umaxtostr (disorder_line_number, hr_buf)); -+ write_bytes (disorder_line->text, disorder_line->length, -+ stderr, _("standard error")); -+ } ++ switch (mblength) ++ { ++ case (size_t)-2: ++ state = state_bak; ++ return; + -+ ordered = false; -+ break; -+ } -+ } ++ case (size_t)-1: ++ state = state_bak; ++ ++output_position; ++ putchar (mbc[0]); ++ memmove (mbc, mbc + 1, MB_CUR_MAX - 1); ++ --mbc_pos; ++ break; + -+ /* Compare each line in the buffer with its successor. */ -+ while (linebase < --line) -+ if (nonunique <= compare (line, line - 1)) -+ goto found_disorder; ++ case 0: ++ mblength = 1; + -+ line_number += buf.nlines; ++ 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 (); + -+ /* Save the last line of the buffer. */ -+ if (alloc < line->length) -+ { -+ do -+ { -+ alloc *= 2; -+ if (! alloc) ++ /* Nonprintables are assumed to have width 0, except L'\b'. */ ++ if ((width = wcwidth (wc)) < 1) + { -+ alloc = line->length; -+ break; ++ if (wc == L'\b') ++ --output_position; + } -+ } -+ while (alloc < line->length); ++ else ++ output_position += width; + -+ temp.text = xrealloc (temp.text, alloc); -+ } -+ memcpy (temp.text, line->text, line->length); -+ temp.length = line->length; -+ if (key) -+ { -+ temp.keybeg = temp.text + (line->keybeg - line->text); -+ temp.keylim = temp.text + (line->keylim - line->text); ++ fwrite (mbc, sizeof(char), mblength, stdout); ++ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); ++ mbc_pos -= mblength; ++ } + } ++ return; + } -+ -+ xfclose (fp, file_name); -+ free (buf.buf); -+ free (temp.text); -+ return ordered; ++ putchar (c); +} ++#endif + -+/* Open FILES (there are NFILES of them) and store the resulting array -+ of stream pointers into (*PFPS). Allocate the array. Return the -+ number of successfully opened files, setting errno if this value is -+ less than NFILES. */ -+ -+static size_t -+open_input_files (struct sortfile *files, size_t nfiles, FILE ***pfps) + /* Skip to page PAGE before printing. + PAGE may be larger than total number of pages. */ + +@@ -2507,9 +2708,9 @@ read_line (COLUMN *p) + align_empty_cols = false; + } + +- 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; + } + +@@ -2610,9 +2811,9 @@ print_stored (COLUMN *p) + } + } + +- 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 +2826,8 @@ print_stored (COLUMN *p) + 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; ++ if (p->start_position - col_sep_width == chars_per_margin) ++ output_position -= col_sep_width; + } + + return true; +@@ -2645,7 +2846,7 @@ print_stored (COLUMN *p) + number of characters is 1.) */ + + static int +-char_to_clump (char c) ++char_to_clump_single (char c) + { + unsigned char uc = c; + char *s = clump_buff; +@@ -2655,10 +2856,10 @@ char_to_clump (char c) + int chars; + int chars_per_c = 8; + +- if (c == input_tab_char) ++ if (c == input_tab_char[0]) + chars_per_c = chars_per_input_tab; + +- if (c == input_tab_char || c == '\t') ++ if (c == input_tab_char[0] || c == '\t') + { + width = TAB_WIDTH (chars_per_c, input_position); + +@@ -2739,6 +2940,154 @@ char_to_clump (char c) + return chars; + } + ++#ifdef HAVE_MBRTOWC ++static int ++char_to_clump_multi (char c) +{ -+ FILE **fps = *pfps = xnmalloc (nfiles, sizeof *fps); -+ int i; -+ -+ /* Open as many input files as we can. */ -+ for (i = 0; i < nfiles; i++) -+ { -+ fps[i] = (files[i].pid -+ ? open_temp (files[i].name, files[i].pid) -+ : stream_open (files[i].name, "r")); -+ if (!fps[i]) -+ break; -+ } -+ -+ return i; -+} ++ static size_t mbc_pos = 0; ++ static char mbc[MB_LEN_MAX] = {'\0'}; ++ static mbstate_t state = {'\0'}; ++ mbstate_t state_bak; ++ wchar_t wc; ++ size_t mblength; ++ int wc_width; ++ register char *s = clump_buff; ++ register int i, j; ++ char esc_buff[4]; ++ int width; ++ int chars; ++ int chars_per_c = 8; + -+/* Merge lines from FILES onto OFP. NTEMPS is the number of temporary -+ files (all of which are at the start of the FILES array), and -+ NFILES is the number of files; 0 <= NTEMPS <= NFILES <= NMERGE. -+ FPS is the vector of open stream corresponding to the files. -+ Close input and output streams before returning. -+ OUTPUT_FILE gives the name of the output file. If it is NULL, -+ the output file is standard output. */ ++ state_bak = state; ++ mbc[mbc_pos++] = c; ++ mblength = mbrtowc (&wc, mbc, mbc_pos, &state); + -+static void -+mergefps (struct sortfile *files, size_t ntemps, size_t nfiles, -+ FILE *ofp, char const *output_file, FILE **fps) -+{ -+ struct buffer *buffer = xnmalloc (nfiles, sizeof *buffer); -+ /* Input buffers for each file. */ -+ struct line saved; /* Saved line storage for unique check. */ -+ struct line const *savedline = NULL; -+ /* &saved if there is a saved line. */ -+ size_t savealloc = 0; /* Size allocated for the saved line. */ -+ struct line const **cur = xnmalloc (nfiles, sizeof *cur); -+ /* Current line in each line table. */ -+ struct line const **base = xnmalloc (nfiles, sizeof *base); -+ /* Base of each line table. */ -+ size_t *ord = xnmalloc (nfiles, sizeof *ord); -+ /* Table representing a permutation of fps, -+ such that cur[ord[0]] is the smallest line -+ and will be next output. */ -+ size_t i; -+ size_t j; -+ size_t t; -+ struct keyfield const *key = keylist; -+ saved.text = NULL; -+ -+ /* Read initial lines from each input file. */ -+ for (i = 0; i < nfiles; ) ++ width = 0; ++ chars = 0; ++ while (mbc_pos > 0) + { -+ initbuf (&buffer[i], sizeof (struct line), -+ MAX (merge_buffer_size, sort_size / nfiles)); -+ if (fillbuf (&buffer[i], fps[i], files[i].name)) -+ { -+ struct line const *linelim = buffer_linelim (&buffer[i]); -+ cur[i] = linelim - 1; -+ base[i] = linelim - buffer[i].nlines; -+ i++; -+ } -+ else ++ switch (mblength) + { -+ /* fps[i] is empty; eliminate it from future consideration. */ -+ xfclose (fps[i], files[i].name); -+ if (i < ntemps) ++ case (size_t)-2: ++ state = state_bak; ++ return 0; ++ ++ case (size_t)-1: ++ state = state_bak; ++ mblength = 1; ++ ++ if (use_esc_sequence || use_cntrl_prefix) + { -+ ntemps--; -+ zaptemp (files[i].name); ++ width = +4; ++ chars = +4; ++ *s++ = '\\'; ++ sprintf (esc_buff, "%03o", mbc[0]); ++ for (i = 0; i <= 2; ++i) ++ *s++ = (int) esc_buff[i]; + } -+ free (buffer[i].buf); -+ --nfiles; -+ for (j = i; j < nfiles; ++j) ++ else + { -+ files[j] = files[j + 1]; -+ fps[j] = fps[j + 1]; ++ width += 1; ++ chars += 1; ++ *s++ = mbc[0]; + } -+ } -+ } ++ break; + -+ /* Set up the ord table according to comparisons among input lines. -+ Since this only reorders two items if one is strictly greater than -+ the other, it is stable. */ -+ for (i = 0; i < nfiles; ++i) -+ ord[i] = i; -+ for (i = 1; i < nfiles; ++i) -+ if (0 < compare (cur[ord[i - 1]], cur[ord[i]])) -+ t = ord[i - 1], ord[i - 1] = ord[i], ord[i] = t, i = 0; -+ -+ /* Repeatedly output the smallest line until no input remains. */ -+ while (nfiles) -+ { -+ struct line const *smallest = cur[ord[0]]; ++ case 0: ++ mblength = 1; ++ /* Fall through */ + -+ /* If uniquified output is turned on, output only the first of -+ an identical series of lines. */ -+ if (unique) -+ { -+ if (savedline && compare (savedline, smallest)) ++ 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') + { -+ savedline = NULL; -+ write_bytes (saved.text, saved.length, ofp, output_file); ++ int 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; ++ } + } -+ if (!savedline) ++ else if ((wc_width = wcwidth (wc)) < 1) + { -+ savedline = &saved; -+ if (savealloc < smallest->length) ++ 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') + { -+ do -+ if (! savealloc) -+ { -+ savealloc = smallest->length; -+ break; -+ } -+ while ((savealloc *= 2) < smallest->length); -+ -+ saved.text = xrealloc (saved.text, savealloc); ++ width += -1; ++ chars += 1; ++ *s++ = c; + } -+ saved.length = smallest->length; -+ memcpy (saved.text, smallest->text, saved.length); -+ if (key) ++ else + { -+ saved.keybeg = -+ saved.text + (smallest->keybeg - smallest->text); -+ saved.keylim = -+ saved.text + (smallest->keylim - smallest->text); ++ width += 0; ++ chars += mblength; ++ for (i = 0; i < mblength; i++) ++ *s++ = mbc[i]; + } + } -+ } -+ else -+ write_bytes (smallest->text, smallest->length, ofp, output_file); -+ -+ /* Check if we need to read more lines into core. */ -+ if (base[ord[0]] < smallest) -+ cur[ord[0]] = smallest - 1; -+ else -+ { -+ if (fillbuf (&buffer[ord[0]], fps[ord[0]], files[ord[0]].name)) -+ { -+ struct line const *linelim = buffer_linelim (&buffer[ord[0]]); -+ cur[ord[0]] = linelim - 1; -+ base[ord[0]] = linelim - buffer[ord[0]].nlines; -+ } + else + { -+ /* We reached EOF on fps[ord[0]]. */ -+ for (i = 1; i < nfiles; ++i) -+ if (ord[i] > ord[0]) -+ --ord[i]; -+ --nfiles; -+ xfclose (fps[ord[0]], files[ord[0]].name); -+ if (ord[0] < ntemps) -+ { -+ ntemps--; -+ zaptemp (files[ord[0]].name); -+ } -+ free (buffer[ord[0]].buf); -+ for (i = ord[0]; i < nfiles; ++i) -+ { -+ fps[i] = fps[i + 1]; -+ files[i] = files[i + 1]; -+ buffer[i] = buffer[i + 1]; -+ cur[i] = cur[i + 1]; -+ base[i] = base[i + 1]; -+ } -+ for (i = 0; i < nfiles; ++i) -+ ord[i] = ord[i + 1]; -+ continue; ++ width += wc_width; ++ chars += mblength; ++ for (i = 0; i < mblength; i++) ++ *s++ = mbc[i]; + } + } -+ -+ /* The new line just read in may be larger than other lines -+ already in main memory; push it back in the queue until we -+ encounter a line larger than it. Optimize for the common -+ case where the new line is smallest. */ -+ { -+ size_t lo = 1; -+ size_t hi = nfiles; -+ size_t probe = lo; -+ size_t ord0 = ord[0]; -+ size_t count_of_smaller_lines; -+ -+ while (lo < hi) -+ { -+ int cmp = compare (cur[ord0], cur[ord[probe]]); -+ if (cmp < 0 || (cmp == 0 && ord0 < ord[probe])) -+ hi = probe; -+ else -+ lo = probe + 1; -+ probe = (lo + hi) / 2; -+ } -+ -+ count_of_smaller_lines = lo - 1; -+ for (j = 0; j < count_of_smaller_lines; j++) -+ ord[j] = ord[j + 1]; -+ ord[count_of_smaller_lines] = ord0; -+ } -+ -+ /* Free up some resources every once in a while. */ -+ if (MAX_PROCS_BEFORE_REAP < nprocs) -+ reap_some (); -+ } -+ -+ if (unique && savedline) -+ { -+ write_bytes (saved.text, saved.length, ofp, output_file); -+ free (saved.text); ++ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); ++ mbc_pos -= mblength; + } + -+ xfclose (ofp, output_file); -+ free(fps); -+ free(buffer); -+ free(ord); -+ free(base); -+ free(cur); -+} -+ -+/* Merge lines from FILES onto OFP. NTEMPS is the number of temporary -+ files (all of which are at the start of the FILES array), and -+ NFILES is the number of files; 0 <= NTEMPS <= NFILES <= NMERGE. -+ Close input and output files before returning. -+ OUTPUT_FILE gives the name of the output file. -+ -+ Return the number of files successfully merged. This number can be -+ less than NFILES if we ran low on file descriptors, but in this -+ case it is never less than 2. */ -+ -+static size_t -+mergefiles (struct sortfile *files, size_t ntemps, size_t nfiles, -+ FILE *ofp, char const *output_file) -+{ -+ FILE **fps; -+ size_t nopened = open_input_files (files, nfiles, &fps); -+ if (nopened < nfiles && nopened < 2) -+ die (_("open failed"), files[nopened].name); -+ mergefps (files, ntemps, nopened, ofp, output_file, fps); -+ return nopened; ++ input_position += width; ++ return chars; +} ++#endif + -+/* Merge into T the two sorted arrays of lines LO (with NLO members) -+ and HI (with NHI members). T, LO, and HI point just past their -+ respective arrays, and the arrays are in reverse order. NLO and -+ NHI must be positive, and HI - NHI must equal T - (NLO + NHI). */ -+ -+static inline void -+mergelines (struct line *t, -+ struct line const *lo, size_t nlo, -+ struct line const *hi, size_t nhi) -+{ -+ for (;;) -+ if (compare (lo - 1, hi - 1) <= 0) -+ { -+ *--t = *--lo; -+ if (! --nlo) -+ { -+ /* HI - NHI equalled T - (NLO + NHI) when this function -+ began. Therefore HI must equal T now, and there is no -+ need to copy from HI to T. */ -+ return; -+ } -+ } -+ else -+ { -+ *--t = *--hi; -+ if (! --nhi) -+ { -+ do -+ *--t = *--lo; -+ while (--nlo); -+ -+ return; -+ } -+ } -+} + /* 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 -urNp coreutils-8.0-orig/src/sort.c coreutils-8.0/src/sort.c +--- coreutils-8.0-orig/src/sort.c 2009-09-29 15:27:54.000000000 +0200 ++++ coreutils-8.0/src/sort.c 2009-10-07 10:07:16.000000000 +0200 +@@ -22,10 +22,19 @@ + + #include + ++#include + #include + #include + #include + #include ++#if HAVE_WCHAR_H ++# include ++#endif ++/* Get isw* functions. */ ++#if HAVE_WCTYPE_H ++# include ++#endif + -+/* Sort the array LINES with NLINES members, using TEMP for temporary space. -+ NLINES must be at least 2. -+ The input and output arrays are in reverse order, and LINES and -+ TEMP point just past the end of their respective arrays. + #include "system.h" + #include "argmatch.h" + #include "error.h" +@@ -122,14 +131,38 @@ static int decimal_point; + /* Thousands separator; if -1, then there isn't one. */ + static int thousands_sep; + ++static int force_general_numcompare = 0; + -+ Use a recursive divide-and-conquer algorithm, in the style -+ suggested by Knuth volume 3 (2nd edition), exercise 5.2.4-23. Use -+ the optimization suggested by exercise 5.2.4-10; this requires room -+ for only 1.5*N lines, rather than the usual 2*N lines. Knuth -+ writes that this memory optimization was originally published by -+ D. A. Bell, Comp J. 1 (1958), 75. */ + /* 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 }; + +@@ -268,13 +301,11 @@ static bool reverse; + 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. */ +@@ -712,6 +743,44 @@ reap_some (void) + update_proc (pid); + } + ++/* Function pointers. */ +static void -+sortlines (struct line *lines, size_t nlines, struct line *temp) -+{ -+ if (nlines == 2) -+ { -+ if (0 < compare (&lines[-1], &lines[-2])) -+ { -+ struct line tmp = lines[-1]; -+ lines[-1] = lines[-2]; -+ lines[-2] = tmp; -+ } -+ } -+ else -+ { -+ size_t nlo = nlines / 2; -+ size_t nhi = nlines - nlo; -+ struct line *lo = lines; -+ struct line *hi = lines - nlo; -+ struct line *sorted_lo = temp; -+ -+ sortlines (hi, nhi, temp); -+ if (1 < nlo) -+ sortlines_temp (lo, nlo, sorted_lo); -+ else -+ sorted_lo[-1] = lo[-1]; -+ -+ mergelines (lines, sorted_lo, nlo, hi, nhi); -+ } -+} -+ -+/* Like sortlines (LINES, NLINES, TEMP), except output into TEMP -+ rather than sorting in place. */ ++(*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 *); + -+static void -+sortlines_temp (struct line *lines, size_t nlines, struct line *temp) ++/* 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) +{ -+ if (nlines == 2) -+ { -+ /* Declare `swap' as int, not bool, to work around a bug -+ -+ in the IBM xlc 6.0.0.0 compiler in 64-bit mode. */ -+ int swap = (0 < compare (&lines[-1], &lines[-2])); -+ temp[-1] = lines[-1 - swap]; -+ temp[-2] = lines[-2 + swap]; -+ } -+ else -+ { -+ size_t nlo = nlines / 2; -+ size_t nhi = nlines - nlo; -+ struct line *lo = lines; -+ struct line *hi = lines - nlo; -+ struct line *sorted_hi = temp - nlo; -+ -+ sortlines_temp (hi, nhi, sorted_hi); -+ if (1 < nlo) -+ sortlines (lo, nlo, temp); -+ -+ mergelines (temp, lo, nlo, sorted_hi, nhi); -+ } -+} ++ size_t mblength; ++ wchar_t wc; ++ mbstate_t state; + -+/* Scan through FILES[NTEMPS .. NFILES-1] looking for a file that is -+ the same as OUTFILE. If found, merge the found instances (and perhaps -+ some other files) into a temporary file so that it can in turn be -+ merged into OUTFILE without destroying OUTFILE before it is completely -+ read. Return the new value of NFILES, which differs from the old if -+ some merging occurred. -+ -+ This test ensures that an otherwise-erroneous use like -+ "sort -m -o FILE ... FILE ..." copies FILE before writing to it. -+ It's not clear that POSIX requires this nicety. -+ Detect common error cases, but don't try to catch obscure cases like -+ "cat ... FILE ... | sort -m -o FILE" -+ where traditional "sort" doesn't copy the input and where -+ people should know that they're getting into trouble anyway. -+ Catching these obscure cases would slow down performance in -+ common cases. */ -+ -+static size_t -+avoid_trashing_input (struct sortfile *files, size_t ntemps, -+ size_t nfiles, char const *outfile) -+{ -+ size_t i; -+ bool got_outstat = false; -+ struct stat outstat; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ mblength = mbrtowc (&wc, str, len, &state); + -+ for (i = ntemps; i < nfiles; i++) ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) + { -+ bool is_stdin = STREQ (files[i].name, "-"); -+ bool same; -+ struct stat instat; -+ -+ if (outfile && STREQ (outfile, files[i].name) && !is_stdin) -+ same = true; -+ else -+ { -+ if (! got_outstat) -+ { -+ if ((outfile -+ ? stat (outfile, &outstat) -+ : fstat (STDOUT_FILENO, &outstat)) -+ != 0) -+ break; -+ got_outstat = true; -+ } -+ -+ same = (((is_stdin -+ ? fstat (STDIN_FILENO, &instat) -+ : stat (files[i].name, &instat)) -+ == 0) -+ && SAME_INODE (instat, outstat)); -+ } -+ -+ if (same) -+ { -+ FILE *tftp; -+ pid_t pid; -+ char *temp = create_temp (&tftp, &pid); -+ size_t num_merged = 0; -+ do -+ { -+ num_merged += mergefiles (&files[i], 0, nfiles - i, tftp, temp); -+ files[i].name = temp; -+ files[i].pid = pid; -+ -+ if (i + num_merged < nfiles) -+ memmove(&files[i + 1], &files[i + num_merged], -+ num_merged * sizeof *files); -+ ntemps += 1; -+ nfiles -= num_merged - 1;; -+ i += num_merged; -+ } -+ while (i < nfiles); -+ } ++ *length = 1; ++ return 0; + } + -+ return nfiles; ++ *length = (mblength < 1) ? 1 : mblength; ++ return iswblank (wc); +} ++#endif + -+/* Merge the input FILES. NTEMPS is the number of files at the -+ start of FILES that are temporary; it is zero at the top level. -+ NFILES is the total number of files. Put the output in -+ OUTPUT_FILE; a null OUTPUT_FILE stands for standard output. */ -+ + /* Clean up any remaining temporary files. */ + + static void +@@ -1093,7 +1162,7 @@ zaptemp (const char *name) + free (node); + } + +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + + static int + struct_month_cmp (const void *m1, const void *m2) +@@ -1108,7 +1177,7 @@ struct_month_cmp (const void *m1, const + /* Initialize the character class tables. */ + + static void +-inittables (void) ++inittables_uni (void) + { + size_t i; + +@@ -1120,7 +1189,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) + { +@@ -1202,6 +1271,64 @@ specify_nmerge (int oi, char c, char con + xstrtol_fatal (e, oi, c, long_options, s); + } + ++#if HAVE_MBRTOWC +static void -+merge (struct sortfile *files, size_t ntemps, size_t nfiles, -+ char const *output_file) ++inittables_mb (void) +{ -+ while (nmerge < nfiles) -+ { -+ /* Number of input files processed so far. */ -+ size_t in; -+ -+ /* Number of output files generated so far. */ -+ size_t out; -+ -+ /* nfiles % NMERGE; this counts input files that are left over -+ after all full-sized merges have been done. */ -+ size_t remainder; -+ -+ /* Number of easily-available slots at the next loop iteration. */ -+ size_t cheap_slots; -+ -+ /* Do as many NMERGE-size merges as possible. In the case that -+ nmerge is bogus, increment by the maximum number of file -+ descriptors allowed. */ -+ for (out = in = 0; nmerge <= nfiles - in; out++) -+ { -+ FILE *tfp; -+ pid_t pid; -+ char *temp = create_temp (&tfp, &pid); -+ size_t num_merged = mergefiles (&files[in], MIN (ntemps, nmerge), -+ nmerge, tfp, temp); -+ ntemps -= MIN (ntemps, num_merged); -+ files[out].name = temp; -+ files[out].pid = pid; -+ in += num_merged; -+ } -+ -+ remainder = nfiles - in; -+ cheap_slots = nmerge - out % nmerge; -+ -+ if (cheap_slots < remainder) -+ { -+ /* So many files remain that they can't all be put into the last -+ NMERGE-sized output window. Do one more merge. Merge as few -+ files as possible, to avoid needless I/O. */ -+ size_t nshortmerge = remainder - cheap_slots + 1; -+ FILE *tfp; -+ pid_t pid; -+ char *temp = create_temp (&tfp, &pid); -+ size_t num_merged = mergefiles (&files[in], MIN (ntemps, nshortmerge), -+ nshortmerge, tfp, temp); -+ ntemps -= MIN (ntemps, num_merged); -+ files[out].name = temp; -+ files[out++].pid = pid; -+ in += num_merged; -+ } -+ -+ /* Put the remaining input files into the last NMERGE-sized output -+ window, so they will be merged in the next pass. */ -+ memmove(&files[out], &files[in], (nfiles - in) * sizeof *files); -+ ntemps += out; -+ nfiles -= in - out; -+ } -+ -+ nfiles = avoid_trashing_input (files, ntemps, nfiles, output_file); -+ -+ /* We aren't guaranteed that this final mergefiles will work, therefore we -+ try to merge into the output, and then merge as much as we can into a -+ temp file if we can't. Repeat. */ ++ 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 (;;) ++ for (i = 0; i < MONTHS_PER_YEAR; i++) + { -+ /* Merge directly into the output file if possible. */ -+ FILE **fps; -+ size_t nopened = open_input_files (files, nfiles, &fps); ++ 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; + -+ if (nopened == nfiles) -+ { -+ FILE *ofp = stream_open (output_file, "w"); -+ if (ofp) -+ { -+ mergefps (files, ntemps, nfiles, ofp, output_file, fps); -+ break; -+ } -+ if (errno != EMFILE || nopened <= 2) -+ die (_("open failed"), output_file); -+ } -+ else if (nopened <= 2) -+ die (_("open failed"), files[nopened].name); -+ -+ /* We ran out of file descriptors. Close one of the input -+ files, to gain a file descriptor. Then create a temporary -+ file with our spare file descriptor. Retry if that failed -+ (e.g., some other process could open a file between the time -+ we closed and tried to create). */ -+ FILE *tfp; -+ pid_t pid; -+ char *temp; -+ do ++ memset (&state_mb, '\0', sizeof (mbstate_t)); ++ memset (&state_wc, '\0', sizeof (mbstate_t)); ++ ++ for (j = 0; j < s_len;) + { -+ nopened--; -+ xfclose (fps[nopened], files[nopened].name); -+ temp = maybe_create_temp (&tfp, &pid, ! (nopened <= 2)); ++ if (!ismbblank (s + j, s_len - j, &mblength)) ++ break; ++ j += mblength; + } -+ while (!temp); -+ -+ /* Merge into the newly allocated temporary. */ -+ mergefps (&files[0], MIN (ntemps, nopened), nopened, tfp, temp, fps); -+ ntemps -= MIN (ntemps, nopened); -+ files[0].name = temp; -+ files[0].pid = pid; -+ -+ memmove (&files[1], &files[nopened], (nfiles - nopened) * sizeof *files); -+ ntemps++; -+ nfiles -= nopened - 1; -+ } -+} -+ -+/* Sort NFILES FILES onto OUTPUT_FILE. */ -+ -+static void -+sort (char * const *files, size_t nfiles, char const *output_file) -+{ -+ struct buffer buf; -+ size_t ntemps = 0; -+ bool output_file_created = false; -+ -+ buf.alloc = 0; + -+ while (nfiles) -+ { -+ char const *temp_output; -+ char const *file = *files; -+ FILE *fp = xfopen (file, "r"); -+ FILE *tfp; -+ size_t bytes_per_line = (2 * sizeof (struct line) -+ - sizeof (struct line) / 2); -+ -+ if (! buf.alloc) -+ initbuf (&buf, bytes_per_line, -+ sort_buffer_size (&fp, 1, files, nfiles, bytes_per_line)); -+ buf.eof = false; -+ files++; -+ nfiles--; -+ -+ while (fillbuf (&buf, fp, file)) ++ for (k = 0; j < s_len;) + { -+ struct line *line; -+ struct line *linebase; -+ -+ if (buf.eof && nfiles -+ && (bytes_per_line + 1 -+ < (buf.alloc - buf.used - bytes_per_line * buf.nlines))) -+ { -+ /* End of file, but there is more input and buffer room. -+ Concatenate the next input file; this is faster in -+ the usual case. */ -+ buf.left = buf.used; -+ break; -+ } ++ mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb); ++ assert (mblength != (size_t)-1 && mblength != (size_t)-2); ++ if (mblength == 0) ++ break; + -+ line = buffer_linelim (&buf); -+ linebase = line - buf.nlines; -+ if (1 < buf.nlines) -+ sortlines (line, buf.nlines, linebase); -+ if (buf.eof && !nfiles && !ntemps && !buf.left) ++ pwc = towupper (wc); ++ if (pwc == wc) + { -+ xfclose (fp, file); -+ tfp = xfopen (output_file, "w"); -+ temp_output = output_file; -+ output_file_created = true; ++ memcpy (mbc, s + j, mblength); ++ j += mblength; + } + else + { -+ ++ntemps; -+ temp_output = create_temp (&tfp, NULL); -+ } -+ -+ do -+ { -+ line--; -+ write_bytes (line->text, line->length, tfp, temp_output); -+ if (unique) -+ while (linebase < line && compare (line, line - 1) == 0) -+ line--; ++ j += mblength; ++ mblength = wcrtomb (mbc, pwc, &state_wc); ++ assert (mblength != (size_t)0 && mblength != (size_t)-1); + } -+ while (linebase < line); -+ -+ xfclose (tfp, temp_output); -+ -+ /* Free up some resources every once in a while. */ -+ if (MAX_PROCS_BEFORE_REAP < nprocs) -+ reap_some (); + -+ if (output_file_created) -+ goto finish; ++ for (l = 0; l < mblength; l++) ++ name[k++] = mbc[l]; + } -+ xfclose (fp, file); ++ name[k] = '\0'; + } ++ qsort ((void *) monthtab, MONTHS_PER_YEAR, ++ sizeof (struct month), struct_month_cmp); ++} ++#endif + -+ finish: -+ free (buf.buf); + /* Specify the amount of main memory to use when sorting. */ + static void + specify_sort_size (int oi, char c, char const *s) +@@ -1412,7 +1539,7 @@ buffer_linelim (struct buffer const *buf + 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; +@@ -1421,10 +1548,10 @@ begfield (const struct line *line, const + /* 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; +@@ -1450,11 +1577,70 @@ begfield (const struct line *line, const + 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; + -+ if (! output_file_created) -+ { -+ size_t i; -+ struct tempnode *node = temphead; -+ struct sortfile *tempfiles = xnmalloc (ntemps, sizeof *tempfiles); -+ for (i = 0; node; i++) -+ { -+ tempfiles[i].name = node->name; -+ tempfiles[i].pid = node->pid; -+ node = node->next; -+ } -+ merge (tempfiles, ntemps, ntemps, output_file); -+ free (tempfiles); -+ } -+} ++ memset (&state, '\0', sizeof(mbstate_t)); + -+/* Insert a malloc'd copy of key KEY_ARG at the end of the key list. */ ++ 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; ++ } + -+static void -+insertkey (struct keyfield *key_arg) -+{ -+ struct keyfield **p; -+ struct keyfield *key = xmemdup (key_arg, sizeof *key); ++ if (key->skipsblanks) ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; + -+ for (p = &keylist; *p; p = &(*p)->next) -+ continue; -+ *p = key; -+ key->next = NULL; -+} ++ for (i = 0; i < schar; i++) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); + -+/* Report a bad field specification SPEC, with extra info MSGID. */ ++ if (ptr + mblength > lim) ++ break; ++ else ++ ptr += mblength; ++ } + -+static void badfieldspec (char const *, char const *) -+ ATTRIBUTE_NORETURN; -+static void -+badfieldspec (char const *spec, char const *msgid) -+{ -+ error (SORT_FAILURE, 0, _("%s: invalid field specification %s"), -+ _(msgid), quote (spec)); -+ abort (); ++ return ptr; +} ++#endif + -+/* Report incompatible options. */ -+ -+static void incompatible_options (char const *) ATTRIBUTE_NORETURN; -+static void -+incompatible_options (char const *opts) + /* 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; +@@ -1469,10 +1655,10 @@ limfield (const struct line *line, const + `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; +@@ -1518,10 +1704,10 @@ limfield (const struct line *line, const + */ + + /* 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; + } +@@ -1552,6 +1738,113 @@ limfield (const struct line *line, const + return ptr; + } + ++#if HAVE_MBRTOWC ++static char * ++limfield_mb (const struct line *line, const struct keyfield *key) +{ -+ error (SORT_FAILURE, 0, _("options `-%s' are incompatible"), opts); -+ abort (); -+} ++ 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; + -+/* Check compatibility of ordering options. */ ++ if (echar == 0) ++ eword++; /* skip all of end field. */ + -+static void -+check_ordering_compatibility (void) -+{ -+ struct keyfield const *key; ++ memset (&state, '\0', sizeof(mbstate_t)); + -+ for (key = keylist; key; key = key->next) -+ if ((1 < (key->random + key->numeric + key->general_numeric + key->month -+ + key->version + !!key->ignore + key->human_numeric)) -+ || (key->random && key->translate)) ++ 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--) + { -+ /* The following is too big, but guaranteed to be "big enough". */ -+ char opts[sizeof short_options]; -+ char *p = opts; -+ if (key->ignore == nondictionary) -+ *p++ = 'd'; -+ if (key->translate) -+ *p++ = 'f'; -+ if (key->general_numeric) -+ *p++ = 'g'; -+ if (key->human_numeric) -+ *p++ = 'h'; -+ if (key->ignore == nonprinting) -+ *p++ = 'i'; -+ if (key->month) -+ *p++ = 'M'; -+ if (key->numeric) -+ *p++ = 'n'; -+ if (key->version) -+ *p++ = 'V'; -+ if (key->random) -+ *p++ = 'R'; -+ *p = '\0'; -+ incompatible_options (opts); ++ 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; + } -+} -+ -+/* Parse the leading integer in STRING and store the resulting value -+ (which must fit into size_t) into *VAL. Return the address of the -+ suffix after the integer. If the value is too large, silently -+ substitute SIZE_MAX. If MSGID is NULL, return NULL after -+ failure; otherwise, report MSGID and exit on failure. */ + -+static char const * -+parse_field_count (char const *string, size_t *val, char const *msgid) -+{ -+ char *suffix; -+ uintmax_t n; + -+ switch (xstrtoumax (string, &suffix, 10, &n, "")) ++# ifdef POSIX_UNSPECIFIED ++ /* Make LIM point to the end of (one byte past) the current field. */ ++ if (tab_length) + { -+ case LONGINT_OK: -+ case LONGINT_INVALID_SUFFIX_CHAR: -+ *val = n; -+ if (*val == n) -+ break; -+ /* Fall through. */ -+ case LONGINT_OVERFLOW: -+ case LONGINT_OVERFLOW | LONGINT_INVALID_SUFFIX_CHAR: -+ *val = SIZE_MAX; -+ break; -+ -+ case LONGINT_INVALID: -+ if (msgid) -+ error (SORT_FAILURE, 0, _("%s: invalid count at start of %s"), -+ _(msgid), quote (string)); -+ return NULL; -+ } -+ -+ return suffix; -+} -+ -+/* Handle interrupts and hangups. */ -+ -+static void -+sighandler (int sig) -+{ -+ if (! SA_NOCLDSTOP) -+ signal (sig, SIG_IGN); -+ -+ cleanup (); -+ -+ signal (sig, SIG_DFL); -+ raise (sig); -+} ++ char *newlim, *p; + -+/* Set the ordering options for KEY specified in S. -+ Return the address of the first character in S that -+ is not a valid ordering option. -+ BLANKTYPE is the kind of blanks that 'b' should skip. */ ++ newlim = NULL; ++ for (p = ptr; p < lim;) ++ { ++ if (memcmp (p, tab, tab_length) == 0) ++ { ++ newlim = p; ++ break; ++ } + -+static char * -+set_ordering (const char *s, struct keyfield *key, enum blanktype blanktype) -+{ -+ while (*s) ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ p += mblength; ++ } ++ } ++ else + { -+ switch (*s) ++ char *newlim; ++ newlim = ptr; ++ ++ while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength)) ++ newlim += mblength; ++ if (ptr < lim) + { -+ case 'b': -+ if (blanktype == bl_start || blanktype == bl_both) -+ key->skipsblanks = true; -+ if (blanktype == bl_end || blanktype == bl_both) -+ key->skipeblanks = true; -+ break; -+ case 'd': -+ key->ignore = nondictionary; -+ break; -+ case 'f': -+ key->translate = fold_toupper; -+ break; -+ case 'g': -+ key->general_numeric = true; -+ break; -+ case 'h': -+ key->human_numeric = true; -+ break; -+ case 'i': -+ /* Option order should not matter, so don't let -i override -+ -d. -d implies -i, but -i does not imply -d. */ -+ if (! key->ignore) -+ key->ignore = nonprinting; -+ break; -+ case 'M': -+ key->month = true; -+ break; -+ case 'n': -+ key->numeric = true; -+ break; -+ case 'R': -+ key->random = true; -+ break; -+ case 'r': -+ key->reverse = true; -+ break; -+ case 'V': -+ key->version = true; -+ break; -+ default: -+ return (char *) s; ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; + } -+ ++s; ++ while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength)) ++ newlim += mblength; ++ lim = newlim; + } -+ return (char *) s; -+} -+ -+static struct keyfield * -+key_init (struct keyfield *key) -+{ -+ memset (key, 0, sizeof *key); -+ key->eword = SIZE_MAX; -+ key->si_present = -1; -+ return key; -+} -+ -+int -+main (int argc, char **argv) -+{ -+ struct keyfield *key; -+ struct keyfield key_buf; -+ struct keyfield gkey; -+ char const *s; -+ int c = 0; -+ char checkonly = 0; -+ bool mergeonly = false; -+ char *random_source = NULL; -+ bool need_random = false; -+ size_t nfiles = 0; -+ bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL); -+ bool obsolete_usage = (posix2_version () < 200112); -+ char **files; -+ char *files_from = NULL; -+ struct Tokens tok; -+ char const *outfile = NULL; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ initialize_exit_failure (SORT_FAILURE); -+ -+ hard_LC_COLLATE = hard_locale (LC_COLLATE); -+#if HAVE_NL_LANGINFO -+ hard_LC_TIME = hard_locale (LC_TIME); -+#endif ++# endif + -+ /* Get locale's representation of the decimal point. */ ++ if (echar != 0) + { -+ struct lconv const *locale = localeconv (); -+ -+ /* If the locale doesn't define a decimal point, or if the decimal -+ point is multibyte, use the C locale's decimal point. FIXME: -+ add support for multibyte decimal points. */ -+ decimal_point = to_uchar (locale->decimal_point[0]); -+ if (! decimal_point || locale->decimal_point[1]) -+ decimal_point = '.'; -+ -+ /* FIXME: add support for multibyte thousands separators. */ -+ thousands_sep = to_uchar (*locale->thousands_sep); -+ if (! thousands_sep || locale->thousands_sep[1]) -+ thousands_sep = -1; -+ } -+ -+ have_read_stdin = false; -+ inittables (); ++ /* 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; + -+ { -+ size_t i; -+ static int const sig[] = -+ { -+ /* The usual suspects. */ -+ SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM, -+#ifdef SIGPOLL -+ SIGPOLL, -+#endif -+#ifdef SIGPROF -+ SIGPROF, -+#endif -+#ifdef SIGVTALRM -+ SIGVTALRM, -+#endif -+#ifdef SIGXCPU -+ SIGXCPU, -+#endif -+#ifdef SIGXFSZ -+ SIGXFSZ, -+#endif -+ }; -+ enum { nsigs = ARRAY_CARDINALITY (sig) }; ++ memset (&state, '\0', sizeof(mbstate_t)); + -+#if SA_NOCLDSTOP -+ struct sigaction act; ++ /* 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); + -+ sigemptyset (&caught_signals); -+ for (i = 0; i < nsigs; i++) -+ { -+ sigaction (sig[i], NULL, &act); -+ if (act.sa_handler != SIG_IGN) -+ sigaddset (&caught_signals, sig[i]); ++ if (ptr + mblength > lim) ++ break; ++ else ++ ptr += mblength; + } -+ -+ act.sa_handler = sighandler; -+ act.sa_mask = caught_signals; -+ act.sa_flags = 0; -+ -+ for (i = 0; i < nsigs; i++) -+ if (sigismember (&caught_signals, sig[i])) -+ sigaction (sig[i], &act, NULL); -+#else -+ for (i = 0; i < nsigs; i++) -+ if (signal (sig[i], SIG_IGN) != SIG_IGN) -+ { -+ signal (sig[i], sighandler); -+ siginterrupt (sig[i], 1); -+ } -+#endif + } + -+ /* The signal mask is known, so it is safe to invoke exit_cleanup. */ -+ atexit (exit_cleanup); -+ -+ gkey.sword = gkey.eword = SIZE_MAX; -+ gkey.ignore = NULL; -+ gkey.translate = NULL; -+ gkey.numeric = gkey.general_numeric = gkey.human_numeric = false; -+ gkey.si_present = -1; -+ gkey.random = gkey.version = false; -+ gkey.month = gkey.reverse = false; -+ gkey.skipsblanks = gkey.skipeblanks = false; -+ -+ files = xnmalloc (argc, sizeof *files); ++ return ptr; ++} ++#endif + -+ for (;;) -+ { -+ /* Parse an operand as a file after "--" was seen; or if -+ pedantic and a file was seen, unless the POSIX version -+ predates 1003.1-2001 and -c was not seen and the operand is -+ "-o FILE" or "-oFILE". */ -+ int oi = -1; -+ -+ if (c == -1 -+ || (posixly_correct && nfiles != 0 -+ && ! (obsolete_usage -+ && ! checkonly -+ && optind != argc -+ && argv[optind][0] == '-' && argv[optind][1] == 'o' -+ && (argv[optind][2] || optind + 1 != argc))) -+ || ((c = getopt_long (argc, argv, short_options, -+ long_options, &oi)) -+ == -1)) -+ { -+ if (argc <= optind) -+ break; -+ files[nfiles++] = argv[optind++]; -+ } -+ else switch (c) -+ { -+ case 1: -+ key = NULL; -+ if (optarg[0] == '+') -+ { -+ bool minus_pos_usage = (optind != argc && argv[optind][0] == '-' -+ && ISDIGIT (argv[optind][1])); -+ obsolete_usage |= minus_pos_usage && !posixly_correct; -+ if (obsolete_usage) -+ { -+ /* Treat +POS1 [-POS2] as a key if possible; but silently -+ treat an operand as a file if it is not a valid +POS1. */ -+ key = key_init (&key_buf); -+ s = parse_field_count (optarg + 1, &key->sword, NULL); -+ if (s && *s == '.') -+ s = parse_field_count (s + 1, &key->schar, NULL); -+ if (! (key->sword || key->schar)) -+ key->sword = SIZE_MAX; -+ if (! s || *set_ordering (s, key, bl_start)) -+ key = NULL; -+ else -+ { -+ if (minus_pos_usage) + /* 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 +@@ -1634,8 +1927,24 @@ fillbuf (struct buffer *buf, FILE *fp, c + else + { + if (key->skipsblanks) +- while (blanks[to_uchar (*line_start)]) +- line_start++; + { -+ char const *optarg1 = argv[optind++]; -+ s = parse_field_count (optarg1 + 1, &key->eword, -+ N_("invalid number after `-'")); -+ if (*s == '.') -+ s = parse_field_count (s + 1, &key->echar, -+ N_("invalid number after `.'")); -+ if (*set_ordering (s, key, bl_end)) -+ badfieldspec (optarg1, -+ N_("stray character in field spec")); ++#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++; + } -+ insertkey (key); -+ } -+ } -+ } -+ if (! key) -+ files[nfiles++] = optarg; -+ break; -+ -+ case SORT_OPTION: -+ c = XARGMATCH ("--sort", optarg, sort_args, sort_types); -+ /* Fall through. */ -+ case 'b': -+ case 'd': -+ case 'f': -+ case 'g': -+ case 'h': -+ case 'i': -+ case 'M': -+ case 'n': -+ case 'r': -+ case 'R': -+ case 'V': -+ { -+ char str[2]; -+ str[0] = c; -+ str[1] = '\0'; -+ set_ordering (str, &gkey, bl_both); -+ } -+ break; + line->keybeg = line_start; + } + } +@@ -1673,7 +1982,7 @@ fillbuf (struct buffer *buf, FILE *fp, c + 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++; +@@ -1782,6 +2091,25 @@ human_numcompare (const char *a, const c + : 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; + -+ case CHECK_OPTION: -+ c = (optarg -+ ? XARGMATCH ("--check", optarg, check_args, check_types) -+ : 'c'); -+ /* Fall through. */ -+ case 'c': -+ case 'C': -+ if (checkonly && checkonly != c) -+ incompatible_options ("cC"); -+ checkonly = c; -+ break; ++ return strnumcmp (a, b, decimal_point, thousands_sep); ++} ++#endif /* HAV_EMBRTOWC */ + -+ case COMPRESS_PROGRAM_OPTION: -+ if (compress_program && !STREQ (compress_program, optarg)) -+ error (SORT_FAILURE, 0, _("multiple compress programs specified")); -+ compress_program = optarg; -+ break; + static int + general_numcompare (const char *sa, const char *sb) + { +@@ -1815,7 +2143,7 @@ general_numcompare (const char *sa, cons + 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; +@@ -1996,11 +2324,79 @@ compare_version (char *restrict texta, s + 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; + -+ case FILES0_FROM_OPTION: -+ files_from = optarg; -+ break; ++ while (len > 0 && ismbblank (s, len, &mblength)) ++ { ++ s += mblength; ++ len -= mblength; ++ } + -+ case 'k': -+ key = key_init (&key_buf); ++ if (len == 0) ++ return 0; + -+ /* Get POS1. */ -+ s = parse_field_count (optarg, &key->sword, -+ N_("invalid number at field start")); -+ if (! key->sword--) -+ { -+ /* Provoke with `sort -k0' */ -+ badfieldspec (optarg, N_("field number is zero")); -+ } -+ if (*s == '.') -+ { -+ s = parse_field_count (s + 1, &key->schar, -+ N_("invalid number after `.'")); -+ if (! key->schar--) -+ { -+ /* Provoke with `sort -k1.0' */ -+ badfieldspec (optarg, N_("character offset is zero")); -+ } -+ } -+ if (! (key->sword || key->schar)) -+ key->sword = SIZE_MAX; -+ s = set_ordering (s, key, bl_start); -+ if (*s != ',') -+ { -+ key->eword = SIZE_MAX; -+ key->echar = 0; -+ } -+ else -+ { -+ /* Get POS2. */ -+ s = parse_field_count (s + 1, &key->eword, -+ N_("invalid number after `,'")); -+ if (! key->eword--) -+ { -+ /* Provoke with `sort -k1,0' */ -+ badfieldspec (optarg, N_("field number is zero")); -+ } -+ if (*s == '.') -+ { -+ s = parse_field_count (s + 1, &key->echar, -+ N_("invalid number after `.'")); -+ } -+ s = set_ordering (s, key, bl_end); -+ } -+ if (*s) -+ badfieldspec (optarg, N_("stray character in field spec")); -+ insertkey (key); -+ break; ++ month = (char *) alloca (len + 1); + -+ case 'm': -+ mergeonly = true; -+ break; ++ 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)); + -+ case NMERGE_OPTION: -+ specify_nmerge (oi, c, optarg); -+ break; ++ wclength = mbsrtowcs (month_wcs, pp, len + 1, &state); ++ assert (wclength != (size_t)-1 && *pp == NULL); + -+ case 'o': -+ if (outfile && !STREQ (outfile, optarg)) -+ error (SORT_FAILURE, 0, _("multiple output files specified")); -+ outfile = optarg; ++ for (i = 0; i < wclength; i++) ++ { ++ month_wcs[i] = towupper(month_wcs[i]); ++ if (iswblank (month_wcs[i])) ++ { ++ month_wcs[i] = L'\0'; + break; ++ } ++ } + -+ case RANDOM_SOURCE_OPTION: -+ if (random_source && !STREQ (random_source, optarg)) -+ error (SORT_FAILURE, 0, _("multiple random sources specified")); -+ random_source = optarg; -+ break; ++ wpp = (const wchar_t **)&month_wcs; + -+ case 's': -+ stable = true; -+ break; ++ mblength = wcsrtombs (month, wpp, len + 1, &state); ++ assert (mblength != (-1) && *wpp == NULL); + -+ case 'S': -+ specify_sort_size (oi, c, optarg); -+ break; ++ do ++ { ++ int ix = (lo + hi) / 2; + -+ case 't': -+ { -+ char newtab = optarg[0]; -+ if (! newtab) -+ error (SORT_FAILURE, 0, _("empty tab")); -+ if (optarg[1]) -+ { -+ if (STREQ (optarg, "\\0")) -+ newtab = '\0'; -+ else -+ { -+ /* Provoke with `sort -txx'. Complain about -+ "multi-character tab" instead of "multibyte tab", so -+ that the diagnostic's wording does not need to be -+ changed once multibyte characters are supported. */ -+ error (SORT_FAILURE, 0, _("multi-character tab %s"), -+ quote (optarg)); -+ } -+ } -+ if (tab != TAB_DEFAULT && tab != newtab) -+ error (SORT_FAILURE, 0, _("incompatible tabs")); -+ tab = newtab; -+ } -+ break; ++ if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0) ++ hi = ix; ++ else ++ lo = ix; ++ } ++ while (hi - lo > 1); + -+ case 'T': -+ add_temp_dir (optarg); -+ break; ++ result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name)) ++ ? monthtab[lo].val : 0); + -+ case 'u': -+ unique = true; -+ break; ++ return result; ++} ++#endif + -+ case 'y': -+ /* Accept and ignore e.g. -y0 for compatibility with Solaris 2.x -+ through Solaris 7. It is also accepted by many non-Solaris -+ "sort" implementations, e.g., AIX 5.2, HP-UX 11i v2, IRIX 6.5. -+ -y is marked as obsolete starting with Solaris 8 (1999), but is -+ still accepted as of Solaris 10 prerelease (2004). -+ -+ Solaris 2.5.1 "sort -y 100" reads the input file "100", but -+ emulate Solaris 8 and 9 "sort -y 100" which ignores the "100", -+ and which in general ignores the argument after "-y" if it -+ consists entirely of digits (it can even be empty). */ -+ if (optarg == argv[optind - 1]) -+ { -+ char const *p; -+ for (p = optarg; ISDIGIT (*p); p++) -+ continue; -+ optind -= (*p != '\0'); -+ } -+ break; + /* 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 *key = keylist; + +@@ -2180,6 +2576,179 @@ keycompare (const struct line *a, const + return key->reverse ? -diff : diff; + } + ++#if HAVE_MBRTOWC ++static int ++keycompare_mb (const struct line *a, const struct line *b) ++{ ++ struct keyfield *key = keylist; + -+ case 'z': -+ eolchar = 0; -+ break; ++ /* 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; + -+ case_GETOPT_HELP_CHAR; ++ size_t mblength_a, mblength_b; ++ wchar_t wc_a, wc_b; ++ mbstate_t state_a, state_b; + -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); ++ int diff; + -+ default: -+ usage (SORT_FAILURE); -+ } -+ } ++ memset (&state_a, '\0', sizeof(mbstate_t)); ++ memset (&state_b, '\0', sizeof(mbstate_t)); + -+ if (files_from) ++ for (;;) + { -+ FILE *stream; ++ char const *translate = 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; + -+ /* When using --files0-from=F, you may not specify any files -+ on the command-line. */ -+ if (nfiles) ++ /* Actually compare the fields. */ ++ if (key->random) ++ diff = compare_random (texta, lena, textb, lenb); ++ else if (key->numeric | key->general_numeric | key->human_numeric) + { -+ error (0, 0, _("extra operand %s"), quote (files[0])); -+ fprintf (stderr, "%s\n", -+ _("file operands cannot be combined with --files0-from")); -+ usage (SORT_FAILURE); -+ } ++ char savea = *lima, saveb = *limb; + -+ if (STREQ (files_from, "-")) -+ stream = stdin; ++ *lima = *limb = '\0'; ++ diff = (key->numeric ? numcompare (texta, textb) ++ : key->general_numeric ? general_numcompare (texta, textb) ++ : human_numcompare (texta, textb, key)); ++ *lima = savea, *limb = saveb; ++ } ++ else if (key->version) ++ diff = compare_version (texta, lena, textb, lenb); ++ else if (key->month) ++ diff = getmonth (texta, lena) - getmonth (textb, lenb); + else + { -+ stream = fopen (files_from, "r"); -+ if (stream == NULL) -+ error (SORT_FAILURE, errno, _("cannot open %s for reading"), -+ quote (files_from)); ++ 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); + } + -+ readtokens0_init (&tok); ++ if (diff) ++ goto not_equal; + -+ if (! readtokens0 (stream, &tok) || fclose (stream) != 0) -+ error (SORT_FAILURE, 0, _("cannot read file names from %s"), -+ quote (files_from)); ++ key = key->next; ++ if (! key) ++ break; + -+ if (tok.n_tok) -+ { -+ size_t i; -+ free (files); -+ files = tok.tok; -+ nfiles = tok.n_tok; -+ for (i = 0; i < nfiles; i++) -+ { -+ if (STREQ (files[i], "-")) -+ error (SORT_FAILURE, 0, _("when reading file names from stdin, " -+ "no file name of %s allowed"), -+ quote (files[i])); -+ else if (files[i][0] == '\0') -+ { -+ /* Using the standard `filename:line-number:' prefix here is -+ not totally appropriate, since NUL is the separator, not NL, -+ but it might be better than nothing. */ -+ unsigned long int file_number = i + 1; -+ error (SORT_FAILURE, 0, -+ _("%s:%lu: invalid zero-length file name"), -+ quotearg_colon (files_from), file_number); -+ } -+ } -+ } ++ /* Find the beginning and limit of the next field. */ ++ if (key->eword != -1) ++ lima = limfield (a, key), limb = limfield (b, key); + else -+ error (SORT_FAILURE, 0, _("no input from %s"), -+ quote (files_from)); -+ } ++ lima = a->text + a->length - 1, limb = b->text + b->length - 1; + -+ /* Inheritance of global options to individual keys. */ -+ for (key = keylist; key; key = key->next) -+ { -+ if (! (key->ignore -+ || key->translate -+ || (key->skipsblanks -+ || key->reverse -+ || key->skipeblanks -+ || key->month -+ || key->numeric -+ || key->version -+ || key->general_numeric -+ || key->human_numeric -+ || key->random))) ++ if (key->sword != -1) ++ texta = begfield (a, key), textb = begfield (b, key); ++ else + { -+ key->ignore = gkey.ignore; -+ key->translate = gkey.translate; -+ key->skipsblanks = gkey.skipsblanks; -+ key->skipeblanks = gkey.skipeblanks; -+ key->month = gkey.month; -+ key->numeric = gkey.numeric; -+ key->general_numeric = gkey.general_numeric; -+ key->human_numeric = gkey.human_numeric; -+ key->random = gkey.random; -+ key->reverse = gkey.reverse; -+ key->version = gkey.version; ++ 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; ++ } + } -+ -+ need_random |= key->random; -+ } -+ -+ if (!keylist && (gkey.ignore -+ || gkey.translate -+ || (gkey.skipsblanks -+ || gkey.skipeblanks -+ || gkey.month -+ || gkey.numeric -+ || gkey.general_numeric -+ || gkey.human_numeric -+ || gkey.random -+ || gkey.version))) -+ { -+ insertkey (&gkey); -+ need_random |= gkey.random; -+ } -+ -+ check_ordering_compatibility (); -+ -+ reverse = gkey.reverse; -+ -+ if (need_random) -+ { -+ randread_source = randread_new (random_source, MD5_DIGEST_SIZE); -+ if (! randread_source) -+ die (_("open failed"), random_source); -+ } -+ -+ if (temp_dir_count == 0) -+ { -+ char const *tmp_dir = getenv ("TMPDIR"); -+ add_temp_dir (tmp_dir ? tmp_dir : DEFAULT_TMPDIR); + } + -+ if (nfiles == 0) -+ { -+ static char *minus = (char *) "-"; -+ nfiles = 1; -+ free (files); -+ files = − -+ } ++ return 0; + -+ /* Need to re-check that we meet the minimum requirement for memory -+ usage with the final value for NMERGE. */ -+ if (0 < sort_size) -+ sort_size = MAX (sort_size, MIN_SORT_SIZE); ++greater: ++ diff = 1; ++not_equal: ++ return key->reverse ? -diff : diff; ++} ++#endif + -+ if (checkonly) + /* Compare two lines A and B, returning negative, zero, or positive + depending on whether A compares less than, equal to, or greater than B. */ + +@@ -3178,7 +3747,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 + +@@ -3199,6 +3768,27 @@ main (int argc, char **argv) + thousands_sep = -1; + } + ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) + { -+ if (nfiles > 1) -+ error (SORT_FAILURE, 0, _("extra operand %s not allowed with -%c"), -+ quote (files[1]), checkonly); -+ -+ if (outfile) -+ { -+ static char opts[] = {0, 'o', 0}; -+ opts[0] = checkonly; -+ incompatible_options (opts); -+ } -+ -+ /* POSIX requires that sort return 1 IFF invoked with -c or -C and the -+ input is not properly sorted. */ -+ exit (check (files[0], checkonly) ? EXIT_SUCCESS : SORT_OUT_OF_ORDER); ++ inittables = inittables_mb; ++ begfield = begfield_mb; ++ limfield = limfield_mb; ++ getmonth = getmonth_mb; ++ keycompare = keycompare_mb; ++ numcompare = numcompare_mb; + } -+ -+ if (mergeonly) ++ else ++#endif + { -+ struct sortfile *sortfiles = xcalloc (nfiles, sizeof *sortfiles); -+ size_t i; -+ -+ for (i = 0; i < nfiles; ++i) -+ sortfiles[i].name = files[i]; -+ -+ merge (sortfiles, 0, nfiles, outfile); -+ IF_LINT (free (sortfiles)); ++ inittables = inittables_uni; ++ begfield = begfield_uni; ++ limfield = limfield_uni; ++ getmonth = getmonth_uni; ++ keycompare = keycompare_uni; ++ numcompare = numcompare_uni; + } -+ else -+ sort (files, nfiles, outfile); + -+ if (have_read_stdin && fclose (stdin) == EOF) -+ die (_("close failed"), "-"); + have_read_stdin = false; + inittables (); + +@@ -3459,13 +4049,35 @@ 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; ++ size_t i; + -+ exit (EXIT_SUCCESS); -+} ++ 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 +@@ -3476,9 +4088,12 @@ 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 -urNp coreutils-8.0-orig/src/unexpand.c coreutils-8.0/src/unexpand.c --- coreutils-8.0-orig/src/unexpand.c 2009-09-29 15:27:54.000000000 +0200 +++ coreutils-8.0/src/unexpand.c 2009-10-07 10:07:16.000000000 +0200 @@ -13130,600 +3478,64 @@ diff -urNp coreutils-8.0-orig/src/unexpand.c coreutils-8.0/src/unexpand.c + } + else if (mblength == 0) + { -+ if (convert && convert_entire_line == 0) -+ convert = 0; -+ mblength = 1; -+ putchar ('\0'); -+ } -+ else -+ { -+ if (convert) -+ { -+ if (wc == L'\b') -+ { -+ if (column > 0) -+ --column; -+ } -+ else -+ { -+ int width; /* The width of WC. */ -+ -+ width = wcwidth (wc); -+ column += (width > 0) ? width : 0; -+ if (convert_entire_line == 0) -+ convert = 0; -+ } -+ } -+ -+ if (wc == L'\n') -+ { -+ tab_index = print_tab_index = 0; -+ column = pending = 0; -+ convert = 1; -+ } -+ fwrite (bufpos, sizeof(char), mblength, stdout); -+ } -+ } -+ buflen -= mblength; -+ bufpos += mblength; -+ } -+} -+#endif -+ -+ - void - usage (int status) - { -@@ -523,7 +742,12 @@ main (int argc, char **argv) - - file_list = (optind < argc ? &argv[optind] : stdin_argv); - -- unexpand (); -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1) -+ unexpand_multibyte (); -+ else -+#endif -+ unexpand (); - - if (have_read_stdin && fclose (stdin) != 0) - error (EXIT_FAILURE, errno, "-"); -diff -urNp coreutils-8.0-orig/src/unexpand.c.orig coreutils-8.0/src/unexpand.c.orig ---- coreutils-8.0-orig/src/unexpand.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/unexpand.c.orig 2009-09-29 15:27:54.000000000 +0200 -@@ -0,0 +1,532 @@ -+/* unexpand - convert blanks to tabs -+ Copyright (C) 89, 91, 1995-2006, 2008-2009 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 . */ -+ -+/* By default, convert only maximal strings of initial blanks and tabs -+ into tabs. -+ Preserves backspace characters in the output; they decrement the -+ column count for tab calculations. -+ The default action is equivalent to -8. -+ -+ Options: -+ --tabs=tab1[,tab2[,...]] -+ -t tab1[,tab2[,...]] -+ -tab1[,tab2[,...]] If only one tab stop is given, set the tabs tab1 -+ columns apart instead of the default 8. Otherwise, -+ set the tabs at columns tab1, tab2, etc. (numbered from -+ 0); preserve any blanks beyond the tab stops given. -+ --all -+ -a Use tabs wherever they would replace 2 or more blanks, -+ not just at the beginnings of lines. -+ -+ David MacKenzie */ -+ -+#include -+ -+#include -+#include -+#include -+#include "system.h" -+#include "error.h" -+#include "quote.h" -+#include "xstrndup.h" -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "unexpand" -+ -+#define AUTHORS proper_name ("David MacKenzie") -+ -+/* If true, convert blanks even after nonblank characters have been -+ read on the line. */ -+static bool convert_entire_line; -+ -+/* If nonzero, the size of all tab stops. If zero, use `tab_list' instead. */ -+static size_t tab_size; -+ -+/* The maximum distance between tab stops. */ -+static size_t max_column_width; -+ -+/* Array of the explicit column numbers of the tab stops; -+ after `tab_list' is exhausted, the rest of the line is printed -+ unchanged. The first column is column 0. */ -+static uintmax_t *tab_list; -+ -+/* The number of allocated entries in `tab_list'. */ -+static size_t n_tabs_allocated; -+ -+/* The index of the first invalid element of `tab_list', -+ where the next element can be added. */ -+static size_t first_free_tab; -+ -+/* Null-terminated array of input filenames. */ -+static char **file_list; -+ -+/* Default for `file_list' if no files are given on the command line. */ -+static char *stdin_argv[] = -+{ -+ (char *) "-", NULL -+}; -+ -+/* True if we have ever read standard input. */ -+static bool have_read_stdin; -+ -+/* The desired exit status. */ -+static int exit_status; -+ -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ CONVERT_FIRST_ONLY_OPTION = CHAR_MAX + 1 -+}; -+ -+static struct option const longopts[] = -+{ -+ {"tabs", required_argument, NULL, 't'}, -+ {"all", no_argument, NULL, 'a'}, -+ {"first-only", no_argument, NULL, CONVERT_FIRST_ONLY_OPTION}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [FILE]...\n\ -+"), -+ program_name); -+ fputs (_("\ -+Convert blanks in each FILE to tabs, writing to standard output.\n\ -+With no FILE, or when FILE is -, read standard input.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ -a, --all convert all blanks, instead of just initial blanks\n\ -+ --first-only convert only leading sequences of blanks (overrides -a)\n\ -+ -t, --tabs=N have tabs N characters apart instead of 8 (enables -a)\n\ -+ -t, --tabs=LIST use comma separated LIST of tab positions (enables -a)\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+/* Add tab stop TABVAL to the end of `tab_list'. */ -+ -+static void -+add_tab_stop (uintmax_t tabval) -+{ -+ uintmax_t prev_column = first_free_tab ? tab_list[first_free_tab - 1] : 0; -+ uintmax_t column_width = prev_column <= tabval ? tabval - prev_column : 0; -+ -+ if (first_free_tab == n_tabs_allocated) -+ tab_list = X2NREALLOC (tab_list, &n_tabs_allocated); -+ tab_list[first_free_tab++] = tabval; -+ -+ if (max_column_width < column_width) -+ { -+ if (SIZE_MAX < column_width) -+ error (EXIT_FAILURE, 0, _("tabs are too far apart")); -+ max_column_width = column_width; -+ } -+} -+ -+/* Add the comma or blank separated list of tab stops STOPS -+ to the list of tab stops. */ -+ -+static void -+parse_tab_stops (char const *stops) -+{ -+ bool have_tabval = false; -+ uintmax_t tabval IF_LINT (= 0); -+ char const *num_start IF_LINT (= NULL); -+ bool ok = true; -+ -+ for (; *stops; stops++) -+ { -+ if (*stops == ',' || isblank (to_uchar (*stops))) -+ { -+ if (have_tabval) -+ add_tab_stop (tabval); -+ have_tabval = false; -+ } -+ else if (ISDIGIT (*stops)) -+ { -+ if (!have_tabval) -+ { -+ tabval = 0; -+ have_tabval = true; -+ num_start = stops; -+ } -+ -+ /* Detect overflow. */ -+ if (!DECIMAL_DIGIT_ACCUMULATE (tabval, *stops - '0', uintmax_t)) -+ { -+ size_t len = strspn (num_start, "0123456789"); -+ char *bad_num = xstrndup (num_start, len); -+ error (0, 0, _("tab stop is too large %s"), quote (bad_num)); -+ free (bad_num); -+ ok = false; -+ stops = num_start + len - 1; -+ } -+ } -+ else -+ { -+ error (0, 0, _("tab size contains invalid character(s): %s"), -+ quote (stops)); -+ ok = false; -+ break; -+ } -+ } -+ -+ if (!ok) -+ exit (EXIT_FAILURE); -+ -+ if (have_tabval) -+ add_tab_stop (tabval); -+} -+ -+/* Check that the list of tab stops TABS, with ENTRIES entries, -+ contains only nonzero, ascending values. */ -+ -+static void -+validate_tab_stops (uintmax_t const *tabs, size_t entries) -+{ -+ uintmax_t prev_tab = 0; -+ size_t i; -+ -+ for (i = 0; i < entries; i++) -+ { -+ if (tabs[i] == 0) -+ error (EXIT_FAILURE, 0, _("tab size cannot be 0")); -+ if (tabs[i] <= prev_tab) -+ error (EXIT_FAILURE, 0, _("tab sizes must be ascending")); -+ prev_tab = tabs[i]; -+ } -+} -+ -+/* Close the old stream pointer FP if it is non-NULL, -+ and return a new one opened to read the next input file. -+ Open a filename of `-' as the standard input. -+ Return NULL if there are no more input files. */ -+ -+static FILE * -+next_file (FILE *fp) -+{ -+ static char *prev_file; -+ char *file; -+ -+ if (fp) -+ { -+ if (ferror (fp)) -+ { -+ error (0, errno, "%s", prev_file); -+ exit_status = EXIT_FAILURE; -+ } -+ if (STREQ (prev_file, "-")) -+ clearerr (fp); /* Also clear EOF. */ -+ else if (fclose (fp) != 0) -+ { -+ error (0, errno, "%s", prev_file); -+ exit_status = EXIT_FAILURE; -+ } -+ } -+ -+ while ((file = *file_list++) != NULL) -+ { -+ if (STREQ (file, "-")) -+ { -+ have_read_stdin = true; -+ prev_file = file; -+ return stdin; -+ } -+ fp = fopen (file, "r"); -+ if (fp) -+ { -+ prev_file = file; -+ return fp; -+ } -+ error (0, errno, "%s", file); -+ exit_status = EXIT_FAILURE; -+ } -+ return NULL; -+} -+ -+/* Change blanks to tabs, writing to stdout. -+ Read each file in `file_list', in order. */ -+ -+static void -+unexpand (void) -+{ -+ /* Input stream. */ -+ FILE *fp = next_file (NULL); -+ -+ /* 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; -+ -+ if (!fp) -+ return; -+ -+ /* 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 = xmalloc (max_column_width); -+ -+ for (;;) -+ { -+ /* Input character, or EOF. */ -+ int c; -+ -+ /* If true, perform translations. */ -+ bool convert = true; -+ -+ -+ /* The following variables have valid values only when CONVERT -+ is true: */ -+ -+ /* Column of next input character. */ -+ uintmax_t column = 0; -+ -+ /* Column the next input tab stop is on. */ -+ uintmax_t next_tab_column = 0; -+ -+ /* Index in TAB_LIST of next tab stop to examine. */ -+ size_t tab_index = 0; -+ -+ /* If true, the first pending blank came just before a tab stop. */ -+ bool one_blank_before_tab_stop = false; -+ -+ /* If true, the previous input character was a blank. This is -+ initially true, since initial strings of blanks are treated -+ as if the line was preceded by a blank. */ -+ bool prev_blank = true; -+ -+ /* Number of pending columns of blanks. */ -+ size_t pending = 0; -+ -+ -+ /* Convert a line of text. */ -+ -+ do -+ { -+ while ((c = getc (fp)) < 0 && (fp = next_file (fp))) -+ continue; -+ -+ if (convert) -+ { -+ bool blank = !! isblank (c); -+ -+ if (blank) -+ { -+ if (next_tab_column <= column) -+ { -+ if (tab_size) -+ next_tab_column = -+ column + (tab_size - column % tab_size); -+ else -+ for (;;) -+ if (tab_index == first_free_tab) -+ { -+ convert = false; -+ break; -+ } -+ else -+ { -+ uintmax_t tab = tab_list[tab_index++]; -+ if (column < tab) -+ { -+ next_tab_column = tab; -+ break; -+ } -+ } -+ } -+ -+ if (convert) -+ { -+ if (next_tab_column < column) -+ error (EXIT_FAILURE, 0, _("input line is too long")); -+ -+ if (c == '\t') -+ { -+ column = next_tab_column; -+ -+ /* Discard pending blanks, unless it was a single -+ blank just before the previous tab stop. */ -+ if (! (pending == 1 && one_blank_before_tab_stop)) -+ { -+ pending = 0; -+ one_blank_before_tab_stop = false; -+ } -+ } -+ else -+ { -+ column++; -+ -+ if (! (prev_blank && column == next_tab_column)) -+ { -+ /* It is not yet known whether the pending blanks -+ will be replaced by tabs. */ -+ if (column == next_tab_column) -+ one_blank_before_tab_stop = true; -+ pending_blank[pending++] = c; -+ prev_blank = true; -+ continue; -+ } -+ -+ /* Replace the pending blanks by a tab or two. */ -+ pending_blank[0] = c = '\t'; -+ pending = one_blank_before_tab_stop; -+ } -+ } -+ } -+ else if (c == '\b') -+ { -+ /* Go back one column, and force recalculation of the -+ next tab stop. */ -+ column -= !!column; -+ next_tab_column = column; -+ tab_index -= !!tab_index; -+ } -+ else -+ { -+ column++; -+ if (!column) -+ error (EXIT_FAILURE, 0, _("input line is too long")); -+ } -+ -+ if (pending) -+ { -+ if (fwrite (pending_blank, 1, pending, stdout) != pending) -+ error (EXIT_FAILURE, errno, _("write error")); -+ pending = 0; -+ one_blank_before_tab_stop = false; -+ } -+ -+ prev_blank = blank; -+ convert &= convert_entire_line || blank; -+ } ++ 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. */ + -+ if (c < 0) -+ { -+ free (pending_blank); -+ return; -+ } ++ width = wcwidth (wc); ++ column += (width > 0) ? width : 0; ++ if (convert_entire_line == 0) ++ convert = 0; ++ } ++ } + -+ if (putchar (c) < 0) -+ error (EXIT_FAILURE, errno, _("write error")); -+ } -+ while (c != '\n'); ++ 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 + -+int -+main (int argc, char **argv) -+{ -+ bool have_tabval = false; -+ uintmax_t tabval IF_LINT (= 0); -+ int c; -+ -+ /* If true, cancel the effect of any -a (explicit or implicit in -t), -+ so that only leading blanks will be considered. */ -+ bool convert_first_only = false; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdout); -+ -+ have_read_stdin = false; -+ exit_status = EXIT_SUCCESS; -+ convert_entire_line = false; -+ tab_list = NULL; -+ first_free_tab = 0; -+ -+ while ((c = getopt_long (argc, argv, ",0123456789at:", longopts, NULL)) -+ != -1) -+ { -+ switch (c) -+ { -+ case '?': -+ usage (EXIT_FAILURE); -+ case 'a': -+ convert_entire_line = true; -+ break; -+ case 't': -+ convert_entire_line = true; -+ parse_tab_stops (optarg); -+ break; -+ case CONVERT_FIRST_ONLY_OPTION: -+ convert_first_only = true; -+ break; -+ case ',': -+ if (have_tabval) -+ add_tab_stop (tabval); -+ have_tabval = false; -+ break; -+ case_GETOPT_HELP_CHAR; -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ default: -+ if (!have_tabval) -+ { -+ tabval = 0; -+ have_tabval = true; -+ } -+ if (!DECIMAL_DIGIT_ACCUMULATE (tabval, c - '0', uintmax_t)) -+ error (EXIT_FAILURE, 0, _("tab stop value is too large")); -+ break; -+ } -+ } -+ -+ if (convert_first_only) -+ convert_entire_line = false; -+ -+ if (have_tabval) -+ add_tab_stop (tabval); -+ -+ validate_tab_stops (tab_list, first_free_tab); + -+ if (first_free_tab == 0) -+ tab_size = max_column_width = 8; -+ else if (first_free_tab == 1) -+ tab_size = tab_list[0]; + void + usage (int status) + { +@@ -523,7 +742,12 @@ main (int argc, char **argv) + + file_list = (optind < argc ? &argv[optind] : stdin_argv); + +- unexpand (); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ unexpand_multibyte (); + else -+ tab_size = 0; -+ -+ file_list = (optind < argc ? &argv[optind] : stdin_argv); -+ -+ unexpand (); -+ -+ if (have_read_stdin && fclose (stdin) != 0) -+ error (EXIT_FAILURE, errno, "-"); -+ -+ exit (exit_status); -+} ++#endif ++ unexpand (); + + if (have_read_stdin && fclose (stdin) != 0) + error (EXIT_FAILURE, errno, "-"); diff -urNp coreutils-8.0-orig/src/uniq.c coreutils-8.0/src/uniq.c --- coreutils-8.0-orig/src/uniq.c 2009-09-23 10:25:44.000000000 +0200 +++ coreutils-8.0/src/uniq.c 2009-10-07 10:07:16.000000000 +0200 @@ -14093,575 +3905,6 @@ diff -urNp coreutils-8.0-orig/src/uniq.c coreutils-8.0/src/uniq.c skip_chars = 0; skip_fields = 0; check_chars = SIZE_MAX; -diff -urNp coreutils-8.0-orig/src/uniq.c.orig coreutils-8.0/src/uniq.c.orig ---- coreutils-8.0-orig/src/uniq.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/uniq.c.orig 2009-09-23 10:25:44.000000000 +0200 -@@ -0,0 +1,565 @@ -+/* uniq -- remove duplicate lines from a sorted file -+ Copyright (C) 86, 91, 1995-2009 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 . */ -+ -+/* Written by Richard M. Stallman and David MacKenzie. */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include "system.h" -+#include "argmatch.h" -+#include "linebuffer.h" -+#include "error.h" -+#include "hard-locale.h" -+#include "posixver.h" -+#include "quote.h" -+#include "xmemcoll.h" -+#include "xstrtol.h" -+#include "memcasecmp.h" -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "uniq" -+ -+#define AUTHORS \ -+ proper_name ("Richard M. Stallman"), \ -+ proper_name ("David MacKenzie") -+ -+#define SWAP_LINES(A, B) \ -+ do \ -+ { \ -+ struct linebuffer *_tmp; \ -+ _tmp = (A); \ -+ (A) = (B); \ -+ (B) = _tmp; \ -+ } \ -+ while (0) -+ -+/* True if the LC_COLLATE locale is hard. */ -+static bool hard_LC_COLLATE; -+ -+/* Number of fields to skip on each line when doing comparisons. */ -+static size_t skip_fields; -+ -+/* Number of chars to skip after skipping any fields. */ -+static size_t skip_chars; -+ -+/* Number of chars to compare. */ -+static size_t check_chars; -+ -+enum countmode -+{ -+ count_occurrences, /* -c Print count before output lines. */ -+ count_none /* Default. Do not print counts. */ -+}; -+ -+/* Whether and how to precede the output lines with a count of the number of -+ times they occurred in the input. */ -+static enum countmode countmode; -+ -+/* Which lines to output: unique lines, the first of a group of -+ repeated lines, and the second and subsequented of a group of -+ repeated lines. */ -+static bool output_unique; -+static bool output_first_repeated; -+static bool output_later_repeated; -+ -+/* If true, ignore case when comparing. */ -+static bool ignore_case; -+ -+enum delimit_method -+{ -+ /* No delimiters output. --all-repeated[=none] */ -+ DM_NONE, -+ -+ /* Delimiter precedes all groups. --all-repeated=prepend */ -+ DM_PREPEND, -+ -+ /* Delimit all groups. --all-repeated=separate */ -+ DM_SEPARATE -+}; -+ -+static char const *const delimit_method_string[] = -+{ -+ "none", "prepend", "separate", NULL -+}; -+ -+static enum delimit_method const delimit_method_map[] = -+{ -+ DM_NONE, DM_PREPEND, DM_SEPARATE -+}; -+ -+/* Select whether/how to delimit groups of duplicate lines. */ -+static enum delimit_method delimit_groups; -+ -+static struct option const longopts[] = -+{ -+ {"count", no_argument, NULL, 'c'}, -+ {"repeated", no_argument, NULL, 'd'}, -+ {"all-repeated", optional_argument, NULL, 'D'}, -+ {"ignore-case", no_argument, NULL, 'i'}, -+ {"unique", no_argument, NULL, 'u'}, -+ {"skip-fields", required_argument, NULL, 'f'}, -+ {"skip-chars", required_argument, NULL, 's'}, -+ {"check-chars", required_argument, NULL, 'w'}, -+ {"zero-terminated", no_argument, NULL, 'z'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ -+"), -+ program_name); -+ fputs (_("\ -+Filter adjacent matching lines from INPUT (or standard input),\n\ -+writing to OUTPUT (or standard output).\n\ -+\n\ -+With no options, matching lines are merged to the first occurrence.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ -c, --count prefix lines by the number of occurrences\n\ -+ -d, --repeated only print duplicate lines\n\ -+"), stdout); -+ fputs (_("\ -+ -D, --all-repeated[=delimit-method] print all duplicate lines\n\ -+ delimit-method={none(default),prepend,separate}\n\ -+ Delimiting is done with blank lines.\n\ -+ -f, --skip-fields=N avoid comparing the first N fields\n\ -+ -i, --ignore-case ignore differences in case when comparing\n\ -+ -s, --skip-chars=N avoid comparing the first N characters\n\ -+ -u, --unique only print unique lines\n\ -+ -z, --zero-terminated end lines with 0 byte, not newline\n\ -+"), stdout); -+ fputs (_("\ -+ -w, --check-chars=N compare no more than N characters in lines\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+A field is a run of blanks (usually spaces and/or TABs), then non-blank\n\ -+characters. Fields are skipped before chars.\n\ -+"), stdout); -+ fputs (_("\ -+\n\ -+Note: 'uniq' does not detect repeated lines unless they are adjacent.\n\ -+You may want to sort the input first, or use `sort -u' without `uniq'.\n\ -+Also, comparisons honor the rules specified by `LC_COLLATE'.\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+/* Convert OPT to size_t, reporting an error using MSGID if OPT is -+ invalid. Silently convert too-large values to SIZE_MAX. */ -+ -+static size_t -+size_opt (char const *opt, char const *msgid) -+{ -+ unsigned long int size; -+ verify (SIZE_MAX <= ULONG_MAX); -+ -+ switch (xstrtoul (opt, NULL, 10, &size, "")) -+ { -+ case LONGINT_OK: -+ case LONGINT_OVERFLOW: -+ break; -+ -+ default: -+ error (EXIT_FAILURE, 0, "%s: %s", opt, _(msgid)); -+ } -+ -+ return MIN (size, SIZE_MAX); -+} -+ -+/* Given a linebuffer LINE, -+ return a pointer to the beginning of the line's field to be compared. */ -+ -+static char * -+find_field (struct linebuffer const *line) -+{ -+ size_t count; -+ char const *lp = line->buffer; -+ size_t size = line->length - 1; -+ size_t i = 0; -+ -+ for (count = 0; count < skip_fields; count++) -+ { -+ while (i < size && isblank (to_uchar (lp[i]))) -+ i++; -+ while (i < size && !isblank (to_uchar (lp[i]))) -+ i++; -+ } -+ -+ for (count = 0; count < skip_chars && i < size; count++) -+ i++; -+ -+ return line->buffer + i; -+} -+ -+/* 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. -+ OLDLEN and NEWLEN are their lengths. */ -+ -+static bool -+different (char *old, char *new, size_t oldlen, size_t newlen) -+{ -+ if (check_chars < oldlen) -+ oldlen = check_chars; -+ if (check_chars < newlen) -+ newlen = check_chars; -+ -+ if (ignore_case) -+ { -+ /* FIXME: This should invoke strcoll somehow. */ -+ return oldlen != newlen || memcasecmp (old, new, oldlen); -+ } -+ else if (hard_LC_COLLATE) -+ return xmemcoll (old, oldlen, new, newlen) != 0; -+ else -+ return oldlen != newlen || memcmp (old, new, oldlen); -+} -+ -+/* Output the line in linebuffer LINE to standard output -+ provided that the switches say it should be output. -+ MATCH is true if the line matches the previous line. -+ If requested, print the number of times it occurred, as well; -+ LINECOUNT + 1 is the number of times that the line occurred. */ -+ -+static void -+writeline (struct linebuffer const *line, -+ bool match, uintmax_t linecount) -+{ -+ if (! (linecount == 0 ? output_unique -+ : !match ? output_first_repeated -+ : output_later_repeated)) -+ return; -+ -+ if (countmode == count_occurrences) -+ printf ("%7" PRIuMAX " ", linecount + 1); -+ -+ fwrite (line->buffer, sizeof (char), line->length, stdout); -+} -+ -+/* Process input file INFILE with output to OUTFILE. -+ If either is "-", use the standard I/O stream for it instead. */ -+ -+static void -+check_file (const char *infile, const char *outfile, char delimiter) -+{ -+ struct linebuffer lb1, lb2; -+ struct linebuffer *thisline, *prevline; -+ -+ if (! (STREQ (infile, "-") || freopen (infile, "r", stdin))) -+ error (EXIT_FAILURE, errno, "%s", infile); -+ if (! (STREQ (outfile, "-") || freopen (outfile, "w", stdout))) -+ error (EXIT_FAILURE, errno, "%s", outfile); -+ -+ thisline = &lb1; -+ prevline = &lb2; -+ -+ initbuffer (thisline); -+ initbuffer (prevline); -+ -+ /* The duplication in the following `if' and `else' blocks is an -+ optimization to distinguish the common case (in which none of -+ the following options has been specified: --count, -repeated, -+ --all-repeated, --unique) from the others. In the common case, -+ this optimization lets uniq output each different line right away, -+ without waiting to see if the next one is different. */ -+ -+ if (output_unique && output_first_repeated && countmode == count_none) -+ { -+ char *prevfield IF_LINT (= NULL); -+ size_t prevlen IF_LINT (= 0); -+ -+ while (!feof (stdin)) -+ { -+ char *thisfield; -+ size_t thislen; -+ if (readlinebuffer_delim (thisline, stdin, delimiter) == 0) -+ break; -+ thisfield = find_field (thisline); -+ thislen = thisline->length - 1 - (thisfield - thisline->buffer); -+ if (prevline->length == 0 -+ || different (thisfield, prevfield, thislen, prevlen)) -+ { -+ fwrite (thisline->buffer, sizeof (char), -+ thisline->length, stdout); -+ -+ SWAP_LINES (prevline, thisline); -+ prevfield = thisfield; -+ prevlen = thislen; -+ } -+ } -+ } -+ else -+ { -+ char *prevfield; -+ size_t prevlen; -+ uintmax_t match_count = 0; -+ bool first_delimiter = true; -+ -+ if (readlinebuffer_delim (prevline, stdin, delimiter) == 0) -+ goto closefiles; -+ prevfield = find_field (prevline); -+ prevlen = prevline->length - 1 - (prevfield - prevline->buffer); -+ -+ while (!feof (stdin)) -+ { -+ bool match; -+ char *thisfield; -+ size_t thislen; -+ if (readlinebuffer_delim (thisline, stdin, delimiter) == 0) -+ { -+ if (ferror (stdin)) -+ goto closefiles; -+ break; -+ } -+ thisfield = find_field (thisline); -+ thislen = thisline->length - 1 - (thisfield - thisline->buffer); -+ match = !different (thisfield, prevfield, thislen, prevlen); -+ match_count += match; -+ -+ if (match_count == UINTMAX_MAX) -+ { -+ if (count_occurrences) -+ error (EXIT_FAILURE, 0, _("too many repeated lines")); -+ match_count--; -+ } -+ -+ if (delimit_groups != DM_NONE) -+ { -+ if (!match) -+ { -+ if (match_count) /* a previous match */ -+ first_delimiter = false; /* Only used when DM_SEPARATE */ -+ } -+ else if (match_count == 1) -+ { -+ if ((delimit_groups == DM_PREPEND) -+ || (delimit_groups == DM_SEPARATE -+ && !first_delimiter)) -+ putchar (delimiter); -+ } -+ } -+ -+ if (!match || output_later_repeated) -+ { -+ writeline (prevline, match, match_count); -+ SWAP_LINES (prevline, thisline); -+ prevfield = thisfield; -+ prevlen = thislen; -+ if (!match) -+ match_count = 0; -+ } -+ } -+ -+ writeline (prevline, false, match_count); -+ } -+ -+ closefiles: -+ if (ferror (stdin) || fclose (stdin) != 0) -+ error (EXIT_FAILURE, 0, _("error reading %s"), infile); -+ -+ /* stdout is handled via the atexit-invoked close_stdout function. */ -+ -+ free (lb1.buffer); -+ free (lb2.buffer); -+} -+ -+enum Skip_field_option_type -+ { -+ SFO_NONE, -+ SFO_OBSOLETE, -+ SFO_NEW -+ }; -+ -+int -+main (int argc, char **argv) -+{ -+ int optc = 0; -+ bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL); -+ enum Skip_field_option_type skip_field_option_type = SFO_NONE; -+ int nfiles = 0; -+ char const *file[2]; -+ char delimiter = '\n'; /* change with --zero-terminated, -z */ -+ -+ file[0] = file[1] = "-"; -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ hard_LC_COLLATE = hard_locale (LC_COLLATE); -+ -+ atexit (close_stdout); -+ -+ skip_chars = 0; -+ skip_fields = 0; -+ check_chars = SIZE_MAX; -+ output_unique = output_first_repeated = true; -+ output_later_repeated = false; -+ countmode = count_none; -+ delimit_groups = DM_NONE; -+ -+ for (;;) -+ { -+ /* Parse an operand with leading "+" as a file after "--" was -+ seen; or if pedantic and a file was seen; or if not -+ obsolete. */ -+ -+ if (optc == -1 -+ || (posixly_correct && nfiles != 0) -+ || ((optc = getopt_long (argc, argv, -+ "-0123456789Dcdf:is:uw:z", longopts, NULL)) -+ == -1)) -+ { -+ if (argc <= optind) -+ break; -+ if (nfiles == 2) -+ { -+ error (0, 0, _("extra operand %s"), quote (argv[optind])); -+ usage (EXIT_FAILURE); -+ } -+ file[nfiles++] = argv[optind++]; -+ } -+ else switch (optc) -+ { -+ case 1: -+ { -+ unsigned long int size; -+ if (optarg[0] == '+' -+ && posix2_version () < 200112 -+ && xstrtoul (optarg, NULL, 10, &size, "") == LONGINT_OK -+ && size <= SIZE_MAX) -+ skip_chars = size; -+ else if (nfiles == 2) -+ { -+ error (0, 0, _("extra operand %s"), quote (optarg)); -+ usage (EXIT_FAILURE); -+ } -+ else -+ file[nfiles++] = optarg; -+ } -+ break; -+ -+ case '0': -+ case '1': -+ case '2': -+ case '3': -+ case '4': -+ case '5': -+ case '6': -+ case '7': -+ case '8': -+ case '9': -+ { -+ if (skip_field_option_type == SFO_NEW) -+ skip_fields = 0; -+ -+ if (!DECIMAL_DIGIT_ACCUMULATE (skip_fields, optc - '0', size_t)) -+ skip_fields = SIZE_MAX; -+ -+ skip_field_option_type = SFO_OBSOLETE; -+ } -+ break; -+ -+ case 'c': -+ countmode = count_occurrences; -+ break; -+ -+ case 'd': -+ output_unique = false; -+ break; -+ -+ case 'D': -+ output_unique = false; -+ output_later_repeated = true; -+ if (optarg == NULL) -+ delimit_groups = DM_NONE; -+ else -+ delimit_groups = XARGMATCH ("--all-repeated", optarg, -+ delimit_method_string, -+ delimit_method_map); -+ break; -+ -+ case 'f': -+ skip_field_option_type = SFO_NEW; -+ skip_fields = size_opt (optarg, -+ N_("invalid number of fields to skip")); -+ break; -+ -+ case 'i': -+ ignore_case = true; -+ break; -+ -+ case 's': -+ skip_chars = size_opt (optarg, -+ N_("invalid number of bytes to skip")); -+ break; -+ -+ case 'u': -+ output_first_repeated = false; -+ break; -+ -+ case 'w': -+ check_chars = size_opt (optarg, -+ N_("invalid number of bytes to compare")); -+ break; -+ -+ case 'z': -+ delimiter = '\0'; -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ if (countmode == count_occurrences && output_later_repeated) -+ { -+ error (0, 0, -+ _("printing all duplicated lines and repeat counts is meaningless")); -+ usage (EXIT_FAILURE); -+ } -+ -+ check_file (file[0], file[1], delimiter); -+ -+ exit (EXIT_SUCCESS); -+} diff -urNp coreutils-8.0-orig/tests/Makefile.am coreutils-8.0/tests/Makefile.am --- coreutils-8.0-orig/tests/Makefile.am 2009-09-29 16:25:44.000000000 +0200 +++ coreutils-8.0/tests/Makefile.am 2009-10-07 10:07:16.000000000 +0200 @@ -14684,626 +3927,6 @@ diff -urNp coreutils-8.0-orig/tests/Makefile.am coreutils-8.0/tests/Makefile.am pr/0F \ pr/0FF \ pr/0FFnt \ -diff -urNp coreutils-8.0-orig/tests/Makefile.am.orig coreutils-8.0/tests/Makefile.am.orig ---- coreutils-8.0-orig/tests/Makefile.am.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/tests/Makefile.am.orig 2009-09-29 16:25:44.000000000 +0200 -@@ -0,0 +1,616 @@ -+## Process this file with automake to produce Makefile.in -*-Makefile-*-. -+ -+# Sort in traditional ASCII order, regardless of the current locale; -+# otherwise we may get into trouble with distinct strings that the -+# current locale considers to be equal. -+ASSORT = LC_ALL=C sort -+ -+EXTRA_DIST = \ -+ Coreutils.pm \ -+ CuTmpdir.pm \ -+ README \ -+ check.mk \ -+ envvar-check \ -+ lang-default \ -+ other-fs-tmpdir \ -+ require-perl \ -+ sample-test \ -+ test-lib.sh \ -+ $(pr_data) -+ -+root_tests = \ -+ chown/basic \ -+ cp/cp-a-selinux \ -+ cp/preserve-gid \ -+ cp/special-bits \ -+ cp/cp-mv-enotsup-xattr \ -+ chroot/credentials \ -+ dd/skip-seek-past-dev \ -+ install/install-C-root \ -+ ls/capability \ -+ ls/nameless-uid \ -+ misc/chcon \ -+ misc/selinux \ -+ misc/truncate-owned-by-other \ -+ mkdir/writable-under-readonly \ -+ mv/sticky-to-xpart \ -+ rm/fail-2eperm \ -+ rm/no-give-up \ -+ rm/one-file-system \ -+ tail-2/append-only \ -+ touch/now-owned-by-other -+ -+.PHONY: check-root -+check-root: -+ $(MAKE) check TESTS='$(root_tests)' -+ -+check-recursive: root-hint -+ -+# Advertise `check-root' target. -+.PHONY: root-hint -+root-hint: -+ @echo '***********************************************************' -+ @echo "NOTICE: Some tests may be run only as root." -+ @echo " See the 'Running tests as root' section in README." -+ @echo '***********************************************************' -+ -+EXTRA_DIST += $(TESTS) -+ -+# Do not choose a name that is a shell keyword like 'if', or a -+# commonly-used utility like 'cat' or 'test', as the name of a test. -+# Otherwise, VPATH builds will fail on hosts like Solaris, since they -+# will expand 'if test ...' to 'if .../test ...', and the '.../test' -+# will execute the test script rather than the standard utility. -+ -+# Notes on the ordering of these tests: -+# Place early in the list tests of the tools that -+# are most commonly used in test scripts themselves. -+# E.g., nearly every test script uses rm and chmod. -+# help-version comes early because it's a basic sanity test. -+# Put seq early, since lots of other tests use it. -+# Put tests that sleep early, but not all together, so in parallel builds -+# they share time with tests that burn CPU, not with others that sleep. -+# Put head-elide-tail early, because it's long-running. -+ -+TESTS = \ -+ misc/help-version \ -+ misc/invalid-opt \ -+ rm/ext3-perf \ -+ rm/cycle \ -+ cp/link-heap \ -+ chmod/no-x \ -+ chgrp/basic \ -+ rm/dangling-symlink \ -+ misc/ls-time \ -+ rm/deep-1 \ -+ rm/deep-2 \ -+ rm/dir-no-w \ -+ rm/dir-nonrecur \ -+ rm/dot-rel \ -+ rm/isatty \ -+ rm/empty-inacc \ -+ rm/empty-name \ -+ rm/f-1 \ -+ rm/fail-eacces \ -+ rm/fail-eperm \ -+ tail-2/assert \ -+ rm/hash \ -+ rm/i-1 \ -+ rm/i-never \ -+ rm/i-no-r \ -+ tail-2/infloop-1 \ -+ rm/ignorable \ -+ rm/inaccessible \ -+ rm/interactive-always \ -+ rm/interactive-once \ -+ rm/ir-1 \ -+ rm/r-1 \ -+ rm/r-2 \ -+ rm/r-3 \ -+ rm/r-4 \ -+ rm/readdir-bug \ -+ rm/rm1 \ -+ touch/empty-file \ -+ rm/rm2 \ -+ rm/rm3 \ -+ rm/rm4 \ -+ rm/rm5 \ -+ rm/sunos-1 \ -+ rm/unread2 \ -+ rm/unread3 \ -+ rm/unreadable \ -+ rm/v-slash \ -+ chgrp/default-no-deref \ -+ chgrp/deref \ -+ chgrp/no-x \ -+ chgrp/posix-H \ -+ chgrp/recurse \ -+ misc/ptx \ -+ misc/test \ -+ misc/seq \ -+ misc/seq-long-double \ -+ misc/head \ -+ misc/head-elide-tail \ -+ tail-2/tail-n0f \ -+ misc/ls-misc \ -+ misc/date \ -+ misc/date-next-dow \ -+ misc/ptx-overrun \ -+ misc/xstrtol \ -+ tail-2/pid \ -+ misc/od \ -+ misc/mktemp \ -+ misc/arch \ -+ misc/pr \ -+ misc/join \ -+ pr/pr-tests \ -+ misc/df-P \ -+ misc/pwd-option \ -+ misc/pwd-unreadable-parent \ -+ misc/chcon-fail \ -+ misc/cut \ -+ misc/wc \ -+ misc/wc-files0-from \ -+ misc/wc-files0 \ -+ misc/cat-proc \ -+ misc/cat-buf \ -+ misc/base64 \ -+ misc/basename \ -+ misc/close-stdout \ -+ misc/comm \ -+ misc/csplit \ -+ misc/date-sec \ -+ misc/dircolors \ -+ misc/df \ -+ misc/dirname \ -+ misc/expand \ -+ misc/expr \ -+ misc/factor \ -+ misc/false-status \ -+ misc/fmt \ -+ misc/fmt-long-line \ -+ misc/fold \ -+ misc/groups-dash \ -+ misc/groups-version \ -+ misc/head-c \ -+ misc/head-pos \ -+ misc/id-context \ -+ misc/id-groups \ -+ misc/md5sum \ -+ misc/md5sum-newline \ -+ misc/mknod \ -+ misc/nice \ -+ misc/nl \ -+ misc/nohup \ -+ misc/od-N \ -+ misc/od-multiple-t \ -+ misc/od-x8 \ -+ misc/paste \ -+ misc/pathchk1 \ -+ misc/printf \ -+ misc/printf-cov \ -+ misc/printf-hex \ -+ misc/printf-surprise \ -+ misc/pwd-long \ -+ misc/readlink-fp-loop \ -+ misc/runcon-no-reorder \ -+ misc/sha1sum \ -+ misc/sha1sum-vec \ -+ misc/sha224sum \ -+ misc/sha256sum \ -+ misc/sha384sum \ -+ misc/sha512sum \ -+ misc/shred-exact \ -+ misc/shred-passes \ -+ misc/shred-remove \ -+ misc/shuf \ -+ misc/sort \ -+ misc/sort-compress \ -+ misc/sort-continue \ -+ misc/sort-files0-from \ -+ misc/sort-merge \ -+ misc/sort-merge-fdlimit \ -+ misc/sort-rand \ -+ misc/sort-version \ -+ misc/split-a \ -+ misc/split-fail \ -+ misc/split-l \ -+ misc/stat-fmt \ -+ misc/stat-hyphen \ -+ misc/stat-printf \ -+ misc/stdbuf \ -+ misc/stty \ -+ misc/stty-invalid \ -+ misc/stty-row-col \ -+ misc/sum \ -+ misc/sum-sysv \ -+ misc/tac \ -+ misc/tac-continue \ -+ misc/tail \ -+ misc/tee \ -+ misc/tee-dash \ -+ misc/test-diag \ -+ misc/timeout \ -+ misc/timeout-parameters \ -+ misc/tr \ -+ misc/truncate-dangling-symlink \ -+ misc/truncate-dir-fail \ -+ misc/truncate-fail-diag \ -+ misc/truncate-fifo \ -+ misc/truncate-no-create-missing \ -+ misc/truncate-overflow \ -+ misc/truncate-parameters \ -+ misc/truncate-relative \ -+ misc/tsort \ -+ misc/tty-eof \ -+ misc/unexpand \ -+ misc/uniq \ -+ misc/xattr \ -+ tail-2/wait \ -+ chmod/c-option \ -+ chmod/equal-x \ -+ chmod/equals \ -+ chmod/inaccessible \ -+ chmod/octal \ -+ chmod/setgid \ -+ chmod/silent \ -+ chmod/thru-dangling \ -+ chmod/umask-x \ -+ chmod/usage \ -+ chown/deref \ -+ chown/preserve-root \ -+ chown/separator \ -+ cp/abuse \ -+ cp/acl \ -+ cp/backup-1 \ -+ cp/backup-dir \ -+ cp/backup-is-src \ -+ cp/cp-HL \ -+ cp/cp-deref \ -+ cp/cp-i \ -+ cp/cp-mv-backup \ -+ cp/cp-parents \ -+ cp/deref-slink \ -+ cp/dir-rm-dest \ -+ cp/dir-slash \ -+ cp/dir-vs-file \ -+ cp/existing-perm-race \ -+ cp/fail-perm \ -+ cp/file-perm-race \ -+ cp/into-self \ -+ cp/link \ -+ cp/link-no-deref \ -+ cp/link-preserve \ -+ cp/no-deref-link1 \ -+ cp/no-deref-link2 \ -+ cp/no-deref-link3 \ -+ cp/parent-perm \ -+ cp/parent-perm-race \ -+ cp/perm \ -+ cp/preserve-2 \ -+ cp/preserve-slink-time \ -+ cp/proc-short-read \ -+ cp/proc-zero-len \ -+ cp/r-vs-symlink \ -+ cp/reflink-auto \ -+ cp/reflink-perm \ -+ cp/same-file \ -+ cp/slink-2-slink \ -+ cp/sparse \ -+ cp/special-f \ -+ cp/src-base-dot \ -+ cp/symlink-slash \ -+ cp/thru-dangling \ -+ df/unreadable \ -+ dd/direct \ -+ dd/misc \ -+ dd/not-rewound \ -+ dd/reblock \ -+ dd/skip-seek \ -+ dd/skip-seek2 \ -+ dd/skip-seek-past-file \ -+ dd/stderr \ -+ dd/unblock \ -+ dd/unblock-sync \ -+ df/total-verify \ -+ du/2g \ -+ du/8gb \ -+ du/basic \ -+ du/deref \ -+ du/deref-args \ -+ du/exclude \ -+ du/fd-leak \ -+ du/files0-from \ -+ du/hard-link \ -+ du/inacc-dest \ -+ du/inacc-dir \ -+ du/inaccessible-cwd \ -+ du/long-from-unreadable \ -+ du/long-sloop \ -+ du/no-deref \ -+ du/no-x \ -+ du/one-file-system \ -+ du/restore-wd \ -+ du/slash \ -+ du/slink \ -+ du/trailing-slash \ -+ du/two-args \ -+ id/no-context \ -+ install/basic-1 \ -+ install/create-leading \ -+ install/d-slashdot \ -+ install/install-C \ -+ install/install-C-selinux \ -+ install/strip-program \ -+ install/trap \ -+ ln/backup-1 \ -+ ln/hard-backup \ -+ ln/hard-to-sym \ -+ ln/misc \ -+ ln/sf-1 \ -+ ln/slash-decorated-nonexistent-dest \ -+ ln/target-1 \ -+ ls/abmon-align \ -+ ls/color-clear-to-eol \ -+ ls/color-dtype-dir \ -+ ls/dangle \ -+ ls/dired \ -+ ls/file-type \ -+ ls/follow-slink \ -+ ls/infloop \ -+ ls/inode \ -+ ls/m-option \ -+ ls/multihardlink \ -+ ls/no-arg \ -+ ls/no-cap \ -+ ls/proc-selinux-segfault \ -+ ls/readdir-mountpoint-inode \ -+ ls/recursive \ -+ ls/rt-1 \ -+ ls/stat-dtype \ -+ ls/stat-failed \ -+ ls/stat-free-symlinks \ -+ ls/stat-vs-dirent \ -+ ls/symlink-slash \ -+ ls/x-option \ -+ mkdir/p-1 \ -+ mkdir/p-2 \ -+ mkdir/p-3 \ -+ mkdir/p-slashdot \ -+ mkdir/p-thru-slink \ -+ mkdir/p-v \ -+ mkdir/parents \ -+ mkdir/perm \ -+ mkdir/selinux \ -+ mkdir/special-1 \ -+ mkdir/t-slash \ -+ mv/acl \ -+ mv/atomic \ -+ mv/atomic2 \ -+ mv/backup-dir \ -+ mv/backup-is-src \ -+ mv/childproof \ -+ mv/diag \ -+ mv/dir-file \ -+ mv/dir2dir \ -+ mv/dup-source \ -+ mv/force \ -+ mv/hard-2 \ -+ mv/hard-3 \ -+ mv/hard-4 \ -+ mv/hard-link-1 \ -+ mv/hard-verbose \ -+ mv/i-1 \ -+ mv/i-2 \ -+ mv/i-3 \ -+ mv/i-4 \ -+ mv/i-5 \ -+ mv/i-link-no \ -+ mv/into-self \ -+ mv/into-self-2 \ -+ mv/into-self-3 \ -+ mv/into-self-4 \ -+ mv/leak-fd \ -+ mv/mv-n \ -+ mv/mv-special-1 \ -+ mv/no-target-dir \ -+ mv/part-fail \ -+ mv/part-hardlink \ -+ mv/part-rename \ -+ mv/part-symlink \ -+ mv/partition-perm \ -+ mv/perm-1 \ -+ mv/to-symlink \ -+ mv/trailing-slash \ -+ mv/update \ -+ readlink/can-e \ -+ readlink/can-f \ -+ readlink/can-m \ -+ readlink/rl-1 \ -+ rmdir/fail-perm \ -+ rmdir/ignore \ -+ rmdir/t-slash \ -+ tail-2/assert-2 \ -+ tail-2/big-4gb \ -+ tail-2/flush-initial \ -+ tail-2/follow-stdin \ -+ tail-2/pipe-f \ -+ tail-2/pipe-f2 \ -+ tail-2/proc-ksyms \ -+ tail-2/start-middle \ -+ touch/60-seconds \ -+ touch/dangling-symlink \ -+ touch/dir-1 \ -+ touch/fail-diag \ -+ touch/fifo \ -+ touch/no-create-missing \ -+ touch/no-rights \ -+ touch/not-owner \ -+ touch/obsolescent \ -+ touch/read-only \ -+ touch/relative \ -+ $(root_tests) -+ -+pr_data = \ -+ pr/0F \ -+ pr/0FF \ -+ pr/0FFnt \ -+ pr/0FFt \ -+ pr/0FnFnt \ -+ pr/0FnFt \ -+ pr/0Fnt \ -+ pr/0Ft \ -+ pr/2-S_f-t_notab \ -+ pr/2-Sf-t_notab \ -+ pr/2f-t_notab \ -+ pr/2s_f-t_notab \ -+ pr/2s_w60f-t_nota \ -+ pr/2sf-t_notab \ -+ pr/2sw60f-t_notab \ -+ pr/2w60f-t_notab \ -+ pr/3-0F \ -+ pr/3-5l24f-t \ -+ pr/3-FF \ -+ pr/3a2l17-FF \ -+ pr/3a3f-0F \ -+ pr/3a3l15-t \ -+ pr/3a3l15f-t \ -+ pr/3b2l17-FF \ -+ pr/3b3f-0F \ -+ pr/3b3f-0FF \ -+ pr/3b3f-FF \ -+ pr/3b3l15-t \ -+ pr/3b3l15f-t \ -+ pr/3f-0F \ -+ pr/3f-FF \ -+ pr/3l24-t \ -+ pr/3l24f-t \ -+ pr/3ml24-FF \ -+ pr/3ml24-t \ -+ pr/3ml24-t-FF \ -+ pr/3ml24f-t \ -+ pr/4-7l24-FF \ -+ pr/4l24-FF \ -+ pr/FF \ -+ pr/FFn \ -+ pr/FFtn \ -+ pr/FnFn \ -+ pr/Ja3l24f-lm \ -+ pr/Jb3l24f-lm \ -+ pr/Jml24f-lm-lo \ -+ pr/W-72l24f-ll \ -+ pr/W20l24f-ll \ -+ pr/W26l24f-ll \ -+ pr/W27l24f-ll \ -+ pr/W28l24f-ll \ -+ pr/W35Ja3l24f-lm \ -+ pr/W35Jb3l24f-lm \ -+ pr/W35Jml24f-lmlo \ -+ pr/W35a3l24f-lm \ -+ pr/W35b3l24f-lm \ -+ pr/W35ml24f-lm-lo \ -+ pr/W72Jl24f-ll \ -+ pr/a2l15-FF \ -+ pr/a2l17-FF \ -+ pr/a3-0F \ -+ pr/a3f-0F \ -+ pr/a3f-0FF \ -+ pr/a3f-FF \ -+ pr/a3l15-t \ -+ pr/a3l15f-t \ -+ pr/a3l24f-lm \ -+ pr/b2l15-FF \ -+ pr/b2l17-FF \ -+ pr/b3-0F \ -+ pr/b3f-0F \ -+ pr/b3f-0FF \ -+ pr/b3f-FF \ -+ pr/b3l15-t \ -+ pr/b3l15f-t \ -+ pr/b3l24f-lm \ -+ pr/l24-FF \ -+ pr/l24-t \ -+ pr/l24f-t \ -+ pr/loli \ -+ pr/ml20-FF-t \ -+ pr/ml24-FF \ -+ pr/ml24-t \ -+ pr/ml24-t-FF \ -+ pr/ml24f-0F \ -+ pr/ml24f-lm-lo \ -+ pr/ml24f-t \ -+ pr/ml24f-t-0F \ -+ pr/n+2-5l24f-0FF \ -+ pr/n+2l24f-0FF \ -+ pr/n+2l24f-bl \ -+ pr/n+3-7l24-FF \ -+ pr/n+3l24f-0FF \ -+ pr/n+3l24f-bl \ -+ pr/n+3ml20f-bl-FF \ -+ pr/n+3ml24f-bl-tn \ -+ pr/n+3ml24f-tn-bl \ -+ pr/n+4-8a2l17-FF \ -+ pr/n+4b2l17f-0FF \ -+ pr/n+5-8b3l17f-FF \ -+ pr/n+5a3l13f-0FF \ -+ pr/n+6a2l17-FF \ -+ pr/n+6b3l13f-FF \ -+ pr/n+7l24-FF \ -+ pr/n+8l20-FF \ -+ pr/nJml24f-lmlmlo \ -+ pr/nJml24f-lmlolm \ -+ pr/nN1+3l24f-bl \ -+ pr/nN15l24f-bl \ -+ pr/nSml20-bl-FF \ -+ pr/nSml20-t-t-FF \ -+ pr/nSml20-t-tFFFF \ -+ pr/nSml24-bl-FF \ -+ pr/nSml24-t-t-FF \ -+ pr/nSml24-t-tFFFF \ -+ pr/nl24f-bl \ -+ pr/o3Jml24f-lm-lo \ -+ pr/o3a3Sl24f-tn \ -+ pr/o3a3Snl24f-tn \ -+ pr/o3a3l24f-tn \ -+ pr/o3b3Sl24f-tn \ -+ pr/o3b3Snl24f-tn \ -+ pr/o3b3l24f-tn \ -+ pr/o3mSl24f-bl-tn \ -+ pr/o3mSnl24fbltn \ -+ pr/o3ml24f-bl-tn \ -+ pr/t-0FF \ -+ pr/t-FF \ -+ pr/t-bl \ -+ pr/t-t \ -+ pr/tFFn \ -+ pr/tFFt \ -+ pr/tFFt-bl \ -+ pr/tFFt-ll \ -+ pr/tFFt-lm \ -+ pr/tFnFt \ -+ pr/t_notab \ -+ pr/t_tab \ -+ pr/t_tab_ \ -+ pr/ta3-0FF \ -+ pr/ta3-FF \ -+ pr/tb3-0FF \ -+ pr/tb3-FF \ -+ pr/tn \ -+ pr/tn2e5o3-t_tab \ -+ pr/tn2e8-t_tab \ -+ pr/tn2e8o3-t_tab \ -+ pr/tn_2e8-t_tab \ -+ pr/tn_2e8S-t_tab \ -+ pr/tne8-t_tab \ -+ pr/tne8o3-t_tab \ -+ pr/tt-0FF \ -+ pr/tt-FF \ -+ pr/tt-bl \ -+ pr/tt-t \ -+ pr/tta3-0FF \ -+ pr/tta3-FF \ -+ pr/ttb3-0FF \ -+ pr/ttb3-FF \ -+ pr/w72l24f-ll -+ -+include $(srcdir)/check.mk diff -urNp coreutils-8.0-orig/tests/misc/cut coreutils-8.0/tests/misc/cut --- coreutils-8.0-orig/tests/misc/cut 2009-09-21 14:29:33.000000000 +0200 +++ coreutils-8.0/tests/misc/cut 2009-10-07 10:07:16.000000000 +0200 diff --git a/coreutils-pam.patch b/coreutils-pam.patch index 2a6334f..24f7437 100644 --- a/coreutils-pam.patch +++ b/coreutils-pam.patch @@ -15,16348 +15,66 @@ diff -urNp coreutils-8.0-orig/configure.ac coreutils-8.0/configure.ac AC_FUNC_FORK optional_bin_progs= -diff -urNp coreutils-8.0-orig/configure.ac.orig coreutils-8.0/configure.ac.orig ---- coreutils-8.0-orig/configure.ac.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/configure.ac.orig 2009-09-29 15:27:11.000000000 +0200 -@@ -0,0 +1,439 @@ -+# -*- autoconf -*- -+# Process this file with autoconf to produce a configure script. -+ -+# Copyright (C) 1991, 1993-2009 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 . -+ -+dnl Written by Jim Meyering. -+ -+AC_PREREQ([2.61]) -+ -+# Make inter-release version strings look like, e.g., v6.9-219-g58ddd, which -+# indicates that it is built from the 219th delta (in _some_ repository) -+# following the v6.9 tag, and that 58ddd is a prefix of the commit SHA1. -+AC_INIT([GNU coreutils], -+ m4_esyscmd([build-aux/git-version-gen .tarball-version]), -+ [bug-coreutils@gnu.org]) -+ -+AC_CONFIG_SRCDIR([src/ls.c]) -+ -+AC_CONFIG_AUX_DIR([build-aux]) -+AC_CONFIG_HEADERS([lib/config.h:lib/config.hin]) -+ -+AM_INIT_AUTOMAKE([1.11 dist-xz color-tests parallel-tests]) -+AM_SILENT_RULES([yes]) # make --enable-silent-rules the default. -+ -+AC_PROG_CC_STDC -+AM_PROG_CC_C_O -+AC_PROG_CPP -+AC_PROG_GCC_TRADITIONAL -+AC_PROG_RANLIB -+AC_PROG_LN_S -+gl_EARLY -+gl_INIT -+coreutils_MACROS -+ -+AC_ARG_ENABLE([gcc-warnings], -+ [AS_HELP_STRING([--enable-gcc-warnings], -+ [turn on lots of GCC warnings (for developers)])], -+ [case $enableval in -+ yes|no) ;; -+ *) AC_MSG_ERROR([bad value $enableval for gcc-warnings option]) ;; -+ esac -+ gl_gcc_warnings=$enableval], -+ [gl_gcc_warnings=no] -+) -+ -+if test "$gl_gcc_warnings" = yes; then -+ gl_WARN_ADD([-Werror], [WERROR_CFLAGS]) -+ AC_SUBST([WERROR_CFLAGS]) -+ -+ nw= -+ # This, $nw, is the list of warnings we disable. -+ nw="$nw -Wdeclaration-after-statement" # too useful to forbid -+ nw="$nw -Waggregate-return" # anachronistic -+ nw="$nw -Wlong-long" # C90 is anachronistic (lib/gethrxtime.h) -+ nw="$nw -Wc++-compat" # We don't care about C++ compilers -+ nw="$nw -Wundef" # Warns on '#if GNULIB_FOO' etc in gnulib -+ nw="$nw -Wtraditional" # Warns on #elif which we use often -+ nw="$nw -Wcast-qual" # Too many warnings for now -+ nw="$nw -Wconversion" # Too many warnings for now -+ nw="$nw -Wsystem-headers" # Don't let system headers trigger warnings -+ nw="$nw -Wsign-conversion" # Too many warnings for now -+ nw="$nw -Wtraditional-conversion" # Too many warnings for now -+ nw="$nw -Wunreachable-code" # Too many warnings for now -+ nw="$nw -Wpadded" # Our structs are not padded -+ nw="$nw -Wredundant-decls" # openat.h declares e.g., mkdirat -+ nw="$nw -Wlogical-op" # any use of fwrite provokes this -+ nw="$nw -Wformat-nonliteral" # who.c and pinky.c strftime uses -+ nw="$nw -Wvla" # warnings in gettext.h -+ nw="$nw -Wnested-externs" # use of XARGMATCH/verify_function__ -+ nw="$nw -Wswitch-enum" # Too many warnings for now -+ nw="$nw -Wswitch-default" # Too many warnings for now -+ nw="$nw -Wstack-protector" # not worth working around -+ # things I might fix soon: -+ nw="$nw -Wfloat-equal" # sort.c, seq.c -+ nw="$nw -Wmissing-format-attribute" # copy.c -+ nw="$nw -Wunsafe-loop-optimizations" # a few src/*.c -+ nw="$nw -Winline" # system.h's readdir_ignoring_dot_and_dotdot -+ nw="$nw -Wstrict-overflow" # expr.c, pr.c, tr.c, factor.c -+ # ?? -Wstrict-overflow -+ -+ gl_MANYWARN_ALL_GCC([ws]) -+ gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw]) -+ for w in $ws; do -+ gl_WARN_ADD([$w]) -+ done -+ gl_WARN_ADD([-Wno-missing-field-initializers]) # We need this one -+ gl_WARN_ADD([-Wno-sign-compare]) # Too many warnings for now -+ gl_WARN_ADD([-Wno-pointer-sign]) # Too many warnings for now -+ gl_WARN_ADD([-Wno-unused-parameter]) # Too many warnings for now -+ -+ # In spite of excluding -Wlogical-op above, it is enabled, as of -+ # gcc 4.5.0 20090517, and it provokes warnings in cat.c, dd.c, truncate.c -+ gl_WARN_ADD([-Wno-logical-op]) -+ -+ gl_WARN_ADD([-fdiagnostics-show-option]) -+ -+ AC_SUBST([WARN_CFLAGS]) -+ -+ AC_DEFINE([lint], [1], [Define to 1 if the compiler is checking for lint.]) -+ AC_DEFINE([_FORTIFY_SOURCE], [2], -+ [enable compile-time and run-time bounds-checking, and some warnings]) -+ AC_DEFINE([GNULIB_PORTCHECK], [1], [enable some gnulib portability checks]) -+fi -+ -+AC_FUNC_FORK -+ -+optional_bin_progs= -+AC_CHECK_FUNCS([uname], -+ gl_ADD_PROG([optional_bin_progs], [uname])) -+AC_CHECK_FUNCS([chroot], -+ gl_ADD_PROG([optional_bin_progs], [chroot])) -+AC_CHECK_FUNCS([gethostid], -+ gl_ADD_PROG([optional_bin_progs], [hostid])) -+ -+gl_WINSIZE_IN_PTEM -+ -+AC_MSG_CHECKING([whether localtime caches TZ]) -+AC_CACHE_VAL([utils_cv_localtime_cache], -+[if test x$ac_cv_func_tzset = xyes; then -+AC_RUN_IFELSE([AC_LANG_SOURCE([[#include -+#if STDC_HEADERS -+# include -+#endif -+extern char **environ; -+void unset_TZ (void) -+{ -+ char **from, **to; -+ for (to = from = environ; (*to = *from); from++) -+ if (! (to[0][0] == 'T' && to[0][1] == 'Z' && to[0][2] == '=')) -+ to++; -+} -+int main() -+{ -+ time_t now = time ((time_t *) 0); -+ int hour_GMT0, hour_unset; -+ if (putenv ("TZ=GMT0") != 0) -+ exit (1); -+ hour_GMT0 = localtime (&now)->tm_hour; -+ unset_TZ (); -+ hour_unset = localtime (&now)->tm_hour; -+ if (putenv ("TZ=PST8") != 0) -+ exit (1); -+ if (localtime (&now)->tm_hour == hour_GMT0) -+ exit (1); -+ unset_TZ (); -+ if (localtime (&now)->tm_hour != hour_unset) -+ exit (1); -+ exit (0); -+}]])], -+[utils_cv_localtime_cache=no], -+[utils_cv_localtime_cache=yes], -+[# If we have tzset, assume the worst when cross-compiling. -+utils_cv_localtime_cache=yes]) -+else -+ # If we lack tzset, report that localtime does not cache TZ, -+ # since we can't invalidate the cache if we don't have tzset. -+ utils_cv_localtime_cache=no -+fi])dnl -+AC_MSG_RESULT([$utils_cv_localtime_cache]) -+if test $utils_cv_localtime_cache = yes; then -+ AC_DEFINE([LOCALTIME_CACHE], [1], [FIXME]) -+fi -+ -+# SCO-ODT-3.0 is reported to need -los to link programs using initgroups -+AC_CHECK_FUNCS([initgroups]) -+if test $ac_cv_func_initgroups = no; then -+ AC_CHECK_LIB([os], [initgroups]) -+fi -+ -+AC_CHECK_FUNCS([syslog]) -+if test $ac_cv_func_syslog = no; then -+ # syslog is not in the default libraries. See if it's in some other. -+ for lib in bsd socket inet; do -+ AC_CHECK_LIB([$lib], [syslog], [AC_DEFINE([HAVE_SYSLOG], [1], [FIXME]) -+ LIBS="$LIBS -l$lib"; break]) -+ done -+fi -+ -+AC_CACHE_CHECK([for 3-argument setpriority function], -+ [utils_cv_func_setpriority], -+ [AC_LINK_IFELSE( -+ [AC_LANG_PROGRAM( -+ [[#include -+ #include -+ ]], -+ [[setpriority (0, 0, 0);]])], -+ [utils_cv_func_setpriority=yes], -+ [utils_cv_func_setpriority=no])]) -+if test $utils_cv_func_setpriority = no; then -+ AC_CHECK_FUNCS([nice]) -+fi -+case $utils_cv_func_setpriority,$ac_cv_func_nice in -+*yes*) -+ gl_ADD_PROG([optional_bin_progs], [nice]) -+esac -+ -+AC_DEFUN([coreutils_DUMMY_1], -+[ -+ AC_REQUIRE([gl_READUTMP]) -+ if test $ac_cv_header_utmp_h = yes || test $ac_cv_header_utmpx_h = yes; then -+ gl_ADD_PROG([optional_bin_progs], [who]) -+ gl_ADD_PROG([optional_bin_progs], [users]) -+ gl_ADD_PROG([optional_bin_progs], [pinky]) -+ fi -+]) -+coreutils_DUMMY_1 -+ -+AC_MSG_CHECKING([ut_host in struct utmp]) -+AC_CACHE_VAL([su_cv_func_ut_host_in_utmp], -+[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -+#include ]], [[struct utmp ut; return !sizeof ut.ut_host;]])], -+ [su_cv_func_ut_host_in_utmp=yes], -+ [su_cv_func_ut_host_in_utmp=no])]) -+AC_MSG_RESULT([$su_cv_func_ut_host_in_utmp]) -+if test $su_cv_func_ut_host_in_utmp = yes; then -+ have_ut_host=1 -+ AC_DEFINE([HAVE_UT_HOST], [1], [FIXME]) -+fi -+ -+if test -z "$have_ut_host"; then -+ AC_MSG_CHECKING([ut_host in struct utmpx]) -+ AC_CACHE_VAL([su_cv_func_ut_host_in_utmpx], -+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -+#include ]], [[struct utmpx ut; return !sizeof ut.ut_host;]])], -+ [su_cv_func_ut_host_in_utmpx=yes], -+ [su_cv_func_ut_host_in_utmpx=no])]) -+ AC_MSG_RESULT([$su_cv_func_ut_host_in_utmpx]) -+ if test $su_cv_func_ut_host_in_utmpx = yes; then -+ AC_DEFINE([HAVE_UTMPX_H], [1], [FIXME]) -+ AC_DEFINE([HAVE_UT_HOST], [1], [FIXME]) -+ fi -+fi -+ -+GNULIB_BOOT_TIME([gl_ADD_PROG([optional_bin_progs], [uptime])]) -+ -+AC_SYS_POSIX_TERMIOS() -+gl_HEADER_TIOCGWINSZ_NEEDS_SYS_IOCTL -+ -+if test $ac_cv_sys_posix_termios = yes; then -+ gl_ADD_PROG([optional_bin_progs], [stty]) -+ -+ AC_MSG_CHECKING([whether termios.h needs _XOPEN_SOURCE]) -+ AC_CACHE_VAL([su_cv_sys_termios_needs_xopen_source], -+ [AC_EGREP_CPP([yes], [#include -+#ifdef IUCLC -+yes -+#endif], su_cv_sys_termios_needs_xopen_source=no, -+ AC_EGREP_CPP([yes], [#define _XOPEN_SOURCE -+#include -+#ifdef IUCLC -+yes -+#endif], su_cv_sys_termios_needs_xopen_source=yes, -+ su_cv_sys_termios_needs_xopen_source=no))]) -+ AC_MSG_RESULT([$su_cv_sys_termios_needs_xopen_source]) -+ test $su_cv_sys_termios_needs_xopen_source = yes && -+ AC_DEFINE([TERMIOS_NEEDS_XOPEN_SOURCE], [1], [FIXME]) -+ -+ AC_MSG_CHECKING([c_line in struct termios]) -+ AC_CACHE_VAL([su_cv_sys_c_line_in_termios], -+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if TERMIOS_NEEDS_XOPEN_SOURCE -+#define _XOPEN_SOURCE -+#endif -+#include -+#include ]], [[struct termios t; return !sizeof t.c_line;]])], -+ [su_cv_sys_c_line_in_termios=yes], -+ [su_cv_sys_c_line_in_termios=no])]) -+ AC_MSG_RESULT([$su_cv_sys_c_line_in_termios]) -+ test $su_cv_sys_c_line_in_termios = yes \ -+ && AC_DEFINE([HAVE_C_LINE], [1], [FIXME]) -+fi -+ -+# FIXME: note that this macro appears above, too. -+# I'm leaving it here for now. This whole thing needs to be modernized... -+gl_WINSIZE_IN_PTEM -+ -+gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H -+ -+if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \ -+ test $gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h = no; then -+ AC_MSG_CHECKING([TIOCGWINSZ in sys/pty.h]) -+ AC_CACHE_VAL([su_cv_sys_tiocgwinsz_in_sys_pty_h], -+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include -+#ifdef WINSIZE_IN_PTEM -+# include -+# include -+#endif -+#include -+#include -+#include ]], [[int x = TIOCGWINSZ;]])], -+ [su_cv_sys_tiocgwinsz_in_sys_pty_h=yes], -+ [su_cv_sys_tiocgwinsz_in_sys_pty_h=no])]) -+ AC_MSG_RESULT([$su_cv_sys_tiocgwinsz_in_sys_pty_h]) -+ -+ test $su_cv_sys_tiocgwinsz_in_sys_pty_h = yes \ -+ && AC_DEFINE([GWINSZ_IN_SYS_PTY], [1], -+ [Define if your system defines TIOCGWINSZ in sys/pty.h.]) -+fi -+ -+# For src/kill.c. -+AC_CHECK_DECLS([strsignal, sys_siglist, _sys_siglist, __sys_siglist], , , -+ [AC_INCLUDES_DEFAULT -+#include ]) -+ -+cu_LIB_CHECK -+cu_GMP -+ -+# Build df only if there's a point to it. -+if test $gl_cv_list_mounted_fs = yes && test $gl_cv_fs_space = yes; then -+ gl_ADD_PROG([optional_bin_progs], [df]) -+fi -+ -+# Limit stdbuf to ELF systems with GCC -+optional_pkglib_progs= -+AC_MSG_CHECKING([whether this is an ELF system]) -+AC_EGREP_CPP([yes], [#if __ELF__ -+yes -+#endif], [elf_sys=yes], [elf_sys=no]) -+AC_MSG_RESULT([$elf_sys]) -+if test "$elf_sys" = "yes" && \ -+ test "$GCC" = "yes"; then -+ gl_ADD_PROG([optional_bin_progs], [stdbuf]) -+ gl_ADD_PROG([optional_pkglib_progs], [libstdbuf.so]) -+fi -+ -+############################################################################ -+mk="$srcdir/src/Makefile.am" -+# Extract all literal names from the definition of $(EXTRA_PROGRAMS) -+# in $mk but don't expand the variable references. -+# Append each literal name to $optional_bin_progs. -+v=EXTRA_PROGRAMS -+for gl_i in `sed -n '/^'$v' =/,/[[^\]]$/p' $mk \ -+ | sed 's/^ *//;/^\$.*/d;/^'$v' =/d' \ -+ | tr -s '\\015\\012\\\\' ' '`; do -+ gl_ADD_PROG([optional_bin_progs], $gl_i) -+done -+ -+# As above, extract literal names from the definition of $(no_install__progs) -+# in $mk but don't expand the variable references. -+v=no_install__progs -+t=`sed -n '/^'$v' =/,/[[^\]]$/p' $mk \ -+ | sed 's/^ *//;/^\$.*/d;/^'$v' =/d' \ -+ | tr -s '\\015\\012\\\\' ' '` -+# Remove any trailing space. -+no_install_progs_default=`echo "$t"|sed 's/ $//'` -+ -+# Unfortunately, due to the way autoconf's AS_HELP_STRING works, the list -+# of default-not-installed programs, "arch hostname su", must appear in two -+# places: in this file below, and in $mk. Using "$no_install_progs_default" -+# below cannot work. And we can't substitute the names into $mk because -+# automake needs the literals, too. -+# The compromise is to ensure that the space-separated list extracted -+# above matches the literal 2nd argument below. -+c="$srcdir/configure.ac" -+re='^g''l_INCLUDE_EXCLUDE_PROG(.* [\[\(.*\)\]])' -+t=`sed -n '/'"$re"'/{s/'"$re"'/\1/;s/,/ /gp -+}' $c` -+case $t in -+ $no_install_progs_default) ;; -+ *) AC_MSG_ERROR([[internal error: g'l_INCLUDE_EXCLUDE_PROG's 2nd arg, $t, -+ does not match the list of default-not-installed programs -+ ($no_install_progs_default) also recorded in $mk]], -+ 1) ;; -+esac -+ -+# Given the name of a variable containing a space-separated list of -+# install-by-default programs and the actual list do-not-install-by-default -+# programs, modify the former variable to reflect any "do-install" and -+# "don't-install" requests. -+# I.e., add any program name specified via --enable-install-program=..., and -+# remove any program name specified via --enable-no-install-program=... -+# Note how the second argument below is a literal, with "," separators. -+# That is required due to the way the macro works, and since the -+# corresponding ./configure option argument is comma-separated on input. -+gl_INCLUDE_EXCLUDE_PROG([optional_bin_progs], [arch,hostname,su]) -+ -+# Set INSTALL_SU if su installation has been requested via -+# --enable-install-program=su. -+AC_SUBST([INSTALL_SU]) -+case " $optional_bin_progs " in -+ *' su '*) INSTALL_SU=yes ;; -+ *) INSTALL_SU=no ;; -+esac -+ -+MAN=`echo "$optional_bin_progs "|sed 's/ /.1 /g;s/ $//'|tr -d '\\015\\012'` -+ -+# Change ginstall.1 to "install.h" in $MAN. -+MAN=`for m in $MAN; do test $m = ginstall.1 && m=install.1; echo $m; done \ -+ | tr '\015\012' ' '; echo` -+ -+# Remove [.1, since writing a portable rule for it in man/Makefile.am -+# is not practical. The sed LHS below uses the autoconf quadrigraph -+# representing '['. -+MAN=`echo "$MAN"|sed 's/\@<:@\.1//'` -+ -+OPTIONAL_BIN_PROGS=`echo "$optional_bin_progs "|sed 's/ /\$(EXEEXT) /g;s/ $//'` -+AC_SUBST([OPTIONAL_BIN_PROGS]) -+OPTIONAL_PKGLIB_PROGS=`echo "$optional_pkglib_progs " | sed 's/ $//'` -+AC_SUBST([OPTIONAL_PKGLIB_PROGS]) -+NO_INSTALL_PROGS_DEFAULT=$no_install_progs_default -+AC_SUBST([NO_INSTALL_PROGS_DEFAULT]) -+ -+AM_CONDITIONAL([CROSS_COMPILING], [test "$cross_compiling" = yes]) -+ -+# Arrange to rerun configure whenever the file, src/Makefile.am, -+# containing the list of program names changes. -+CONFIG_STATUS_DEPENDENCIES='$(top_srcdir)/src/Makefile.am' -+AC_SUBST([CONFIG_STATUS_DEPENDENCIES]) -+############################################################################ -+ -+AM_GNU_GETTEXT([external], [need-formatstring-macros]) -+AM_GNU_GETTEXT_VERSION([0.15]) -+ -+# For a test of uniq: it uses the $LOCALE_FR envvar. -+gt_LOCALE_FR -+ -+AC_CONFIG_FILES( -+ Makefile -+ doc/Makefile -+ lib/Makefile -+ man/Makefile -+ po/Makefile.in -+ src/Makefile -+ tests/Makefile -+ gnulib-tests/Makefile -+ ) -+AC_OUTPUT diff -urNp coreutils-8.0-orig/doc/coreutils.texi coreutils-8.0/doc/coreutils.texi --- coreutils-8.0-orig/doc/coreutils.texi 2009-09-29 15:27:54.000000000 +0200 +++ coreutils-8.0/doc/coreutils.texi 2009-10-07 10:04:27.000000000 +0200 @@ -14742,8 +14742,11 @@ to certain shells, etc.). @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}. - -@@ -14785,6 +14788,8 @@ environment variables except @env{TERM}, - @env{PATH} to a compiled-in default value. Change to @var{user}'s home - directory. Prepend @samp{-} to the shell's name, intended to make it - read its login startup file(s). -+Additionaly @env{DISPLAY} and @env{XAUTHORITY} environment variables -+are preserved as well for PAM functionality. - - @item -m - @itemx -p -@@ -14824,33 +14829,6 @@ Exit status: - 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 timeout invocation - @section @command{timeout}: Run a command with a time limit - -diff -urNp coreutils-8.0-orig/doc/coreutils.texi.orig coreutils-8.0/doc/coreutils.texi.orig ---- coreutils-8.0-orig/doc/coreutils.texi.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/doc/coreutils.texi.orig 2009-09-29 15:27:54.000000000 +0200 -@@ -0,0 +1,15835 @@ -+\input texinfo -+@c %**start of header -+@setfilename coreutils.info -+@settitle @sc{gnu} Coreutils -+ -+@c %**end of header -+ -+@include version.texi -+@include constants.texi -+ -+@c Define new indices. -+@defcodeindex op -+@defcodeindex fl -+ -+@c Put everything in one index (arbitrarily chosen to be the concept index). -+@syncodeindex fl cp -+@syncodeindex fn cp -+@syncodeindex ky cp -+@syncodeindex op cp -+@syncodeindex pg cp -+@syncodeindex vr cp -+ -+@dircategory Basics -+@direntry -+* Coreutils: (coreutils). Core GNU (file, text, shell) utilities. -+* Common options: (coreutils)Common options. Common options. -+* File permissions: (coreutils)File permissions. Access modes. -+* Date input formats: (coreutils)Date input formats. -+@end direntry -+ -+@c FIXME: the following need documentation -+@c * [: (coreutils)[ invocation. File/string tests. -+@c * pinky: (coreutils)pinky invocation. FIXME. -+@c * mktemp: (coreutils)mktemp invocation. FIXME. -+ -+@dircategory Individual utilities -+@direntry -+* arch: (coreutils)arch invocation. Print machine hardware name. -+* base64: (coreutils)base64 invocation. Base64 encode/decode data. -+* basename: (coreutils)basename invocation. Strip directory and suffix. -+* cat: (coreutils)cat invocation. Concatenate and write files. -+* chcon: (coreutils)chcon invocation. Change SELinux CTX of files. -+* chgrp: (coreutils)chgrp invocation. Change file groups. -+* chmod: (coreutils)chmod invocation. Change file permissions. -+* chown: (coreutils)chown invocation. Change file owners/groups. -+* chroot: (coreutils)chroot invocation. Specify the root directory. -+* cksum: (coreutils)cksum invocation. Print POSIX CRC checksum. -+* comm: (coreutils)comm invocation. Compare sorted files by line. -+* cp: (coreutils)cp invocation. Copy files. -+* csplit: (coreutils)csplit invocation. Split by context. -+* cut: (coreutils)cut invocation. Print selected parts of lines. -+* date: (coreutils)date invocation. Print/set system date and time. -+* dd: (coreutils)dd invocation. Copy and convert a file. -+* df: (coreutils)df invocation. Report file system disk usage. -+* dir: (coreutils)dir invocation. List directories briefly. -+* dircolors: (coreutils)dircolors invocation. Color setup for ls. -+* dirname: (coreutils)dirname invocation. Strip non-directory suffix. -+* du: (coreutils)du invocation. Report on disk usage. -+* echo: (coreutils)echo invocation. Print a line of text. -+* env: (coreutils)env invocation. Modify the environment. -+* expand: (coreutils)expand invocation. Convert tabs to spaces. -+* expr: (coreutils)expr invocation. Evaluate expressions. -+* factor: (coreutils)factor invocation. Print prime factors -+* false: (coreutils)false invocation. Do nothing, unsuccessfully. -+* fmt: (coreutils)fmt invocation. Reformat paragraph text. -+* fold: (coreutils)fold invocation. Wrap long input lines. -+* groups: (coreutils)groups invocation. Print group names a user is in. -+* head: (coreutils)head invocation. Output the first part of files. -+* hostid: (coreutils)hostid invocation. Print numeric host identifier. -+* hostname: (coreutils)hostname invocation. Print or set system name. -+* id: (coreutils)id invocation. Print user identity. -+* install: (coreutils)install invocation. Copy and change attributes. -+* join: (coreutils)join invocation. Join lines on a common field. -+* kill: (coreutils)kill invocation. Send a signal to processes. -+* link: (coreutils)link invocation. Make hard links between files. -+* ln: (coreutils)ln invocation. Make links between files. -+* logname: (coreutils)logname invocation. Print current login name. -+* ls: (coreutils)ls invocation. List directory contents. -+* md5sum: (coreutils)md5sum invocation. Print or check MD5 digests. -+* mkdir: (coreutils)mkdir invocation. Create directories. -+* mkfifo: (coreutils)mkfifo invocation. Create FIFOs (named pipes). -+* mknod: (coreutils)mknod invocation. Create special files. -+* mv: (coreutils)mv invocation. Rename files. -+* nice: (coreutils)nice invocation. Modify niceness. -+* nl: (coreutils)nl invocation. Number lines and write files. -+* nohup: (coreutils)nohup invocation. Immunize to hangups. -+* od: (coreutils)od invocation. Dump files in octal, etc. -+* paste: (coreutils)paste invocation. Merge lines of files. -+* pathchk: (coreutils)pathchk invocation. Check file name portability. -+* pr: (coreutils)pr invocation. Paginate or columnate files. -+* printenv: (coreutils)printenv invocation. Print environment variables. -+* printf: (coreutils)printf invocation. Format and print data. -+* ptx: (coreutils)ptx invocation. Produce permuted indexes. -+* pwd: (coreutils)pwd invocation. Print working directory. -+* readlink: (coreutils)readlink invocation. Print referent of a symlink. -+* rm: (coreutils)rm invocation. Remove files. -+* rmdir: (coreutils)rmdir invocation. Remove empty directories. -+* runcon: (coreutils)runcon invocation. Run in specified SELinux CTX. -+* seq: (coreutils)seq invocation. Print numeric sequences -+* sha1sum: (coreutils)sha1sum invocation. Print or check SHA-1 digests. -+* sha2: (coreutils)sha2 utilities. Print or check SHA-2 digests. -+* shred: (coreutils)shred invocation. Remove files more securely. -+* shuf: (coreutils)shuf invocation. Shuffling text files. -+* sleep: (coreutils)sleep invocation. Delay for a specified time. -+* sort: (coreutils)sort invocation. Sort text files. -+* split: (coreutils)split invocation. Split into fixed-size pieces. -+* stat: (coreutils)stat invocation. Report file(system) status. -+* stdbuf: (coreutils)stdbuf invocation. Modify stdio buffering. -+* stty: (coreutils)stty invocation. Print/change terminal settings. -+* su: (coreutils)su invocation. Modify user and group ID. -+* sum: (coreutils)sum invocation. Print traditional checksum. -+* sync: (coreutils)sync invocation. Synchronize memory and disk. -+* tac: (coreutils)tac invocation. Reverse files. -+* tail: (coreutils)tail invocation. Output the last part of files. -+* tee: (coreutils)tee invocation. Redirect to multiple files. -+* test: (coreutils)test invocation. File/string tests. -+* timeout: (coreutils)timeout invocation. Run with time limit. -+* touch: (coreutils)touch invocation. Change file timestamps. -+* tr: (coreutils)tr invocation. Translate characters. -+* true: (coreutils)true invocation. Do nothing, successfully. -+* truncate: (coreutils)truncate invocation. Shrink/extend size of a file. -+* tsort: (coreutils)tsort invocation. Topological sort. -+* tty: (coreutils)tty invocation. Print terminal name. -+* uname: (coreutils)uname invocation. Print system information. -+* unexpand: (coreutils)unexpand invocation. Convert spaces to tabs. -+* uniq: (coreutils)uniq invocation. Uniquify files. -+* unlink: (coreutils)unlink invocation. Removal via unlink(2). -+* uptime: (coreutils)uptime invocation. Print uptime and load. -+* users: (coreutils)users invocation. Print current user names. -+* vdir: (coreutils)vdir invocation. List directories verbosely. -+* wc: (coreutils)wc invocation. Line, word, and byte counts. -+* who: (coreutils)who invocation. Print who is logged in. -+* whoami: (coreutils)whoami invocation. Print effective user ID. -+* yes: (coreutils)yes invocation. Print a string indefinitely. -+@end direntry -+ -+@copying -+This manual documents version @value{VERSION} of the @sc{gnu} core -+utilities, including the standard programs for text and file manipulation. -+ -+Copyright @copyright{} 1994-1996, 2000-2009 Free Software Foundation, Inc. -+ -+@quotation -+Permission is granted to copy, distribute and/or modify this document -+under the terms of the GNU Free Documentation License, Version 1.3 or -+any later version published by the Free Software Foundation; with no -+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover -+Texts. A copy of the license is included in the section entitled ``GNU -+Free Documentation License''. -+@end quotation -+@end copying -+ -+@titlepage -+@title @sc{gnu} @code{Coreutils} -+@subtitle Core GNU utilities -+@subtitle for version @value{VERSION}, @value{UPDATED} -+@author David MacKenzie et al. -+ -+@page -+@vskip 0pt plus 1filll -+@insertcopying -+@end titlepage -+@shortcontents -+@contents -+ -+@ifnottex -+@node Top -+@top GNU Coreutils -+ -+@insertcopying -+@end ifnottex -+ -+@cindex core utilities -+@cindex text utilities -+@cindex shell utilities -+@cindex file utilities -+ -+@menu -+* Introduction:: Caveats, overview, and authors -+* Common options:: Common options -+* Output of entire files:: cat tac nl od base64 -+* Formatting file contents:: fmt pr fold -+* Output of parts of files:: head tail split csplit -+* Summarizing files:: wc sum cksum md5sum sha1sum sha2 -+* Operating on sorted files:: sort shuf uniq comm ptx tsort -+* Operating on fields:: cut paste join -+* Operating on characters:: tr expand unexpand -+* Directory listing:: ls dir vdir dircolors -+* Basic operations:: cp dd install mv rm shred -+* Special file types:: mkdir rmdir unlink mkfifo mknod ln link readlink -+* Changing file attributes:: chgrp chmod chown touch -+* Disk usage:: df du stat sync truncate -+* Printing text:: echo printf yes -+* Conditions:: false true test expr -+* Redirection:: tee -+* File name manipulation:: dirname basename pathchk -+* Working context:: pwd stty printenv tty -+* User information:: id logname whoami groups users who -+* System context:: date arch uname hostname hostid uptime -+* SELinux context:: chcon runcon -+* Modified command invocation:: chroot env nice nohup stdbuf su timeout -+* Process control:: kill -+* Delaying:: sleep -+* Numeric operations:: factor seq -+* File permissions:: Access modes -+* Date input formats:: Specifying date strings -+* Opening the software toolbox:: The software tools philosophy -+* GNU Free Documentation License:: Copying and sharing this manual -+* Concept index:: General index -+ -+@detailmenu -+ --- The Detailed Node Listing --- -+ -+Common Options -+ -+* Exit status:: Indicating program success or failure -+* Backup options:: Backup options -+* Block size:: Block size -+* Signal specifications:: Specifying signals -+* Disambiguating names and IDs:: chgrp and chown owner and group syntax -+* Random sources:: Sources of random data -+* Target directory:: Target directory -+* Trailing slashes:: Trailing slashes -+* Traversing symlinks:: Traversing symlinks to directories -+* Treating / specially:: Treating / specially -+* Standards conformance:: Standards conformance -+ -+Output of entire files -+ -+* cat invocation:: Concatenate and write files -+* tac invocation:: Concatenate and write files in reverse -+* nl invocation:: Number lines and write files -+* od invocation:: Write files in octal or other formats -+* base64 invocation:: Transform data into printable data -+ -+Formatting file contents -+ -+* fmt invocation:: Reformat paragraph text -+* pr invocation:: Paginate or columnate files for printing -+* fold invocation:: Wrap input lines to fit in specified width -+ -+Output of parts of files -+ -+* head invocation:: Output the first part of files -+* tail invocation:: Output the last part of files -+* split invocation:: Split a file into fixed-size pieces -+* csplit invocation:: Split a file into context-determined pieces -+ -+Summarizing files -+ -+* wc invocation:: Print newline, word, and byte counts -+* sum invocation:: Print checksum and block counts -+* cksum invocation:: Print CRC checksum and byte counts -+* md5sum invocation:: Print or check MD5 digests -+* sha1sum invocation:: Print or check SHA-1 digests -+* sha2 utilities:: Print or check SHA-2 digests -+ -+Operating on sorted files -+ -+* sort invocation:: Sort text files -+* shuf invocation:: Shuffle text files -+* uniq invocation:: Uniquify files -+* comm invocation:: Compare two sorted files line by line -+* ptx invocation:: Produce a permuted index of file contents -+* tsort invocation:: Topological sort -+ -+@command{ptx}: Produce permuted indexes -+ -+* General options in ptx:: Options which affect general program behavior -+* Charset selection in ptx:: Underlying character set considerations -+* Input processing in ptx:: Input fields, contexts, and keyword selection -+* Output formatting in ptx:: Types of output format, and sizing the fields -+* Compatibility in ptx:: The @acronym{GNU} extensions to @command{ptx} -+ -+Operating on fields -+ -+* cut invocation:: Print selected parts of lines -+* paste invocation:: Merge lines of files -+* join invocation:: Join lines on a common field -+ -+Operating on characters -+ -+* tr invocation:: Translate, squeeze, and/or delete characters -+* expand invocation:: Convert tabs to spaces -+* unexpand invocation:: Convert spaces to tabs -+ -+@command{tr}: Translate, squeeze, and/or delete characters -+ -+* Character sets:: Specifying sets of characters -+* Translating:: Changing one set of characters to another -+* Squeezing:: Squeezing repeats and deleting -+ -+Directory listing -+ -+* ls invocation:: List directory contents -+* dir invocation:: Briefly list directory contents -+* vdir invocation:: Verbosely list directory contents -+* dircolors invocation:: Color setup for @command{ls} -+ -+@command{ls}: List directory contents -+ -+* Which files are listed:: Which files are listed -+* What information is listed:: What information is listed -+* Sorting the output:: Sorting the output -+* Details about version sort:: More details about version sort -+* General output formatting:: General output formatting -+* Formatting the file names:: Formatting the file names -+ -+Basic operations -+ -+* cp invocation:: Copy files and directories -+* dd invocation:: Convert and copy a file -+* install invocation:: Copy files and set attributes -+* mv invocation:: Move (rename) files -+* rm invocation:: Remove files or directories -+* shred invocation:: Remove files more securely -+ -+Special file types -+ -+* link invocation:: Make a hard link via the link syscall -+* ln invocation:: Make links between files -+* mkdir invocation:: Make directories -+* mkfifo invocation:: Make FIFOs (named pipes) -+* mknod invocation:: Make block or character special files -+* readlink invocation:: Print value of a symlink or canonical file name -+* rmdir invocation:: Remove empty directories -+* unlink invocation:: Remove files via unlink syscall -+ -+Changing file attributes -+ -+* chown invocation:: Change file owner and group -+* chgrp invocation:: Change group ownership -+* chmod invocation:: Change access permissions -+* touch invocation:: Change file timestamps -+ -+Disk usage -+ -+* df invocation:: Report file system disk space usage -+* du invocation:: Estimate file space usage -+* stat invocation:: Report file or file system status -+* sync invocation:: Synchronize data on disk with memory -+* truncate invocation:: Shrink or extend the size of a file -+ -+Printing text -+ -+* echo invocation:: Print a line of text -+* printf invocation:: Format and print data -+* yes invocation:: Print a string until interrupted -+ -+Conditions -+ -+* false invocation:: Do nothing, unsuccessfully -+* true invocation:: Do nothing, successfully -+* test invocation:: Check file types and compare values -+* expr invocation:: Evaluate expressions -+ -+@command{test}: Check file types and compare values -+ -+* File type tests:: File type tests -+* Access permission tests:: Access permission tests -+* File characteristic tests:: File characteristic tests -+* String tests:: String tests -+* Numeric tests:: Numeric tests -+ -+@command{expr}: Evaluate expression -+ -+* String expressions:: + : match substr index length -+* Numeric expressions:: + - * / % -+* Relations for expr:: | & < <= = == != >= > -+* Examples of expr:: Examples of using @command{expr} -+ -+Redirection -+ -+* tee invocation:: Redirect output to multiple files or processes -+ -+File name manipulation -+ -+* basename invocation:: Strip directory and suffix from a file name -+* dirname invocation:: Strip non-directory suffix from a file name -+* pathchk invocation:: Check file name validity and portability -+ -+Working context -+ -+* pwd invocation:: Print working directory -+* stty invocation:: Print or change terminal characteristics -+* printenv invocation:: Print all or some environment variables -+* tty invocation:: Print file name of terminal on standard input -+ -+@command{stty}: Print or change terminal characteristics -+ -+* Control:: Control settings -+* Input:: Input settings -+* Output:: Output settings -+* Local:: Local settings -+* Combination:: Combination settings -+* Characters:: Special characters -+* Special:: Special settings -+ -+User information -+ -+* id invocation:: Print user identity -+* logname invocation:: Print current login name -+* whoami invocation:: Print effective user ID -+* groups invocation:: Print group names a user is in -+* users invocation:: Print login names of users currently logged in -+* who invocation:: Print who is currently logged in -+ -+System context -+ -+* arch invocation:: Print machine hardware name -+* date invocation:: Print or set system date and time -+* uname invocation:: Print system information -+* hostname invocation:: Print or set system name -+* hostid invocation:: Print numeric host identifier -+* uptime invocation:: Print system uptime and load -+ -+@command{date}: Print or set system date and time -+ -+* Time conversion specifiers:: %[HIklMNpPrRsSTXzZ] -+* Date conversion specifiers:: %[aAbBcCdDeFgGhjmuUVwWxyY] -+* Literal conversion specifiers:: %[%nt] -+* Padding and other flags:: Pad with zeros, spaces, etc. -+* Setting the time:: Changing the system clock -+* Options for date:: Instead of the current time -+* Date input formats:: Specifying date strings -+* Examples of date:: Examples -+ -+SELinux context -+ -+* chcon invocation:: Change SELinux context of file -+* runcon invocation:: Run a command in specified SELinux context -+ -+Modified command invocation -+ -+* chroot invocation:: Run a command with a different root directory -+* env invocation:: Run a command in a modified environment -+* nice invocation:: Run a command with modified niceness -+* nohup invocation:: Run a command immune to hangups -+* stdbuf invocation:: Run a command with modified I/O buffering -+* su invocation:: Run a command with substitute user and group ID -+* timeout invocation:: Run a command with a time limit -+ -+Process control -+ -+* kill invocation:: Sending a signal to processes. -+ -+Delaying -+ -+* sleep invocation:: Delay for a specified time -+ -+Numeric operations -+ -+* factor invocation:: Print prime factors -+* seq invocation:: Print numeric sequences -+ -+File permissions -+ -+* Mode Structure:: Structure of file mode bits -+* Symbolic Modes:: Mnemonic representation of file mode bits -+* Numeric Modes:: File mode bits as octal numbers -+* Directory Setuid and Setgid:: Set-user-ID and set-group-ID on directories -+ -+Date input formats -+ -+* General date syntax:: Common rules -+* Calendar date items:: 19 Dec 1994 -+* Time of day items:: 9:20pm -+* Time zone items:: @sc{est}, @sc{pdt}, @sc{gmt} -+* Day of week items:: Monday and others -+* Relative items in date strings:: next tuesday, 2 years ago -+* Pure numbers in date strings:: 19931219, 1440 -+* Seconds since the Epoch:: @@1078100502 -+* Specifying time zone rules:: TZ="America/New_York", TZ="UTC0" -+* Authors of get_date:: Bellovin, Eggert, Salz, Berets, et al -+ -+Opening the software toolbox -+ -+* Toolbox introduction:: Toolbox introduction -+* I/O redirection:: I/O redirection -+* The who command:: The @command{who} command -+* The cut command:: The @command{cut} command -+* The sort command:: The @command{sort} command -+* The uniq command:: The @command{uniq} command -+* Putting the tools together:: Putting the tools together -+ -+Copying This Manual -+ -+* GNU Free Documentation License:: Copying and sharing this manual -+ -+@end detailmenu -+@end menu -+ -+ -+@node Introduction -+@chapter Introduction -+ -+This manual is a work in progress: many sections make no attempt to explain -+basic concepts in a way suitable for novices. Thus, if you are interested, -+please get involved in improving this manual. The entire @sc{gnu} community -+will benefit. -+ -+@cindex @acronym{POSIX} -+The @sc{gnu} utilities documented here are mostly compatible with the -+@acronym{POSIX} standard. -+@cindex bugs, reporting -+Please report bugs to @email{bug-coreutils@@gnu.org}. Remember -+to include the version number, machine architecture, input files, and -+any other information needed to reproduce the bug: your input, what you -+expected, what you got, and why it is wrong. Diffs are welcome, but -+please include a description of the problem as well, since this is -+sometimes difficult to infer. @xref{Bugs, , , gcc, Using and Porting GNU CC}. -+ -+@cindex Berry, K. -+@cindex Paterson, R. -+@cindex Stallman, R. -+@cindex Pinard, F. -+@cindex MacKenzie, D. -+@cindex Meyering, J. -+@cindex Youmans, B. -+This manual was originally derived from the Unix man pages in the -+distributions, which were written by David MacKenzie and updated by Jim -+Meyering. What you are reading now is the authoritative documentation -+for these utilities; the man pages are no longer being maintained. The -+original @command{fmt} man page was written by Ross Paterson. Fran@,{c}ois -+Pinard did the initial conversion to Texinfo format. Karl Berry did the -+indexing, some reorganization, and editing of the results. Brian -+Youmans of the Free Software Foundation office staff combined the -+manuals for textutils, fileutils, and sh-utils to produce the present -+omnibus manual. Richard Stallman contributed his usual invaluable -+insights to the overall process. -+ -+@node Common options -+@chapter Common options -+ -+@macro optBackup -+@item -b -+@itemx @w{@kbd{--backup}[=@var{method}]} -+@opindex -b -+@opindex --backup -+@vindex VERSION_CONTROL -+@cindex backups, making -+@xref{Backup options}. -+Make a backup of each file that would otherwise be overwritten or removed. -+@end macro -+ -+@macro optBackupSuffix -+@item -S @var{suffix} -+@itemx --suffix=@var{suffix} -+@opindex -S -+@opindex --suffix -+Append @var{suffix} to each backup file made with @option{-b}. -+@xref{Backup options}. -+@end macro -+ -+@macro optTargetDirectory -+@item -t @var{directory} -+@itemx @w{@kbd{--target-directory}=@var{directory}} -+@opindex -t -+@opindex --target-directory -+@cindex target directory -+@cindex destination directory -+Specify the destination @var{directory}. -+@xref{Target directory}. -+@end macro -+ -+@macro optNoTargetDirectory -+@item -T -+@itemx --no-target-directory -+@opindex -T -+@opindex --no-target-directory -+@cindex target directory -+@cindex destination directory -+Do not treat the last operand specially when it is a directory or a -+symbolic link to a directory. @xref{Target directory}. -+@end macro -+ -+@macro optSi -+@itemx --si -+@opindex --si -+@cindex SI output -+Append an SI-style abbreviation to each size, such as @samp{M} for -+megabytes. Powers of 1000 are used, not 1024; @samp{M} stands for -+1,000,000 bytes. This option is equivalent to -+@option{--block-size=si}. Use the @option{-h} or -+@option{--human-readable} option if -+you prefer powers of 1024. -+@end macro -+ -+@macro optHumanReadable -+@item -h -+@itemx --human-readable -+@opindex -h -+@opindex --human-readable -+@cindex human-readable output -+Append a size letter to each size, such as @samp{M} for mebibytes. -+Powers of 1024 are used, not 1000; @samp{M} stands for 1,048,576 bytes. -+This option is equivalent to @option{--block-size=human-readable}. -+Use the @option{--si} option if you prefer powers of 1000. -+@end macro -+ -+@macro optStripTrailingSlashes -+@itemx @w{@kbd{--strip-trailing-slashes}} -+@opindex --strip-trailing-slashes -+@cindex stripping trailing slashes -+Remove any trailing slashes from each @var{source} argument. -+@xref{Trailing slashes}. -+@end macro -+ -+@macro mayConflictWithShellBuiltIn{cmd} -+@cindex conflicts with shell built-ins -+@cindex built-in shell commands, conflicts with -+Due to shell aliases and built-in @command{\cmd\} command, using an -+unadorned @command{\cmd\} interactively or in a script may get you -+different functionality than that described here. Invoke it via -+@command{env} (i.e., @code{env \cmd\ @dots{}}) to avoid interference -+from the shell. -+ -+@end macro -+ -+@macro multiplierSuffixes{varName} -+@var{\varName\} may be, or may be an integer optionally followed by, -+one of the following multiplicative suffixes: -+@example -+@samp{b} => 512 ("blocks") -+@samp{KB} => 1000 (KiloBytes) -+@samp{K} => 1024 (KibiBytes) -+@samp{MB} => 1000*1000 (MegaBytes) -+@samp{M} => 1024*1024 (MebiBytes) -+@samp{GB} => 1000*1000*1000 (GigaBytes) -+@samp{G} => 1024*1024*1024 (GibiBytes) -+@end example -+and so on for @samp{T}, @samp{P}, @samp{E}, @samp{Z}, and @samp{Y}. -+@end macro -+ -+@c FIXME: same as above, but no ``blocks'' line. -+@macro multiplierSuffixesNoBlocks{varName} -+@var{\varName\} may be, or may be an integer optionally followed by, -+one of the following multiplicative suffixes: -+@example -+@samp{KB} => 1000 (KiloBytes) -+@samp{K} => 1024 (KibiBytes) -+@samp{MB} => 1000*1000 (MegaBytes) -+@samp{M} => 1024*1024 (MebiBytes) -+@samp{GB} => 1000*1000*1000 (GigaBytes) -+@samp{G} => 1024*1024*1024 (GibiBytes) -+@end example -+and so on for @samp{T}, @samp{P}, @samp{E}, @samp{Z}, and @samp{Y}. -+@end macro -+ -+@cindex common options -+ -+Certain options are available in all of these programs. Rather than -+writing identical descriptions for each of the programs, they are -+described here. (In fact, every @sc{gnu} program accepts (or should accept) -+these options.) -+ -+@vindex POSIXLY_CORRECT -+Normally options and operands can appear in any order, and programs act -+as if all the options appear before any operands. For example, -+@samp{sort -r passwd -t :} acts like @samp{sort -r -t : passwd}, since -+@samp{:} is an option-argument of @option{-t}. However, if the -+@env{POSIXLY_CORRECT} environment variable is set, options must appear -+before operands, unless otherwise specified for a particular command. -+ -+A few programs can usefully have trailing operands with leading -+@samp{-}. With such a program, options must precede operands even if -+@env{POSIXLY_CORRECT} is not set, and this fact is noted in the -+program description. For example, the @command{env} command's options -+must appear before its operands, since in some cases the operands -+specify a command that itself contains options. -+ -+Most programs that accept long options recognize unambiguous -+abbreviations of those options. For example, @samp{rmdir -+--ignore-fail-on-non-empty} can be invoked as @samp{rmdir -+--ignore-fail} or even @samp{rmdir --i}. Ambiguous options, such as -+@samp{ls --h}, are identified as such. -+ -+Some of these programs recognize the @option{--help} and @option{--version} -+options only when one of them is the sole command line argument. For -+these programs, abbreviations of the long options are not always recognized. -+ -+@table @samp -+ -+@item --help -+@opindex --help -+@cindex help, online -+Print a usage message listing all available options, then exit successfully. -+ -+@item --version -+@opindex --version -+@cindex version number, finding -+Print the version number, then exit successfully. -+ -+@item -- -+@opindex -- -+@cindex option delimiter -+Delimit the option list. Later arguments, if any, are treated as -+operands even if they begin with @samp{-}. For example, @samp{sort -- -+-r} reads from the file named @file{-r}. -+ -+@end table -+ -+@cindex standard input -+@cindex standard output -+A single @samp{-} operand is not really an option, though it looks like one. It -+stands for standard input, or for standard output if that is clear from -+the context. For example, @samp{sort -} reads from standard input, -+and is equivalent to plain @samp{sort}, and @samp{tee -} writes an -+extra copy of its input to standard output. Unless otherwise -+specified, @samp{-} can appear as any operand that requires a file -+name. -+ -+@menu -+* Exit status:: Indicating program success or failure. -+* Backup options:: -b -S, in some programs. -+* Block size:: BLOCK_SIZE and --block-size, in some programs. -+* Signal specifications:: Specifying signals using the --signal option. -+* Disambiguating names and IDs:: chgrp and chown owner and group syntax -+* Random sources:: --random-source, in some programs. -+* Target directory:: Specifying a target directory, in some programs. -+* Trailing slashes:: --strip-trailing-slashes, in some programs. -+* Traversing symlinks:: -H, -L, or -P, in some programs. -+* Treating / specially:: --preserve-root and --no-preserve-root. -+* Special built-in utilities:: @command{break}, @command{:}, @command{eval}, @dots{} -+* Standards conformance:: Conformance to the @acronym{POSIX} standard. -+@end menu -+ -+ -+@node Exit status -+@section Exit status -+ -+@macro exitstatus -+An exit status of zero indicates success, -+and a nonzero value indicates failure. -+@end macro -+ -+Nearly every command invocation yields an integral @dfn{exit status} -+that can be used to change how other commands work. -+For the vast majority of commands, an exit status of zero indicates -+success. Failure is indicated by a nonzero value---typically -+@samp{1}, though it may differ on unusual platforms as @acronym{POSIX} -+requires only that it be nonzero. -+ -+However, some of the programs documented here do produce -+other exit status values and a few associate different -+meanings with the values @samp{0} and @samp{1}. -+Here are some of the exceptions: -+@command{chroot}, @command{env}, @command{expr}, @command{nice}, -+@command{nohup}, @command{printenv}, @command{sort}, @command{stdbuf}, -+@command{su}, @command{test}, @command{timeout}, @command{tty}. -+ -+ -+@node Backup options -+@section Backup options -+ -+@cindex backup options -+ -+Some @sc{gnu} programs (at least @command{cp}, @command{install}, -+@command{ln}, and @command{mv}) optionally make backups of files -+before writing new versions. -+These options control the details of these backups. The options are also -+briefly mentioned in the descriptions of the particular programs. -+ -+@table @samp -+ -+@item -b -+@itemx @w{@kbd{--backup}[=@var{method}]} -+@opindex -b -+@opindex --backup -+@vindex VERSION_CONTROL -+@cindex backups, making -+Make a backup of each file that would otherwise be overwritten or removed. -+Without this option, the original versions are destroyed. -+Use @var{method} to determine the type of backups to make. -+When this option is used but @var{method} is not specified, -+then the value of the @env{VERSION_CONTROL} -+environment variable is used. And if @env{VERSION_CONTROL} is not set, -+the default backup type is @samp{existing}. -+ -+Note that the short form of this option, @option{-b} does not accept any -+argument. Using @option{-b} is equivalent to using @option{--backup=existing}. -+ -+@vindex version-control @r{Emacs variable} -+This option corresponds to the Emacs variable @samp{version-control}; -+the values for @var{method} are the same as those used in Emacs. -+This option also accepts more descriptive names. -+The valid @var{method}s are (unique abbreviations are accepted): -+ -+@table @samp -+@item none -+@itemx off -+@opindex none @r{backup method} -+Never make backups. -+ -+@item numbered -+@itemx t -+@opindex numbered @r{backup method} -+Always make numbered backups. -+ -+@item existing -+@itemx nil -+@opindex existing @r{backup method} -+Make numbered backups of files that already have them, simple backups -+of the others. -+ -+@item simple -+@itemx never -+@opindex simple @r{backup method} -+Always make simple backups. Please note @samp{never} is not to be -+confused with @samp{none}. -+ -+@end table -+ -+@item -S @var{suffix} -+@itemx --suffix=@var{suffix} -+@opindex -S -+@opindex --suffix -+@cindex backup suffix -+@vindex SIMPLE_BACKUP_SUFFIX -+Append @var{suffix} to each backup file made with @option{-b}. If this -+option is not specified, the value of the @env{SIMPLE_BACKUP_SUFFIX} -+environment variable is used. And if @env{SIMPLE_BACKUP_SUFFIX} is not -+set, the default is @samp{~}, just as in Emacs. -+ -+@end table -+ -+@node Block size -+@section Block size -+ -+@cindex block size -+ -+Some @sc{gnu} programs (at least @command{df}, @command{du}, and -+@command{ls}) display sizes in ``blocks''. You can adjust the block size -+and method of display to make sizes easier to read. The block size -+used for display is independent of any file system block size. -+Fractional block counts are rounded up to the nearest integer. -+ -+@opindex --block-size=@var{size} -+@vindex BLOCKSIZE -+@vindex BLOCK_SIZE -+@vindex DF_BLOCK_SIZE -+@vindex DU_BLOCK_SIZE -+@vindex LS_BLOCK_SIZE -+@vindex POSIXLY_CORRECT@r{, and block size} -+ -+The default block size is chosen by examining the following environment -+variables in turn; the first one that is set determines the block size. -+ -+@table @code -+ -+@item DF_BLOCK_SIZE -+This specifies the default block size for the @command{df} command. -+Similarly, @env{DU_BLOCK_SIZE} specifies the default for @command{du} and -+@env{LS_BLOCK_SIZE} for @command{ls}. -+ -+@item BLOCK_SIZE -+This specifies the default block size for all three commands, if the -+above command-specific environment variables are not set. -+ -+@item BLOCKSIZE -+This specifies the default block size for all values that are normally -+printed as blocks, if neither @env{BLOCK_SIZE} nor the above -+command-specific environment variables are set. Unlike the other -+environment variables, @env{BLOCKSIZE} does not affect values that are -+normally printed as byte counts, e.g., the file sizes contained in -+@code{ls -l} output. -+ -+@item POSIXLY_CORRECT -+If neither @env{@var{command}_BLOCK_SIZE}, nor @env{BLOCK_SIZE}, nor -+@env{BLOCKSIZE} is set, but this variable is set, the block size -+defaults to 512. -+ -+@end table -+ -+If none of the above environment variables are set, the block size -+currently defaults to 1024 bytes in most contexts, but this number may -+change in the future. For @command{ls} file sizes, the block size -+defaults to 1 byte. -+ -+@cindex human-readable output -+@cindex SI output -+ -+A block size specification can be a positive integer specifying the number -+of bytes per block, or it can be @code{human-readable} or @code{si} to -+select a human-readable format. Integers may be followed by suffixes -+that are upward compatible with the -+@uref{http://www.bipm.fr/enus/3_SI/si-prefixes.html, SI prefixes} -+for decimal multiples and with the -+@uref{http://physics.nist.gov/cuu/Units/binary.html, IEC 60027-2 -+prefixes for binary multiples}. -+ -+With human-readable formats, output sizes are followed by a size letter -+such as @samp{M} for megabytes. @code{BLOCK_SIZE=human-readable} uses -+powers of 1024; @samp{M} stands for 1,048,576 bytes. -+@code{BLOCK_SIZE=si} is similar, but uses powers of 1000 and appends -+@samp{B}; @samp{MB} stands for 1,000,000 bytes. -+ -+@vindex LC_NUMERIC -+A block size specification preceded by @samp{'} causes output sizes to -+be displayed with thousands separators. The @env{LC_NUMERIC} locale -+specifies the thousands separator and grouping. For example, in an -+American English locale, @samp{--block-size="'1kB"} would cause a size -+of 1234000 bytes to be displayed as @samp{1,234}. In the default C -+locale, there is no thousands separator so a leading @samp{'} has no -+effect. -+ -+An integer block size can be followed by a suffix to specify a -+multiple of that size. A bare size letter, -+or one followed by @samp{iB}, specifies -+a multiple using powers of 1024. A size letter followed by @samp{B} -+specifies powers of 1000 instead. For example, @samp{1M} and -+@samp{1MiB} are equivalent to @samp{1048576}, whereas @samp{1MB} is -+equivalent to @samp{1000000}. -+ -+A plain suffix without a preceding integer acts as if @samp{1} were -+prepended, except that it causes a size indication to be appended to -+the output. For example, @samp{--block-size="kB"} displays 3000 as -+@samp{3kB}. -+ -+The following suffixes are defined. Large sizes like @code{1Y} -+may be rejected by your computer due to limitations of its arithmetic. -+ -+@table @samp -+@item kB -+@cindex kilobyte, definition of -+kilobyte: @math{10^3 = 1000}. -+@item k -+@itemx K -+@itemx KiB -+@cindex kibibyte, definition of -+kibibyte: @math{2^{10} = 1024}. @samp{K} is special: the SI prefix is -+@samp{k} and the IEC 60027-2 prefix is @samp{Ki}, but tradition and -+@acronym{POSIX} use @samp{k} to mean @samp{KiB}. -+@item MB -+@cindex megabyte, definition of -+megabyte: @math{10^6 = 1,000,000}. -+@item M -+@itemx MiB -+@cindex mebibyte, definition of -+mebibyte: @math{2^{20} = 1,048,576}. -+@item GB -+@cindex gigabyte, definition of -+gigabyte: @math{10^9 = 1,000,000,000}. -+@item G -+@itemx GiB -+@cindex gibibyte, definition of -+gibibyte: @math{2^{30} = 1,073,741,824}. -+@item TB -+@cindex terabyte, definition of -+terabyte: @math{10^{12} = 1,000,000,000,000}. -+@item T -+@itemx TiB -+@cindex tebibyte, definition of -+tebibyte: @math{2^{40} = 1,099,511,627,776}. -+@item PB -+@cindex petabyte, definition of -+petabyte: @math{10^{15} = 1,000,000,000,000,000}. -+@item P -+@itemx PiB -+@cindex pebibyte, definition of -+pebibyte: @math{2^{50} = 1,125,899,906,842,624}. -+@item EB -+@cindex exabyte, definition of -+exabyte: @math{10^{18} = 1,000,000,000,000,000,000}. -+@item E -+@itemx EiB -+@cindex exbibyte, definition of -+exbibyte: @math{2^{60} = 1,152,921,504,606,846,976}. -+@item ZB -+@cindex zettabyte, definition of -+zettabyte: @math{10^{21} = 1,000,000,000,000,000,000,000} -+@item Z -+@itemx ZiB -+@math{2^{70} = 1,180,591,620,717,411,303,424}. -+(@samp{Zi} is a @acronym{GNU} extension to IEC 60027-2.) -+@item YB -+@cindex yottabyte, definition of -+yottabyte: @math{10^{24} = 1,000,000,000,000,000,000,000,000}. -+@item Y -+@itemx YiB -+@math{2^{80} = 1,208,925,819,614,629,174,706,176}. -+(@samp{Yi} is a @acronym{GNU} extension to IEC 60027-2.) -+@end table -+ -+@opindex -k -+@opindex -h -+@opindex --block-size -+@opindex --human-readable -+@opindex --si -+ -+Block size defaults can be overridden by an explicit -+@option{--block-size=@var{size}} option. The @option{-k} -+option is equivalent to @option{--block-size=1K}, which -+is the default unless the @env{POSIXLY_CORRECT} environment variable is -+set. The @option{-h} or @option{--human-readable} option is equivalent to -+@option{--block-size=human-readable}. The @option{--si} option is -+equivalent to @option{--block-size=si}. -+ -+@node Signal specifications -+@section Signal specifications -+@cindex signals, specifying -+ -+A @var{signal} may be a signal name like @samp{HUP}, or a signal -+number like @samp{1}, or an exit status of a process terminated by the -+signal. A signal name can be given in canonical form or prefixed by -+@samp{SIG}. The case of the letters is ignored. The following signal names -+and numbers are supported on all @acronym{POSIX} compliant systems: -+ -+@table @samp -+@item HUP -+1. Hangup. -+@item INT -+2. Terminal interrupt. -+@item QUIT -+3. Terminal quit. -+@item ABRT -+6. Process abort. -+@item KILL -+9. Kill (cannot be caught or ignored). -+@item ALRM -+14. Alarm Clock. -+@item TERM -+15. Termination. -+@end table -+ -+@noindent -+Other supported signal names have system-dependent corresponding -+numbers. All systems conforming to @acronym{POSIX} 1003.1-2001 also -+support the following signals: -+ -+@table @samp -+@item BUS -+Access to an undefined portion of a memory object. -+@item CHLD -+Child process terminated, stopped, or continued. -+@item CONT -+Continue executing, if stopped. -+@item FPE -+Erroneous arithmetic operation. -+@item ILL -+Illegal Instruction. -+@item PIPE -+Write on a pipe with no one to read it. -+@item SEGV -+Invalid memory reference. -+@item STOP -+Stop executing (cannot be caught or ignored). -+@item TSTP -+Terminal stop. -+@item TTIN -+Background process attempting read. -+@item TTOU -+Background process attempting write. -+@item URG -+High bandwidth data is available at a socket. -+@item USR1 -+User-defined signal 1. -+@item USR2 -+User-defined signal 2. -+@end table -+ -+@noindent -+@acronym{POSIX} 1003.1-2001 systems that support the @acronym{XSI} extension -+also support the following signals: -+ -+@table @samp -+@item POLL -+Pollable event. -+@item PROF -+Profiling timer expired. -+@item SYS -+Bad system call. -+@item TRAP -+Trace/breakpoint trap. -+@item VTALRM -+Virtual timer expired. -+@item XCPU -+CPU time limit exceeded. -+@item XFSZ -+File size limit exceeded. -+@end table -+ -+@noindent -+@acronym{POSIX} 1003.1-2001 systems that support the @acronym{XRT} extension -+also support at least eight real-time signals called @samp{RTMIN}, -+@samp{RTMIN+1}, @dots{}, @samp{RTMAX-1}, @samp{RTMAX}. -+ -+@node Disambiguating names and IDs -+@section chown and chgrp: Disambiguating user names and IDs -+@cindex user names, disambiguating -+@cindex user IDs, disambiguating -+@cindex group names, disambiguating -+@cindex group IDs, disambiguating -+@cindex disambiguating group names and IDs -+ -+Since the @var{owner} and @var{group} arguments to @command{chown} and -+@command{chgrp} may be specified as names or numeric IDs, there is an -+apparent ambiguity. -+What if a user or group @emph{name} is a string of digits? -+@footnote{Using a number as a user name is common in some environments.} -+Should the command interpret it as a user name or as an ID? -+@acronym{POSIX} requires that @command{chown} and @command{chgrp} -+first attempt to resolve the specified string as a name, and -+only once that fails, then try to interpret it as an ID. -+This is troublesome when you want to specify a numeric ID, say 42, -+and it must work even in a pathological situation where -+@samp{42} is a user name that maps to some other user ID, say 1000. -+Simply invoking @code{chown 42 F}, will set @file{F}s owner ID to -+1000---not what you intended. -+ -+GNU @command{chown} and @command{chgrp} provide a way to work around this, -+that at the same time may result in a significant performance improvement -+by eliminating a database look-up. -+Simply precede each numeric user ID and/or group ID with a @samp{+}, -+in order to force its interpretation as an integer: -+ -+@example -+chown +42 F -+chgrp +$numeric_group_id another-file -+chown +0:+0 / -+@end example -+ -+GNU @command{chown} and @command{chgrp} -+skip the name look-up process for each @samp{+}-prefixed string, -+because a string containing @samp{+} is never a valid user or group name. -+This syntax is accepted on most common Unix systems, but not on Solaris 10. -+ -+@node Random sources -+@section Sources of random data -+ -+@cindex random sources -+ -+The @command{shuf}, @command{shred}, and @command{sort} commands -+sometimes need random data to do their work. For example, @samp{sort -+-R} must choose a hash function at random, and it needs random data to -+make this selection. -+ -+By default these commands use an internal pseudorandom generator -+initialized by a small amount of entropy, but can be directed to use -+an external source with the @option{--random-source=@var{file}} option. -+An error is reported if @var{file} does not contain enough bytes. -+ -+For example, the device file @file{/dev/urandom} could be used as the -+source of random data. Typically, this device gathers environmental -+noise from device drivers and other sources into an entropy pool, and -+uses the pool to generate random bits. If the pool is short of data, -+the device reuses the internal pool to produce more bits, using a -+cryptographically secure pseudorandom number generator. But be aware -+that this device is not designed for bulk random data generation -+and is relatively slow. -+ -+@file{/dev/urandom} suffices for most practical uses, but applications -+requiring high-value or long-term protection of private data may -+require an alternate data source like @file{/dev/random} or -+@file{/dev/arandom}. The set of available sources depends on your -+operating system. -+ -+To reproduce the results of an earlier invocation of a command, you -+can save some random data into a file and then use that file as the -+random source in earlier and later invocations of the command. -+ -+@node Target directory -+@section Target directory -+ -+@cindex target directory -+ -+The @command{cp}, @command{install}, @command{ln}, and @command{mv} -+commands normally treat the last operand specially when it is a -+directory or a symbolic link to a directory. For example, @samp{cp -+source dest} is equivalent to @samp{cp source dest/source} if -+@file{dest} is a directory. Sometimes this behavior is not exactly -+what is wanted, so these commands support the following options to -+allow more fine-grained control: -+ -+@table @samp -+ -+@item -T -+@itemx --no-target-directory -+@opindex --no-target-directory -+@cindex target directory -+@cindex destination directory -+Do not treat the last operand specially when it is a directory or a -+symbolic link to a directory. This can help avoid race conditions in -+programs that operate in a shared area. For example, when the command -+@samp{mv /tmp/source /tmp/dest} succeeds, there is no guarantee that -+@file{/tmp/source} was renamed to @file{/tmp/dest}: it could have been -+renamed to @file{/tmp/dest/source} instead, if some other process -+created @file{/tmp/dest} as a directory. However, if @file{mv -+-T /tmp/source /tmp/dest} succeeds, there is no -+question that @file{/tmp/source} was renamed to @file{/tmp/dest}. -+ -+In the opposite situation, where you want the last operand to be -+treated as a directory and want a diagnostic otherwise, you can use -+the @option{--target-directory} (@option{-t}) option. -+ -+@item -t @var{directory} -+@itemx @w{@kbd{--target-directory}=@var{directory}} -+@opindex --target-directory -+@cindex target directory -+@cindex destination directory -+Use @var{directory} as the directory component of each destination -+file name. -+ -+The interface for most programs is that after processing options and a -+finite (possibly zero) number of fixed-position arguments, the remaining -+argument list is either expected to be empty, or is a list of items -+(usually files) that will all be handled identically. The @command{xargs} -+program is designed to work well with this convention. -+ -+The commands in the @command{mv}-family are unusual in that they take -+a variable number of arguments with a special case at the @emph{end} -+(namely, the target directory). This makes it nontrivial to perform some -+operations, e.g., ``move all files from here to ../d/'', because -+@code{mv * ../d/} might exhaust the argument space, and @code{ls | xargs ...} -+doesn't have a clean way to specify an extra final argument for each -+invocation of the subject command. (It can be done by going through a -+shell command, but that requires more human labor and brain power than -+it should.) -+ -+The @w{@kbd{--target-directory}} (@option{-t}) option allows the @command{cp}, -+@command{install}, @command{ln}, and @command{mv} programs to be used -+conveniently with @command{xargs}. For example, you can move the files -+from the current directory to a sibling directory, @code{d} like this: -+ -+@smallexample -+ls | xargs mv -t ../d -- -+@end smallexample -+ -+However, this doesn't move files whose names begin with @samp{.}. -+If you use the @sc{gnu} @command{find} program, you can move those -+files too, with this command: -+ -+@example -+find . -mindepth 1 -maxdepth 1 \ -+ | xargs mv -t ../d -+@end example -+ -+But both of the above approaches fail if there are no files in the -+current directory, or if any file has a name containing a blank or -+some other special characters. -+The following example removes those limitations and requires both -+@sc{gnu} @command{find} and @sc{gnu} @command{xargs}: -+ -+@example -+find . -mindepth 1 -maxdepth 1 -print0 \ -+ | xargs --null --no-run-if-empty \ -+ mv -t ../d -+@end example -+ -+@end table -+ -+@noindent -+The @option{--target-directory} (@option{-t}) and -+@option{--no-target-directory} (@option{-T}) -+options cannot be combined. -+ -+@node Trailing slashes -+@section Trailing slashes -+ -+@cindex trailing slashes -+ -+Some @sc{gnu} programs (at least @command{cp} and @command{mv}) allow you to -+remove any trailing slashes from each @var{source} argument before -+operating on it. The @w{@kbd{--strip-trailing-slashes}} option enables -+this behavior. -+ -+This is useful when a @var{source} argument may have a trailing slash and -+@c FIXME: mv's behavior in this case is system-dependent -+specify a symbolic link to a directory. This scenario is in fact rather -+common because some shells can automatically append a trailing slash when -+performing file name completion on such symbolic links. Without this -+option, @command{mv}, for example, (via the system's rename function) must -+interpret a trailing slash as a request to dereference the symbolic link -+and so must rename the indirectly referenced @emph{directory} and not -+the symbolic link. Although it may seem surprising that such behavior -+be the default, it is required by @acronym{POSIX} and is consistent with -+other parts of that standard. -+ -+@node Traversing symlinks -+@section Traversing symlinks -+ -+@cindex symbolic link to directory, controlling traversal of -+ -+The following options modify how @command{chown} and @command{chgrp} -+@c FIXME: note that `du' has these options, too, but they have slightly -+@c different meaning. -+traverse a hierarchy when the @option{--recursive} (@option{-R}) -+option is also specified. -+If more than one of the following options is specified, only the final -+one takes effect. -+These options specify whether processing a symbolic link to a directory -+entails operating on just the symbolic link or on all files in the -+hierarchy rooted at that directory. -+ -+These options are independent of @option{--dereference} and -+@option{--no-dereference} (@option{-h}), which control whether to modify -+a symlink or its referent. -+ -+@table @samp -+ -+@macro choptH -+@item -H -+@opindex -H -+@cindex symbolic link to directory, traverse each that is specified on the command line -+If @option{--recursive} (@option{-R}) is specified and -+a command line argument is a symbolic link to a directory, traverse it. -+@end macro -+@choptH -+ -+@macro choptL -+@item -L -+@opindex -L -+@cindex symbolic link to directory, traverse each that is encountered -+In a recursive traversal, traverse every symbolic link to a directory -+that is encountered. -+@end macro -+@choptL -+ -+@macro choptP -+@item -P -+@opindex -P -+@cindex symbolic link to directory, never traverse -+Do not traverse any symbolic links. -+This is the default if none of @option{-H}, @option{-L}, -+or @option{-P} is specified. -+@end macro -+@choptP -+ -+@end table -+ -+ -+@node Treating / specially -+@section Treating @file{/} specially -+ -+Certain commands can operate destructively on entire hierarchies. -+For example, if a user with appropriate privileges mistakenly runs -+@samp{rm -rf / tmp/junk}, that may remove -+all files on the entire system. Since there are so few -+legitimate uses for such a command, -+@sc{gnu} @command{rm} normally declines to operate on any directory -+that resolves to @file{/}. If you really want to try to remove all -+the files on your system, you can use the @option{--no-preserve-root} -+option, but the default behavior, specified by the -+@option{--preserve-option}, is safer for most purposes. -+ -+The commands @command{chgrp}, @command{chmod} and @command{chown} -+can also operate destructively on entire hierarchies, so they too -+support these options. Although, unlike @command{rm}, they don't -+actually unlink files, these commands are arguably more dangerous -+when operating recursively on @file{/}, since they often work much -+more quickly, and hence damage more files before an alert user can -+interrupt them. Tradition and @acronym{POSIX} require these commands -+to operate recursively on @file{/}, so they default to -+@option{--no-preserve-root}, but using the @option{--preserve-root} -+option makes them safer for most purposes. For convenience you can -+specify @option{--preserve-root} in an alias or in a shell function. -+ -+Note that the @option{--preserve-root} option also ensures -+that @command{chgrp} and @command{chown} do not modify @file{/} -+even when dereferencing a symlink pointing to @file{/}. -+ -+@node Special built-in utilities -+@section Special built-in utilities -+ -+Some programs like @command{nice} can invoke other programs; for -+example, the command @samp{nice cat file} invokes the program -+@command{cat} by executing the command @samp{cat file}. However, -+@dfn{special built-in utilities} like @command{exit} cannot be invoked -+this way. For example, the command @samp{nice exit} does not have a -+well-defined behavior: it may generate an error message instead of -+exiting. -+ -+Here is a list of the special built-in utilities that are standardized -+by @acronym{POSIX} 1003.1-2004. -+ -+@quotation -+@t{.@: : break continue eval exec exit export readonly -+return set shift times trap unset} -+@end quotation -+ -+For example, because @samp{.}, @samp{:}, and @samp{exec} are special, -+the commands @samp{nice . foo.sh}, @samp{nice :}, and @samp{nice exec -+pwd} do not work as you might expect. -+ -+Many shells extend this list. For example, Bash has several extra -+special built-in utilities like @command{history}, and -+@command{suspend}, and with Bash the command @samp{nice suspend} -+generates an error message instead of suspending. -+ -+@node Standards conformance -+@section Standards conformance -+ -+@vindex POSIXLY_CORRECT -+In a few cases, the @sc{gnu} utilities' default behavior is -+incompatible with the @acronym{POSIX} standard. To suppress these -+incompatibilities, define the @env{POSIXLY_CORRECT} environment -+variable. Unless you are checking for @acronym{POSIX} conformance, you -+probably do not need to define @env{POSIXLY_CORRECT}. -+ -+Newer versions of @acronym{POSIX} are occasionally incompatible with older -+versions. For example, older versions of @acronym{POSIX} required the -+command @samp{sort +1} to sort based on the second and succeeding -+fields in each input line, but starting with @acronym{POSIX} 1003.1-2001 -+the same command is required to sort the file named @file{+1}, and you -+must instead use the command @samp{sort -k 2} to get the field-based -+sort. -+ -+@vindex _POSIX2_VERSION -+The @sc{gnu} utilities normally conform to the version of @acronym{POSIX} -+that is standard for your system. To cause them to conform to a -+different version of @acronym{POSIX}, define the @env{_POSIX2_VERSION} -+environment variable to a value of the form @var{yyyymm} specifying -+the year and month the standard was adopted. Two values are currently -+supported for @env{_POSIX2_VERSION}: @samp{199209} stands for -+@acronym{POSIX} 1003.2-1992, and @samp{200112} stands for @acronym{POSIX} -+1003.1-2001. For example, if you have a newer system but are running software -+that assumes an older version of @acronym{POSIX} and uses @samp{sort +1} -+or @samp{tail +10}, you can work around any compatibility problems by setting -+@samp{_POSIX2_VERSION=199209} in your environment. -+ -+@node Output of entire files -+@chapter Output of entire files -+ -+@cindex output of entire files -+@cindex entire files, output of -+ -+These commands read and write entire files, possibly transforming them -+in some way. -+ -+@menu -+* cat invocation:: Concatenate and write files. -+* tac invocation:: Concatenate and write files in reverse. -+* nl invocation:: Number lines and write files. -+* od invocation:: Write files in octal or other formats. -+* base64 invocation:: Transform data into printable data. -+@end menu -+ -+@node cat invocation -+@section @command{cat}: Concatenate and write files -+ -+@pindex cat -+@cindex concatenate and write files -+@cindex copying files -+ -+@command{cat} copies each @var{file} (@samp{-} means standard input), or -+standard input if none are given, to standard output. Synopsis: -+ -+@example -+cat [@var{option}] [@var{file}]@dots{} -+@end example -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -A -+@itemx --show-all -+@opindex -A -+@opindex --show-all -+Equivalent to @option{-vET}. -+ -+@item -b -+@itemx --number-nonblank -+@opindex -b -+@opindex --number-nonblank -+Number all nonempty output lines, starting with 1. -+ -+@item -e -+@opindex -e -+Equivalent to @option{-vE}. -+ -+@item -E -+@itemx --show-ends -+@opindex -E -+@opindex --show-ends -+Display a @samp{$} after the end of each line. -+ -+@item -n -+@itemx --number -+@opindex -n -+@opindex --number -+Number all output lines, starting with 1. -+ -+@item -s -+@itemx --squeeze-blank -+@opindex -s -+@opindex --squeeze-blank -+@cindex squeezing empty lines -+Suppress repeated adjacent empty lines; output just one empty line -+instead of several. -+ -+@item -t -+@opindex -t -+Equivalent to @option{-vT}. -+ -+@item -T -+@itemx --show-tabs -+@opindex -T -+@opindex --show-tabs -+Display TAB characters as @samp{^I}. -+ -+@item -u -+@opindex -u -+Ignored; for @acronym{POSIX} compatibility. -+ -+@item -v -+@itemx --show-nonprinting -+@opindex -v -+@opindex --show-nonprinting -+Display control characters except for LFD and TAB using -+@samp{^} notation and precede characters that have the high bit set with -+@samp{M-}. -+ -+@end table -+ -+On systems like MS-DOS that distinguish between text and binary files, -+@command{cat} normally reads and writes in binary mode. However, -+@command{cat} reads in text mode if one of the options -+@option{-bensAE} is used or if @command{cat} is reading from standard -+input and standard input is a terminal. Similarly, @command{cat} -+writes in text mode if one of the options @option{-bensAE} is used or -+if standard output is a terminal. -+ -+@exitstatus -+ -+Examples: -+ -+@smallexample -+# Output f's contents, then standard input, then g's contents. -+cat f - g -+ -+# Copy standard input to standard output. -+cat -+@end smallexample -+ -+ -+@node tac invocation -+@section @command{tac}: Concatenate and write files in reverse -+ -+@pindex tac -+@cindex reversing files -+ -+@command{tac} copies each @var{file} (@samp{-} means standard input), or -+standard input if none are given, to standard output, reversing the -+records (lines by default) in each separately. Synopsis: -+ -+@example -+tac [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@dfn{Records} are separated by instances of a string (newline by -+default). By default, this separator string is attached to the end of -+the record that it follows in the file. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -b -+@itemx --before -+@opindex -b -+@opindex --before -+The separator is attached to the beginning of the record that it -+precedes in the file. -+ -+@item -r -+@itemx --regex -+@opindex -r -+@opindex --regex -+Treat the separator string as a regular expression. Users of @command{tac} -+on MS-DOS/MS-Windows should note that, since @command{tac} reads files in -+binary mode, each line of a text file might end with a CR/LF pair -+instead of the Unix-style LF. -+ -+@item -s @var{separator} -+@itemx --separator=@var{separator} -+@opindex -s -+@opindex --separator -+Use @var{separator} as the record separator, instead of newline. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node nl invocation -+@section @command{nl}: Number lines and write files -+ -+@pindex nl -+@cindex numbering lines -+@cindex line numbering -+ -+@command{nl} writes each @var{file} (@samp{-} means standard input), or -+standard input if none are given, to standard output, with line numbers -+added to some or all of the lines. Synopsis: -+ -+@example -+nl [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@cindex logical pages, numbering on -+@command{nl} decomposes its input into (logical) pages; by default, the -+line number is reset to 1 at the top of each logical page. @command{nl} -+treats all of the input files as a single document; it does not reset -+line numbers or logical pages between files. -+ -+@cindex headers, numbering -+@cindex body, numbering -+@cindex footers, numbering -+A logical page consists of three sections: header, body, and footer. -+Any of the sections can be empty. Each can be numbered in a different -+style from the others. -+ -+The beginnings of the sections of logical pages are indicated in the -+input file by a line containing exactly one of these delimiter strings: -+ -+@table @samp -+@item \:\:\: -+start of header; -+@item \:\: -+start of body; -+@item \: -+start of footer. -+@end table -+ -+The two characters from which these strings are made can be changed from -+@samp{\} and @samp{:} via options (see below), but the pattern and -+length of each string cannot be changed. -+ -+A section delimiter is replaced by an empty line on output. Any text -+that comes before the first section delimiter string in the input file -+is considered to be part of a body section, so @command{nl} treats a -+file that contains no section delimiters as a single body section. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -b @var{style} -+@itemx --body-numbering=@var{style} -+@opindex -b -+@opindex --body-numbering -+Select the numbering style for lines in the body section of each -+logical page. When a line is not numbered, the current line number -+is not incremented, but the line number separator character is still -+prepended to the line. The styles are: -+ -+@table @samp -+@item a -+number all lines, -+@item t -+number only nonempty lines (default for body), -+@item n -+do not number lines (default for header and footer), -+@item p@var{bre} -+number only lines that contain a match for the basic regular -+expression @var{bre}. -+@xref{Regular Expressions, , Regular Expressions, grep, The GNU Grep Manual}. -+@end table -+ -+@item -d @var{cd} -+@itemx --section-delimiter=@var{cd} -+@opindex -d -+@opindex --section-delimiter -+@cindex section delimiters of pages -+Set the section delimiter characters to @var{cd}; default is -+@samp{\:}. If only @var{c} is given, the second remains @samp{:}. -+(Remember to protect @samp{\} or other metacharacters from shell -+expansion with quotes or extra backslashes.) -+ -+@item -f @var{style} -+@itemx --footer-numbering=@var{style} -+@opindex -f -+@opindex --footer-numbering -+Analogous to @option{--body-numbering}. -+ -+@item -h @var{style} -+@itemx --header-numbering=@var{style} -+@opindex -h -+@opindex --header-numbering -+Analogous to @option{--body-numbering}. -+ -+@item -i @var{number} -+@itemx --line-increment=@var{number} -+@opindex -i -+@opindex --line-increment -+Increment line numbers by @var{number} (default 1). -+ -+@item -l @var{number} -+@itemx --join-blank-lines=@var{number} -+@opindex -l -+@opindex --join-blank-lines -+@cindex empty lines, numbering -+@cindex blank lines, numbering -+Consider @var{number} (default 1) consecutive empty lines to be one -+logical line for numbering, and only number the last one. Where fewer -+than @var{number} consecutive empty lines occur, do not number them. -+An empty line is one that contains no characters, not even spaces -+or tabs. -+ -+@item -n @var{format} -+@itemx --number-format=@var{format} -+@opindex -n -+@opindex --number-format -+Select the line numbering format (default is @code{rn}): -+ -+@table @samp -+@item ln -+@opindex ln @r{format for @command{nl}} -+left justified, no leading zeros; -+@item rn -+@opindex rn @r{format for @command{nl}} -+right justified, no leading zeros; -+@item rz -+@opindex rz @r{format for @command{nl}} -+right justified, leading zeros. -+@end table -+ -+@item -p -+@itemx --no-renumber -+@opindex -p -+@opindex --no-renumber -+Do not reset the line number at the start of a logical page. -+ -+@item -s @var{string} -+@itemx --number-separator=@var{string} -+@opindex -s -+@opindex --number-separator -+Separate the line number from the text line in the output with -+@var{string} (default is the TAB character). -+ -+@item -v @var{number} -+@itemx --starting-line-number=@var{number} -+@opindex -v -+@opindex --starting-line-number -+Set the initial line number on each logical page to @var{number} (default 1). -+ -+@item -w @var{number} -+@itemx --number-width=@var{number} -+@opindex -w -+@opindex --number-width -+Use @var{number} characters for line numbers (default 6). -+ -+@end table -+ -+@exitstatus -+ -+ -+@node od invocation -+@section @command{od}: Write files in octal or other formats -+ -+@pindex od -+@cindex octal dump of files -+@cindex hex dump of files -+@cindex ASCII dump of files -+@cindex file contents, dumping unambiguously -+ -+@command{od} writes an unambiguous representation of each @var{file} -+(@samp{-} means standard input), or standard input if none are given. -+Synopses: -+ -+@smallexample -+od [@var{option}]@dots{} [@var{file}]@dots{} -+od [-abcdfilosx]@dots{} [@var{file}] [[+]@var{offset}[.][b]] -+od [@var{option}]@dots{} --traditional [@var{file}] [[+]@var{offset}[.][b] [[+]@var{label}[.][b]]] -+@end smallexample -+ -+Each line of output consists of the offset in the input, followed by -+groups of data from the file. By default, @command{od} prints the offset in -+octal, and each group of file data is a C @code{short int}'s worth of input -+printed as a single octal number. -+ -+If @var{offset} is given, it specifies how many input bytes to skip -+before formatting and writing. By default, it is interpreted as an -+octal number, but the optional trailing decimal point causes it to be -+interpreted as decimal. If no decimal is specified and the offset -+begins with @samp{0x} or @samp{0X} it is interpreted as a hexadecimal -+number. If there is a trailing @samp{b}, the number of bytes skipped -+will be @var{offset} multiplied by 512. -+ -+If a command is of both the first and second forms, the second form is -+assumed if the last operand begins with @samp{+} or (if there are two -+operands) a digit. For example, in @samp{od foo 10} and @samp{od +10} -+the @samp{10} is an offset, whereas in @samp{od 10} the @samp{10} is a -+file name. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -A @var{radix} -+@itemx --address-radix=@var{radix} -+@opindex -A -+@opindex --address-radix -+@cindex radix for file offsets -+@cindex file offset radix -+Select the base in which file offsets are printed. @var{radix} can -+be one of the following: -+ -+@table @samp -+@item d -+decimal; -+@item o -+octal; -+@item x -+hexadecimal; -+@item n -+none (do not print offsets). -+@end table -+ -+The default is octal. -+ -+@item -j @var{bytes} -+@itemx --skip-bytes=@var{bytes} -+@opindex -j -+@opindex --skip-bytes -+Skip @var{bytes} input bytes before formatting and writing. If -+@var{bytes} begins with @samp{0x} or @samp{0X}, it is interpreted in -+hexadecimal; otherwise, if it begins with @samp{0}, in octal; otherwise, -+in decimal. -+@multiplierSuffixes{bytes} -+ -+@item -N @var{bytes} -+@itemx --read-bytes=@var{bytes} -+@opindex -N -+@opindex --read-bytes -+Output at most @var{bytes} bytes of the input. Prefixes and suffixes on -+@code{bytes} are interpreted as for the @option{-j} option. -+ -+@item -S @var{bytes} -+@itemx --strings[=@var{bytes}] -+@opindex -S -+@opindex --strings -+@cindex string constants, outputting -+Instead of the normal output, output only @dfn{string constants}: at -+least @var{bytes} consecutive @acronym{ASCII} graphic characters, -+followed by a zero byte (@acronym{ASCII} @sc{nul}). -+Prefixes and suffixes on @code{bytes} are interpreted as for the -+@option{-j} option. -+ -+If @var{n} is omitted with @option{--strings}, the default is 3. -+ -+@item -t @var{type} -+@itemx --format=@var{type} -+@opindex -t -+@opindex --format -+Select the format in which to output the file data. @var{type} is a -+string of one or more of the below type indicator characters. If you -+include more than one type indicator character in a single @var{type} -+string, or use this option more than once, @command{od} writes one copy -+of each output line using each of the data types that you specified, -+in the order that you specified. -+ -+Adding a trailing ``z'' to any type specification appends a display -+of the @acronym{ASCII} character representation of the printable characters -+to the output line generated by the type specification. -+ -+@table @samp -+@item a -+named character, ignoring high-order bit -+@item c -+@acronym{ASCII} character or backslash escape, -+@item d -+signed decimal -+@item f -+floating point -+@item o -+octal -+@item u -+unsigned decimal -+@item x -+hexadecimal -+@end table -+ -+The type @code{a} outputs things like @samp{sp} for space, @samp{nl} for -+newline, and @samp{nul} for a zero byte. Only the least significant -+seven bits of each byte is used; the high-order bit is ignored. -+Type @code{c} outputs -+@samp{ }, @samp{\n}, and @code{\0}, respectively. -+ -+@cindex type size -+Except for types @samp{a} and @samp{c}, you can specify the number -+of bytes to use in interpreting each number in the given data type -+by following the type indicator character with a decimal integer. -+Alternately, you can specify the size of one of the C compiler's -+built-in data types by following the type indicator character with -+one of the following characters. For integers (@samp{d}, @samp{o}, -+@samp{u}, @samp{x}): -+ -+@table @samp -+@item C -+char -+@item S -+short -+@item I -+int -+@item L -+long -+@end table -+ -+For floating point (@code{f}): -+ -+@table @asis -+@item F -+float -+@item D -+double -+@item L -+long double -+@end table -+ -+@item -v -+@itemx --output-duplicates -+@opindex -v -+@opindex --output-duplicates -+Output consecutive lines that are identical. By default, when two or -+more consecutive output lines would be identical, @command{od} outputs only -+the first line, and puts just an asterisk on the following line to -+indicate the elision. -+ -+@item -w[@var{n}] -+@itemx --width[=@var{n}] -+@opindex -w -+@opindex --width -+Dump @code{n} input bytes per output line. This must be a multiple of -+the least common multiple of the sizes associated with the specified -+output types. -+ -+If this option is not given at all, the default is 16. If @var{n} is -+omitted, the default is 32. -+ -+@end table -+ -+The next several options are shorthands for format specifications. -+@sc{gnu} @command{od} accepts any combination of shorthands and format -+specification options. These options accumulate. -+ -+@table @samp -+ -+@item -a -+@opindex -a -+Output as named characters. Equivalent to @samp{-t a}. -+ -+@item -b -+@opindex -b -+Output as octal bytes. Equivalent to @samp{-t o1}. -+ -+@item -c -+@opindex -c -+Output as @acronym{ASCII} characters or backslash escapes. Equivalent to -+@samp{-t c}. -+ -+@item -d -+@opindex -d -+Output as unsigned decimal two-byte units. Equivalent to @samp{-t u2}. -+ -+@item -f -+@opindex -f -+Output as floats. Equivalent to @samp{-t fF}. -+ -+@item -i -+@opindex -i -+Output as decimal ints. Equivalent to @samp{-t dI}. -+ -+@item -l -+@opindex -l -+Output as decimal long ints. Equivalent to @samp{-t dL}. -+ -+@item -o -+@opindex -o -+Output as octal two-byte units. Equivalent to @option{-t o2}. -+ -+@item -s -+@opindex -s -+Output as decimal two-byte units. Equivalent to @option{-t d2}. -+ -+@item -x -+@opindex -x -+Output as hexadecimal two-byte units. Equivalent to @samp{-t x2}. -+ -+@item --traditional -+@opindex --traditional -+Recognize the non-option label argument that traditional @command{od} -+accepted. The following syntax: -+ -+@smallexample -+od --traditional [@var{file}] [[+]@var{offset}[.][b] [[+]@var{label}[.][b]]] -+@end smallexample -+ -+@noindent -+can be used to specify at most one file and optional arguments -+specifying an offset and a pseudo-start address, @var{label}. -+The @var{label} argument is interpreted -+just like @var{offset}, but it specifies an initial pseudo-address. The -+pseudo-addresses are displayed in parentheses following any normal -+address. -+ -+@end table -+ -+@exitstatus -+ -+@node base64 invocation -+@section @command{base64}: Transform data into printable data -+ -+@pindex base64 -+@cindex base64 encoding -+ -+@command{base64} transforms data read from a file, or standard input, -+into (or from) base64 encoded form. The base64 encoded form uses -+printable @acronym{ASCII} characters to represent binary data. -+Synopses: -+ -+@smallexample -+base64 [@var{option}]@dots{} [@var{file}] -+base64 --decode [@var{option}]@dots{} [@var{file}] -+@end smallexample -+ -+The base64 encoding expands data to roughly 133% of the original. -+The format conforms to -+@uref{ftp://ftp.rfc-editor.org/in-notes/rfc4648.txt, RFC 4648}. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -w @var{cols} -+@itemx --wrap=@var{cols} -+@opindex -w -+@opindex --wrap -+@cindex wrap data -+@cindex column to wrap data after -+During encoding, wrap lines after @var{cols} characters. This must be -+a positive number. -+ -+The default is to wrap after 76 characters. Use the value 0 to -+disable line wrapping altogether. -+ -+@item -d -+@itemx --decode -+@opindex -d -+@opindex --decode -+@cindex Decode base64 data -+@cindex Base64 decoding -+Change the mode of operation, from the default of encoding data, to -+decoding data. Input is expected to be base64 encoded data, and the -+output will be the original data. -+ -+@item -i -+@itemx --ignore-garbage -+@opindex -i -+@opindex --ignore-garbage -+@cindex Ignore garbage in base64 stream -+When decoding, newlines are always accepted. -+During decoding, ignore unrecognized bytes, -+to permit distorted data to be decoded. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node Formatting file contents -+@chapter Formatting file contents -+ -+@cindex formatting file contents -+ -+These commands reformat the contents of files. -+ -+@menu -+* fmt invocation:: Reformat paragraph text. -+* pr invocation:: Paginate or columnate files for printing. -+* fold invocation:: Wrap input lines to fit in specified width. -+@end menu -+ -+ -+@node fmt invocation -+@section @command{fmt}: Reformat paragraph text -+ -+@pindex fmt -+@cindex reformatting paragraph text -+@cindex paragraphs, reformatting -+@cindex text, reformatting -+ -+@command{fmt} fills and joins lines to produce output lines of (at most) -+a given number of characters (75 by default). Synopsis: -+ -+@example -+fmt [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@command{fmt} reads from the specified @var{file} arguments (or standard -+input if none are given), and writes to standard output. -+ -+By default, blank lines, spaces between words, and indentation are -+preserved in the output; successive input lines with different -+indentation are not joined; tabs are expanded on input and introduced on -+output. -+ -+@cindex line-breaking -+@cindex sentences and line-breaking -+@cindex Knuth, Donald E. -+@cindex Plass, Michael F. -+@command{fmt} prefers breaking lines at the end of a sentence, and tries to -+avoid line breaks after the first word of a sentence or before the last -+word of a sentence. A @dfn{sentence break} is defined as either the end -+of a paragraph or a word ending in any of @samp{.?!}, followed by two -+spaces or end of line, ignoring any intervening parentheses or quotes. -+Like @TeX{}, @command{fmt} reads entire ``paragraphs'' before choosing line -+breaks; the algorithm is a variant of that given by Donald E. Knuth -+and Michael F. Plass in ``Breaking Paragraphs Into Lines'', -+@cite{Software---Practice & Experience} @b{11}, 11 (November 1981), -+1119--1184. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c -+@itemx --crown-margin -+@opindex -c -+@opindex --crown-margin -+@cindex crown margin -+@dfn{Crown margin} mode: preserve the indentation of the first two -+lines within a paragraph, and align the left margin of each subsequent -+line with that of the second line. -+ -+@item -t -+@itemx --tagged-paragraph -+@opindex -t -+@opindex --tagged-paragraph -+@cindex tagged paragraphs -+@dfn{Tagged paragraph} mode: like crown margin mode, except that if -+indentation of the first line of a paragraph is the same as the -+indentation of the second, the first line is treated as a one-line -+paragraph. -+ -+@item -s -+@itemx --split-only -+@opindex -s -+@opindex --split-only -+Split lines only. Do not join short lines to form longer ones. This -+prevents sample lines of code, and other such ``formatted'' text from -+being unduly combined. -+ -+@item -u -+@itemx --uniform-spacing -+@opindex -u -+@opindex --uniform-spacing -+Uniform spacing. Reduce spacing between words to one space, and spacing -+between sentences to two spaces. -+ -+@item -@var{width} -+@itemx -w @var{width} -+@itemx --width=@var{width} -+@opindex -@var{width} -+@opindex -w -+@opindex --width -+Fill output lines up to @var{width} characters (default 75). @command{fmt} -+initially tries to make lines about 7% shorter than this, to give it -+room to balance line lengths. -+ -+@item -p @var{prefix} -+@itemx --prefix=@var{prefix} -+Only lines beginning with @var{prefix} (possibly preceded by whitespace) -+are subject to formatting. The prefix and any preceding whitespace are -+stripped for the formatting and then re-attached to each formatted output -+line. One use is to format certain kinds of program comments, while -+leaving the code unchanged. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node pr invocation -+@section @command{pr}: Paginate or columnate files for printing -+ -+@pindex pr -+@cindex printing, preparing files for -+@cindex multicolumn output, generating -+@cindex merging files in parallel -+ -+@command{pr} writes each @var{file} (@samp{-} means standard input), or -+standard input if none are given, to standard output, paginating and -+optionally outputting in multicolumn format; optionally merges all -+@var{file}s, printing all in parallel, one per column. Synopsis: -+ -+@example -+pr [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@vindex LC_MESSAGES -+By default, a 5-line header is printed at each page: two blank lines; -+a line with the date, the file name, and the page count; and two more -+blank lines. A footer of five blank lines is also printed. -+The default @var{page_length} is 66 -+lines. The default number of text lines is therefore 56. -+The text line of the header takes the form -+@samp{@var{date} @var{string} @var{page}}, with spaces inserted around -+@var{string} so that the line takes up the full @var{page_width}. Here, -+@var{date} is the date (see the @option{-D} or @option{--date-format} -+option for details), @var{string} is the centered header string, and -+@var{page} identifies the page number. The @env{LC_MESSAGES} locale -+category affects the spelling of @var{page}; in the default C locale, it -+is @samp{Page @var{number}} where @var{number} is the decimal page -+number. -+ -+Form feeds in the input cause page breaks in the output. Multiple form -+feeds produce empty pages. -+ -+Columns are of equal width, separated by an optional string (default -+is @samp{space}). For multicolumn output, lines will always be truncated to -+@var{page_width} (default 72), unless you use the @option{-J} option. -+For single -+column output no line truncation occurs by default. Use @option{-W} option to -+truncate lines in that case. -+ -+The following changes were made in version 1.22i and apply to later -+versions of @command{pr}: -+@c FIXME: this whole section here sounds very awkward to me. I -+@c made a few small changes, but really it all needs to be redone. - Brian -+@c OK, I fixed another sentence or two, but some of it I just don't understand. -+@ - Brian -+@itemize @bullet -+ -+@item -+Some small @var{letter options} (@option{-s}, @option{-w}) have been -+redefined for better @acronym{POSIX} compliance. The output of some further -+cases has been adapted to other Unix systems. These changes are not -+compatible with earlier versions of the program. -+ -+@item -+Some @var{new capital letter} options (@option{-J}, @option{-S}, @option{-W}) -+have been introduced to turn off unexpected interferences of small letter -+options. The @option{-N} option and the second argument @var{last_page} -+of @samp{+FIRST_PAGE} offer more flexibility. The detailed handling of -+form feeds set in the input files requires the @option{-T} option. -+ -+@item -+Capital letter options override small letter ones. -+ -+@item -+Some of the option-arguments (compare @option{-s}, @option{-e}, -+@option{-i}, @option{-n}) cannot be specified as separate arguments from the -+preceding option letter (already stated in the @acronym{POSIX} specification). -+@end itemize -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item +@var{first_page}[:@var{last_page}] -+@itemx --pages=@var{first_page}[:@var{last_page}] -+@c The two following @opindex lines evoke warnings because they contain `:' -+@c The `info' spec does not permit that. If we use those lines, we end -+@c up with truncated index entries that don't work. -+@c @opindex +@var{first_page}[:@var{last_page}] -+@c @opindex --pages=@var{first_page}[:@var{last_page}] -+@opindex +@var{page_range} -+@opindex --pages=@var{page_range} -+Begin printing with page @var{first_page} and stop with @var{last_page}. -+Missing @samp{:@var{last_page}} implies end of file. While estimating -+the number of skipped pages each form feed in the input file results -+in a new page. Page counting with and without @samp{+@var{first_page}} -+is identical. By default, counting starts with the first page of input -+file (not first page printed). Line numbering may be altered by @option{-N} -+option. -+ -+@item -@var{column} -+@itemx --columns=@var{column} -+@opindex -@var{column} -+@opindex --columns -+@cindex down columns -+With each single @var{file}, produce @var{column} columns of output -+(default is 1) and print columns down, unless @option{-a} is used. The -+column width is automatically decreased as @var{column} increases; unless -+you use the @option{-W/-w} option to increase @var{page_width} as well. -+This option might well cause some lines to be truncated. The number of -+lines in the columns on each page are balanced. The options @option{-e} -+and @option{-i} are on for multiple text-column output. Together with -+@option{-J} option column alignment and line truncation is turned off. -+Lines of full length are joined in a free field format and @option{-S} -+option may set field separators. @option{-@var{column}} may not be used -+with @option{-m} option. -+ -+@item -a -+@itemx --across -+@opindex -a -+@opindex --across -+@cindex across columns -+With each single @var{file}, print columns across rather than down. The -+@option{-@var{column}} option must be given with @var{column} greater than one. -+If a line is too long to fit in a column, it is truncated. -+ -+@item -c -+@itemx --show-control-chars -+@opindex -c -+@opindex --show-control-chars -+Print control characters using hat notation (e.g., @samp{^G}); print -+other nonprinting characters in octal backslash notation. By default, -+nonprinting characters are not changed. -+ -+@item -d -+@itemx --double-space -+@opindex -d -+@opindex --double-space -+@cindex double spacing -+Double space the output. -+ -+@item -D @var{format} -+@itemx --date-format=@var{format} -+@cindex time formats -+@cindex formatting times -+Format header dates using @var{format}, using the same conventions as -+for the command @samp{date +@var{format}}; @xref{date invocation}. -+Except for directives, which start with -+@samp{%}, characters in @var{format} are printed unchanged. You can use -+this option to specify an arbitrary string in place of the header date, -+e.g., @option{--date-format="Monday morning"}. -+ -+@vindex POSIXLY_CORRECT -+@vindex LC_TIME -+The default date format is @samp{%Y-%m-%d %H:%M} (for example, -+@samp{2001-12-04 23:59}); -+but if the @env{POSIXLY_CORRECT} environment variable is set -+and the @env{LC_TIME} locale category specifies the @acronym{POSIX} -+locale, the default is @samp{%b %e %H:%M %Y} (for example, -+@samp{Dec@ @ 4 23:59 2001}. -+ -+@vindex TZ -+Time stamps are listed according to the time zone rules specified by -+the @env{TZ} environment variable, or by the system default rules if -+@env{TZ} is not set. @xref{TZ Variable,, Specifying the Time Zone -+with @env{TZ}, libc, The GNU C Library Reference Manual}. -+ -+@item -e[@var{in-tabchar}[@var{in-tabwidth}]] -+@itemx --expand-tabs[=@var{in-tabchar}[@var{in-tabwidth}]] -+@opindex -e -+@opindex --expand-tabs -+@cindex input tabs -+Expand @var{tab}s to spaces on input. Optional argument @var{in-tabchar} is -+the input tab character (default is the TAB character). Second optional -+argument @var{in-tabwidth} is the input tab character's width (default -+is 8). -+ -+@item -f -+@itemx -F -+@itemx --form-feed -+@opindex -F -+@opindex -f -+@opindex --form-feed -+Use a form feed instead of newlines to separate output pages. This does -+not alter the default page length of 66 lines. -+ -+@item -h @var{header} -+@itemx --header=@var{header} -+@opindex -h -+@opindex --header -+Replace the file name in the header with the centered string @var{header}. -+When using the shell, @var{header} should be quoted and should be -+separated from @option{-h} by a space. -+ -+@item -i[@var{out-tabchar}[@var{out-tabwidth}]] -+@itemx --output-tabs[=@var{out-tabchar}[@var{out-tabwidth}]] -+@opindex -i -+@opindex --output-tabs -+@cindex output tabs -+Replace spaces with @var{tab}s on output. Optional argument @var{out-tabchar} -+is the output tab character (default is the TAB character). Second optional -+argument @var{out-tabwidth} is the output tab character's width (default -+is 8). -+ -+@item -J -+@itemx --join-lines -+@opindex -J -+@opindex --join-lines -+Merge lines of full length. Used together with the column options -+@option{-@var{column}}, @option{-a -@var{column}} or @option{-m}. Turns off -+@option{-W/-w} line truncation; -+no column alignment used; may be used with -+@option{--sep-string[=@var{string}]}. @option{-J} has been introduced -+(together with @option{-W} and @option{--sep-string}) -+to disentangle the old (@acronym{POSIX}-compliant) options @option{-w} and -+@option{-s} along with the three column options. -+ -+ -+@item -l @var{page_length} -+@itemx --length=@var{page_length} -+@opindex -l -+@opindex --length -+Set the page length to @var{page_length} (default 66) lines, including -+the lines of the header [and the footer]. If @var{page_length} is less -+than or equal to 10, the header and footer are omitted, as if the -+@option{-t} option had been given. -+ -+@item -m -+@itemx --merge -+@opindex -m -+@opindex --merge -+Merge and print all @var{file}s in parallel, one in each column. If a -+line is too long to fit in a column, it is truncated, unless the @option{-J} -+option is used. @option{--sep-string[=@var{string}]} may be used. -+Empty pages in -+some @var{file}s (form feeds set) produce empty columns, still marked -+by @var{string}. The result is a continuous line numbering and column -+marking throughout the whole merged file. Completely empty merged pages -+show no separators or line numbers. The default header becomes -+@samp{@var{date} @var{page}} with spaces inserted in the middle; this -+may be used with the @option{-h} or @option{--header} option to fill up -+the middle blank part. -+ -+@item -n[@var{number-separator}[@var{digits}]] -+@itemx --number-lines[=@var{number-separator}[@var{digits}]] -+@opindex -n -+@opindex --number-lines -+Provide @var{digits} digit line numbering (default for @var{digits} is -+5). With multicolumn output the number occupies the first @var{digits} -+column positions of each text column or only each line of @option{-m} -+output. With single column output the number precedes each line just as -+@option{-m} does. Default counting of the line numbers starts with the -+first line of the input file (not the first line printed, compare the -+@option{--page} option and @option{-N} option). -+Optional argument @var{number-separator} is the character appended to -+the line number to separate it from the text followed. The default -+separator is the TAB character. In a strict sense a TAB is always -+printed with single column output only. The TAB width varies -+with the TAB position, e.g., with the left @var{margin} specified -+by @option{-o} option. With multicolumn output priority is given to -+@samp{equal width of output columns} (a @acronym{POSIX} specification). -+The TAB width is fixed to the value of the first column and does -+not change with different values of left @var{margin}. That means a -+fixed number of spaces is always printed in the place of the -+@var{number-separator} TAB. The tabification depends upon the output -+position. -+ -+@item -N @var{line_number} -+@itemx --first-line-number=@var{line_number} -+@opindex -N -+@opindex --first-line-number -+Start line counting with the number @var{line_number} at first line of -+first page printed (in most cases not the first line of the input file). -+ -+@item -o @var{margin} -+@itemx --indent=@var{margin} -+@opindex -o -+@opindex --indent -+@cindex indenting lines -+@cindex left margin -+Indent each line with a margin @var{margin} spaces wide (default is zero). -+The total page width is the size of the margin plus the @var{page_width} -+set with the @option{-W/-w} option. A limited overflow may occur with -+numbered single column output (compare @option{-n} option). -+ -+@item -r -+@itemx --no-file-warnings -+@opindex -r -+@opindex --no-file-warnings -+Do not print a warning message when an argument @var{file} cannot be -+opened. (The exit status will still be nonzero, however.) -+ -+@item -s[@var{char}] -+@itemx --separator[=@var{char}] -+@opindex -s -+@opindex --separator -+Separate columns by a single character @var{char}. The default for -+@var{char} is the TAB character without @option{-w} and @samp{no -+character} with @option{-w}. Without @option{-s} the default separator -+@samp{space} is set. @option{-s[char]} turns off line truncation of all -+three column options (@option{-COLUMN}|@option{-a -COLUMN}|@option{-m}) unless -+@option{-w} is set. This is a @acronym{POSIX}-compliant formulation. -+ -+ -+@item -S@var{string} -+@itemx --sep-string[=@var{string}] -+@opindex -S -+@opindex --sep-string -+Use @var{string} to separate output columns. The @option{-S} option doesn't -+affect the @option{-W/-w} option, unlike the @option{-s} option which does. It -+does not affect line truncation or column alignment. -+Without @option{-S}, and with @option{-J}, @command{pr} uses the default output -+separator, TAB@. -+Without @option{-S} or @option{-J}, @command{pr} uses a @samp{space} -+(same as @option{-S"@w{ }"}). @option{--sep-string} with no -+@samp{=@var{string}} is equivalent to @option{--sep-string=""}. -+ -+@item -t -+@itemx --omit-header -+@opindex -t -+@opindex --omit-header -+Do not print the usual header [and footer] on each page, and do not fill -+out the bottom of pages (with blank lines or a form feed). No page -+structure is produced, but form feeds set in the input files are retained. -+The predefined pagination is not changed. @option{-t} or @option{-T} may be -+useful together with other options; e.g.: @option{-t -e4}, expand TAB characters -+in the input file to 4 spaces but don't make any other changes. Use of -+@option{-t} overrides @option{-h}. -+ -+@item -T -+@itemx --omit-pagination -+@opindex -T -+@opindex --omit-pagination -+Do not print header [and footer]. In addition eliminate all form feeds -+set in the input files. -+ -+@item -v -+@itemx --show-nonprinting -+@opindex -v -+@opindex --show-nonprinting -+Print nonprinting characters in octal backslash notation. -+ -+@item -w @var{page_width} -+@itemx --width=@var{page_width} -+@opindex -w -+@opindex --width -+Set page width to @var{page_width} characters for multiple text-column -+output only (default for @var{page_width} is 72). @option{-s[CHAR]} turns -+off the default page width and any line truncation and column alignment. -+Lines of full length are merged, regardless of the column options -+set. No @var{page_width} setting is possible with single column output. -+A @acronym{POSIX}-compliant formulation. -+ -+@item -W @var{page_width} -+@itemx --page_width=@var{page_width} -+@opindex -W -+@opindex --page_width -+Set the page width to @var{page_width} characters. That's valid with and -+without a column option. Text lines are truncated, unless @option{-J} -+is used. Together with one of the three column options -+(@option{-@var{column}}, @option{-a -@var{column}} or @option{-m}) column -+alignment is always used. The separator options @option{-S} or @option{-s} -+don't affect the @option{-W} option. Default is 72 characters. Without -+@option{-W @var{page_width}} and without any of the column options NO line -+truncation is used (defined to keep downward compatibility and to meet -+most frequent tasks). That's equivalent to @option{-W 72 -J}. The header -+line is never truncated. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node fold invocation -+@section @command{fold}: Wrap input lines to fit in specified width -+ -+@pindex fold -+@cindex wrapping long input lines -+@cindex folding long input lines -+ -+@command{fold} writes each @var{file} (@option{-} means standard input), or -+standard input if none are given, to standard output, breaking long -+lines. Synopsis: -+ -+@example -+fold [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+By default, @command{fold} breaks lines wider than 80 columns. The output -+is split into as many lines as necessary. -+ -+@cindex screen columns -+@command{fold} counts screen columns by default; thus, a tab may count more -+than one column, backspace decreases the column count, and carriage -+return sets the column to zero. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -b -+@itemx --bytes -+@opindex -b -+@opindex --bytes -+Count bytes rather than columns, so that tabs, backspaces, and carriage -+returns are each counted as taking up one column, just like other -+characters. -+ -+@item -s -+@itemx --spaces -+@opindex -s -+@opindex --spaces -+Break at word boundaries: the line is broken after the last blank before -+the maximum line length. If the line contains no such blanks, the line -+is broken at the maximum line length as usual. -+ -+@item -w @var{width} -+@itemx --width=@var{width} -+@opindex -w -+@opindex --width -+Use a maximum line length of @var{width} columns instead of 80. -+ -+For compatibility @command{fold} supports an obsolete option syntax -+@option{-@var{width}}. New scripts should use @option{-w @var{width}} -+instead. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node Output of parts of files -+@chapter Output of parts of files -+ -+@cindex output of parts of files -+@cindex parts of files, output of -+ -+These commands output pieces of the input. -+ -+@menu -+* head invocation:: Output the first part of files. -+* tail invocation:: Output the last part of files. -+* split invocation:: Split a file into fixed-size pieces. -+* csplit invocation:: Split a file into context-determined pieces. -+@end menu -+ -+@node head invocation -+@section @command{head}: Output the first part of files -+ -+@pindex head -+@cindex initial part of files, outputting -+@cindex first part of files, outputting -+ -+@command{head} prints the first part (10 lines by default) of each -+@var{file}; it reads from standard input if no files are given or -+when given a @var{file} of @option{-}. Synopsis: -+ -+@example -+head [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+If more than one @var{file} is specified, @command{head} prints a -+one-line header consisting of: -+ -+@example -+==> @var{file name} <== -+@end example -+ -+@noindent -+before the output for each @var{file}. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c @var{k} -+@itemx --bytes=@var{k} -+@opindex -c -+@opindex --bytes -+Print the first @var{k} bytes, instead of initial lines. -+However, if @var{k} starts with a @samp{-}, -+print all but the last @var{k} bytes of each file. -+@multiplierSuffixes{k} -+ -+@itemx -n @var{k} -+@itemx --lines=@var{k} -+@opindex -n -+@opindex --lines -+Output the first @var{k} lines. -+However, if @var{k} starts with a @samp{-}, -+print all but the last @var{k} lines of each file. -+Size multiplier suffixes are the same as with the @option{-c} option. -+ -+@item -q -+@itemx --quiet -+@itemx --silent -+@opindex -q -+@opindex --quiet -+@opindex --silent -+Never print file name headers. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Always print file name headers. -+ -+@end table -+ -+For compatibility @command{head} also supports an obsolete option syntax -+@option{-@var{count}@var{options}}, which is recognized only if it is -+specified first. @var{count} is a decimal number optionally followed -+by a size letter (@samp{b}, @samp{k}, @samp{m}) as in @option{-c}, or -+@samp{l} to mean count by lines, or other option letters (@samp{cqv}). -+Scripts intended for standard hosts should use @option{-c @var{count}} -+or @option{-n @var{count}} instead. If your script must also run on -+hosts that support only the obsolete syntax, it is usually simpler to -+avoid @command{head}, e.g., by using @samp{sed 5q} instead of -+@samp{head -5}. -+ -+@exitstatus -+ -+ -+@node tail invocation -+@section @command{tail}: Output the last part of files -+ -+@pindex tail -+@cindex last part of files, outputting -+ -+@command{tail} prints the last part (10 lines by default) of each -+@var{file}; it reads from standard input if no files are given or -+when given a @var{file} of @samp{-}. Synopsis: -+ -+@example -+tail [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+If more than one @var{file} is specified, @command{tail} prints a -+one-line header consisting of: -+ -+@example -+==> @var{file name} <== -+@end example -+ -+@noindent -+before the output for each @var{file}. -+ -+@cindex BSD @command{tail} -+@sc{gnu} @command{tail} can output any amount of data (some other versions of -+@command{tail} cannot). It also has no @option{-r} option (print in -+reverse), since reversing a file is really a different job from printing -+the end of a file; BSD @command{tail} (which is the one with @option{-r}) can -+only reverse files that are at most as large as its buffer, which is -+typically 32 KiB@. A more reliable and versatile way to reverse files is -+the @sc{gnu} @command{tac} command. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c @var{k} -+@itemx --bytes=@var{k} -+@opindex -c -+@opindex --bytes -+Output the last @var{k} bytes, instead of final lines. -+However, if @var{k} starts with a @samp{+}, start printing with the -+@var{k}th byte from the start of each file, instead of from the end. -+@multiplierSuffixes{k} -+ -+@item -f -+@itemx --follow[=@var{how}] -+@opindex -f -+@opindex --follow -+@cindex growing files -+@vindex name @r{follow option} -+@vindex descriptor @r{follow option} -+Loop forever trying to read more characters at the end of the file, -+presumably because the file is growing. -+If more than one file is given, @command{tail} prints a header whenever it -+gets output from a different file, to indicate which file that output is -+from. -+ -+There are two ways to specify how you'd like to track files with this option, -+but that difference is noticeable only when a followed file is removed or -+renamed. -+If you'd like to continue to track the end of a growing file even after -+it has been unlinked, use @option{--follow=descriptor}. This is the default -+behavior, but it is not useful if you're tracking a log file that may be -+rotated (removed or renamed, then reopened). In that case, use -+@option{--follow=name} to track the named file by reopening it periodically -+to see if it has been removed and recreated by some other program. -+ -+No matter which method you use, if the tracked file is determined to have -+shrunk, @command{tail} prints a message saying the file has been truncated -+and resumes tracking the end of the file from the newly-determined endpoint. -+ -+When a file is removed, @command{tail}'s behavior depends on whether it is -+following the name or the descriptor. When following by name, tail can -+detect that a file has been removed and gives a message to that effect, -+and if @option{--retry} has been specified it will continue checking -+periodically to see if the file reappears. -+When following a descriptor, tail does not detect that the file has -+been unlinked or renamed and issues no message; even though the file -+may no longer be accessible via its original name, it may still be -+growing. -+ -+The option values @samp{descriptor} and @samp{name} may be specified only -+with the long form of the option, not with @option{-f}. -+ -+The @option{-f} option is ignored if -+no @var{file} operand is specified and standard input is a FIFO or a pipe. -+Likewise, the @option{-f} option has no effect for any -+operand specified as @samp{-}, when standard input is a FIFO or a pipe. -+ -+@item -F -+@opindex -F -+This option is the same as @option{--follow=name --retry}. That is, tail -+will attempt to reopen a file when it is removed. Should this fail, tail -+will keep trying until it becomes accessible again. -+ -+@itemx --retry -+@opindex --retry -+This option is useful mainly when following by name (i.e., with -+@option{--follow=name}). -+Without this option, when tail encounters a file that doesn't -+exist or is otherwise inaccessible, it reports that fact and -+never checks it again. -+ -+@itemx --sleep-interval=@var{number} -+@opindex --sleep-interval -+Change the number of seconds to wait between iterations (the default is 1.0). -+During one iteration, every specified file is checked to see if it has -+changed size. -+Historical implementations of @command{tail} have required that -+@var{number} be an integer. However, GNU @command{tail} accepts -+an arbitrary floating point number (using a period before any -+fractional digits). -+ -+@itemx --pid=@var{pid} -+@opindex --pid -+When following by name or by descriptor, you may specify the process ID, -+@var{pid}, of the sole writer of all @var{file} arguments. Then, shortly -+after that process terminates, tail will also terminate. This will -+work properly only if the writer and the tailing process are running on -+the same machine. For example, to save the output of a build in a file -+and to watch the file grow, if you invoke @command{make} and @command{tail} -+like this then the tail process will stop when your build completes. -+Without this option, you would have had to kill the @code{tail -f} -+process yourself. -+ -+@example -+$ make >& makerr & tail --pid=$! -f makerr -+@end example -+ -+If you specify a @var{pid} that is not in use or that does not correspond -+to the process that is writing to the tailed files, then @command{tail} -+may terminate long before any @var{file}s stop growing or it may not -+terminate until long after the real writer has terminated. -+Note that @option{--pid} cannot be supported on some systems; @command{tail} -+will print a warning if this is the case. -+ -+@itemx --max-unchanged-stats=@var{n} -+@opindex --max-unchanged-stats -+When tailing a file by name, if there have been @var{n} (default -+n=@value{DEFAULT_MAX_N_UNCHANGED_STATS_BETWEEN_OPENS}) consecutive -+iterations for which the file has not changed, then -+@code{open}/@code{fstat} the file to determine if that file name is -+still associated with the same device/inode-number pair as before. -+When following a log file that is rotated, this is approximately the -+number of seconds between when tail prints the last pre-rotation lines -+and when it prints the lines that have accumulated in the new log file. -+This option is meaningful only when following by name. -+ -+@itemx -n @var{k} -+@itemx --lines=@var{k} -+@opindex -n -+@opindex --lines -+Output the last @var{k} lines. -+However, if @var{k} starts with a @samp{+}, start printing with the -+@var{k}th line from the start of each file, instead of from the end. -+Size multiplier suffixes are the same as with the @option{-c} option. -+ -+@item -q -+@itemx --quiet -+@itemx --silent -+@opindex -q -+@opindex --quiet -+@opindex --silent -+Never print file name headers. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Always print file name headers. -+ -+@end table -+ -+For compatibility @command{tail} also supports an obsolete usage -+@samp{tail -[@var{count}][bcl][f] [@var{file}]}, which is recognized -+only if it does not conflict with the usage described -+above. This obsolete form uses exactly one option and at most one -+file. In the option, @var{count} is an optional decimal number optionally -+followed by a size letter (@samp{b}, @samp{c}, @samp{l}) to mean count -+by 512-byte blocks, bytes, or lines, optionally followed by @samp{f} -+which has the same meaning as @option{-f}. -+ -+@vindex _POSIX2_VERSION -+On older systems, the leading @samp{-} can be replaced by @samp{+} in -+the obsolete option syntax with the same meaning as in counts, and -+obsolete usage overrides normal usage when the two conflict. -+This obsolete behavior can be enabled or disabled with the -+@env{_POSIX2_VERSION} environment variable (@pxref{Standards -+conformance}). -+ -+Scripts intended for use on standard hosts should avoid obsolete -+syntax and should use @option{-c @var{count}[b]}, @option{-n -+@var{count}}, and/or @option{-f} instead. If your script must also -+run on hosts that support only the obsolete syntax, you can often -+rewrite it to avoid problematic usages, e.g., by using @samp{sed -n -+'$p'} rather than @samp{tail -1}. If that's not possible, the script -+can use a test like @samp{if tail -c +1 /dev/null 2>&1; -+then @dots{}} to decide which syntax to use. -+ -+Even if your script assumes the standard behavior, you should still -+beware usages whose behaviors differ depending on the @acronym{POSIX} -+version. For example, avoid @samp{tail - main.c}, since it might be -+interpreted as either @samp{tail main.c} or as @samp{tail -- - -+main.c}; avoid @samp{tail -c 4}, since it might mean either @samp{tail -+-c4} or @samp{tail -c 10 4}; and avoid @samp{tail +4}, since it might -+mean either @samp{tail ./+4} or @samp{tail -n +4}. -+ -+@exitstatus -+ -+ -+@node split invocation -+@section @command{split}: Split a file into fixed-size pieces -+ -+@pindex split -+@cindex splitting a file into pieces -+@cindex pieces, splitting a file into -+ -+@command{split} creates output files containing consecutive sections of -+@var{input} (standard input if none is given or @var{input} is -+@samp{-}). Synopsis: -+ -+@example -+split [@var{option}] [@var{input} [@var{prefix}]] -+@end example -+ -+By default, @command{split} puts 1000 lines of @var{input} (or whatever is -+left over for the last section), into each output file. -+ -+@cindex output file name prefix -+The output files' names consist of @var{prefix} (@samp{x} by default) -+followed by a group of characters (@samp{aa}, @samp{ab}, @dots{} by -+default), such that concatenating the output files in traditional -+sorted order by file name produces -+the original input file. If the output file names are exhausted, -+@command{split} reports an error without deleting the output files -+that it did create. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -l @var{lines} -+@itemx --lines=@var{lines} -+@opindex -l -+@opindex --lines -+Put @var{lines} lines of @var{input} into each output file. -+ -+For compatibility @command{split} also supports an obsolete -+option syntax @option{-@var{lines}}. New scripts should use @option{-l -+@var{lines}} instead. -+ -+@item -b @var{size} -+@itemx --bytes=@var{size} -+@opindex -b -+@opindex --bytes -+Put @var{size} bytes of @var{input} into each output file. -+@multiplierSuffixes{size} -+ -+@item -C @var{size} -+@itemx --line-bytes=@var{size} -+@opindex -C -+@opindex --line-bytes -+Put into each output file as many complete lines of @var{input} as -+possible without exceeding @var{size} bytes. Individual lines longer than -+@var{size} bytes are broken into multiple files. -+@var{size} has the same format as for the @option{--bytes} option. -+ -+@item -a @var{length} -+@itemx --suffix-length=@var{length} -+@opindex -a -+@opindex --suffix-length -+Use suffixes of length @var{length}. The default @var{length} is 2. -+ -+@item -d -+@itemx --numeric-suffixes -+@opindex -d -+@opindex --numeric-suffixes -+Use digits in suffixes rather than lower-case letters. -+ -+@itemx --verbose -+@opindex --verbose -+Write a diagnostic just before each output file is opened. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node csplit invocation -+@section @command{csplit}: Split a file into context-determined pieces -+ -+@pindex csplit -+@cindex context splitting -+@cindex splitting a file into pieces by context -+ -+@command{csplit} creates zero or more output files containing sections of -+@var{input} (standard input if @var{input} is @samp{-}). Synopsis: -+ -+@example -+csplit [@var{option}]@dots{} @var{input} @var{pattern}@dots{} -+@end example -+ -+The contents of the output files are determined by the @var{pattern} -+arguments, as detailed below. An error occurs if a @var{pattern} -+argument refers to a nonexistent line of the input file (e.g., if no -+remaining line matches a given regular expression). After every -+@var{pattern} has been matched, any remaining input is copied into one -+last output file. -+ -+By default, @command{csplit} prints the number of bytes written to each -+output file after it has been created. -+ -+The types of pattern arguments are: -+ -+@table @samp -+ -+@item @var{n} -+Create an output file containing the input up to but not including line -+@var{n} (a positive integer). If followed by a repeat count, also -+create an output file containing the next @var{n} lines of the input -+file once for each repeat. -+ -+@item /@var{regexp}/[@var{offset}] -+Create an output file containing the current line up to (but not -+including) the next line of the input file that contains a match for -+@var{regexp}. The optional @var{offset} is an integer. -+If it is given, the input up to (but not including) the -+matching line plus or minus @var{offset} is put into the output file, -+and the line after that begins the next section of input. -+ -+@item %@var{regexp}%[@var{offset}] -+Like the previous type, except that it does not create an output -+file, so that section of the input file is effectively ignored. -+ -+@item @{@var{repeat-count}@} -+Repeat the previous pattern @var{repeat-count} additional -+times. The @var{repeat-count} can either be a positive integer or an -+asterisk, meaning repeat as many times as necessary until the input is -+exhausted. -+ -+@end table -+ -+The output files' names consist of a prefix (@samp{xx} by default) -+followed by a suffix. By default, the suffix is an ascending sequence -+of two-digit decimal numbers from @samp{00} to @samp{99}. In any case, -+concatenating the output files in sorted order by file name produces the -+original input file. -+ -+By default, if @command{csplit} encounters an error or receives a hangup, -+interrupt, quit, or terminate signal, it removes any output files -+that it has created so far before it exits. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -f @var{prefix} -+@itemx --prefix=@var{prefix} -+@opindex -f -+@opindex --prefix -+@cindex output file name prefix -+Use @var{prefix} as the output file name prefix. -+ -+@item -b @var{suffix} -+@itemx --suffix=@var{suffix} -+@opindex -b -+@opindex --suffix -+@cindex output file name suffix -+Use @var{suffix} as the output file name suffix. When this option is -+specified, the suffix string must include exactly one -+@code{printf(3)}-style conversion specification, possibly including -+format specification flags, a field width, a precision specifications, -+or all of these kinds of modifiers. The format letter must convert a -+binary integer argument to readable form; thus, only @samp{d}, @samp{i}, -+@samp{u}, @samp{o}, @samp{x}, and @samp{X} conversions are allowed. The -+entire @var{suffix} is given (with the current output file number) to -+@code{sprintf(3)} to form the file name suffixes for each of the -+individual output files in turn. If this option is used, the -+@option{--digits} option is ignored. -+ -+@item -n @var{digits} -+@itemx --digits=@var{digits} -+@opindex -n -+@opindex --digits -+Use output file names containing numbers that are @var{digits} digits -+long instead of the default 2. -+ -+@item -k -+@itemx --keep-files -+@opindex -k -+@opindex --keep-files -+Do not remove output files when errors are encountered. -+ -+@item -z -+@itemx --elide-empty-files -+@opindex -z -+@opindex --elide-empty-files -+Suppress the generation of zero-length output files. (In cases where -+the section delimiters of the input file are supposed to mark the first -+lines of each of the sections, the first output file will generally be a -+zero-length file unless you use this option.) The output file sequence -+numbers always run consecutively starting from 0, even when this option -+is specified. -+ -+@item -s -+@itemx -q -+@itemx --silent -+@itemx --quiet -+@opindex -s -+@opindex -q -+@opindex --silent -+@opindex --quiet -+Do not print counts of output file sizes. -+ -+@end table -+ -+@exitstatus -+ -+Here is an example of its usage. -+First, create an empty directory for the exercise, -+and cd into it: -+ -+@example -+$ mkdir d && cd d -+@end example -+ -+Now, split the sequence of 1..14 on lines that end with 0 or 5: -+ -+@example -+$ seq 14 | csplit - '/[05]$/' '@{*@}' -+8 -+10 -+15 -+@end example -+ -+Each number printed above is the size of an output -+file that csplit has just created. -+List the names of those output files: -+ -+@example -+$ ls -+xx00 xx01 xx02 -+@end example -+ -+Use @command{head} to show their contents: -+ -+@example -+$ head xx* -+==> xx00 <== -+1 -+2 -+3 -+4 -+ -+==> xx01 <== -+5 -+6 -+7 -+8 -+9 -+ -+==> xx02 <== -+10 -+11 -+12 -+13 -+14 -+@end example -+ -+@node Summarizing files -+@chapter Summarizing files -+ -+@cindex summarizing files -+ -+These commands generate just a few numbers representing entire -+contents of files. -+ -+@menu -+* wc invocation:: Print newline, word, and byte counts. -+* sum invocation:: Print checksum and block counts. -+* cksum invocation:: Print CRC checksum and byte counts. -+* md5sum invocation:: Print or check MD5 digests. -+* sha1sum invocation:: Print or check SHA-1 digests. -+* sha2 utilities:: Print or check SHA-2 digests. -+@end menu -+ -+ -+@node wc invocation -+@section @command{wc}: Print newline, word, and byte counts -+ -+@pindex wc -+@cindex byte count -+@cindex character count -+@cindex word count -+@cindex line count -+ -+@command{wc} counts the number of bytes, characters, whitespace-separated -+words, and newlines in each given @var{file}, or standard input if none -+are given or for a @var{file} of @samp{-}. Synopsis: -+ -+@example -+wc [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@cindex total counts -+@command{wc} prints one line of counts for each file, and if the file was -+given as an argument, it prints the file name following the counts. If -+more than one @var{file} is given, @command{wc} prints a final line -+containing the cumulative counts, with the file name @file{total}. The -+counts are printed in this order: newlines, words, characters, bytes, -+maximum line length. -+Each count is printed right-justified in a field with at least one -+space between fields so that the numbers and file names normally line -+up nicely in columns. The width of the count fields varies depending -+on the inputs, so you should not depend on a particular field width. -+However, as a @acronym{GNU} extension, if only one count is printed, -+it is guaranteed to be printed without leading spaces. -+ -+By default, @command{wc} prints three counts: the newline, words, and byte -+counts. Options can specify that only certain counts be printed. -+Options do not undo others previously given, so -+ -+@example -+wc --bytes --words -+@end example -+ -+@noindent -+prints both the byte counts and the word counts. -+ -+With the @option{--max-line-length} option, @command{wc} prints the length -+of the longest line per file, and if there is more than one file it -+prints the maximum (not the sum) of those lengths. The line lengths here -+are measured in screen columns, according to the current locale and -+assuming tab positions in every 8th column. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c -+@itemx --bytes -+@opindex -c -+@opindex --bytes -+Print only the byte counts. -+ -+@item -m -+@itemx --chars -+@opindex -m -+@opindex --chars -+Print only the character counts. -+ -+@item -w -+@itemx --words -+@opindex -w -+@opindex --words -+Print only the word counts. -+ -+@item -l -+@itemx --lines -+@opindex -l -+@opindex --lines -+Print only the newline counts. -+ -+@item -L -+@itemx --max-line-length -+@opindex -L -+@opindex --max-line-length -+Print only the maximum line lengths. -+ -+@macro filesZeroFromOption{cmd,withTotalOption,subListOutput} -+@itemx --files0-from=@var{file} -+@opindex --files0-from=@var{file} -+@c This is commented out to avoid a texi2dvi failure. -+@c texi2dvi (GNU Texinfo 4.11) 1.104 -+@c @cindex including files from @command{\cmd\} -+Disallow processing files named on the command line, and instead process -+those named in file @var{file}; each name being terminated by a zero byte -+(@acronym{ASCII} @sc{nul}). -+This is useful \withTotalOption\ -+when the list of file names is so long that it may exceed a command line -+length limitation. -+In such cases, running @command{\cmd\} via @command{xargs} is undesirable -+because it splits the list into pieces and makes @command{\cmd\} print -+\subListOutput\ for each sublist rather than for the entire list. -+One way to produce a list of @acronym{ASCII} @sc{nul} terminated file names is with @sc{gnu} -+@command{find}, using its @option{-print0} predicate. -+If @var{file} is @samp{-} then the @acronym{ASCII} @sc{nul} terminated file names -+are read from standard input. -+@end macro -+@filesZeroFromOption{wc,,a total} -+ -+For example, to find the length of the longest line in any @file{.c} or -+@file{.h} file in the current hierarchy, do this: -+ -+@example -+find . -name '*.[ch]' -print0 | -+ wc -L --files0-from=- | tail -n1 -+@end example -+ -+@end table -+ -+@exitstatus -+ -+ -+@node sum invocation -+@section @command{sum}: Print checksum and block counts -+ -+@pindex sum -+@cindex 16-bit checksum -+@cindex checksum, 16-bit -+ -+@command{sum} computes a 16-bit checksum for each given @var{file}, or -+standard input if none are given or for a @var{file} of @samp{-}. Synopsis: -+ -+@example -+sum [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@command{sum} prints the checksum for each @var{file} followed by the -+number of blocks in the file (rounded up). If more than one @var{file} -+is given, file names are also printed (by default). (With the -+@option{--sysv} option, corresponding file names are printed when there is -+at least one file argument.) -+ -+By default, @sc{gnu} @command{sum} computes checksums using an algorithm -+compatible with BSD @command{sum} and prints file sizes in units of -+1024-byte blocks. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -r -+@opindex -r -+@cindex BSD @command{sum} -+Use the default (BSD compatible) algorithm. This option is included for -+compatibility with the System V @command{sum}. Unless @option{-s} was also -+given, it has no effect. -+ -+@item -s -+@itemx --sysv -+@opindex -s -+@opindex --sysv -+@cindex System V @command{sum} -+Compute checksums using an algorithm compatible with System V -+@command{sum}'s default, and print file sizes in units of 512-byte blocks. -+ -+@end table -+ -+@command{sum} is provided for compatibility; the @command{cksum} program (see -+next section) is preferable in new applications. -+ -+@exitstatus -+ -+ -+@node cksum invocation -+@section @command{cksum}: Print CRC checksum and byte counts -+ -+@pindex cksum -+@cindex cyclic redundancy check -+@cindex CRC checksum -+ -+@command{cksum} computes a cyclic redundancy check (CRC) checksum for each -+given @var{file}, or standard input if none are given or for a -+@var{file} of @samp{-}. Synopsis: -+ -+@example -+cksum [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@command{cksum} prints the CRC checksum for each file along with the number -+of bytes in the file, and the file name unless no arguments were given. -+ -+@command{cksum} is typically used to ensure that files -+transferred by unreliable means (e.g., netnews) have not been corrupted, -+by comparing the @command{cksum} output for the received files with the -+@command{cksum} output for the original files (typically given in the -+distribution). -+ -+The CRC algorithm is specified by the @acronym{POSIX} standard. It is not -+compatible with the BSD or System V @command{sum} algorithms (see the -+previous section); it is more robust. -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. -+ -+@exitstatus -+ -+ -+@node md5sum invocation -+@section @command{md5sum}: Print or check MD5 digests -+ -+@pindex md5sum -+@cindex MD5 -+@cindex 128-bit checksum -+@cindex checksum, 128-bit -+@cindex fingerprint, 128-bit -+@cindex message-digest, 128-bit -+ -+@command{md5sum} computes a 128-bit checksum (or @dfn{fingerprint} or -+@dfn{message-digest}) for each specified @var{file}. -+ -+Note: The MD5 digest is more reliable than a simple CRC (provided by -+the @command{cksum} command) for detecting accidental file corruption, -+as the chances of accidentally having two files with identical MD5 -+are vanishingly small. However, it should not be considered truly -+secure against malicious tampering: although finding a file with a -+given MD5 fingerprint, or modifying a file so as to retain its MD5 are -+considered infeasible at the moment, it is known how to produce -+different files with identical MD5 (a ``collision''), something which -+can be a security issue in certain contexts. For more secure hashes, -+consider using SHA-1 or SHA-2. @xref{sha1sum invocation}, and -+@ref{sha2 utilities}. -+ -+If a @var{file} is specified as @samp{-} or if no files are given -+@command{md5sum} computes the checksum for the standard input. -+@command{md5sum} can also determine whether a file and checksum are -+consistent. Synopsis: -+ -+@example -+md5sum [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+For each @var{file}, @samp{md5sum} outputs the MD5 checksum, a flag -+indicating a binary or text input file, and the file name. -+If @var{file} contains a backslash or newline, the -+line is started with a backslash, and each problematic character in -+the file name is escaped with a backslash, making the output -+unambiguous even in the presence of arbitrary file names. -+If @var{file} is omitted or specified as @samp{-}, standard input is read. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -b -+@itemx --binary -+@opindex -b -+@opindex --binary -+@cindex binary input files -+Treat each input file as binary, by reading it in binary mode and -+outputting a @samp{*} flag. This is the inverse of @option{--text}. -+On systems like @acronym{GNU} that do not distinguish between binary -+and text files, this option merely flags each input file as binary: -+the MD5 checksum is unaffected. This option is the default on systems -+like MS-DOS that distinguish between binary and text files, except -+for reading standard input when standard input is a terminal. -+ -+@item -c -+@itemx --check -+Read file names and checksum information (not data) from each -+@var{file} (or from stdin if no @var{file} was specified) and report -+whether the checksums match the contents of the named files. -+The input to this mode of @command{md5sum} is usually the output of -+a prior, checksum-generating run of @samp{md5sum}. -+Each valid line of input consists of an MD5 checksum, a binary/text -+flag, and then a file name. -+Binary files are marked with @samp{*}, text with @samp{ }. -+For each such line, @command{md5sum} reads the named file and computes its -+MD5 checksum. Then, if the computed message digest does not match the -+one on the line with the file name, the file is noted as having -+failed the test. Otherwise, the file passes the test. -+By default, for each valid line, one line is written to standard -+output indicating whether the named file passed the test. -+After all checks have been performed, if there were any failures, -+a warning is issued to standard error. -+Use the @option{--status} option to inhibit that output. -+If any listed file cannot be opened or read, if any valid line has -+an MD5 checksum inconsistent with the associated file, or if no valid -+line is found, @command{md5sum} exits with nonzero status. Otherwise, -+it exits successfully. -+ -+@itemx --quiet -+@opindex --quiet -+@cindex verifying MD5 checksums -+This option is useful only when verifying checksums. -+When verifying checksums, don't generate an 'OK' message per successfully -+checked file. Files that fail the verification are reported in the -+default one-line-per-file format. If there is any checksum mismatch, -+print a warning summarizing the failures to standard error. -+ -+@itemx --status -+@opindex --status -+@cindex verifying MD5 checksums -+This option is useful only when verifying checksums. -+When verifying checksums, don't generate the default one-line-per-file -+diagnostic and don't output the warning summarizing any failures. -+Failures to open or read a file still evoke individual diagnostics to -+standard error. -+If all listed files are readable and are consistent with the associated -+MD5 checksums, exit successfully. Otherwise exit with a status code -+indicating there was a failure. -+ -+@item -t -+@itemx --text -+@opindex -t -+@opindex --text -+@cindex text input files -+Treat each input file as text, by reading it in text mode and -+outputting a @samp{ } flag. This is the inverse of @option{--binary}. -+This option is the default on systems like @acronym{GNU} that do not -+distinguish between binary and text files. On other systems, it is -+the default for reading standard input when standard input is a -+terminal. -+ -+@item -w -+@itemx --warn -+@opindex -w -+@opindex --warn -+@cindex verifying MD5 checksums -+When verifying checksums, warn about improperly formatted MD5 checksum lines. -+This option is useful only if all but a few lines in the checked input -+are valid. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node sha1sum invocation -+@section @command{sha1sum}: Print or check SHA-1 digests -+ -+@pindex sha1sum -+@cindex SHA-1 -+@cindex 160-bit checksum -+@cindex checksum, 160-bit -+@cindex fingerprint, 160-bit -+@cindex message-digest, 160-bit -+ -+@command{sha1sum} computes a 160-bit checksum for each specified -+@var{file}. The usage and options of this command are precisely the -+same as for @command{md5sum}. @xref{md5sum invocation}. -+ -+Note: The SHA-1 digest is more secure than MD5, and no collisions of -+it are known (different files having the same fingerprint). However, -+it is known that they can be produced with considerable, but not -+unreasonable, resources. For this reason, it is generally considered -+that SHA-1 should be gradually phased out in favor of the more secure -+SHA-2 hash algorithms. @xref{sha2 utilities}. -+ -+ -+@node sha2 utilities -+@section sha2 utilities: Print or check SHA-2 digests -+ -+@pindex sha224sum -+@pindex sha256sum -+@pindex sha384sum -+@pindex sha512sum -+@cindex SHA-2 -+@cindex 224-bit checksum -+@cindex 256-bit checksum -+@cindex 384-bit checksum -+@cindex 512-bit checksum -+@cindex checksum, 224-bit -+@cindex checksum, 256-bit -+@cindex checksum, 384-bit -+@cindex checksum, 512-bit -+@cindex fingerprint, 224-bit -+@cindex fingerprint, 256-bit -+@cindex fingerprint, 384-bit -+@cindex fingerprint, 512-bit -+@cindex message-digest, 224-bit -+@cindex message-digest, 256-bit -+@cindex message-digest, 384-bit -+@cindex message-digest, 512-bit -+ -+The commands @command{sha224sum}, @command{sha256sum}, -+@command{sha384sum} and @command{sha512sum} compute checksums of -+various lengths (respectively 224, 256, 384 and 512 bits), -+collectively known as the SHA-2 hashes. The usage and options of -+these commands are precisely the same as for @command{md5sum}. -+@xref{md5sum invocation}. -+ -+Note: The SHA384 and SHA512 digests are considerably slower to -+compute, especially on 32-bit computers, than SHA224 or SHA256. -+ -+ -+@node Operating on sorted files -+@chapter Operating on sorted files -+ -+@cindex operating on sorted files -+@cindex sorted files, operations on -+ -+These commands work with (or produce) sorted files. -+ -+@menu -+* sort invocation:: Sort text files. -+* shuf invocation:: Shuffle text files. -+* uniq invocation:: Uniquify files. -+* comm invocation:: Compare two sorted files line by line. -+* ptx invocation:: Produce a permuted index of file contents. -+* tsort invocation:: Topological sort. -+@end menu -+ -+ -+@node sort invocation -+@section @command{sort}: Sort text files -+ -+@pindex sort -+@cindex sorting files -+ -+@command{sort} sorts, merges, or compares all the lines from the given -+files, or standard input if none are given or for a @var{file} of -+@samp{-}. By default, @command{sort} writes the results to standard -+output. Synopsis: -+ -+@example -+sort [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@command{sort} has three modes of operation: sort (the default), merge, -+and check for sortedness. The following options change the operation -+mode: -+ -+@table @samp -+ -+@item -c -+@itemx --check -+@itemx --check=diagnose-first -+@opindex -c -+@opindex --check -+@cindex checking for sortedness -+Check whether the given file is already sorted: if it is not all -+sorted, print a diagnostic containing the first out-of-order line and -+exit with a status of 1. -+Otherwise, exit successfully. -+At most one input file can be given. -+ -+@item -C -+@itemx --check=quiet -+@itemx --check=silent -+@opindex -c -+@opindex --check -+@cindex checking for sortedness -+Exit successfully if the given file is already sorted, and -+exit with status 1 otherwise. -+At most one input file can be given. -+This is like @option{-c}, except it does not print a diagnostic. -+ -+@item -m -+@itemx --merge -+@opindex -m -+@opindex --merge -+@cindex merging sorted files -+Merge the given files by sorting them as a group. Each input file must -+always be individually sorted. It always works to sort instead of -+merge; merging is provided because it is faster, in the case where it -+works. -+ -+@end table -+ -+@cindex sort stability -+@cindex sort's last-resort comparison -+A pair of lines is compared as follows: -+@command{sort} compares each pair of fields, in the -+order specified on the command line, according to the associated -+ordering options, until a difference is found or no fields are left. -+If no key fields are specified, @command{sort} uses a default key of -+the entire line. Finally, as a last resort when all keys compare -+equal, @command{sort} compares entire lines as if no ordering options -+other than @option{--reverse} (@option{-r}) were specified. The -+@option{--stable} (@option{-s}) option disables this @dfn{last-resort -+comparison} so that lines in which all fields compare equal are left -+in their original relative order. The @option{--unique} -+(@option{-u}) option also disables the last-resort comparison. -+ -+@vindex LC_ALL -+@vindex LC_COLLATE -+Unless otherwise specified, all comparisons use the character collating -+sequence specified by the @env{LC_COLLATE} locale.@footnote{If you -+use a non-@acronym{POSIX} locale (e.g., by setting @env{LC_ALL} -+to @samp{en_US}), then @command{sort} may produce output that is sorted -+differently than you're accustomed to. In that case, set the @env{LC_ALL} -+environment variable to @samp{C}. Note that setting only @env{LC_COLLATE} -+has two problems. First, it is ineffective if @env{LC_ALL} is also set. -+Second, it has undefined behavior if @env{LC_CTYPE} (or @env{LANG}, if -+@env{LC_CTYPE} is unset) is set to an incompatible value. For example, -+you get undefined behavior if @env{LC_CTYPE} is @code{ja_JP.PCK} but -+@env{LC_COLLATE} is @code{en_US.UTF-8}.} -+ -+@sc{gnu} @command{sort} (as specified for all @sc{gnu} utilities) has no -+limit on input line length or restrictions on bytes allowed within lines. -+In addition, if the final byte of an input file is not a newline, @sc{gnu} -+@command{sort} silently supplies one. A line's trailing newline is not -+part of the line for comparison purposes. -+ -+@cindex exit status of @command{sort} -+Exit status: -+ -+@display -+0 if no error occurred -+1 if invoked with @option{-c} or @option{-C} and the input is not sorted -+2 if an error occurred -+@end display -+ -+@vindex TMPDIR -+If the environment variable @env{TMPDIR} is set, @command{sort} uses its -+value as the directory for temporary files instead of @file{/tmp}. The -+@option{--temporary-directory} (@option{-T}) option in turn overrides -+the environment variable. -+ -+The following options affect the ordering of output lines. They may be -+specified globally or as part of a specific key field. If no key -+fields are specified, global options apply to comparison of entire -+lines; otherwise the global options are inherited by key fields that do -+not specify any special options of their own. In pre-@acronym{POSIX} -+versions of @command{sort}, global options affect only later key fields, -+so portable shell scripts should specify global options first. -+ -+@table @samp -+ -+@item -b -+@itemx --ignore-leading-blanks -+@opindex -b -+@opindex --ignore-leading-blanks -+@cindex blanks, ignoring leading -+@vindex LC_CTYPE -+Ignore leading blanks when finding sort keys in each line. -+By default a blank is a space or a tab, but the @env{LC_CTYPE} locale -+can change this. Note blanks may be ignored by your locale's collating -+rules, but without this option they will be significant for character -+positions specified in keys with the @option{-k} option. -+ -+@item -d -+@itemx --dictionary-order -+@opindex -d -+@opindex --dictionary-order -+@cindex dictionary order -+@cindex phone directory order -+@cindex telephone directory order -+@vindex LC_CTYPE -+Sort in @dfn{phone directory} order: ignore all characters except -+letters, digits and blanks when sorting. -+By default letters and digits are those of @acronym{ASCII} and a blank -+is a space or a tab, but the @env{LC_CTYPE} locale can change this. -+ -+@item -f -+@itemx --ignore-case -+@opindex -f -+@opindex --ignore-case -+@cindex ignoring case -+@cindex case folding -+@vindex LC_CTYPE -+Fold lowercase characters into the equivalent uppercase characters when -+comparing so that, for example, @samp{b} and @samp{B} sort as equal. -+The @env{LC_CTYPE} locale determines character types. -+When used with @option{--unique} those lower case equivalent lines are -+thrown away. (There is currently no way to throw away the upper case -+equivalent instead. (Any @option{--reverse} given would only affect -+the final result, after the throwing away.)) -+ -+@item -g -+@itemx --general-numeric-sort -+@itemx --sort=general-numeric -+@opindex -g -+@opindex --general-numeric-sort -+@opindex --sort -+@cindex general numeric sort -+@vindex LC_NUMERIC -+Sort numerically, using the standard C function @code{strtod} to convert -+a prefix of each line to a double-precision floating point number. -+This allows floating point numbers to be specified in scientific notation, -+like @code{1.0e-34} and @code{10e100}. -+The @env{LC_NUMERIC} locale determines the decimal-point character. -+Do not report overflow, underflow, or conversion errors. -+Use the following collating sequence: -+ -+@itemize @bullet -+@item -+Lines that do not start with numbers (all considered to be equal). -+@item -+NaNs (``Not a Number'' values, in IEEE floating point arithmetic) -+in a consistent but machine-dependent order. -+@item -+Minus infinity. -+@item -+Finite numbers in ascending numeric order (with @math{-0} and @math{+0} equal). -+@item -+Plus infinity. -+@end itemize -+ -+Use this option only if there is no alternative; it is much slower than -+@option{--numeric-sort} (@option{-n}) and it can lose information when -+converting to floating point. -+ -+@item -h -+@itemx --human-numeric-sort -+@itemx --sort=human-numeric -+@opindex -h -+@opindex --human-numeric-sort -+@opindex --sort -+@cindex human numeric sort -+@vindex LC_NUMERIC -+Sort numerically, as per the @option{--numeric-sort} option below, and in -+addition handle IEC or SI suffixes like MiB, MB etc (@ref{Block size}). -+Note a mixture of IEC and SI suffixes is not supported and will -+be flagged as an error. Also the numbers must be abbreviated uniformly. -+I.E. values with different precisions like 6000K and 5M will be sorted -+incorrectly. -+ -+@item -i -+@itemx --ignore-nonprinting -+@opindex -i -+@opindex --ignore-nonprinting -+@cindex nonprinting characters, ignoring -+@cindex unprintable characters, ignoring -+@vindex LC_CTYPE -+Ignore nonprinting characters. -+The @env{LC_CTYPE} locale determines character types. -+This option has no effect if the stronger @option{--dictionary-order} -+(@option{-d}) option is also given. -+ -+@item -M -+@itemx --month-sort -+@itemx --sort=month -+@opindex -M -+@opindex --month-sort -+@opindex --sort -+@cindex months, sorting by -+@vindex LC_TIME -+An initial string, consisting of any amount of blanks, followed -+by a month name abbreviation, is folded to UPPER case and -+compared in the order @samp{JAN} < @samp{FEB} < @dots{} < @samp{DEC}. -+Invalid names compare low to valid names. The @env{LC_TIME} locale -+category determines the month spellings. -+By default a blank is a space or a tab, but the @env{LC_CTYPE} locale -+can change this. -+ -+@item -n -+@itemx --numeric-sort -+@itemx --sort=numeric -+@opindex -n -+@opindex --numeric-sort -+@opindex --sort -+@cindex numeric sort -+@vindex LC_NUMERIC -+Sort numerically. The number begins each line and consists -+of optional blanks, an optional @samp{-} sign, and zero or more -+digits possibly separated by thousands separators, optionally followed -+by a decimal-point character and zero or more digits. An empty -+number is treated as @samp{0}. The @env{LC_NUMERIC} -+locale specifies the decimal-point character and thousands separator. -+By default a blank is a space or a tab, but the @env{LC_CTYPE} locale -+can change this. -+ -+Comparison is exact; there is no rounding error. -+ -+Neither a leading @samp{+} nor exponential notation is recognized. -+To compare such strings numerically, use the -+@option{--general-numeric-sort} (@option{-g}) option. -+ -+@item -V -+@itemx --version-sort -+@opindex -V -+@opindex --version-sort -+@cindex version number sort -+@vindex LC_NUMERIC -+Sort per @code{strverscmp(3)}. This is a normal string comparison, except -+that embedded decimal numbers are sorted by numeric value -+(see @option{--numeric-sort} above). -+ -+@item -r -+@itemx --reverse -+@opindex -r -+@opindex --reverse -+@cindex reverse sorting -+Reverse the result of comparison, so that lines with greater key values -+appear earlier in the output instead of later. -+ -+@item -R -+@itemx --random-sort -+@itemx --sort=random -+@opindex -R -+@opindex --random-sort -+@opindex --sort -+@cindex random sort -+Sort by hashing the input keys and then sorting the hash values. -+Choose the hash function at random, ensuring that it is free of -+collisions so that differing keys have differing hash values. This is -+like a random permutation of the inputs (@pxref{shuf invocation}), -+except that keys with the same value sort together. -+ -+If multiple random sort fields are specified, the same random hash -+function is used for all fields. To use different random hash -+functions for different fields, you can invoke @command{sort} more -+than once. -+ -+The choice of hash function is affected by the -+@option{--random-source} option. -+ -+@end table -+ -+Other options are: -+ -+@table @samp -+ -+@item --compress-program=@var{prog} -+Compress any temporary files with the program @var{prog}. -+ -+With no arguments, @var{prog} must compress standard input to standard -+output, and when given the @option{-d} option it must decompress -+standard input to standard output. -+ -+Terminate with an error if @var{prog} exits with nonzero status. -+ -+White space and the backslash character should not appear in -+@var{prog}; they are reserved for future use. -+ -+@filesZeroFromOption{sort,,sorted output} -+ -+@item -k @var{pos1}[,@var{pos2}] -+@itemx --key=@var{pos1}[,@var{pos2}] -+@opindex -k -+@opindex --key -+@cindex sort field -+Specify a sort field that consists of the part of the line between -+@var{pos1} and @var{pos2} (or the end of the line, if @var{pos2} is -+omitted), @emph{inclusive}. -+ -+Each @var{pos} has the form @samp{@var{f}[.@var{c}][@var{opts}]}, -+where @var{f} is the number of the field to use, and @var{c} is the number -+of the first character from the beginning of the field. Fields and character -+positions are numbered starting with 1; a character position of zero in -+@var{pos2} indicates the field's last character. If @samp{.@var{c}} is -+omitted from @var{pos1}, it defaults to 1 (the beginning of the field); -+if omitted from @var{pos2}, it defaults to 0 (the end of the field). -+@var{opts} are ordering options, allowing individual keys to be sorted -+according to different rules; see below for details. Keys can span -+multiple fields. -+ -+Example: To sort on the second field, use @option{--key=2,2} -+(@option{-k 2,2}). See below for more notes on keys and more examples. -+ -+@item --batch-size=@var{nmerge} -+@opindex --batch-size -+@cindex number of inputs to merge, nmerge -+Merge at most @var{nmerge} inputs at once. -+ -+When @command{sort} has to merge more than @var{nmerge} inputs, -+it merges them in groups of @var{nmerge}, saving the result in -+a temporary file, which is then used as an input in a subsequent merge. -+ -+A large value of @var{nmerge} may improve merge performance and decrease -+temporary storage utilization at the expense of increased memory usage -+and I/0. Conversely a small value of @var{nmerge} may reduce memory -+requirements and I/0 at the expense of temporary storage consumption and -+merge performance. -+ -+The value of @var{nmerge} must be at least 2. The default value is -+currently 16, but this is implementation-dependent and may change in -+the future. -+ -+The value of @var{nmerge} may be bounded by a resource limit for open -+file descriptors. The commands @samp{ulimit -n} or @samp{getconf -+OPEN_MAX} may display limits for your systems; these limits may be -+modified further if your program already has some files open, or if -+the operating system has other limits on the number of open files. If -+the value of @var{nmerge} exceeds the resource limit, @command{sort} -+silently uses a smaller value. -+ -+@item -o @var{output-file} -+@itemx --output=@var{output-file} -+@opindex -o -+@opindex --output -+@cindex overwriting of input, allowed -+Write output to @var{output-file} instead of standard output. -+Normally, @command{sort} reads all input before opening -+@var{output-file}, so you can safely sort a file in place by using -+commands like @code{sort -o F F} and @code{cat F | sort -o F}. -+However, @command{sort} with @option{--merge} (@option{-m}) can open -+the output file before reading all input, so a command like @code{cat -+F | sort -m -o F - G} is not safe as @command{sort} might start -+writing @file{F} before @command{cat} is done reading it. -+ -+@vindex POSIXLY_CORRECT -+On newer systems, @option{-o} cannot appear after an input file if -+@env{POSIXLY_CORRECT} is set, e.g., @samp{sort F -o F}. Portable -+scripts should specify @option{-o @var{output-file}} before any input -+files. -+ -+@item --random-source=@var{file} -+@opindex --random-source -+@cindex random source for sorting -+Use @var{file} as a source of random data used to determine which -+random hash function to use with the @option{-R} option. @xref{Random -+sources}. -+ -+@item -s -+@itemx --stable -+@opindex -s -+@opindex --stable -+@cindex sort stability -+@cindex sort's last-resort comparison -+ -+Make @command{sort} stable by disabling its last-resort comparison. -+This option has no effect if no fields or global ordering options -+other than @option{--reverse} (@option{-r}) are specified. -+ -+@item -S @var{size} -+@itemx --buffer-size=@var{size} -+@opindex -S -+@opindex --buffer-size -+@cindex size for main memory sorting -+Use a main-memory sort buffer of the given @var{size}. By default, -+@var{size} is in units of 1024 bytes. Appending @samp{%} causes -+@var{size} to be interpreted as a percentage of physical memory. -+Appending @samp{K} multiplies @var{size} by 1024 (the default), -+@samp{M} by 1,048,576, @samp{G} by 1,073,741,824, and so on for -+@samp{T}, @samp{P}, @samp{E}, @samp{Z}, and @samp{Y}. Appending -+@samp{b} causes @var{size} to be interpreted as a byte count, with no -+multiplication. -+ -+This option can improve the performance of @command{sort} by causing it -+to start with a larger or smaller sort buffer than the default. -+However, this option affects only the initial buffer size. The buffer -+grows beyond @var{size} if @command{sort} encounters input lines larger -+than @var{size}. -+ -+@item -t @var{separator} -+@itemx --field-separator=@var{separator} -+@opindex -t -+@opindex --field-separator -+@cindex field separator character -+Use character @var{separator} as the field separator when finding the -+sort keys in each line. By default, fields are separated by the empty -+string between a non-blank character and a blank character. -+By default a blank is a space or a tab, but the @env{LC_CTYPE} locale -+can change this. -+ -+That is, given the input line @w{@samp{ foo bar}}, @command{sort} breaks it -+into fields @w{@samp{ foo}} and @w{@samp{ bar}}. The field separator is -+not considered to be part of either the field preceding or the field -+following, so with @samp{sort @w{-t " "}} the same input line has -+three fields: an empty field, @samp{foo}, and @samp{bar}. -+However, fields that extend to the end of the line, -+as @option{-k 2}, or fields consisting of a range, as @option{-k 2,3}, -+retain the field separators present between the endpoints of the range. -+ -+To specify @acronym{ASCII} @sc{nul} as the field separator, -+use the two-character string @samp{\0}, e.g., @samp{sort -t '\0'}. -+ -+@item -T @var{tempdir} -+@itemx --temporary-directory=@var{tempdir} -+@opindex -T -+@opindex --temporary-directory -+@cindex temporary directory -+@vindex TMPDIR -+Use directory @var{tempdir} to store temporary files, overriding the -+@env{TMPDIR} environment variable. If this option is given more than -+once, temporary files are stored in all the directories given. If you -+have a large sort or merge that is I/O-bound, you can often improve -+performance by using this option to specify directories on different -+disks and controllers. -+ -+@item -u -+@itemx --unique -+@opindex -u -+@opindex --unique -+@cindex uniquifying output -+ -+Normally, output only the first of a sequence of lines that compare -+equal. For the @option{--check} (@option{-c} or @option{-C}) option, -+check that no pair of consecutive lines compares equal. -+ -+This option also disables the default last-resort comparison. -+ -+The commands @code{sort -u} and @code{sort | uniq} are equivalent, but -+this equivalence does not extend to arbitrary @command{sort} options. -+For example, @code{sort -n -u} inspects only the value of the initial -+numeric string when checking for uniqueness, whereas @code{sort -n | -+uniq} inspects the entire line. @xref{uniq invocation}. -+ -+@macro zeroTerminatedOption -+@item -z -+@itemx --zero-terminated -+@opindex -z -+@opindex --zero-terminated -+@cindex process zero-terminated items -+Delimit items with a zero byte rather than a newline (@acronym{ASCII} @sc{lf}). -+I.E. treat input as items separated by @acronym{ASCII} @sc{nul} -+and terminate output items with @acronym{ASCII} @sc{nul}. -+This option can be useful in conjunction with @samp{perl -0} or -+@samp{find -print0} and @samp{xargs -0} which do the same in order to -+reliably handle arbitrary file names (even those containing blanks -+or other special characters). -+@end macro -+@zeroTerminatedOption -+ -+@end table -+ -+Historical (BSD and System V) implementations of @command{sort} have -+differed in their interpretation of some options, particularly -+@option{-b}, @option{-f}, and @option{-n}. @sc{gnu} sort follows the @acronym{POSIX} -+behavior, which is usually (but not always!) like the System V behavior. -+According to @acronym{POSIX}, @option{-n} no longer implies @option{-b}. For -+consistency, @option{-M} has been changed in the same way. This may -+affect the meaning of character positions in field specifications in -+obscure cases. The only fix is to add an explicit @option{-b}. -+ -+A position in a sort field specified with @option{-k} may have any -+of the option letters @samp{MbdfghinRrV} appended to it, in which case no -+global ordering options are inherited by that particular field. The -+@option{-b} option may be independently attached to either or both of -+the start and end positions of a field specification, and if it is -+inherited from the global options it will be attached to both. -+If input lines can contain leading or adjacent blanks and @option{-t} -+is not used, then @option{-k} is typically combined with @option{-b} or -+an option that implicitly ignores leading blanks (@samp{MghnV}) as otherwise -+the varying numbers of leading blanks in fields can cause confusing results. -+ -+If the start position in a sort field specifier falls after the end of -+the line or after the end field, the field is empty. If the @option{-b} -+option was specified, the @samp{.@var{c}} part of a field specification -+is counted from the first nonblank character of the field. -+ -+@vindex _POSIX2_VERSION -+@vindex POSIXLY_CORRECT -+On older systems, @command{sort} supports an obsolete origin-zero -+syntax @samp{+@var{pos1} [-@var{pos2}]} for specifying sort keys. -+This obsolete behavior can be enabled or disabled with the -+@env{_POSIX2_VERSION} environment variable (@pxref{Standards -+conformance}); it can also be enabled when @env{POSIXLY_CORRECT} is -+not set by using the obsolete syntax with @samp{-@var{pos2}} present. -+ -+Scripts intended for use on standard hosts should avoid obsolete -+syntax and should use @option{-k} instead. For example, avoid -+@samp{sort +2}, since it might be interpreted as either @samp{sort -+./+2} or @samp{sort -k 3}. If your script must also run on hosts that -+support only the obsolete syntax, it can use a test like @samp{if sort -+-k 1 /dev/null 2>&1; then @dots{}} to decide which syntax -+to use. -+ -+Here are some examples to illustrate various combinations of options. -+ -+@itemize @bullet -+ -+@item -+Sort in descending (reverse) numeric order. -+ -+@example -+sort -n -r -+@end example -+ -+@item -+Sort alphabetically, omitting the first and second fields -+and the blanks at the start of the third field. -+This uses a single key composed of the characters beginning -+at the start of the first nonblank character in field three -+and extending to the end of each line. -+ -+@example -+sort -k 3b -+@end example -+ -+@item -+Sort numerically on the second field and resolve ties by sorting -+alphabetically on the third and fourth characters of field five. -+Use @samp{:} as the field delimiter. -+ -+@example -+sort -t : -k 2,2n -k 5.3,5.4 -+@end example -+ -+Note that if you had written @option{-k 2n} instead of @option{-k 2,2n} -+@command{sort} would have used all characters beginning in the second field -+and extending to the end of the line as the primary @emph{numeric} -+key. For the large majority of applications, treating keys spanning -+more than one field as numeric will not do what you expect. -+ -+Also note that the @samp{n} modifier was applied to the field-end -+specifier for the first key. It would have been equivalent to -+specify @option{-k 2n,2} or @option{-k 2n,2n}. All modifiers except -+@samp{b} apply to the associated @emph{field}, regardless of whether -+the modifier character is attached to the field-start and/or the -+field-end part of the key specifier. -+ -+@item -+Sort the password file on the fifth field and ignore any -+leading blanks. Sort lines with equal values in field five -+on the numeric user ID in field three. Fields are separated -+by @samp{:}. -+ -+@example -+sort -t : -k 5b,5 -k 3,3n /etc/passwd -+sort -t : -n -k 5b,5 -k 3,3 /etc/passwd -+sort -t : -b -k 5,5 -k 3,3n /etc/passwd -+@end example -+ -+These three commands have equivalent effect. The first specifies that -+the first key's start position ignores leading blanks and the second -+key is sorted numerically. The other two commands rely on global -+options being inherited by sort keys that lack modifiers. The inheritance -+works in this case because @option{-k 5b,5b} and @option{-k 5b,5} are -+equivalent, as the location of a field-end lacking a @samp{.@var{c}} -+character position is not affected by whether initial blanks are -+skipped. -+ -+@item -+Sort a set of log files, primarily by IPv4 address and secondarily by -+time stamp. If two lines' primary and secondary keys are identical, -+output the lines in the same order that they were input. The log -+files contain lines that look like this: -+ -+@example -+4.150.156.3 - - [01/Apr/2004:06:31:51 +0000] message 1 -+211.24.3.231 - - [24/Apr/2004:20:17:39 +0000] message 2 -+@end example -+ -+Fields are separated by exactly one space. Sort IPv4 addresses -+lexicographically, e.g., 212.61.52.2 sorts before 212.129.233.201 -+because 61 is less than 129. -+ -+@example -+sort -s -t ' ' -k 4.9n -k 4.5M -k 4.2n -k 4.14,4.21 file*.log | -+sort -s -t '.' -k 1,1n -k 2,2n -k 3,3n -k 4,4n -+@end example -+ -+This example cannot be done with a single @command{sort} invocation, -+since IPv4 address components are separated by @samp{.} while dates -+come just after a space. So it is broken down into two invocations of -+@command{sort}: the first sorts by time stamp and the second by IPv4 -+address. The time stamp is sorted by year, then month, then day, and -+finally by hour-minute-second field, using @option{-k} to isolate each -+field. Except for hour-minute-second there's no need to specify the -+end of each key field, since the @samp{n} and @samp{M} modifiers sort -+based on leading prefixes that cannot cross field boundaries. The -+IPv4 addresses are sorted lexicographically. The second sort uses -+@samp{-s} so that ties in the primary key are broken by the secondary -+key; the first sort uses @samp{-s} so that the combination of the two -+sorts is stable. -+ -+@item -+Generate a tags file in case-insensitive sorted order. -+ -+@smallexample -+find src -type f -print0 | sort -z -f | xargs -0 etags --append -+@end smallexample -+ -+The use of @option{-print0}, @option{-z}, and @option{-0} in this case means -+that file names that contain blanks or other special characters are -+not broken up -+by the sort operation. -+ -+@c This example is a bit contrived and needs more explanation. -+@c @item -+@c Sort records separated by an arbitrary string by using a pipe to convert -+@c each record delimiter string to @samp{\0}, then using sort's -z option, -+@c and converting each @samp{\0} back to the original record delimiter. -+@c -+@c @example -+@c printf 'c\n\nb\n\na\n'|perl -0pe 's/\n\n/\n\0/g'|sort -z|perl -0pe 's/\0/\n/g' -+@c @end example -+ -+@item -+Use the common @acronym{DSU, Decorate Sort Undecorate} idiom to -+sort lines according to their length. -+ -+@example -+awk '@{print length, $0@}' /etc/passwd | sort -n | cut -f2- -d' ' -+@end example -+ -+In general this technique can be used to sort data that the @command{sort} -+command does not support, or is inefficient at, sorting directly. -+ -+@item -+Shuffle a list of directories, but preserve the order of files within -+each directory. For instance, one could use this to generate a music -+playlist in which albums are shuffled but the songs of each album are -+played in order. -+ -+@example -+ls */* | sort -t / -k 1,1R -k 2,2 -+@end example -+ -+@end itemize -+ -+ -+@node shuf invocation -+@section @command{shuf}: Shuffling text -+ -+@pindex shuf -+@cindex shuffling files -+ -+@command{shuf} shuffles its input by outputting a random permutation -+of its input lines. Each output permutation is equally likely. -+Synopses: -+ -+@example -+shuf [@var{option}]@dots{} [@var{file}] -+shuf -e [@var{option}]@dots{} [@var{arg}]@dots{} -+shuf -i @var{lo}-@var{hi} [@var{option}]@dots{} -+@end example -+ -+@command{shuf} has three modes of operation that affect where it -+obtains its input lines. By default, it reads lines from standard -+input. The following options change the operation mode: -+ -+@table @samp -+ -+@item -e -+@itemx --echo -+@opindex -c -+@opindex --echo -+@cindex command-line operands to shuffle -+Treat each command-line operand as an input line. -+ -+@item -i @var{lo}-@var{hi} -+@itemx --input-range=@var{lo}-@var{hi} -+@opindex -i -+@opindex --input-range -+@cindex input range to shuffle -+Act as if input came from a file containing the range of unsigned -+decimal integers @var{lo}@dots{}@var{hi}, one per line. -+ -+@end table -+ -+@command{shuf}'s other options can affect its behavior in all -+operation modes: -+ -+@table @samp -+ -+@item -n @var{lines} -+@itemx --head-count=@var{count} -+@opindex -n -+@opindex --head-count -+@cindex head of output -+Output at most @var{count} lines. By default, all input lines are -+output. -+ -+@item -o @var{output-file} -+@itemx --output=@var{output-file} -+@opindex -o -+@opindex --output -+@cindex overwriting of input, allowed -+Write output to @var{output-file} instead of standard output. -+@command{shuf} reads all input before opening -+@var{output-file}, so you can safely shuffle a file in place by using -+commands like @code{shuf -o F out -+$ dd bs=1 skip=222 count=6 < out 2>/dev/null; echo -+deeper -+@end example -+ -+Note that although the listing above includes a trailing slash -+for the @samp{deeper} entry, the offsets select the name without -+the trailing slash. However, if you invoke @command{ls} with @option{--dired} -+along with an option like @option{--escape} (aka @option{-b}) and operate -+on a file whose name contains special characters, notice that the backslash -+@emph{is} included: -+ -+@example -+$ touch 'a b' -+$ ls -blog --dired 'a b' -+ -rw-r--r-- 1 0 Jun 10 12:28 a\ b -+//DIRED// 30 34 -+//DIRED-OPTIONS// --quoting-style=escape -+@end example -+ -+If you use a quoting style that adds quote marks -+(e.g., @option{--quoting-style=c}), then the offsets include the quote marks. -+So beware that the user may select the quoting style via the environment -+variable @env{QUOTING_STYLE}. Hence, applications using @option{--dired} -+should either specify an explicit @option{--quoting-style=literal} option -+(aka @option{-N} or @option{--literal}) on the command line, or else be -+prepared to parse the escaped names. -+ -+@item --full-time -+@opindex --full-time -+Produce long format directory listings, and list times in full. It is -+equivalent to using @option{--format=long} with -+@option{--time-style=full-iso} (@pxref{Formatting file timestamps}). -+ -+@item -g -+@opindex -g -+Produce long format directory listings, but don't display owner information. -+ -+@item -G -+@itemx --no-group -+@opindex -G -+@opindex --no-group -+Inhibit display of group information in a long format directory listing. -+(This is the default in some non-@sc{gnu} versions of @command{ls}, so we -+provide this option for compatibility.) -+ -+@optHumanReadable -+ -+@item -i -+@itemx --inode -+@opindex -i -+@opindex --inode -+@cindex inode number, printing -+Print the inode number (also called the file serial number and index -+number) of each file to the left of the file name. (This number -+uniquely identifies each file within a particular file system.) -+ -+@item -l -+@itemx --format=long -+@itemx --format=verbose -+@opindex -l -+@opindex --format -+@opindex long ls @r{format} -+@opindex verbose ls @r{format} -+In addition to the name of each file, print the file type, file mode bits, -+number of hard links, owner name, group name, size, and -+timestamp (@pxref{Formatting file timestamps}), normally -+the modification time. Print question marks for information that -+cannot be determined. -+ -+Normally the size is printed as a byte count without punctuation, but -+this can be overridden (@pxref{Block size}). For example, @option{-h} -+prints an abbreviated, human-readable count, and -+@samp{--block-size="'1"} prints a byte count with the thousands -+separator of the current locale. -+ -+For each directory that is listed, preface the files with a line -+@samp{total @var{blocks}}, where @var{blocks} is the total disk allocation -+for all files in that directory. The block size currently defaults to 1024 -+bytes, but this can be overridden (@pxref{Block size}). -+The @var{blocks} computed counts each hard link separately; -+this is arguably a deficiency. -+ -+The file type is one of the following characters: -+ -+@c The commented-out entries are ones we're not sure about. -+ -+@table @samp -+@item - -+regular file -+@item b -+block special file -+@item c -+character special file -+@item C -+high performance (``contiguous data'') file -+@item d -+directory -+@item D -+door (Solaris 2.5 and up) -+@c @item F -+@c semaphore, if this is a distinct file type -+@item l -+symbolic link -+@c @item m -+@c multiplexed file (7th edition Unix; obsolete) -+@item M -+off-line (``migrated'') file (Cray DMF) -+@item n -+network special file (HP-UX) -+@item p -+FIFO (named pipe) -+@item P -+port (Solaris 10 and up) -+@c @item Q -+@c message queue, if this is a distinct file type -+@item s -+socket -+@c @item S -+@c shared memory object, if this is a distinct file type -+@c @item T -+@c typed memory object, if this is a distinct file type -+@c @item w -+@c whiteout (4.4BSD; not implemented) -+@item ? -+some other file type -+@end table -+ -+@cindex permissions, output by @command{ls} -+The file mode bits listed are similar to symbolic mode specifications -+(@pxref{Symbolic Modes}). But @command{ls} combines multiple bits into the -+third character of each set of permissions as follows: -+ -+@table @samp -+@item s -+If the set-user-ID or set-group-ID bit and the corresponding executable bit -+are both set. -+ -+@item S -+If the set-user-ID or set-group-ID bit is set but the corresponding -+executable bit is not set. -+ -+@item t -+If the restricted deletion flag or sticky bit, and the -+other-executable bit, are both set. The restricted deletion flag is -+another name for the sticky bit. @xref{Mode Structure}. -+ -+@item T -+If the restricted deletion flag or sticky bit is set but the -+other-executable bit is not set. -+ -+@item x -+If the executable bit is set and none of the above apply. -+ -+@item - -+Otherwise. -+@end table -+ -+Following the file mode bits is a single character that specifies -+whether an alternate access method such as an access control list -+applies to the file. When the character following the file mode bits is a -+space, there is no alternate access method. When it is a printing -+character, then there is such a method. -+ -+GNU @command{ls} uses a @samp{.} character to indicate a file -+with an SELinux security context, but no other alternate access method. -+ -+A file with any other combination of alternate access methods -+is marked with a @samp{+} character. -+ -+@item -n -+@itemx --numeric-uid-gid -+@opindex -n -+@opindex --numeric-uid-gid -+@cindex numeric uid and gid -+@cindex numeric user and group IDs -+Produce long format directory listings, but -+display numeric user and group IDs instead of the owner and group names. -+ -+@item -o -+@opindex -o -+Produce long format directory listings, but don't display group information. -+It is equivalent to using @option{--format=long} with @option{--no-group} . -+ -+@item -s -+@itemx --size -+@opindex -s -+@opindex --size -+@cindex disk allocation -+@cindex size of files, reporting -+Print the disk allocation of each file to the left of the file name. -+This is the amount of disk space used by the file, which is usually a -+bit more than the file's size, but it can be less if the file has holes. -+ -+Normally the disk allocation is printed in units of -+1024 bytes, but this can be overridden (@pxref{Block size}). -+ -+@cindex NFS mounts from BSD to HP-UX -+For files that are NFS-mounted from an HP-UX system to a BSD system, -+this option reports sizes that are half the correct values. On HP-UX -+systems, it reports sizes that are twice the correct values for files -+that are NFS-mounted from BSD systems. This is due to a flaw in HP-UX; -+it also affects the HP-UX @command{ls} program. -+ -+@optSi -+ -+@item -Z -+@itemx --context -+@opindex -Z -+@opindex --context -+@cindex SELinux -+@cindex security context -+Display the SELinux security context or @samp{?} if none is found. -+When used with the @option{-l} option, print the security context -+to the left of the size column. -+ -+@end table -+ -+ -+@node Sorting the output -+@subsection Sorting the output -+ -+@cindex sorting @command{ls} output -+These options change the order in which @command{ls} sorts the information -+it outputs. By default, sorting is done by character code -+(e.g., @acronym{ASCII} order). -+ -+@table @samp -+ -+@item -c -+@itemx --time=ctime -+@itemx --time=status -+@opindex -c -+@opindex --time -+@opindex ctime@r{, printing or sorting by} -+@opindex status time@r{, printing or sorting by} -+@opindex use time@r{, printing or sorting files by} -+If the long listing format (e.g., @option{-l}, @option{-o}) is being used, -+print the status change time (the @samp{ctime} in the inode) instead of -+the modification time. -+When explicitly sorting by time (@option{--sort=time} or @option{-t}) -+or when not using a long listing format, -+sort according to the status change time. -+ -+@item -f -+@opindex -f -+@cindex unsorted directory listing -+@cindex directory order, listing by -+Primarily, like @option{-U}---do not sort; list the files in whatever -+order they are stored in the directory. But also enable @option{-a} (list -+all files) and disable @option{-l}, @option{--color}, and @option{-s} (if they -+were specified before the @option{-f}). -+ -+@item -r -+@itemx --reverse -+@opindex -r -+@opindex --reverse -+@cindex reverse sorting -+Reverse whatever the sorting method is---e.g., list files in reverse -+alphabetical order, youngest first, smallest first, or whatever. -+ -+@item -S -+@itemx --sort=size -+@opindex -S -+@opindex --sort -+@opindex size of files@r{, sorting files by} -+Sort by file size, largest first. -+ -+@item -t -+@itemx --sort=time -+@opindex -t -+@opindex --sort -+@opindex modification time@r{, sorting files by} -+Sort by modification time (the @samp{mtime} in the inode), newest first. -+ -+@item -u -+@itemx --time=atime -+@itemx --time=access -+@itemx --time=use -+@opindex -u -+@opindex --time -+@opindex use time@r{, printing or sorting files by} -+@opindex atime@r{, printing or sorting files by} -+@opindex access time@r{, printing or sorting files by} -+If the long listing format (e.g., @option{--format=long}) is being used, -+print the last access time (the @samp{atime} in the inode). -+When explicitly sorting by time (@option{--sort=time} or @option{-t}) -+or when not using a long listing format, sort according to the access time. -+ -+@item -U -+@itemx --sort=none -+@opindex -U -+@opindex --sort -+@opindex none@r{, sorting option for @command{ls}} -+Do not sort; list the files in whatever order they are -+stored in the directory. (Do not do any of the other unrelated things -+that @option{-f} does.) This is especially useful when listing very large -+directories, since not doing any sorting can be noticeably faster. -+ -+@item -v -+@itemx --sort=version -+@opindex -v -+@opindex --sort -+@opindex version@r{, sorting option for @command{ls}} -+Sort by version name and number, lowest first. It behaves like a default -+sort, except that each sequence of decimal digits is treated numerically -+as an index/version number. (@xref{Details about version sort}.) -+ -+@item -X -+@itemx --sort=extension -+@opindex -X -+@opindex --sort -+@opindex extension@r{, sorting files by} -+Sort directory contents alphabetically by file extension (characters -+after the last @samp{.}); files with no extension are sorted first. -+ -+@end table -+ -+ -+@node Details about version sort -+@subsection Details about version sort -+ -+The version sort takes into account the fact that file names frequently include -+indices or version numbers. Standard sorting functions usually do not produce -+the ordering that people expect because comparisons are made on a -+character-by-character basis. The version -+sort addresses this problem, and is especially useful when browsing -+directories that contain many files with indices/version numbers in their -+names: -+ -+@example -+$ ls -1 $ ls -1v -+foo.zml-1.gz foo.zml-1.gz -+foo.zml-100.gz foo.zml-2.gz -+foo.zml-12.gz foo.zml-6.gz -+foo.zml-13.gz foo.zml-12.gz -+foo.zml-2.gz foo.zml-13.gz -+foo.zml-25.gz foo.zml-25.gz -+foo.zml-6.gz foo.zml-100.gz -+@end example -+ -+Version-sorted strings are compared such that if @var{ver1} and @var{ver2} -+are version numbers and @var{prefix} and @var{suffix} (@var{suffix} matching -+the regular expression @samp{(\.[A-Za-z~][A-Za-z0-9~]*)*}) are strings then -+@var{ver1} < @var{ver2} implies that the name composed of -+``@var{prefix} @var{ver1} @var{suffix}'' sorts before -+``@var{prefix} @var{ver2} @var{suffix}''. -+ -+Note also that leading zeros of numeric parts are ignored: -+ -+@example -+$ ls -1 $ ls -1v -+abc-1.007.tgz abc-1.01a.tgz -+abc-1.012b.tgz abc-1.007.tgz -+abc-1.01a.tgz abc-1.012b.tgz -+@end example -+ -+This functionality is implemented using gnulib's @code{filevercmp} function. -+One result of that implementation decision is that @samp{ls -v} -+and @samp{sort -V} do not use the locale category, @env{LC_COLLATE}, -+which means non-numeric prefixes are sorted as if @env{LC_COLLATE} were set -+to @samp{C}. -+ -+@node General output formatting -+@subsection General output formatting -+ -+These options affect the appearance of the overall output. -+ -+@table @samp -+ -+@item -1 -+@itemx --format=single-column -+@opindex -1 -+@opindex --format -+@opindex single-column @r{output of files} -+List one file per line. This is the default for @command{ls} when standard -+output is not a terminal. -+ -+@item -C -+@itemx --format=vertical -+@opindex -C -+@opindex --format -+@opindex vertical @r{sorted files in columns} -+List files in columns, sorted vertically. This is the default for -+@command{ls} if standard output is a terminal. It is always the default -+for the @command{dir} program. -+@sc{gnu} @command{ls} uses variable width columns to display as many files as -+possible in the fewest lines. -+ -+@item --color [=@var{when}] -+@opindex --color -+@cindex color, distinguishing file types with -+Specify whether to use color for distinguishing file types. @var{when} -+may be omitted, or one of: -+@itemize @bullet -+@item none -+@vindex none @r{color option} -+- Do not use color at all. This is the default. -+@item auto -+@vindex auto @r{color option} -+@cindex terminal, using color iff -+- Only use color if standard output is a terminal. -+@item always -+@vindex always @r{color option} -+- Always use color. -+@end itemize -+Specifying @option{--color} and no @var{when} is equivalent to -+@option{--color=always}. -+Piping a colorized listing through a pager like @command{more} or -+@command{less} usually produces unreadable results. However, using -+@code{more -f} does seem to work. -+ -+@item -F -+@itemx --classify -+@itemx --indicator-style=classify -+@opindex -F -+@opindex --classify -+@opindex --indicator-style -+@cindex file type and executables, marking -+@cindex executables and file type, marking -+Append a character to each file name indicating the file type. Also, -+for regular files that are executable, append @samp{*}. The file type -+indicators are @samp{/} for directories, @samp{@@} for symbolic links, -+@samp{|} for FIFOs, @samp{=} for sockets, @samp{>} for doors, -+and nothing for regular files. -+@c The following sentence is the same as the one for -d. -+Do not follow symbolic links listed on the -+command line unless the @option{--dereference-command-line} (@option{-H}), -+@option{--dereference} (@option{-L}), or -+@option{--dereference-command-line-symlink-to-dir} options are specified. -+ -+@item --file-type -+@itemx --indicator-style=file-type -+@opindex --file-type -+@opindex --indicator-style -+@cindex file type, marking -+Append a character to each file name indicating the file type. This is -+like @option{-F}, except that executables are not marked. -+ -+@item --indicator-style=@var{word} -+@opindex --indicator-style -+Append a character indicator with style @var{word} to entry names, -+as follows: -+ -+@table @samp -+@item none -+Do not append any character indicator; this is the default. -+@item slash -+Append @samp{/} for directories. This is the same as the @option{-p} -+option. -+@item file-type -+Append @samp{/} for directories, @samp{@@} for symbolic links, @samp{|} -+for FIFOs, @samp{=} for sockets, and nothing for regular files. This is -+the same as the @option{--file-type} option. -+@item classify -+Append @samp{*} for executable regular files, otherwise behave as for -+@samp{file-type}. This is the same as the @option{-F} or -+@option{--classify} option. -+@end table -+ -+@item -k -+@opindex -k -+Print file sizes in 1024-byte blocks, overriding the default block -+size (@pxref{Block size}). -+This option is equivalent to @option{--block-size=1K}. -+ -+@item -m -+@itemx --format=commas -+@opindex -m -+@opindex --format -+@opindex commas@r{, outputting between files} -+List files horizontally, with as many as will fit on each line, -+separated by @samp{, } (a comma and a space). -+ -+@item -p -+@itemx --indicator-style=slash -+@opindex -p -+@opindex --indicator-style -+@cindex file type, marking -+Append a @samp{/} to directory names. -+ -+@item -x -+@itemx --format=across -+@itemx --format=horizontal -+@opindex -x -+@opindex --format -+@opindex across@r{, listing files} -+@opindex horizontal@r{, listing files} -+List the files in columns, sorted horizontally. -+ -+@item -T @var{cols} -+@itemx --tabsize=@var{cols} -+@opindex -T -+@opindex --tabsize -+Assume that each tab stop is @var{cols} columns wide. The default is 8. -+@command{ls} uses tabs where possible in the output, for efficiency. If -+@var{cols} is zero, do not use tabs at all. -+ -+@c FIXME: remove in 2009, if Apple Terminal has been fixed for long enough. -+Some terminal emulators (at least Apple Terminal 1.5 (133) from Mac OS X 10.4.8) -+do not properly align columns to the right of a TAB following a -+non-@acronym{ASCII} byte. If you use such a terminal emulator, use the -+@option{-T0} option or put @code{TABSIZE=0} in your environment to tell -+@command{ls} to align using spaces, not tabs. -+ -+@item -w -+@itemx --width=@var{cols} -+@opindex -w -+@opindex --width -+@vindex COLUMNS -+Assume the screen is @var{cols} columns wide. The default is taken -+from the terminal settings if possible; otherwise the environment -+variable @env{COLUMNS} is used if it is set; otherwise the default -+is 80. -+ -+@end table -+ -+ -+@node Formatting file timestamps -+@subsection Formatting file timestamps -+ -+By default, file timestamps are listed in abbreviated form. Most -+locales use a timestamp like @samp{2002-03-30 23:45}. However, the -+default @acronym{POSIX} locale uses a date like @samp{Mar 30@ @ 2002} -+for non-recent timestamps, and a date-without-year and time like -+@samp{Mar 30 23:45} for recent timestamps. -+ -+A timestamp is considered to be @dfn{recent} if it is less than six -+months old, and is not dated in the future. If a timestamp dated -+today is not listed in recent form, the timestamp is in the future, -+which means you probably have clock skew problems which may break -+programs like @command{make} that rely on file timestamps. -+ -+@vindex TZ -+Time stamps are listed according to the time zone rules specified by -+the @env{TZ} environment variable, or by the system default rules if -+@env{TZ} is not set. @xref{TZ Variable,, Specifying the Time Zone -+with @env{TZ}, libc, The GNU C Library Reference Manual}. -+ -+The following option changes how file timestamps are printed. -+ -+@table @samp -+@item --time-style=@var{style} -+@opindex --time-style -+@cindex time style -+List timestamps in style @var{style}. The @var{style} should -+be one of the following: -+ -+@table @samp -+@item +@var{format} -+@vindex LC_TIME -+List timestamps using @var{format}, where @var{format} is interpreted -+like the format argument of @command{date} (@pxref{date invocation}). -+For example, @option{--time-style="+%Y-%m-%d %H:%M:%S"} causes -+@command{ls} to list timestamps like @samp{2002-03-30 23:45:56}. As -+with @command{date}, @var{format}'s interpretation is affected by the -+@env{LC_TIME} locale category. -+ -+If @var{format} contains two format strings separated by a newline, -+the former is used for non-recent files and the latter for recent -+files; if you want output columns to line up, you may need to insert -+spaces in one of the two formats. -+ -+@item full-iso -+List timestamps in full using @acronym{ISO} 8601 date, time, and time zone -+format with nanosecond precision, e.g., @samp{2002-03-30 -+23:45:56.477817180 -0700}. This style is equivalent to -+@samp{+%Y-%m-%d %H:%M:%S.%N %z}. -+ -+This is useful because the time output includes all the information that -+is available from the operating system. For example, this can help -+explain @command{make}'s behavior, since @acronym{GNU} @command{make} -+uses the full timestamp to determine whether a file is out of date. -+ -+@item long-iso -+List @acronym{ISO} 8601 date and time in minutes, e.g., -+@samp{2002-03-30 23:45}. These timestamps are shorter than -+@samp{full-iso} timestamps, and are usually good enough for everyday -+work. This style is equivalent to @samp{+%Y-%m-%d %H:%M}. -+ -+@item iso -+List @acronym{ISO} 8601 dates for non-recent timestamps (e.g., -+@samp{2002-03-30@ }), and @acronym{ISO} 8601 month, day, hour, and -+minute for recent timestamps (e.g., @samp{03-30 23:45}). These -+timestamps are uglier than @samp{long-iso} timestamps, but they carry -+nearly the same information in a smaller space and their brevity helps -+@command{ls} output fit within traditional 80-column output lines. -+The following two @command{ls} invocations are equivalent: -+ -+@example -+newline=' -+' -+ls -l --time-style="+%Y-%m-%d $newline%m-%d %H:%M" -+ls -l --time-style="iso" -+@end example -+ -+@item locale -+@vindex LC_TIME -+List timestamps in a locale-dependent form. For example, a Finnish -+locale might list non-recent timestamps like @samp{maalis 30@ @ 2002} -+and recent timestamps like @samp{maalis 30 23:45}. Locale-dependent -+timestamps typically consume more space than @samp{iso} timestamps and -+are harder for programs to parse because locale conventions vary so -+widely, but they are easier for many people to read. -+ -+The @env{LC_TIME} locale category specifies the timestamp format. The -+default @acronym{POSIX} locale uses timestamps like @samp{Mar 30@ -+@ 2002} and @samp{Mar 30 23:45}; in this locale, the following two -+@command{ls} invocations are equivalent: -+ -+@example -+newline=' -+' -+ls -l --time-style="+%b %e %Y$newline%b %e %H:%M" -+ls -l --time-style="locale" -+@end example -+ -+Other locales behave differently. For example, in a German locale, -+@option{--time-style="locale"} might be equivalent to -+@option{--time-style="+%e. %b %Y $newline%e. %b %H:%M"} -+and might generate timestamps like @samp{30. M@"ar 2002@ } and -+@samp{30. M@"ar 23:45}. -+ -+@item posix-@var{style} -+@vindex LC_TIME -+List @acronym{POSIX}-locale timestamps if the @env{LC_TIME} locale -+category is @acronym{POSIX}, @var{style} timestamps otherwise. For -+example, the @samp{posix-long-iso} style lists -+timestamps like @samp{Mar 30@ @ 2002} and @samp{Mar 30 23:45} when in -+the @acronym{POSIX} locale, and like @samp{2002-03-30 23:45} otherwise. -+@end table -+@end table -+ -+@vindex TIME_STYLE -+You can specify the default value of the @option{--time-style} option -+with the environment variable @env{TIME_STYLE}; if @env{TIME_STYLE} is not set -+the default style is @samp{locale}. @acronym{GNU} Emacs 21.3 and -+later use the @option{--dired} option and therefore can parse any date -+format, but if you are using Emacs 21.1 or 21.2 and specify a -+non-@acronym{POSIX} locale you may need to set -+@samp{TIME_STYLE="posix-long-iso"}. -+ -+To avoid certain denial-of-service attacks, timestamps that would be -+longer than 1000 bytes may be treated as errors. -+ -+ -+@node Formatting the file names -+@subsection Formatting the file names -+ -+These options change how file names themselves are printed. -+ -+@table @samp -+ -+@item -b -+@itemx --escape -+@itemx --quoting-style=escape -+@opindex -b -+@opindex --escape -+@opindex --quoting-style -+@cindex backslash sequences for file names -+Quote nongraphic characters in file names using alphabetic and octal -+backslash sequences like those used in C. -+ -+@item -N -+@itemx --literal -+@itemx --quoting-style=literal -+@opindex -N -+@opindex --literal -+@opindex --quoting-style -+Do not quote file names. However, with @command{ls} nongraphic -+characters are still printed as question marks if the output is a -+terminal and you do not specify the @option{--show-control-chars} -+option. -+ -+@item -q -+@itemx --hide-control-chars -+@opindex -q -+@opindex --hide-control-chars -+Print question marks instead of nongraphic characters in file names. -+This is the default if the output is a terminal and the program is -+@command{ls}. -+ -+@item -Q -+@itemx --quote-name -+@itemx --quoting-style=c -+@opindex -Q -+@opindex --quote-name -+@opindex --quoting-style -+Enclose file names in double quotes and quote nongraphic characters as -+in C. -+ -+@item --quoting-style=@var{word} -+@opindex --quoting-style -+@cindex quoting style -+Use style @var{word} to quote file names and other strings that may -+contain arbitrary characters. The @var{word} should -+be one of the following: -+ -+@table @samp -+@item literal -+Output strings as-is; this is the same as the @option{-N} or -+@option{--literal} option. -+@item shell -+Quote strings for the shell if they contain shell metacharacters or would -+cause ambiguous output. -+The quoting is suitable for @acronym{POSIX}-compatible shells like -+@command{bash}, but it does not always work for incompatible shells -+like @command{csh}. -+@item shell-always -+Quote strings for the shell, even if they would normally not require quoting. -+@item c -+Quote strings as for C character string literals, including the -+surrounding double-quote characters; this is the same as the -+@option{-Q} or @option{--quote-name} option. -+@item escape -+Quote strings as for C character string literals, except omit the -+surrounding double-quote -+characters; this is the same as the @option{-b} or @option{--escape} option. -+@item clocale -+Quote strings as for C character string literals, except use -+surrounding quotation marks appropriate for the -+locale. -+@item locale -+@c Use @t instead of @samp to avoid duplicate quoting in some output styles. -+Quote strings as for C character string literals, except use -+surrounding quotation marks appropriate for the locale, and quote -+@t{`like this'} instead of @t{"like -+this"} in the default C locale. This looks nicer on many displays. -+@end table -+ -+You can specify the default value of the @option{--quoting-style} option -+with the environment variable @env{QUOTING_STYLE}. If that environment -+variable is not set, the default value is @samp{literal}, but this -+default may change to @samp{shell} in a future version of this package. -+ -+@item --show-control-chars -+@opindex --show-control-chars -+Print nongraphic characters as-is in file names. -+This is the default unless the output is a terminal and the program is -+@command{ls}. -+ -+@end table -+ -+ -+@node dir invocation -+@section @command{dir}: Briefly list directory contents -+ -+@pindex dir -+@cindex directory listing, brief -+ -+@command{dir} is equivalent to @code{ls -C -+-b}; that is, by default files are listed in columns, sorted vertically, -+and special characters are represented by backslash escape sequences. -+ -+@xref{ls invocation, @command{ls}}. -+ -+ -+@node vdir invocation -+@section @command{vdir}: Verbosely list directory contents -+ -+@pindex vdir -+@cindex directory listing, verbose -+ -+@command{vdir} is equivalent to @code{ls -l -+-b}; that is, by default files are listed in long format and special -+characters are represented by backslash escape sequences. -+ -+@node dircolors invocation -+@section @command{dircolors}: Color setup for @command{ls} -+ -+@pindex dircolors -+@cindex color setup -+@cindex setup for color -+ -+@command{dircolors} outputs a sequence of shell commands to set up the -+terminal for color output from @command{ls} (and @command{dir}, etc.). -+Typical usage: -+ -+@example -+eval "`dircolors [@var{option}]@dots{} [@var{file}]`" -+@end example -+ -+If @var{file} is specified, @command{dircolors} reads it to determine which -+colors to use for which file types and extensions. Otherwise, a -+precompiled database is used. For details on the format of these files, -+run @samp{dircolors --print-database}. -+ -+To make @command{dircolors} read a @file{~/.dircolors} file if it -+exists, you can put the following lines in your @file{~/.bashrc} (or -+adapt them to your favorite shell): -+ -+@example -+d=.dircolors -+test -r $d && eval "$(dircolors $d)" -+@end example -+ -+@vindex LS_COLORS -+@vindex SHELL @r{environment variable, and color} -+The output is a shell command to set the @env{LS_COLORS} environment -+variable. You can specify the shell syntax to use on the command line, -+or @command{dircolors} will guess it from the value of the @env{SHELL} -+environment variable. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+@item -b -+@itemx --sh -+@itemx --bourne-shell -+@opindex -b -+@opindex --sh -+@opindex --bourne-shell -+@cindex Bourne shell syntax for color setup -+@cindex @command{sh} syntax for color setup -+Output Bourne shell commands. This is the default if the @env{SHELL} -+environment variable is set and does not end with @samp{csh} or -+@samp{tcsh}. -+ -+@item -c -+@itemx --csh -+@itemx --c-shell -+@opindex -c -+@opindex --csh -+@opindex --c-shell -+@cindex C shell syntax for color setup -+@cindex @command{csh} syntax for color setup -+Output C shell commands. This is the default if @code{SHELL} ends with -+@command{csh} or @command{tcsh}. -+ -+@item -p -+@itemx --print-database -+@opindex -p -+@opindex --print-database -+@cindex color database, printing -+@cindex database for color setup, printing -+@cindex printing color database -+Print the (compiled-in) default color configuration database. This -+output is itself a valid configuration file, and is fairly descriptive -+of the possibilities. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node Basic operations -+@chapter Basic operations -+ -+@cindex manipulating files -+ -+This chapter describes the commands for basic file manipulation: -+copying, moving (renaming), and deleting (removing). -+ -+@menu -+* cp invocation:: Copy files. -+* dd invocation:: Convert and copy a file. -+* install invocation:: Copy files and set attributes. -+* mv invocation:: Move (rename) files. -+* rm invocation:: Remove files or directories. -+* shred invocation:: Remove files more securely. -+@end menu -+ -+ -+@node cp invocation -+@section @command{cp}: Copy files and directories -+ -+@pindex cp -+@cindex copying files and directories -+@cindex files, copying -+@cindex directories, copying -+ -+@command{cp} copies files (or, optionally, directories). The copy is -+completely independent of the original. You can either copy one file to -+another, or copy arbitrarily many files to a destination directory. -+Synopses: -+ -+@example -+cp [@var{option}]@dots{} [-T] @var{source} @var{dest} -+cp [@var{option}]@dots{} @var{source}@dots{} @var{directory} -+cp [@var{option}]@dots{} -t @var{directory} @var{source}@dots{} -+@end example -+ -+@itemize @bullet -+@item -+If two file names are given, @command{cp} copies the first file to the -+second. -+ -+@item -+If the @option{--target-directory} (@option{-t}) option is given, or -+failing that if the last file is a directory and the -+@option{--no-target-directory} (@option{-T}) option is not given, -+@command{cp} copies each @var{source} file to the specified directory, -+using the @var{source}s' names. -+@end itemize -+ -+Generally, files are written just as they are read. For exceptions, -+see the @option{--sparse} option below. -+ -+By default, @command{cp} does not copy directories. However, the -+@option{-R}, @option{-a}, and @option{-r} options cause @command{cp} to -+copy recursively by descending into source directories and copying files -+to corresponding destination directories. -+ -+When copying from a symbolic link, @command{cp} normally follows the -+link only when not copying -+recursively. This default can be overridden with the -+@option{--archive} (@option{-a}), @option{-d}, @option{--dereference} -+(@option{-L}), @option{--no-dereference} (@option{-P}), and -+@option{-H} options. If more than one of these options is specified, -+the last one silently overrides the others. -+ -+When copying to a symbolic link, @command{cp} follows the -+link only when it refers to an existing regular file. -+However, when copying to a dangling symbolic link, @command{cp} -+refuses by default, and fails with a diagnostic, since the operation -+is inherently dangerous. This behavior is contrary to historical -+practice and to @acronym{POSIX}. -+Set @env{POSIXLY_CORRECT} to make @command{cp} attempt to create -+the target of a dangling destination symlink, in spite of the possible risk. -+Also, when an option like -+@option{--backup} or @option{--link} acts to rename or remove the -+destination before copying, @command{cp} renames or removes the -+symbolic link rather than the file it points to. -+ -+By default, @command{cp} copies the contents of special files only -+when not copying recursively. This default can be overridden with the -+@option{--copy-contents} option. -+ -+@cindex self-backups -+@cindex backups, making only -+@command{cp} generally refuses to copy a file onto itself, with the -+following exception: if @option{--force --backup} is specified with -+@var{source} and @var{dest} identical, and referring to a regular file, -+@command{cp} will make a backup file, either regular or numbered, as -+specified in the usual ways (@pxref{Backup options}). This is useful when -+you simply want to make a backup of an existing file before changing it. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+@item -a -+@itemx --archive -+@opindex -a -+@opindex --archive -+Preserve as much as possible of the structure and attributes of the -+original files in the copy (but do not attempt to preserve internal -+directory structure; i.e., @samp{ls -U} may list the entries in a copied -+directory in a different order). -+Try to preserve SELinux security context and extended attributes (xattr), -+but ignore any failure to do that and print no corresponding diagnostic. -+Equivalent to @option{-dR --preserve=all} with the reduced diagnostics. -+ -+@item -b -+@itemx @w{@kbd{--backup}[=@var{method}]} -+@opindex -b -+@opindex --backup -+@vindex VERSION_CONTROL -+@cindex backups, making -+@xref{Backup options}. -+Make a backup of each file that would otherwise be overwritten or removed. -+As a special case, @command{cp} makes a backup of @var{source} when the force -+and backup options are given and @var{source} and @var{dest} are the same -+name for an existing, regular file. One useful application of this -+combination of options is this tiny Bourne shell script: -+ -+@example -+#!/bin/sh -+# Usage: backup FILE... -+# Create a @sc{gnu}-style backup of each listed FILE. -+for i; do -+ cp --backup --force -- "$i" "$i" -+done -+@end example -+ -+@item --copy-contents -+@cindex directories, copying recursively -+@cindex copying directories recursively -+@cindex recursively copying directories -+@cindex non-directories, copying as special files -+If copying recursively, copy the contents of any special files (e.g., -+FIFOs and device files) as if they were regular files. This means -+trying to read the data in each source file and writing it to the -+destination. It is usually a mistake to use this option, as it -+normally has undesirable effects on special files like FIFOs and the -+ones typically found in the @file{/dev} directory. In most cases, -+@code{cp -R --copy-contents} will hang indefinitely trying to read -+from FIFOs and special files like @file{/dev/console}, and it will -+fill up your destination disk if you use it to copy @file{/dev/zero}. -+This option has no effect unless copying recursively, and it does not -+affect the copying of symbolic links. -+ -+@item -d -+@opindex -d -+@cindex symbolic links, copying -+@cindex hard links, preserving -+Copy symbolic links as symbolic links rather than copying the files that -+they point to, and preserve hard links between source files in the copies. -+Equivalent to @option{--no-dereference --preserve=links}. -+ -+@item -f -+@itemx --force -+@opindex -f -+@opindex --force -+When copying without this option and an existing destination file cannot -+be opened for writing, the copy fails. However, with @option{--force}), -+when a destination file cannot be opened, @command{cp} then removes it and -+tries to open it again. Contrast this behavior with that enabled by -+@option{--link} and @option{--symbolic-link}, whereby the destination file -+is never opened but rather is removed unconditionally. Also see the -+description of @option{--remove-destination}. -+ -+This option is independent of the @option{--interactive} or -+@option{-i} option: neither cancels the effect of the other. -+ -+This option is redundant if the @option{--no-clobber} or @option{-n} option is -+used. -+ -+@item -H -+@opindex -H -+If a command line argument specifies a symbolic link, then copy the -+file it points to rather than the symbolic link itself. However, -+copy (preserving its nature) any symbolic link that is encountered -+via recursive traversal. -+ -+@item -i -+@itemx --interactive -+@opindex -i -+@opindex --interactive -+When copying a file other than a directory, prompt whether to -+overwrite an existing destination file. The @option{-i} option overrides -+a previous @option{-n} option. -+ -+@item -l -+@itemx --link -+@opindex -l -+@opindex --link -+Make hard links instead of copies of non-directories. -+ -+@item -L -+@itemx --dereference -+@opindex -L -+@opindex --dereference -+Follow symbolic links when copying from them. -+With this option, @command{cp} cannot create a symbolic link. -+For example, a symlink (to regular file) in the source tree will be copied to -+a regular file in the destination tree. -+ -+@item -n -+@itemx --no-clobber -+@opindex -n -+@opindex --no-clobber -+Do not overwrite an existing file. The @option{-n} option overrides a previous -+@option{-i} option. This option is mutually exclusive with @option{-b} or -+@option{--backup} option. -+ -+@item -P -+@itemx --no-dereference -+@opindex -P -+@opindex --no-dereference -+@cindex symbolic links, copying -+Copy symbolic links as symbolic links rather than copying the files that -+they point to. This option affects only symbolic links in the source; -+symbolic links in the destination are always followed if possible. -+ -+@item -p -+@itemx @w{@kbd{--preserve}[=@var{attribute_list}]} -+@opindex -p -+@opindex --preserve -+@cindex file information, preserving, extended attributes, xattr -+Preserve the specified attributes of the original files. -+If specified, the @var{attribute_list} must be a comma-separated list -+of one or more of the following strings: -+ -+@table @samp -+@itemx mode -+Preserve the file mode bits and access control lists. -+@itemx ownership -+Preserve the owner and group. On most modern systems, -+only users with appropriate privileges may change the owner of a file, -+and ordinary users -+may preserve the group ownership of a file only if they happen to be -+a member of the desired group. -+@itemx timestamps -+Preserve the times of last access and last modification, when possible. -+On older systems, it is not possible to preserve these attributes -+when the affected file is a symbolic link. -+However, many systems now provide the @code{utimensat} function, -+which makes it possible even for symbolic links. -+@itemx links -+Preserve in the destination files -+any links between corresponding source files. -+Note that with @option{-L} or @option{-H}, this option can convert -+symbolic links to hard links. For example, -+@example -+$ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c -+74161745 a -+74161745 b -+@end example -+@noindent -+Note the inputs: @file{b} is a symlink to regular file @file{a}, -+yet the files in destination directory, @file{c/}, are hard-linked. -+Since @option{-a} implies @option{--preserve=links}, and since @option{-H} -+tells @command{cp} to dereference command line arguments, it sees two files -+with the same inode number, and preserves the perceived hard link. -+ -+Here is a similar example that exercises @command{cp}'s @option{-L} option: -+@smallexample -+$ mkdir b c; (cd b; : > a; ln -s a b); cp -aL b c; ls -i1 c/b -+74163295 a -+74163295 b -+@end smallexample -+ -+@itemx context -+Preserve SELinux security context of the file. @command{cp} will fail -+if the preserving of SELinux security context is not succesful. -+@itemx xattr -+Preserve extended attributes if @command{cp} is built with xattr support, -+and xattrs are supported and enabled on your file system. -+If SELinux context and/or ACLs are implemented using xattrs, -+they are preserved by this option as well. -+@itemx all -+Preserve all file attributes. -+Equivalent to specifying all of the above, but with the difference -+that failure to preserve SELinux security context or extended attributes -+does not change @command{cp}'s exit status. -+@command{cp} does diagnose such failures. -+@end table -+ -+Using @option{--preserve} with no @var{attribute_list} is equivalent -+to @option{--preserve=mode,ownership,timestamps}. -+ -+In the absence of this option, each destination file is created with the -+mode bits of the corresponding source file, minus the bits set in the -+umask and minus the set-user-ID and set-group-ID bits. -+@xref{File permissions}. -+ -+@itemx @w{@kbd{--no-preserve}=@var{attribute_list}} -+@cindex file information, preserving -+Do not preserve the specified attributes. The @var{attribute_list} -+has the same form as for @option{--preserve}. -+ -+@itemx --parents -+@opindex --parents -+@cindex parent directories and @command{cp} -+Form the name of each destination file by appending to the target -+directory a slash and the specified name of the source file. The last -+argument given to @command{cp} must be the name of an existing directory. -+For example, the command: -+ -+@example -+cp --parents a/b/c existing_dir -+@end example -+ -+@noindent -+copies the file @file{a/b/c} to @file{existing_dir/a/b/c}, creating -+any missing intermediate directories. -+ -+@item -R -+@itemx -r -+@itemx --recursive -+@opindex -R -+@opindex -r -+@opindex --recursive -+@cindex directories, copying recursively -+@cindex copying directories recursively -+@cindex recursively copying directories -+@cindex non-directories, copying as special files -+Copy directories recursively. By default, do not follow symbolic -+links in the source; see the @option{--archive} (@option{-a}), @option{-d}, -+@option{--dereference} (@option{-L}), @option{--no-dereference} -+(@option{-P}), and @option{-H} options. Special files are copied by -+creating a destination file of the same type as the source; see the -+@option{--copy-contents} option. It is not portable to use -+@option{-r} to copy symbolic links or special files. On some -+non-@sc{gnu} systems, @option{-r} implies the equivalent of -+@option{-L} and @option{--copy-contents} for historical reasons. -+Also, it is not portable to use @option{-R} to copy symbolic links -+unless you also specify @option{-P}, as @acronym{POSIX} allows -+implementations that dereference symbolic links by default. -+ -+@item --reflink[=@var{when}] -+@opindex --reflink[=@var{when}] -+@cindex COW -+@cindex clone -+@cindex copy on write -+Perform a lightweight, copy-on-write (COW) copy. -+Copying with this option can succeed only on some file systems. -+Once it has succeeded, beware that the source and destination files -+share the same disk data blocks as long as they remain unmodified. -+Thus, if a disk I/O error affects data blocks of one of the files, -+the other suffers the exact same fate. -+ -+The @var{when} value can be one of the following: -+ -+@table @samp -+@item always -+The default behavior: if the copy-on-write operation is not supported -+then report the failure for each file and exit with a failure status. -+ -+@item auto -+If the copy-on-write operation is not supported then fall back -+to the standard copy behaviour. -+@end table -+ -+ -+@item --remove-destination -+@opindex --remove-destination -+Remove each existing destination file before attempting to open it -+(contrast with @option{-f} above). -+ -+@item --sparse=@var{when} -+@opindex --sparse=@var{when} -+@cindex sparse files, copying -+@cindex holes, copying files with -+@findex read @r{system call, and holes} -+A @dfn{sparse file} contains @dfn{holes}---a sequence of zero bytes that -+does not occupy any physical disk blocks; the @samp{read} system call -+reads these as zeros. This can both save considerable disk space and -+increase speed, since many binary files contain lots of consecutive zero -+bytes. By default, @command{cp} detects holes in input source files via a crude -+heuristic and makes the corresponding output file sparse as well. -+Only regular files may be sparse. -+ -+The @var{when} value can be one of the following: -+ -+@table @samp -+@item auto -+The default behavior: if the input file is sparse, attempt to make -+the output file sparse, too. However, if an output file exists but -+refers to a non-regular file, then do not attempt to make it sparse. -+ -+@item always -+For each sufficiently long sequence of zero bytes in the input file, -+attempt to create a corresponding hole in the output file, even if the -+input file does not appear to be sparse. -+This is useful when the input file resides on a file system -+that does not support sparse files -+(for example, @samp{efs} file systems in SGI IRIX 5.3 and earlier), -+but the output file is on a type of file system that does support them. -+Holes may be created only in regular files, so if the destination file -+is of some other type, @command{cp} does not even try to make it sparse. -+ -+@item never -+Never make the output file sparse. -+This is useful in creating a file for use with the @command{mkswap} command, -+since such a file must not have any holes. -+@end table -+ -+@optStripTrailingSlashes -+ -+@item -s -+@itemx --symbolic-link -+@opindex -s -+@opindex --symbolic-link -+@cindex symbolic links, copying with -+Make symbolic links instead of copies of non-directories. All source -+file names must be absolute (starting with @samp{/}) unless the -+destination files are in the current directory. This option merely -+results in an error message on systems that do not support symbolic links. -+ -+@optBackupSuffix -+ -+@optTargetDirectory -+ -+@optNoTargetDirectory -+ -+@item -u -+@itemx --update -+@opindex -u -+@opindex --update -+@cindex newer files, copying only -+Do not copy a non-directory that has an existing destination with the -+same or newer modification time. If time stamps are being preserved, -+the comparison is to the source time stamp truncated to the -+resolutions of the destination file system and of the system calls -+used to update time stamps; this avoids duplicate work if several -+@samp{cp -pu} commands are executed with the same source and -+destination. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Print the name of each file before copying it. -+ -+@item -x -+@itemx --one-file-system -+@opindex -x -+@opindex --one-file-system -+@cindex file systems, omitting copying to different -+Skip subdirectories that are on different file systems from the one that -+the copy started on. -+However, mount point directories @emph{are} copied. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node dd invocation -+@section @command{dd}: Convert and copy a file -+ -+@pindex dd -+@cindex converting while copying a file -+ -+@command{dd} copies a file (from standard input to standard output, by -+default) with a changeable I/O block size, while optionally performing -+conversions on it. Synopses: -+ -+@example -+dd [@var{operand}]@dots{} -+dd @var{option} -+@end example -+ -+The only options are @option{--help} and @option{--version}. -+@xref{Common options}. @command{dd} accepts the following operands. -+ -+@table @samp -+ -+@item if=@var{file} -+@opindex if -+Read from @var{file} instead of standard input. -+ -+@item of=@var{file} -+@opindex of -+Write to @var{file} instead of standard output. Unless -+@samp{conv=notrunc} is given, @command{dd} truncates @var{file} to zero -+bytes (or the size specified with @samp{seek=}). -+ -+@item ibs=@var{bytes} -+@opindex ibs -+@cindex block size of input -+@cindex input block size -+Set the input block size to @var{bytes}. -+This makes @command{dd} read @var{bytes} per block. -+The default is 512 bytes. -+ -+@item obs=@var{bytes} -+@opindex obs -+@cindex block size of output -+@cindex output block size -+Set the output block size to @var{bytes}. -+This makes @command{dd} write @var{bytes} per block. -+The default is 512 bytes. -+ -+@item bs=@var{bytes} -+@opindex bs -+@cindex block size -+Set both input and output block sizes to @var{bytes}. -+This makes @command{dd} read and write @var{bytes} per block, -+overriding any @samp{ibs} and @samp{obs} settings. -+In addition, if no data-transforming @option{conv} option is specified, -+each input block is copied to the output as a single block, -+without aggregating short reads. -+ -+@item cbs=@var{bytes} -+@opindex cbs -+@cindex block size of conversion -+@cindex conversion block size -+@cindex fixed-length records, converting to variable-length -+@cindex variable-length records, converting to fixed-length -+Set the conversion block size to @var{bytes}. -+When converting variable-length records to fixed-length ones -+(@option{conv=block}) or the reverse (@option{conv=unblock}), -+use @var{bytes} as the fixed record length. -+ -+@item skip=@var{blocks} -+@opindex skip -+Skip @var{blocks} @samp{ibs}-byte blocks in the input file before copying. -+ -+@item seek=@var{blocks} -+@opindex seek -+Skip @var{blocks} @samp{obs}-byte blocks in the output file before copying. -+ -+@item count=@var{blocks} -+@opindex count -+Copy @var{blocks} @samp{ibs}-byte blocks from the input file, instead -+of everything until the end of the file. -+ -+@item status=noxfer -+@opindex status -+Do not print the overall transfer rate and volume statistics -+that normally make up the third status line when @command{dd} exits. -+ -+@item conv=@var{conversion}[,@var{conversion}]@dots{} -+@opindex conv -+Convert the file as specified by the @var{conversion} argument(s). -+(No spaces around any comma(s).) -+ -+Conversions: -+ -+@table @samp -+ -+@item ascii -+@opindex ascii@r{, converting to} -+Convert @acronym{EBCDIC} to @acronym{ASCII}, -+using the conversion table specified by @acronym{POSIX}. -+This provides a 1:1 translation for all 256 bytes. -+ -+@item ebcdic -+@opindex ebcdic@r{, converting to} -+Convert @acronym{ASCII} to @acronym{EBCDIC}. -+This is the inverse of the @samp{ascii} conversion. -+ -+@item ibm -+@opindex alternate ebcdic@r{, converting to} -+Convert @acronym{ASCII} to alternate @acronym{EBCDIC}, -+using the alternate conversion table specified by @acronym{POSIX}. -+This is not a 1:1 translation, but reflects common historical practice -+for @samp{~}, @samp{[}, and @samp{]}. -+ -+The @samp{ascii}, @samp{ebcdic}, and @samp{ibm} conversions are -+mutually exclusive. -+ -+@item block -+@opindex block @r{(space-padding)} -+For each line in the input, output @samp{cbs} bytes, replacing the -+input newline with a space and padding with spaces as necessary. -+ -+@item unblock -+@opindex unblock -+Remove any trailing spaces in each @samp{cbs}-sized input block, -+and append a newline. -+ -+The @samp{block} and @samp{unblock} conversions are mutually exclusive. -+ -+@item lcase -+@opindex lcase@r{, converting to} -+Change uppercase letters to lowercase. -+ -+@item ucase -+@opindex ucase@r{, converting to} -+Change lowercase letters to uppercase. -+ -+The @samp{lcase} and @samp{ucase} conversions are mutually exclusive. -+ -+@item swab -+@opindex swab @r{(byte-swapping)} -+@cindex byte-swapping -+Swap every pair of input bytes. @sc{gnu} @command{dd}, unlike others, works -+when an odd number of bytes are read---the last byte is simply copied -+(since there is nothing to swap it with). -+ -+@item noerror -+@opindex noerror -+@cindex read errors, ignoring -+Continue after read errors. -+ -+@item nocreat -+@opindex nocreat -+@cindex creating output file, avoiding -+Do not create the output file; the output file must already exist. -+ -+@item excl -+@opindex excl -+@cindex creating output file, requiring -+Fail if the output file already exists; @command{dd} must create the -+output file itself. -+ -+The @samp{excl} and @samp{nocreat} conversions are mutually exclusive. -+ -+@item notrunc -+@opindex notrunc -+@cindex truncating output file, avoiding -+Do not truncate the output file. -+ -+@item sync -+@opindex sync @r{(padding with @acronym{ASCII} @sc{nul}s)} -+Pad every input block to size of @samp{ibs} with trailing zero bytes. -+When used with @samp{block} or @samp{unblock}, pad with spaces instead of -+zero bytes. -+ -+@item fdatasync -+@opindex fdatasync -+@cindex synchronized data writes, before finishing -+Synchronize output data just before finishing. This forces a physical -+write of output data. -+ -+@item fsync -+@opindex fsync -+@cindex synchronized data and metadata writes, before finishing -+Synchronize output data and metadata just before finishing. This -+forces a physical write of output data and metadata. -+ -+@end table -+ -+@item iflag=@var{flag}[,@var{flag}]@dots{} -+@opindex iflag -+Access the input file using the flags specified by the @var{flag} -+argument(s). (No spaces around any comma(s).) -+ -+@item oflag=@var{flag}[,@var{flag}]@dots{} -+@opindex oflag -+Access the output file using the flags specified by the @var{flag} -+argument(s). (No spaces around any comma(s).) -+ -+Here are the flags. Not every flag is supported on every operating -+system. -+ -+@table @samp -+ -+@item append -+@opindex append -+@cindex appending to the output file -+Write in append mode, so that even if some other process is writing to -+this file, every @command{dd} write will append to the current -+contents of the file. This flag makes sense only for output. -+If you combine this flag with the @samp{of=@var{file}} operand, -+you should also specify @samp{conv=notrunc} unless you want the -+output file to be truncated before being appended to. -+ -+@item cio -+@opindex cio -+@cindex concurrent I/O -+Use concurrent I/O mode for data. This mode performs direct I/O -+and drops the @acronym{POSIX} requirement to serialize all I/O to the same file. -+A file cannot be opened in CIO mode and with a standard open at the -+same time. -+ -+@item direct -+@opindex direct -+@cindex direct I/O -+Use direct I/O for data, avoiding the buffer cache. -+Note that the kernel may impose restrictions on read or write buffer sizes. -+For example, with an ext4 destination file system and a linux-based kernel, -+using @samp{oflag=direct} will cause writes to fail with @code{EINVAL} if the -+output buffer size is not a multiple of 512. -+ -+@item directory -+@opindex directory -+@cindex directory I/O -+ -+Fail unless the file is a directory. Most operating systems do not -+allow I/O to a directory, so this flag has limited utility. -+ -+@item dsync -+@opindex dsync -+@cindex synchronized data reads -+Use synchronized I/O for data. For the output file, this forces a -+physical write of output data on each write. For the input file, -+this flag can matter when reading from a remote file that has been -+written to synchronously by some other process. Metadata (e.g., -+last-access and last-modified time) is not necessarily synchronized. -+ -+@item sync -+@opindex sync -+@cindex synchronized data and metadata I/O -+Use synchronized I/O for both data and metadata. -+ -+@item nonblock -+@opindex nonblock -+@cindex nonblocking I/O -+Use non-blocking I/O. -+ -+@item noatime -+@opindex noatime -+@cindex access time -+Do not update the file's access time. -+Some older file systems silently ignore this flag, so it is a good -+idea to test it on your files before relying on it. -+ -+@item noctty -+@opindex noctty -+@cindex controlling terminal -+Do not assign the file to be a controlling terminal for @command{dd}. -+This has no effect when the file is not a terminal. -+On many hosts (e.g., @acronym{GNU}/Linux hosts), this option has no effect -+at all. -+ -+@item nofollow -+@opindex nofollow -+@cindex symbolic links, following -+Do not follow symbolic links. -+ -+@item nolinks -+@opindex nolinks -+@cindex hard links -+Fail if the file has multiple hard links. -+ -+@item binary -+@opindex binary -+@cindex binary I/O -+Use binary I/O. This option has an effect only on nonstandard -+platforms that distinguish binary from text I/O. -+ -+@item text -+@opindex text -+@cindex text I/O -+Use text I/O. Like @samp{binary}, this option has no effect on -+standard platforms. -+ -+@item fullblock -+@opindex fullblock -+Accumulate full blocks from input. The @code{read} system call -+may return early if a full block is not available. -+When that happens, continue calling @code{read} to fill the remainder -+of the block. -+This flag can be used only with @code{iflag}. -+ -+@end table -+ -+These flags are not supported on all systems, and @samp{dd} rejects -+attempts to use them when they are not supported. When reading from -+standard input or writing to standard output, the @samp{nofollow} and -+@samp{noctty} flags should not be specified, and the other flags -+(e.g., @samp{nonblock}) can affect how other processes behave with the -+affected file descriptors, even after @command{dd} exits. -+ -+@end table -+ -+@cindex multipliers after numbers -+The numeric-valued strings above (@var{bytes} and @var{blocks}) can be -+followed by a multiplier: @samp{b}=512, @samp{c}=1, -+@samp{w}=2, @samp{x@var{m}}=@var{m}, or any of the -+standard block size suffixes like @samp{k}=1024 (@pxref{Block size}). -+ -+Use different @command{dd} invocations to use different block sizes for -+skipping and I/O@. For example, the following shell commands copy data -+in 512 KiB blocks between a disk and a tape, but do not save or restore a -+4 KiB label at the start of the disk: -+ -+@example -+disk=/dev/rdsk/c0t1d0s2 -+tape=/dev/rmt/0 -+ -+# Copy all but the label from disk to tape. -+(dd bs=4k skip=1 count=0 && dd bs=512k) <$disk >$tape -+ -+# Copy from tape back to disk, but leave the disk label alone. -+(dd bs=4k seek=1 count=0 && dd bs=512k) <$tape >$disk -+@end example -+ -+Sending an @samp{INFO} signal to a running @command{dd} -+process makes it print I/O statistics to standard error -+and then resume copying. In the example below, -+@command{dd} is run in the background to copy 10 million blocks. -+The @command{kill} command makes it output intermediate I/O statistics, -+and when @command{dd} completes normally or is killed by the -+@code{SIGINT} signal, it outputs the final statistics. -+ -+@example -+$ dd if=/dev/zero of=/dev/null count=10MB & pid=$! -+$ kill -s INFO $pid; wait $pid -+3385223+0 records in -+3385223+0 records out -+1733234176 bytes (1.7 GB) copied, 6.42173 seconds, 270 MB/s -+10000000+0 records in -+10000000+0 records out -+5120000000 bytes (5.1 GB) copied, 18.913 seconds, 271 MB/s -+@end example -+ -+@vindex POSIXLY_CORRECT -+On systems lacking the @samp{INFO} signal @command{dd} responds to the -+@samp{USR1} signal instead, unless the @env{POSIXLY_CORRECT} -+environment variable is set. -+ -+@exitstatus -+ -+ -+@node install invocation -+@section @command{install}: Copy files and set attributes -+ -+@pindex install -+@cindex copying files and setting attributes -+ -+@command{install} copies files while setting their file mode bits and, if -+possible, their owner and group. Synopses: -+ -+@example -+install [@var{option}]@dots{} [-T] @var{source} @var{dest} -+install [@var{option}]@dots{} @var{source}@dots{} @var{directory} -+install [@var{option}]@dots{} -t @var{directory} @var{source}@dots{} -+install [@var{option}]@dots{} -d @var{directory}@dots{} -+@end example -+ -+@itemize @bullet -+@item -+If two file names are given, @command{install} copies the first file to the -+second. -+ -+@item -+If the @option{--target-directory} (@option{-t}) option is given, or -+failing that if the last file is a directory and the -+@option{--no-target-directory} (@option{-T}) option is not given, -+@command{install} copies each @var{source} file to the specified -+directory, using the @var{source}s' names. -+ -+@item -+If the @option{--directory} (@option{-d}) option is given, -+@command{install} creates each @var{directory} and any missing parent -+directories. Parent directories are created with mode -+@samp{u=rwx,go=rx} (755), regardless of the @option{-m} option or the -+current umask. @xref{Directory Setuid and Setgid}, for how the -+set-user-ID and set-group-ID bits of parent directories are inherited. -+@end itemize -+ -+@cindex Makefiles, installing programs in -+@command{install} is similar to @command{cp}, but allows you to control the -+attributes of destination files. It is typically used in Makefiles to -+copy programs into their destination directories. It refuses to copy -+files onto themselves. -+ -+@cindex extended attributes, xattr -+@command{install} never preserves extended attributes (xattr). -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@optBackup -+ -+@item -C -+@itemx --compare -+@opindex -C -+@opindex --compare -+Compare each pair of source and destination files, and if the destination has -+identical content and any specified owner, group, permissions, and possibly -+SELinux context, then do not modify the destination at all. -+ -+@item -c -+@opindex -c -+Ignored; for compatibility with old Unix versions of @command{install}. -+ -+@item -D -+@opindex -D -+Create any missing parent directories of @var{dest}, -+then copy @var{source} to @var{dest}. -+This option is ignored if a destination directory is specified -+via @option{--target-directory=DIR}. -+ -+@item -d -+@itemx --directory -+@opindex -d -+@opindex --directory -+@cindex directories, creating with given attributes -+@cindex parent directories, creating missing -+@cindex leading directories, creating missing -+Create any missing parent directories, giving them the default -+attributes. Then create each given directory, setting their owner, -+group and mode as given on the command line or to the defaults. -+ -+@item -g @var{group} -+@itemx --group=@var{group} -+@opindex -g -+@opindex --group -+@cindex group ownership of installed files, setting -+Set the group ownership of installed files or directories to -+@var{group}. The default is the process's current group. @var{group} -+may be either a group name or a numeric group ID. -+ -+@item -m @var{mode} -+@itemx --mode=@var{mode} -+@opindex -m -+@opindex --mode -+@cindex permissions of installed files, setting -+Set the file mode bits for the installed file or directory to @var{mode}, -+which can be either an octal number, or a symbolic mode as in -+@command{chmod}, with @samp{a=} (no access allowed to anyone) as the -+point of departure (@pxref{File permissions}). -+The default mode is @samp{u=rwx,go=rx,a-s}---read, write, and -+execute for the owner, read and execute for group and other, and with -+set-user-ID and set-group-ID disabled. -+This default is not quite the same as @samp{755}, since it disables -+instead of preserving set-user-ID and set-group-ID on directories. -+@xref{Directory Setuid and Setgid}. -+ -+@item -o @var{owner} -+@itemx --owner=@var{owner} -+@opindex -o -+@opindex --owner -+@cindex ownership of installed files, setting -+@cindex appropriate privileges -+@vindex root @r{as default owner} -+If @command{install} has appropriate privileges (is run as root), set the -+ownership of installed files or directories to @var{owner}. The default -+is @code{root}. @var{owner} may be either a user name or a numeric user -+ID. -+ -+@item --preserve-context -+@opindex --preserve-context -+@cindex SELinux -+@cindex security context -+Preserve the SELinux security context of files and directories. -+Failure to preserve the context in all of the files or directories -+will result in an exit status of 1. If SELinux is disabled then -+print a warning and ignore the option. -+ -+@item -p -+@itemx --preserve-timestamps -+@opindex -p -+@opindex --preserve-timestamps -+@cindex timestamps of installed files, preserving -+Set the time of last access and the time of last modification of each -+installed file to match those of each corresponding original file. -+When a file is installed without this option, its last access and -+last modification times are both set to the time of installation. -+This option is useful if you want to use the last modification times -+of installed files to keep track of when they were last built as opposed -+to when they were last installed. -+ -+@item -s -+@itemx --strip -+@opindex -s -+@opindex --strip -+@cindex symbol table information, stripping -+@cindex stripping symbol table information -+Strip the symbol tables from installed binary executables. -+ -+@itemx --strip-program=@var{program} -+@opindex --strip-program -+@cindex symbol table information, stripping, program -+Program used to strip binaries. -+ -+@optBackupSuffix -+ -+@optTargetDirectory -+ -+@optNoTargetDirectory -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Print the name of each file before copying it. -+ -+@item -Z @var{context} -+@itemx --context=@var{context} -+@opindex -Z -+@opindex --context -+@cindex SELinux -+@cindex security context -+Set the default SELinux security context to be used for any -+created files and directories. If SELinux is disabled then -+print a warning and ignore the option. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node mv invocation -+@section @command{mv}: Move (rename) files -+ -+@pindex mv -+ -+@command{mv} moves or renames files (or directories). Synopses: -+ -+@example -+mv [@var{option}]@dots{} [-T] @var{source} @var{dest} -+mv [@var{option}]@dots{} @var{source}@dots{} @var{directory} -+mv [@var{option}]@dots{} -t @var{directory} @var{source}@dots{} -+@end example -+ -+@itemize @bullet -+@item -+If two file names are given, @command{mv} moves the first file to the -+second. -+ -+@item -+If the @option{--target-directory} (@option{-t}) option is given, or -+failing that if the last file is a directory and the -+@option{--no-target-directory} (@option{-T}) option is not given, -+@command{mv} moves each @var{source} file to the specified -+directory, using the @var{source}s' names. -+@end itemize -+ -+@command{mv} can move any type of file from one file system to another. -+Prior to version @code{4.0} of the fileutils, -+@command{mv} could move only regular files between file systems. -+For example, now @command{mv} can move an entire directory hierarchy -+including special device files from one partition to another. It first -+uses some of the same code that's used by @code{cp -a} to copy the -+requested directories and files, then (assuming the copy succeeded) -+it removes the originals. If the copy fails, then the part that was -+copied to the destination partition is removed. If you were to copy -+three directories from one partition to another and the copy of the first -+directory succeeded, but the second didn't, the first would be left on -+the destination partition and the second and third would be left on the -+original partition. -+ -+@cindex extended attributes, xattr -+@command{mv} always tries to copy extended attributes (xattr). -+ -+@cindex prompting, and @command{mv} -+If a destination file exists but is normally unwritable, standard input -+is a terminal, and the @option{-f} or @option{--force} option is not given, -+@command{mv} prompts the user for whether to replace the file. (You might -+own the file, or have write permission on its directory.) If the -+response is not affirmative, the file is skipped. -+ -+@emph{Warning}: Avoid specifying a source name with a trailing slash, -+when it might be a symlink to a directory. -+Otherwise, @command{mv} may do something very surprising, since -+its behavior depends on the underlying rename system call. -+On a system with a modern Linux-based kernel, it fails with @code{errno=ENOTDIR}. -+However, on other systems (at least FreeBSD 6.1 and Solaris 10) it silently -+renames not the symlink but rather the directory referenced by the symlink. -+@xref{Trailing slashes}. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@optBackup -+ -+@item -f -+@itemx --force -+@opindex -f -+@opindex --force -+@cindex prompts, omitting -+Do not prompt the user before removing a destination file. -+@macro mvOptsIfn -+If you specify more than one of the @option{-i}, @option{-f}, @option{-n} -+options, only the final one takes effect. -+@end macro -+@mvOptsIfn -+ -+@item -i -+@itemx --interactive -+@opindex -i -+@opindex --interactive -+@cindex prompts, forcing -+Prompt whether to overwrite each existing destination file, regardless -+of its permissions. -+If the response is not affirmative, the file is skipped. -+@mvOptsIfn -+ -+@item -n -+@itemx --no-clobber -+@opindex -n -+@opindex --no-clobber -+@cindex prompts, omitting -+Do not overwrite an existing file. -+@mvOptsIfn -+This option is mutually exclusive with @option{-b} or @option{--backup} option. -+ -+@item -u -+@itemx --update -+@opindex -u -+@opindex --update -+@cindex newer files, moving only -+Do not move a non-directory that has an existing destination with the -+same or newer modification time. -+If the move is across file system boundaries, the comparison is to the -+source time stamp truncated to the resolutions of the destination file -+system and of the system calls used to update time stamps; this avoids -+duplicate work if several @samp{mv -u} commands are executed with the -+same source and destination. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Print the name of each file before moving it. -+ -+@optStripTrailingSlashes -+ -+@optBackupSuffix -+ -+@optTargetDirectory -+ -+@optNoTargetDirectory -+ -+@end table -+ -+@exitstatus -+ -+ -+@node rm invocation -+@section @command{rm}: Remove files or directories -+ -+@pindex rm -+@cindex removing files or directories -+ -+@command{rm} removes each given @var{file}. By default, it does not remove -+directories. Synopsis: -+ -+@example -+rm [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+@cindex prompting, and @command{rm} -+If the @option{-I} or @option{--interactive=once} option is given, -+and there are more than three files or the @option{-r}, @option{-R}, -+or @option{--recursive} are given, then @command{rm} prompts the user -+for whether to proceed with the entire operation. If the response is -+not affirmative, the entire command is aborted. -+ -+Otherwise, if a file is unwritable, standard input is a terminal, and -+the @option{-f} or @option{--force} option is not given, or the -+@option{-i} or @option{--interactive=always} option @emph{is} given, -+@command{rm} prompts the user for whether to remove the file. -+If the response is not affirmative, the file is skipped. -+ -+Any attempt to remove a file whose last file name component is -+@file{.} or @file{..} is rejected without any prompting. -+ -+@emph{Warning}: If you use @command{rm} to remove a file, it is usually -+possible to recover the contents of that file. If you want more assurance -+that the contents are truly unrecoverable, consider using @command{shred}. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -f -+@itemx --force -+@opindex -f -+@opindex --force -+Ignore nonexistent files and never prompt the user. -+Ignore any previous @option{--interactive} (@option{-i}) option. -+ -+@item -i -+@opindex -i -+Prompt whether to remove each file. -+If the response is not affirmative, the file is skipped. -+Ignore any previous @option{--force} (@option{-f}) option. -+Equivalent to @option{--interactive=always}. -+ -+@item -I -+@opindex -I -+Prompt once whether to proceed with the command, if more than three -+files are named or if a recursive removal is requested. Ignore any -+previous @option{--force} (@option{-f}) option. Equivalent to -+@option{--interactive=once}. -+ -+@itemx --interactive [=@var{when}] -+@opindex --interactive -+Specify when to issue an interactive prompt. @var{when} may be -+omitted, or one of: -+@itemize @bullet -+@item never -+@vindex never @r{interactive option} -+- Do not prompt at all. -+@item once -+@vindex once @r{interactive option} -+- Prompt once if more than three files are named or if a recursive -+removal is requested. Equivalent to @option{-I}. -+@item always -+@vindex always @r{interactive option} -+- Prompt for every file being removed. Equivalent to @option{-i}. -+@end itemize -+@option{--interactive} with no @var{when} is equivalent to -+@option{--interactive=always}. -+ -+@itemx --one-file-system -+@opindex --one-file-system -+@cindex one file system, restricting @command{rm} to -+When removing a hierarchy recursively, skip any directory that is on a -+file system different from that of the corresponding command line argument. -+ -+This option is useful when removing a build ``chroot'' hierarchy, -+which normally contains no valuable data. However, it is not uncommon -+to bind-mount @file{/home} into such a hierarchy, to make it easier to -+use one's start-up file. The catch is that it's easy to forget to -+unmount @file{/home}. Then, when you use @command{rm -rf} to remove -+your normally throw-away chroot, that command will remove everything -+under @file{/home}, too. -+Use the @option{--one-file-system} option, and it will -+warn about and skip directories on other file systems. -+Of course, this will not save your @file{/home} if it and your -+chroot happen to be on the same file system. -+ -+@itemx --preserve-root -+@opindex --preserve-root -+@cindex root directory, disallow recursive destruction -+Fail upon any attempt to remove the root directory, @file{/}, -+when used with the @option{--recursive} option. -+This is the default behavior. -+@xref{Treating / specially}. -+ -+@itemx --no-preserve-root -+@opindex --no-preserve-root -+@cindex root directory, allow recursive destruction -+Do not treat @file{/} specially when removing recursively. -+This option is not recommended unless you really want to -+remove all the files on your computer. -+@xref{Treating / specially}. -+ -+@item -r -+@itemx -R -+@itemx --recursive -+@opindex -r -+@opindex -R -+@opindex --recursive -+@cindex directories, removing (recursively) -+Remove the listed directories and their contents recursively. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Print the name of each file before removing it. -+ -+@end table -+ -+@cindex files beginning with @samp{-}, removing -+@cindex @samp{-}, removing files beginning with -+One common question is how to remove files whose names begin with a -+@samp{-}. @sc{gnu} @command{rm}, like every program that uses the @code{getopt} -+function to parse its arguments, lets you use the @samp{--} option to -+indicate that all following arguments are non-options. To remove a file -+called @file{-f} in the current directory, you could type either: -+ -+@example -+rm -- -f -+@end example -+ -+@noindent -+or: -+ -+@example -+rm ./-f -+@end example -+ -+@opindex - @r{and Unix @command{rm}} -+The Unix @command{rm} program's use of a single @samp{-} for this purpose -+predates the development of the getopt standard syntax. -+ -+@exitstatus -+ -+ -+@node shred invocation -+@section @command{shred}: Remove files more securely -+ -+@pindex shred -+@cindex data, erasing -+@cindex erasing data -+ -+@command{shred} overwrites devices or files, to help prevent even -+very expensive hardware from recovering the data. -+ -+Ordinarily when you remove a file (@pxref{rm invocation}), the data is -+not actually destroyed. Only the index listing where the file is -+stored is destroyed, and the storage is made available for reuse. -+There are undelete utilities that will attempt to reconstruct the index -+and can bring the file back if the parts were not reused. -+ -+On a busy system with a nearly-full drive, space can get reused in a few -+seconds. But there is no way to know for sure. If you have sensitive -+data, you may want to be sure that recovery is not possible by actually -+overwriting the file with non-sensitive data. -+ -+However, even after doing that, it is possible to take the disk back -+to a laboratory and use a lot of sensitive (and expensive) equipment -+to look for the faint ``echoes'' of the original data underneath the -+overwritten data. If the data has only been overwritten once, it's not -+even that hard. -+ -+The best way to remove something irretrievably is to destroy the media -+it's on with acid, melt it down, or the like. For cheap removable media -+like floppy disks, this is the preferred method. However, hard drives -+are expensive and hard to melt, so the @command{shred} utility tries -+to achieve a similar effect non-destructively. -+ -+This uses many overwrite passes, with the data patterns chosen to -+maximize the damage they do to the old data. While this will work on -+floppies, the patterns are designed for best effect on hard drives. -+For more details, see the source code and Peter Gutmann's paper -+@uref{http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html, -+@cite{Secure Deletion of Data from Magnetic and Solid-State Memory}}, -+from the proceedings of the Sixth @acronym{USENIX} Security Symposium (San Jose, -+California, July 22--25, 1996). -+ -+@strong{Please note} that @command{shred} relies on a very important assumption: -+that the file system overwrites data in place. This is the traditional -+way to do things, but many modern file system designs do not satisfy this -+assumption. Exceptions include: -+ -+@itemize @bullet -+ -+@item -+Log-structured or journaled file systems, such as those supplied with -+AIX and Solaris, and JFS, ReiserFS, XFS, Ext3 (in @code{data=journal} mode), -+BFS, NTFS, etc.@: when they are configured to journal @emph{data}. -+ -+@item -+File systems that write redundant data and carry on even if some writes -+fail, such as RAID-based file systems. -+ -+@item -+File systems that make snapshots, such as Network Appliance's NFS server. -+ -+@item -+File systems that cache in temporary locations, such as NFS version 3 -+clients. -+ -+@item -+Compressed file systems. -+@end itemize -+ -+In the particular case of ext3 file systems, the above disclaimer applies (and -+@command{shred} is thus of limited effectiveness) only in @code{data=journal} -+mode, which journals file data in addition to just metadata. In both -+the @code{data=ordered} (default) and @code{data=writeback} modes, -+@command{shred} works as usual. Ext3 journaling modes can be changed -+by adding the @code{data=something} option to the mount options for a -+particular file system in the @file{/etc/fstab} file, as documented in -+the mount man page (man mount). -+ -+If you are not sure how your file system operates, then you should assume -+that it does not overwrite data in place, which means that shred cannot -+reliably operate on regular files in your file system. -+ -+Generally speaking, it is more reliable to shred a device than a file, -+since this bypasses the problem of file system design mentioned above. -+However, even shredding devices is not always completely reliable. For -+example, most disks map out bad sectors invisibly to the application; if -+the bad sectors contain sensitive data, @command{shred} won't be able to -+destroy it. -+ -+@command{shred} makes no attempt to detect or report this problem, just as -+it makes no attempt to do anything about backups. However, since it is -+more reliable to shred devices than files, @command{shred} by default does -+not truncate or remove the output file. This default is more suitable -+for devices, which typically cannot be truncated and should not be -+removed. -+ -+Finally, consider the risk of backups and mirrors. -+File system backups and remote mirrors may contain copies of the -+file that cannot be removed, and that will allow a shredded file -+to be recovered later. So if you keep any data you may later want -+to destroy using @command{shred}, be sure that it is not backed up or mirrored. -+ -+@example -+shred [@var{option}]@dots{} @var{file}[@dots{}] -+@end example -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -f -+@itemx --force -+@opindex -f -+@opindex --force -+@cindex force deletion -+Override file permissions if necessary to allow overwriting. -+ -+@item -@var{number} -+@itemx -n @var{number} -+@itemx --iterations=@var{number} -+@opindex -n @var{number} -+@opindex --iterations=@var{number} -+@cindex iterations, selecting the number of -+By default, @command{shred} uses @value{SHRED_DEFAULT_PASSES} passes of -+overwrite. You can reduce this to save time, or increase it if you think it's -+appropriate. After 25 passes all of the internal overwrite patterns will have -+been used at least once. -+ -+@item --random-source=@var{file} -+@opindex --random-source -+@cindex random source for shredding -+Use @var{file} as a source of random data used to overwrite and to -+choose pass ordering. @xref{Random sources}. -+ -+@item -s @var{bytes} -+@itemx --size=@var{bytes} -+@opindex -s @var{bytes} -+@opindex --size=@var{bytes} -+@cindex size of file to shred -+Shred the first @var{bytes} bytes of the file. The default is to shred -+the whole file. @var{bytes} can be followed by a size specification like -+@samp{K}, @samp{M}, or @samp{G} to specify a multiple. @xref{Block size}. -+ -+@item -u -+@itemx --remove -+@opindex -u -+@opindex --remove -+@cindex removing files after shredding -+After shredding a file, truncate it (if possible) and then remove it. -+If a file has multiple links, only the named links will be removed. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Display to standard error all status updates as sterilization proceeds. -+ -+@item -x -+@itemx --exact -+@opindex -x -+@opindex --exact -+By default, @command{shred} rounds the size of a regular file up to the next -+multiple of the file system block size to fully erase the last block of the file. -+Use @option{--exact} to suppress that behavior. -+Thus, by default if you shred a 10-byte regular file on a system with 512-byte -+blocks, the resulting file will be 512 bytes long. With this option, -+shred does not increase the apparent size of the file. -+ -+@item -z -+@itemx --zero -+@opindex -z -+@opindex --zero -+Normally, the last pass that @command{shred} writes is made up of -+random data. If this would be conspicuous on your hard drive (for -+example, because it looks like encrypted data), or you just think -+it's tidier, the @option{--zero} option adds an additional overwrite pass with -+all zero bits. This is in addition to the number of passes specified -+by the @option{--iterations} option. -+ -+@end table -+ -+You might use the following command to erase all trace of the -+file system you'd created on the floppy disk in your first drive. -+That command takes about 20 minutes to erase a ``1.44MB'' (actually -+1440 KiB) floppy. -+ -+@example -+shred --verbose /dev/fd0 -+@end example -+ -+Similarly, to erase all data on a selected partition of -+your hard disk, you could give a command like this: -+ -+@example -+shred --verbose /dev/sda5 -+@end example -+ -+A @var{file} of @samp{-} denotes standard output. -+The intended use of this is to shred a removed temporary file. -+For example: -+ -+@example -+i=`tempfile -m 0600` -+exec 3<>"$i" -+rm -- "$i" -+echo "Hello, world" >&3 -+shred - >&3 -+exec 3>- -+@end example -+ -+However, the command @samp{shred - >file} does not shred the contents -+of @var{file}, since the shell truncates @var{file} before invoking -+@command{shred}. Use the command @samp{shred file} or (if using a -+Bourne-compatible shell) the command @samp{shred - 1<>file} instead. -+ -+@exitstatus -+ -+ -+@node Special file types -+@chapter Special file types -+ -+@cindex special file types -+@cindex file types, special -+ -+This chapter describes commands which create special types of files (and -+@command{rmdir}, which removes directories, one special file type). -+ -+@cindex special file types -+@cindex file types -+Although Unix-like operating systems have markedly fewer special file -+types than others, not @emph{everything} can be treated only as the -+undifferentiated byte stream of @dfn{normal files}. For example, when a -+file is created or removed, the system must record this information, -+which it does in a @dfn{directory}---a special type of file. Although -+you can read directories as normal files, if you're curious, in order -+for the system to do its job it must impose a structure, a certain -+order, on the bytes of the file. Thus it is a ``special'' type of file. -+ -+Besides directories, other special file types include named pipes -+(FIFOs), symbolic links, sockets, and so-called @dfn{special files}. -+ -+@menu -+* link invocation:: Make a hard link via the link syscall -+* ln invocation:: Make links between files. -+* mkdir invocation:: Make directories. -+* mkfifo invocation:: Make FIFOs (named pipes). -+* mknod invocation:: Make block or character special files. -+* readlink invocation:: Print value of a symlink or canonical file name. -+* rmdir invocation:: Remove empty directories. -+* unlink invocation:: Remove files via the unlink syscall -+@end menu -+ -+ -+@node link invocation -+@section @command{link}: Make a hard link via the link syscall -+ -+@pindex link -+@cindex links, creating -+@cindex hard links, creating -+@cindex creating links (hard only) -+ -+@command{link} creates a single hard link at a time. -+It is a minimalist interface to the system-provided -+@code{link} function. @xref{Hard Links, , , libc, -+The GNU C Library Reference Manual}. -+It avoids the bells and whistles of the more commonly-used -+@command{ln} command (@pxref{ln invocation}). -+Synopsis: -+ -+@example -+link @var{filename} @var{linkname} -+@end example -+ -+@var{filename} must specify an existing file, and @var{linkname} -+must specify a nonexistent entry in an existing directory. -+@command{link} simply calls @code{link (@var{filename}, @var{linkname})} -+to create the link. -+ -+On a @acronym{GNU} system, this command acts like @samp{ln --directory -+--no-target-directory @var{filename} @var{linkname}}. However, the -+@option{--directory} and @option{--no-target-directory} options are -+not specified by @acronym{POSIX}, and the @command{link} command is -+more portable in practice. -+ -+If @var{filename} is a symbolic link, it is unspecified whether -+@var{linkname} will be a hard link to the symbolic link or to the -+target of the symbolic link. Use @command{ln -P} or @command{ln -L} -+to specify which behavior is desired. -+ -+@exitstatus -+ -+ -+@node ln invocation -+@section @command{ln}: Make links between files -+ -+@pindex ln -+@cindex links, creating -+@cindex hard links, creating -+@cindex symbolic (soft) links, creating -+@cindex creating links (hard or soft) -+ -+@cindex file systems and hard links -+@command{ln} makes links between files. By default, it makes hard links; -+with the @option{-s} option, it makes symbolic (or @dfn{soft}) links. -+Synopses: -+ -+@example -+ln [@var{option}]@dots{} [-T] @var{target} @var{linkname} -+ln [@var{option}]@dots{} @var{target} -+ln [@var{option}]@dots{} @var{target}@dots{} @var{directory} -+ln [@var{option}]@dots{} -t @var{directory} @var{target}@dots{} -+@end example -+ -+@itemize @bullet -+ -+@item -+If two file names are given, @command{ln} creates a link to the first -+file from the second. -+ -+@item -+If one @var{target} is given, @command{ln} creates a link to that file -+in the current directory. -+ -+@item -+If the @option{--target-directory} (@option{-t}) option is given, or -+failing that if the last file is a directory and the -+@option{--no-target-directory} (@option{-T}) option is not given, -+@command{ln} creates a link to each @var{target} file in the specified -+directory, using the @var{target}s' names. -+ -+@end itemize -+ -+Normally @command{ln} does not remove existing files. Use the -+@option{--force} (@option{-f}) option to remove them unconditionally, -+the @option{--interactive} (@option{-i}) option to remove them -+conditionally, and the @option{--backup} (@option{-b}) option to -+rename them. -+ -+@cindex hard link, defined -+@cindex inode, and hard links -+A @dfn{hard link} is another name for an existing file; the link and the -+original are indistinguishable. Technically speaking, they share the -+same inode, and the inode contains all the information about a -+file---indeed, it is not incorrect to say that the inode @emph{is} the -+file. Most systems prohibit making a hard link to -+a directory; on those where it is allowed, only the super-user can do -+so (and with caution, since creating a cycle will cause problems to many -+other utilities). Hard links cannot cross file system boundaries. (These -+restrictions are not mandated by @acronym{POSIX}, however.) -+ -+@cindex dereferencing symbolic links -+@cindex symbolic link, defined -+@dfn{Symbolic links} (@dfn{symlinks} for short), on the other hand, are -+a special file type (which not all kernels support: System V release 3 -+(and older) systems lack symlinks) in which the link file actually -+refers to a different file, by name. When most operations (opening, -+reading, writing, and so on) are passed the symbolic link file, the -+kernel automatically @dfn{dereferences} the link and operates on the -+target of the link. But some operations (e.g., removing) work on the -+link file itself, rather than on its target. The owner and group of a -+symlink are not significant to file access performed through -+the link, but do have implications on deleting a symbolic link from a -+directory with the restricted deletion bit set. On the GNU system, -+the mode of a symlink has no significance and cannot be changed, but -+on some BSD systems, the mode can be changed and will affect whether -+the symlink will be traversed in file name resolution. @xref{Symbolic Links,,, -+libc, The GNU C Library Reference Manual}. -+ -+Symbolic links can contain arbitrary strings; a @dfn{dangling symlink} -+occurs when the string in the symlink does not resolve to a file. -+There are no restrictions against creating dangling symbolic links. -+There are trade-offs to using absolute or relative symlinks. An -+absolute symlink always points to the same file, even if the directory -+containing the link is moved. However, if the symlink is visible from -+more than one machine (such as on a networked file system), the file -+pointed to might not always be the same. A relative symbolic link is -+resolved in relation to the directory that contains the link, and is -+often useful in referring to files on the same device without regards -+to what name that device is mounted on when accessed via networked -+machines. -+ -+When creating a relative symlink in a different location than the -+current directory, the resolution of the symlink will be different -+than the resolution of the same string from the current directory. -+Therefore, many users prefer to first change directories to the -+location where the relative symlink will be created, so that -+tab-completion or other file resolution will find the same target as -+what will be placed in the symlink. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@optBackup -+ -+@item -d -+@itemx -F -+@itemx --directory -+@opindex -d -+@opindex -F -+@opindex --directory -+@cindex hard links to directories -+Allow users with appropriate privileges to attempt to make hard links -+to directories. -+However, note that this will probably fail due to -+system restrictions, even for the super-user. -+ -+@item -f -+@itemx --force -+@opindex -f -+@opindex --force -+Remove existing destination files. -+ -+@item -i -+@itemx --interactive -+@opindex -i -+@opindex --interactive -+@cindex prompting, and @command{ln} -+Prompt whether to remove existing destination files. -+ -+@item -L -+@itemx --logical -+@opindex -L -+@opindex --logical -+If @option{-s} is not in effect, and the source file is a symbolic -+link, create the hard link to the file referred to by the symbolic -+link, rather than the symbolic link itself. -+ -+@item -n -+@itemx --no-dereference -+@opindex -n -+@opindex --no-dereference -+Do not treat the last operand specially when it is a symbolic link to -+a directory. Instead, treat it as if it were a normal file. -+ -+When the destination is an actual directory (not a symlink to one), -+there is no ambiguity. The link is created in that directory. -+But when the specified destination is a symlink to a directory, -+there are two ways to treat the user's request. @command{ln} can -+treat the destination just as it would a normal directory and create -+the link in it. On the other hand, the destination can be viewed as a -+non-directory---as the symlink itself. In that case, @command{ln} -+must delete or backup that symlink before creating the new link. -+The default is to treat a destination that is a symlink to a directory -+just like a directory. -+ -+This option is weaker than the @option{--no-target-directory} -+(@option{-T}) option, so it has no effect if both options are given. -+ -+@item -P -+@itemx --physical -+@opindex -P -+@opindex --physical -+If @option{-s} is not in effect, and the source file is a symbolic -+link, create the hard link to the symbolic link itself. On platforms -+where this is not supported by the kernel, this option creates a -+symbolic link with identical contents; since symbolic link contents -+cannot be edited, any file name resolution performed through either -+link will be the same as if a hard link had been created. -+ -+@item -s -+@itemx --symbolic -+@opindex -s -+@opindex --symbolic -+Make symbolic links instead of hard links. This option merely produces -+an error message on systems that do not support symbolic links. -+ -+@optBackupSuffix -+ -+@optTargetDirectory -+ -+@optNoTargetDirectory -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Print the name of each file after linking it successfully. -+ -+@end table -+ -+@cindex hard links to symbolic links -+@cindex symbolic links and @command{ln} -+If @option{-L} and @option{-P} are both given, the last one takes -+precedence. If @option{-s} is also given, @option{-L} and @option{-P} -+are silently ignored. If neither option is given, then this -+implementation defaults to @option{-P} if the system @code{link} supports -+hard links to symbolic links (such as the GNU system), and @option{-L} -+if @code{link} follows symbolic links (such as on BSD). -+ -+@exitstatus -+ -+Examples: -+ -+@smallexample -+Bad Example: -+ -+# Create link ../a pointing to a in that directory. -+# Not really useful because it points to itself. -+ln -s a .. -+ -+Better Example: -+ -+# Change to the target before creating symlinks to avoid being confused. -+cd .. -+ln -s adir/a . -+ -+Bad Example: -+ -+# Hard coded file names don't move well. -+ln -s $(pwd)/a /some/dir/ -+ -+Better Example: -+ -+# Relative file names survive directory moves and also -+# work across networked file systems. -+ln -s afile anotherfile -+ln -s ../adir/afile yetanotherfile -+@end smallexample -+ -+ -+@node mkdir invocation -+@section @command{mkdir}: Make directories -+ -+@pindex mkdir -+@cindex directories, creating -+@cindex creating directories -+ -+@command{mkdir} creates directories with the specified names. Synopsis: -+ -+@example -+mkdir [@var{option}]@dots{} @var{name}@dots{} -+@end example -+ -+@command{mkdir} creates each directory @var{name} in the order given. -+It reports an error if @var{name} already exists, unless the -+@option{-p} option is given and @var{name} is a directory. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -m @var{mode} -+@itemx --mode=@var{mode} -+@opindex -m -+@opindex --mode -+@cindex modes of created directories, setting -+Set the file permission bits of created directories to @var{mode}, -+which uses the same syntax as -+in @command{chmod} and uses @samp{a=rwx} (read, write and execute allowed for -+everyone) for the point of the departure. @xref{File permissions}. -+ -+Normally the directory has the desired file mode bits at the moment it -+is created. As a @acronym{GNU} extension, @var{mode} may also mention -+special mode bits, but in this case there may be a temporary window -+during which the directory exists but its special mode bits are -+incorrect. @xref{Directory Setuid and Setgid}, for how the -+set-user-ID and set-group-ID bits of directories are inherited unless -+overridden in this way. -+ -+@item -p -+@itemx --parents -+@opindex -p -+@opindex --parents -+@cindex parent directories, creating -+Make any missing parent directories for each argument, setting their -+file permission bits to the umask modified by @samp{u+wx}. Ignore -+existing parent directories, and do not change their file permission -+bits. -+ -+To set the file permission bits of any newly-created parent -+directories to a value that includes @samp{u+wx}, you can set the -+umask before invoking @command{mkdir}. For example, if the shell -+command @samp{(umask u=rwx,go=rx; mkdir -p P/Q)} creates the parent -+@file{P} it sets the parent's permission bits to @samp{u=rwx,go=rx}. -+To set a parent's special mode bits as well, you can invoke -+@command{chmod} after @command{mkdir}. @xref{Directory Setuid and -+Setgid}, for how the set-user-ID and set-group-ID bits of -+newly-created parent directories are inherited. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Print a message for each created directory. This is most useful with -+@option{--parents}. -+ -+@item -Z @var{context} -+@itemx --context=@var{context} -+@opindex -Z -+@opindex --context -+@cindex SELinux -+@cindex security context -+Set the default SELinux security context to be used for created directories. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node mkfifo invocation -+@section @command{mkfifo}: Make FIFOs (named pipes) -+ -+@pindex mkfifo -+@cindex FIFOs, creating -+@cindex named pipes, creating -+@cindex creating FIFOs (named pipes) -+ -+@command{mkfifo} creates FIFOs (also called @dfn{named pipes}) with the -+specified names. Synopsis: -+ -+@example -+mkfifo [@var{option}] @var{name}@dots{} -+@end example -+ -+A @dfn{FIFO} is a special file type that permits independent processes -+to communicate. One process opens the FIFO file for writing, and -+another for reading, after which data can flow as with the usual -+anonymous pipe in shells or elsewhere. -+ -+The program accepts the following option. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -m @var{mode} -+@itemx --mode=@var{mode} -+@opindex -m -+@opindex --mode -+@cindex modes of created FIFOs, setting -+Set the mode of created FIFOs to @var{mode}, which is symbolic as in -+@command{chmod} and uses @samp{a=rw} (read and write allowed for everyone) -+for the point of departure. @var{mode} should specify only file -+permission bits. @xref{File permissions}. -+ -+@item -Z @var{context} -+@itemx --context=@var{context} -+@opindex -Z -+@opindex --context -+@cindex SELinux -+@cindex security context -+Set the default SELinux security context to be used for created FIFOs. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node mknod invocation -+@section @command{mknod}: Make block or character special files -+ -+@pindex mknod -+@cindex block special files, creating -+@cindex character special files, creating -+ -+@command{mknod} creates a FIFO, character special file, or block special -+file with the specified name. Synopsis: -+ -+@example -+mknod [@var{option}]@dots{} @var{name} @var{type} [@var{major} @var{minor}] -+@end example -+ -+@cindex special files -+@cindex block special files -+@cindex character special files -+Unlike the phrase ``special file type'' above, the term @dfn{special -+file} has a technical meaning on Unix: something that can generate or -+receive data. Usually this corresponds to a physical piece of hardware, -+e.g., a printer or a disk. (These files are typically created at -+system-configuration time.) The @command{mknod} command is what creates -+files of this type. Such devices can be read either a character at a -+time or a ``block'' (many characters) at a time, hence we say there are -+@dfn{block special} files and @dfn{character special} files. -+ -+@c mknod is a shell built-in at least with OpenBSD's /bin/sh -+@mayConflictWithShellBuiltIn{mknod} -+ -+The arguments after @var{name} specify the type of file to make: -+ -+@table @samp -+ -+@item p -+@opindex p @r{for FIFO file} -+for a FIFO -+ -+@item b -+@opindex b @r{for block special file} -+for a block special file -+ -+@item c -+@c Don't document the `u' option -- it's just a synonym for `c'. -+@c Do *any* versions of mknod still use it? -+@c @itemx u -+@opindex c @r{for character special file} -+@c @opindex u @r{for character special file} -+for a character special file -+ -+@end table -+ -+When making a block or character special file, the major and minor -+device numbers must be given after the file type. -+If a major or minor device number begins with @samp{0x} or @samp{0X}, -+it is interpreted as hexadecimal; otherwise, if it begins with @samp{0}, -+as octal; otherwise, as decimal. -+ -+The program accepts the following option. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -m @var{mode} -+@itemx --mode=@var{mode} -+@opindex -m -+@opindex --mode -+Set the mode of created files to @var{mode}, which is symbolic as in -+@command{chmod} and uses @samp{a=rw} as the point of departure. -+@var{mode} should specify only file permission bits. -+@xref{File permissions}. -+ -+@item -Z @var{context} -+@itemx --context=@var{context} -+@opindex -Z -+@opindex --context -+@cindex SELinux -+@cindex security context -+Set the default SELinux security context to be used for created files. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node readlink invocation -+@section @command{readlink}: Print value of a symlink or canonical file name -+ -+@pindex readlink -+@cindex displaying value of a symbolic link -+@cindex canonical file name -+@cindex canonicalize a file name -+@pindex realpath -+@findex realpath -+ -+@command{readlink} may work in one of two supported modes: -+ -+@table @samp -+ -+@item Readlink mode -+ -+@command{readlink} outputs the value of the given symbolic link. -+If @command{readlink} is invoked with an argument other than the name -+of a symbolic link, it produces no output and exits with a nonzero exit code. -+ -+@item Canonicalize mode -+ -+@command{readlink} outputs the absolute name of the given file which contains -+no @file{.}, @file{..} components nor any repeated separators -+(@file{/}) or symbolic links. -+ -+@end table -+ -+@example -+readlink [@var{option}] @var{file} -+@end example -+ -+By default, @command{readlink} operates in readlink mode. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -f -+@itemx --canonicalize -+@opindex -f -+@opindex --canonicalize -+Activate canonicalize mode. -+If any component of the file name except the last one is missing or unavailable, -+@command{readlink} produces no output and exits with a nonzero exit -+code. A trailing slash is ignored. -+ -+@item -e -+@itemx --canonicalize-existing -+@opindex -e -+@opindex --canonicalize-existing -+Activate canonicalize mode. -+If any component is missing or unavailable, @command{readlink} produces -+no output and exits with a nonzero exit code. A trailing slash -+requires that the name resolve to a directory. -+ -+@item -m -+@itemx --canonicalize-missing -+@opindex -m -+@opindex --canonicalize-missing -+Activate canonicalize mode. -+If any component is missing or unavailable, @command{readlink} treats it -+as a directory. -+ -+@item -n -+@itemx --no-newline -+@opindex -n -+@opindex --no-newline -+Do not output the trailing newline. -+ -+@item -s -+@itemx -q -+@itemx --silent -+@itemx --quiet -+@opindex -s -+@opindex -q -+@opindex --silent -+@opindex --quiet -+Suppress most error messages. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Report error messages. -+ -+@end table -+ -+The @command{readlink} utility first appeared in OpenBSD 2.1. -+ -+There is a @command{realpath} command on some systems -+which operates like @command{readlink} in canonicalize mode. -+ -+@exitstatus -+ -+ -+@node rmdir invocation -+@section @command{rmdir}: Remove empty directories -+ -+@pindex rmdir -+@cindex removing empty directories -+@cindex directories, removing empty -+ -+@command{rmdir} removes empty directories. Synopsis: -+ -+@example -+rmdir [@var{option}]@dots{} @var{directory}@dots{} -+@end example -+ -+If any @var{directory} argument does not refer to an existing empty -+directory, it is an error. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item --ignore-fail-on-non-empty -+@opindex --ignore-fail-on-non-empty -+@cindex directory deletion, ignoring failures -+Ignore each failure to remove a directory that is solely because -+the directory is non-empty. -+ -+@item -p -+@itemx --parents -+@opindex -p -+@opindex --parents -+@cindex parent directories, removing -+Remove @var{directory}, then try to remove each component of @var{directory}. -+So, for example, @samp{rmdir -p a/b/c} is similar to @samp{rmdir a/b/c a/b a}. -+As such, it fails if any of those directories turns out not to be empty. -+Use the @option{--ignore-fail-on-non-empty} option to make it so such -+a failure does not evoke a diagnostic and does not cause @command{rmdir} to -+exit unsuccessfully. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+@cindex directory deletion, reporting -+Give a diagnostic for each successful removal. -+@var{directory} is removed. -+ -+@end table -+ -+@xref{rm invocation}, for how to remove non-empty directories (recursively). -+ -+@exitstatus -+ -+ -+@node unlink invocation -+@section @command{unlink}: Remove files via the unlink syscall -+ -+@pindex unlink -+@cindex removing files or directories (via the unlink syscall) -+ -+@command{unlink} deletes a single specified file name. -+It is a minimalist interface to the system-provided -+@code{unlink} function. @xref{Deleting Files, , , libc, -+The GNU C Library Reference Manual}. Synopsis: -+It avoids the bells and whistles of the more commonly-used -+@command{rm} command (@pxref{rm invocation}). -+ -+@example -+unlink @var{filename} -+@end example -+ -+On some systems @code{unlink} can be used to delete the name of a -+directory. On others, it can be used that way only by a privileged user. -+In the GNU system @code{unlink} can never delete the name of a directory. -+ -+The @command{unlink} command honors the @option{--help} and -+@option{--version} options. To remove a file whose name begins with -+@samp{-}, prefix the name with @samp{./}, e.g., @samp{unlink ./--help}. -+ -+@exitstatus -+ -+ -+@node Changing file attributes -+@chapter Changing file attributes -+ -+@cindex changing file attributes -+@cindex file attributes, changing -+@cindex attributes, file -+ -+A file is not merely its contents, a name, and a file type -+(@pxref{Special file types}). A file also has an owner (a user ID), a -+group (a group ID), permissions (what the owner can do with the file, -+what people in the group can do, and what everyone else can do), various -+timestamps, and other information. Collectively, we call these a file's -+@dfn{attributes}. -+ -+These commands change file attributes. -+ -+@menu -+* chgrp invocation:: Change file groups. -+* chmod invocation:: Change access permissions. -+* chown invocation:: Change file owners and groups. -+* touch invocation:: Change file timestamps. -+@end menu -+ -+ -+@node chown invocation -+@section @command{chown}: Change file owner and group -+ -+@pindex chown -+@cindex file ownership, changing -+@cindex group ownership, changing -+@cindex changing file ownership -+@cindex changing group ownership -+ -+@command{chown} changes the user and/or group ownership of each given @var{file} -+to @var{new-owner} or to the user and group of an existing reference file. -+Synopsis: -+ -+@example -+chown [@var{option}]@dots{} @{@var{new-owner} | --reference=@var{ref_file}@} @var{file}@dots{} -+@end example -+ -+If used, @var{new-owner} specifies the new owner and/or group as follows -+(with no embedded white space): -+ -+@example -+[@var{owner}] [ : [@var{group}] ] -+@end example -+ -+Specifically: -+ -+@table @var -+@item owner -+If only an @var{owner} (a user name or numeric user ID) is given, that -+user is made the owner of each given file, and the files' group is not -+changed. -+ -+@item owner@samp{:}group -+If the @var{owner} is followed by a colon and a @var{group} (a -+group name or numeric group ID), with no spaces between them, the group -+ownership of the files is changed as well (to @var{group}). -+ -+@item owner@samp{:} -+If a colon but no group name follows @var{owner}, that user is -+made the owner of the files and the group of the files is changed to -+@var{owner}'s login group. -+ -+@item @samp{:}group -+If the colon and following @var{group} are given, but the owner -+is omitted, only the group of the files is changed; in this case, -+@command{chown} performs the same function as @command{chgrp}. -+ -+@item @samp{:} -+If only a colon is given, or if @var{new-owner} is empty, neither the -+owner nor the group is changed. -+ -+@end table -+ -+If @var{owner} or @var{group} is intended to represent a numeric user -+or group ID, then you may specify it with a leading @samp{+}. -+@xref{Disambiguating names and IDs}. -+ -+Some older scripts may still use @samp{.} in place of the @samp{:} separator. -+@acronym{POSIX} 1003.1-2001 (@pxref{Standards conformance}) does not -+require support for that, but for backward compatibility @acronym{GNU} -+@command{chown} supports @samp{.} so long as no ambiguity results. -+New scripts should avoid the use of @samp{.} because it is not -+portable, and because it has undesirable results if the entire -+@var{owner@samp{.}group} happens to identify a user whose name -+contains @samp{.}. -+ -+The @command{chown} command sometimes clears the set-user-ID or -+set-group-ID permission bits. This behavior depends on the policy and -+functionality of the underlying @code{chown} system call, which may -+make system-dependent file mode modifications outside the control of -+the @command{chown} command. For example, the @command{chown} command -+might not affect those bits when invoked by a user with appropriate -+privileges, or when the -+bits signify some function other than executable permission (e.g., -+mandatory locking). -+When in doubt, check the underlying system behavior. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c -+@itemx --changes -+@opindex -c -+@opindex --changes -+@cindex changed owners, verbosely describing -+Verbosely describe the action for each @var{file} whose ownership -+actually changes. -+ -+@item -f -+@itemx --silent -+@itemx --quiet -+@opindex -f -+@opindex --silent -+@opindex --quiet -+@cindex error messages, omitting -+Do not print error messages about files whose ownership cannot be -+changed. -+ -+@itemx @w{@kbd{--from}=@var{old-owner}} -+@opindex --from -+@cindex symbolic links, changing owner -+Change a @var{file}'s ownership only if it has current attributes specified -+by @var{old-owner}. @var{old-owner} has the same form as @var{new-owner} -+described above. -+This option is useful primarily from a security standpoint in that -+it narrows considerably the window of potential abuse. -+For example, to reflect a user ID numbering change for one user's files -+without an option like this, @code{root} might run -+ -+@smallexample -+find / -owner OLDUSER -print0 | xargs -0 chown -h NEWUSER -+@end smallexample -+ -+But that is dangerous because the interval between when the @command{find} -+tests the existing file's owner and when the @command{chown} is actually run -+may be quite large. -+One way to narrow the gap would be to invoke chown for each file -+as it is found: -+ -+@example -+find / -owner OLDUSER -exec chown -h NEWUSER @{@} \; -+@end example -+ -+But that is very slow if there are many affected files. -+With this option, it is safer (the gap is narrower still) -+though still not perfect: -+ -+@example -+chown -h -R --from=OLDUSER NEWUSER / -+@end example -+ -+@item --dereference -+@opindex --dereference -+@cindex symbolic links, changing owner -+@findex lchown -+Do not act on symbolic links themselves but rather on what they point to. -+This is the default. -+ -+@item -h -+@itemx --no-dereference -+@opindex -h -+@opindex --no-dereference -+@cindex symbolic links, changing owner -+@findex lchown -+Act on symbolic links themselves instead of what they point to. -+This mode relies on the @code{lchown} system call. -+On systems that do not provide the @code{lchown} system call, -+@command{chown} fails when a file specified on the command line -+is a symbolic link. -+By default, no diagnostic is issued for symbolic links encountered -+during a recursive traversal, but see @option{--verbose}. -+ -+@itemx --preserve-root -+@opindex --preserve-root -+@cindex root directory, disallow recursive modification -+Fail upon any attempt to recursively change the root directory, @file{/}. -+Without @option{--recursive}, this option has no effect. -+@xref{Treating / specially}. -+ -+@itemx --no-preserve-root -+@opindex --no-preserve-root -+@cindex root directory, allow recursive modification -+Cancel the effect of any preceding @option{--preserve-root} option. -+@xref{Treating / specially}. -+ -+@item --reference=@var{ref_file} -+@opindex --reference -+Change the user and group of each @var{file} to be the same as those of -+@var{ref_file}. If @var{ref_file} is a symbolic link, do not use the -+user and group of the symbolic link, but rather those of the file it -+refers to. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Output a diagnostic for every file processed. -+If a symbolic link is encountered during a recursive traversal -+on a system without the @code{lchown} system call, and @option{--no-dereference} -+is in effect, then issue a diagnostic saying neither the symbolic link nor -+its referent is being changed. -+ -+@item -R -+@itemx --recursive -+@opindex -R -+@opindex --recursive -+@cindex recursively changing file ownership -+Recursively change ownership of directories and their contents. -+ -+@choptH -+@xref{Traversing symlinks}. -+ -+@choptL -+@xref{Traversing symlinks}. -+ -+@choptP -+@xref{Traversing symlinks}. -+ -+@end table -+ -+@exitstatus -+ -+Examples: -+ -+@smallexample -+# Change the owner of /u to "root". -+chown root /u -+ -+# Likewise, but also change its group to "staff". -+chown root:staff /u -+ -+# Change the owner of /u and subfiles to "root". -+chown -hR root /u -+@end smallexample -+ -+ -+@node chgrp invocation -+@section @command{chgrp}: Change group ownership -+ -+@pindex chgrp -+@cindex group ownership, changing -+@cindex changing group ownership -+ -+@command{chgrp} changes the group ownership of each given @var{file} -+to @var{group} (which can be either a group name or a numeric group ID) -+or to the group of an existing reference file. Synopsis: -+ -+@example -+chgrp [@var{option}]@dots{} @{@var{group} | --reference=@var{ref_file}@} @var{file}@dots{} -+@end example -+ -+If @var{group} is intended to represent a -+numeric group ID, then you may specify it with a leading @samp{+}. -+@xref{Disambiguating names and IDs}. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c -+@itemx --changes -+@opindex -c -+@opindex --changes -+@cindex changed files, verbosely describing -+Verbosely describe the action for each @var{file} whose group actually -+changes. -+ -+@item -f -+@itemx --silent -+@itemx --quiet -+@opindex -f -+@opindex --silent -+@opindex --quiet -+@cindex error messages, omitting -+Do not print error messages about files whose group cannot be -+changed. -+ -+@item --dereference -+@opindex --dereference -+@cindex symbolic links, changing owner -+@findex lchown -+Do not act on symbolic links themselves but rather on what they point to. -+This is the default. -+ -+@item -h -+@itemx --no-dereference -+@opindex -h -+@opindex --no-dereference -+@cindex symbolic links, changing group -+@findex lchown -+Act on symbolic links themselves instead of what they point to. -+This mode relies on the @code{lchown} system call. -+On systems that do not provide the @code{lchown} system call, -+@command{chgrp} fails when a file specified on the command line -+is a symbolic link. -+By default, no diagnostic is issued for symbolic links encountered -+during a recursive traversal, but see @option{--verbose}. -+ -+@itemx --preserve-root -+@opindex --preserve-root -+@cindex root directory, disallow recursive modification -+Fail upon any attempt to recursively change the root directory, @file{/}. -+Without @option{--recursive}, this option has no effect. -+@xref{Treating / specially}. -+ -+@itemx --no-preserve-root -+@opindex --no-preserve-root -+@cindex root directory, allow recursive modification -+Cancel the effect of any preceding @option{--preserve-root} option. -+@xref{Treating / specially}. -+ -+@item --reference=@var{ref_file} -+@opindex --reference -+Change the group of each @var{file} to be the same as that of -+@var{ref_file}. If @var{ref_file} is a symbolic link, do not use the -+group of the symbolic link, but rather that of the file it refers to. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Output a diagnostic for every file processed. -+If a symbolic link is encountered during a recursive traversal -+on a system without the @code{lchown} system call, and @option{--no-dereference} -+is in effect, then issue a diagnostic saying neither the symbolic link nor -+its referent is being changed. -+ -+@item -R -+@itemx --recursive -+@opindex -R -+@opindex --recursive -+@cindex recursively changing group ownership -+Recursively change the group ownership of directories and their contents. -+ -+@choptH -+@xref{Traversing symlinks}. -+ -+@choptL -+@xref{Traversing symlinks}. -+ -+@choptP -+@xref{Traversing symlinks}. -+ -+@end table -+ -+@exitstatus -+ -+Examples: -+ -+@smallexample -+# Change the group of /u to "staff". -+chgrp staff /u -+ -+# Change the group of /u and subfiles to "staff". -+chgrp -hR staff /u -+@end smallexample -+ -+ -+@node chmod invocation -+@section @command{chmod}: Change access permissions -+ -+@pindex chmod -+@cindex changing access permissions -+@cindex access permissions, changing -+@cindex permissions, changing access -+ -+@command{chmod} changes the access permissions of the named files. Synopsis: -+ -+@example -+chmod [@var{option}]@dots{} @{@var{mode} | --reference=@var{ref_file}@} @var{file}@dots{} -+@end example -+ -+@cindex symbolic links, permissions of -+@command{chmod} never changes the permissions of symbolic links, since -+the @command{chmod} system call cannot change their permissions. -+This is not a problem since the permissions of symbolic links are -+never used. However, for each symbolic link listed on the command -+line, @command{chmod} changes the permissions of the pointed-to file. -+In contrast, @command{chmod} ignores symbolic links encountered during -+recursive directory traversals. -+ -+A successful use of @command{chmod} clears the set-group-ID bit of a -+regular file if the file's group ID does not match the user's -+effective group ID or one of the user's supplementary group IDs, -+unless the user has appropriate privileges. Additional restrictions -+may cause the set-user-ID and set-group-ID bits of @var{mode} or -+@var{ref_file} to be ignored. This behavior depends on the policy and -+functionality of the underlying @code{chmod} system call. When in -+doubt, check the underlying system behavior. -+ -+If used, @var{mode} specifies the new file mode bits. -+For details, see the section on @ref{File permissions}. -+If you really want @var{mode} to have a leading @samp{-}, you should -+use @option{--} first, e.g., @samp{chmod -- -w file}. Typically, -+though, @samp{chmod a-w file} is preferable, and @command{chmod -w -+file} (without the @option{--}) complains if it behaves differently -+from what @samp{chmod a-w file} would do. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c -+@itemx --changes -+@opindex -c -+@opindex --changes -+Verbosely describe the action for each @var{file} whose permissions -+actually changes. -+ -+@item -f -+@itemx --silent -+@itemx --quiet -+@opindex -f -+@opindex --silent -+@opindex --quiet -+@cindex error messages, omitting -+Do not print error messages about files whose permissions cannot be -+changed. -+ -+@itemx --preserve-root -+@opindex --preserve-root -+@cindex root directory, disallow recursive modification -+Fail upon any attempt to recursively change the root directory, @file{/}. -+Without @option{--recursive}, this option has no effect. -+@xref{Treating / specially}. -+ -+@itemx --no-preserve-root -+@opindex --no-preserve-root -+@cindex root directory, allow recursive modification -+Cancel the effect of any preceding @option{--preserve-root} option. -+@xref{Treating / specially}. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+Verbosely describe the action or non-action taken for every @var{file}. -+ -+@item --reference=@var{ref_file} -+@opindex --reference -+Change the mode of each @var{file} to be the same as that of @var{ref_file}. -+@xref{File permissions}. -+If @var{ref_file} is a symbolic link, do not use the mode -+of the symbolic link, but rather that of the file it refers to. -+ -+@item -R -+@itemx --recursive -+@opindex -R -+@opindex --recursive -+@cindex recursively changing access permissions -+Recursively change permissions of directories and their contents. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node touch invocation -+@section @command{touch}: Change file timestamps -+ -+@pindex touch -+@cindex changing file timestamps -+@cindex file timestamps, changing -+@cindex timestamps, changing file -+ -+@command{touch} changes the access and/or modification times of the -+specified files. Synopsis: -+ -+@example -+touch [@var{option}]@dots{} @var{file}@dots{} -+@end example -+ -+@cindex empty files, creating -+Any @var{file} argument that does not exist is created empty. -+ -+A @var{file} argument string of @samp{-} is handled specially and -+causes @command{touch} to change the times of the file associated with -+standard output. -+ -+@cindex permissions, for changing file timestamps -+If changing both the access and modification times to the current -+time, @command{touch} can change the timestamps for files that the user -+running it does not own but has write permission for. Otherwise, the -+user must own the files. -+ -+Although @command{touch} provides options for changing two of the times---the -+times of last access and modification---of a file, there is actually -+a third one as well: the inode change time. This is often referred to -+as a file's @code{ctime}. -+The inode change time represents the time when the file's meta-information -+last changed. One common example of this is when the permissions of a -+file change. Changing the permissions doesn't access the file, so -+the atime doesn't change, nor does it modify the file, so the mtime -+doesn't change. Yet, something about the file itself has changed, -+and this must be noted somewhere. This is the job of the ctime field. -+This is necessary, so that, for example, a backup program can make a -+fresh copy of the file, including the new permissions value. -+Another operation that modifies a file's ctime without affecting -+the others is renaming. In any case, it is not possible, in normal -+operations, for a user to change the ctime field to a user-specified value. -+ -+@vindex TZ -+Time stamps assume the time zone rules specified by the @env{TZ} -+environment variable, or by the system default rules if @env{TZ} is -+not set. @xref{TZ Variable,, Specifying the Time Zone with @env{TZ}, -+libc, The GNU C Library Reference Manual}. -+You can avoid ambiguities during -+daylight saving transitions by using @sc{utc} time stamps. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -a -+@itemx --time=atime -+@itemx --time=access -+@itemx --time=use -+@opindex -a -+@opindex --time -+@opindex atime@r{, changing} -+@opindex access @r{time, changing} -+@opindex use @r{time, changing} -+Change the access time only. -+ -+@item -c -+@itemx --no-create -+@opindex -c -+@opindex --no-create -+Do not create files that do not exist. -+ -+@item -d -+@itemx --date=@var{time} -+@opindex -d -+@opindex --date -+@opindex time -+Use @var{time} instead of the current time. It can contain month names, -+time zones, @samp{am} and @samp{pm}, @samp{yesterday}, etc. For -+example, @option{--date="2004-02-27 14:19:13.489392193 +0530"} -+specifies the instant of time that is 489,392,193 nanoseconds after -+February 27, 2004 at 2:19:13 PM in a time zone that is 5 hours and 30 -+minutes east of @acronym{UTC}. @xref{Date input formats}. -+File systems that do not support high-resolution time stamps -+silently ignore any excess precision here. -+ -+@item -f -+@opindex -f -+@cindex BSD @command{touch} compatibility -+Ignored; for compatibility with BSD versions of @command{touch}. -+ -+@item -m -+@itemx --time=mtime -+@itemx --time=modify -+@opindex -m -+@opindex --time -+@opindex mtime@r{, changing} -+@opindex modify @r{time, changing} -+Change the modification time only. -+ -+@item -r @var{file} -+@itemx --reference=@var{file} -+@opindex -r -+@opindex --reference -+Use the times of the reference @var{file} instead of the current time. -+If this option is combined with the @option{--date=@var{time}} -+(@option{-d @var{time}}) option, the reference @var{file}'s time is -+the origin for any relative @var{time}s given, but is otherwise ignored. -+For example, @samp{-r foo -d '-5 seconds'} specifies a time stamp -+equal to five seconds before the corresponding time stamp for @file{foo}. -+ -+@item -t [[@var{cc}]@var{yy}]@var{mmddhhmm}[.@var{ss}] -+Use the argument (optional four-digit or two-digit years, months, -+days, hours, minutes, optional seconds) instead of the current time. -+If the year is specified with only two digits, then @var{cc} -+is 20 for years in the range 0 @dots{} 68, and 19 for years in -+69 @dots{} 99. If no digits of the year are specified, -+the argument is interpreted as a date in the current year. -+Note that @var{ss} may be @samp{60}, to accommodate leap seconds. -+ -+@end table -+ -+@vindex _POSIX2_VERSION -+On older systems, @command{touch} supports an obsolete syntax, as follows. -+If no timestamp is given with any of the @option{-d}, @option{-r}, or -+@option{-t} options, and if there are two or more @var{file}s and the -+first @var{file} is of the form @samp{@var{mmddhhmm}[@var{yy}]} and this -+would be a valid argument to the @option{-t} option (if the @var{yy}, if -+any, were moved to the front), and if the represented year -+is in the range 1969--1999, that argument is interpreted as the time -+for the other files instead of as a file name. -+This obsolete behavior can be enabled or disabled with the -+@env{_POSIX2_VERSION} environment variable (@pxref{Standards -+conformance}), but portable scripts should avoid commands whose -+behavior depends on this variable. -+For example, use @samp{touch ./12312359 main.c} or @samp{touch -t -+12312359 main.c} rather than the ambiguous @samp{touch 12312359 main.c}. -+ -+@exitstatus -+ -+ -+@node Disk usage -+@chapter Disk usage -+ -+@cindex disk usage -+ -+No disk can hold an infinite amount of data. These commands report -+how much disk storage is in use or available, report other file and -+file status information, and write buffers to disk. -+ -+@menu -+* df invocation:: Report file system disk space usage. -+* du invocation:: Estimate file space usage. -+* stat invocation:: Report file or file system status. -+* sync invocation:: Synchronize memory and disk. -+* truncate invocation:: Shrink or extend the size of a file. -+@end menu -+ -+ -+@node df invocation -+@section @command{df}: Report file system disk space usage -+ -+@pindex df -+@cindex file system disk usage -+@cindex disk usage by file system -+ -+@command{df} reports the amount of disk space used and available on -+file systems. Synopsis: -+ -+@example -+df [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+With no arguments, @command{df} reports the space used and available on all -+currently mounted file systems (of all types). Otherwise, @command{df} -+reports on the file system containing each argument @var{file}. -+ -+Normally the disk space is printed in units of -+1024 bytes, but this can be overridden (@pxref{Block size}). -+Non-integer quantities are rounded up to the next higher unit. -+ -+@cindex disk device file -+@cindex device file, disk -+If an argument @var{file} is a disk device file containing a mounted -+file system, @command{df} shows the space available on that file system -+rather than on the file system containing the device node (i.e., the root -+file system). @sc{gnu} @command{df} does not attempt to determine the disk usage -+on unmounted file systems, because on most kinds of systems doing so -+requires extremely nonportable intimate knowledge of file system -+structures. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -a -+@itemx --all -+@opindex -a -+@opindex --all -+@cindex automounter file systems -+@cindex ignore file systems -+Include in the listing dummy file systems, which -+are omitted by default. Such file systems are typically special-purpose -+pseudo-file-systems, such as automounter entries. -+ -+@item -B @var{size} -+@itemx --block-size=@var{size} -+@opindex -B -+@opindex --block-size -+@cindex file system sizes -+Scale sizes by @var{size} before printing them (@pxref{Block size}). -+For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes. -+ -+@itemx --total -+@opindex --total -+@cindex grand total of disk size, usage and available space -+Print a grand total of all arguments after all arguments have -+been processed. This can be used to find out the total disk size, usage -+and available space of all listed devices. -+ -+@optHumanReadable -+ -+@item -H -+@opindex -H -+Equivalent to @option{--si}. -+ -+@item -i -+@itemx --inodes -+@opindex -i -+@opindex --inodes -+@cindex inode usage -+List inode usage information instead of block usage. An inode (short -+for index node) contains information about a file such as its owner, -+permissions, timestamps, and location on the disk. -+ -+@item -k -+@opindex -k -+@cindex kibibytes for file system sizes -+Print sizes in 1024-byte blocks, overriding the default block size -+(@pxref{Block size}). -+This option is equivalent to @option{--block-size=1K}. -+ -+@item -l -+@itemx --local -+@opindex -l -+@opindex --local -+@cindex file system types, limiting output to certain -+Limit the listing to local file systems. By default, remote file systems -+are also listed. -+ -+@item --no-sync -+@opindex --no-sync -+@cindex file system space, retrieving old data more quickly -+Do not invoke the @code{sync} system call before getting any usage data. -+This may make @command{df} run significantly faster on systems with many -+disks, but on some systems (notably SunOS) the results may be slightly -+out of date. This is the default. -+ -+@item -P -+@itemx --portability -+@opindex -P -+@opindex --portability -+@cindex one-line output format -+@cindex @acronym{POSIX} output format -+@cindex portable output format -+@cindex output format, portable -+Use the @acronym{POSIX} output format. This is like the default format except -+for the following: -+ -+@enumerate -+@item -+The information about each file system is always printed on exactly -+one line; a mount device is never put on a line by itself. This means -+that if the mount device name is more than 20 characters long (e.g., for -+some network mounts), the columns are misaligned. -+ -+@item -+The labels in the header output line are changed to conform to @acronym{POSIX}. -+ -+@item -+The default block size and output format are unaffected by the -+@env{DF_BLOCK_SIZE}, @env{BLOCK_SIZE} and @env{BLOCKSIZE} environment -+variables. However, the default block size is still affected by -+@env{POSIXLY_CORRECT}: it is 512 if @env{POSIXLY_CORRECT} is set, 1024 -+otherwise. @xref{Block size}. -+@end enumerate -+ -+@optSi -+ -+@item --sync -+@opindex --sync -+@cindex file system space, retrieving current data more slowly -+Invoke the @code{sync} system call before getting any usage data. On -+some systems (notably SunOS), 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 -t @var{fstype} -+@itemx --type=@var{fstype} -+@opindex -t -+@opindex --type -+@cindex file system types, limiting output to certain -+Limit the listing to file systems of type @var{fstype}. Multiple -+file system types can be specified by giving multiple @option{-t} options. -+By default, nothing is omitted. -+ -+@item -T -+@itemx --print-type -+@opindex -T -+@opindex --print-type -+@cindex file system types, printing -+Print each file system's type. The types printed here are the same ones -+you can include or exclude with @option{-t} and @option{-x}. The particular -+types printed are whatever is supported by the system. Here are some of -+the common names (this list is certainly not exhaustive): -+ -+@table @samp -+ -+@item nfs -+@cindex @acronym{NFS} file system type -+An @acronym{NFS} file system, i.e., one mounted over a network from another -+machine. This is the one type name which seems to be used uniformly by -+all systems. -+ -+@item 4.2@r{, }ufs@r{, }efs@dots{} -+@cindex Linux file system types -+@cindex local file system types -+@opindex 4.2 @r{file system type} -+@opindex ufs @r{file system type} -+@opindex efs @r{file system type} -+A file system on a locally-mounted hard disk. (The system might even -+support more than one type here; Linux does.) -+ -+@item hsfs@r{, }cdfs -+@cindex CD-ROM file system type -+@cindex High Sierra file system -+@opindex hsfs @r{file system type} -+@opindex cdfs @r{file system type} -+A file system on a CD-ROM drive. HP-UX uses @samp{cdfs}, most other -+systems use @samp{hsfs} (@samp{hs} for ``High Sierra''). -+ -+@item pcfs -+@cindex PC file system -+@cindex DOS file system -+@cindex MS-DOS file system -+@cindex diskette file system -+@opindex pcfs -+An MS-DOS file system, usually on a diskette. -+ -+@end table -+ -+@item -x @var{fstype} -+@itemx --exclude-type=@var{fstype} -+@opindex -x -+@opindex --exclude-type -+Limit the listing to file systems not of type @var{fstype}. -+Multiple file system types can be eliminated by giving multiple -+@option{-x} options. By default, no file system types are omitted. -+ -+@item -v -+Ignored; for compatibility with System V versions of @command{df}. -+ -+@end table -+ -+@exitstatus -+Failure includes the case where no output is generated, so you can -+inspect the exit status of a command like @samp{df -t ext3 -t reiserfs -+@var{dir}} to test whether @var{dir} is on a file system of type -+@samp{ext3} or @samp{reiserfs}. -+ -+ -+@node du invocation -+@section @command{du}: Estimate file space usage -+ -+@pindex du -+@cindex file space usage -+@cindex disk usage for files -+ -+@command{du} reports the amount of disk space used by the specified files -+and for each subdirectory (of directory arguments). Synopsis: -+ -+@example -+du [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+With no arguments, @command{du} reports the disk space for the current -+directory. Normally the disk space is printed in units of -+1024 bytes, but this can be overridden (@pxref{Block size}). -+Non-integer quantities are rounded up to the next higher unit. -+ -+If two or more hard links point to the same file, only one of the hard -+links is counted. The @var{file} argument order affects which links -+are counted, and changing the argument order may change the numbers -+that @command{du} outputs. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -a -+@itemx --all -+@opindex -a -+@opindex --all -+Show counts for all files, not just directories. -+ -+@itemx --apparent-size -+@opindex --apparent-size -+Print apparent sizes, rather than disk usage. The apparent size of a -+file is the number of bytes reported by @code{wc -c} on regular files, -+or more generally, @code{ls -l --block-size=1} or @code{stat --format=%s}. -+For example, a file containing the word @samp{zoo} with no newline would, -+of course, have an apparent size of 3. Such a small file may require -+anywhere from 0 to 16 KiB or more of disk space, depending on -+the type and configuration of the file system on which the file resides. -+However, a sparse file created with this command: -+ -+@example -+dd bs=1 seek=2GiB if=/dev/null of=big -+@end example -+ -+@noindent -+has an apparent size of 2 GiB, yet on most modern -+systems, it actually uses almost no disk space. -+ -+@item -b -+@itemx --bytes -+@opindex -b -+@opindex --bytes -+Equivalent to @code{--apparent-size --block-size=1}. -+ -+@item -B @var{size} -+@itemx --block-size=@var{size} -+@opindex -B -+@opindex --block-size -+@cindex file sizes -+Scale sizes by @var{size} before printing them (@pxref{Block size}). -+For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes. -+ -+@item -c -+@itemx --total -+@opindex -c -+@opindex --total -+@cindex grand total of disk space -+Print a grand total of all arguments after all arguments have -+been processed. This can be used to find out the total disk usage of -+a given set of files or directories. -+ -+@item -D -+@itemx --dereference-args -+@opindex -D -+@opindex --dereference-args -+Dereference symbolic links that are command line arguments. -+Does not affect other symbolic links. This is helpful for finding -+out the disk usage of directories, such as @file{/usr/tmp}, which -+are often symbolic links. -+ -+@c --files0-from=FILE -+@filesZeroFromOption{du,, with the @option{--total} (@option{-c}) option} -+ -+@optHumanReadable -+ -+@item -H -+@opindex -H -+Equivalent to @option{--dereference-args} (@option{-D}). -+ -+@item -k -+@opindex -k -+@cindex kibibytes for file sizes -+Print sizes in 1024-byte blocks, overriding the default block size -+(@pxref{Block size}). -+This option is equivalent to @option{--block-size=1K}. -+ -+@item -l -+@itemx --count-links -+@opindex -l -+@opindex --count-links -+@cindex hard links, counting in @command{du} -+Count the size of all files, even if they have appeared already (as a -+hard link). -+ -+@item -L -+@itemx --dereference -+@opindex -L -+@opindex --dereference -+@cindex symbolic links, dereferencing in @command{du} -+Dereference symbolic links (show the disk space used by the file -+or directory that the link points to instead of the space used by -+the link). -+ -+@item -m -+@opindex -m -+@cindex mebibytes for file sizes -+Print sizes in 1,048,576-byte blocks, overriding the default block size -+(@pxref{Block size}). -+This option is equivalent to @option{--block-size=1M}. -+ -+@item -P -+@itemx --no-dereference -+@opindex -P -+@opindex --no-dereference -+@cindex symbolic links, dereferencing in @command{du} -+For each symbolic links encountered by @command{du}, -+consider the disk space used by the symbolic link. -+ -+@item --max-depth=@var{depth} -+@opindex --max-depth=@var{depth} -+@cindex limiting output of @command{du} -+Show the total for each directory (and file if --all) that is at -+most MAX_DEPTH levels down from the root of the hierarchy. The root -+is at level 0, so @code{du --max-depth=0} is equivalent to @code{du -s}. -+ -+@item -0 -+@opindex -0 -+@itemx --null -+@opindex --null -+@cindex output null-byte-terminated lines -+Output a zero byte (@acronym{ASCII} @sc{nul}) at the end of each line, -+rather than a newline. This option enables other programs to parse the -+output of @command{du} even when that output would contain file names -+with embedded newlines. -+ -+@optSi -+ -+@item -s -+@itemx --summarize -+@opindex -s -+@opindex --summarize -+Display only a total for each argument. -+ -+@item -S -+@itemx --separate-dirs -+@opindex -S -+@opindex --separate-dirs -+Normally, in the output of @command{du} (when not using @option{--summarize}), -+the size listed next to a directory name, @var{d}, represents the sum -+of sizes of all entries beneath @var{d} as well as the size of @var{d} itself. -+With @option{--separate-dirs}, the size reported for a directory name, -+@var{d}, is merely the @code{stat.st_size}-derived size of the directory -+entry, @var{d}. -+ -+@itemx --time -+@opindex --time -+@cindex last modified dates, displaying in @command{du} -+Show time of the most recent modification of any file in the directory, -+or any of its subdirectories. -+ -+@itemx --time=ctime -+@itemx --time=status -+@itemx --time=use -+@opindex --time -+@opindex ctime@r{, show the most recent} -+@opindex status time@r{, show the most recent} -+@opindex use time@r{, show the most recent} -+Show the most recent status change time (the @samp{ctime} in the inode) of -+any file in the directory, instead of the modification time. -+ -+@itemx --time=atime -+@itemx --time=access -+@opindex --time -+@opindex atime@r{, show the most recent} -+@opindex access time@r{, show the most recent} -+Show the most recent access time (the @samp{atime} in the inode) of -+any file in the directory, instead of the modification time. -+ -+@item --time-style=@var{style} -+@opindex --time-style -+@cindex time style -+List timestamps in style @var{style}. This option has an effect only if -+the @option{--time} option is also specified. The @var{style} should -+be one of the following: -+ -+@table @samp -+@item +@var{format} -+@vindex LC_TIME -+List timestamps using @var{format}, where @var{format} is interpreted -+like the format argument of @command{date} (@pxref{date invocation}). -+For example, @option{--time-style="+%Y-%m-%d %H:%M:%S"} causes -+@command{du} to list timestamps like @samp{2002-03-30 23:45:56}. As -+with @command{date}, @var{format}'s interpretation is affected by the -+@env{LC_TIME} locale category. -+ -+@item full-iso -+List timestamps in full using @acronym{ISO} 8601 date, time, and time zone -+format with nanosecond precision, e.g., @samp{2002-03-30 -+23:45:56.477817180 -0700}. This style is equivalent to -+@samp{+%Y-%m-%d %H:%M:%S.%N %z}. -+ -+@item long-iso -+List @acronym{ISO} 8601 date and time in minutes, e.g., -+@samp{2002-03-30 23:45}. These timestamps are shorter than -+@samp{full-iso} timestamps, and are usually good enough for everyday -+work. This style is equivalent to @samp{+%Y-%m-%d %H:%M}. -+ -+@item iso -+List @acronym{ISO} 8601 dates for timestamps, e.g., @samp{2002-03-30}. -+This style is equivalent to @samp{+%Y-%m-%d}. -+@end table -+ -+@vindex TIME_STYLE -+You can specify the default value of the @option{--time-style} option -+with the environment variable @env{TIME_STYLE}; if @env{TIME_STYLE} is not set -+the default style is @samp{long-iso}. For compatibility with @command{ls}, -+if @env{TIME_STYLE} begins with @samp{+} and contains a newline, -+the newline and any later characters are ignored; if @env{TIME_STYLE} -+begins with @samp{posix-} the @samp{posix-} is ignored; and if -+@env{TIME_STYLE} is @samp{locale} it is ignored. -+ -+@item -x -+@itemx --one-file-system -+@opindex -x -+@opindex --one-file-system -+@cindex one file system, restricting @command{du} to -+Skip directories that are on different file systems from the one that -+the argument being processed is on. -+ -+@item --exclude=@var{pattern} -+@opindex --exclude=@var{pattern} -+@cindex excluding files from @command{du} -+When recursing, skip subdirectories or files matching @var{pattern}. -+For example, @code{du --exclude='*.o'} excludes files whose names -+end in @samp{.o}. -+ -+@item -X @var{file} -+@itemx --exclude-from=@var{file} -+@opindex -X @var{file} -+@opindex --exclude-from=@var{file} -+@cindex excluding files from @command{du} -+Like @option{--exclude}, except take the patterns to exclude from @var{file}, -+one per line. If @var{file} is @samp{-}, take the patterns from standard -+input. -+ -+@end table -+ -+@cindex NFS mounts from BSD to HP-UX -+On BSD systems, @command{du} reports sizes that are half the correct -+values for files that are NFS-mounted from HP-UX systems. On HP-UX -+systems, it reports sizes that are twice the correct values for -+files that are NFS-mounted from BSD systems. This is due to a flaw -+in HP-UX; it also affects the HP-UX @command{du} program. -+ -+@exitstatus -+ -+ -+@node stat invocation -+@section @command{stat}: Report file or file system status -+ -+@pindex stat -+@cindex file status -+@cindex file system status -+ -+@command{stat} displays information about the specified file(s). Synopsis: -+ -+@example -+stat [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+With no option, @command{stat} reports all information about the given files. -+But it also can be used to report the information of the file systems the -+given files are located on. If the files are links, @command{stat} can -+also give information about the files the links point to. -+ -+@mayConflictWithShellBuiltIn{stat} -+ -+@table @samp -+ -+@item -L -+@itemx --dereference -+@opindex -L -+@opindex --dereference -+@cindex symbolic links, dereferencing in @command{stat} -+Change how @command{stat} treats symbolic links. -+With this option, @command{stat} acts on the file referenced -+by each symbolic link argument. -+Without it, @command{stat} acts on any symbolic link argument directly. -+ -+@item -f -+@itemx --file-system -+@opindex -f -+@opindex --file-system -+@cindex file systems -+Report information about the file systems where the given files are located -+instead of information about the files themselves. -+ -+@item -c -+@itemx --format=@var{format} -+@opindex -c -+@opindex --format=@var{format} -+@cindex output format -+Use @var{format} rather than the default format. -+@var{format} is automatically newline-terminated, so -+running a command like the following with two or more @var{file} -+operands produces a line of output for each operand: -+@example -+$ stat --format=%d:%i / /usr -+2050:2 -+2057:2 -+@end example -+ -+@itemx --printf=@var{format} -+@opindex --printf=@var{format} -+@cindex output format -+Use @var{format} rather than the default format. -+Like @option{--format}, but interpret backslash escapes, -+and do not output a mandatory trailing newline. -+If you want a newline, include @samp{\n} in the @var{format}. -+Here's how you would use @option{--printf} to print the device -+and inode numbers of @file{/} and @file{/usr}: -+@example -+$ stat --printf='%d:%i\n' / /usr -+2050:2 -+2057:2 -+@end example -+ -+@item -t -+@itemx --terse -+@opindex -t -+@opindex --terse -+@cindex terse output -+Print the information in terse form, suitable for parsing by other programs. -+ -+@end table -+ -+The valid @var{format} directives for files with @option{--format} and -+@option{--printf} are: -+ -+@itemize @bullet -+@item %a - Access rights in octal -+@item %A - Access rights in human readable form -+@item %b - Number of blocks allocated (see @samp{%B}) -+@item %B - The size in bytes of each block reported by @samp{%b} -+@item %d - Device number in decimal -+@item %D - Device number in hex -+@item %f - Raw mode in hex -+@item %F - File type -+@item %g - Group ID of owner -+@item %G - Group name of owner -+@item %h - Number of hard links -+@item %i - Inode number -+@item %n - File name -+@item %N - Quoted file name with dereference if symbolic link -+@item %o - I/O block size -+@item %s - Total size, in bytes -+@item %t - Major device type in hex -+@item %T - Minor device type in hex -+@item %u - User ID of owner -+@item %U - User name of owner -+@item %x - Time of last access -+@item %X - Time of last access as seconds since Epoch -+@item %y - Time of last modification -+@item %Y - Time of last modification as seconds since Epoch -+@item %z - Time of last change -+@item %Z - Time of last change as seconds since Epoch -+@end itemize -+ -+When listing file system information (@option{--file-system} (@option{-f})), -+you must use a different set of @var{format} directives: -+ -+@itemize @bullet -+@item %a - Free blocks available to non-super-user -+@item %b - Total data blocks in file system -+@item %c - Total file nodes in file system -+@item %d - Free file nodes in file system -+@item %f - Free blocks in file system -+@item %i - File System ID in hex -+@item %l - Maximum length of file names -+@item %n - File name -+@item %s - Block size (for faster transfers) -+@item %S - Fundamental block size (for block counts) -+@item %t - Type in hex -+@item %T - Type in human readable form -+@end itemize -+ -+@vindex TZ -+Time stamps are listed according to the time zone rules specified by -+the @env{TZ} environment variable, or by the system default rules if -+@env{TZ} is not set. @xref{TZ Variable,, Specifying the Time Zone -+with @env{TZ}, libc, The GNU C Library Reference Manual}. -+ -+@exitstatus -+ -+ -+@node sync invocation -+@section @command{sync}: Synchronize data on disk with memory -+ -+@pindex sync -+@cindex synchronize disk and memory -+ -+@cindex superblock, writing -+@cindex inodes, written buffered -+@command{sync} writes any data buffered in memory out to disk. This can -+include (but is not limited to) modified superblocks, modified inodes, -+and delayed reads and writes. This must be implemented by the kernel; -+The @command{sync} program does nothing but exercise the @code{sync} system -+call. -+ -+@cindex crashes and corruption -+The kernel keeps data in memory to avoid doing (relatively slow) disk -+reads and writes. This improves performance, but if the computer -+crashes, data may be lost or the file system corrupted as a -+result. The @command{sync} command ensures everything in memory -+is written to disk. -+ -+Any arguments are ignored, except for a lone @option{--help} or -+@option{--version} (@pxref{Common options}). -+ -+@exitstatus -+ -+ -+@node truncate invocation -+@section @command{truncate}: Shrink or extend the size of a file -+ -+@pindex truncate -+@cindex truncating, file sizes -+ -+@command{truncate} shrinks or extends the size of each @var{file} to the -+specified size. Synopsis: -+ -+@example -+truncate @var{option}@dots{} @var{file}@dots{} -+@end example -+ -+@cindex files, creating -+Any @var{file} that does not exist is created. -+ -+@cindex sparse files, creating -+@cindex holes, creating files with -+If a @var{file} is larger than the specified size, the extra data is lost. -+If a @var{file} is shorter, it is extended and the extended part (or hole) -+reads as zero bytes. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c -+@itemx --no-create -+@opindex -c -+@opindex --no-create -+Do not create files that do not exist. -+ -+@item -o -+@itemx --io-blocks -+@opindex -o -+@opindex --io-blocks -+Treat @var{size} as number of I/O blocks of the @var{file} rather than bytes. -+ -+@item -r @var{rfile} -+@itemx --reference=@var{rfile} -+@opindex -r -+@opindex --reference -+Set the size of each @var{file} to the same size as @var{rfile}. -+ -+@item -s @var{size} -+@itemx --size=@var{size} -+@opindex -s -+@opindex --size -+Set the size of each @var{file} to this @var{size}. -+@multiplierSuffixesNoBlocks{size} -+ -+@var{size} may also be prefixed by one of the following to adjust -+the size of each @var{file} based on their current size: -+@example -+@samp{+} => extend by -+@samp{-} => reduce by -+@samp{<} => at most -+@samp{>} => at least -+@samp{/} => round down to multiple of -+@samp{%} => round up to multiple of -+@end example -+ -+@end table -+ -+@exitstatus -+ -+ -+@node Printing text -+@chapter Printing text -+ -+@cindex printing text, commands for -+@cindex commands for printing text -+ -+This section describes commands that display text strings. -+ -+@menu -+* echo invocation:: Print a line of text. -+* printf invocation:: Format and print data. -+* yes invocation:: Print a string until interrupted. -+@end menu -+ -+ -+@node echo invocation -+@section @command{echo}: Print a line of text -+ -+@pindex echo -+@cindex displaying text -+@cindex printing text -+@cindex text, displaying -+@cindex arbitrary text, displaying -+ -+@command{echo} writes each given @var{string} to standard output, with a -+space between each and a newline after the last one. Synopsis: -+ -+@example -+echo [@var{option}]@dots{} [@var{string}]@dots{} -+@end example -+ -+@mayConflictWithShellBuiltIn{echo} -+ -+The program accepts the following options. Also see @ref{Common options}. -+Options must precede operands, and the normally-special argument -+@samp{--} has no special meaning and is treated like any other -+@var{string}. -+ -+@table @samp -+@item -n -+@opindex -n -+Do not output the trailing newline. -+ -+@item -e -+@opindex -e -+@cindex backslash escapes -+Enable interpretation of the following backslash-escaped characters in -+each @var{string}: -+ -+@table @samp -+@item \a -+alert (bell) -+@item \b -+backspace -+@item \c -+produce no further output -+@item \f -+form feed -+@item \n -+newline -+@item \r -+carriage return -+@item \t -+horizontal tab -+@item \v -+vertical tab -+@item \\ -+backslash -+@item \0@var{nnn} -+the eight-bit value that is the octal number @var{nnn} -+(zero to three octal digits) -+@item \@var{nnn} -+the eight-bit value that is the octal number @var{nnn} -+(one to three octal digits) -+@item \x@var{hh} -+the eight-bit value that is the hexadecimal number @var{hh} -+(one or two hexadecimal digits) -+@end table -+ -+@item -E -+@opindex -E -+@cindex backslash escapes -+Disable interpretation of backslash escapes in each @var{string}. -+This is the default. If @option{-e} and @option{-E} are both -+specified, the last one given takes effect. -+ -+@end table -+ -+@vindex POSIXLY_CORRECT -+If the @env{POSIXLY_CORRECT} environment variable is set, then when -+@command{echo}'s first argument is not @option{-n} it outputs -+option-like arguments instead of treating them as options. For -+example, @code{echo -ne hello} outputs @samp{-ne hello} instead of -+plain @samp{hello}. -+ -+@acronym{POSIX} does not require support for any options, and says -+that the behavior of @command{echo} is implementation-defined if any -+@var{string} contains a backslash or if the first argument is -+@option{-n}. Portable programs can use the @command{printf} command -+if they need to omit trailing newlines or output control characters or -+backslashes. @xref{printf invocation}. -+ -+@exitstatus -+ -+ -+@node printf invocation -+@section @command{printf}: Format and print data -+ -+@pindex printf -+@command{printf} does formatted printing of text. Synopsis: -+ -+@example -+printf @var{format} [@var{argument}]@dots{} -+@end example -+ -+@command{printf} prints the @var{format} string, interpreting @samp{%} -+directives and @samp{\} escapes to format numeric and string arguments -+in a way that is mostly similar to the C @samp{printf} function. -+@xref{Output Conversion Syntax,, @command{printf} format directives, -+libc, The GNU C Library Reference Manual}, for details. -+The differences are listed below. -+ -+@mayConflictWithShellBuiltIn{printf} -+ -+@itemize @bullet -+ -+@item -+The @var{format} argument is reused as necessary to convert all the -+given @var{argument}s. For example, the command @samp{printf %s a b} -+outputs @samp{ab}. -+ -+@item -+Missing @var{argument}s are treated as null strings or as zeros, -+depending on whether the context expects a string or a number. For -+example, the command @samp{printf %sx%d} prints @samp{x0}. -+ -+@item -+@kindex \c -+An additional escape, @samp{\c}, causes @command{printf} to produce no -+further output. For example, the command @samp{printf 'A%sC\cD%sF' B -+E} prints @samp{ABC}. -+ -+@item -+The hexadecimal escape sequence @samp{\x@var{hh}} has at most two -+digits, as opposed to C where it can have an unlimited number of -+digits. For example, the command @samp{printf '\x07e'} prints two -+bytes, whereas the C statement @samp{printf ("\x07e")} prints just -+one. -+ -+@item -+@kindex %b -+@command{printf} has an additional directive, @samp{%b}, which prints its -+argument string with @samp{\} escapes interpreted in the same way as in -+the @var{format} string, except that octal escapes are of the form -+@samp{\0@var{ooo}} where @var{ooo} is 0 to 3 octal digits. -+If a precision is also given, it limits the number of bytes printed -+from the converted string. -+ -+@item -+Numeric arguments must be single C constants, possibly with leading -+@samp{+} or @samp{-}. For example, @samp{printf %.4d -3} outputs -+@samp{-0003}. -+ -+@item -+@vindex POSIXLY_CORRECT -+If the leading character of a numeric argument is @samp{"} or @samp{'} -+then its value is the numeric value of the immediately following -+character. Any remaining characters are silently ignored if the -+@env{POSIXLY_CORRECT} environment variable is set; otherwise, a -+warning is printed. For example, @samp{printf "%d" "'a"} outputs -+@samp{97} on hosts that use the @acronym{ASCII} character set, since -+@samp{a} has the numeric value 97 in @acronym{ASCII}. -+ -+@end itemize -+ -+@vindex LC_NUMERIC -+A floating-point argument must use a period before any fractional -+digits, but is printed according to the @env{LC_NUMERIC} category of the -+current locale. For example, in a locale whose radix character is a -+comma, the command @samp{printf %g 3.14} outputs @samp{3,14} whereas -+the command @samp{printf %g 3,14} is an error. -+ -+@kindex \@var{ooo} -+@kindex \x@var{hh} -+@command{printf} interprets @samp{\@var{ooo}} in @var{format} as an octal number -+(if @var{ooo} is 1 to 3 octal digits) specifying a character to print, -+and @samp{\x@var{hh}} as a hexadecimal number (if @var{hh} is 1 to 2 hex -+digits) specifying a character to print. -+ -+@kindex \uhhhh -+@kindex \Uhhhhhhhh -+@cindex Unicode -+@cindex ISO/IEC 10646 -+@vindex LC_CTYPE -+@command{printf} interprets two character syntaxes introduced in -+@acronym{ISO} C 99: -+@samp{\u} for 16-bit Unicode (@acronym{ISO}/@acronym{IEC} 10646) -+characters, specified as -+four hexadecimal digits @var{hhhh}, and @samp{\U} for 32-bit Unicode -+characters, specified as eight hexadecimal digits @var{hhhhhhhh}. -+@command{printf} outputs the Unicode characters -+according to the @env{LC_CTYPE} locale. Unicode characters in the ranges -+U+0000...U+009F, U+D800...U+DFFF cannot be specified by this syntax, except -+for U+0024 ($), U+0040 (@@), and U+0060 (@`). -+ -+The processing of @samp{\u} and @samp{\U} requires a full-featured -+@code{iconv} facility. It is activated on systems with glibc 2.2 (or newer), -+or when @code{libiconv} is installed prior to this package. Otherwise -+@samp{\u} and @samp{\U} will print as-is. -+ -+The only options are a lone @option{--help} or -+@option{--version}. @xref{Common options}. -+Options must precede operands. -+ -+The Unicode character syntaxes are useful for writing strings in a locale -+independent way. For example, a string containing the Euro currency symbol -+ -+@example -+$ env printf '\u20AC 14.95' -+@end example -+ -+@noindent -+will be output correctly in all locales supporting the Euro symbol -+(@acronym{ISO}-8859-15, UTF-8, and others). Similarly, a Chinese string -+ -+@example -+$ env printf '\u4e2d\u6587' -+@end example -+ -+@noindent -+will be output correctly in all Chinese locales (GB2312, BIG5, UTF-8, etc). -+ -+Note that in these examples, the @command{printf} command has been -+invoked via @command{env} to ensure that we run the program found via -+your shell's search path, and not a shell alias or a built-in function. -+ -+For larger strings, you don't need to look up the hexadecimal code -+values of each character one by one. @acronym{ASCII} characters mixed with \u -+escape sequences is also known as the JAVA source file encoding. You can -+use GNU recode 3.5c (or newer) to convert strings to this encoding. Here -+is how to convert a piece of text into a shell script which will output -+this text in a locale-independent way: -+ -+@smallexample -+$ LC_CTYPE=zh_CN.big5 /usr/local/bin/printf \ -+ '\u4e2d\u6587\n' > sample.txt -+$ recode BIG5..JAVA < sample.txt \ -+ | sed -e "s|^|/usr/local/bin/printf '|" -e "s|$|\\\\n'|" \ -+ > sample.sh -+@end smallexample -+ -+@exitstatus -+ -+ -+@node yes invocation -+@section @command{yes}: Print a string until interrupted -+ -+@pindex yes -+@cindex repeated output of a string -+ -+@command{yes} prints the command line arguments, separated by spaces and -+followed by a newline, forever until it is killed. If no arguments are -+given, it prints @samp{y} followed by a newline forever until killed. -+ -+Upon a write error, @command{yes} exits with status @samp{1}. -+ -+The only options are a lone @option{--help} or @option{--version}. -+To output an argument that begins with -+@samp{-}, precede it with @option{--}, e.g., @samp{yes -- --help}. -+@xref{Common options}. -+ -+ -+@node Conditions -+@chapter Conditions -+ -+@cindex conditions -+@cindex commands for exit status -+@cindex exit status commands -+ -+This section describes commands that are primarily useful for their exit -+status, rather than their output. Thus, they are often used as the -+condition of shell @code{if} statements, or as the last command in a -+pipeline. -+ -+@menu -+* false invocation:: Do nothing, unsuccessfully. -+* true invocation:: Do nothing, successfully. -+* test invocation:: Check file types and compare values. -+* expr invocation:: Evaluate expressions. -+@end menu -+ -+ -+@node false invocation -+@section @command{false}: Do nothing, unsuccessfully -+ -+@pindex false -+@cindex do nothing, unsuccessfully -+@cindex failure exit status -+@cindex exit status of @command{false} -+ -+@command{false} does nothing except return an exit status of 1, meaning -+@dfn{failure}. It can be used as a place holder in shell scripts -+where an unsuccessful command is needed. -+In most modern shells, @command{false} is a built-in command, so when -+you use @samp{false} in a script, you're probably using the built-in -+command, not the one documented here. -+ -+@command{false} honors the @option{--help} and @option{--version} options. -+ -+This version of @command{false} is implemented as a C program, and is thus -+more secure and faster than a shell script implementation, and may safely -+be used as a dummy shell for the purpose of disabling accounts. -+ -+Note that @command{false} (unlike all other programs documented herein) -+exits unsuccessfully, even when invoked with -+@option{--help} or @option{--version}. -+ -+Portable programs should not assume that the exit status of -+@command{false} is 1, as it is greater than 1 on some -+non-@acronym{GNU} hosts. -+ -+ -+@node true invocation -+@section @command{true}: Do nothing, successfully -+ -+@pindex true -+@cindex do nothing, successfully -+@cindex no-op -+@cindex successful exit -+@cindex exit status of @command{true} -+ -+@command{true} does nothing except return an exit status of 0, meaning -+@dfn{success}. It can be used as a place holder in shell scripts -+where a successful command is needed, although the shell built-in -+command @code{:} (colon) may do the same thing faster. -+In most modern shells, @command{true} is a built-in command, so when -+you use @samp{true} in a script, you're probably using the built-in -+command, not the one documented here. -+ -+@command{true} honors the @option{--help} and @option{--version} options. -+ -+Note, however, that it is possible to cause @command{true} -+to exit with nonzero status: with the @option{--help} or @option{--version} -+option, and with standard -+output already closed or redirected to a file that evokes an I/O error. -+For example, using a Bourne-compatible shell: -+ -+@example -+$ ./true --version >&- -+./true: write error: Bad file number -+$ ./true --version > /dev/full -+./true: write error: No space left on device -+@end example -+ -+This version of @command{true} is implemented as a C program, and is thus -+more secure and faster than a shell script implementation, and may safely -+be used as a dummy shell for the purpose of disabling accounts. -+ -+@node test invocation -+@section @command{test}: Check file types and compare values -+ -+@pindex test -+@cindex check file types -+@cindex compare values -+@cindex expression evaluation -+ -+@command{test} returns a status of 0 (true) or 1 (false) depending on the -+evaluation of the conditional expression @var{expr}. Each part of the -+expression must be a separate argument. -+ -+@command{test} has file status checks, string operators, and numeric -+comparison operators. -+ -+@command{test} has an alternate form that uses opening and closing -+square brackets instead a leading @samp{test}. For example, instead -+of @samp{test -d /}, you can write @samp{[ -d / ]}. The square -+brackets must be separate arguments; for example, @samp{[-d /]} does -+not have the desired effect. Since @samp{test @var{expr}} and @samp{[ -+@var{expr} ]} have the same meaning, only the former form is discussed -+below. -+ -+Synopses: -+ -+@example -+test @var{expression} -+test -+[ @var{expression} ] -+[ ] -+[ @var{option} -+@end example -+ -+@mayConflictWithShellBuiltIn{test} -+ -+If @var{expression} is omitted, @command{test} returns false. -+If @var{expression} is a single argument, -+@command{test} returns false if the argument is null and true otherwise. The argument -+can be any string, including strings like @samp{-d}, @samp{-1}, -+@samp{--}, @samp{--help}, and @samp{--version} that most other -+programs would treat as options. To get help and version information, -+invoke the commands @samp{[ --help} and @samp{[ --version}, without -+the usual closing brackets. @xref{Common options}. -+ -+@cindex exit status of @command{test} -+Exit status: -+ -+@display -+0 if the expression is true, -+1 if the expression is false, -+2 if an error occurred. -+@end display -+ -+@menu -+* File type tests:: -[bcdfhLpSt] -+* Access permission tests:: -[gkruwxOG] -+* File characteristic tests:: -e -s -nt -ot -ef -+* String tests:: -z -n = != -+* Numeric tests:: -eq -ne -lt -le -gt -ge -+* Connectives for test:: ! -a -o -+@end menu -+ -+ -+@node File type tests -+@subsection File type tests -+ -+@cindex file type tests -+ -+These options test for particular types of files. (Everything's a file, -+but not all files are the same!) -+ -+@table @samp -+ -+@item -b @var{file} -+@opindex -b -+@cindex block special check -+True if @var{file} exists and is a block special device. -+ -+@item -c @var{file} -+@opindex -c -+@cindex character special check -+True if @var{file} exists and is a character special device. -+ -+@item -d @var{file} -+@opindex -d -+@cindex directory check -+True if @var{file} exists and is a directory. -+ -+@item -f @var{file} -+@opindex -f -+@cindex regular file check -+True if @var{file} exists and is a regular file. -+ -+@item -h @var{file} -+@itemx -L @var{file} -+@opindex -L -+@opindex -h -+@cindex symbolic link check -+True if @var{file} exists and is a symbolic link. -+Unlike all other file-related tests, this test does not dereference -+@var{file} if it is a symbolic link. -+ -+@item -p @var{file} -+@opindex -p -+@cindex named pipe check -+True if @var{file} exists and is a named pipe. -+ -+@item -S @var{file} -+@opindex -S -+@cindex socket check -+True if @var{file} exists and is a socket. -+ -+@item -t @var{fd} -+@opindex -t -+@cindex terminal check -+True if @var{fd} is a file descriptor that is associated with a -+terminal. -+ -+@end table -+ -+ -+@node Access permission tests -+@subsection Access permission tests -+ -+@cindex access permission tests -+@cindex permission tests -+ -+These options test for particular access permissions. -+ -+@table @samp -+ -+@item -g @var{file} -+@opindex -g -+@cindex set-group-ID check -+True if @var{file} exists and has its set-group-ID bit set. -+ -+@item -k @var{file} -+@opindex -k -+@cindex sticky bit check -+True if @var{file} exists and has its @dfn{sticky} bit set. -+ -+@item -r @var{file} -+@opindex -r -+@cindex readable file check -+True if @var{file} exists and read permission is granted. -+ -+@item -u @var{file} -+@opindex -u -+@cindex set-user-ID check -+True if @var{file} exists and has its set-user-ID bit set. -+ -+@item -w @var{file} -+@opindex -w -+@cindex writable file check -+True if @var{file} exists and write permission is granted. -+ -+@item -x @var{file} -+@opindex -x -+@cindex executable file check -+True if @var{file} exists and execute permission is granted -+(or search permission, if it is a directory). -+ -+@item -O @var{file} -+@opindex -O -+@cindex owned by effective user ID check -+True if @var{file} exists and is owned by the current effective user ID. -+ -+@item -G @var{file} -+@opindex -G -+@cindex owned by effective group ID check -+True if @var{file} exists and is owned by the current effective group ID. -+ -+@end table -+ -+@node File characteristic tests -+@subsection File characteristic tests -+ -+@cindex file characteristic tests -+ -+These options test other file characteristics. -+ -+@table @samp -+ -+@item -e @var{file} -+@opindex -e -+@cindex existence-of-file check -+True if @var{file} exists. -+ -+@item -s @var{file} -+@opindex -s -+@cindex nonempty file check -+True if @var{file} exists and has a size greater than zero. -+ -+@item @var{file1} -nt @var{file2} -+@opindex -nt -+@cindex newer-than file check -+True if @var{file1} is newer (according to modification date) than -+@var{file2}, or if @var{file1} exists and @var{file2} does not. -+ -+@item @var{file1} -ot @var{file2} -+@opindex -ot -+@cindex older-than file check -+True if @var{file1} is older (according to modification date) than -+@var{file2}, or if @var{file2} exists and @var{file1} does not. -+ -+@item @var{file1} -ef @var{file2} -+@opindex -ef -+@cindex same file check -+@cindex hard link check -+True if @var{file1} and @var{file2} have the same device and inode -+numbers, i.e., if they are hard links to each other. -+ -+@end table -+ -+ -+@node String tests -+@subsection String tests -+ -+@cindex string tests -+ -+These options test string characteristics. You may need to quote -+@var{string} arguments for the shell. For example: -+ -+@example -+test -n "$V" -+@end example -+ -+The quotes here prevent the wrong arguments from being passed to -+@command{test} if @samp{$V} is empty or contains special characters. -+ -+@table @samp -+ -+@item -z @var{string} -+@opindex -z -+@cindex zero-length string check -+True if the length of @var{string} is zero. -+ -+@item -n @var{string} -+@itemx @var{string} -+@opindex -n -+@cindex nonzero-length string check -+True if the length of @var{string} is nonzero. -+ -+@item @var{string1} = @var{string2} -+@opindex = -+@cindex equal string check -+True if the strings are equal. -+ -+@item @var{string1} != @var{string2} -+@opindex != -+@cindex not-equal string check -+True if the strings are not equal. -+ -+@end table -+ -+ -+@node Numeric tests -+@subsection Numeric tests -+ -+@cindex numeric tests -+@cindex arithmetic tests -+ -+Numeric relational operators. The arguments must be entirely numeric -+(possibly negative), or the special expression @w{@code{-l @var{string}}}, -+which evaluates to the length of @var{string}. -+ -+@table @samp -+ -+@item @var{arg1} -eq @var{arg2} -+@itemx @var{arg1} -ne @var{arg2} -+@itemx @var{arg1} -lt @var{arg2} -+@itemx @var{arg1} -le @var{arg2} -+@itemx @var{arg1} -gt @var{arg2} -+@itemx @var{arg1} -ge @var{arg2} -+@opindex -eq -+@opindex -ne -+@opindex -lt -+@opindex -le -+@opindex -gt -+@opindex -ge -+These arithmetic binary operators return true if @var{arg1} is equal, -+not-equal, less-than, less-than-or-equal, greater-than, or -+greater-than-or-equal than @var{arg2}, respectively. -+ -+@end table -+ -+For example: -+ -+@example -+test -1 -gt -2 && echo yes -+@result{} yes -+test -l abc -gt 1 && echo yes -+@result{} yes -+test 0x100 -eq 1 -+@error{} test: integer expression expected before -eq -+@end example -+ -+ -+@node Connectives for test -+@subsection Connectives for @command{test} -+ -+@cindex logical connectives -+@cindex connectives, logical -+ -+The usual logical connectives. -+ -+@table @samp -+ -+@item ! @var{expr} -+@opindex ! -+True if @var{expr} is false. -+ -+@item @var{expr1} -a @var{expr2} -+@opindex -a -+@cindex logical and operator -+@cindex and operator -+True if both @var{expr1} and @var{expr2} are true. -+ -+@item @var{expr1} -o @var{expr2} -+@opindex -o -+@cindex logical or operator -+@cindex or operator -+True if either @var{expr1} or @var{expr2} is true. -+ -+@end table -+ -+ -+@node expr invocation -+@section @command{expr}: Evaluate expressions -+ -+@pindex expr -+@cindex expression evaluation -+@cindex evaluation of expressions -+ -+@command{expr} evaluates an expression and writes the result on standard -+output. Each token of the expression must be a separate argument. -+ -+Operands are either integers or strings. Integers consist of one or -+more decimal digits, with an optional leading @samp{-}. -+@command{expr} converts -+anything appearing in an operand position to an integer or a string -+depending on the operation being applied to it. -+ -+Strings are not quoted for @command{expr} itself, though you may need to -+quote them to protect characters with special meaning to the shell, -+e.g., spaces. However, regardless of whether it is quoted, a string -+operand should not be a parenthesis or any of @command{expr}'s -+operators like @code{+}, so you cannot safely pass an arbitrary string -+@code{$str} to expr merely by quoting it to the shell. One way to -+work around this is to use the @sc{gnu} extension @code{+}, -+(e.g., @code{+ "$str" = foo}); a more portable way is to use -+@code{@w{" $str"}} and to adjust the rest of the expression to take -+the leading space into account (e.g., @code{@w{" $str" = " foo"}}). -+ -+You should not pass a negative integer or a string with leading -+@samp{-} as @command{expr}'s first argument, as it might be -+misinterpreted as an option; this can be avoided by parenthesization. -+Also, portable scripts should not use a string operand that happens to -+take the form of an integer; this can be worked around by inserting -+leading spaces as mentioned above. -+ -+@cindex parentheses for grouping -+Operators may be given as infix symbols or prefix keywords. Parentheses -+may be used for grouping in the usual manner. You must quote -+parentheses and many operators to avoid the shell evaluating them, -+however. -+ -+When built with support for the GNU MP library, @command{expr} uses -+arbitrary-precision arithmetic; otherwise, it uses native arithmetic -+types and may fail due to arithmetic overflow. -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. Options must precede operands. -+ -+@cindex exit status of @command{expr} -+Exit status: -+ -+@display -+0 if the expression is neither null nor 0, -+1 if the expression is null or 0, -+2 if the expression is invalid, -+3 if an internal error occurred (e.g., arithmetic overflow). -+@end display -+ -+@menu -+* String expressions:: + : match substr index length -+* Numeric expressions:: + - * / % -+* Relations for expr:: | & < <= = == != >= > -+* Examples of expr:: Examples. -+@end menu -+ -+ -+@node String expressions -+@subsection String expressions -+ -+@cindex string expressions -+@cindex expressions, string -+ -+@command{expr} supports pattern matching and other string operators. These -+have higher precedence than both the numeric and relational operators (in -+the next sections). -+ -+@table @samp -+ -+@item @var{string} : @var{regex} -+@cindex pattern matching -+@cindex regular expression matching -+@cindex matching patterns -+Perform pattern matching. The arguments are converted to strings and the -+second is considered to be a (basic, a la GNU @code{grep}) regular -+expression, with a @code{^} implicitly prepended. The first argument is -+then matched against this regular expression. -+ -+If the match succeeds and @var{regex} uses @samp{\(} and @samp{\)}, the -+@code{:} expression returns the part of @var{string} that matched the -+subexpression; otherwise, it returns the number of characters matched. -+ -+If the match fails, the @code{:} operator returns the null string if -+@samp{\(} and @samp{\)} are used in @var{regex}, otherwise 0. -+ -+@kindex \( @r{regexp operator} -+Only the first @samp{\( @dots{} \)} pair is relevant to the return -+value; additional pairs are meaningful only for grouping the regular -+expression operators. -+ -+@kindex \+ @r{regexp operator} -+@kindex \? @r{regexp operator} -+@kindex \| @r{regexp operator} -+In the regular expression, @code{\+}, @code{\?}, and @code{\|} are -+operators which respectively match one or more, zero or one, or separate -+alternatives. SunOS and other @command{expr}'s treat these as regular -+characters. (@acronym{POSIX} allows either behavior.) -+@xref{Top, , Regular Expression Library, regex, Regex}, for details of -+regular expression syntax. Some examples are in @ref{Examples of expr}. -+ -+@item match @var{string} @var{regex} -+@findex match -+An alternative way to do pattern matching. This is the same as -+@w{@samp{@var{string} : @var{regex}}}. -+ -+@item substr @var{string} @var{position} @var{length} -+@findex substr -+Returns the substring of @var{string} beginning at @var{position} -+with length at most @var{length}. If either @var{position} or -+@var{length} is negative, zero, or non-numeric, returns the null string. -+ -+@item index @var{string} @var{charset} -+@findex index -+Returns the first position in @var{string} where the first character in -+@var{charset} was found. If no character in @var{charset} is found in -+@var{string}, return 0. -+ -+@item length @var{string} -+@findex length -+Returns the length of @var{string}. -+ -+@item + @var{token} -+@kindex + -+Interpret @var{token} as a string, even if it is a keyword like @var{match} -+or an operator like @code{/}. -+This makes it possible to test @code{expr length + "$x"} or -+@code{expr + "$x" : '.*/\(.\)'} and have it do the right thing even if -+the value of @var{$x} happens to be (for example) @code{/} or @code{index}. -+This operator is a @acronym{GNU} extension. Portable shell scripts should use -+@code{@w{" $token"} : @w{' \(.*\)'}} instead of @code{+ "$token"}. -+ -+@end table -+ -+To make @command{expr} interpret keywords as strings, you must use the -+@code{quote} operator. -+ -+ -+@node Numeric expressions -+@subsection Numeric expressions -+ -+@cindex numeric expressions -+@cindex expressions, numeric -+ -+@command{expr} supports the usual numeric operators, in order of increasing -+precedence. These numeric operators have lower precedence than the -+string operators described in the previous section, and higher precedence -+than the connectives (next section). -+ -+@table @samp -+ -+@item + - -+@kindex + -+@kindex - -+@cindex addition -+@cindex subtraction -+Addition and subtraction. Both arguments are converted to integers; -+an error occurs if this cannot be done. -+ -+@item * / % -+@kindex * -+@kindex / -+@kindex % -+@cindex multiplication -+@cindex division -+@cindex remainder -+Multiplication, division, remainder. Both arguments are converted to -+integers; an error occurs if this cannot be done. -+ -+@end table -+ -+ -+@node Relations for expr -+@subsection Relations for @command{expr} -+ -+@cindex connectives, logical -+@cindex logical connectives -+@cindex relations, numeric or string -+ -+@command{expr} supports the usual logical connectives and relations. These -+have lower precedence than the string and numeric operators -+(previous sections). Here is the list, lowest-precedence operator first. -+ -+@table @samp -+ -+@item | -+@kindex | -+@cindex logical or operator -+@cindex or operator -+Returns its first argument if that is neither null nor zero, otherwise -+its second argument if it is neither null nor zero, otherwise 0. It -+does not evaluate its second argument if its first argument is neither -+null nor zero. -+ -+@item & -+@kindex & -+@cindex logical and operator -+@cindex and operator -+Return its first argument if neither argument is null or zero, otherwise -+0. It does not evaluate its second argument if its first argument is -+null or zero. -+ -+@item < <= = == != >= > -+@kindex < -+@kindex <= -+@kindex = -+@kindex == -+@kindex > -+@kindex >= -+@cindex comparison operators -+@vindex LC_COLLATE -+Compare the arguments and return 1 if the relation is true, 0 otherwise. -+@code{==} is a synonym for @code{=}. @command{expr} first tries to convert -+both arguments to integers and do a numeric comparison; if either -+conversion fails, it does a lexicographic comparison using the character -+collating sequence specified by the @env{LC_COLLATE} locale. -+ -+@end table -+ -+ -+@node Examples of expr -+@subsection Examples of using @command{expr} -+ -+@cindex examples of @command{expr} -+Here are a few examples, including quoting for shell metacharacters. -+ -+To add 1 to the shell variable @code{foo}, in Bourne-compatible shells: -+ -+@example -+foo=`expr $foo + 1` -+@end example -+ -+To print the non-directory part of the file name stored in -+@code{$fname}, which need not contain a @code{/}: -+ -+@example -+expr $fname : '.*/\(.*\)' '|' $fname -+@end example -+ -+An example showing that @code{\+} is an operator: -+ -+@example -+expr aaa : 'a\+' -+@result{} 3 -+@end example -+ -+@example -+expr abc : 'a\(.\)c' -+@result{} b -+expr index abcdef cz -+@result{} 3 -+expr index index a -+@error{} expr: syntax error -+expr index + index a -+@result{} 0 -+@end example -+ -+ -+@node Redirection -+@chapter Redirection -+ -+@cindex redirection -+@cindex commands for redirection -+ -+Unix shells commonly provide several forms of @dfn{redirection}---ways -+to change the input source or output destination of a command. But one -+useful redirection is performed by a separate command, not by the shell; -+it's described here. -+ -+@menu -+* tee invocation:: Redirect output to multiple files or processes. -+@end menu -+ -+ -+@node tee invocation -+@section @command{tee}: Redirect output to multiple files or processes -+ -+@pindex tee -+@cindex pipe fitting -+@cindex destinations, multiple output -+@cindex read from stdin and write to stdout and files -+ -+The @command{tee} command copies standard input to standard output and also -+to any files given as arguments. This is useful when you want not only -+to send some data down a pipe, but also to save a copy. Synopsis: -+ -+@example -+tee [@var{option}]@dots{} [@var{file}]@dots{} -+@end example -+ -+If a file being written to does not already exist, it is created. If a -+file being written to already exists, the data it previously contained -+is overwritten unless the @option{-a} option is used. -+ -+A @var{file} of @samp{-} causes @command{tee} to send another copy of -+input to standard output, but this is typically not that useful as the -+copies are interleaved. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+@item -a -+@itemx --append -+@opindex -a -+@opindex --append -+Append standard input to the given files rather than overwriting -+them. -+ -+@item -i -+@itemx --ignore-interrupts -+@opindex -i -+@opindex --ignore-interrupts -+Ignore interrupt signals. -+ -+@end table -+ -+The @command{tee} command is useful when you happen to be transferring a large -+amount of data and also want to summarize that data without reading -+it a second time. For example, when you are downloading a DVD image, -+you often want to verify its signature or checksum right away. -+The inefficient way to do it is simply: -+ -+@example -+wget http://example.com/some.iso && sha1sum some.iso -+@end example -+ -+One problem with the above is that it makes you wait for the -+download to complete before starting the time-consuming SHA1 computation. -+Perhaps even more importantly, the above requires reading -+the DVD image a second time (the first was from the network). -+ -+The efficient way to do it is to interleave the download -+and SHA1 computation. Then, you'll get the checksum for -+free, because the entire process parallelizes so well: -+ -+@example -+# slightly contrived, to demonstrate process substitution -+wget -O - http://example.com/dvd.iso \ -+ | tee >(sha1sum > dvd.sha1) > dvd.iso -+@end example -+ -+That makes @command{tee} write not just to the expected output file, -+but also to a pipe running @command{sha1sum} and saving the final -+checksum in a file named @file{dvd.sha1}. -+ -+Note, however, that this example relies on a feature of modern shells -+called @dfn{process substitution} -+(the @samp{>(command)} syntax, above; -+@xref{Process Substitution,,Process Substitution, bashref, -+The Bash Reference Manual}.), -+so it works with @command{zsh}, @command{bash}, and @command{ksh}, -+but not with @command{/bin/sh}. So if you write code like this -+in a shell script, be sure to start the script with @samp{#!/bin/bash}. -+ -+Since the above example writes to one file and one process, -+a more conventional and portable use of @command{tee} is even better: -+ -+@example -+wget -O - http://example.com/dvd.iso \ -+ | tee dvd.iso | sha1sum > dvd.sha1 -+@end example -+ -+You can extend this example to make @command{tee} write to two processes, -+computing MD5 and SHA1 checksums in parallel. In this case, -+process substitution is required: -+ -+@example -+wget -O - http://example.com/dvd.iso \ -+ | tee >(sha1sum > dvd.sha1) \ -+ >(md5sum > dvd.md5) \ -+ > dvd.iso -+@end example -+ -+This technique is also useful when you want to make a @emph{compressed} -+copy of the contents of a pipe. -+Consider a tool to graphically summarize disk usage data from @samp{du -ak}. -+For a large hierarchy, @samp{du -ak} can run for a long time, -+and can easily produce terabytes of data, so you won't want to -+rerun the command unnecessarily. Nor will you want to save -+the uncompressed output. -+ -+Doing it the inefficient way, you can't even start the GUI -+until after you've compressed all of the @command{du} output: -+ -+@example -+du -ak | gzip -9 > /tmp/du.gz -+gzip -d /tmp/du.gz | xdiskusage -a -+@end example -+ -+With @command{tee} and process substitution, you start the GUI -+right away and eliminate the decompression completely: -+ -+@example -+du -ak | tee >(gzip -9 > /tmp/du.gz) | xdiskusage -a -+@end example -+ -+Finally, if you regularly create more than one type of -+compressed tarball at once, for example when @code{make dist} creates -+both @command{gzip}-compressed and @command{bzip2}-compressed tarballs, -+there may be a better way. -+Typical @command{automake}-generated @file{Makefile} rules create -+the two compressed tar archives with commands in sequence, like this -+(slightly simplified): -+ -+@example -+tardir=your-pkg-M.N -+tar chof - "$tardir" | gzip -9 -c > your-pkg-M.N.tar.gz -+tar chof - "$tardir" | bzip2 -9 -c > your-pkg-M.N.tar.bz2 -+@end example -+ -+However, if the hierarchy you are archiving and compressing is larger -+than a couple megabytes, and especially if you are using a multi-processor -+system with plenty of memory, then you can do much better by reading the -+directory contents only once and running the compression programs in parallel: -+ -+@example -+tardir=your-pkg-M.N -+tar chof - "$tardir" \ -+ | tee >(gzip -9 -c > your-pkg-M.N.tar.gz) \ -+ | bzip2 -9 -c > your-pkg-M.N.tar.bz2 -+@end example -+ -+@exitstatus -+ -+ -+@node File name manipulation -+@chapter File name manipulation -+ -+@cindex file name manipulation -+@cindex manipulation of file names -+@cindex commands for file name manipulation -+ -+This section describes commands that manipulate file names. -+ -+@menu -+* basename invocation:: Strip directory and suffix from a file name. -+* dirname invocation:: Strip non-directory suffix from a file name. -+* pathchk invocation:: Check file name validity and portability. -+@end menu -+ -+ -+@node basename invocation -+@section @command{basename}: Strip directory and suffix from a file name -+ -+@pindex basename -+@cindex strip directory and suffix from file names -+@cindex directory, stripping from file names -+@cindex suffix, stripping from file names -+@cindex file names, stripping directory and suffix -+@cindex leading directory components, stripping -+ -+@command{basename} removes any leading directory components from -+@var{name}. Synopsis: -+ -+@example -+basename @var{name} [@var{suffix}] -+@end example -+ -+If @var{suffix} is specified and is identical to the end of @var{name}, -+it is removed from @var{name} as well. Note that since trailing slashes -+are removed prior to suffix matching, @var{suffix} will do nothing if it -+contains slashes. @command{basename} prints the result on standard -+output. -+ -+@c This test is used both here and in the section on dirname. -+@macro basenameAndDirname -+Together, @command{basename} and @command{dirname} are designed such -+that if @samp{ls "$name"} succeeds, then the command sequence @samp{cd -+"$(dirname "$name")"; ls "$(basename "$name")"} will, too. This works -+for everything except file names containing a trailing newline. -+@end macro -+@basenameAndDirname -+ -+@acronym{POSIX} allows the implementation to define the results if -+@var{name} is empty or @samp{//}. In the former case, @acronym{GNU} -+@command{basename} returns the empty string. In the latter case, the -+result is @samp{//} on platforms where @var{//} is distinct from -+@var{/}, and @samp{/} on platforms where there is no difference. -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. Options must precede operands. -+ -+@exitstatus -+ -+Examples: -+ -+@smallexample -+# Output "sort". -+basename /usr/bin/sort -+ -+# Output "stdio". -+basename include/stdio.h .h -+@end smallexample -+ -+ -+@node dirname invocation -+@section @command{dirname}: Strip non-directory suffix from a file name -+ -+@pindex dirname -+@cindex directory components, printing -+@cindex stripping non-directory suffix -+@cindex non-directory suffix, stripping -+ -+@command{dirname} prints all but the final slash-delimited component of -+a string (presumably a file name). Synopsis: -+ -+@example -+dirname @var{name} -+@end example -+ -+If @var{name} is a single component, @command{dirname} prints @samp{.} -+(meaning the current directory). -+ -+@basenameAndDirname -+ -+@acronym{POSIX} allows the implementation to define the results if -+@var{name} is @samp{//}. With @acronym{GNU} @command{dirname}, the -+result is @samp{//} on platforms where @var{//} is distinct from -+@var{/}, and @samp{/} on platforms where there is no difference. -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. -+ -+@exitstatus -+ -+Examples: -+ -+@smallexample -+# Output "/usr/bin". -+dirname /usr/bin/sort -+ -+# Output ".". -+dirname stdio.h -+@end smallexample -+ -+ -+@node pathchk invocation -+@section @command{pathchk}: Check file name validity and portability -+ -+@pindex pathchk -+@cindex file names, checking validity and portability -+@cindex valid file names, checking for -+@cindex portable file names, checking for -+ -+@command{pathchk} checks validity and portability of file names. Synopsis: -+ -+@example -+pathchk [@var{option}]@dots{} @var{name}@dots{} -+@end example -+ -+For each @var{name}, @command{pathchk} prints an error message if any of -+these conditions is true: -+ -+@enumerate -+@item -+One of the existing directories in @var{name} does not have search -+(execute) permission, -+@item -+The length of @var{name} is larger than the maximum supported by the -+operating system. -+@item -+The length of one component of @var{name} is longer than -+its file system's maximum. -+@end enumerate -+ -+A nonexistent @var{name} is not an error, so long a file with that -+name could be created under the above conditions. -+ -+The program accepts the following options. Also see @ref{Common options}. -+Options must precede operands. -+ -+@table @samp -+ -+@item -p -+@opindex -p -+Instead of performing checks based on the underlying file system, -+print an error message if any of these conditions is true: -+ -+@enumerate -+@item -+A file name is empty. -+ -+@item -+A file name contains a character outside the @acronym{POSIX} portable file -+name character set, namely, the ASCII letters and digits, @samp{.}, -+@samp{_}, @samp{-}, and @samp{/}. -+ -+@item -+The length of a file name or one of its components exceeds the -+@acronym{POSIX} minimum limits for portability. -+@end enumerate -+ -+@item -P -+@opindex -P -+Print an error message if a file name is empty, or if it contains a component -+that begins with @samp{-}. -+ -+@item --portability -+@opindex --portability -+Print an error message if a file name is not portable to all @acronym{POSIX} -+hosts. This option is equivalent to @samp{-p -P}. -+ -+@end table -+ -+@cindex exit status of @command{pathchk} -+Exit status: -+ -+@display -+0 if all specified file names passed all checks, -+1 otherwise. -+@end display -+ -+ -+@node Working context -+@chapter Working context -+ -+@cindex working context -+@cindex commands for printing the working context -+ -+This section describes commands that display or alter the context in -+which you are working: the current directory, the terminal settings, and -+so forth. See also the user-related commands in the next section. -+ -+@menu -+* pwd invocation:: Print working directory. -+* stty invocation:: Print or change terminal characteristics. -+* printenv invocation:: Print environment variables. -+* tty invocation:: Print file name of terminal on standard input. -+@end menu -+ -+ -+@node pwd invocation -+@section @command{pwd}: Print working directory -+ -+@pindex pwd -+@cindex print name of current directory -+@cindex current working directory, printing -+@cindex working directory, printing -+ -+ -+@command{pwd} prints the name of the current directory. Synopsis: -+ -+@example -+pwd [@var{option}]@dots{} -+@end example -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+@item -L -+@itemx --logical -+@opindex -L -+@opindex --logical -+If the contents of the environment variable @env{PWD} provide an -+absolute name of the current directory with no @samp{.} or @samp{..} -+components, but possibly with symbolic links, then output those -+contents. Otherwise, fall back to default @option{-P} handling. -+ -+@item -P -+@itemx --physical -+@opindex -P -+@opindex --physical -+Print a fully resolved name for the current directory. That is, all -+components of the printed name will be actual directory names---none -+will be symbolic links. -+@end table -+ -+@cindex symbolic links and @command{pwd} -+If @option{-L} and @option{-P} are both given, the last one takes -+precedence. If neither option is given, then this implementation uses -+@option{-P} as the default unless the @env{POSIXLY_CORRECT} -+environment variable is set. -+ -+@mayConflictWithShellBuiltIn{pwd} -+ -+@exitstatus -+ -+ -+@node stty invocation -+@section @command{stty}: Print or change terminal characteristics -+ -+@pindex stty -+@cindex change or print terminal settings -+@cindex terminal settings -+@cindex line settings of terminal -+ -+@command{stty} prints or changes terminal characteristics, such as baud rate. -+Synopses: -+ -+@example -+stty [@var{option}] [@var{setting}]@dots{} -+stty [@var{option}] -+@end example -+ -+If given no line settings, @command{stty} prints the baud rate, line -+discipline number (on systems that support it), and line settings -+that have been changed from the values set by @samp{stty sane}. -+By default, mode reading and setting are performed on the tty line -+connected to standard input, although this can be modified by the -+@option{--file} option. -+ -+@command{stty} accepts many non-option arguments that change aspects of -+the terminal line operation, as described below. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+@item -a -+@itemx --all -+@opindex -a -+@opindex --all -+Print all current settings in human-readable form. This option may not -+be used in combination with any line settings. -+ -+@item -F @var{device} -+@itemx --file=@var{device} -+@opindex -F -+@opindex --file -+Set the line opened by the file name specified in @var{device} instead of -+the tty line connected to standard input. This option is necessary -+because opening a @acronym{POSIX} tty requires use of the @code{O_NONDELAY} flag to -+prevent a @acronym{POSIX} tty from blocking until the carrier detect line is high if -+the @code{clocal} flag is not set. Hence, it is not always possible -+to allow the shell to open the device in the traditional manner. -+ -+@item -g -+@itemx --save -+@opindex -g -+@opindex --save -+@cindex machine-readable @command{stty} output -+Print all current settings in a form that can be used as an argument to -+another @command{stty} command to restore the current settings. This option -+may not be used in combination with any line settings. -+ -+@end table -+ -+Many settings can be turned off by preceding them with a @samp{-}. -+Such arguments are marked below with ``May be negated'' in their -+description. The descriptions themselves refer to the positive -+case, that is, when @emph{not} negated (unless stated otherwise, -+of course). -+ -+Some settings are not available on all @acronym{POSIX} systems, since they use -+extensions. Such arguments are marked below with ``Non-@acronym{POSIX}'' in their -+description. On non-@acronym{POSIX} systems, those or other settings also may not -+be available, but it's not feasible to document all the variations: just -+try it and see. -+ -+@exitstatus -+ -+@menu -+* Control:: Control settings -+* Input:: Input settings -+* Output:: Output settings -+* Local:: Local settings -+* Combination:: Combination settings -+* Characters:: Special characters -+* Special:: Special settings -+@end menu -+ -+ -+@node Control -+@subsection Control settings -+ -+@cindex control settings -+Control settings: -+ -+@table @samp -+@item parenb -+@opindex parenb -+@cindex two-way parity -+Generate parity bit in output and expect parity bit in input. -+May be negated. -+ -+@item parodd -+@opindex parodd -+@cindex odd parity -+@cindex even parity -+Set odd parity (even if negated). May be negated. -+ -+@item cs5 -+@itemx cs6 -+@itemx cs7 -+@itemx cs8 -+@opindex cs@var{n} -+@cindex character size -+@cindex eight-bit characters -+Set character size to 5, 6, 7, or 8 bits. -+ -+@item hup -+@itemx hupcl -+@opindex hup[cl] -+Send a hangup signal when the last process closes the tty. May be -+negated. -+ -+@item cstopb -+@opindex cstopb -+@cindex stop bits -+Use two stop bits per character (one if negated). May be negated. -+ -+@item cread -+@opindex cread -+Allow input to be received. May be negated. -+ -+@item clocal -+@opindex clocal -+@cindex modem control -+Disable modem control signals. May be negated. -+ -+@item crtscts -+@opindex crtscts -+@cindex hardware flow control -+@cindex flow control, hardware -+@cindex RTS/CTS flow control -+Enable RTS/CTS flow control. Non-@acronym{POSIX}. May be negated. -+@end table -+ -+ -+@node Input -+@subsection Input settings -+ -+@cindex input settings -+These settings control operations on data received from the terminal. -+ -+@table @samp -+@item ignbrk -+@opindex ignbrk -+@cindex breaks, ignoring -+Ignore break characters. May be negated. -+ -+@item brkint -+@opindex brkint -+@cindex breaks, cause interrupts -+Make breaks cause an interrupt signal. May be negated. -+ -+@item ignpar -+@opindex ignpar -+@cindex parity, ignoring -+Ignore characters with parity errors. May be negated. -+ -+@item parmrk -+@opindex parmrk -+@cindex parity errors, marking -+Mark parity errors (with a 255-0-character sequence). May be negated. -+ -+@item inpck -+@opindex inpck -+Enable input parity checking. May be negated. -+ -+@item istrip -+@opindex istrip -+@cindex eight-bit input -+Clear high (8th) bit of input characters. May be negated. -+ -+@item inlcr -+@opindex inlcr -+@cindex newline, translating to return -+Translate newline to carriage return. May be negated. -+ -+@item igncr -+@opindex igncr -+@cindex return, ignoring -+Ignore carriage return. May be negated. -+ -+@item icrnl -+@opindex icrnl -+@cindex return, translating to newline -+Translate carriage return to newline. May be negated. -+ -+@item iutf8 -+@opindex iutf8 -+@cindex input encoding, UTF-8 -+Assume input characters are UTF-8 encoded. May be negated. -+ -+@item ixon -+@opindex ixon -+@kindex C-s/C-q flow control -+@cindex XON/XOFF flow control -+Enable XON/XOFF flow control (that is, @kbd{CTRL-S}/@kbd{CTRL-Q}). May -+be negated. -+ -+@item ixoff -+@itemx tandem -+@opindex ixoff -+@opindex tandem -+@cindex software flow control -+@cindex flow control, software -+Enable sending of @code{stop} character when the system input buffer -+is almost full, and @code{start} character when it becomes almost -+empty again. May be negated. -+ -+@item iuclc -+@opindex iuclc -+@cindex uppercase, translating to lowercase -+Translate uppercase characters to lowercase. Non-@acronym{POSIX}. May be -+negated. Note ilcuc is not implemented, as one would not be able to issue -+almost any (lowercase) Unix command, after invoking it. -+ -+@item ixany -+@opindex ixany -+Allow any character to restart output (only the start character -+if negated). Non-@acronym{POSIX}. May be negated. -+ -+@item imaxbel -+@opindex imaxbel -+@cindex beeping at input buffer full -+Enable beeping and not flushing input buffer if a character arrives -+when the input buffer is full. Non-@acronym{POSIX}. May be negated. -+@end table -+ -+ -+@node Output -+@subsection Output settings -+ -+@cindex output settings -+These settings control operations on data sent to the terminal. -+ -+@table @samp -+@item opost -+@opindex opost -+Postprocess output. May be negated. -+ -+@item olcuc -+@opindex olcuc -+@cindex lowercase, translating to output -+Translate lowercase characters to uppercase. Non-@acronym{POSIX}. May be -+negated. (Note ouclc is not currently implemented.) -+ -+@item ocrnl -+@opindex ocrnl -+@cindex return, translating to newline -+Translate carriage return to newline. Non-@acronym{POSIX}. May be negated. -+ -+@item onlcr -+@opindex onlcr -+@cindex newline, translating to crlf -+Translate newline to carriage return-newline. Non-@acronym{POSIX}. May be -+negated. -+ -+@item onocr -+@opindex onocr -+Do not print carriage returns in the first column. Non-@acronym{POSIX}. -+May be negated. -+ -+@item onlret -+@opindex onlret -+Newline performs a carriage return. Non-@acronym{POSIX}. May be negated. -+ -+@item ofill -+@opindex ofill -+@cindex pad instead of timing for delaying -+Use fill (padding) characters instead of timing for delays. Non-@acronym{POSIX}. -+May be negated. -+ -+@item ofdel -+@opindex ofdel -+@cindex pad character -+Use @acronym{ASCII} @sc{del} characters for fill instead of -+@acronym{ASCII} @sc{nul} characters. Non-@acronym{POSIX}. -+May be negated. -+ -+@item nl1 -+@itemx nl0 -+@opindex nl@var{n} -+Newline delay style. Non-@acronym{POSIX}. -+ -+@item cr3 -+@itemx cr2 -+@itemx cr1 -+@itemx cr0 -+@opindex cr@var{n} -+Carriage return delay style. Non-@acronym{POSIX}. -+ -+@item tab3 -+@itemx tab2 -+@itemx tab1 -+@itemx tab0 -+@opindex tab@var{n} -+Horizontal tab delay style. Non-@acronym{POSIX}. -+ -+@item bs1 -+@itemx bs0 -+@opindex bs@var{n} -+Backspace delay style. Non-@acronym{POSIX}. -+ -+@item vt1 -+@itemx vt0 -+@opindex vt@var{n} -+Vertical tab delay style. Non-@acronym{POSIX}. -+ -+@item ff1 -+@itemx ff0 -+@opindex ff@var{n} -+Form feed delay style. Non-@acronym{POSIX}. -+@end table -+ -+ -+@node Local -+@subsection Local settings -+ -+@cindex local settings -+ -+@table @samp -+@item isig -+@opindex isig -+Enable @code{interrupt}, @code{quit}, and @code{suspend} special -+characters. May be negated. -+ -+@item icanon -+@opindex icanon -+Enable @code{erase}, @code{kill}, @code{werase}, and @code{rprnt} -+special characters. May be negated. -+ -+@item iexten -+@opindex iexten -+Enable non-@acronym{POSIX} special characters. May be negated. -+ -+@item echo -+@opindex echo -+Echo input characters. May be negated. -+ -+@item echoe -+@itemx crterase -+@opindex echoe -+@opindex crterase -+Echo @code{erase} characters as backspace-space-backspace. May be -+negated. -+ -+@item echok -+@opindex echok -+@cindex newline echoing after @code{kill} -+Echo a newline after a @code{kill} character. May be negated. -+ -+@item echonl -+@opindex echonl -+@cindex newline, echoing -+Echo newline even if not echoing other characters. May be negated. -+ -+@item noflsh -+@opindex noflsh -+@cindex flushing, disabling -+Disable flushing after @code{interrupt} and @code{quit} special -+characters. May be negated. -+ -+@item xcase -+@opindex xcase -+@cindex case translation -+Enable input and output of uppercase characters by preceding their -+lowercase equivalents with @samp{\}, when @code{icanon} is set. -+Non-@acronym{POSIX}. May be negated. -+ -+@item tostop -+@opindex tostop -+@cindex background jobs, stopping at terminal write -+Stop background jobs that try to write to the terminal. Non-@acronym{POSIX}. -+May be negated. -+ -+@item echoprt -+@itemx prterase -+@opindex echoprt -+@opindex prterase -+Echo erased characters backward, between @samp{\} and @samp{/}. -+Non-@acronym{POSIX}. May be negated. -+ -+@item echoctl -+@itemx ctlecho -+@opindex echoctl -+@opindex ctlecho -+@cindex control characters, using @samp{^@var{c}} -+@cindex hat notation for control characters -+Echo control characters in hat notation (@samp{^@var{c}}) instead -+of literally. Non-@acronym{POSIX}. May be negated. -+ -+@item echoke -+@itemx crtkill -+@opindex echoke -+@opindex crtkill -+Echo the @code{kill} special character by erasing each character on -+the line as indicated by the @code{echoprt} and @code{echoe} settings, -+instead of by the @code{echoctl} and @code{echok} settings. Non-@acronym{POSIX}. -+May be negated. -+@end table -+ -+ -+@node Combination -+@subsection Combination settings -+ -+@cindex combination settings -+Combination settings: -+ -+@table @samp -+@item evenp -+@opindex evenp -+@itemx parity -+@opindex parity -+Same as @code{parenb -parodd cs7}. May be negated. If negated, same -+as @code{-parenb cs8}. -+ -+@item oddp -+@opindex oddp -+Same as @code{parenb parodd cs7}. May be negated. If negated, same -+as @code{-parenb cs8}. -+ -+@item nl -+@opindex nl -+Same as @code{-icrnl -onlcr}. May be negated. If negated, same as -+@code{icrnl -inlcr -igncr onlcr -ocrnl -onlret}. -+ -+@item ek -+@opindex ek -+Reset the @code{erase} and @code{kill} special characters to their default -+values. -+ -+@item sane -+@opindex sane -+Same as: -+ -+@c This is too long to write inline. -+@example -+cread -ignbrk brkint -inlcr -igncr icrnl -ixoff -+-iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr -+-onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 -+ff0 isig icanon iexten echo echoe echok -echonl -+-noflsh -xcase -tostop -echoprt echoctl echoke -+@end example -+ -+@noindent -+and also sets all special characters to their default values. -+ -+@item cooked -+@opindex cooked -+Same as @code{brkint ignpar istrip icrnl ixon opost isig icanon}, plus -+sets the @code{eof} and @code{eol} characters to their default values -+if they are the same as the @code{min} and @code{time} characters. -+May be negated. If negated, same as @code{raw}. -+ -+@item raw -+@opindex raw -+Same as: -+ -+@example -+-ignbrk -brkint -ignpar -parmrk -inpck -istrip -+-inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -+-imaxbel -opost -isig -icanon -xcase min 1 time 0 -+@end example -+ -+@noindent -+May be negated. If negated, same as @code{cooked}. -+ -+@item cbreak -+@opindex cbreak -+Same as @option{-icanon}. May be negated. If negated, same as -+@code{icanon}. -+ -+@item pass8 -+@opindex pass8 -+@cindex eight-bit characters -+Same as @code{-parenb -istrip cs8}. May be negated. If negated, -+same as @code{parenb istrip cs7}. -+ -+@item litout -+@opindex litout -+Same as @option{-parenb -istrip -opost cs8}. May be negated. -+If negated, same as @code{parenb istrip opost cs7}. -+ -+@item decctlq -+@opindex decctlq -+Same as @option{-ixany}. Non-@acronym{POSIX}. May be negated. -+ -+@item tabs -+@opindex tabs -+Same as @code{tab0}. Non-@acronym{POSIX}. May be negated. If negated, same -+as @code{tab3}. -+ -+@item lcase -+@itemx LCASE -+@opindex lcase -+@opindex LCASE -+Same as @code{xcase iuclc olcuc}. Non-@acronym{POSIX}. May be negated. -+(Used for terminals with uppercase characters only.) -+ -+@item crt -+@opindex crt -+Same as @code{echoe echoctl echoke}. -+ -+@item dec -+@opindex dec -+Same as @code{echoe echoctl echoke -ixany intr ^C erase ^? kill C-u}. -+@end table -+ -+ -+@node Characters -+@subsection Special characters -+ -+@cindex special characters -+@cindex characters, special -+ -+The special characters' default values vary from system to system. -+They are set with the syntax @samp{name value}, where the names are -+listed below and the value can be given either literally, in hat -+notation (@samp{^@var{c}}), or as an integer which may start with -+@samp{0x} to indicate hexadecimal, @samp{0} to indicate octal, or -+any other digit to indicate decimal. -+ -+@cindex disabling special characters -+@kindex u@r{, and disabling special characters} -+For GNU stty, giving a value of @code{^-} or @code{undef} disables that -+special character. (This is incompatible with Ultrix @command{stty}, -+which uses a value of @samp{u} to disable a special character. GNU -+@command{stty} treats a value @samp{u} like any other, namely to set that -+special character to @key{U}.) -+ -+@table @samp -+ -+@item intr -+@opindex intr -+Send an interrupt signal. -+ -+@item quit -+@opindex quit -+Send a quit signal. -+ -+@item erase -+@opindex erase -+Erase the last character typed. -+ -+@item kill -+@opindex kill -+Erase the current line. -+ -+@item eof -+@opindex eof -+Send an end of file (terminate the input). -+ -+@item eol -+@opindex eol -+End the line. -+ -+@item eol2 -+@opindex eol2 -+Alternate character to end the line. Non-@acronym{POSIX}. -+ -+@item swtch -+@opindex swtch -+Switch to a different shell layer. Non-@acronym{POSIX}. -+ -+@item start -+@opindex start -+Restart the output after stopping it. -+ -+@item stop -+@opindex stop -+Stop the output. -+ -+@item susp -+@opindex susp -+Send a terminal stop signal. -+ -+@item dsusp -+@opindex dsusp -+Send a terminal stop signal after flushing the input. Non-@acronym{POSIX}. -+ -+@item rprnt -+@opindex rprnt -+Redraw the current line. Non-@acronym{POSIX}. -+ -+@item werase -+@opindex werase -+Erase the last word typed. Non-@acronym{POSIX}. -+ -+@item lnext -+@opindex lnext -+Enter the next character typed literally, even if it is a special -+character. Non-@acronym{POSIX}. -+@end table -+ -+ -+@node Special -+@subsection Special settings -+ -+@cindex special settings -+ -+@table @samp -+@item min @var{n} -+@opindex min -+Set the minimum number of characters that will satisfy a read until -+the time value has expired, when @option{-icanon} is set. -+ -+@item time @var{n} -+@opindex time -+Set the number of tenths of a second before reads time out if the minimum -+number of characters have not been read, when @option{-icanon} is set. -+ -+@item ispeed @var{n} -+@opindex ispeed -+Set the input speed to @var{n}. -+ -+@item ospeed @var{n} -+@opindex ospeed -+Set the output speed to @var{n}. -+ -+@item rows @var{n} -+@opindex rows -+Tell the tty kernel driver that the terminal has @var{n} rows. Non-@acronym{POSIX}. -+ -+@item cols @var{n} -+@itemx columns @var{n} -+@opindex cols -+@opindex columns -+Tell the kernel that the terminal has @var{n} columns. Non-@acronym{POSIX}. -+ -+@item size -+@opindex size -+@vindex LINES -+@vindex COLUMNS -+Print the number of rows and columns that the kernel thinks the -+terminal has. (Systems that don't support rows and columns in the kernel -+typically use the environment variables @env{LINES} and @env{COLUMNS} -+instead; however, GNU @command{stty} does not know anything about them.) -+Non-@acronym{POSIX}. -+ -+@item line @var{n} -+@opindex line -+Use line discipline @var{n}. Non-@acronym{POSIX}. -+ -+@item speed -+@opindex speed -+Print the terminal speed. -+ -+@item @var{n} -+@cindex baud rate, setting -+Set the input and output speeds to @var{n}. @var{n} can be one of: 0 -+50 75 110 134 134.5 150 200 300 600 1200 1800 2400 4800 9600 19200 -+38400 @code{exta} @code{extb}. @code{exta} is the same as 19200; -+@code{extb} is the same as 38400. Many systems, including GNU/Linux, -+support higher speeds. The @command{stty} command includes support -+for speeds of -+57600, -+115200, -+230400, -+460800, -+500000, -+576000, -+921600, -+1000000, -+1152000, -+1500000, -+2000000, -+2500000, -+3000000, -+3500000, -+or -+4000000 where the system supports these. -+0 hangs up the line if @option{-clocal} is set. -+@end table -+ -+ -+@node printenv invocation -+@section @command{printenv}: Print all or some environment variables -+ -+@pindex printenv -+@cindex printing all or some environment variables -+@cindex environment variables, printing -+ -+@command{printenv} prints environment variable values. Synopsis: -+ -+@example -+printenv [@var{option}] [@var{variable}]@dots{} -+@end example -+ -+If no @var{variable}s are specified, @command{printenv} prints the value of -+every environment variable. Otherwise, it prints the value of each -+@var{variable} that is set, and nothing for those that are not set. -+ -+The only options are a lone @option{--help} or @option{--version}. -+@xref{Common options}. -+ -+@cindex exit status of @command{printenv} -+Exit status: -+ -+@display -+0 if all variables specified were found -+1 if at least one specified variable was not found -+2 if a write error occurred -+@end display -+ -+ -+@node tty invocation -+@section @command{tty}: Print file name of terminal on standard input -+ -+@pindex tty -+@cindex print terminal file name -+@cindex terminal file name, printing -+ -+@command{tty} prints the file name of the terminal connected to its standard -+input. It prints @samp{not a tty} if standard input is not a terminal. -+Synopsis: -+ -+@example -+tty [@var{option}]@dots{} -+@end example -+ -+The program accepts the following option. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -s -+@itemx --silent -+@itemx --quiet -+@opindex -s -+@opindex --silent -+@opindex --quiet -+Print nothing; only return an exit status. -+ -+@end table -+ -+@cindex exit status of @command{tty} -+Exit status: -+ -+@display -+0 if standard input is a terminal -+1 if standard input is not a terminal -+2 if given incorrect arguments -+3 if a write error occurs -+@end display -+ -+ -+@node User information -+@chapter User information -+ -+@cindex user information, commands for -+@cindex commands for printing user information -+ -+This section describes commands that print user-related information: -+logins, groups, and so forth. -+ -+@menu -+* id invocation:: Print user identity. -+* logname invocation:: Print current login name. -+* whoami invocation:: Print effective user ID. -+* groups invocation:: Print group names a user is in. -+* users invocation:: Print login names of users currently logged in. -+* who invocation:: Print who is currently logged in. -+@end menu -+ -+ -+@node id invocation -+@section @command{id}: Print user identity -+ -+@pindex id -+@cindex real user and group IDs, printing -+@cindex effective user and group IDs, printing -+@cindex printing real and effective user and group IDs -+ -+@command{id} prints information about the given user, or the process -+running it if no user is specified. Synopsis: -+ -+@example -+id [@var{option}]@dots{} [@var{username}] -+@end example -+ -+@vindex POSIXLY_CORRECT -+By default, it prints the real user ID, real group ID, effective user ID -+if different from the real user ID, effective group ID if different from -+the real group ID, and supplemental group IDs. -+In addition, if SELinux -+is enabled and the @env{POSIXLY_CORRECT} environment variable is not set, -+then print @samp{context=@var{c}}, where @var{c} is the security context. -+ -+Each of these numeric values is preceded by an identifying string and -+followed by the corresponding user or group name in parentheses. -+ -+The options cause @command{id} to print only part of the above information. -+Also see @ref{Common options}. -+ -+@table @samp -+@item -g -+@itemx --group -+@opindex -g -+@opindex --group -+Print only the group ID. -+ -+@item -G -+@itemx --groups -+@opindex -G -+@opindex --groups -+Print only the group ID and the supplementary groups. -+ -+@item -n -+@itemx --name -+@opindex -n -+@opindex --name -+Print the user or group name instead of the ID number. Requires -+@option{-u}, @option{-g}, or @option{-G}. -+ -+@item -r -+@itemx --real -+@opindex -r -+@opindex --real -+Print the real, instead of effective, user or group ID. Requires -+@option{-u}, @option{-g}, or @option{-G}. -+ -+@item -u -+@itemx --user -+@opindex -u -+@opindex --user -+Print only the user ID. -+ -+@item -Z -+@itemx --context -+@opindex -Z -+@opindex --context -+@cindex SELinux -+@cindex security context -+Print only the security context of the current user. -+If SELinux is disabled then print a warning and -+set the exit status to 1. -+ -+@end table -+ -+@exitstatus -+ -+@macro primaryAndSupplementaryGroups{cmd,arg} -+Primary and supplementary groups for a process are normally inherited -+from its parent and are usually unchanged since login. This means -+that if you change the group database after logging in, @command{\cmd\} -+will not reflect your changes within your existing login session. -+Running @command{\cmd\} with a \arg\ causes the user and group -+database to be consulted afresh, and so will give a different result. -+@end macro -+@primaryAndSupplementaryGroups{id,user argument} -+ -+@node logname invocation -+@section @command{logname}: Print current login name -+ -+@pindex logname -+@cindex printing user's login name -+@cindex login name, printing -+@cindex user name, printing -+ -+@flindex utmp -+@command{logname} prints the calling user's name, as found in a -+system-maintained file (often @file{/var/run/utmp} or -+@file{/etc/utmp}), and exits with a status of 0. If there is no entry -+for the calling process, @command{logname} prints -+an error message and exits with a status of 1. -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. -+ -+@exitstatus -+ -+ -+@node whoami invocation -+@section @command{whoami}: Print effective user ID -+ -+@pindex whoami -+@cindex effective user ID, printing -+@cindex printing the effective user ID -+ -+@command{whoami} prints the user name associated with the current -+effective user ID. It is equivalent to the command @samp{id -un}. -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. -+ -+@exitstatus -+ -+ -+@node groups invocation -+@section @command{groups}: Print group names a user is in -+ -+@pindex groups -+@cindex printing groups a user is in -+@cindex supplementary groups, printing -+ -+@command{groups} prints the names of the primary and any supplementary -+groups for each given @var{username}, or the current process if no names -+are given. If more than one name is given, the name of each user is -+printed before -+the list of that user's groups and the user name is separated from the -+group list by a colon. Synopsis: -+ -+@example -+groups [@var{username}]@dots{} -+@end example -+ -+The group lists are equivalent to the output of the command @samp{id -Gn}. -+ -+@primaryAndSupplementaryGroups{groups,list of users} -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. -+ -+@exitstatus -+ -+ -+@node users invocation -+@section @command{users}: Print login names of users currently logged in -+ -+@pindex users -+@cindex printing current usernames -+@cindex usernames, printing current -+ -+@cindex login sessions, printing users with -+@command{users} prints on a single line a blank-separated list of user -+names of users currently logged in to the current host. Each user name -+corresponds to a login session, so if a user has more than one login -+session, that user's name will appear the same number of times in the -+output. Synopsis: -+ -+@example -+users [@var{file}] -+@end example -+ -+@flindex utmp -+@flindex wtmp -+With no @var{file} argument, @command{users} extracts its information from -+a system-maintained file (often @file{/var/run/utmp} or -+@file{/etc/utmp}). If a file argument is given, @command{users} uses -+that file instead. A common choice is @file{/var/log/wtmp}. -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. -+ -+@exitstatus -+ -+ -+@node who invocation -+@section @command{who}: Print who is currently logged in -+ -+@pindex who -+@cindex printing current user information -+@cindex information, about current users -+ -+@command{who} prints information about users who are currently logged on. -+Synopsis: -+ -+@example -+@command{who} [@var{option}] [@var{file}] [am i] -+@end example -+ -+@cindex terminal lines, currently used -+@cindex login time -+@cindex remote hostname -+If given no non-option arguments, @command{who} prints the following -+information for each user currently logged on: login name, terminal -+line, login time, and remote hostname or X display. -+ -+@flindex utmp -+@flindex wtmp -+If given one non-option argument, @command{who} uses that instead of -+a default system-maintained file (often @file{/var/run/utmp} or -+@file{/etc/utmp}) as the name of the file containing the record of -+users logged on. @file{/var/log/wtmp} is commonly given as an argument -+to @command{who} to look at who has previously logged on. -+ -+@opindex am i -+@opindex who am i -+If given two non-option arguments, @command{who} prints only the entry -+for the user running it (determined from its standard input), preceded -+by the hostname. Traditionally, the two arguments given are @samp{am -+i}, as in @samp{who am i}. -+ -+@vindex TZ -+Time stamps are listed according to the time zone rules specified by -+the @env{TZ} environment variable, or by the system default rules if -+@env{TZ} is not set. @xref{TZ Variable,, Specifying the Time Zone -+with @env{TZ}, libc, The GNU C Library Reference Manual}. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -a -+@itemx --all -+@opindex -a -+@opindex --all -+Same as @samp{-b -d --login -p -r -t -T -u}. -+ -+@item -b -+@itemx --boot -+@opindex -b -+@opindex --boot -+Print the date and time of last system boot. -+ -+@item -d -+@itemx --dead -+@opindex -d -+@opindex --dead -+Print information corresponding to dead processes. -+ -+@item -H -+@itemx --heading -+@opindex -H -+@opindex --heading -+Print a line of column headings. -+ -+@item -l -+@itemx --login -+@opindex -l -+@opindex --login -+List only the entries that correspond to processes via which the -+system is waiting for a user to login. The user name is always @samp{LOGIN}. -+ -+@itemx --lookup -+@opindex --lookup -+Attempt to canonicalize hostnames found in utmp through a DNS lookup. This -+is not the default because it can cause significant delays on systems with -+automatic dial-up internet access. -+ -+@item -m -+@opindex -m -+Same as @samp{who am i}. -+ -+@item -p -+@itemx --process -+@opindex -p -+@opindex --process -+List active processes spawned by init. -+ -+@item -q -+@itemx --count -+@opindex -q -+@opindex --count -+Print only the login names and the number of users logged on. -+Overrides all other options. -+ -+@item -r -+@itemx --runlevel -+@opindex -r -+@opindex --runlevel -+Print the current (and maybe previous) run-level of the init process. -+ -+@item -s -+@opindex -s -+Ignored; for compatibility with other versions of @command{who}. -+ -+@item -t -+@itemx --time -+@opindex -t -+@opindex --time -+Print last system clock change. -+ -+@itemx -u -+@opindex -u -+@cindex idle time -+After the login time, print the number of hours and minutes that the -+user has been idle. @samp{.} means the user was active in the last minute. -+@samp{old} means the user has been idle for more than 24 hours. -+ -+@item -w -+@itemx -T -+@itemx --mesg -+@itemx --message -+@itemx --writable -+@opindex -w -+@opindex -T -+@opindex --mesg -+@opindex --message -+@opindex --writable -+@cindex message status -+@pindex write@r{, allowed} -+After each login name print a character indicating the user's message status: -+ -+@display -+@samp{+} allowing @code{write} messages -+@samp{-} disallowing @code{write} messages -+@samp{?} cannot find terminal device -+@end display -+ -+@end table -+ -+@exitstatus -+ -+ -+@node System context -+@chapter System context -+ -+@cindex system context -+@cindex context, system -+@cindex commands for system context -+ -+This section describes commands that print or change system-wide -+information. -+ -+@menu -+* date invocation:: Print or set system date and time. -+* arch invocation:: Print machine hardware name. -+* uname invocation:: Print system information. -+* hostname invocation:: Print or set system name. -+* hostid invocation:: Print numeric host identifier. -+* uptime invocation:: Print system uptime and load. -+@end menu -+ -+@node date invocation -+@section @command{date}: Print or set system date and time -+ -+@pindex date -+@cindex time, printing or setting -+@cindex printing the current time -+ -+Synopses: -+ -+@example -+date [@var{option}]@dots{} [+@var{format}] -+date [-u|--utc|--universal] @c this avoids a newline in the output -+[ MMDDhhmm[[CC]YY][.ss] ] -+@end example -+ -+@vindex LC_TIME -+Invoking @command{date} with no @var{format} argument is equivalent to invoking -+it with a default format that depends on the @env{LC_TIME} locale category. -+In the default C locale, this format is @samp{'+%a %b %e %H:%M:%S %Z %Y'}, -+so the output looks like @samp{Thu Mar @ 3 13:47:51 PST 2005}. -+ -+@vindex TZ -+Normally, @command{date} uses the time zone rules indicated by the -+@env{TZ} environment variable, or the system default rules if @env{TZ} -+is not set. @xref{TZ Variable,, Specifying the Time Zone with -+@env{TZ}, libc, The GNU C Library Reference Manual}. -+ -+@findex strftime @r{and @command{date}} -+@cindex time formats -+@cindex formatting times -+If given an argument that starts with a @samp{+}, @command{date} prints the -+current date and time (or the date and time specified by the -+@option{--date} option, see below) in the format defined by that argument, -+which is similar to that of the @code{strftime} function. Except for -+conversion specifiers, which start with @samp{%}, characters in the -+format string are printed unchanged. The conversion specifiers are -+described below. -+ -+@exitstatus -+ -+@menu -+* Time conversion specifiers:: %[HIklMNpPrRsSTXzZ] -+* Date conversion specifiers:: %[aAbBcCdDeFgGhjmuUVwWxyY] -+* Literal conversion specifiers:: %[%nt] -+* Padding and other flags:: Pad with zeros, spaces, etc. -+* Setting the time:: Changing the system clock. -+* Options for date:: Instead of the current time. -+@detailmenu -+* Date input formats:: Specifying date strings. -+@end detailmenu -+* Examples of date:: Examples. -+@end menu -+ -+@node Time conversion specifiers -+@subsection Time conversion specifiers -+ -+@cindex time conversion specifiers -+@cindex conversion specifiers, time -+ -+@command{date} conversion specifiers related to times. -+ -+@table @samp -+@item %H -+hour (@samp{00}@dots{}@samp{23}) -+@item %I -+hour (@samp{01}@dots{}@samp{12}) -+@item %k -+hour (@samp{ 0}@dots{}@samp{23}). -+This is a @acronym{GNU} extension. -+@item %l -+hour (@samp{ 1}@dots{}@samp{12}). -+This is a @acronym{GNU} extension. -+@item %M -+minute (@samp{00}@dots{}@samp{59}) -+@item %N -+nanoseconds (@samp{000000000}@dots{}@samp{999999999}). -+This is a @acronym{GNU} extension. -+@item %p -+locale's equivalent of either @samp{AM} or @samp{PM}; -+blank in many locales. -+Noon is treated as @samp{PM} and midnight as @samp{AM}. -+@item %P -+like @samp{%p}, except lower case. -+This is a @acronym{GNU} extension. -+@item %r -+locale's 12-hour clock time (e.g., @samp{11:11:04 PM}) -+@item %R -+24-hour hour and minute. Same as @samp{%H:%M}. -+This is a @acronym{GNU} extension. -+@item %s -+@cindex epoch, seconds since -+@cindex seconds since the epoch -+@cindex beginning of time -+seconds since the epoch, i.e., since 1970-01-01 00:00:00 UTC. -+Leap seconds are not counted unless leap second support is available. -+@xref{%s-examples}, for examples. -+This is a @acronym{GNU} extension. -+@item %S -+second (@samp{00}@dots{}@samp{60}). -+This may be @samp{60} if leap seconds are supported. -+@item %T -+24-hour hour, minute, and second. Same as @samp{%H:%M:%S}. -+@item %X -+locale's time representation (e.g., @samp{23:13:48}) -+@item %z -+@w{@acronym{RFC} 2822/@acronym{ISO} 8601} style numeric time zone -+(e.g., @samp{-0600} or @samp{+0530}), or nothing if no -+time zone is determinable. This value reflects the numeric time zone -+appropriate for the current time, using the time zone rules specified -+by the @env{TZ} environment variable. -+The time (and optionally, the time zone rules) can be overridden -+by the @option{--date} option. -+This is a @acronym{GNU} extension. -+@item %:z -+@w{@acronym{RFC} 3339/@acronym{ISO} 8601} style numeric time zone with -+@samp{:} (e.g., @samp{-06:00} or @samp{+05:30}), or nothing if no time -+zone is determinable. -+This is a @acronym{GNU} extension. -+@item %::z -+Numeric time zone to the nearest second with @samp{:} (e.g., -+@samp{-06:00:00} or @samp{+05:30:00}), or nothing if no time zone is -+determinable. -+This is a @acronym{GNU} extension. -+@item %:::z -+Numeric time zone with @samp{:} using the minimum necessary precision -+(e.g., @samp{-06}, @samp{+05:30}, or @samp{-04:56:02}), or nothing if -+no time zone is determinable. -+This is a @acronym{GNU} extension. -+@item %Z -+alphabetic time zone abbreviation (e.g., @samp{EDT}), or nothing if no -+time zone is determinable. See @samp{%z} for how it is determined. -+@end table -+ -+ -+@node Date conversion specifiers -+@subsection Date conversion specifiers -+ -+@cindex date conversion specifiers -+@cindex conversion specifiers, date -+ -+@command{date} conversion specifiers related to dates. -+ -+@table @samp -+@item %a -+locale's abbreviated weekday name (e.g., @samp{Sun}) -+@item %A -+locale's full weekday name, variable length (e.g., @samp{Sunday}) -+@item %b -+locale's abbreviated month name (e.g., @samp{Jan}) -+@item %B -+locale's full month name, variable length (e.g., @samp{January}) -+@item %c -+locale's date and time (e.g., @samp{Thu Mar @ 3 23:05:25 2005}) -+@item %C -+century. This is like @samp{%Y}, except the last two digits are omitted. -+For example, it is @samp{20} if @samp{%Y} is @samp{2000}, -+and is @samp{-0} if @samp{%Y} is @samp{-001}. -+It is normally at least two characters, but it may be more. -+@item %d -+day of month (e.g., @samp{01}) -+@item %D -+date; same as @samp{%m/%d/%y} -+@item %e -+day of month, space padded; same as @samp{%_d} -+@item %F -+full date in @acronym{ISO} 8601 format; same as @samp{%Y-%m-%d}. -+This is a good choice for a date format, as it is standard and -+is easy to sort in the usual case where years are in the range -+0000@dots{}9999. -+This is a @acronym{GNU} extension. -+@item %g -+year corresponding to the @acronym{ISO} week number, but without the century -+(range @samp{00} through @samp{99}). This has the same format and value -+as @samp{%y}, except that if the @acronym{ISO} week number (see -+@samp{%V}) belongs -+to the previous or next year, that year is used instead. -+This is a @acronym{GNU} extension. -+@item %G -+year corresponding to the @acronym{ISO} week number. This has the -+same format and value as @samp{%Y}, except that if the @acronym{ISO} -+week number (see -+@samp{%V}) belongs to the previous or next year, that year is used -+instead. -+It is normally useful only if @samp{%V} is also used; -+for example, the format @samp{%G-%m-%d} is probably a mistake, -+since it combines the ISO week number year with the conventional month and day. -+This is a @acronym{GNU} extension. -+@item %h -+same as @samp{%b} -+@item %j -+day of year (@samp{001}@dots{}@samp{366}) -+@item %m -+month (@samp{01}@dots{}@samp{12}) -+@item %u -+day of week (@samp{1}@dots{}@samp{7}) with @samp{1} corresponding to Monday -+@item %U -+week number of year, with Sunday as the first day of the week -+(@samp{00}@dots{}@samp{53}). -+Days in a new year preceding the first Sunday are in week zero. -+@item %V -+@acronym{ISO} week number, that is, the -+week number of year, with Monday as the first day of the week -+(@samp{01}@dots{}@samp{53}). -+If the week containing January 1 has four or more days in -+the new year, then it is considered week 1; otherwise, it is week 53 of -+the previous year, and the next week is week 1. (See the @acronym{ISO} 8601 -+standard.) -+@item %w -+day of week (@samp{0}@dots{}@samp{6}) with 0 corresponding to Sunday -+@item %W -+week number of year, with Monday as first day of week -+(@samp{00}@dots{}@samp{53}). -+Days in a new year preceding the first Monday are in week zero. -+@item %x -+locale's date representation (e.g., @samp{12/31/99}) -+@item %y -+last two digits of year (@samp{00}@dots{}@samp{99}) -+@item %Y -+year. This is normally at least four characters, but it may be more. -+Year @samp{0000} precedes year @samp{0001}, and year @samp{-001} -+precedes year @samp{0000}. -+@end table -+ -+ -+@node Literal conversion specifiers -+@subsection Literal conversion specifiers -+ -+@cindex literal conversion specifiers -+@cindex conversion specifiers, literal -+ -+@command{date} conversion specifiers that produce literal strings. -+ -+@table @samp -+@item %% -+a literal % -+@item %n -+a newline -+@item %t -+a horizontal tab -+@end table -+ -+ -+@node Padding and other flags -+@subsection Padding and other flags -+ -+@cindex numeric field padding -+@cindex padding of numeric fields -+@cindex fields, padding numeric -+ -+Unless otherwise specified, @command{date} normally pads numeric fields -+with zeros, so that, for -+example, numeric months are always output as two digits. -+Seconds since the epoch are not padded, though, -+since there is no natural width for them. -+ -+As a @acronym{GNU} extension, @command{date} recognizes any of the -+following optional flags after the @samp{%}: -+ -+@table @samp -+@item - -+(hyphen) Do not pad the field; useful if the output is intended for -+human consumption. -+@item _ -+(underscore) Pad with spaces; useful if you need a fixed -+number of characters in the output, but zeros are too distracting. -+@item 0 -+(zero) Pad with zeros even if the conversion specifier -+would normally pad with spaces. -+@item ^ -+Use upper case characters if possible. -+@item # -+Use opposite case characters if possible. -+A field that is normally upper case becomes lower case, and vice versa. -+@end table -+ -+@noindent -+Here are some examples of padding: -+ -+@example -+date +%d/%m -d "Feb 1" -+@result{} 01/02 -+date +%-d/%-m -d "Feb 1" -+@result{} 1/2 -+date +%_d/%_m -d "Feb 1" -+@result{} 1/ 2 -+@end example -+ -+As a @acronym{GNU} extension, you can specify the field width -+(after any flag, if present) as a decimal number. If the natural size of the -+output of the field has less than the specified number of characters, -+the result is written right adjusted and padded to the given -+size. For example, @samp{%9B} prints the right adjusted month name in -+a field of width 9. -+ -+An optional modifier can follow the optional flag and width -+specification. The modifiers are: -+ -+@table @samp -+@item E -+Use the locale's alternate representation for date and time. This -+modifier applies to the @samp{%c}, @samp{%C}, @samp{%x}, @samp{%X}, -+@samp{%y} and @samp{%Y} conversion specifiers. In a Japanese locale, for -+example, @samp{%Ex} might yield a date format based on the Japanese -+Emperors' reigns. -+ -+@item O -+Use the locale's alternate numeric symbols for numbers. This modifier -+applies only to numeric conversion specifiers. -+@end table -+ -+If the format supports the modifier but no alternate representation -+is available, it is ignored. -+ -+ -+@node Setting the time -+@subsection Setting the time -+ -+@cindex setting the time -+@cindex time setting -+@cindex appropriate privileges -+ -+If given an argument that does not start with @samp{+}, @command{date} sets -+the system clock to the date and time specified by that argument (as -+described below). You must have appropriate privileges to set the -+system clock. The @option{--date} and @option{--set} options may not be -+used with such an argument. The @option{--universal} option may be used -+with such an argument to indicate that the specified date and time are -+relative to Coordinated Universal Time rather than to the local time -+zone. -+ -+The argument must consist entirely of digits, which have the following -+meaning: -+ -+@table @samp -+@item MM -+month -+@item DD -+day within month -+@item hh -+hour -+@item mm -+minute -+@item CC -+first two digits of year (optional) -+@item YY -+last two digits of year (optional) -+@item ss -+second (optional) -+@end table -+ -+The @option{--set} option also sets the system clock; see the next section. -+ -+ -+@node Options for date -+@subsection Options for @command{date} -+ -+@cindex @command{date} options -+@cindex options for @command{date} -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -d @var{datestr} -+@itemx --date=@var{datestr} -+@opindex -d -+@opindex --date -+@cindex parsing date strings -+@cindex date strings, parsing -+@cindex arbitrary date strings, parsing -+@opindex yesterday -+@opindex tomorrow -+@opindex next @var{day} -+@opindex last @var{day} -+Display the date and time specified in @var{datestr} instead of the -+current date and time. @var{datestr} can be in almost any common -+format. It can contain month names, time zones, @samp{am} and @samp{pm}, -+@samp{yesterday}, etc. For example, @option{--date="2004-02-27 -+14:19:13.489392193 +0530"} specifies the instant of time that is -+489,392,193 nanoseconds after February 27, 2004 at 2:19:13 PM in a -+time zone that is 5 hours and 30 minutes east of @acronym{UTC}.@* -+Note: input currently must be in locale independent format. E.g., the -+LC_TIME=C below is needed to print back the correct date in many locales: -+@example -+date -d "$(LC_TIME=C date)" -+@end example -+@xref{Date input formats}. -+ -+@item -f @var{datefile} -+@itemx --file=@var{datefile} -+@opindex -f -+@opindex --file -+Parse each line in @var{datefile} as with @option{-d} and display the -+resulting date and time. If @var{datefile} is @samp{-}, use standard -+input. This is useful when you have many dates to process, because the -+system overhead of starting up the @command{date} executable many times can -+be considerable. -+ -+@item -r @var{file} -+@itemx --reference=@var{file} -+@opindex -r -+@opindex --reference -+Display the date and time of the last modification of @var{file}, -+instead of the current date and time. -+ -+@item -R -+@itemx --rfc-822 -+@itemx --rfc-2822 -+@opindex -R -+@opindex --rfc-822 -+@opindex --rfc-2822 -+Display the date and time using the format @samp{%a, %d %b %Y %H:%M:%S -+%z}, evaluated in the C locale so abbreviations are always in English. -+For example: -+ -+@example -+Fri, 09 Sep 2005 13:51:39 -0700 -+@end example -+ -+This format conforms to -+@uref{ftp://ftp.rfc-editor.org/in-notes/rfc2822.txt, Internet -+@acronym{RFCs} 2822} and -+@uref{ftp://ftp.rfc-editor.org/in-notes/rfc822.txt, 822}, the -+current and previous standards for Internet email. -+ -+@item --rfc-3339=@var{timespec} -+@opindex --rfc-3339=@var{timespec} -+Display the date using a format specified by -+@uref{ftp://ftp.rfc-editor.org/in-notes/rfc3339.txt, Internet -+@acronym{RFC} 3339}. This is a subset of the @acronym{ISO} 8601 -+format, except that it also permits applications to use a space rather -+than a @samp{T} to separate dates from times. Unlike the other -+standard formats, @acronym{RFC} 3339 format is always suitable as -+input for the @option{--date} (@option{-d}) and @option{--file} -+(@option{-f}) options, regardless of the current locale. -+ -+The argument @var{timespec} specifies how much of the time to include. -+It can be one of the following: -+ -+@table @samp -+@item date -+Print just the full-date, e.g., @samp{2005-09-14}. -+This is equivalent to the format @samp{%Y-%m-%d}. -+ -+@item seconds -+Print the full-date and full-time separated by a space, e.g., -+@samp{2005-09-14 00:56:06+05:30}. The output ends with a numeric -+time-offset; here the @samp{+05:30} means that local time is five -+hours and thirty minutes east of @acronym{UTC}. This is equivalent to -+the format @samp{%Y-%m-%d %H:%M:%S%:z}. -+ -+@item ns -+Like @samp{seconds}, but also print nanoseconds, e.g., -+@samp{2005-09-14 00:56:06.998458565+05:30}. -+This is equivalent to the format @samp{%Y-%m-%d %H:%M:%S.%N%:z}. -+ -+@end table -+ -+@item -s @var{datestr} -+@itemx --set=@var{datestr} -+@opindex -s -+@opindex --set -+Set the date and time to @var{datestr}. See @option{-d} above. -+ -+@item -u -+@itemx --utc -+@itemx --universal -+@opindex -u -+@opindex --utc -+@opindex --universal -+@cindex Coordinated Universal Time -+@cindex UTC -+@cindex Greenwich Mean Time -+@cindex GMT -+@vindex TZ -+Use Coordinated Universal Time (@acronym{UTC}) by operating as if the -+@env{TZ} environment variable were set to the string @samp{UTC0}. -+Coordinated -+Universal Time is often called ``Greenwich Mean Time'' (@sc{gmt}) for -+historical reasons. -+@end table -+ -+ -+@node Examples of date -+@subsection Examples of @command{date} -+ -+@cindex examples of @command{date} -+ -+Here are a few examples. Also see the documentation for the @option{-d} -+option in the previous section. -+ -+@itemize @bullet -+ -+@item -+To print the date of the day before yesterday: -+ -+@example -+date --date='2 days ago' -+@end example -+ -+@item -+To print the date of the day three months and one day hence: -+ -+@example -+date --date='3 months 1 day' -+@end example -+ -+@item -+To print the day of year of Christmas in the current year: -+ -+@example -+date --date='25 Dec' +%j -+@end example -+ -+@item -+To print the current full month name and the day of the month: -+ -+@example -+date '+%B %d' -+@end example -+ -+But this may not be what you want because for the first nine days of -+the month, the @samp{%d} expands to a zero-padded two-digit field, -+for example @samp{date -d 1may '+%B %d'} will print @samp{May 01}. -+ -+@item -+To print a date without the leading zero for one-digit days -+of the month, you can use the (@acronym{GNU} extension) -+@samp{-} flag to suppress -+the padding altogether: -+ -+@example -+date -d 1may '+%B %-d -+@end example -+ -+@item -+To print the current date and time in the format required by many -+non-@acronym{GNU} versions of @command{date} when setting the system clock: -+ -+@example -+date +%m%d%H%M%Y.%S -+@end example -+ -+@item -+To set the system clock forward by two minutes: -+ -+@example -+date --set='+2 minutes' -+@end example -+ -+@item -+To print the date in @acronym{RFC} 2822 format, -+use @samp{date --rfc-2822}. Here is some example output: -+ -+@example -+Fri, 09 Sep 2005 13:51:39 -0700 -+@end example -+ -+@anchor{%s-examples} -+@item -+To convert a date string to the number of seconds since the epoch -+(which is 1970-01-01 00:00:00 UTC), use the @option{--date} option with -+the @samp{%s} format. That can be useful in sorting and/or graphing -+and/or comparing data by date. The following command outputs the -+number of the seconds since the epoch for the time two minutes after the -+epoch: -+ -+@example -+date --date='1970-01-01 00:02:00 +0000' +%s -+120 -+@end example -+ -+If you do not specify time zone information in the date string, -+@command{date} uses your computer's idea of the time zone when -+interpreting the string. For example, if your computer's time zone is -+that of Cambridge, Massachusetts, which was then 5 hours (i.e., 18,000 -+seconds) behind UTC: -+ -+@example -+# local time zone used -+date --date='1970-01-01 00:02:00' +%s -+18120 -+@end example -+ -+@item -+If you're sorting or graphing dated data, your raw date values may be -+represented as seconds since the epoch. But few people can look at -+the date @samp{946684800} and casually note ``Oh, that's the first second -+of the year 2000 in Greenwich, England.'' -+ -+@example -+date --date='2000-01-01 UTC' +%s -+946684800 -+@end example -+ -+An alternative is to use the @option{--utc} (@option{-u}) option. -+Then you may omit @samp{UTC} from the date string. Although this -+produces the same result for @samp{%s} and many other format sequences, -+with a time zone offset different from zero, it would give a different -+result for zone-dependent formats like @samp{%z}. -+ -+@example -+date -u --date=2000-01-01 +%s -+946684800 -+@end example -+ -+To convert such an unwieldy number of seconds back to -+a more readable form, use a command like this: -+ -+@smallexample -+# local time zone used -+date -d '1970-01-01 UTC 946684800 seconds' +"%Y-%m-%d %T %z" -+1999-12-31 19:00:00 -0500 -+@end smallexample -+ -+Or if you do not mind depending on the @samp{@@} feature present since -+coreutils 5.3.0, you could shorten this to: -+ -+@smallexample -+date -d @@946684800 +"%F %T %z" -+1999-12-31 19:00:00 -0500 -+@end smallexample -+ -+Often it is better to output UTC-relative date and time: -+ -+@smallexample -+date -u -d '1970-01-01 946684800 seconds' +"%Y-%m-%d %T %z" -+2000-01-01 00:00:00 +0000 -+@end smallexample -+ -+@end itemize -+ -+ -+@node arch invocation -+@section @command{arch}: Print machine hardware name -+ -+@pindex arch -+@cindex print machine hardware name -+@cindex system information, printing -+ -+@command{arch} prints the machine hardware name, -+and is equivalent to @samp{uname -m}. -+Synopsis: -+ -+@example -+arch [@var{option}] -+@end example -+ -+The program accepts the @ref{Common options} only. -+ -+@exitstatus -+ -+ -+@node uname invocation -+@section @command{uname}: Print system information -+ -+@pindex uname -+@cindex print system information -+@cindex system information, printing -+ -+@command{uname} prints information about the machine and operating system -+it is run on. If no options are given, @command{uname} acts as if the -+@option{-s} option were given. Synopsis: -+ -+@example -+uname [@var{option}]@dots{} -+@end example -+ -+If multiple options or @option{-a} are given, the selected information is -+printed in this order: -+ -+@example -+@var{kernel-name} @var{nodename} @var{kernel-release} @var{kernel-version} -+@var{machine} @var{processor} @var{hardware-platform} @var{operating-system} -+@end example -+ -+The information may contain internal spaces, so such output cannot be -+parsed reliably. In the following example, @var{release} is -+@samp{2.2.18ss.e820-bda652a #4 SMP Tue Jun 5 11:24:08 PDT 2001}: -+ -+@smallexample -+uname -a -+@result{} Linux dum 2.2.18 #4 SMP Tue Jun 5 11:24:08 PDT 2001 i686 unknown unknown GNU/Linux -+@end smallexample -+ -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -a -+@itemx --all -+@opindex -a -+@opindex --all -+Print all of the below information, except omit the processor type -+and the hardware platform name if they are unknown. -+ -+@item -i -+@itemx --hardware-platform -+@opindex -i -+@opindex --hardware-platform -+@cindex implementation, hardware -+@cindex hardware platform -+@cindex platform, hardware -+Print the hardware platform name -+(sometimes called the hardware implementation). -+Print @samp{unknown} if the kernel does not make this information -+easily available, as is the case with Linux kernels. -+ -+@item -m -+@itemx --machine -+@opindex -m -+@opindex --machine -+@cindex machine type -+@cindex hardware class -+@cindex hardware type -+Print the machine hardware name (sometimes called the hardware class -+or hardware type). -+ -+@item -n -+@itemx --nodename -+@opindex -n -+@opindex --nodename -+@cindex hostname -+@cindex node name -+@cindex network node name -+Print the network node hostname. -+ -+@item -p -+@itemx --processor -+@opindex -p -+@opindex --processor -+@cindex host processor type -+Print the processor type (sometimes called the instruction set -+architecture or ISA). -+Print @samp{unknown} if the kernel does not make this information -+easily available, as is the case with Linux kernels. -+ -+@item -o -+@itemx --operating-system -+@opindex -o -+@opindex --operating-system -+@cindex operating system name -+Print the name of the operating system. -+ -+@item -r -+@itemx --kernel-release -+@opindex -r -+@opindex --kernel-release -+@cindex kernel release -+@cindex release of kernel -+Print the kernel release. -+ -+@item -s -+@itemx --kernel-name -+@opindex -s -+@opindex --kernel-name -+@cindex kernel name -+@cindex name of kernel -+Print the kernel name. -+@acronym{POSIX} 1003.1-2001 (@pxref{Standards conformance}) calls this -+``the implementation of the operating system'', because the -+@acronym{POSIX} specification itself has no notion of ``kernel''. -+The kernel name might be the same as the operating system name printed -+by the @option{-o} or @option{--operating-system} option, but it might -+differ. Some operating systems (e.g., FreeBSD, HP-UX) have the same -+name as their underlying kernels; others (e.g., GNU/Linux, Solaris) -+do not. -+ -+@item -v -+@itemx --kernel-version -+@opindex -v -+@opindex --kernel-version -+@cindex kernel version -+@cindex version of kernel -+Print the kernel version. -+ -+@end table -+ -+@exitstatus -+ -+ -+@node hostname invocation -+@section @command{hostname}: Print or set system name -+ -+@pindex hostname -+@cindex setting the hostname -+@cindex printing the hostname -+@cindex system name, printing -+@cindex appropriate privileges -+ -+With no arguments, @command{hostname} prints the name of the current host -+system. With one argument, it sets the current host name to the -+specified string. You must have appropriate privileges to set the host -+name. Synopsis: -+ -+@example -+hostname [@var{name}] -+@end example -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. -+ -+@exitstatus -+ -+ -+@node hostid invocation -+@section @command{hostid}: Print numeric host identifier -+ -+@pindex hostid -+@cindex printing the host identifier -+ -+@command{hostid} prints the numeric identifier of the current host -+in hexadecimal. This command accepts no arguments. -+The only options are @option{--help} and @option{--version}. -+@xref{Common options}. -+ -+For example, here's what it prints on one system I use: -+ -+@example -+$ hostid -+1bac013d -+@end example -+ -+On that system, the 32-bit quantity happens to be closely -+related to the system's Internet address, but that isn't always -+the case. -+ -+@exitstatus -+ -+@node uptime invocation -+@section @command{uptime}: Print system uptime and load -+ -+@pindex uptime -+@cindex printing the system uptime and load -+ -+@command{uptime} prints the current time, the system's uptime, the -+number of logged-in users and the current load average. -+ -+If an argument is specified, it is used as the file to be read -+to discover how many users are logged in. If no argument is -+specified, a system default is used (@command{uptime --help} indicates -+the default setting). -+ -+The only options are @option{--help} and @option{--version}. -+@xref{Common options}. -+ -+For example, here's what it prints right now on one system I use: -+ -+@example -+$ uptime -+ 14:07 up 3:35, 3 users, load average: 1.39, 1.15, 1.04 -+@end example -+ -+The precise method of calculation of load average varies somewhat -+between systems. Some systems calculate it as the average number of -+runnable processes over the last 1, 5 and 15 minutes, but some systems -+also include processes in the uninterruptible sleep state (that is, -+those processes which are waiting for disk I/O). The Linux kernel -+includes uninterruptible processes. -+ -+@node SELinux context -+@chapter SELinux context -+ -+@cindex SELinux context -+@cindex SELinux, context -+@cindex commands for SELinux context -+ -+This section describes commands for operations with SELinux -+contexts. -+ -+@menu -+* chcon invocation:: Change SELinux context of file -+* runcon invocation:: Run a command in specified SELinux context -+@end menu -+ -+@node chcon invocation -+@section @command{chcon}: Change SELinux context of file -+ -+@pindex chcon -+@cindex changing security context -+@cindex change SELinux context -+ -+@command{chcon} changes the SELinux security context of the selected files. -+Synopses: -+ -+@smallexample -+chcon [@var{option}]@dots{} @var{context} @var{file}@dots{} -+chcon [@var{option}]@dots{} [-u @var{user}] [-r @var{role}] [-l @var{range}] [-t @var{type}] @var{file}@dots{} -+chcon [@var{option}]@dots{} --reference=@var{rfile} @var{file}@dots{} -+@end smallexample -+ -+Change the SELinux security context of each @var{file} to @var{context}. -+With @option{--reference}, change the security context of each @var{file} -+to that of @var{rfile}. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -h -+@itemx --no-dereference -+@opindex -h -+@opindex --no-dereference -+@cindex no dereference -+Affect symbolic links instead of any referenced file. -+ -+@item --reference=@var{rfile} -+@opindex --reference -+@cindex reference file -+Use @var{rfile}'s security context rather than specifying a @var{context} value. -+ -+@item -R -+@itemx --recursive -+@opindex -R -+@opindex --recursive -+Operate on files and directories recursively. -+ -+@choptH -+@xref{Traversing symlinks}. -+ -+@choptL -+@xref{Traversing symlinks}. -+ -+@choptP -+@xref{Traversing symlinks}. -+ -+@item -v -+@itemx --verbose -+@opindex -v -+@opindex --verbose -+@cindex diagnostic -+Output a diagnostic for every file processed. -+ -+@item -u @var{user} -+@itemx --user=@var{user} -+@opindex -u -+@opindex --user -+Set user @var{user} in the target security context. -+ -+@item -r @var{role} -+@itemx --role=@var{role} -+@opindex -r -+@opindex --role -+Set role @var{role} in the target security context. -+ -+@item -t @var{type} -+@itemx --type=@var{type} -+@opindex -t -+@opindex --type -+Set type @var{type} in the target security context. -+ -+@item -l @var{range} -+@itemx --range=@var{range} -+@opindex -l -+@opindex --range -+Set range @var{range} in the target security context. -+ -+@end table -+ -+@exitstatus -+ -+@node runcon invocation -+@section @command{runcon}: Run a command in specified SELinux context -+ -+@pindex runcon -+@cindex run with security context -+ -+ -+@command{runcon} runs file in specified SELinux security context. -+ -+Synopses: -+@smallexample -+runcon @var{context} @var{command} [@var{args}] -+runcon [ -c ] [-u @var{user}] [-r @var{role}] [-t @var{type}] [-l @var{range}] @var{command} [@var{args}] -+@end smallexample -+ -+Run @var{command} with completely-specified @var{context}, or with -+current or transitioned security context modified by one or more of @var{level}, -+@var{role}, @var{type} and @var{user}. -+ -+If none of @option{-c}, @option{-t}, @option{-u}, @option{-r}, or @option{-l} -+is specified, the first argument is used as the complete context. -+Any additional arguments after @var{command} -+are interpreted as arguments to the command. -+ -+With neither @var{context} nor @var{command}, print the current security context. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -c -+@itemx --compute -+@opindex -c -+@opindex --compute -+Compute process transition context before modifying. -+ -+@item -u @var{user} -+@itemx --user=@var{user} -+@opindex -u -+@opindex --user -+Set user @var{user} in the target security context. -+ -+@item -r @var{role} -+@itemx --role=@var{role} -+@opindex -r -+@opindex --role -+Set role @var{role} in the target security context. -+ -+@item -t @var{type} -+@itemx --type=@var{type} -+@opindex -t -+@opindex --type -+Set type @var{type} in the target security context. -+ -+@item -l @var{range} -+@itemx --range=@var{range} -+@opindex -l -+@opindex --range -+Set range @var{range} in the target security context. -+ -+@end table -+ -+@cindex exit status of @command{runcon} -+Exit status: -+ -+@display -+126 if @var{command} is found but cannot be invoked -+127 if @command{runcon} itself fails or if @var{command} cannot be found -+the exit status of @var{command} otherwise -+@end display -+ -+@node Modified command invocation -+@chapter Modified command invocation -+ -+@cindex modified command invocation -+@cindex invocation of commands, modified -+@cindex commands for invoking other commands -+ -+This section describes commands that run other commands in some context -+different than the current one: a modified environment, as a different -+user, etc. -+ -+@menu -+* chroot invocation:: Modify the root directory. -+* env invocation:: Modify environment variables. -+* nice invocation:: Modify niceness. -+* nohup invocation:: Immunize to hangups. -+* stdbuf invocation:: Modify buffering of standard streams. -+* su invocation:: Modify user and group ID. -+* timeout invocation:: Run with time limit. -+@end menu -+ -+ -+@node chroot invocation -+@section @command{chroot}: Run a command with a different root directory -+ -+@pindex chroot -+@cindex running a program in a specified root directory -+@cindex root directory, running a program in a specified -+ -+@command{chroot} runs a command with a specified root directory. -+On many systems, only the super-user can do this.@footnote{However, -+some systems (e.g., FreeBSD) can be configured to allow certain regular -+users to use the @code{chroot} system call, and hence to run this program. -+Also, on Cygwin, anyone can run the @command{chroot} command, because the -+underlying function is non-privileged due to lack of support in MS-Windows.} -+Synopses: -+ -+@example -+chroot @var{option} @var{newroot} [@var{command} [@var{args}]@dots{}] -+chroot @var{option} -+@end example -+ -+Ordinarily, file names are looked up starting at the root of the -+directory structure, i.e., @file{/}. @command{chroot} changes the root to -+the directory @var{newroot} (which must exist) and then runs -+@var{command} with optional @var{args}. If @var{command} is not -+specified, the default is the value of the @env{SHELL} environment -+variable or @command{/bin/sh} if not set, invoked with the @option{-i} option. -+@var{command} must not be a special built-in utility -+(@pxref{Special built-in utilities}). -+ -+The program accepts the following options. Also see @ref{Common options}. -+Options must precede operands. -+ -+@table @samp -+ -+@itemx --userspec=@var{user}[:@var{group}] -+@opindex --userspec -+By default, @var{command} is run with the same credentials -+as the invoking process. -+Use this option to run it as a different @var{user} and/or with a -+different primary @var{group}. -+ -+@itemx --groups=@var{groups} -+@opindex --groups -+Use this option to specify the supplementary @var{groups} to be -+used by the new process. -+The items in the list (names or numeric IDs) must be separated by commas. -+ -+@end table -+ -+Here are a few tips to help avoid common problems in using chroot. -+To start with a simple example, make @var{command} refer to a statically -+linked binary. If you were to use a dynamically linked executable, then -+you'd have to arrange to have the shared libraries in the right place under -+your new root directory. -+ -+For example, if you create a statically linked @command{ls} executable, -+and put it in @file{/tmp/empty}, you can run this command as root: -+ -+@example -+$ chroot /tmp/empty /ls -Rl / -+@end example -+ -+Then you'll see output like this: -+ -+@example -+/: -+total 1023 -+-rwxr-xr-x 1 0 0 1041745 Aug 16 11:17 ls -+@end example -+ -+If you want to use a dynamically linked executable, say @command{bash}, -+then first run @samp{ldd bash} to see what shared objects it needs. -+Then, in addition to copying the actual binary, also copy the listed -+files to the required positions under your intended new root directory. -+Finally, if the executable requires any other files (e.g., data, state, -+device files), copy them into place, too. -+ -+@cindex exit status of @command{chroot} -+Exit status: -+ -+@display -+1 if @command{chroot} itself fails -+126 if @var{command} is found but cannot be invoked -+127 if @var{command} cannot be found -+the exit status of @var{command} otherwise -+@end display -+ -+ -+@node env invocation -+@section @command{env}: Run a command in a modified environment -+ -+@pindex env -+@cindex environment, running a program in a modified -+@cindex modified environment, running a program in a -+@cindex running a program in a modified environment -+ -+@command{env} runs a command with a modified environment. Synopses: -+ -+@example -+env [@var{option}]@dots{} [@var{name}=@var{value}]@dots{} @c -+[@var{command} [@var{args}]@dots{}] -+env -+@end example -+ -+Operands of the form @samp{@var{variable}=@var{value}} set -+the environment variable @var{variable} to value @var{value}. -+@var{value} may be empty (@samp{@var{variable}=}). Setting a variable -+to an empty value is different from unsetting it. -+These operands are evaluated left-to-right, so if two operands -+mention the same variable the earlier is ignored. -+ -+Environment variable names can be empty, and can contain any -+characters other than @samp{=} and @acronym{ASCII} @sc{nul}. -+However, it is wise to limit yourself to names that -+consist solely of underscores, digits, and @acronym{ASCII} letters, -+and that begin with a non-digit, as applications like the shell do not -+work well with other names. -+ -+@vindex PATH -+The first operand that does not contain the character @samp{=} -+specifies the program to invoke; it is -+searched for according to the @env{PATH} environment variable. Any -+remaining arguments are passed as arguments to that program. -+The program should not be a special built-in utility -+(@pxref{Special built-in utilities}). -+ -+@cindex environment, printing -+ -+If no command name is specified following the environment -+specifications, the resulting environment is printed. This is like -+specifying the @command{printenv} program. -+ -+The program accepts the following options. Also see @ref{Common options}. -+Options must precede operands. -+ -+@table @samp -+ -+@item -u @var{name} -+@itemx --unset=@var{name} -+@opindex -u -+@opindex --unset -+Remove variable @var{name} from the environment, if it was in the -+environment. -+ -+@item - -+@itemx -i -+@itemx --ignore-environment -+@opindex - -+@opindex -i -+@opindex --ignore-environment -+Start with an empty environment, ignoring the inherited environment. -+ -+@end table -+ -+@cindex exit status of @command{env} -+Exit status: -+ -+@display -+0 if no @var{command} is specified and the environment is output -+1 if @command{env} itself fails -+126 if @var{command} is found but cannot be invoked -+127 if @var{command} cannot be found -+the exit status of @var{command} otherwise -+@end display -+ -+ -+@node nice invocation -+@section @command{nice}: Run a command with modified niceness -+ -+@pindex nice -+@cindex niceness -+@cindex scheduling, affecting -+@cindex appropriate privileges -+ -+@command{nice} prints or modifies a process's @dfn{niceness}, -+a parameter that affects whether the process is scheduled favorably. -+Synopsis: -+ -+@example -+nice [@var{option}]@dots{} [@var{command} [@var{arg}]@dots{}] -+@end example -+ -+If no arguments are given, @command{nice} prints the current niceness. -+Otherwise, @command{nice} runs the given @var{command} with its -+niceness adjusted. By default, its niceness is incremented by 10. -+ -+Niceness values range at least from @minus{}20 (process has high priority -+and gets more resources, thus slowing down other processes) through 19 -+(process has lower priority and runs slowly itself, but has less impact -+on the speed of other running processes). Some systems -+may have a wider range of nicenesses; conversely, other systems may -+enforce more restrictive limits. An attempt to set the niceness -+outside the supported range is treated as an attempt to use the -+minimum or maximum supported value. -+ -+A niceness should not be confused with a scheduling priority, which -+lets applications determine the order in which threads are scheduled -+to run. Unlike a priority, a niceness is merely advice to the -+scheduler, which the scheduler is free to ignore. Also, as a point of -+terminology, @acronym{POSIX} defines the behavior of @command{nice} in -+terms of a @dfn{nice value}, which is the nonnegative difference -+between a niceness and the minimum niceness. Though @command{nice} -+conforms to @acronym{POSIX}, its documentation and diagnostics use the -+term ``niceness'' for compatibility with historical practice. -+ -+@var{command} must not be a special built-in utility (@pxref{Special -+built-in utilities}). -+ -+@mayConflictWithShellBuiltIn{nice} -+ -+The program accepts the following option. Also see @ref{Common options}. -+Options must precede operands. -+ -+@table @samp -+@item -n @var{adjustment} -+@itemx --adjustment=@var{adjustment} -+@opindex -n -+@opindex --adjustment -+Add @var{adjustment} instead of 10 to the command's niceness. If -+@var{adjustment} is negative and you lack appropriate privileges, -+@command{nice} issues a warning but otherwise acts as if you specified -+a zero adjustment. -+ -+For compatibility @command{nice} also supports an obsolete -+option syntax @option{-@var{adjustment}}. New scripts should use -+@option{-n @var{adjustment}} instead. -+ -+@end table -+ -+@cindex exit status of @command{nice} -+Exit status: -+ -+@display -+0 if no @var{command} is specified and the niceness is output -+1 if @command{nice} itself fails -+126 if @var{command} is found but cannot be invoked -+127 if @var{command} cannot be found -+the exit status of @var{command} otherwise -+@end display -+ -+It is sometimes useful to run a non-interactive program with reduced niceness. -+ -+@example -+$ nice factor 4611686018427387903 -+@end example -+ -+Since @command{nice} prints the current niceness, -+you can invoke it through itself to demonstrate how it works. -+ -+The default behavior is to increase the niceness by @samp{10}: -+ -+@example -+$ nice -+0 -+$ nice nice -+10 -+$ nice -n 10 nice -+10 -+@end example -+ -+The @var{adjustment} is relative to the current niceness. In the -+next example, the first @command{nice} invocation runs the second one -+with niceness 10, and it in turn runs the final one with a niceness -+that is 3 more: -+ -+@example -+$ nice nice -n 3 nice -+13 -+@end example -+ -+Specifying a niceness larger than the supported range -+is the same as specifying the maximum supported value: -+ -+@example -+$ nice -n 10000000000 nice -+19 -+@end example -+ -+Only a privileged user may run a process with lower niceness: -+ -+@example -+$ nice -n -1 nice -+nice: cannot set niceness: Permission denied -+0 -+$ sudo nice -n -1 nice -+-1 -+@end example -+ -+ -+@node nohup invocation -+@section @command{nohup}: Run a command immune to hangups -+ -+@pindex nohup -+@cindex hangups, immunity to -+@cindex immunity to hangups -+@cindex logging out and continuing to run -+ -+@flindex nohup.out -+@command{nohup} runs the given @var{command} with hangup signals ignored, -+so that the command can continue running in the background after you log -+out. Synopsis: -+ -+@example -+nohup @var{command} [@var{arg}]@dots{} -+@end example -+ -+If standard input is a terminal, it is redirected from -+@file{/dev/null} so that terminal sessions do not mistakenly consider -+the terminal to be used by the command. This is a @acronym{GNU} -+extension; programs intended to be portable to non-@acronym{GNU} hosts -+should use @samp{nohup @var{command} [@var{arg}]@dots{} make.log -+@end example -+ -+@command{nohup} does not automatically put the command it runs in the -+background; you must do that explicitly, by ending the command line -+with an @samp{&}. Also, @command{nohup} does not alter the -+niceness of @var{command}; use @command{nice} for that, -+e.g., @samp{nohup nice @var{command}}. -+ -+@var{command} must not be a special built-in utility (@pxref{Special -+built-in utilities}). -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. Options must precede operands. -+ -+@cindex exit status of @command{nohup} -+Exit status: -+ -+@display -+126 if @var{command} is found but cannot be invoked -+127 if @command{nohup} itself fails or if @var{command} cannot be found -+the exit status of @var{command} otherwise -+@end display -+ -+ -+@node stdbuf invocation -+@section @command{stdbuf}: Run a command with modified I/O stream buffering -+ -+@pindex stdbuf -+@cindex standard streams, buffering -+@cindex line buffered -+ -+@command{stdbuf} allows one to modify the buffering operations of the -+three standard I/O streams associated with a program. Synopsis: -+ -+@example -+stdbuf @var{option}@dots{} @var{command} -+@end example -+ -+Any additional @var{arg}s are passed as additional arguments to the -+@var{command}. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+ -+@item -i @var{mode} -+@itemx --input=@var{mode} -+@opindex -i -+@opindex --input -+Adjust the standard input stream buffering. -+ -+@item -o @var{mode} -+@itemx --output=@var{mode} -+@opindex -o -+@opindex --output -+Adjust the standard output stream buffering. -+ -+@item -e @var{mode} -+@itemx --error=@var{mode} -+@opindex -e -+@opindex --error -+Adjust the standard error stream buffering. -+ -+@end table -+ -+The @var{mode} can be specified as follows: -+ -+@table @samp -+ -+@item L -+Set the stream to line buffered mode. -+In this mode data is coalesced until a newline is output or -+input is read from any stream attached to a terminal device. -+This option is invalid with standard input. -+ -+@item 0 -+Disable buffering of the selected stream. -+In this mode data is output immediately and only the -+amount of data requested is read from input. -+ -+@item @var{size} -+Specify the size of the buffer to use in fully buffered mode. -+@multiplierSuffixesNoBlocks{size} -+ -+@end table -+ -+NOTE: If @var{command} adjusts the buffering of its standard streams -+(@command{tee} does for e.g.) then that will override corresponding settings -+changed by @command{stdbuf}. Also some filters (like @command{dd} and -+@command{cat} etc.) don't use streams for I/O, and are thus unaffected -+by @command{stdbuf} settings. -+ -+@cindex exit status of @command{stdbuf} -+Exit status: -+ -+@display -+125 if @command{stdbuf} itself fails -+126 if @var{command} is found but cannot be invoked -+127 if @var{command} cannot be found -+the exit status of @var{command} otherwise -+@end display -+ -+ -+@node su invocation -+@section @command{su}: Run a command with substitute user and group ID -+ -+@pindex su -+@cindex substitute user and group IDs -+@cindex user ID, switching -+@cindex super-user, becoming -+@cindex root, becoming -+ -+@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: -+ -+@example -+su [@var{option}]@dots{} [@var{user} [@var{arg}]@dots{}] -+@end example -+ -+@cindex passwd entry, and @command{su} shell -+@flindex /bin/sh -+@flindex /etc/passwd -+If no @var{user} is given, the default is @code{root}, the super-user. -+The shell to use is taken from @var{user}'s @code{passwd} entry, or -+@file{/bin/sh} if none is specified there. If @var{user} has a -+password, @command{su} prompts for the password unless run by a user with -+effective user ID of zero (the super-user). -+ -+@vindex HOME -+@vindex SHELL -+@vindex USER -+@vindex LOGNAME -+@cindex login shell -+By default, @command{su} does not change the current directory. -+It sets the environment variables @env{HOME} and @env{SHELL} -+from the password entry for @var{user}, and if @var{user} is not -+the super-user, sets @env{USER} and @env{LOGNAME} to @var{user}. -+By default, the shell is not a login shell. -+ -+Any additional @var{arg}s are passed as additional arguments to the -+shell. -+ -+@cindex @option{-su} -+GNU @command{su} does not treat @file{/bin/sh} or any other shells specially -+(e.g., by setting @code{argv[0]} to @option{-su}, passing @option{-c} only -+to certain shells, etc.). -+ -+@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. -+ -+The program accepts the following options. Also see @ref{Common options}. -+ -+@table @samp -+@item -c @var{command} -+@itemx --command=@var{command} -+@opindex -c -+@opindex --command -+Pass @var{command}, a single command line to run, to the shell with -+a @option{-c} option instead of starting an interactive shell. -+ -+@item -f -+@itemx --fast -+@opindex -f -+@opindex --fast -+@flindex .cshrc -+@cindex file name pattern expansion, disabled -+@cindex globbing, disabled -+Pass the @option{-f} option to the shell. This probably only makes sense -+if the shell run is @command{csh} or @command{tcsh}, for which the @option{-f} -+option prevents reading the startup file (@file{.cshrc}). With -+Bourne-like shells, the @option{-f} option disables file name pattern -+expansion (globbing), which is not likely to be useful. -+ -+@item - -+@itemx -l -+@itemx --login -+@opindex - -+@opindex -l -+@opindex --login -+@c other variables already indexed above -+@vindex TERM -+@vindex PATH -+@cindex login shell, creating -+Make the shell a login shell. This means the following. Unset all -+environment variables except @env{TERM}, @env{HOME}, and @env{SHELL} -+(which are set as described above), and @env{USER} and @env{LOGNAME} -+(which are set, even for the super-user, as described above), and set -+@env{PATH} to a compiled-in default value. Change to @var{user}'s home -+directory. Prepend @samp{-} to the shell's name, intended to make it -+read its login startup file(s). -+ -+@item -m -+@itemx -p -+@itemx --preserve-environment -+@opindex -m -+@opindex -p -+@opindex --preserve-environment -+@cindex environment, preserving -+@flindex /etc/shells -+@cindex restricted shell -+Do not change the environment variables @env{HOME}, @env{USER}, -+@env{LOGNAME}, or @env{SHELL}. Run the shell given in the environment -+variable @env{SHELL} instead of the shell from @var{user}'s passwd -+entry, unless the user running @command{su} is not the super-user and -+@var{user}'s shell is restricted. A @dfn{restricted shell} is one that -+is not listed in the file @file{/etc/shells}, or in a compiled-in list -+if that file does not exist. Parts of what this option does can be -+overridden by @option{--login} and @option{--shell}. -+ -+@item -s @var{shell} -+@itemx --shell=@var{shell} -+@opindex -s -+@opindex --shell -+Run @var{shell} instead of the shell from @var{user}'s passwd entry, -+unless the user running @command{su} is not the super-user and @var{user}'s -+shell is restricted (see @option{-m} just above). -+ -+@end table -+ -+@cindex exit status of @command{su} -+Exit status: -+ -+@display -+1 if @command{su} itself fails -+126 if subshell is found but cannot be invoked -+127 if subshell cannot be found -+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 timeout invocation -+@section @command{timeout}: Run a command with a time limit -+ -+@pindex timeout -+@cindex time limit -+@cindex run commands with bounded time -+ -+@command{timeout} runs the given @var{command} and kills it if it is -+still running after the specified time interval. Synopsis: -+ -+@example -+timeout [@var{option}] @var{number}[smhd] @var{command} [@var{arg}]@dots{} -+@end example -+ -+@cindex time units -+@var{number} is an integer followed by an optional unit; the default -+is seconds. The units are: -+ -+@table @samp -+@item s -+seconds -+@item m -+minutes -+@item h -+hours -+@item d -+days -+@end table -+ -+@var{command} must not be a special built-in utility (@pxref{Special -+built-in utilities}). -+ -+The program accepts the following option. Also see @ref{Common options}. -+Options must precede operands. -+ -+@table @samp -+@item -s @var{signal} -+@itemx --signal=@var{signal} -+@opindex -s -+@opindex --signal -+Send this @var{signal} to @var{command} on timeout, rather than the -+default @samp{TERM} signal. @var{signal} may be a name like @samp{HUP} -+or a number. Also see @xref{Signal specifications}. -+ -+@end table -+ -+@cindex exit status of @command{timeout} -+Exit status: -+ -+@display -+124 if @var{command} times out -+125 if @command{timeout} itself fails -+126 if @var{command} is found but cannot be invoked -+127 if @var{command} cannot be found -+the exit status of @var{command} otherwise -+@end display -+ -+ -+@node Process control -+@chapter Process control -+ -+@cindex processes, commands for controlling -+@cindex commands for controlling processes -+ -+@menu -+* kill invocation:: Sending a signal to processes. -+@end menu -+ -+ -+@node kill invocation -+@section @command{kill}: Send a signal to processes -+ -+@pindex kill -+@cindex send a signal to processes -+ -+The @command{kill} command sends a signal to processes, causing them -+to terminate or otherwise act upon receiving the signal in some way. -+Alternatively, it lists information about signals. Synopses: -+ -+@example -+kill [-s @var{signal} | --signal @var{signal} | -@var{signal}] @var{pid}@dots{} -+kill [-l | --list | -t | --table] [@var{signal}]@dots{} -+@end example -+ -+@mayConflictWithShellBuiltIn{kill} -+ -+The first form of the @command{kill} command sends a signal to all -+@var{pid} arguments. The default signal to send if none is specified -+is @samp{TERM}. The special signal number @samp{0} does not denote a -+valid signal, but can be used to test whether the @var{pid} arguments -+specify processes to which a signal could be sent. -+ -+If @var{pid} is positive, the signal is sent to the process with the -+process ID @var{pid}. If @var{pid} is zero, the signal is sent to all -+processes in the process group of the current process. If @var{pid} -+is @minus{}1, the signal is sent to all processes for which the user has -+permission to send a signal. If @var{pid} is less than @minus{}1, the signal -+is sent to all processes in the process group that equals the absolute -+value of @var{pid}. -+ -+If @var{pid} is not positive, a system-dependent set of system -+processes is excluded from the list of processes to which the signal -+is sent. -+ -+If a negative @var{pid} argument is desired as the first one, it -+should be preceded by @option{--}. However, as a common extension to -+@acronym{POSIX}, @option{--} is not required with @samp{kill -+-@var{signal} -@var{pid}}. The following commands are equivalent: -+ -+@example -+kill -15 -1 -+kill -TERM -1 -+kill -s TERM -- -1 -+kill -- -1 -+@end example -+ -+The first form of the @command{kill} command succeeds if every @var{pid} -+argument specifies at least one process that the signal was sent to. -+ -+The second form of the @command{kill} command lists signal information. -+Either the @option{-l} or @option{--list} option, or the @option{-t} -+or @option{--table} option must be specified. Without any -+@var{signal} argument, all supported signals are listed. The output -+of @option{-l} or @option{--list} is a list of the signal names, one -+per line; if @var{signal} is already a name, the signal number is -+printed instead. The output of @option{-t} or @option{--table} is a -+table of signal numbers, names, and descriptions. This form of the -+@command{kill} command succeeds if all @var{signal} arguments are valid -+and if there is no output error. -+ -+The @command{kill} command also supports the @option{--help} and -+@option{--version} options. @xref{Common options}. -+ -+A @var{signal} may be a signal name like @samp{HUP}, or a signal -+number like @samp{1}, or an exit status of a process terminated by the -+signal. A signal name can be given in canonical form or prefixed by -+@samp{SIG}. The case of the letters is ignored, except for the -+@option{-@var{signal}} option which must use upper case to avoid -+ambiguity with lower case option letters. For a list of supported -+signal names and numbers see @xref{Signal specifications}. -+ -+@node Delaying -+@chapter Delaying -+ -+@cindex delaying commands -+@cindex commands for delaying -+ -+@c Perhaps @command{wait} or other commands should be described here also? -+ -+@menu -+* sleep invocation:: Delay for a specified time. -+@end menu -+ -+ -+@node sleep invocation -+@section @command{sleep}: Delay for a specified time -+ -+@pindex sleep -+@cindex delay for a specified time -+ -+@command{sleep} pauses for an amount of time specified by the sum of -+the values of the command line arguments. -+Synopsis: -+ -+@example -+sleep @var{number}[smhd]@dots{} -+@end example -+ -+@cindex time units -+Each argument is a number followed by an optional unit; the default -+is seconds. The units are: -+ -+@table @samp -+@item s -+seconds -+@item m -+minutes -+@item h -+hours -+@item d -+days -+@end table -+ -+Historical implementations of @command{sleep} have required that -+@var{number} be an integer, and only accepted a single argument -+without a suffix. However, GNU @command{sleep} accepts -+arbitrary floating point numbers (using a period before any fractional -+digits). -+ -+The only options are @option{--help} and @option{--version}. @xref{Common -+options}. -+ -+@c sleep is a shell built-in at least with Solaris 11's /bin/sh -+@mayConflictWithShellBuiltIn{sleep} -+ -+@exitstatus -+ -+ -+@node Numeric operations -+@chapter Numeric operations -+ -+@cindex numeric operations -+These programs do numerically-related operations. -+ -+@menu -+* factor invocation:: Show factors of numbers. -+* seq invocation:: Print sequences of numbers. -+@end menu -+ -+ -+@node factor invocation -+@section @command{factor}: Print prime factors -+ -+@pindex factor -+@cindex prime factors -+ -+@command{factor} prints prime factors. Synopses: -+ -+@example -+factor [@var{number}]@dots{} -+factor @var{option} -+@end example -+ -+If no @var{number} is specified on the command line, @command{factor} reads -+numbers from standard input, delimited by newlines, tabs, or spaces. -+ -+The @command{factor} command supports only a small number of options: -+ -+@table @samp -+@item --help -+Print a short help on standard output, then exit without further -+processing. -+ -+@item --version -+Print the program version on standard output, then exit without further -+processing. -+@end table -+ -+Factoring the product of the eighth and ninth Mersenne primes -+takes about 30 milliseconds of CPU time on a 2.2 GHz Athlon. -+ -+@example -+M8=`echo 2^31-1|bc` ; M9=`echo 2^61-1|bc` -+/usr/bin/time -f '%U' factor $(echo "$M8 * $M9" | bc) -+4951760154835678088235319297: 2147483647 2305843009213693951 -+0.03 -+@end example -+ -+Similarly, factoring the eighth Fermat number @math{2^{256}+1} takes -+about 20 seconds on the same machine. -+ -+Factoring large prime numbers is, in general, hard. The Pollard Rho -+algorithm used by @command{factor} is particularly effective for -+numbers with relatively small factors. If you wish to factor large -+numbers which do not have small factors (for example, numbers which -+are the product of two large primes), other methods are far better. -+ -+If @command{factor} is built without using GNU MP, only -+single-precision arithmetic is available, and so large numbers -+(typically @math{2^{64}} and above) will not be supported. The single-precision -+code uses an algorithm which is designed for factoring smaller -+numbers. -+ -+@exitstatus -+ -+ -+@node seq invocation -+@section @command{seq}: Print numeric sequences -+ -+@pindex seq -+@cindex numeric sequences -+@cindex sequence of numbers -+ -+@command{seq} prints a sequence of numbers to standard output. Synopses: -+ -+@example -+seq [@var{option}]@dots{} @var{last} -+seq [@var{option}]@dots{} @var{first} @var{last} -+seq [@var{option}]@dots{} @var{first} @var{increment} @var{last} -+@end example -+ -+@command{seq} prints the numbers from @var{first} to @var{last} by -+@var{increment}. By default, each number is printed on a separate line. -+When @var{increment} is not specified, it defaults to @samp{1}, -+even when @var{first} is larger than @var{last}. -+@var{first} also defaults to @samp{1}. So @code{seq 1} prints -+@samp{1}, but @code{seq 0} and @code{seq 10 5} produce no output. -+Floating-point numbers -+may be specified (using a period before any fractional digits). -+ -+The program accepts the following options. Also see @ref{Common options}. -+Options must precede operands. -+ -+@table @samp -+@item -f @var{format} -+@itemx --format=@var{format} -+@opindex -f @var{format} -+@opindex --format=@var{format} -+@cindex formatting of numbers in @command{seq} -+Print all numbers using @var{format}. -+@var{format} must contain exactly one of the @samp{printf}-style -+floating point conversion specifications @samp{%a}, @samp{%e}, -+@samp{%f}, @samp{%g}, @samp{%A}, @samp{%E}, @samp{%F}, @samp{%G}. -+The @samp{%} may be followed by zero or more flags taken from the set -+@samp{-+#0 '}, then an optional width containing one or more digits, -+then an optional precision consisting of a @samp{.} followed by zero -+or more digits. @var{format} may also contain any number of @samp{%%} -+conversion specifications. All conversion specifications have the -+same meaning as with @samp{printf}. -+ -+The default format is derived from @var{first}, @var{step}, and -+@var{last}. If these all use a fixed point decimal representation, -+the default format is @samp{%.@var{p}f}, where @var{p} is the minimum -+precision that can represent the output numbers exactly. Otherwise, -+the default format is @samp{%g}. -+ -+@item -s @var{string} -+@itemx --separator=@var{string} -+@cindex separator for numbers in @command{seq} -+Separate numbers with @var{string}; default is a newline. -+The output always terminates with a newline. -+ -+@item -w -+@itemx --equal-width -+Print all numbers with the same width, by padding with leading zeros. -+@var{first}, @var{step}, and @var{last} should all use a fixed point -+decimal representation. -+(To have other kinds of padding, use @option{--format}). -+ -+@end table -+ -+You can get finer-grained control over output with @option{-f}: -+ -+@example -+$ seq -f '(%9.2E)' -9e5 1.1e6 1.3e6 -+(-9.00E+05) -+( 2.00E+05) -+( 1.30E+06) -+@end example -+ -+If you want hexadecimal integer output, you can use @command{printf} -+to perform the conversion: -+ -+@example -+$ printf '%x\n' `seq 1048575 1024 1050623` -+fffff -+1003ff -+1007ff -+@end example -+ -+For very long lists of numbers, use xargs to avoid -+system limitations on the length of an argument list: -+ -+@example -+$ seq 1000000 | xargs printf '%x\n' | tail -n 3 -+f423e -+f423f -+f4240 -+@end example -+ -+To generate octal output, use the printf @code{%o} format instead -+of @code{%x}. -+ -+On most systems, seq can produce whole-number output for values up to -+at least @math{2^{53}}. Larger integers are approximated. The details -+differ depending on your floating-point implementation, but a common -+case is that @command{seq} works with integers through @math{2^{64}}, -+and larger integers may not be numerically correct: -+ -+@example -+$ seq 18446744073709551616 1 18446744073709551618 -+18446744073709551616 -+18446744073709551616 -+18446744073709551618 -+@end example -+ -+Be careful when using @command{seq} with outlandish values: otherwise -+you may see surprising results, as @command{seq} uses floating point -+internally. For example, on the x86 platform, where the internal -+representation uses a 64-bit fraction, the command: -+ -+@example -+seq 1 0.0000000000000000001 1.0000000000000000009 -+@end example -+ -+outputs 1.0000000000000000007 twice and skips 1.0000000000000000008. -+ -+@exitstatus -+ -+ -+@node File permissions -+@chapter File permissions -+@include perm.texi -+ -+@include getdate.texi -+ -+@c What's GNU? -+@c Arnold Robbins -+@node Opening the software toolbox -+@chapter Opening the Software Toolbox -+ -+An earlier version of this chapter appeared in -+@uref{http://www.linuxjournal.com/article.php?sid=2762, the -+@cite{What's GNU?} column of @cite{Linux Journal}, 2 (June, 1994)}. -+It was written by Arnold Robbins. -+ -+@menu -+* Toolbox introduction:: Toolbox introduction -+* I/O redirection:: I/O redirection -+* The who command:: The @command{who} command -+* The cut command:: The @command{cut} command -+* The sort command:: The @command{sort} command -+* The uniq command:: The @command{uniq} command -+* Putting the tools together:: Putting the tools together -+@end menu -+ -+ -+@node Toolbox introduction -+@unnumberedsec Toolbox Introduction -+ -+This month's column is only peripherally related to the GNU Project, in -+that it describes a number of the GNU tools on your GNU/Linux system and how they -+might be used. What it's really about is the ``Software Tools'' philosophy -+of program development and usage. -+ -+The software tools philosophy was an important and integral concept -+in the initial design and development of Unix (of which Linux and GNU are -+essentially clones). Unfortunately, in the modern day press of -+Internetworking and flashy GUIs, it seems to have fallen by the -+wayside. This is a shame, since it provides a powerful mental model -+for solving many kinds of problems. -+ -+Many people carry a Swiss Army knife around in their pants pockets (or -+purse). A Swiss Army knife is a handy tool to have: it has several knife -+blades, a screwdriver, tweezers, toothpick, nail file, corkscrew, and perhaps -+a number of other things on it. For the everyday, small miscellaneous jobs -+where you need a simple, general purpose tool, it's just the thing. -+ -+On the other hand, an experienced carpenter doesn't build a house using -+a Swiss Army knife. Instead, he has a toolbox chock full of specialized -+tools---a saw, a hammer, a screwdriver, a plane, and so on. And he knows -+exactly when and where to use each tool; you won't catch him hammering nails -+with the handle of his screwdriver. -+ -+The Unix developers at Bell Labs were all professional programmers and trained -+computer scientists. They had found that while a one-size-fits-all program -+might appeal to a user because there's only one program to use, in practice -+such programs are -+ -+@enumerate a -+@item -+difficult to write, -+ -+@item -+difficult to maintain and -+debug, and -+ -+@item -+difficult to extend to meet new situations. -+@end enumerate -+ -+Instead, they felt that programs should be specialized tools. In short, each -+program ``should do one thing well.'' No more and no less. Such programs are -+simpler to design, write, and get right---they only do one thing. -+ -+Furthermore, they found that with the right machinery for hooking programs -+together, that the whole was greater than the sum of the parts. By combining -+several special purpose programs, you could accomplish a specific task -+that none of the programs was designed for, and accomplish it much more -+quickly and easily than if you had to write a special purpose program. -+We will see some (classic) examples of this further on in the column. -+(An important additional point was that, if necessary, take a detour -+and build any software tools you may need first, if you don't already -+have something appropriate in the toolbox.) -+ -+@node I/O redirection -+@unnumberedsec I/O Redirection -+ -+Hopefully, you are familiar with the basics of I/O redirection in the -+shell, in particular the concepts of ``standard input,'' ``standard output,'' -+and ``standard error''. Briefly, ``standard input'' is a data source, where -+data comes from. A program should not need to either know or care if the -+data source is a disk file, a keyboard, a magnetic tape, or even a punched -+card reader. Similarly, ``standard output'' is a data sink, where data goes -+to. The program should neither know nor care where this might be. -+Programs that only read their standard input, do something to the data, -+and then send it on, are called @dfn{filters}, by analogy to filters in a -+water pipeline. -+ -+With the Unix shell, it's very easy to set up data pipelines: -+ -+@smallexample -+program_to_create_data | filter1 | ... | filterN > final.pretty.data -+@end smallexample -+ -+We start out by creating the raw data; each filter applies some successive -+transformation to the data, until by the time it comes out of the pipeline, -+it is in the desired form. -+ -+This is fine and good for standard input and standard output. Where does the -+standard error come in to play? Well, think about @command{filter1} in -+the pipeline above. What happens if it encounters an error in the data it -+sees? If it writes an error message to standard output, it will just -+disappear down the pipeline into @command{filter2}'s input, and the -+user will probably never see it. So programs need a place where they can send -+error messages so that the user will notice them. This is standard error, -+and it is usually connected to your console or window, even if you have -+redirected standard output of your program away from your screen. -+ -+For filter programs to work together, the format of the data has to be -+agreed upon. The most straightforward and easiest format to use is simply -+lines of text. Unix data files are generally just streams of bytes, with -+lines delimited by the @acronym{ASCII} @sc{lf} (Line Feed) character, -+conventionally called a ``newline'' in the Unix literature. (This is -+@code{'\n'} if you're a C programmer.) This is the format used by all -+the traditional filtering programs. (Many earlier operating systems -+had elaborate facilities and special purpose programs for managing -+binary data. Unix has always shied away from such things, under the -+philosophy that it's easiest to simply be able to view and edit your -+data with a text editor.) -+ -+OK, enough introduction. Let's take a look at some of the tools, and then -+we'll see how to hook them together in interesting ways. In the following -+discussion, we will only present those command line options that interest -+us. As you should always do, double check your system documentation -+for the full story. -+ -+@node The who command -+@unnumberedsec The @command{who} Command -+ -+The first program is the @command{who} command. By itself, it generates a -+list of the users who are currently logged in. Although I'm writing -+this on a single-user system, we'll pretend that several people are -+logged in: -+ -+@example -+$ who -+@print{} arnold console Jan 22 19:57 -+@print{} miriam ttyp0 Jan 23 14:19(:0.0) -+@print{} bill ttyp1 Jan 21 09:32(:0.0) -+@print{} arnold ttyp2 Jan 23 20:48(:0.0) -+@end example -+ -+Here, the @samp{$} is the usual shell prompt, at which I typed @samp{who}. -+There are three people logged in, and I am logged in twice. On traditional -+Unix systems, user names are never more than eight characters long. This -+little bit of trivia will be useful later. The output of @command{who} is nice, -+but the data is not all that exciting. -+ -+@node The cut command -+@unnumberedsec The @command{cut} Command -+ -+The next program we'll look at is the @command{cut} command. This program -+cuts out columns or fields of input data. For example, we can tell it -+to print just the login name and full name from the @file{/etc/passwd} -+file. The @file{/etc/passwd} file has seven fields, separated by -+colons: -+ -+@example -+arnold:xyzzy:2076:10:Arnold D. Robbins:/home/arnold:/bin/bash -+@end example -+ -+To get the first and fifth fields, we would use @command{cut} like this: -+ -+@example -+$ cut -d: -f1,5 /etc/passwd -+@print{} root:Operator -+@dots{} -+@print{} arnold:Arnold D. Robbins -+@print{} miriam:Miriam A. Robbins -+@dots{} -+@end example -+ -+With the @option{-c} option, @command{cut} will cut out specific characters -+(i.e., columns) in the input lines. This is useful for input data -+that has fixed width fields, and does not have a field separator. For -+example, list the Monday dates for the current month: -+ -+@c Is using cal ok? Looked at gcal, but I don't like it. -+@example -+$ cal | cut -c 3-5 -+@print{}Mo -+@print{} -+@print{} 6 -+@print{} 13 -+@print{} 20 -+@print{} 27 -+@end example -+ -+@node The sort command -+@unnumberedsec The @command{sort} Command -+ -+Next we'll look at the @command{sort} command. This is one of the most -+powerful commands on a Unix-style system; one that you will often find -+yourself using when setting up fancy data plumbing. -+ -+The @command{sort} -+command reads and sorts each file named on the command line. It then -+merges the sorted data and writes it to standard output. It will read -+standard input if no files are given on the command line (thus -+making it into a filter). The sort is based on the character collating -+sequence or based on user-supplied ordering criteria. -+ -+ -+@node The uniq command -+@unnumberedsec The @command{uniq} Command -+ -+Finally (at least for now), we'll look at the @command{uniq} program. When -+sorting data, you will often end up with duplicate lines, lines that -+are identical. Usually, all you need is one instance of each line. -+This is where @command{uniq} comes in. The @command{uniq} program reads its -+standard input. It prints only one -+copy of each repeated line. It does have several options. Later on, -+we'll use the @option{-c} option, which prints each unique line, preceded -+by a count of the number of times that line occurred in the input. -+ -+ -+@node Putting the tools together -+@unnumberedsec Putting the Tools Together -+ -+Now, let's suppose this is a large ISP server system with dozens of users -+logged in. The management wants the system administrator to write a program that will -+generate a sorted list of logged in users. Furthermore, even if a user -+is logged in multiple times, his or her name should only show up in the -+output once. -+ -+The administrator could sit down with the system documentation and write a C -+program that did this. It would take perhaps a couple of hundred lines -+of code and about two hours to write it, test it, and debug it. -+However, knowing the software toolbox, the administrator can instead start out -+by generating just a list of logged on users: -+ -+@example -+$ who | cut -c1-8 -+@print{} arnold -+@print{} miriam -+@print{} bill -+@print{} arnold -+@end example -+ -+Next, sort the list: -+ -+@example -+$ who | cut -c1-8 | sort -+@print{} arnold -+@print{} arnold -+@print{} bill -+@print{} miriam -+@end example -+ -+Finally, run the sorted list through @command{uniq}, to weed out duplicates: -+ -+@example -+$ who | cut -c1-8 | sort | uniq -+@print{} arnold -+@print{} bill -+@print{} miriam -+@end example -+ -+The @command{sort} command actually has a @option{-u} option that does what -+@command{uniq} does. However, @command{uniq} has other uses for which one -+cannot substitute @samp{sort -u}. -+ -+The administrator puts this pipeline into a shell script, and makes it available for -+all the users on the system (@samp{#} is the system administrator, -+or @code{root}, prompt): -+ -+@example -+# cat > /usr/local/bin/listusers -+who | cut -c1-8 | sort | uniq -+^D -+# chmod +x /usr/local/bin/listusers -+@end example -+ -+There are four major points to note here. First, with just four -+programs, on one command line, the administrator was able to save about two -+hours worth of work. Furthermore, the shell pipeline is just about as -+efficient as the C program would be, and it is much more efficient in -+terms of programmer time. People time is much more expensive than -+computer time, and in our modern ``there's never enough time to do -+everything'' society, saving two hours of programmer time is no mean -+feat. -+ -+Second, it is also important to emphasize that with the -+@emph{combination} of the tools, it is possible to do a special -+purpose job never imagined by the authors of the individual programs. -+ -+Third, it is also valuable to build up your pipeline in stages, as we did here. -+This allows you to view the data at each stage in the pipeline, which helps -+you acquire the confidence that you are indeed using these tools correctly. -+ -+Finally, by bundling the pipeline in a shell script, other users can use -+your command, without having to remember the fancy plumbing you set up for -+them. In terms of how you run them, shell scripts and compiled programs are -+indistinguishable. -+ -+After the previous warm-up exercise, we'll look at two additional, more -+complicated pipelines. For them, we need to introduce two more tools. -+ -+The first is the @command{tr} command, which stands for ``transliterate.'' -+The @command{tr} command works on a character-by-character basis, changing -+characters. Normally it is used for things like mapping upper case to -+lower case: -+ -+@example -+$ echo ThIs ExAmPlE HaS MIXED case! | tr '[:upper:]' '[:lower:]' -+@print{} this example has mixed case! -+@end example -+ -+There are several options of interest: -+ -+@table @code -+@item -c -+work on the complement of the listed characters, i.e., -+operations apply to characters not in the given set -+ -+@item -d -+delete characters in the first set from the output -+ -+@item -s -+squeeze repeated characters in the output into just one character. -+@end table -+ -+We will be using all three options in a moment. -+ -+The other command we'll look at is @command{comm}. The @command{comm} -+command takes two sorted input files as input data, and prints out the -+files' lines in three columns. The output columns are the data lines -+unique to the first file, the data lines unique to the second file, and -+the data lines that are common to both. The @option{-1}, @option{-2}, and -+@option{-3} command line options @emph{omit} the respective columns. (This is -+non-intuitive and takes a little getting used to.) For example: -+ -+@example -+$ cat f1 -+@print{} 11111 -+@print{} 22222 -+@print{} 33333 -+@print{} 44444 -+$ cat f2 -+@print{} 00000 -+@print{} 22222 -+@print{} 33333 -+@print{} 55555 -+$ comm f1 f2 -+@print{} 00000 -+@print{} 11111 -+@print{} 22222 -+@print{} 33333 -+@print{} 44444 -+@print{} 55555 -+@end example -+ -+The file name @file{-} tells @command{comm} to read standard input -+instead of a regular file. -+ -+Now we're ready to build a fancy pipeline. The first application is a word -+frequency counter. This helps an author determine if he or she is over-using -+certain words. -+ -+The first step is to change the case of all the letters in our input file -+to one case. ``The'' and ``the'' are the same word when doing counting. -+ -+@example -+$ tr '[:upper:]' '[:lower:]' < whats.gnu | ... -+@end example -+ -+The next step is to get rid of punctuation. Quoted words and unquoted words -+should be treated identically; it's easiest to just get the punctuation out of -+the way. -+ -+@smallexample -+$ tr '[:upper:]' '[:lower:]' < whats.gnu | tr -cd '[:alnum:]_ \n' | ... -+@end smallexample -+ -+The second @command{tr} command operates on the complement of the listed -+characters, which are all the letters, the digits, the underscore, and -+the blank. The @samp{\n} represents the newline character; it has to -+be left alone. (The @acronym{ASCII} tab character should also be included for -+good measure in a production script.) -+ -+At this point, we have data consisting of words separated by blank space. -+The words only contain alphanumeric characters (and the underscore). The -+next step is break the data apart so that we have one word per line. This -+makes the counting operation much easier, as we will see shortly. -+ -+@smallexample -+$ tr '[:upper:]' '[:lower:]' < whats.gnu | tr -cd '[:alnum:]_ \n' | -+> tr -s ' ' '\n' | ... -+@end smallexample -+ -+This command turns blanks into newlines. The @option{-s} option squeezes -+multiple newline characters in the output into just one. This helps us -+avoid blank lines. (The @samp{>} is the shell's ``secondary prompt.'' -+This is what the shell prints when it notices you haven't finished -+typing in all of a command.) -+ -+We now have data consisting of one word per line, no punctuation, all one -+case. We're ready to count each word: -+ -+@smallexample -+$ tr '[:upper:]' '[:lower:]' < whats.gnu | tr -cd '[:alnum:]_ \n' | -+> tr -s ' ' '\n' | sort | uniq -c | ... -+@end smallexample -+ -+At this point, the data might look something like this: -+ -+@example -+ 60 a -+ 2 able -+ 6 about -+ 1 above -+ 2 accomplish -+ 1 acquire -+ 1 actually -+ 2 additional -+@end example -+ -+The output is sorted by word, not by count! What we want is the most -+frequently used words first. Fortunately, this is easy to accomplish, -+with the help of two more @command{sort} options: -+ -+@table @code -+@item -n -+do a numeric sort, not a textual one -+ -+@item -r -+reverse the order of the sort -+@end table -+ -+The final pipeline looks like this: -+ -+@smallexample -+$ tr '[:upper:]' '[:lower:]' < whats.gnu | tr -cd '[:alnum:]_ \n' | -+> tr -s ' ' '\n' | sort | uniq -c | sort -n -r -+@print{} 156 the -+@print{} 60 a -+@print{} 58 to -+@print{} 51 of -+@print{} 51 and -+@dots{} -+@end smallexample -+ -+Whew! That's a lot to digest. Yet, the same principles apply. With six -+commands, on two lines (really one long one split for convenience), we've -+created a program that does something interesting and useful, in much -+less time than we could have written a C program to do the same thing. -+ -+A minor modification to the above pipeline can give us a simple spelling -+checker! To determine if you've spelled a word correctly, all you have to -+do is look it up in a dictionary. If it is not there, then chances are -+that your spelling is incorrect. So, we need a dictionary. -+The conventional location for a dictionary is @file{/usr/dict/words}. -+On my GNU/Linux system,@footnote{Redhat Linux 6.1, for the November 2000 -+revision of this article.} -+this is a sorted, 45,402 word dictionary. -+ -+Now, how to compare our file with the dictionary? As before, we generate -+a sorted list of words, one per line: -+ -+@smallexample -+$ tr '[:upper:]' '[:lower:]' < whats.gnu | tr -cd '[:alnum:]_ \n' | -+> tr -s ' ' '\n' | sort -u | ... -+@end smallexample -+ -+Now, all we need is a list of words that are @emph{not} in the -+dictionary. Here is where the @command{comm} command comes in. -+ -+@smallexample -+$ tr '[:upper:]' '[:lower:]' < whats.gnu | tr -cd '[:alnum:]_ \n' | -+> tr -s ' ' '\n' | sort -u | -+> comm -23 - /usr/dict/words -+@end smallexample -+ -+The @option{-2} and @option{-3} options eliminate lines that are only in the -+dictionary (the second file), and lines that are in both files. Lines -+only in the first file (standard input, our stream of words), are -+words that are not in the dictionary. These are likely candidates for -+spelling errors. This pipeline was the first cut at a production -+spelling checker on Unix. -+ -+There are some other tools that deserve brief mention. -+ -+@table @command -+@item grep -+search files for text that matches a regular expression -+ -+@item wc -+count lines, words, characters -+ -+@item tee -+a T-fitting for data pipes, copies data to files and to standard output -+ -+@item sed -+the stream editor, an advanced tool -+ -+@item awk -+a data manipulation language, another advanced tool -+@end table -+ -+The software tools philosophy also espoused the following bit of -+advice: ``Let someone else do the hard part.'' This means, take -+something that gives you most of what you need, and then massage it the -+rest of the way until it's in the form that you want. -+ -+To summarize: -+ -+@enumerate 1 -+@item -+Each program should do one thing well. No more, no less. -+ -+@item -+Combining programs with appropriate plumbing leads to results where -+the whole is greater than the sum of the parts. It also leads to novel -+uses of programs that the authors might never have imagined. -+ -+@item -+Programs should never print extraneous header or trailer data, since these -+could get sent on down a pipeline. (A point we didn't mention earlier.) -+ -+@item -+Let someone else do the hard part. -+ -+@item -+Know your toolbox! Use each program appropriately. If you don't have an -+appropriate tool, build one. -+@end enumerate -+ -+As of this writing, all the programs we've discussed are available via -+anonymous @command{ftp} from: @* -+@uref{ftp://gnudist.gnu.org/textutils/textutils-1.22.tar.gz}. (There may -+be more recent versions available now.) -+ -+None of what I have presented in this column is new. The Software Tools -+philosophy was first introduced in the book @cite{Software Tools}, by -+Brian Kernighan and P.J. Plauger (Addison-Wesley, ISBN 0-201-03669-X). -+This book showed how to write and use software tools. It was written in -+1976, using a preprocessor for FORTRAN named @command{ratfor} (RATional -+FORtran). At the time, C was not as ubiquitous as it is now; FORTRAN -+was. The last chapter presented a @command{ratfor} to FORTRAN -+processor, written in @command{ratfor}. @command{ratfor} looks an awful -+lot like C; if you know C, you won't have any problem following the -+code. -+ -+In 1981, the book was updated and made available as @cite{Software Tools -+in Pascal} (Addison-Wesley, ISBN 0-201-10342-7). Both books are -+still in print and are well worth -+reading if you're a programmer. They certainly made a major change in -+how I view programming. -+ -+The programs in both books are available from -+@uref{http://cm.bell-labs.com/who/bwk, Brian Kernighan's home page}. -+For a number of years, there was an active -+Software Tools Users Group, whose members had ported the original -+@command{ratfor} programs to essentially every computer system with a -+FORTRAN compiler. The popularity of the group waned in the middle 1980s -+as Unix began to spread beyond universities. -+ -+With the current proliferation of GNU code and other clones of Unix programs, -+these programs now receive little attention; modern C versions are -+much more efficient and do more than these programs do. Nevertheless, as -+exposition of good programming style, and evangelism for a still-valuable -+philosophy, these books are unparalleled, and I recommend them highly. -+ -+Acknowledgment: I would like to express my gratitude to Brian Kernighan -+of Bell Labs, the original Software Toolsmith, for reviewing this column. -+ -+@node GNU Free Documentation License -+@appendix GNU Free Documentation License -+ -+@include fdl.texi -+ -+@node Concept index -+@unnumbered Index -+ -+@printindex cp -+ -+@bye + 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}.) + -+@c Local variables: -+@c texinfo-column-for-description: 32 -+@c End: ++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}. + +@@ -14785,6 +14788,8 @@ environment variables except @env{TERM}, + @env{PATH} to a compiled-in default value. Change to @var{user}'s home + directory. Prepend @samp{-} to the shell's name, intended to make it + read its login startup file(s). ++Additionaly @env{DISPLAY} and @env{XAUTHORITY} environment variables ++are preserved as well for PAM functionality. + + @item -m + @itemx -p +@@ -14824,33 +14829,6 @@ Exit status: + 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 timeout invocation + @section @command{timeout}: Run a command with a time limit + diff -urNp coreutils-8.0-orig/src/Makefile.am coreutils-8.0/src/Makefile.am --- coreutils-8.0-orig/src/Makefile.am 2009-09-21 14:29:33.000000000 +0200 +++ coreutils-8.0/src/Makefile.am 2009-10-07 10:04:27.000000000 +0200 @@ -16369,490 +87,6 @@ diff -urNp coreutils-8.0-orig/src/Makefile.am coreutils-8.0/src/Makefile.am dir_LDADD += $(LIB_ACL) ls_LDADD += $(LIB_ACL) -diff -urNp coreutils-8.0-orig/src/Makefile.am.orig coreutils-8.0/src/Makefile.am.orig ---- coreutils-8.0-orig/src/Makefile.am.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/Makefile.am.orig 2009-09-21 14:29:33.000000000 +0200 -@@ -0,0 +1,480 @@ -+## Process this file with automake to produce Makefile.in -*-Makefile-*- -+ -+## Copyright (C) 1990, 1991, 1993-2009 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 . -+ -+# These are the names of programs that are not installed by default. -+# This list is *not* intended for programs like who, nice, chroot, etc., -+# that are built only when certain requisite system features are detected. -+# Hence, if you want to install programs from this list anyway, say A and B, -+# use --enable-install-program=A,B -+no_install__progs = \ -+ arch hostname su -+ -+build_if_possible__progs = \ -+ chroot df hostid nice pinky stdbuf libstdbuf.so stty su uname uptime users who -+ -+AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) -+ -+EXTRA_PROGRAMS = \ -+ $(no_install__progs) \ -+ $(build_if_possible__progs) \ -+ [ chcon chgrp chown chmod cp dd dircolors du \ -+ ginstall link ln dir vdir ls mkdir \ -+ mkfifo mknod mktemp \ -+ mv nohup readlink rm rmdir shred stat sync touch unlink \ -+ cat cksum comm csplit cut expand fmt fold head join groups 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 \ -+ id kill logname pathchk printenv printf pwd \ -+ runcon seq sleep tee \ -+ test timeout true truncate tty whoami yes \ -+ base64 -+ -+bin_PROGRAMS = $(OPTIONAL_BIN_PROGS) -+ -+noinst_PROGRAMS = setuidgid getlimits -+ -+pkglib_PROGRAMS = $(OPTIONAL_PKGLIB_PROGS) -+ -+noinst_HEADERS = \ -+ chown-core.h \ -+ copy.h \ -+ cp-hash.h \ -+ dircolors.h \ -+ fs.h \ -+ group-list.h \ -+ ls.h \ -+ operand2sig.h \ -+ prog-fprintf.h \ -+ remove.h \ -+ system.h \ -+ wheel-size.h \ -+ wheel.h \ -+ uname.h -+ -+EXTRA_DIST = dcgen dircolors.hin tac-pipe.c \ -+ wheel-gen.pl extract-magic c99-to-c89.diff -+BUILT_SOURCES = -+CLEANFILES = $(SCRIPTS) su -+ -+# Also remove these sometimes-built programs. -+# For example, even when excluded, they're built via sc_check-AUTHORS. -+CLEANFILES += $(no_install__progs) -+ -+AM_CPPFLAGS = -I$(top_srcdir)/lib -+ -+noinst_LIBRARIES = libver.a -+nodist_libver_a_SOURCES = version.c version.h -+ -+# Sometimes, the expansion of $(LIBINTL) includes -lc which may -+# include modules defining variables like `optind', so libcoreutils.a -+# must precede $(LIBINTL) in order to ensure we use GNU getopt. -+# But libcoreutils.a must also follow $(LIBINTL), since libintl uses -+# replacement functions defined in libcoreutils.a. -+LDADD = libver.a ../lib/libcoreutils.a $(LIBINTL) ../lib/libcoreutils.a -+ -+cat_LDADD = $(LDADD) -+df_LDADD = $(LDADD) -+du_LDADD = $(LDADD) -+getlimits_LDADD = $(LDADD) -+ptx_LDADD = $(LDADD) -+split_LDADD = $(LDADD) -+stdbuf_LDADD = $(LDADD) -+timeout_LDADD = $(LDADD) -+truncate_LDADD = $(LDADD) -+ -+# for eaccess in lib/euidaccess.c. -+chcon_LDADD = $(LDADD) $(LIB_SELINUX) -+cp_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX) -+ginstall_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX) -+mkdir_LDADD = $(LDADD) $(LIB_SELINUX) -+mkfifo_LDADD = $(LDADD) $(LIB_SELINUX) -+mknod_LDADD = $(LDADD) $(LIB_SELINUX) -+mv_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX) -+runcon_LDADD = $(LDADD) $(LIB_SELINUX) -+pathchk_LDADD = $(LDADD) $(LIB_EACCESS) -+rm_LDADD = $(LDADD) $(LIB_EACCESS) -+test_LDADD = $(LDADD) $(LIB_EACCESS) -+# This is for the '[' program. Automake transliterates '[' to '_'. -+__LDADD = $(LDADD) $(LIB_EACCESS) -+ -+# for clock_gettime and fdatasync -+dd_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC) -+dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX) $(LIB_CAP) -+id_LDADD = $(LDADD) $(LIB_SELINUX) -+ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX) $(LIB_CAP) -+mktemp_LDADD = $(LDADD) $(LIB_GETHRXTIME) -+pr_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -+shred_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC) -+shuf_LDADD = $(LDADD) $(LIB_GETHRXTIME) -+tac_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -+vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX) $(LIB_CAP) -+ -+## If necessary, add -lm to resolve use of pow in lib/strtod.c. -+sort_LDADD = $(LDADD) $(POW_LIB) $(LIB_GETHRXTIME) -+ -+# for get_date and gettime -+date_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -+touch_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -+ -+# If necessary, add -lm to resolve use of pow in lib/strtod.c. -+# If necessary, add -liconv to resolve use of iconv in lib/unicodeio.c. -+printf_LDADD = $(LDADD) $(POW_LIB) $(LIBICONV) -+ -+# If necessary, add -lm to resolve use of pow in lib/strtod.c. -+seq_LDADD = $(LDADD) $(POW_LIB) -+ -+# If necessary, add libraries to resolve the `pow' reference in lib/strtod.c -+# and the `nanosleep' reference in lib/xnanosleep.c. -+nanosec_libs = $(LDADD) $(POW_LIB) $(LIB_NANOSLEEP) -+ -+# for various GMP functions -+expr_LDADD = $(LDADD) $(LIB_GMP) -+ -+# for various GMP functions -+factor_LDADD = $(LDADD) $(LIB_GMP) -+ -+sleep_LDADD = $(nanosec_libs) -+tail_LDADD = $(nanosec_libs) -+ -+# 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) -+ -+dir_LDADD += $(LIB_ACL) -+ls_LDADD += $(LIB_ACL) -+vdir_LDADD += $(LIB_ACL) -+cp_LDADD += $(LIB_ACL) $(LIB_XATTR) -+mv_LDADD += $(LIB_ACL) $(LIB_XATTR) -+ginstall_LDADD += $(LIB_ACL) $(LIB_XATTR) -+ -+stat_LDADD = $(LDADD) $(LIB_SELINUX) -+ -+# Append $(LIBICONV) to each program that uses proper_name_utf8. -+cat_LDADD += $(LIBICONV) -+cp_LDADD += $(LIBICONV) -+df_LDADD += $(LIBICONV) -+du_LDADD += $(LIBICONV) -+getlimits_LDADD += $(LIBICONV) -+ptx_LDADD += $(LIBICONV) -+split_LDADD += $(LIBICONV) -+stdbuf_LDADD += $(LIBICONV) -+timeout_LDADD += $(LIBICONV) -+truncate_LDADD += $(LIBICONV) -+ -+# programs that use getaddrinfo (e.g., via canon_host) -+pinky_LDADD = $(LDADD) $(GETADDRINFO_LIB) -+who_LDADD = $(LDADD) $(GETADDRINFO_LIB) -+ -+$(PROGRAMS): ../lib/libcoreutils.a -+ -+# Get the release year from ../lib/version-etc.c. -+RELEASE_YEAR = \ -+ `sed -n '/.*COPYRIGHT_YEAR = \([0-9][0-9][0-9][0-9]\) };/s//\1/p' \ -+ $(top_srcdir)/lib/version-etc.c` -+ -+all-local: su$(EXEEXT) -+ -+installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` -+ -+setuid_root_mode = a=rx,u+s -+ -+install_su = \ -+ if test "$(INSTALL_SU)" = yes; then \ -+ p=su; \ -+ echo " $(INSTALL_PROGRAM) $$p $(installed_su)"; \ -+ $(INSTALL_PROGRAM) $$p $(installed_su); \ -+ echo " chown root $(installed_su)"; \ -+ chown root $(installed_su); \ -+ echo " chmod $(setuid_root_mode) $(installed_su)"; \ -+ chmod $(setuid_root_mode) $(installed_su); \ -+ else \ -+ :; \ -+ fi -+ -+install-root: su$(EXEEXT) -+ @$(install_su) -+ -+install-exec-hook: su$(EXEEXT) -+ @if test "$(INSTALL_SU)" = yes; then \ -+ TMPFILE=$(DESTDIR)$(bindir)/.su-$$$$; \ -+ rm -f $$TMPFILE; \ -+ echo > $$TMPFILE; \ -+## See if we can create a setuid root executable in $(bindir). -+## If not, then don't even try to install su. -+ can_create_suid_root_executable=no; \ -+ chown root $$TMPFILE > /dev/null 2>&1 \ -+ && chmod $(setuid_root_mode) $$TMPFILE > /dev/null 2>&1 \ -+ && can_create_suid_root_executable=yes; \ -+ rm -f $$TMPFILE; \ -+ if test $$can_create_suid_root_executable = yes; then \ -+ $(install_su); \ -+ else \ -+ echo "WARNING: insufficient access; not installing su"; \ -+ echo "NOTE: to install su, run 'make install-root' as root"; \ -+ rm -f $(installed_su); \ -+ fi; \ -+ else :; \ -+ fi -+ -+uninstall-local: -+# Remove su only if it's one we installed. -+ @if test "$(INSTALL_SU)" = yes; then \ -+ if grep '$(PACKAGE_NAME)' $(installed_su) > /dev/null 2>&1; then \ -+ echo " rm -f $(installed_su)"; \ -+ rm -f $(installed_su); \ -+ else :; \ -+ fi; \ -+ fi -+ -+copy_sources = copy.c cp-hash.c -+ -+# Use `ginstall' in the definition of PROGRAMS and in dependencies to avoid -+# confusion with the `install' target. The install rule transforms `ginstall' -+# to install before applying any user-specified name transformations. -+ -+transform = s/ginstall/install/; $(program_transform_name) -+ginstall_SOURCES = install.c prog-fprintf.c $(copy_sources) -+ -+# This is for the '[' program. Automake transliterates '[' to '_'. -+__SOURCES = lbracket.c -+ -+cp_SOURCES = cp.c $(copy_sources) -+dir_SOURCES = ls.c ls-dir.c -+vdir_SOURCES = ls.c ls-vdir.c -+id_SOURCES = id.c group-list.c -+groups_SOURCES = groups.c group-list.c -+ln_SOURCES = ln.c -+ls_SOURCES = ls.c ls-ls.c -+chown_SOURCES = chown.c chown-core.c -+chgrp_SOURCES = chgrp.c chown-core.c -+kill_SOURCES = kill.c operand2sig.c -+timeout_SOURCES = timeout.c operand2sig.c -+ -+mv_SOURCES = mv.c remove.c $(copy_sources) -+rm_SOURCES = rm.c remove.c -+ -+mkdir_SOURCES = mkdir.c prog-fprintf.c -+rmdir_SOURCES = rmdir.c prog-fprintf.c -+ -+uname_SOURCES = uname.c uname-uname.c -+arch_SOURCES = uname.c uname-arch.c -+ -+md5sum_SOURCES = md5sum.c -+md5sum_CPPFLAGS = -DHASH_ALGO_MD5=1 $(AM_CPPFLAGS) -+sha1sum_SOURCES = md5sum.c -+sha1sum_CPPFLAGS = -DHASH_ALGO_SHA1=1 $(AM_CPPFLAGS) -+sha224sum_SOURCES = md5sum.c -+sha224sum_CPPFLAGS = -DHASH_ALGO_SHA224=1 $(AM_CPPFLAGS) -+sha256sum_SOURCES = md5sum.c -+sha256sum_CPPFLAGS = -DHASH_ALGO_SHA256=1 $(AM_CPPFLAGS) -+sha384sum_SOURCES = md5sum.c -+sha384sum_CPPFLAGS = -DHASH_ALGO_SHA384=1 $(AM_CPPFLAGS) -+sha512sum_SOURCES = md5sum.c -+sha512sum_CPPFLAGS = -DHASH_ALGO_SHA512=1 $(AM_CPPFLAGS) -+ -+ginstall_CPPFLAGS = -DENABLE_MATCHPATHCON=1 $(AM_CPPFLAGS) -+ -+# Ensure we don't link against libcoreutils.a as that lib is -+# not compiled with -fPIC which causes issues on 64 bit at least -+libstdbuf_so_LDADD = -+ -+# Note libstdbuf is only compiled if GCC is available -+# (as per the check in configure.ac), so these flags should be available. -+# libtool is probably required to relax this dependency. -+libstdbuf_so_LDFLAGS = -shared -+libstdbuf_so_CFLAGS = -fPIC $(AM_CFLAGS) -+ -+editpl = sed -e 's,@''PERL''@,$(PERL),g' -+ -+BUILT_SOURCES += dircolors.h -+dircolors.h: dcgen dircolors.hin -+ $(AM_V_GEN)rm -f $@ $@-t -+ $(AM_V_at)$(PERL) -w -- $(srcdir)/dcgen $(srcdir)/dircolors.hin > $@-t -+ $(AM_V_at)chmod a-w $@-t -+ $(AM_V_at)mv $@-t $@ -+ -+wheel_size = 5 -+ -+BUILT_SOURCES += wheel-size.h -+wheel-size.h: Makefile.am -+ $(AM_V_GEN)rm -f $@ $@-t -+ $(AM_V_at)echo '#define WHEEL_SIZE $(wheel_size)' > $@-t -+ $(AM_V_at)chmod a-w $@-t -+ $(AM_V_at)mv $@-t $@ -+ -+BUILT_SOURCES += wheel.h -+wheel.h: wheel-gen.pl Makefile.am -+ $(AM_V_GEN)rm -f $@ $@-t -+ $(AM_V_at)$(srcdir)/wheel-gen.pl $(wheel_size) > $@-t -+ $(AM_V_at)chmod a-w $@-t -+ $(AM_V_at)mv $@-t $@ -+ -+# false exits nonzero even with --help or --version. -+# test doesn't support --help or --version. -+# Tell automake to exempt then from that installcheck test. -+AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = false test -+ -+BUILT_SOURCES += fs.h -+fs.h: stat.c extract-magic -+ $(AM_V_GEN)rm -f $@ -+ $(AM_V_at)$(PERL) $(srcdir)/extract-magic $(srcdir)/stat.c > $@t -+ $(AM_V_at)chmod a-w $@t -+ $(AM_V_at)mv $@t $@ -+ -+BUILT_SOURCES += version.c -+version.c: Makefile -+ $(AM_V_GEN)rm -f $@ -+ $(AM_V_at)printf '#include \n' > $@t -+ $(AM_V_at)printf 'char const *Version = "$(PACKAGE_VERSION)";\n' >> $@t -+ $(AM_V_at)chmod a-w $@t -+ $(AM_V_at)mv $@t $@ -+ -+BUILT_SOURCES += version.h -+version.h: Makefile -+ $(AM_V_GEN)rm -f $@ -+ $(AM_V_at)printf 'extern char const *Version;\n' > $@t -+ $(AM_V_at)chmod a-w $@t -+ $(AM_V_at)mv $@t $@ -+ -+DISTCLEANFILES = version.c version.h -+MAINTAINERCLEANFILES = $(BUILT_SOURCES) -+ -+# Sort in traditional ASCII order, regardless of the current locale; -+# otherwise we may get into trouble with distinct strings that the -+# current locale considers to be equal. -+ASSORT = LC_ALL=C sort -+ -+all_programs = \ -+ $(bin_PROGRAMS) \ -+ $(bin_SCRIPTS) \ -+ $(EXTRA_PROGRAMS) -+ -+built_programs.list: -+ @echo $(bin_PROGRAMS) $(bin_SCRIPTS) | tr ' ' '\n' \ -+ | sed -e 's,$(EXEEXT)$$,,' | $(ASSORT) -u | tr '\n' ' ' -+ -+all_programs.list: -+ @echo $(all_programs) | tr ' ' '\n' | sed -e 's,$(EXEEXT)$$,,' \ -+ | $(ASSORT) -u -+ -+# This is required because we have broken inter-directory dependencies: -+# in order to generate all man pages, even those for which we don't -+# install a binary, require that all programs be built at distribution time. -+dist-hook: $(all_programs) -+ -+pm = progs-makefile -+pr = progs-readme -+# Ensure that the list of programs in README matches the list -+# of programs we can build. -+check: check-README check-duplicate-no-install -+.PHONY: check-README -+check-README: -+ $(AM_V_GEN)rm -rf $(pr) $(pm) -+ $(AM_V_at)echo $(all_programs) \ -+ | tr -s ' ' '\n' | sed -e 's,$(EXEEXT)$$,,;s/ginstall/install/' \ -+ | sed /libstdbuf/d \ -+ | $(ASSORT) -u > $(pm) && \ -+ sed -n '/^The programs .* are:/,/^[a-zA-Z]/p' $(top_srcdir)/README \ -+ | sed -n '/^ */s///p' | tr -s ' ' '\n' > $(pr) -+ $(AM_V_at)diff $(pm) $(pr) && rm -rf $(pr) $(pm) -+ -+# Ensure that a by-default-not-installed program (listed in -+# $(no_install__progs) is not also listed in $(EXTRA_PROGRAMS), because -+# if that were to happen, it *would* be installed by default. -+.PHONY: check-duplicate-no-install -+check-duplicate-no-install: tr -+ $(AM_V_GEN)test -z "`echo '$(EXTRA_PROGRAMS)'| ./tr ' ' '\n' | uniq -d`" -+ -+# Ensure that the list of programs and author names is accurate. -+# We need a UTF8 locale. If a lack of locale support or a missing -+# translation inhibits printing of UTF-8 names, just skip this test. -+au_dotdot = authors-dotdot -+au_actual = authors-actual -+.PHONY: sc_check-AUTHORS -+sc_check-AUTHORS: $(all_programs) -+ $(AM_V_GEN)locale=en_US.UTF-8; \ -+ LC_ALL="$$locale" ./cat --version \ -+ | grep ' Torbjorn ' > /dev/null \ -+ && { echo "$@: skipping this check"; exit 0; }; \ -+ rm -f $(au_actual) $(au_dotdot); \ -+ for i in `ls $(all_programs) | sed -e 's,$(EXEEXT)$$,,' \ -+ | sed /libstdbuf/d \ -+ | $(ASSORT) -u`; do \ -+ test "$$i" = '[' && continue; \ -+ exe=$$i; \ -+ if test "$$i" = install; then \ -+ exe=ginstall; \ -+ elif test "$$i" = test; then \ -+ exe='['; \ -+ fi; \ -+ LC_ALL="$$locale" ./$$exe --version \ -+ | perl -0 -pi -e 's/,\n/, /gm' \ -+ | sed -n -e '/Written by /{ s//'"$$i"': /;' \ -+ -e 's/,* and /, /; s/\.$$//; p; }'; \ -+ done > $(au_actual) && \ -+ sed -n '/^[^ ][^ ]*:/p' $(top_srcdir)/AUTHORS > $(au_dotdot) && \ -+ diff $(au_actual) $(au_dotdot) && rm -f $(au_actual) $(au_dotdot) -+ -+# The following rule is not designed to be portable, -+# and relies on tools that not everyone has. -+ -+# Most functions in src/*.c should have static scope. -+# Any that don't must be marked with `extern', but `main' -+# and `usage' are exceptions. They're always extern, but -+# don't need to be marked. Also functions starting with __ -+# are exempted due to possibly being added by the compiler -+# (when compiled as a shared library for example). -+# -+# The second nm|grep checks for file-scope variables with `extern' scope. -+.PHONY: sc_tight_scope -+sc_tight_scope: $(bin_PROGRAMS) -+ $(AM_V_GEN)t=exceptions-$$$$; \ -+ trap "s=$$?; rm -f $$t; exit $$s" 0 1 2 13 15; \ -+ src=`for f in $(SOURCES); do \ -+ test -f $$f && d= || d=$(srcdir)/; echo $$d$$f; done`; \ -+ hdr=`for f in $(noinst_HEADERS); do \ -+ test -f $$f && d= || d=$(srcdir)/; echo $$d$$f; done`; \ -+ ( printf 'main\nusage\n_.*\n'; \ -+ grep -h -A1 '^extern .*[^;]$$' $$src \ -+ | grep -vE '^(extern |--)' | sed 's/ .*//'; \ -+ perl -ne '/^extern (?:enum )?\S+ (\S*) \(/ and print "$$1\n"' $$hdr; \ -+ ) | $(ASSORT) -u | sed 's/^/^/;s/$$/$$/' > $$t; \ -+ nm -e *.$(OBJEXT) \ -+ | sed -n 's/.* T //p' \ -+ | sed 's/^_//' \ -+ | grep -Ev -f $$t && \ -+ { echo 'the above functions should have static scope' 1>&2; \ -+ exit 1; } || : ; \ -+ ( printf '^program_name$$\n'; \ -+ perl -ne '/^extern .*?\**(\w+);/ and print "^$$1\$$\n"' \ -+ $$hdr *.h ) | $(ASSORT) -u > $$t; \ -+ nm -e *.$(OBJEXT) \ -+ | sed -n 's/.* [BD] //p' \ -+ | sed 's/^_//' \ -+ | grep -Ev -f $$t && \ -+ { echo 'the above variables should have static scope' 1>&2; \ -+ exit 1; } || : -+ -+# Use the just-built ./ginstall, when not cross-compiling. -+if CROSS_COMPILING -+cu_install_program = @INSTALL_PROGRAM@ -+else -+cu_install_program = ./ginstall -+endif -+INSTALL_PROGRAM = $(cu_install_program) diff -urNp coreutils-8.0-orig/src/su.c coreutils-8.0/src/su.c --- coreutils-8.0-orig/src/su.c 2009-10-07 10:03:29.000000000 +0200 +++ coreutils-8.0/src/su.c 2009-10-07 10:04:27.000000000 +0200 @@ -17187,528 +421,4 @@ diff -urNp coreutils-8.0-orig/src/su.c coreutils-8.0/src/su.c - run_shell (shell, command, argv + optind, MAX (0, argc - optind)); + run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw); } -diff -urNp coreutils-8.0-orig/src/su.c.orig coreutils-8.0/src/su.c.orig ---- coreutils-8.0-orig/src/su.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/su.c.orig 2009-10-07 10:03:29.000000000 +0200 -@@ -0,0 +1,521 @@ -+/* su for GNU. Run a shell with substitute user and group IDs. -+ Copyright (C) 1992-2006, 2008-2009 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 . */ -+ -+/* Run a shell with the real and effective UID and GID and groups -+ of USER, default `root'. -+ -+ The shell run is taken from USER's password entry, /bin/sh if -+ none is specified there. If the account has a password, su -+ prompts for a password unless run by a user with real UID 0. -+ -+ Does not change the current directory. -+ Sets `HOME' and `SHELL' from the password entry for USER, and if -+ USER is not root, sets `USER' and `LOGNAME' to USER. -+ The subshell is not a login shell. -+ -+ If one or more ARGs are given, they are passed as additional -+ arguments to the subshell. -+ -+ Does not handle /bin/sh or other shells specially -+ (setting argv[0] to "-su", passing -c only to certain shells, etc.). -+ I don't see the point in doing that, and it's ugly. -+ -+ This program intentionally does not support a "wheel group" that -+ restricts who can su to UID 0 accounts. RMS considers that to -+ be fascist. -+ -+ 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. -+ -+ -DSYSLOG_NON_ROOT Log all su's, not just those to root (UID 0). -+ Never logs attempted su's to nonexistent accounts. -+ -+ Written by David MacKenzie . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "system.h" -+#include "getpass.h" -+ -+#if HAVE_SYSLOG_H && HAVE_SYSLOG -+# include -+#else -+# undef SYSLOG_SUCCESS -+# undef SYSLOG_FAILURE -+# undef SYSLOG_NON_ROOT -+#endif -+ -+#if HAVE_SYS_PARAM_H -+# include -+#endif -+ -+#ifndef HAVE_ENDGRENT -+# define endgrent() ((void) 0) -+#endif -+ -+#ifndef HAVE_ENDPWENT -+# define endpwent() ((void) 0) -+#endif -+ -+#if HAVE_SHADOW_H -+# include -+#endif -+ -+#include "error.h" -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "su" -+ -+#define AUTHORS proper_name ("David MacKenzie") -+ -+#if HAVE_PATHS_H -+# include -+#endif -+ -+/* The default PATH for simulated logins to non-superuser accounts. */ -+#ifdef _PATH_DEFPATH -+# define DEFAULT_LOGIN_PATH _PATH_DEFPATH -+#else -+# define DEFAULT_LOGIN_PATH ":/usr/ucb:/bin:/usr/bin" -+#endif -+ -+/* The default PATH for simulated logins to superuser accounts. */ -+#ifdef _PATH_DEFPATH_ROOT -+# define DEFAULT_ROOT_LOGIN_PATH _PATH_DEFPATH_ROOT -+#else -+# 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" -+ -+/* The user to become if none is specified. */ -+#define DEFAULT_USER "root" -+ -+char *crypt (char const *key, char const *salt); -+ -+extern char **environ; -+ -+static void run_shell (char const *, char const *, char **, size_t) -+ ATTRIBUTE_NORETURN; -+ -+/* If true, pass the `-f' option to the subshell. */ -+static bool fast_startup; -+ -+/* If true, simulate a login instead of just starting a shell. */ -+static bool simulate_login; -+ -+/* If true, change some environment vars to indicate the user su'd to. */ -+static bool change_environment; -+ -+static struct option const longopts[] = -+{ -+ {"command", required_argument, NULL, 'c'}, -+ {"fast", no_argument, NULL, 'f'}, -+ {"login", no_argument, NULL, 'l'}, -+ {"preserve-environment", no_argument, NULL, 'p'}, -+ {"shell", required_argument, NULL, 's'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+/* Add NAME=VAL to the environment, checking for out of memory errors. */ -+ -+static void -+xsetenv (char const *name, char const *val) -+{ -+ size_t namelen = strlen (name); -+ size_t vallen = strlen (val); -+ char *string = xmalloc (namelen + 1 + vallen + 1); -+ strcpy (string, name); -+ string[namelen] = '='; -+ strcpy (string + namelen + 1, val); -+ if (putenv (string) != 0) -+ xalloc_die (); -+} -+ -+#if defined SYSLOG_SUCCESS || defined SYSLOG_FAILURE -+/* Log the fact that someone has run su to the user given by PW; -+ if SUCCESSFUL is true, they gave the correct password, etc. */ -+ -+static void -+log_su (struct passwd const *pw, bool successful) -+{ -+ const char *new_user, *old_user, *tty; -+ -+# ifndef SYSLOG_NON_ROOT -+ if (pw->pw_uid) -+ return; -+# endif -+ new_user = pw->pw_name; -+ /* The utmp entry (via getlogin) is probably the best way to identify -+ the user, especially if someone su's from a su-shell. */ -+ old_user = getlogin (); -+ if (!old_user) -+ { -+ /* getlogin can fail -- usually due to lack of utmp entry. -+ Resort to getpwuid. */ -+ struct passwd *pwd = getpwuid (getuid ()); -+ old_user = (pwd ? pwd->pw_name : ""); -+ } -+ tty = ttyname (STDERR_FILENO); -+ if (!tty) -+ tty = "none"; -+ /* 4.2BSD openlog doesn't have the third parameter. */ -+ openlog (last_component (program_name), 0 -+# ifdef LOG_AUTH -+ , LOG_AUTH -+# endif -+ ); -+ syslog (LOG_NOTICE, -+# ifdef SYSLOG_NON_ROOT -+ "%s(to %s) %s on %s", -+# else -+ "%s%s on %s", -+# endif -+ successful ? "" : "FAILED SU ", -+# ifdef SYSLOG_NON_ROOT -+ new_user, -+# endif -+ old_user, tty); -+ closelog (); -+} -+#endif -+ -+/* Ask the user for a password. -+ 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. */ -+ -+static bool -+correct_password (const struct passwd *pw) -+{ -+ char *unencrypted, *encrypted, *correct; -+#if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP -+ /* Shadow passwd stuff for SVR3 and maybe other systems. */ -+ struct spwd *sp = getspnam (pw->pw_name); -+ -+ endspent (); -+ if (sp) -+ correct = sp->sp_pwdp; -+ else -+#endif -+ correct = pw->pw_passwd; -+ -+ if (getuid () == 0 || !correct || correct[0] == '\0') -+ return true; -+ -+ unencrypted = getpass (_("Password:")); -+ if (!unencrypted) -+ { -+ error (0, 0, _("getpass: cannot open /dev/tty")); -+ return false; -+ } -+ encrypted = crypt (unencrypted, correct); -+ memset (unencrypted, 0, strlen (unencrypted)); -+ return STREQ (encrypted, correct); -+} -+ -+/* Update `environ' for the new shell based on PW, with SHELL being -+ the value for the SHELL environment variable. */ -+ -+static void -+modify_environment (const struct passwd *pw, const char *shell) -+{ -+ if (simulate_login) -+ { -+ /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. -+ Unset all other environment variables. */ -+ char const *term = getenv ("TERM"); -+ if (term) -+ term = xstrdup (term); -+ environ = xmalloc ((6 + !!term) * sizeof (char *)); -+ environ[0] = NULL; -+ if (term) -+ xsetenv ("TERM", term); -+ xsetenv ("HOME", pw->pw_dir); -+ xsetenv ("SHELL", shell); -+ xsetenv ("USER", pw->pw_name); -+ xsetenv ("LOGNAME", pw->pw_name); -+ xsetenv ("PATH", (pw->pw_uid -+ ? DEFAULT_LOGIN_PATH -+ : DEFAULT_ROOT_LOGIN_PATH)); -+ } -+ else -+ { -+ /* Set HOME, SHELL, and if not becoming a super-user, -+ USER and LOGNAME. */ -+ if (change_environment) -+ { -+ xsetenv ("HOME", pw->pw_dir); -+ xsetenv ("SHELL", shell); -+ if (pw->pw_uid) -+ { -+ xsetenv ("USER", pw->pw_name); -+ xsetenv ("LOGNAME", pw->pw_name); -+ } -+ } -+ } -+} -+ -+/* Become the user and group(s) specified by PW. */ -+ -+static void -+change_identity (const struct passwd *pw) -+{ -+#ifdef HAVE_INITGROUPS -+ errno = 0; -+ if (initgroups (pw->pw_name, pw->pw_gid) == -1) -+ error (EXIT_FAILURE, errno, _("cannot set groups")); -+ endgrent (); -+#endif -+ if (setgid (pw->pw_gid)) -+ error (EXIT_FAILURE, errno, _("cannot set group id")); -+ if (setuid (pw->pw_uid)) -+ error (EXIT_FAILURE, errno, _("cannot set user id")); -+} -+ -+/* 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 -+ are N_ADDITIONAL_ARGS extra arguments. */ -+ -+static void -+run_shell (char const *shell, char const *command, char **additional_args, -+ size_t n_additional_args) -+{ -+ 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; -+ -+ if (simulate_login) -+ { -+ char *arg0; -+ char *shell_basename; -+ -+ shell_basename = last_component (shell); -+ arg0 = xmalloc (strlen (shell_basename) + 2); -+ arg0[0] = '-'; -+ strcpy (arg0 + 1, shell_basename); -+ args[0] = arg0; -+ } -+ else -+ args[0] = last_component (shell); -+ if (fast_startup) -+ args[argno++] = "-f"; -+ if (command) -+ { -+ args[argno++] = "-c"; -+ args[argno++] = command; -+ } -+ memcpy (args + argno, additional_args, n_additional_args * sizeof *args); -+ args[argno + n_additional_args] = NULL; -+ execv (shell, (char **) args); -+ -+ { -+ int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE); -+ error (0, errno, "%s", shell); -+ exit (exit_status); -+ } -+} -+ -+/* Return true if SHELL is a restricted shell (one not returned by -+ getusershell), else false, meaning it is a standard shell. */ -+ -+static bool -+restricted_shell (const char *shell) -+{ -+ char *line; -+ -+ setusershell (); -+ while ((line = getusershell ()) != NULL) -+ { -+ if (*line != '#' && STREQ (line, shell)) -+ { -+ endusershell (); -+ return false; -+ } -+ } -+ endusershell (); -+ return true; -+} -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("Usage: %s [OPTION]... [-] [USER [ARG]...]\n"), program_name); -+ fputs (_("\ -+Change the effective user id and group id to that of USER.\n\ -+\n\ -+ -, -l, --login make the shell a login shell\n\ -+ -c, --command=COMMAND pass a single COMMAND to the shell with -c\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\ -+ -s, --shell=SHELL run SHELL if /etc/shells allows it\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+A mere - implies -l. If USER not given, assume root.\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int optc; -+ const char *new_user = DEFAULT_USER; -+ char *command = NULL; -+ char *shell = NULL; -+ struct passwd *pw; -+ struct passwd pw_copy; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ initialize_exit_failure (EXIT_FAILURE); -+ atexit (close_stdout); -+ -+ fast_startup = false; -+ simulate_login = false; -+ change_environment = true; -+ -+ while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, NULL)) != -1) -+ { -+ switch (optc) -+ { -+ case 'c': -+ command = optarg; -+ break; -+ -+ case 'f': -+ fast_startup = true; -+ break; -+ -+ case 'l': -+ simulate_login = true; -+ break; -+ -+ case 'm': -+ case 'p': -+ change_environment = false; -+ break; -+ -+ case 's': -+ shell = optarg; -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ if (optind < argc && STREQ (argv[optind], "-")) -+ { -+ simulate_login = true; -+ ++optind; -+ } -+ if (optind < argc) -+ new_user = argv[optind++]; -+ -+ pw = getpwnam (new_user); -+ if (! (pw && pw->pw_name && pw->pw_name[0] && pw->pw_dir && pw->pw_dir[0] -+ && pw->pw_passwd)) -+ error (EXIT_FAILURE, 0, _("user %s does not exist"), new_user); -+ -+ /* Make a copy of the password information and point pw at the local -+ copy instead. Otherwise, some systems (e.g. GNU/Linux) would clobber -+ the static data through the getlogin call from log_su. -+ Also, make sure pw->pw_shell is a nonempty string. -+ It may be NULL when NEW_USER is a username that is retrieved via NIS (YP), -+ but that doesn't have a default shell listed. */ -+ pw_copy = *pw; -+ pw = &pw_copy; -+ pw->pw_name = xstrdup (pw->pw_name); -+ pw->pw_passwd = xstrdup (pw->pw_passwd); -+ pw->pw_dir = xstrdup (pw->pw_dir); -+ pw->pw_shell = xstrdup (pw->pw_shell && pw->pw_shell[0] -+ ? pw->pw_shell -+ : DEFAULT_SHELL); -+ endpwent (); -+ -+ if (!correct_password (pw)) -+ { -+#ifdef SYSLOG_FAILURE -+ log_su (pw, false); -+#endif -+ error (EXIT_FAILURE, 0, _("incorrect password")); -+ } -+#ifdef SYSLOG_SUCCESS -+ else -+ { -+ log_su (pw, true); -+ } -+#endif -+ -+ if (!shell && !change_environment) -+ shell = getenv ("SHELL"); -+ if (shell && getuid () != 0 && restricted_shell (pw->pw_shell)) -+ { -+ /* The user being su'd to has a nonstandard shell, and so is -+ probably a uucp account or has restricted access. Don't -+ compromise the account by allowing access with a standard -+ shell. */ -+ error (0, 0, _("using restricted shell %s"), pw->pw_shell); -+ shell = NULL; -+ } -+ shell = xstrdup (shell ? shell : pw->pw_shell); -+ modify_environment (pw, shell); -+ -+ change_identity (pw); -+ if (simulate_login && chdir (pw->pw_dir) != 0) -+ error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir); -+ -+ run_shell (shell, command, argv + optind, MAX (0, argc - optind)); -+} + diff --git a/coreutils-selinux.patch b/coreutils-selinux.patch index 12995d2..a2dc61d 100644 --- a/coreutils-selinux.patch +++ b/coreutils-selinux.patch @@ -15,23 +15,6 @@ diff -urNp coreutils-8.0-orig/configure.ac coreutils-8.0/configure.ac AC_FUNC_FORK optional_bin_progs= -diff -urNp coreutils-8.0-orig/configure.ac.orig coreutils-8.0/configure.ac.orig ---- coreutils-8.0-orig/configure.ac.orig 2009-10-07 10:09:43.000000000 +0200 -+++ coreutils-8.0/configure.ac.orig 2009-10-07 10:09:43.000000000 +0200 -@@ -115,6 +115,13 @@ if test "$gl_gcc_warnings" = yes; then - AC_DEFINE([GNULIB_PORTCHECK], [1], [enable some gnulib portability checks]) - fi - -+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_FUNC_FORK - - optional_bin_progs= diff -urNp coreutils-8.0-orig/man/chcon.x coreutils-8.0/man/chcon.x --- coreutils-8.0-orig/man/chcon.x 2009-09-01 13:01:16.000000000 +0200 +++ coreutils-8.0/man/chcon.x 2009-10-07 10:10:11.000000000 +0200 @@ -63,11222 +46,593 @@ diff -urNp coreutils-8.0-orig/src/copy.c coreutils-8.0/src/copy.c } else { -diff -urNp coreutils-8.0-orig/src/copy.c.orig coreutils-8.0/src/copy.c.orig ---- coreutils-8.0-orig/src/copy.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/copy.c.orig 2009-09-29 15:27:54.000000000 +0200 -@@ -0,0 +1,2369 @@ -+/* copy.c -- core functions for copying files and directories -+ Copyright (C) 89, 90, 91, 1995-2009 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 . */ -+ -+/* Extracted from cp.c and librarified by Jim Meyering. */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#if HAVE_HURD_H -+# include -+#endif -+#if HAVE_PRIV_H -+# include -+#endif -+ -+#include "system.h" -+#include "acl.h" -+#include "backupfile.h" -+#include "buffer-lcm.h" -+#include "copy.h" -+#include "cp-hash.h" -+#include "error.h" -+#include "fcntl--.h" -+#include "file-set.h" -+#include "filemode.h" -+#include "filenamecat.h" -+#include "full-write.h" -+#include "hash.h" -+#include "hash-triple.h" -+#include "ignore-value.h" -+#include "quote.h" -+#include "same.h" -+#include "savedir.h" -+#include "stat-time.h" -+#include "utimecmp.h" -+#include "utimens.h" -+#include "write-any-file.h" -+#include "areadlink.h" -+#include "yesno.h" -+ -+#if USE_XATTR -+# include -+# include -+# include -+# include "verror.h" -+#endif -+ -+#if HAVE_SYS_IOCTL_H -+# include -+#endif -+ -+#ifndef HAVE_FCHOWN -+# define HAVE_FCHOWN false -+# define fchown(fd, uid, gid) (-1) -+#endif -+ -+#ifndef HAVE_LCHOWN -+# define HAVE_LCHOWN false -+# define lchown(name, uid, gid) chown (name, uid, gid) -+#endif -+ -+#ifndef HAVE_MKFIFO -+static int -+rpl_mkfifo (char const *file, mode_t mode) -+{ -+ errno = ENOTSUP; -+ return -1; -+} -+# define mkfifo rpl_mkfifo -+#endif -+ -+#ifndef USE_ACL -+# define USE_ACL 0 -+#endif -+ -+#define SAME_OWNER(A, B) ((A).st_uid == (B).st_uid) -+#define SAME_GROUP(A, B) ((A).st_gid == (B).st_gid) -+#define SAME_OWNER_AND_GROUP(A, B) (SAME_OWNER (A, B) && SAME_GROUP (A, B)) -+ -+struct dir_list -+{ -+ struct dir_list *parent; -+ ino_t ino; -+ dev_t dev; -+}; -+ -+/* Initial size of the cp.dest_info hash table. */ -+#define DEST_INFO_INITIAL_CAPACITY 61 -+ -+static bool copy_internal (char const *src_name, char const *dst_name, -+ bool new_dst, dev_t device, -+ struct dir_list *ancestors, -+ const struct cp_options *x, -+ bool command_line_arg, -+ bool *first_dir_created_per_command_line_arg, -+ bool *copy_into_self, -+ bool *rename_succeeded); -+static bool owner_failure_ok (struct cp_options const *x); -+ -+/* Pointers to the file names: they're used in the diagnostic that is issued -+ when we detect the user is trying to copy a directory into itself. */ -+static char const *top_level_src_name; -+static char const *top_level_dst_name; -+ -+/* Set the timestamp of symlink, FILE, to TIMESPEC. -+ If this system lacks support for that, simply return 0. */ -+static inline int -+utimens_symlink (char const *file, struct timespec const *timespec) -+{ -+ int err = 0; -+ -+#if HAVE_UTIMENSAT -+ err = utimensat (AT_FDCWD, file, timespec, AT_SYMLINK_NOFOLLOW); -+ /* When configuring on a system with new headers and libraries, and -+ running on one with a kernel that is old enough to lack the syscall, -+ utimensat fails with ENOSYS. Ignore that. */ -+ if (err && errno == ENOSYS) -+ err = 0; -+#else -+ (void) file; -+ (void) timespec; -+#endif -+ -+ return err; -+} -+ -+/* Perform the O(1) btrfs clone operation, if possible. -+ Upon success, return 0. Otherwise, return -1 and set errno. */ -+static inline int -+clone_file (int dest_fd, int src_fd) -+{ -+#ifdef __linux__ -+# undef BTRFS_IOCTL_MAGIC -+# define BTRFS_IOCTL_MAGIC 0x94 -+# undef BTRFS_IOC_CLONE -+# define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int) -+ return ioctl (dest_fd, BTRFS_IOC_CLONE, src_fd); -+#else -+ (void) dest_fd; -+ (void) src_fd; -+ errno = ENOTSUP; -+ return -1; -+#endif -+} -+ -+/* FIXME: describe */ -+/* FIXME: rewrite this to use a hash table so we avoid the quadratic -+ performance hit that's probably noticeable only on trees deeper -+ than a few hundred levels. See use of active_dir_map in remove.c */ -+ -+static bool -+is_ancestor (const struct stat *sb, const struct dir_list *ancestors) -+{ -+ while (ancestors != 0) -+ { -+ if (ancestors->ino == sb->st_ino && ancestors->dev == sb->st_dev) -+ return true; -+ ancestors = ancestors->parent; -+ } -+ return false; -+} -+ -+static bool -+errno_unsupported (int err) -+{ -+ return err == ENOTSUP || err == ENODATA; -+} -+ -+#if USE_XATTR -+static void -+copy_attr_error (struct error_context *ctx ATTRIBUTE_UNUSED, -+ char const *fmt, ...) -+{ -+ int err = errno; -+ va_list ap; -+ -+ if (!errno_unsupported (errno)) -+ { -+ /* use verror module to print error message */ -+ va_start (ap, fmt); -+ verror (0, err, fmt, ap); -+ va_end (ap); -+ } -+} -+ -+static void -+copy_attr_allerror (struct error_context *ctx ATTRIBUTE_UNUSED, -+ char const *fmt, ...) -+{ -+ int err = errno; -+ va_list ap; -+ -+ /* use verror module to print error message */ -+ va_start (ap, fmt); -+ verror (0, err, fmt, ap); -+ va_end (ap); -+} -+ -+static char const * -+copy_attr_quote (struct error_context *ctx ATTRIBUTE_UNUSED, char const *str) -+{ -+ return quote (str); -+} -+ -+static void -+copy_attr_free (struct error_context *ctx ATTRIBUTE_UNUSED, -+ char const *str ATTRIBUTE_UNUSED) -+{ -+} -+ -+static bool -+copy_attr_by_fd (char const *src_path, int src_fd, -+ char const *dst_path, int dst_fd, const struct cp_options *x) -+{ -+ struct error_context ctx = -+ { -+ .error = x->require_preserve_xattr ? copy_attr_allerror : copy_attr_error, -+ .quote = copy_attr_quote, -+ .quote_free = copy_attr_free -+ }; -+ return 0 == attr_copy_fd (src_path, src_fd, dst_path, dst_fd, 0, -+ (x->reduce_diagnostics -+ && !x->require_preserve_xattr)? NULL : &ctx); -+} -+ -+static bool -+copy_attr_by_name (char const *src_path, char const *dst_path, -+ const struct cp_options *x) -+{ -+ struct error_context ctx = -+ { -+ .error = x->require_preserve_xattr ? copy_attr_allerror : copy_attr_error, -+ .quote = copy_attr_quote, -+ .quote_free = copy_attr_free -+ }; -+ return 0 == attr_copy_file (src_path, dst_path, 0, -+ (x-> reduce_diagnostics -+ && !x->require_preserve_xattr) ? NULL : &ctx); -+} -+#else /* USE_XATTR */ -+ -+static bool -+copy_attr_by_fd (char const *src_path ATTRIBUTE_UNUSED, -+ int src_fd ATTRIBUTE_UNUSED, -+ char const *dst_path ATTRIBUTE_UNUSED, -+ int dst_fd ATTRIBUTE_UNUSED, -+ const struct cp_options *x ATTRIBUTE_UNUSED) -+{ -+ return true; -+} -+ -+static bool -+copy_attr_by_name (char const *src_path ATTRIBUTE_UNUSED, -+ char const *dst_path ATTRIBUTE_UNUSED, -+ const struct cp_options *x ATTRIBUTE_UNUSED) -+{ -+ return true; -+} -+#endif /* USE_XATTR */ -+ -+/* Read the contents of the directory SRC_NAME_IN, and recursively -+ copy the contents to DST_NAME_IN. NEW_DST is true if -+ DST_NAME_IN is a directory that was created previously in the -+ recursion. SRC_SB and ANCESTORS describe SRC_NAME_IN. -+ Set *COPY_INTO_SELF if SRC_NAME_IN is a parent of -+ FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG FIXME -+ (or the same as) DST_NAME_IN; otherwise, clear it. -+ Return true if successful. */ -+ -+static bool -+copy_dir (char const *src_name_in, char const *dst_name_in, bool new_dst, -+ const struct stat *src_sb, struct dir_list *ancestors, -+ const struct cp_options *x, -+ bool *first_dir_created_per_command_line_arg, -+ bool *copy_into_self) -+{ -+ char *name_space; -+ char *namep; -+ struct cp_options non_command_line_options = *x; -+ bool ok = true; -+ -+ name_space = savedir (src_name_in); -+ if (name_space == NULL) -+ { -+ /* This diagnostic is a bit vague because savedir can fail in -+ several different ways. */ -+ error (0, errno, _("cannot access %s"), quote (src_name_in)); -+ return false; -+ } -+ -+ /* For cp's -H option, dereference command line arguments, but do not -+ dereference symlinks that are found via recursive traversal. */ -+ if (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS) -+ non_command_line_options.dereference = DEREF_NEVER; -+ -+ namep = name_space; -+ while (*namep != '\0') -+ { -+ bool local_copy_into_self; -+ char *src_name = file_name_concat (src_name_in, namep, NULL); -+ char *dst_name = file_name_concat (dst_name_in, namep, NULL); -+ -+ ok &= copy_internal (src_name, dst_name, new_dst, src_sb->st_dev, -+ ancestors, &non_command_line_options, false, -+ first_dir_created_per_command_line_arg, -+ &local_copy_into_self, NULL); -+ *copy_into_self |= local_copy_into_self; -+ -+ free (dst_name); -+ free (src_name); -+ -+ /* If we're copying into self, there's no point in continuing, -+ and in fact, that would even infloop, now that we record only -+ the first created directory per command line argument. */ -+ if (local_copy_into_self) -+ break; -+ -+ namep += strlen (namep) + 1; -+ } -+ free (name_space); -+ return ok; -+} -+ -+/* Set the owner and owning group of DEST_DESC to the st_uid and -+ st_gid fields of SRC_SB. If DEST_DESC is undefined (-1), set -+ the owner and owning group of DST_NAME instead; for -+ safety prefer lchown if the system supports it since no -+ symbolic links should be involved. DEST_DESC must -+ refer to the same file as DEST_NAME if defined. -+ Upon failure to set both UID and GID, try to set only the GID. -+ NEW_DST is true if the file was newly created; otherwise, -+ DST_SB is the status of the destination. -+ Return 1 if the initial syscall succeeds, 0 if it fails but it's OK -+ not to preserve ownership, -1 otherwise. */ -+ -+static int -+set_owner (const struct cp_options *x, char const *dst_name, int dest_desc, -+ struct stat const *src_sb, bool new_dst, -+ struct stat const *dst_sb) -+{ -+ uid_t uid = src_sb->st_uid; -+ gid_t gid = src_sb->st_gid; -+ -+ /* Naively changing the ownership of an already-existing file before -+ changing its permissions would create a window of vulnerability if -+ the file's old permissions are too generous for the new owner and -+ group. Avoid the window by first changing to a restrictive -+ temporary mode if necessary. */ -+ -+ if (!new_dst && (x->preserve_mode || x->move_mode || x->set_mode)) -+ { -+ mode_t old_mode = dst_sb->st_mode; -+ mode_t new_mode = -+ (x->preserve_mode || x->move_mode ? src_sb->st_mode : x->mode); -+ mode_t restrictive_temp_mode = old_mode & new_mode & S_IRWXU; -+ -+ if ((USE_ACL -+ || (old_mode & CHMOD_MODE_BITS -+ & (~new_mode | S_ISUID | S_ISGID | S_ISVTX))) -+ && qset_acl (dst_name, dest_desc, restrictive_temp_mode) != 0) -+ { -+ if (! owner_failure_ok (x)) -+ error (0, errno, _("clearing permissions for %s"), quote (dst_name)); -+ return -x->require_preserve; -+ } -+ } -+ -+ if (HAVE_FCHOWN && dest_desc != -1) -+ { -+ if (fchown (dest_desc, uid, gid) == 0) -+ return 1; -+ if (errno == EPERM || errno == EINVAL) -+ { -+ /* We've failed to set *both*. Now, try to set just the group -+ ID, but ignore any failure here, and don't change errno. */ -+ int saved_errno = errno; -+ ignore_value (fchown (dest_desc, -1, gid)); -+ errno = saved_errno; -+ } -+ } -+ else -+ { -+ if (lchown (dst_name, uid, gid) == 0) -+ return 1; -+ if (errno == EPERM || errno == EINVAL) -+ { -+ /* We've failed to set *both*. Now, try to set just the group -+ ID, but ignore any failure here, and don't change errno. */ -+ int saved_errno = errno; -+ ignore_value (lchown (dst_name, -1, gid)); -+ errno = saved_errno; -+ } -+ } -+ -+ if (! chown_failure_ok (x)) -+ { -+ error (0, errno, _("failed to preserve ownership for %s"), -+ quote (dst_name)); -+ if (x->require_preserve) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/* Set the st_author field of DEST_DESC to the st_author field of -+ SRC_SB. If DEST_DESC is undefined (-1), set the st_author field -+ of DST_NAME instead. DEST_DESC must refer to the same file as -+ DEST_NAME if defined. */ -+ -+static void -+set_author (const char *dst_name, int dest_desc, const struct stat *src_sb) -+{ -+#if HAVE_STRUCT_STAT_ST_AUTHOR -+ /* FIXME: Modify the following code so that it does not -+ follow symbolic links. */ -+ -+ /* Preserve the st_author field. */ -+ file_t file = (dest_desc < 0 -+ ? file_name_lookup (dst_name, 0, 0) -+ : getdport (dest_desc)); -+ if (file == MACH_PORT_NULL) -+ error (0, errno, _("failed to lookup file %s"), quote (dst_name)); -+ else -+ { -+ error_t err = file_chauthor (file, src_sb->st_author); -+ if (err) -+ error (0, err, _("failed to preserve authorship for %s"), -+ quote (dst_name)); -+ mach_port_deallocate (mach_task_self (), file); -+ } -+#else -+ (void) dst_name; -+ (void) dest_desc; -+ (void) src_sb; -+#endif -+} -+ -+/* Change the file mode bits of the file identified by DESC or NAME to MODE. -+ Use DESC if DESC is valid and fchmod is available, NAME otherwise. */ -+ -+static int -+fchmod_or_lchmod (int desc, char const *name, mode_t mode) -+{ -+#if HAVE_FCHMOD -+ if (0 <= desc) -+ return fchmod (desc, mode); -+#endif -+ return lchmod (name, mode); -+} -+ -+/* Copy a regular file from SRC_NAME to DST_NAME. -+ If the source file contains holes, copies holes and blocks of zeros -+ in the source file as holes in the destination file. -+ (Holes are read as zeroes by the `read' system call.) -+ When creating the destination, use DST_MODE & ~OMITTED_PERMISSIONS -+ as the third argument in the call to open, adding -+ OMITTED_PERMISSIONS after copying as needed. -+ X provides many option settings. -+ Return true if successful. -+ *NEW_DST is as in copy_internal. -+ SRC_SB is the result of calling XSTAT (aka stat) on SRC_NAME. */ -+ -+static bool -+copy_reg (char const *src_name, char const *dst_name, -+ const struct cp_options *x, -+ mode_t dst_mode, mode_t omitted_permissions, bool *new_dst, -+ struct stat const *src_sb) -+{ -+ char *buf; -+ char *buf_alloc = NULL; -+ char *name_alloc = NULL; -+ int dest_desc; -+ int dest_errno; -+ int source_desc; -+ mode_t src_mode = src_sb->st_mode; -+ struct stat sb; -+ struct stat src_open_sb; -+ bool return_val = true; -+ bool data_copy_required = true; -+ -+ source_desc = open (src_name, -+ (O_RDONLY | O_BINARY -+ | (x->dereference == DEREF_NEVER ? O_NOFOLLOW : 0))); -+ if (source_desc < 0) -+ { -+ error (0, errno, _("cannot open %s for reading"), quote (src_name)); -+ return false; -+ } -+ -+ if (fstat (source_desc, &src_open_sb) != 0) -+ { -+ error (0, errno, _("cannot fstat %s"), quote (src_name)); -+ return_val = false; -+ goto close_src_desc; -+ } -+ -+ /* Compare the source dev/ino from the open file to the incoming, -+ saved ones obtained via a previous call to stat. */ -+ if (! SAME_INODE (*src_sb, src_open_sb)) -+ { -+ error (0, 0, -+ _("skipping file %s, as it was replaced while being copied"), -+ quote (src_name)); -+ return_val = false; -+ goto close_src_desc; -+ } -+ -+ /* The semantics of the following open calls are mandated -+ by the specs for both cp and mv. */ -+ if (! *new_dst) -+ { -+ dest_desc = open (dst_name, O_WRONLY | O_TRUNC | O_BINARY); -+ dest_errno = errno; -+ -+ /* When using cp --preserve=context to copy to an existing destination, -+ use the default context rather than that of the source. Why? -+ 1) the src context may prohibit writing, and -+ 2) because it's more consistent to use the same context -+ that is used when the destination file doesn't already exist. */ -+ if (x->preserve_security_context && 0 <= dest_desc) -+ { -+ security_context_t con = NULL; -+ if (getfscreatecon (&con) < 0) -+ { -+ if (!x->reduce_diagnostics || x->require_preserve_context) -+ error (0, errno, _("failed to get file system create context")); -+ if (x->require_preserve_context) -+ { -+ return_val = false; -+ goto close_src_and_dst_desc; -+ } -+ } -+ -+ if (con) -+ { -+ if (fsetfilecon (dest_desc, con) < 0) -+ { -+ if (!x->reduce_diagnostics || x->require_preserve_context) -+ error (0, errno, -+ _("failed to set the security context of %s to %s"), -+ quote_n (0, dst_name), quote_n (1, con)); -+ if (x->require_preserve_context) -+ { -+ return_val = false; -+ freecon (con); -+ goto close_src_and_dst_desc; -+ } -+ } -+ freecon (con); -+ } -+ } -+ -+ if (dest_desc < 0 && x->unlink_dest_after_failed_open) -+ { -+ if (unlink (dst_name) != 0) -+ { -+ error (0, errno, _("cannot remove %s"), quote (dst_name)); -+ return_val = false; -+ goto close_src_desc; -+ } -+ if (x->verbose) -+ printf (_("removed %s\n"), quote (dst_name)); -+ -+ /* Tell caller that the destination file was unlinked. */ -+ *new_dst = true; -+ } -+ } -+ -+ if (*new_dst) -+ { -+ int open_flags = O_WRONLY | O_CREAT | O_BINARY; -+ dest_desc = open (dst_name, open_flags | O_EXCL, -+ dst_mode & ~omitted_permissions); -+ dest_errno = errno; -+ -+ /* When trying to copy through a dangling destination symlink, -+ the above open fails with EEXIST. If that happens, and -+ lstat'ing the DST_NAME shows that it is a symlink, then we -+ have a problem: trying to resolve this dangling symlink to -+ a directory/destination-entry pair is fundamentally racy, -+ so punt. If POSIXLY_CORRECT is set, simply call open again, -+ but without O_EXCL (potentially dangerous). If not, fail -+ with a diagnostic. These shenanigans are necessary only -+ when copying, i.e., not in move_mode. */ -+ if (dest_desc < 0 && dest_errno == EEXIST && ! x->move_mode) -+ { -+ struct stat dangling_link_sb; -+ if (lstat (dst_name, &dangling_link_sb) == 0 -+ && S_ISLNK (dangling_link_sb.st_mode)) -+ { -+ if (x->open_dangling_dest_symlink) -+ { -+ dest_desc = open (dst_name, open_flags, -+ dst_mode & ~omitted_permissions); -+ dest_errno = errno; -+ } -+ else -+ { -+ error (0, 0, _("not writing through dangling symlink %s"), -+ quote (dst_name)); -+ return_val = false; -+ goto close_src_desc; -+ } -+ } -+ } -+ } -+ else -+ omitted_permissions = 0; -+ -+ if (dest_desc < 0) -+ { -+ error (0, dest_errno, _("cannot create regular file %s"), -+ quote (dst_name)); -+ return_val = false; -+ goto close_src_desc; -+ } -+ -+ if (fstat (dest_desc, &sb) != 0) -+ { -+ error (0, errno, _("cannot fstat %s"), quote (dst_name)); -+ return_val = false; -+ goto close_src_and_dst_desc; -+ } -+ -+ if (x->reflink_mode) -+ { -+ bool clone_ok = clone_file (dest_desc, source_desc) == 0; -+ if (clone_ok || x->reflink_mode == REFLINK_ALWAYS) -+ { -+ if (!clone_ok) -+ { -+ error (0, errno, _("failed to clone %s"), quote (dst_name)); -+ return_val = false; -+ goto close_src_and_dst_desc; -+ } -+ data_copy_required = false; -+ } -+ } -+ -+ if (data_copy_required) -+ { -+ typedef uintptr_t word; -+ off_t n_read_total = 0; -+ -+ /* Choose a suitable buffer size; it may be adjusted later. */ -+ size_t buf_alignment = lcm (getpagesize (), sizeof (word)); -+ size_t buf_alignment_slop = sizeof (word) + buf_alignment - 1; -+ size_t buf_size = io_blksize (sb); -+ -+ /* Deal with sparse files. */ -+ bool last_write_made_hole = false; -+ bool make_holes = false; -+ -+ if (S_ISREG (sb.st_mode)) -+ { -+ /* Even with --sparse=always, try to create holes only -+ if the destination is a regular file. */ -+ if (x->sparse_mode == SPARSE_ALWAYS) -+ make_holes = true; +diff -urNp coreutils-8.0-orig/src/copy.h coreutils-8.0/src/copy.h +--- coreutils-8.0-orig/src/copy.h 2009-09-21 14:29:33.000000000 +0200 ++++ coreutils-8.0/src/copy.h 2009-10-07 10:10:11.000000000 +0200 +@@ -158,6 +158,9 @@ struct cp_options + bool preserve_mode; + bool preserve_timestamps; + ++ /* If true, attempt to set specified security context */ ++ bool set_security_context; + -+#if HAVE_STRUCT_STAT_ST_BLOCKS -+ /* Use a heuristic to determine whether SRC_NAME contains any sparse -+ blocks. If the file has fewer blocks than would normally be -+ needed for a file of its size, then at least one of the blocks in -+ the file is a hole. */ -+ if (x->sparse_mode == SPARSE_AUTO && S_ISREG (src_open_sb.st_mode) -+ && ST_NBLOCKS (src_open_sb) < src_open_sb.st_size / ST_NBLOCKSIZE) -+ make_holes = true; -+#endif -+ } + /* Enabled for mv, and for cp by the --preserve=links option. + If true, attempt to preserve in the destination files any + logical hard links between the source files. If used with cp's +diff -urNp coreutils-8.0-orig/src/cp.c coreutils-8.0/src/cp.c +--- coreutils-8.0-orig/src/cp.c 2009-09-29 15:27:54.000000000 +0200 ++++ coreutils-8.0/src/cp.c 2009-10-07 10:10:11.000000000 +0200 +@@ -139,6 +139,7 @@ static struct option const long_opts[] = + {"target-directory", required_argument, NULL, 't'}, + {"update", no_argument, NULL, 'u'}, + {"verbose", no_argument, NULL, 'v'}, ++ {"context", required_argument, NULL, 'Z'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +@@ -197,6 +198,9 @@ Mandatory arguments to long options are + 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); +@@ -223,6 +227,7 @@ Mandatory arguments to long options are + 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); +@@ -777,6 +782,7 @@ cp_option_init (struct cp_options *x) + x->preserve_timestamps = false; + x->preserve_security_context = false; + x->require_preserve_context = false; ++ x->set_security_context = false; + x->preserve_xattr = false; + x->reduce_diagnostics = false; + x->require_preserve_xattr = false; +@@ -923,7 +929,7 @@ main (int argc, char **argv) + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + +- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:T", ++ while ((c = getopt_long (argc, argv, "abcdfHilLnprst:uvxPRS:TZ:", + long_opts, NULL)) + != -1) + { +@@ -966,6 +972,16 @@ main (int argc, char **argv) + copy_contents = true; + break; + ++ 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; ++ x.require_preserve_context = true; ++ } ++ break; + case 'd': + x.preserve_links = true; + x.dereference = DEREF_NEVER; +@@ -1075,6 +1091,27 @@ main (int argc, char **argv) + x.one_file_system = true; + break; + + -+ /* If not making a sparse file, try to use a more-efficient -+ buffer size. */ -+ if (! make_holes) -+ { -+ /* Compute the least common multiple of the input and output -+ buffer sizes, adjusting for outlandish values. */ -+ size_t blcm_max = MIN (SIZE_MAX, SSIZE_MAX) - buf_alignment_slop; -+ size_t blcm = buffer_lcm (io_blksize (src_open_sb), buf_size, -+ blcm_max); ++ 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; + -+ /* Do not bother with a buffer larger than the input file, plus one -+ byte to make sure the file has not grown while reading it. */ -+ if (S_ISREG (src_open_sb.st_mode) && src_open_sb.st_size < buf_size) -+ buf_size = src_open_sb.st_size + 1; -+ -+ /* However, stick with a block size that is a positive multiple of -+ blcm, overriding the above adjustments. Watch out for -+ overflow. */ -+ buf_size += blcm - 1; -+ buf_size -= buf_size % blcm; -+ if (buf_size == 0 || blcm_max < buf_size) -+ buf_size = blcm; -+ } -+ -+ /* Make a buffer with space for a sentinel at the end. */ -+ buf_alloc = xmalloc (buf_size + buf_alignment_slop); -+ buf = ptr_align (buf_alloc, buf_alignment); -+ -+ for (;;) -+ { -+ word *wp = NULL; -+ -+ ssize_t n_read = read (source_desc, buf, buf_size); -+ if (n_read < 0) -+ { -+#ifdef EINTR -+ if (errno == EINTR) -+ continue; -+#endif -+ error (0, errno, _("reading %s"), quote (src_name)); -+ return_val = false; -+ goto close_src_and_dst_desc; -+ } -+ if (n_read == 0) -+ break; -+ -+ n_read_total += n_read; -+ -+ if (make_holes) -+ { -+ char *cp; -+ -+ /* Sentinel to stop loop. */ -+ buf[n_read] = '\1'; -+#ifdef lint -+ /* Usually, buf[n_read] is not the byte just before a "word" -+ (aka uintptr_t) boundary. In that case, the word-oriented -+ test below (*wp++ == 0) would read some uninitialized bytes -+ after the sentinel. To avoid false-positive reports about -+ this condition (e.g., from a tool like valgrind), set the -+ remaining bytes -- to any value. */ -+ memset (buf + n_read + 1, 0, sizeof (word) - 1); -+#endif -+ -+ /* Find first nonzero *word*, or the word with the sentinel. */ -+ -+ wp = (word *) buf; -+ while (*wp++ == 0) -+ continue; -+ -+ /* Find the first nonzero *byte*, or the sentinel. */ -+ -+ cp = (char *) (wp - 1); -+ while (*cp++ == 0) -+ continue; -+ -+ if (cp <= buf + n_read) -+ /* Clear to indicate that a normal write is needed. */ -+ wp = NULL; -+ else -+ { -+ /* We found the sentinel, so the whole input block was zero. -+ Make a hole. */ -+ if (lseek (dest_desc, n_read, SEEK_CUR) < 0) -+ { -+ error (0, errno, _("cannot lseek %s"), quote (dst_name)); -+ return_val = false; -+ goto close_src_and_dst_desc; -+ } -+ last_write_made_hole = true; -+ } -+ } -+ -+ if (!wp) -+ { -+ size_t n = n_read; -+ if (full_write (dest_desc, buf, n) != n) -+ { -+ error (0, errno, _("writing %s"), quote (dst_name)); -+ return_val = false; -+ goto close_src_and_dst_desc; -+ } -+ last_write_made_hole = false; -+ -+ /* It is tempting to return early here upon a short read from a -+ regular file. That would save the final read syscall for each -+ file. Unfortunately that doesn't work for certain files in -+ /proc with linux kernels from at least 2.6.9 .. 2.6.29. */ -+ } -+ } -+ -+ /* If the file ends with a `hole', we need to do something to record -+ the length of the file. On modern systems, calling ftruncate does -+ the job. On systems without native ftruncate support, we have to -+ write a byte at the ending position. Otherwise the kernel would -+ truncate the file at the end of the last write operation. */ -+ -+ if (last_write_made_hole) -+ { -+ if (HAVE_FTRUNCATE -+ ? /* ftruncate sets the file size, -+ so there is no need for a write. */ -+ ftruncate (dest_desc, n_read_total) < 0 -+ : /* Seek backwards one character and write a null. */ -+ (lseek (dest_desc, (off_t) -1, SEEK_CUR) < 0L -+ || full_write (dest_desc, "", 1) != 1)) -+ { -+ error (0, errno, _("writing %s"), quote (dst_name)); -+ return_val = false; -+ goto close_src_and_dst_desc; -+ } -+ } -+ } -+ -+ if (x->preserve_timestamps) -+ { -+ struct timespec timespec[2]; -+ timespec[0] = get_stat_atime (src_sb); -+ timespec[1] = get_stat_mtime (src_sb); -+ -+ if (gl_futimens (dest_desc, dst_name, timespec) != 0) -+ { -+ error (0, errno, _("preserving times for %s"), quote (dst_name)); -+ if (x->require_preserve) -+ { -+ return_val = false; -+ goto close_src_and_dst_desc; -+ } -+ } -+ } -+ -+ /* To allow copying xattrs on read-only files, temporarily chmod u+rw. -+ This workaround is required as an inode permission check is done -+ by xattr_permission() in fs/xattr.c of the GNU/Linux kernel tree. */ -+ if (x->preserve_xattr) -+ { -+ bool access_changed = false; -+ -+ if (!(sb.st_mode & S_IWUSR) && geteuid() != 0) -+ access_changed = fchmod_or_lchmod (dest_desc, dst_name, 0600) == 0; -+ -+ if (!copy_attr_by_fd (src_name, source_desc, dst_name, dest_desc, x) -+ && x->require_preserve_xattr) -+ return_val = false; -+ -+ if (access_changed) -+ fchmod_or_lchmod (dest_desc, dst_name, dst_mode & ~omitted_permissions); -+ } -+ -+ if (x->preserve_ownership && ! SAME_OWNER_AND_GROUP (*src_sb, sb)) -+ { -+ switch (set_owner (x, dst_name, dest_desc, src_sb, *new_dst, &sb)) -+ { -+ case -1: -+ return_val = false; -+ goto close_src_and_dst_desc; -+ -+ case 0: -+ src_mode &= ~ (S_ISUID | S_ISGID | S_ISVTX); -+ break; -+ } -+ } -+ -+ set_author (dst_name, dest_desc, src_sb); -+ -+ if (x->preserve_mode || x->move_mode) -+ { -+ if (copy_acl (src_name, source_desc, dst_name, dest_desc, src_mode) != 0 -+ && x->require_preserve) -+ return_val = false; -+ } -+ else if (x->set_mode) -+ { -+ if (set_acl (dst_name, dest_desc, x->mode) != 0) -+ return_val = false; -+ } -+ else if (omitted_permissions) -+ { -+ omitted_permissions &= ~ cached_umask (); -+ if (omitted_permissions -+ && fchmod_or_lchmod (dest_desc, dst_name, dst_mode) != 0) -+ { -+ error (0, errno, _("preserving permissions for %s"), -+ quote (dst_name)); -+ if (x->require_preserve) -+ return_val = false; -+ } -+ } -+ -+close_src_and_dst_desc: -+ if (close (dest_desc) < 0) -+ { -+ error (0, errno, _("closing %s"), quote (dst_name)); -+ return_val = false; -+ } -+close_src_desc: -+ if (close (source_desc) < 0) -+ { -+ error (0, errno, _("closing %s"), quote (src_name)); -+ return_val = false; -+ } -+ -+ free (buf_alloc); -+ free (name_alloc); -+ return return_val; -+} -+ -+/* Return true if it's ok that the source and destination -+ files are the `same' by some measure. The goal is to avoid -+ making the `copy' operation remove both copies of the file -+ in that case, while still allowing the user to e.g., move or -+ copy a regular file onto a symlink that points to it. -+ Try to minimize the cost of this function in the common case. -+ Set *RETURN_NOW if we've determined that the caller has no more -+ work to do and should return successfully, right away. -+ -+ Set *UNLINK_SRC if we've determined that the caller wants to do -+ `rename (a, b)' where `a' and `b' are distinct hard links to the same -+ file. In that case, the caller should try to unlink `a' and then return -+ successfully. Ideally, we wouldn't have to do that, and we'd be -+ able to rely on rename to remove the source file. However, POSIX -+ mistakenly requires that such a rename call do *nothing* and return -+ successfully. */ -+ -+static bool -+same_file_ok (char const *src_name, struct stat const *src_sb, -+ char const *dst_name, struct stat const *dst_sb, -+ const struct cp_options *x, bool *return_now, bool *unlink_src) -+{ -+ const struct stat *src_sb_link; -+ const struct stat *dst_sb_link; -+ struct stat tmp_dst_sb; -+ struct stat tmp_src_sb; -+ -+ bool same_link; -+ bool same = SAME_INODE (*src_sb, *dst_sb); -+ -+ *return_now = false; -+ *unlink_src = false; -+ -+ /* FIXME: this should (at the very least) be moved into the following -+ if-block. More likely, it should be removed, because it inhibits -+ making backups. But removing it will result in a change in behavior -+ that will probably have to be documented -- and tests will have to -+ be updated. */ -+ if (same && x->hard_link) -+ { -+ *return_now = true; -+ return true; -+ } -+ -+ if (x->dereference == DEREF_NEVER) -+ { -+ same_link = same; -+ -+ /* If both the source and destination files are symlinks (and we'll -+ know this here IFF preserving symlinks), then it's ok -- as long -+ as they are distinct. */ -+ if (S_ISLNK (src_sb->st_mode) && S_ISLNK (dst_sb->st_mode)) -+ return ! same_name (src_name, dst_name); -+ -+ src_sb_link = src_sb; -+ dst_sb_link = dst_sb; -+ } -+ else -+ { -+ if (!same) -+ return true; -+ -+ if (lstat (dst_name, &tmp_dst_sb) != 0 -+ || lstat (src_name, &tmp_src_sb) != 0) -+ return true; -+ -+ src_sb_link = &tmp_src_sb; -+ dst_sb_link = &tmp_dst_sb; -+ -+ same_link = SAME_INODE (*src_sb_link, *dst_sb_link); -+ -+ /* If both are symlinks, then it's ok, but only if the destination -+ will be unlinked before being opened. This is like the test -+ above, but with the addition of the unlink_dest_before_opening -+ conjunct because otherwise, with two symlinks to the same target, -+ we'd end up truncating the source file. */ -+ if (S_ISLNK (src_sb_link->st_mode) && S_ISLNK (dst_sb_link->st_mode) -+ && x->unlink_dest_before_opening) -+ return true; -+ } -+ -+ /* The backup code ensures there's a copy, so it's usually ok to -+ remove any destination file. One exception is when both -+ source and destination are the same directory entry. In that -+ case, moving the destination file aside (in making the backup) -+ would also rename the source file and result in an error. */ -+ if (x->backup_type != no_backups) -+ { -+ if (!same_link) -+ { -+ /* In copy mode when dereferencing symlinks, if the source is a -+ symlink and the dest is not, then backing up the destination -+ (moving it aside) would make it a dangling symlink, and the -+ subsequent attempt to open it in copy_reg would fail with -+ a misleading diagnostic. Avoid that by returning zero in -+ that case so the caller can make cp (or mv when it has to -+ resort to reading the source file) fail now. */ -+ -+ /* FIXME-note: even with the following kludge, we can still provoke -+ the offending diagnostic. It's just a little harder to do :-) -+ $ rm -f a b c; touch c; ln -s c b; ln -s b a; cp -b a b -+ cp: cannot open `a' for reading: No such file or directory -+ That's misleading, since a subsequent `ls' shows that `a' -+ is still there. -+ One solution would be to open the source file *before* moving -+ aside the destination, but that'd involve a big rewrite. */ -+ if ( ! x->move_mode -+ && x->dereference != DEREF_NEVER -+ && S_ISLNK (src_sb_link->st_mode) -+ && ! S_ISLNK (dst_sb_link->st_mode)) -+ return false; -+ -+ return true; -+ } -+ -+ return ! same_name (src_name, dst_name); -+ } -+ -+#if 0 -+ /* FIXME: use or remove */ -+ -+ /* If we're making a backup, we'll detect the problem case in -+ copy_reg because SRC_NAME will no longer exist. Allowing -+ the test to be deferred lets cp do some useful things. -+ But when creating hardlinks and SRC_NAME is a symlink -+ but DST_NAME is not we must test anyway. */ -+ if (x->hard_link -+ || !S_ISLNK (src_sb_link->st_mode) -+ || S_ISLNK (dst_sb_link->st_mode)) -+ return true; -+ -+ if (x->dereference != DEREF_NEVER) -+ return true; -+#endif -+ -+ /* They may refer to the same file if we're in move mode and the -+ target is a symlink. That is ok, since we remove any existing -+ destination file before opening it -- via `rename' if they're on -+ the same file system, via `unlink (DST_NAME)' otherwise. -+ It's also ok if they're distinct hard links to the same file. */ -+ if (x->move_mode || x->unlink_dest_before_opening) -+ { -+ if (S_ISLNK (dst_sb_link->st_mode)) -+ return true; -+ -+ if (same_link -+ && 1 < dst_sb_link->st_nlink -+ && ! same_name (src_name, dst_name)) -+ { -+ if (x->move_mode) -+ { -+ *unlink_src = true; -+ *return_now = true; -+ } -+ return true; -+ } -+ } -+ -+ /* If neither is a symlink, then it's ok as long as they aren't -+ hard links to the same file. */ -+ if (!S_ISLNK (src_sb_link->st_mode) && !S_ISLNK (dst_sb_link->st_mode)) -+ { -+ if (!SAME_INODE (*src_sb_link, *dst_sb_link)) -+ return true; -+ -+ /* If they are the same file, it's ok if we're making hard links. */ -+ if (x->hard_link) -+ { -+ *return_now = true; -+ return true; -+ } -+ } -+ -+ /* It's ok to remove a destination symlink. But that works only when we -+ unlink before opening the destination and when the source and destination -+ files are on the same partition. */ -+ if (x->unlink_dest_before_opening -+ && S_ISLNK (dst_sb_link->st_mode)) -+ return dst_sb_link->st_dev == src_sb_link->st_dev; -+ -+ if (x->dereference == DEREF_NEVER) -+ { -+ if ( ! S_ISLNK (src_sb_link->st_mode)) -+ tmp_src_sb = *src_sb_link; -+ else if (stat (src_name, &tmp_src_sb) != 0) -+ return true; -+ -+ if ( ! S_ISLNK (dst_sb_link->st_mode)) -+ tmp_dst_sb = *dst_sb_link; -+ else if (stat (dst_name, &tmp_dst_sb) != 0) -+ return true; -+ -+ if ( ! SAME_INODE (tmp_src_sb, tmp_dst_sb)) -+ return true; -+ -+ /* FIXME: shouldn't this be testing whether we're making symlinks? */ -+ if (x->hard_link) -+ { -+ *return_now = true; -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+/* Return true if FILE, with mode MODE, is writable in the sense of 'mv'. -+ Always consider a symbolic link to be writable. */ -+static bool -+writable_destination (char const *file, mode_t mode) -+{ -+ return (S_ISLNK (mode) -+ || can_write_any_file () -+ || euidaccess (file, W_OK) == 0); -+} -+ -+static void -+overwrite_prompt (char const *dst_name, struct stat const *dst_sb) -+{ -+ if (! writable_destination (dst_name, dst_sb->st_mode)) -+ { -+ char perms[12]; /* "-rwxrwxrwx " ls-style modes. */ -+ strmode (dst_sb->st_mode, perms); -+ perms[10] = '\0'; -+ fprintf (stderr, -+ _("%s: try to overwrite %s, overriding mode %04lo (%s)? "), -+ program_name, quote (dst_name), -+ (unsigned long int) (dst_sb->st_mode & CHMOD_MODE_BITS), -+ &perms[1]); -+ } -+ else -+ { -+ fprintf (stderr, _("%s: overwrite %s? "), -+ program_name, quote (dst_name)); -+ } -+} -+ -+/* Initialize the hash table implementing a set of F_triple entries -+ corresponding to destination files. */ -+extern void -+dest_info_init (struct cp_options *x) -+{ -+ x->dest_info -+ = hash_initialize (DEST_INFO_INITIAL_CAPACITY, -+ NULL, -+ triple_hash, -+ triple_compare, -+ triple_free); -+} -+ -+/* Initialize the hash table implementing a set of F_triple entries -+ corresponding to source files listed on the command line. */ -+extern void -+src_info_init (struct cp_options *x) -+{ -+ -+ /* Note that we use triple_hash_no_name here. -+ Contrast with the use of triple_hash above. -+ That is necessary because a source file may be specified -+ in many different ways. We want to warn about this -+ cp a a d/ -+ as well as this: -+ cp a ./a d/ -+ */ -+ x->src_info -+ = hash_initialize (DEST_INFO_INITIAL_CAPACITY, -+ NULL, -+ triple_hash_no_name, -+ triple_compare, -+ triple_free); -+} -+ -+/* When effecting a move (e.g., for mv(1)), and given the name DST_NAME -+ of the destination and a corresponding stat buffer, DST_SB, return -+ true if the logical `move' operation should _not_ proceed. -+ Otherwise, return false. -+ Depending on options specified in X, this code may issue an -+ interactive prompt asking whether it's ok to overwrite DST_NAME. */ -+static bool -+abandon_move (const struct cp_options *x, -+ char const *dst_name, -+ struct stat const *dst_sb) -+{ -+ assert (x->move_mode); -+ return (x->interactive == I_ALWAYS_NO -+ || ((x->interactive == I_ASK_USER -+ || (x->interactive == I_UNSPECIFIED -+ && x->stdin_tty -+ && ! writable_destination (dst_name, dst_sb->st_mode))) -+ && (overwrite_prompt (dst_name, dst_sb), 1) -+ && ! yesno ())); -+} -+ -+/* Print --verbose output on standard output, e.g. `new' -> `old'. -+ If BACKUP_DST_NAME is non-NULL, then also indicate that it is -+ the name of a backup file. */ -+static void -+emit_verbose (char const *src, char const *dst, char const *backup_dst_name) -+{ -+ printf ("%s -> %s", quote_n (0, src), quote_n (1, dst)); -+ if (backup_dst_name) -+ printf (_(" (backup: %s)"), quote (backup_dst_name)); -+ putchar ('\n'); -+} -+ -+/* A wrapper around "setfscreatecon (NULL)" that exits upon failure. */ -+static void -+restore_default_fscreatecon_or_die (void) -+{ -+ if (setfscreatecon (NULL) != 0) -+ error (EXIT_FAILURE, errno, -+ _("failed to restore the default file creation context")); -+} -+ -+/* Copy the file SRC_NAME to the file DST_NAME. The files may be of -+ any type. NEW_DST should be true if the file DST_NAME cannot -+ exist because its parent directory was just created; NEW_DST should -+ be false if DST_NAME might already exist. DEVICE is the device -+ number of the parent directory, or 0 if the parent of this file is -+ not known. ANCESTORS points to a linked, null terminated list of -+ devices and inodes of parent directories of SRC_NAME. COMMAND_LINE_ARG -+ is true iff SRC_NAME was specified on the command line. -+ FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG is both input and output. -+ Set *COPY_INTO_SELF if SRC_NAME is a parent of (or the -+ same as) DST_NAME; otherwise, clear it. -+ Return true if successful. */ -+static bool -+copy_internal (char const *src_name, char const *dst_name, -+ bool new_dst, -+ dev_t device, -+ struct dir_list *ancestors, -+ const struct cp_options *x, -+ bool command_line_arg, -+ bool *first_dir_created_per_command_line_arg, -+ bool *copy_into_self, -+ bool *rename_succeeded) -+{ -+ struct stat src_sb; -+ struct stat dst_sb; -+ mode_t src_mode; -+ mode_t dst_mode IF_LINT (= 0); -+ mode_t dst_mode_bits; -+ mode_t omitted_permissions; -+ bool restore_dst_mode = false; -+ char *earlier_file = NULL; -+ char *dst_backup = NULL; -+ bool backup_succeeded = false; -+ bool delayed_ok; -+ bool copied_as_regular = false; -+ bool dest_is_symlink = false; -+ bool have_dst_lstat = false; -+ -+ if (x->move_mode && rename_succeeded) -+ *rename_succeeded = false; -+ -+ *copy_into_self = false; -+ -+ if (XSTAT (x, src_name, &src_sb) != 0) -+ { -+ error (0, errno, _("cannot stat %s"), quote (src_name)); -+ return false; -+ } -+ -+ src_mode = src_sb.st_mode; -+ -+ if (S_ISDIR (src_mode) && !x->recursive) -+ { -+ error (0, 0, _("omitting directory %s"), quote (src_name)); -+ return false; -+ } -+ -+ /* Detect the case in which the same source file appears more than -+ once on the command line and no backup option has been selected. -+ If so, simply warn and don't copy it the second time. -+ This check is enabled only if x->src_info is non-NULL. */ -+ if (command_line_arg) -+ { -+ if ( ! S_ISDIR (src_sb.st_mode) -+ && x->backup_type == no_backups -+ && seen_file (x->src_info, src_name, &src_sb)) -+ { -+ error (0, 0, _("warning: source file %s specified more than once"), -+ quote (src_name)); -+ return true; -+ } -+ -+ record_file (x->src_info, src_name, &src_sb); -+ } -+ -+ if (!new_dst) -+ { -+ /* Regular files can be created by writing through symbolic -+ links, but other files cannot. So use stat on the -+ destination when copying a regular file, and lstat otherwise. -+ However, if we intend to unlink or remove the destination -+ first, use lstat, since a copy won't actually be made to the -+ destination in that case. */ -+ bool use_stat = -+ ((S_ISREG (src_mode) -+ || (x->copy_as_regular -+ && ! (S_ISDIR (src_mode) || S_ISLNK (src_mode)))) -+ && ! (x->move_mode || x->symbolic_link || x->hard_link -+ || x->backup_type != no_backups -+ || x->unlink_dest_before_opening)); -+ if ((use_stat -+ ? stat (dst_name, &dst_sb) -+ : lstat (dst_name, &dst_sb)) -+ != 0) -+ { -+ if (errno != ENOENT) -+ { -+ error (0, errno, _("cannot stat %s"), quote (dst_name)); -+ return false; -+ } -+ else -+ { -+ new_dst = true; -+ } -+ } -+ else -+ { /* Here, we know that dst_name exists, at least to the point -+ that it is stat'able or lstat'able. */ -+ bool return_now; -+ bool unlink_src; -+ -+ have_dst_lstat = !use_stat; -+ if (! same_file_ok (src_name, &src_sb, dst_name, &dst_sb, -+ x, &return_now, &unlink_src)) -+ { -+ error (0, 0, _("%s and %s are the same file"), -+ quote_n (0, src_name), quote_n (1, 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 -+ prompt about the existing file. It may also be due to the -+ use of the --reply=no option. -+ -+ cp and mv treat -i and -f differently. */ -+ if (x->move_mode) -+ { -+ if (abandon_move (x, dst_name, &dst_sb) -+ || (unlink_src && unlink (src_name) == 0)) -+ { -+ /* Pretend the rename succeeded, so the caller (mv) -+ doesn't end up removing the source file. */ -+ if (rename_succeeded) -+ *rename_succeeded = true; -+ if (unlink_src && x->verbose) -+ printf (_("removed %s\n"), quote (src_name)); -+ return true; -+ } -+ if (unlink_src) -+ { -+ error (0, errno, _("cannot remove %s"), quote (src_name)); -+ return false; -+ } -+ } -+ else -+ { -+ if (! S_ISDIR (src_mode) -+ && (x->interactive == I_ALWAYS_NO -+ || (x->interactive == I_ASK_USER -+ && (overwrite_prompt (dst_name, &dst_sb), 1) -+ && ! yesno ()))) -+ return true; -+ } -+ -+ if (return_now) -+ return true; -+ -+ if (!S_ISDIR (dst_sb.st_mode)) -+ { -+ if (S_ISDIR (src_mode)) -+ { -+ if (x->move_mode && x->backup_type != no_backups) -+ { -+ /* Moving a directory onto an existing -+ non-directory is ok only with --backup. */ -+ } -+ else -+ { -+ error (0, 0, -+ _("cannot overwrite non-directory %s with directory %s"), -+ quote_n (0, dst_name), quote_n (1, src_name)); -+ return false; -+ } -+ } -+ -+ /* Don't let the user destroy their data, even if they try hard: -+ This mv command must fail (likewise for cp): -+ rm -rf a b c; mkdir a b c; touch a/f b/f; mv a/f b/f c -+ Otherwise, the contents of b/f would be lost. -+ In the case of `cp', b/f would be lost if the user simulated -+ a move using cp and rm. -+ Note that it works fine if you use --backup=numbered. */ -+ if (command_line_arg -+ && x->backup_type != numbered_backups -+ && seen_file (x->dest_info, dst_name, &dst_sb)) -+ { -+ error (0, 0, -+ _("will not overwrite just-created %s with %s"), -+ quote_n (0, dst_name), quote_n (1, src_name)); -+ return false; -+ } -+ } -+ -+ if (!S_ISDIR (src_mode)) -+ { -+ if (S_ISDIR (dst_sb.st_mode)) -+ { -+ if (x->move_mode && x->backup_type != no_backups) -+ { -+ /* Moving a non-directory onto an existing -+ directory is ok only with --backup. */ -+ } -+ else -+ { -+ error (0, 0, -+ _("cannot overwrite directory %s with non-directory"), -+ quote (dst_name)); -+ return false; -+ } -+ } -+ } -+ -+ if (x->move_mode) -+ { -+ /* Don't allow user to move a directory onto a non-directory. */ -+ if (S_ISDIR (src_sb.st_mode) && !S_ISDIR (dst_sb.st_mode) -+ && x->backup_type == no_backups) -+ { -+ error (0, 0, -+ _("cannot move directory onto non-directory: %s -> %s"), -+ quote_n (0, src_name), quote_n (0, dst_name)); -+ return false; -+ } -+ } -+ -+ if (x->backup_type != no_backups -+ /* Don't try to back up a destination if the last -+ component of src_name is "." or "..". */ -+ && ! dot_or_dotdot (last_component (src_name)) -+ /* Create a backup of each destination directory in move mode, -+ but not in copy mode. FIXME: it might make sense to add an -+ option to suppress backup creation also for move mode. -+ That would let one use mv to merge new content into an -+ existing hierarchy. */ -+ && (x->move_mode || ! S_ISDIR (dst_sb.st_mode))) -+ { -+ char *tmp_backup = find_backup_file_name (dst_name, -+ x->backup_type); -+ -+ /* Detect (and fail) when creating the backup file would -+ destroy the source file. Before, running the commands -+ cd /tmp; rm -f a a~; : > a; echo A > a~; cp --b=simple a~ a -+ would leave two zero-length files: a and a~. */ -+ /* FIXME: but simply change e.g., the final a~ to `./a~' -+ and the source will still be destroyed. */ -+ if (STREQ (tmp_backup, src_name)) -+ { -+ const char *fmt; -+ fmt = (x->move_mode -+ ? _("backing up %s would destroy source; %s not moved") -+ : _("backing up %s would destroy source; %s not copied")); -+ error (0, 0, fmt, -+ quote_n (0, dst_name), -+ quote_n (1, src_name)); -+ free (tmp_backup); -+ return false; -+ } -+ -+ /* FIXME: use fts: -+ Using alloca for a file name that may be arbitrarily -+ long is not recommended. In fact, even forming such a name -+ should be discouraged. Eventually, this code will be rewritten -+ to use fts, so using alloca here will be less of a problem. */ -+ ASSIGN_STRDUPA (dst_backup, tmp_backup); -+ free (tmp_backup); -+ if (rename (dst_name, dst_backup) != 0) -+ { -+ if (errno != ENOENT) -+ { -+ error (0, errno, _("cannot backup %s"), quote (dst_name)); -+ return false; -+ } -+ else -+ { -+ dst_backup = NULL; -+ } -+ } -+ else -+ { -+ backup_succeeded = true; -+ } -+ 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->dereference == DEREF_NEVER -+ && ! S_ISREG (src_sb.st_mode)) -+ )) -+ { -+ if (unlink (dst_name) != 0 && errno != ENOENT) -+ { -+ error (0, errno, _("cannot remove %s"), quote (dst_name)); -+ return false; -+ } -+ new_dst = true; -+ if (x->verbose) -+ printf (_("removed %s\n"), quote (dst_name)); -+ } -+ } -+ } -+ -+ /* Ensure we don't try to copy through a symlink that was -+ created by a prior call to this function. */ -+ if (command_line_arg -+ && x->dest_info -+ && ! x->move_mode -+ && x->backup_type == no_backups) -+ { -+ bool lstat_ok = true; -+ struct stat tmp_buf; -+ struct stat *dst_lstat_sb; -+ -+ /* If we called lstat above, good: use that data. -+ Otherwise, call lstat here, in case dst_name is a symlink. */ -+ if (have_dst_lstat) -+ dst_lstat_sb = &dst_sb; -+ else -+ { -+ if (lstat (dst_name, &tmp_buf) == 0) -+ dst_lstat_sb = &tmp_buf; -+ else -+ lstat_ok = false; -+ } -+ -+ /* Never copy through a symlink we've just created. */ -+ if (lstat_ok -+ && S_ISLNK (dst_lstat_sb->st_mode) -+ && seen_file (x->dest_info, dst_name, dst_lstat_sb)) -+ { -+ error (0, 0, -+ _("will not copy %s through just-created symlink %s"), -+ quote_n (0, src_name), quote_n (1, dst_name)); -+ return false; -+ } -+ } -+ -+ /* If the source is a directory, we don't always create the destination -+ directory. So --verbose should not announce anything until we're -+ sure we'll create a directory. */ -+ if (x->verbose && !S_ISDIR (src_mode)) -+ emit_verbose (src_name, dst_name, backup_succeeded ? dst_backup : NULL); -+ -+ /* Associate the destination file name with the source device and inode -+ so that if we encounter a matching dev/ino pair in the source tree -+ we can arrange to create a hard link between the corresponding names -+ in the destination tree. -+ -+ When using the --link (-l) option, there is no need to take special -+ measures, because (barring race conditions) files that are hard-linked -+ in the source tree will also be hard-linked in the destination tree. -+ -+ Sometimes, when preserving links, we have to record dev/ino even -+ though st_nlink == 1: -+ - when in move_mode, since we may be moving a group of N hard-linked -+ files (via two or more command line arguments) to a different -+ partition; the links may be distributed among the command line -+ arguments (possibly hierarchies) so that the link count of -+ the final, once-linked source file is reduced to 1 when it is -+ considered below. But in this case (for mv) we don't need to -+ incur the expense of recording the dev/ino => name mapping; all we -+ really need is a lookup, to see if the dev/ino pair has already -+ been copied. -+ - when using -H and processing a command line argument; -+ that command line argument could be a symlink pointing to another -+ command line argument. With `cp -H --preserve=link', we hard-link -+ those two destination files. -+ - likewise for -L except that it applies to all files, not just -+ command line arguments. -+ -+ Also, with --recursive, record dev/ino of each command-line directory. -+ We'll use that info to detect this problem: cp -R dir dir. */ -+ -+ if (x->move_mode && src_sb.st_nlink == 1) -+ { -+ earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev); -+ } -+ else if (x->preserve_links -+ && !x->hard_link -+ && (1 < src_sb.st_nlink -+ || (command_line_arg -+ && x->dereference == DEREF_COMMAND_LINE_ARGUMENTS) -+ || x->dereference == DEREF_ALWAYS)) -+ { -+ earlier_file = remember_copied (dst_name, src_sb.st_ino, src_sb.st_dev); -+ } -+ else if (x->recursive && S_ISDIR (src_mode)) -+ { -+ if (command_line_arg) -+ earlier_file = remember_copied (dst_name, src_sb.st_ino, src_sb.st_dev); -+ else -+ earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev); -+ } -+ -+ /* Did we copy this inode somewhere else (in this command line argument) -+ and therefore this is a second hard link to the inode? */ -+ -+ if (earlier_file) -+ { -+ /* Avoid damaging the destination file system by refusing to preserve -+ hard-linked directories (which are found at least in Netapp snapshot -+ directories). */ -+ if (S_ISDIR (src_mode)) -+ { -+ /* If src_name and earlier_file refer to the same directory entry, -+ then warn about copying a directory into itself. */ -+ if (same_name (src_name, earlier_file)) -+ { -+ error (0, 0, _("cannot copy a directory, %s, into itself, %s"), -+ quote_n (0, top_level_src_name), -+ quote_n (1, top_level_dst_name)); -+ *copy_into_self = true; -+ goto un_backup; -+ } -+ else if (x->dereference == DEREF_ALWAYS) -+ { -+ /* This happens when e.g., encountering a directory for the -+ second or subsequent time via symlinks when cp is invoked -+ with -R and -L. E.g., -+ rm -rf a b c d; mkdir a b c d; ln -s ../c a; ln -s ../c b; -+ cp -RL a b d -+ */ -+ } -+ else -+ { -+ error (0, 0, _("will not create hard link %s to directory %s"), -+ quote_n (0, dst_name), quote_n (1, earlier_file)); -+ goto un_backup; -+ } -+ } -+ else -+ { -+ /* We want to guarantee that symlinks are not followed. */ -+ bool link_failed = (linkat (AT_FDCWD, earlier_file, AT_FDCWD, -+ dst_name, 0) != 0); -+ -+ /* If the link failed because of an existing destination, -+ remove that file and then call link again. */ -+ if (link_failed && errno == EEXIST) -+ { -+ if (unlink (dst_name) != 0) -+ { -+ error (0, errno, _("cannot remove %s"), quote (dst_name)); -+ goto un_backup; -+ } -+ if (x->verbose) -+ printf (_("removed %s\n"), quote (dst_name)); -+ link_failed = (linkat (AT_FDCWD, earlier_file, AT_FDCWD, -+ dst_name, 0) != 0); -+ } -+ -+ if (link_failed) -+ { -+ error (0, errno, _("cannot create hard link %s to %s"), -+ quote_n (0, dst_name), quote_n (1, earlier_file)); -+ goto un_backup; -+ } -+ -+ return true; -+ } -+ } -+ -+ if (x->move_mode) -+ { -+ if (rename (src_name, dst_name) == 0) -+ { -+ if (x->verbose && S_ISDIR (src_mode)) -+ emit_verbose (src_name, dst_name, -+ backup_succeeded ? dst_backup : NULL); -+ -+ if (rename_succeeded) -+ *rename_succeeded = true; -+ -+ if (command_line_arg) -+ { -+ /* Record destination dev/ino/name, so that if we are asked -+ to overwrite that file again, we can detect it and fail. */ -+ /* It's fine to use the _source_ stat buffer (src_sb) to get the -+ _destination_ dev/ino, since the rename above can't have -+ changed those, and `mv' always uses lstat. -+ We could limit it further by operating -+ only on non-directories. */ -+ record_file (x->dest_info, dst_name, &src_sb); -+ } -+ -+ return true; -+ } -+ -+ /* FIXME: someday, consider what to do when moving a directory into -+ itself but when source and destination are on different devices. */ -+ -+ /* This happens when attempting to rename a directory to a -+ subdirectory of itself. */ -+ if (errno == EINVAL) -+ { -+ /* FIXME: this is a little fragile in that it relies on rename(2) -+ failing with a specific errno value. Expect problems on -+ non-POSIX systems. */ -+ error (0, 0, _("cannot move %s to a subdirectory of itself, %s"), -+ quote_n (0, top_level_src_name), -+ quote_n (1, top_level_dst_name)); -+ -+ /* Note that there is no need to call forget_created here, -+ (compare with the other calls in this file) since the -+ destination directory didn't exist before. */ -+ -+ *copy_into_self = true; -+ /* FIXME-cleanup: Don't return true here; adjust mv.c accordingly. -+ The only caller that uses this code (mv.c) ends up setting its -+ exit status to nonzero when copy_into_self is nonzero. */ -+ return true; -+ } -+ -+ /* WARNING: there probably exist systems for which an inter-device -+ rename fails with a value of errno not handled here. -+ If/as those are reported, add them to the condition below. -+ If this happens to you, please do the following and send the output -+ to the bug-reporting address (e.g., in the output of cp --help): -+ touch k; perl -e 'rename "k","/tmp/k" or print "$!(",$!+0,")\n"' -+ where your current directory is on one partion and /tmp is the other. -+ Also, please try to find the E* errno macro name corresponding to -+ the diagnostic and parenthesized integer, and include that in your -+ e-mail. One way to do that is to run a command like this -+ find /usr/include/. -type f \ -+ | xargs grep 'define.*\.*\<18\>' /dev/null -+ where you'd replace `18' with the integer in parentheses that -+ was output from the perl one-liner above. -+ If necessary, of course, change `/tmp' to some other directory. */ -+ if (errno != EXDEV) -+ { -+ /* There are many ways this can happen due to a race condition. -+ When something happens between the initial XSTAT and the -+ subsequent rename, we can get many different types of errors. -+ For example, if the destination is initially a non-directory -+ or non-existent, but it is created as a directory, the rename -+ fails. If two `mv' commands try to rename the same file at -+ about the same time, one will succeed and the other will fail. -+ If the permissions on the directory containing the source or -+ destination file are made too restrictive, the rename will -+ fail. Etc. */ -+ error (0, errno, -+ _("cannot move %s to %s"), -+ quote_n (0, src_name), quote_n (1, dst_name)); -+ forget_created (src_sb.st_ino, src_sb.st_dev); -+ return false; -+ } -+ -+ /* The rename attempt has failed. Remove any existing destination -+ file so that a cross-device `mv' acts as if it were really using -+ the rename syscall. */ -+ if (unlink (dst_name) != 0 && errno != ENOENT) -+ { -+ error (0, errno, -+ _("inter-device move failed: %s to %s; unable to remove target"), -+ quote_n (0, src_name), quote_n (1, dst_name)); -+ forget_created (src_sb.st_ino, src_sb.st_dev); -+ return false; -+ } -+ -+ new_dst = true; -+ } -+ -+ /* If the ownership might change, or if it is a directory (whose -+ special mode bits may change after the directory is created), -+ omit some permissions at first, so unauthorized users cannot nip -+ in before the file is ready. */ -+ dst_mode_bits = (x->set_mode ? x->mode : src_mode) & CHMOD_MODE_BITS; -+ omitted_permissions = -+ (dst_mode_bits -+ & (x->preserve_ownership ? S_IRWXG | S_IRWXO -+ : S_ISDIR (src_mode) ? S_IWGRP | S_IWOTH -+ : 0)); -+ -+ delayed_ok = true; -+ -+ if (x->preserve_security_context) -+ { -+ security_context_t con; -+ -+ if (0 <= lgetfilecon (src_name, &con)) -+ { -+ if (setfscreatecon (con) < 0) -+ { -+ if (!x->reduce_diagnostics || x->require_preserve_context) -+ error (0, errno, -+ _("failed to set default file creation context to %s"), -+ quote (con)); -+ if (x->require_preserve_context) -+ { -+ freecon (con); -+ return false; -+ } -+ } -+ freecon (con); -+ } -+ else -+ { -+ if (!errno_unsupported (errno) || x->require_preserve_context) -+ { -+ if (!x->reduce_diagnostics || x->require_preserve_context) -+ error (0, errno, -+ _("failed to get security context of %s"), -+ quote (src_name)); -+ if (x->require_preserve_context) -+ return false; -+ } -+ } -+ } -+ -+ if (S_ISDIR (src_mode)) -+ { -+ struct dir_list *dir; -+ -+ /* If this directory has been copied before during the -+ recursion, there is a symbolic link to an ancestor -+ directory of the symbolic link. It is impossible to -+ continue to copy this, unless we've got an infinite disk. */ -+ -+ if (is_ancestor (&src_sb, ancestors)) -+ { -+ error (0, 0, _("cannot copy cyclic symbolic link %s"), -+ quote (src_name)); -+ goto un_backup; -+ } -+ -+ /* Insert the current directory in the list of parents. */ -+ -+ dir = alloca (sizeof *dir); -+ dir->parent = ancestors; -+ dir->ino = src_sb.st_ino; -+ dir->dev = src_sb.st_dev; -+ -+ if (new_dst || !S_ISDIR (dst_sb.st_mode)) -+ { -+ /* POSIX says mkdir's behavior is implementation-defined when -+ (src_mode & ~S_IRWXUGO) != 0. However, common practice is -+ to ask mkdir to copy all the CHMOD_MODE_BITS, letting mkdir -+ decide what to do with S_ISUID | S_ISGID | S_ISVTX. */ -+ if (mkdir (dst_name, dst_mode_bits & ~omitted_permissions) != 0) -+ { -+ error (0, errno, _("cannot create directory %s"), -+ quote (dst_name)); -+ goto un_backup; -+ } -+ -+ /* We need search and write permissions to the new directory -+ for writing the directory's contents. Check if these -+ permissions are there. */ -+ -+ if (lstat (dst_name, &dst_sb) != 0) -+ { -+ error (0, errno, _("cannot stat %s"), quote (dst_name)); -+ goto un_backup; -+ } -+ else if ((dst_sb.st_mode & S_IRWXU) != S_IRWXU) -+ { -+ /* Make the new directory searchable and writable. */ -+ -+ dst_mode = dst_sb.st_mode; -+ restore_dst_mode = true; -+ -+ if (lchmod (dst_name, dst_mode | S_IRWXU) != 0) -+ { -+ error (0, errno, _("setting permissions for %s"), -+ quote (dst_name)); -+ goto un_backup; -+ } -+ } -+ -+ /* Record the created directory's inode and device numbers into -+ the search structure, so that we can avoid copying it again. -+ Do this only for the first directory that is created for each -+ source command line argument. */ -+ if (!*first_dir_created_per_command_line_arg) -+ { -+ remember_copied (dst_name, dst_sb.st_ino, dst_sb.st_dev); -+ *first_dir_created_per_command_line_arg = true; -+ } -+ -+ if (x->verbose) -+ emit_verbose (src_name, dst_name, NULL); -+ } -+ -+ /* Decide whether to copy the contents of the directory. */ -+ if (x->one_file_system && device != 0 && device != src_sb.st_dev) -+ { -+ /* 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. */ -+ } -+ else -+ { -+ /* Copy the contents of the directory. Don't just return if -+ this fails -- otherwise, the failure to read a single file -+ in a source directory would cause the containing destination -+ directory not to have owner/perms set properly. */ -+ delayed_ok = copy_dir (src_name, dst_name, new_dst, &src_sb, dir, x, -+ first_dir_created_per_command_line_arg, -+ copy_into_self); -+ } -+ } -+ else if (x->symbolic_link) -+ { -+ dest_is_symlink = true; -+ if (*src_name != '/') -+ { -+ /* Check that DST_NAME denotes a file in the current directory. */ -+ struct stat dot_sb; -+ struct stat dst_parent_sb; -+ char *dst_parent; -+ bool in_current_dir; -+ -+ dst_parent = dir_name (dst_name); -+ -+ in_current_dir = (STREQ (".", dst_parent) -+ /* If either stat call fails, it's ok not to report -+ the failure and say dst_name is in the current -+ directory. Other things will fail later. */ -+ || stat (".", &dot_sb) != 0 -+ || stat (dst_parent, &dst_parent_sb) != 0 -+ || SAME_INODE (dot_sb, dst_parent_sb)); -+ free (dst_parent); -+ -+ if (! in_current_dir) -+ { -+ error (0, 0, -+ _("%s: can make relative symbolic links only in current directory"), -+ quote (dst_name)); -+ goto un_backup; -+ } -+ } -+ if (symlink (src_name, dst_name) != 0) -+ { -+ error (0, errno, _("cannot create symbolic link %s to %s"), -+ quote_n (0, dst_name), quote_n (1, src_name)); -+ goto un_backup; -+ } -+ } -+ -+ /* cp, invoked with `--link --no-dereference', should not follow the -+ link; we guarantee this with gnulib's linkat module (on systems -+ where link(2) follows the link, gnulib creates a symlink with -+ identical contents, which is good enough for our purposes). */ -+ else if (x->hard_link -+ && (!S_ISLNK (src_mode) -+ || x->dereference != DEREF_NEVER)) -+ { -+ if (linkat (AT_FDCWD, src_name, AT_FDCWD, dst_name, 0)) -+ { -+ error (0, errno, _("cannot create link %s"), quote (dst_name)); -+ goto un_backup; -+ } -+ } -+ else if (S_ISREG (src_mode) -+ || (x->copy_as_regular && !S_ISLNK (src_mode))) -+ { -+ copied_as_regular = true; -+ /* POSIX says the permission bits of the source file must be -+ used as the 3rd argument in the open call. Historical -+ practice passed all the source mode bits to 'open', but the extra -+ bits were ignored, so it should be the same either way. */ -+ if (! copy_reg (src_name, dst_name, x, src_mode & S_IRWXUGO, -+ omitted_permissions, &new_dst, &src_sb)) -+ goto un_backup; -+ } -+ else if (S_ISFIFO (src_mode)) -+ { -+ /* Use mknod, rather than mkfifo, because the former preserves -+ the special mode bits of a fifo on Solaris 10, while mkfifo -+ does not. But fall back on mkfifo, because on some BSD systems, -+ mknod always fails when asked to create a FIFO. */ -+ if (mknod (dst_name, src_mode & ~omitted_permissions, 0) != 0) -+ if (mkfifo (dst_name, src_mode & ~S_IFIFO & ~omitted_permissions) != 0) -+ { -+ error (0, errno, _("cannot create fifo %s"), quote (dst_name)); -+ goto un_backup; -+ } -+ } -+ else if (S_ISBLK (src_mode) || S_ISCHR (src_mode) || S_ISSOCK (src_mode)) -+ { -+ if (mknod (dst_name, src_mode & ~omitted_permissions, src_sb.st_rdev) -+ != 0) -+ { -+ error (0, errno, _("cannot create special file %s"), -+ quote (dst_name)); -+ goto un_backup; -+ } -+ } -+ else if (S_ISLNK (src_mode)) -+ { -+ char *src_link_val = areadlink_with_size (src_name, src_sb.st_size); -+ dest_is_symlink = true; -+ if (src_link_val == NULL) -+ { -+ error (0, errno, _("cannot read symbolic link %s"), quote (src_name)); -+ goto un_backup; -+ } -+ -+ if (symlink (src_link_val, dst_name) == 0) -+ free (src_link_val); -+ else -+ { -+ int saved_errno = errno; -+ bool same_link = false; -+ if (x->update && !new_dst && S_ISLNK (dst_sb.st_mode) -+ && dst_sb.st_size == strlen (src_link_val)) -+ { -+ /* See if the destination is already the desired symlink. -+ FIXME: This behavior isn't documented, and seems wrong -+ in some cases, e.g., if the destination symlink has the -+ wrong ownership, permissions, or time stamps. */ -+ char *dest_link_val = -+ areadlink_with_size (dst_name, dst_sb.st_size); -+ if (dest_link_val && STREQ (dest_link_val, src_link_val)) -+ same_link = true; -+ free (dest_link_val); -+ } -+ free (src_link_val); -+ -+ if (! same_link) -+ { -+ error (0, saved_errno, _("cannot create symbolic link %s"), -+ quote (dst_name)); -+ goto un_backup; -+ } -+ } -+ -+ if (x->preserve_security_context) -+ restore_default_fscreatecon_or_die (); -+ -+ if (x->preserve_ownership) -+ { -+ /* Preserve the owner and group of the just-`copied' -+ symbolic link, if possible. */ -+ if (HAVE_LCHOWN -+ && lchown (dst_name, src_sb.st_uid, src_sb.st_gid) != 0 -+ && ! chown_failure_ok (x)) -+ { -+ error (0, errno, _("failed to preserve ownership for %s"), -+ dst_name); -+ goto un_backup; -+ } -+ else -+ { -+ /* Can't preserve ownership of symlinks. -+ FIXME: maybe give a warning or even error for symlinks -+ in directories with the sticky bit set -- there, not -+ preserving owner/group is a potential security problem. */ -+ } -+ } -+ } -+ else -+ { -+ error (0, 0, _("%s has unknown file type"), quote (src_name)); -+ goto un_backup; -+ } -+ -+ if (command_line_arg && x->dest_info) -+ { -+ /* Now that the destination file is very likely to exist, -+ add its info to the set. */ -+ struct stat sb; -+ if (lstat (dst_name, &sb) == 0) -+ record_file (x->dest_info, dst_name, &sb); -+ } -+ -+ /* If we've just created a hard-link due to cp's --link option, -+ we're done. */ -+ if (x->hard_link && ! S_ISDIR (src_mode)) -+ return delayed_ok; -+ -+ if (copied_as_regular) -+ return delayed_ok; -+ -+ /* POSIX says that `cp -p' must restore the following: -+ - permission bits -+ - setuid, setgid bits -+ - owner and group -+ If it fails to restore any of those, we may give a warning but -+ the destination must not be removed. -+ FIXME: implement the above. */ -+ -+ /* Adjust the times (and if possible, ownership) for the copy. -+ chown turns off set[ug]id bits for non-root, -+ so do the chmod last. */ -+ -+ if (x->preserve_timestamps) -+ { -+ struct timespec timespec[2]; -+ timespec[0] = get_stat_atime (&src_sb); -+ timespec[1] = get_stat_mtime (&src_sb); -+ -+ if ((dest_is_symlink -+ ? utimens_symlink (dst_name, timespec) -+ : utimens (dst_name, timespec)) -+ != 0) -+ { -+ error (0, errno, _("preserving times for %s"), quote (dst_name)); -+ if (x->require_preserve) -+ return false; -+ } -+ } -+ -+ /* The operations beyond this point may dereference a symlink. */ -+ if (dest_is_symlink) -+ return delayed_ok; -+ -+ /* Avoid calling chown if we know it's not necessary. */ -+ if (x->preserve_ownership -+ && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) -+ { -+ switch (set_owner (x, dst_name, -1, &src_sb, new_dst, &dst_sb)) -+ { -+ case -1: -+ return false; -+ -+ case 0: -+ src_mode &= ~ (S_ISUID | S_ISGID | S_ISVTX); -+ break; -+ } -+ } -+ -+ set_author (dst_name, -1, &src_sb); -+ -+ if (x->preserve_xattr && ! copy_attr_by_name (src_name, dst_name, x) -+ && x->require_preserve_xattr) -+ return false; -+ -+ if (x->preserve_mode || x->move_mode) -+ { -+ if (copy_acl (src_name, -1, dst_name, -1, src_mode) != 0 -+ && x->require_preserve) -+ return false; -+ } -+ else if (x->set_mode) -+ { -+ if (set_acl (dst_name, -1, x->mode) != 0) -+ return false; -+ } -+ else -+ { -+ if (omitted_permissions) -+ { -+ omitted_permissions &= ~ cached_umask (); -+ -+ if (omitted_permissions && !restore_dst_mode) -+ { -+ /* Permissions were deliberately omitted when the file -+ was created due to security concerns. See whether -+ they need to be re-added now. It'd be faster to omit -+ the lstat, but deducing the current destination mode -+ is tricky in the presence of implementation-defined -+ rules for special mode bits. */ -+ if (new_dst && lstat (dst_name, &dst_sb) != 0) -+ { -+ error (0, errno, _("cannot stat %s"), quote (dst_name)); -+ return false; -+ } -+ dst_mode = dst_sb.st_mode; -+ if (omitted_permissions & ~dst_mode) -+ restore_dst_mode = true; -+ } -+ } -+ -+ if (restore_dst_mode) -+ { -+ if (lchmod (dst_name, dst_mode | omitted_permissions) != 0) -+ { -+ error (0, errno, _("preserving permissions for %s"), -+ quote (dst_name)); -+ if (x->require_preserve) -+ return false; -+ } -+ } -+ } -+ -+ return delayed_ok; -+ -+un_backup: -+ -+ if (x->preserve_security_context) -+ restore_default_fscreatecon_or_die (); -+ -+ /* 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), -+ remove the entry associating the source dev/ino with the -+ destination file name, so we don't try to `preserve' a link -+ to a file we didn't create. */ -+ if (earlier_file == NULL) -+ forget_created (src_sb.st_ino, src_sb.st_dev); -+ -+ if (dst_backup) -+ { -+ if (rename (dst_backup, dst_name) != 0) -+ error (0, errno, _("cannot un-backup %s"), quote (dst_name)); -+ else -+ { -+ if (x->verbose) -+ printf (_("%s -> %s (unbackup)\n"), -+ quote_n (0, dst_backup), quote_n (1, dst_name)); -+ } -+ } -+ return false; -+} -+ -+static bool -+valid_options (const struct cp_options *co) -+{ -+ assert (co != NULL); -+ assert (VALID_BACKUP_TYPE (co->backup_type)); -+ assert (VALID_SPARSE_MODE (co->sparse_mode)); -+ assert (VALID_REFLINK_MODE (co->reflink_mode)); -+ assert (!(co->hard_link && co->symbolic_link)); -+ assert (! -+ (co->reflink_mode == REFLINK_ALWAYS -+ && co->sparse_mode != SPARSE_AUTO)); -+ return true; -+} -+ -+/* Copy the file SRC_NAME to the file DST_NAME. The files may be of -+ any type. NONEXISTENT_DST should be true if the file DST_NAME -+ is known not to exist (e.g., because its parent directory was just -+ created); NONEXISTENT_DST should be false if DST_NAME might already -+ exist. OPTIONS is ... FIXME-describe -+ Set *COPY_INTO_SELF if SRC_NAME is a parent of (or the -+ same as) DST_NAME; otherwise, set clear it. -+ Return true if successful. */ -+ -+extern bool -+copy (char const *src_name, char const *dst_name, -+ bool nonexistent_dst, const struct cp_options *options, -+ bool *copy_into_self, bool *rename_succeeded) -+{ -+ assert (valid_options (options)); -+ -+ /* Record the file names: they're used in case of error, when copying -+ a directory into itself. I don't like to make these tools do *any* -+ extra work in the common case when that work is solely to handle -+ exceptional cases, but in this case, I don't see a way to derive the -+ top level source and destination directory names where they're used. -+ An alternative is to use COPY_INTO_SELF and print the diagnostic -+ from every caller -- but I don't want to do that. */ -+ top_level_src_name = src_name; -+ top_level_dst_name = dst_name; -+ -+ bool first_dir_created_per_command_line_arg = false; -+ return copy_internal (src_name, dst_name, nonexistent_dst, 0, NULL, -+ options, true, -+ &first_dir_created_per_command_line_arg, -+ copy_into_self, rename_succeeded); -+} -+ -+/* Set *X to the default options for a value of type struct cp_options. */ -+ -+extern void -+cp_options_default (struct cp_options *x) -+{ -+ memset (x, 0, sizeof *x); -+#ifdef PRIV_FILE_CHOWN -+ { -+ priv_set_t *pset = priv_allocset (); -+ if (!pset) -+ xalloc_die (); -+ if (getppriv (PRIV_EFFECTIVE, pset) == 0) -+ { -+ x->chown_privileges = priv_ismember (pset, PRIV_FILE_CHOWN); -+ x->owner_privileges = priv_ismember (pset, PRIV_FILE_OWNER); -+ } -+ priv_freeset (pset); -+ } -+#else -+ x->chown_privileges = x->owner_privileges = (geteuid () == 0); -+#endif -+} -+ -+/* Return true if it's OK for chown to fail, where errno is -+ the error number that chown failed with and X is the copying -+ option set. */ -+ -+extern bool -+chown_failure_ok (struct cp_options const *x) -+{ -+ /* If non-root uses -p, it's ok if we can't preserve ownership. -+ But root probably wants to know, e.g. if NFS disallows it, -+ or if the target system doesn't support file ownership. */ -+ -+ return ((errno == EPERM || errno == EINVAL) && !x->chown_privileges); -+} -+ -+/* Similarly, return true if it's OK for chmod and similar operations -+ to fail, where errno is the error number that chmod failed with and -+ X is the copying option set. */ -+ -+static bool -+owner_failure_ok (struct cp_options const *x) -+{ -+ return ((errno == EPERM || errno == EINVAL) && !x->owner_privileges); -+} -+ -+/* Return the user's umask, caching the result. */ -+ -+extern mode_t -+cached_umask (void) -+{ -+ static mode_t mask = (mode_t) -1; -+ if (mask == (mode_t) -1) -+ { -+ mask = umask (0); -+ umask (mask); -+ } -+ return mask; -+} -diff -urNp coreutils-8.0-orig/src/copy.h coreutils-8.0/src/copy.h ---- coreutils-8.0-orig/src/copy.h 2009-09-21 14:29:33.000000000 +0200 -+++ coreutils-8.0/src/copy.h 2009-10-07 10:10:11.000000000 +0200 -@@ -158,6 +158,9 @@ struct cp_options - bool preserve_mode; - bool preserve_timestamps; - -+ /* If true, attempt to set specified security context */ -+ bool set_security_context; -+ - /* Enabled for mv, and for cp by the --preserve=links option. - If true, attempt to preserve in the destination files any - logical hard links between the source files. If used with cp's -diff -urNp coreutils-8.0-orig/src/copy.h.orig coreutils-8.0/src/copy.h.orig ---- coreutils-8.0-orig/src/copy.h.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/copy.h.orig 2009-09-21 14:29:33.000000000 +0200 -@@ -0,0 +1,283 @@ -+/* core functions for copying files and directories -+ Copyright (C) 89, 90, 91, 1995-2009 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 . */ -+ -+/* Extracted from cp.c and librarified by Jim Meyering. */ -+ -+#ifndef COPY_H -+# define COPY_H -+ -+# include -+# include "hash.h" -+ -+/* Control creation of sparse files (files with holes). */ -+enum Sparse_type -+{ -+ SPARSE_UNUSED, -+ -+ /* Never create holes in DEST. */ -+ SPARSE_NEVER, -+ -+ /* This is the default. Use a crude (and sometimes inaccurate) -+ heuristic to determine if SOURCE has holes. If so, try to create -+ holes in DEST. */ -+ SPARSE_AUTO, -+ -+ /* For every sufficiently long sequence of bytes in SOURCE, try to -+ create a corresponding hole in DEST. There is a performance penalty -+ here because CP has to search for holes in SRC. But if the holes are -+ big enough, that penalty can be offset by the decrease in the amount -+ of data written to disk. */ -+ SPARSE_ALWAYS -+}; -+ -+/* Control creation of COW files. */ -+enum Reflink_type -+{ -+ /* Default to a standard copy. */ -+ REFLINK_NEVER, -+ -+ /* Try a COW copy and fall back to a standard copy. */ -+ REFLINK_AUTO, -+ -+ /* Require a COW copy and fail if not available. */ -+ REFLINK_ALWAYS -+}; -+ -+/* This type is used to help mv (via copy.c) distinguish these cases. */ -+enum Interactive -+{ -+ I_ALWAYS_YES = 1, -+ I_ALWAYS_NO, -+ I_ASK_USER, -+ I_UNSPECIFIED -+}; -+ -+/* How to handle symbolic links. */ -+enum Dereference_symlink -+{ -+ DEREF_UNDEFINED = 1, -+ -+ /* Copy the symbolic link itself. -P */ -+ DEREF_NEVER, -+ -+ /* If the symbolic is a command line argument, then copy -+ its referent. Otherwise, copy the symbolic link itself. -H */ -+ DEREF_COMMAND_LINE_ARGUMENTS, -+ -+ /* Copy the referent of the symbolic link. -L */ -+ DEREF_ALWAYS -+}; -+ -+# define VALID_SPARSE_MODE(Mode) \ -+ ((Mode) == SPARSE_NEVER \ -+ || (Mode) == SPARSE_AUTO \ -+ || (Mode) == SPARSE_ALWAYS) -+ -+# define VALID_REFLINK_MODE(Mode) \ -+ ((Mode) == REFLINK_NEVER \ -+ || (Mode) == REFLINK_AUTO \ -+ || (Mode) == REFLINK_ALWAYS) -+ -+/* These options control how files are copied by at least the -+ following programs: mv (when rename doesn't work), cp, install. -+ So, if you add a new member, be sure to initialize it in -+ mv.c, cp.c, and install.c. */ -+struct cp_options -+{ -+ enum backup_type backup_type; -+ -+ /* How to handle symlinks in the source. */ -+ enum Dereference_symlink dereference; -+ -+ /* This value is used to determine whether to prompt before removing -+ each existing destination file. It works differently depending on -+ whether move_mode is set. See code/comments in copy.c. */ -+ enum Interactive interactive; -+ -+ /* Control creation of sparse files. */ -+ enum Sparse_type sparse_mode; -+ -+ /* Set the mode of the destination file to exactly this value -+ if SET_MODE is nonzero. */ -+ mode_t mode; -+ -+ /* If true, copy all files except (directories and, if not dereferencing -+ them, symbolic links,) as if they were regular files. */ -+ bool copy_as_regular; -+ -+ /* If true, remove each existing destination nondirectory before -+ trying to open it. */ -+ bool unlink_dest_before_opening; -+ -+ /* If true, first try to open each existing destination nondirectory, -+ then, if the open fails, unlink and try again. -+ This option must be set for `cp -f', in case the destination file -+ exists when the open is attempted. It is irrelevant to `mv' since -+ any destination is sure to be removed before the open. */ -+ bool unlink_dest_after_failed_open; -+ -+ /* If true, create hard links instead of copying files. -+ Create destination directories as usual. */ -+ bool hard_link; -+ -+ /* If true, rather than copying, first attempt to use rename. -+ If that fails, then resort to copying. */ -+ bool move_mode; -+ -+ /* Whether this process has appropriate privileges to chown a file -+ whose owner is not the effective user ID. */ -+ bool chown_privileges; -+ -+ /* Whether this process has appropriate privileges to do the -+ following operations on a file even when it is owned by some -+ other user: set the file's atime, mtime, mode, or ACL; remove or -+ rename an entry in the file even though it is a sticky directory, -+ or to mount on the file. */ -+ bool owner_privileges; -+ -+ /* If true, when copying recursively, skip any subdirectories that are -+ on different file systems from the one we started on. */ -+ bool one_file_system; -+ -+ /* If true, attempt to give the copies the original files' permissions, -+ owner, group, and timestamps. */ -+ bool preserve_ownership; -+ bool preserve_mode; -+ bool preserve_timestamps; -+ -+ /* Enabled for mv, and for cp by the --preserve=links option. -+ If true, attempt to preserve in the destination files any -+ logical hard links between the source files. If used with cp's -+ --no-dereference option, and copying two hard-linked files, -+ the two corresponding destination files will also be hard linked. -+ -+ If used with cp's --dereference (-L) option, then, as that option implies, -+ hard links are *not* preserved. However, when copying a file F and -+ a symlink S to F, the resulting S and F in the destination directory -+ will be hard links to the same file (a copy of F). */ -+ bool preserve_links; -+ -+ /* If true and any of the above (for preserve) file attributes cannot -+ be applied to a destination file, treat it as a failure and return -+ nonzero immediately. E.g. for cp -p this must be true, for mv it -+ must be false. */ -+ bool require_preserve; -+ -+ /* If true, attempt to preserve the SELinux security context, too. -+ Set this only if the kernel is SELinux enabled. */ -+ bool preserve_security_context; -+ -+ /* 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, attempt to preserve extended attributes using libattr. -+ Ignored if coreutils are compiled without xattr support. */ -+ bool preserve_xattr; -+ -+ /* Useful only when preserve_xattr is true. -+ If true, a failed attempt to preserve file's extended attributes -+ propagates failure "out" to the caller. If false, a failure to -+ preserve file's extended attributes does not change the invoking -+ application's exit status. Give diagnostics for failed syscalls -+ regardless of this setting. For example, with "cp --preserve=xattr" -+ this flag is "true", while with "cp --preserve=all", it is false. */ -+ bool require_preserve_xattr; -+ -+ /* Used as difference boolean between cp -a and cp -dR --preserve=all. -+ If true, non-mandatory failure diagnostics are not displayed. This -+ should prevent poluting cp -a output. -+ */ -+ bool reduce_diagnostics; -+ -+ /* If true, copy directories recursively and copy special files -+ as themselves rather than copying their contents. */ -+ bool recursive; -+ -+ /* If true, set file mode to value of MODE. Otherwise, -+ set it based on current umask modified by UMASK_KILL. */ -+ bool set_mode; -+ -+ /* If true, create symbolic links instead of copying files. -+ Create destination directories as usual. */ -+ bool symbolic_link; -+ -+ /* If true, do not copy a nondirectory that has an existing destination -+ with the same or newer modification time. */ -+ bool update; -+ -+ /* If true, display the names of the files before copying them. */ -+ bool verbose; -+ -+ /* If true, stdin is a tty. */ -+ bool stdin_tty; -+ -+ /* If true, open a dangling destination symlink when not in move_mode. -+ Otherwise, copy_reg gives a diagnostic (it refuses to write through -+ such a symlink) and returns false. */ -+ bool open_dangling_dest_symlink; -+ -+ /* Control creation of COW files. */ -+ enum Reflink_type reflink_mode; -+ -+ /* This is a set of destination name/inode/dev triples. Each such triple -+ represents a file we have created corresponding to a source file name -+ that was specified on the command line. Use it to avoid clobbering -+ source files in commands like this: -+ rm -rf a b c; mkdir a b c; touch a/f b/f; mv a/f b/f c -+ For now, it protects only regular files when copying (i.e. not renaming). -+ When renaming, it protects all non-directories. -+ Use dest_info_init to initialize it, or set it to NULL to disable -+ this feature. */ -+ Hash_table *dest_info; -+ -+ /* FIXME */ -+ Hash_table *src_info; -+}; -+ -+# define XSTAT(X, Src_name, Src_sb) \ -+ ((X)->dereference == DEREF_NEVER \ -+ ? lstat (Src_name, Src_sb) \ -+ : stat (Src_name, Src_sb)) -+ -+/* Arrange to make rename calls go through the wrapper function -+ on systems with a rename function that fails for a source file name -+ specified with a trailing slash. */ -+# if RENAME_TRAILING_SLASH_BUG -+int rpl_rename (const char *, const char *); -+# undef rename -+# define rename rpl_rename -+# endif -+ -+bool copy (char const *src_name, char const *dst_name, -+ bool nonexistent_dst, const struct cp_options *options, -+ bool *copy_into_self, bool *rename_succeeded); -+ -+void dest_info_init (struct cp_options *); -+void src_info_init (struct cp_options *); -+ -+void cp_options_default (struct cp_options *); -+bool chown_failure_ok (struct cp_options const *); -+mode_t cached_umask (void); -+ -+#endif -diff -urNp coreutils-8.0-orig/src/cp.c coreutils-8.0/src/cp.c ---- coreutils-8.0-orig/src/cp.c 2009-09-29 15:27:54.000000000 +0200 -+++ coreutils-8.0/src/cp.c 2009-10-07 10:10:11.000000000 +0200 -@@ -139,6 +139,7 @@ static struct option const long_opts[] = - {"target-directory", required_argument, NULL, 't'}, - {"update", no_argument, NULL, 'u'}, - {"verbose", no_argument, NULL, 'v'}, -+ {"context", required_argument, NULL, 'Z'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -@@ -197,6 +198,9 @@ Mandatory arguments to long options are - 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); -@@ -223,6 +227,7 @@ Mandatory arguments to long options are - 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); -@@ -777,6 +782,7 @@ cp_option_init (struct cp_options *x) - x->preserve_timestamps = false; - x->preserve_security_context = false; - x->require_preserve_context = false; -+ x->set_security_context = false; - x->preserve_xattr = false; - x->reduce_diagnostics = false; - x->require_preserve_xattr = false; -@@ -923,7 +929,7 @@ main (int argc, char **argv) - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); - -- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:T", -+ while ((c = getopt_long (argc, argv, "abcdfHilLnprst:uvxPRS:TZ:", - long_opts, NULL)) - != -1) - { -@@ -966,6 +972,16 @@ main (int argc, char **argv) - copy_contents = true; - break; - -+ 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; -+ x.require_preserve_context = true; -+ } -+ break; - case 'd': - x.preserve_links = true; - x.dereference = DEREF_NEVER; -@@ -1075,6 +1091,27 @@ main (int argc, char **argv) - x.one_file_system = 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; -+ - case 'S': - make_backups = true; - backup_suffix_string = optarg; -diff -urNp coreutils-8.0-orig/src/cp.c.orig coreutils-8.0/src/cp.c.orig ---- coreutils-8.0-orig/src/cp.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/cp.c.orig 2009-09-29 15:27:54.000000000 +0200 -@@ -0,0 +1,1160 @@ -+/* cp.c -- file copying (main routines) -+ Copyright (C) 89, 90, 91, 1995-2009 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 . -+ -+ Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering. */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "system.h" -+#include "argmatch.h" -+#include "backupfile.h" -+#include "copy.h" -+#include "cp-hash.h" -+#include "error.h" -+#include "filenamecat.h" -+#include "ignore-value.h" -+#include "quote.h" -+#include "stat-time.h" -+#include "utimens.h" -+#include "acl.h" -+ -+#if ! HAVE_LCHOWN -+# define lchown(name, uid, gid) chown (name, uid, gid) -+#endif -+ -+#define ASSIGN_BASENAME_STRDUPA(Dest, File_name) \ -+ do \ -+ { \ -+ char *tmp_abns_; \ -+ ASSIGN_STRDUPA (tmp_abns_, (File_name)); \ -+ Dest = last_component (tmp_abns_); \ -+ strip_trailing_slashes (Dest); \ -+ } \ -+ while (0) -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "cp" -+ -+#define AUTHORS \ -+ proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \ -+ proper_name ("David MacKenzie"), \ -+ proper_name ("Jim Meyering") -+ -+/* 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. */ -+struct dir_attr -+{ -+ struct stat st; -+ bool restore_mode; -+ size_t slash_offset; -+ struct dir_attr *next; -+}; -+ -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ COPY_CONTENTS_OPTION = CHAR_MAX + 1, -+ NO_PRESERVE_ATTRIBUTES_OPTION, -+ PARENTS_OPTION, -+ PRESERVE_ATTRIBUTES_OPTION, -+ REFLINK_OPTION, -+ SPARSE_OPTION, -+ STRIP_TRAILING_SLASHES_OPTION, -+ UNLINK_DEST_BEFORE_OPENING -+}; -+ -+/* True if the kernel is SELinux enabled. */ -+static bool selinux_enabled; -+ -+/* If true, the command "cp x/e_file e_dir" uses "e_dir/x/e_file" -+ as its destination instead of the usual "e_dir/e_file." */ -+static bool parents_option = false; -+ -+/* Remove any trailing slashes from each SOURCE argument. */ -+static bool remove_trailing_slashes; -+ -+static char const *const sparse_type_string[] = -+{ -+ "never", "auto", "always", NULL -+}; -+static enum Sparse_type const sparse_type[] = -+{ -+ SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS -+}; -+ARGMATCH_VERIFY (sparse_type_string, sparse_type); -+ -+static char const *const reflink_type_string[] = -+{ -+ "auto", "always", NULL -+}; -+static enum Reflink_type const reflink_type[] = -+{ -+ REFLINK_AUTO, REFLINK_ALWAYS -+}; -+ARGMATCH_VERIFY (reflink_type_string, reflink_type); -+ -+static struct option const long_opts[] = -+{ -+ {"archive", no_argument, NULL, 'a'}, -+ {"backup", optional_argument, NULL, 'b'}, -+ {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION}, -+ {"dereference", no_argument, NULL, 'L'}, -+ {"force", no_argument, NULL, 'f'}, -+ {"interactive", no_argument, NULL, 'i'}, -+ {"link", no_argument, NULL, 'l'}, -+ {"no-clobber", no_argument, NULL, 'n'}, -+ {"no-dereference", no_argument, NULL, 'P'}, -+ {"no-preserve", required_argument, NULL, NO_PRESERVE_ATTRIBUTES_OPTION}, -+ {"no-target-directory", no_argument, NULL, 'T'}, -+ {"one-file-system", no_argument, NULL, 'x'}, -+ {"parents", no_argument, NULL, PARENTS_OPTION}, -+ {"path", no_argument, NULL, PARENTS_OPTION}, /* Deprecated. */ -+ {"preserve", optional_argument, NULL, PRESERVE_ATTRIBUTES_OPTION}, -+ {"recursive", no_argument, NULL, 'R'}, -+ {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING}, -+ {"sparse", required_argument, NULL, SPARSE_OPTION}, -+ {"reflink", optional_argument, NULL, REFLINK_OPTION}, -+ {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, -+ {"suffix", required_argument, NULL, 'S'}, -+ {"symbolic-link", no_argument, NULL, 's'}, -+ {"target-directory", required_argument, NULL, 't'}, -+ {"update", no_argument, NULL, 'u'}, -+ {"verbose", no_argument, NULL, 'v'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [-T] SOURCE DEST\n\ -+ or: %s [OPTION]... SOURCE... DIRECTORY\n\ -+ or: %s [OPTION]... -t DIRECTORY SOURCE...\n\ -+"), -+ program_name, program_name, program_name); -+ fputs (_("\ -+Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ -a, --archive same as -dR --preserve=all\n\ -+ --backup[=CONTROL] make a backup of each existing destination file\n\ -+ -b like --backup but does not accept an argument\n\ -+ --copy-contents copy contents of special files when recursive\n\ -+ -d same as --no-dereference --preserve=links\n\ -+"), stdout); -+ fputs (_("\ -+ -f, --force if an existing destination file cannot be\n\ -+ opened, remove it and try again (redundant if\n\ -+ the -n option is used)\n\ -+ -i, --interactive prompt before overwrite (overrides a previous -n\n\ -+ option)\n\ -+ -H follow command-line symbolic links in SOURCE\n\ -+"), stdout); -+ fputs (_("\ -+ -l, --link link files instead of copying\n\ -+ -L, --dereference always follow symbolic links in SOURCE\n\ -+"), stdout); -+ fputs (_("\ -+ -n, --no-clobber do not overwrite an existing file (overrides\n\ -+ a previous -i option)\n\ -+ -P, --no-dereference never follow symbolic links in SOURCE\n\ -+"), stdout); -+ fputs (_("\ -+ -p same as --preserve=mode,ownership,timestamps\n\ -+ --preserve[=ATTR_LIST] preserve the specified attributes (default:\n\ -+ mode,ownership,timestamps), if possible\n\ -+ additional attributes: context, links, xattr,\n\ -+ all\n\ -+"), stdout); -+ fputs (_("\ -+ --no-preserve=ATTR_LIST don't preserve the specified attributes\n\ -+ --parents use full source file name under DIRECTORY\n\ -+"), stdout); -+ fputs (_("\ -+ -R, -r, --recursive copy directories recursively\n\ -+ --reflink[=WHEN] control clone/CoW copies. See below.\n\ -+ --remove-destination remove each existing destination file before\n\ -+ attempting to open it (contrast with --force)\n\ -+"), stdout); -+ fputs (_("\ -+ --sparse=WHEN control creation of sparse files. See below.\n\ -+ --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\ -+ argument\n\ -+"), stdout); -+ fputs (_("\ -+ -s, --symbolic-link make symbolic links instead of copying\n\ -+ -S, --suffix=SUFFIX override the usual backup suffix\n\ -+ -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\ -+ -T, --no-target-directory treat DEST as a normal file\n\ -+"), stdout); -+ fputs (_("\ -+ -u, --update copy only when the SOURCE file is newer\n\ -+ than the destination file or when the\n\ -+ destination file is missing\n\ -+ -v, --verbose explain what is being done\n\ -+ -x, --one-file-system stay on this file system\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+By default, sparse SOURCE files are detected by a crude heuristic and the\n\ -+corresponding DEST file is made sparse as well. That is the behavior\n\ -+selected by --sparse=auto. Specify --sparse=always to create a sparse DEST\n\ -+file whenever the SOURCE file contains a long enough sequence of zero bytes.\n\ -+Use --sparse=never to inhibit creation of sparse files.\n\ -+\n\ -+When --reflink[=always] is specified, perform a lightweight copy, where the\n\ -+data blocks are copied only when modified. If this is not possible the copy\n\ -+fails, or if --reflink=auto is specified, fall back to a standard copy.\n\ -+"), stdout); -+ fputs (_("\ -+\n\ -+The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ -+The version control method may be selected via the --backup option or through\n\ -+the VERSION_CONTROL environment variable. Here are the values:\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+ none, off never make backups (even if --backup is given)\n\ -+ numbered, t make numbered backups\n\ -+ existing, nil numbered if numbered backups exist, simple otherwise\n\ -+ simple, never always make simple backups\n\ -+"), stdout); -+ fputs (_("\ -+\n\ -+As a special case, cp makes a backup of SOURCE when the force and backup\n\ -+options are given and SOURCE and DEST are the same name for an existing,\n\ -+regular file.\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+/* Ensure that the parent directories of CONST_DST_NAME have the -+ correct protections, for the --parents option. This is done -+ after all copying has been completed, to allow permissions -+ that don't include user write/execute. -+ -+ SRC_OFFSET is the index in CONST_DST_NAME of the beginning of the -+ source directory name. -+ -+ ATTR_LIST is a null-terminated linked list of structures that -+ indicates the end of the filename of each intermediate directory -+ in CONST_DST_NAME that may need to have its attributes changed. -+ The command `cp --parents --preserve a/b/c d/e_dir' changes the -+ attributes of the directories d/e_dir/a and d/e_dir/a/b to match -+ the corresponding source directories regardless of whether they -+ existed before the `cp' command was given. -+ -+ Return true if the parent of CONST_DST_NAME and any intermediate -+ directories specified by ATTR_LIST have the proper permissions -+ when done. */ -+ -+static bool -+re_protect (char const *const_dst_name, size_t src_offset, -+ struct dir_attr *attr_list, const struct cp_options *x) -+{ -+ struct dir_attr *p; -+ char *dst_name; /* A copy of CONST_DST_NAME we can change. */ -+ char *src_name; /* The source name in `dst_name'. */ -+ -+ ASSIGN_STRDUPA (dst_name, const_dst_name); -+ src_name = dst_name + src_offset; -+ -+ for (p = attr_list; p; p = p->next) -+ { -+ dst_name[p->slash_offset] = '\0'; -+ -+ /* Adjust the times (and if possible, ownership) for the copy. -+ chown turns off set[ug]id bits for non-root, -+ so do the chmod last. */ -+ -+ if (x->preserve_timestamps) -+ { -+ struct timespec timespec[2]; -+ -+ timespec[0] = get_stat_atime (&p->st); -+ timespec[1] = get_stat_mtime (&p->st); -+ -+ if (utimens (dst_name, timespec)) -+ { -+ error (0, errno, _("failed to preserve times for %s"), -+ quote (dst_name)); -+ return false; -+ } -+ } -+ -+ if (x->preserve_ownership) -+ { -+ if (lchown (dst_name, p->st.st_uid, p->st.st_gid) != 0) -+ { -+ if (! chown_failure_ok (x)) -+ { -+ error (0, errno, _("failed to preserve ownership for %s"), -+ quote (dst_name)); -+ return false; -+ } -+ /* Failing to preserve ownership is OK. Still, try to preserve -+ the group, but ignore the possible error. */ -+ ignore_value (lchown (dst_name, -1, p->st.st_gid)); -+ } -+ } -+ -+ if (x->preserve_mode) -+ { -+ if (copy_acl (src_name, -1, dst_name, -1, p->st.st_mode) != 0) -+ return false; -+ } -+ else if (p->restore_mode) -+ { -+ if (lchmod (dst_name, p->st.st_mode) != 0) -+ { -+ error (0, errno, _("failed to preserve permissions for %s"), -+ quote (dst_name)); -+ return false; -+ } -+ } -+ -+ dst_name[p->slash_offset] = '/'; -+ } -+ return true; -+} -+ -+/* Ensure that the parent directory of CONST_DIR exists, for -+ the --parents option. -+ -+ SRC_OFFSET is the index in CONST_DIR (which is a destination -+ directory) of the beginning of the source directory name. -+ Create any leading directories that don't already exist. -+ If VERBOSE_FMT_STRING is nonzero, use it as a printf format -+ string for printing a message after successfully making a directory. -+ The format should take two string arguments: the names of the -+ source and destination directories. -+ Creates a linked list of attributes of intermediate directories, -+ *ATTR_LIST, for re_protect to use after calling copy. -+ Sets *NEW_DST if this function creates parent of CONST_DIR. -+ -+ Return true if parent of CONST_DIR exists as a directory with the proper -+ permissions when done. */ -+ -+/* FIXME: Synch this function with the one in ../lib/mkdir-p.c. */ -+ -+static bool -+make_dir_parents_private (char const *const_dir, size_t src_offset, -+ char const *verbose_fmt_string, -+ struct dir_attr **attr_list, bool *new_dst, -+ const struct cp_options *x) -+{ -+ struct stat stats; -+ char *dir; /* A copy of CONST_DIR we can change. */ -+ char *src; /* Source name in DIR. */ -+ char *dst_dir; /* Leading directory of DIR. */ -+ size_t dirlen; /* Length of DIR. */ -+ -+ ASSIGN_STRDUPA (dir, const_dir); -+ -+ src = dir + src_offset; -+ -+ dirlen = dir_len (dir); -+ dst_dir = alloca (dirlen + 1); -+ memcpy (dst_dir, dir, dirlen); -+ dst_dir[dirlen] = '\0'; -+ -+ *attr_list = NULL; -+ -+ if (stat (dst_dir, &stats) != 0) -+ { -+ /* A parent of CONST_DIR does not exist. -+ Make all missing intermediate directories. */ -+ char *slash; -+ -+ slash = src; -+ while (*slash == '/') -+ slash++; -+ while ((slash = strchr (slash, '/'))) -+ { -+ struct dir_attr *new IF_LINT (= NULL); -+ bool missing_dir; -+ -+ *slash = '\0'; -+ missing_dir = (stat (dir, &stats) != 0); -+ -+ if (missing_dir | x->preserve_ownership | x->preserve_mode -+ | x->preserve_timestamps) -+ { -+ /* Add this directory to the list of directories whose -+ modes might need fixing later. */ -+ struct stat src_st; -+ int src_errno = (stat (src, &src_st) != 0 -+ ? errno -+ : S_ISDIR (src_st.st_mode) -+ ? 0 -+ : ENOTDIR); -+ if (src_errno) -+ { -+ error (0, src_errno, _("failed to get attributes of %s"), -+ quote (src)); -+ return false; -+ } -+ -+ new = xmalloc (sizeof *new); -+ new->st = src_st; -+ new->slash_offset = slash - dir; -+ new->restore_mode = false; -+ new->next = *attr_list; -+ *attr_list = new; -+ } -+ -+ if (missing_dir) -+ { -+ mode_t src_mode; -+ mode_t omitted_permissions; -+ mode_t mkdir_mode; -+ -+ /* This component does not exist. We must set -+ *new_dst and new->st.st_mode inside this loop because, -+ for example, in the command `cp --parents ../a/../b/c e_dir', -+ make_dir_parents_private creates only e_dir/../a if -+ ./b already exists. */ -+ *new_dst = true; -+ src_mode = new->st.st_mode; -+ -+ /* If the ownership or special mode bits might change, -+ omit some permissions at first, so unauthorized users -+ cannot nip in before the file is ready. */ -+ omitted_permissions = (src_mode -+ & (x->preserve_ownership -+ ? S_IRWXG | S_IRWXO -+ : x->preserve_mode -+ ? S_IWGRP | S_IWOTH -+ : 0)); -+ -+ /* POSIX says mkdir's behavior is implementation-defined when -+ (src_mode & ~S_IRWXUGO) != 0. However, common practice is -+ to ask mkdir to copy all the CHMOD_MODE_BITS, letting mkdir -+ decide what to do with S_ISUID | S_ISGID | S_ISVTX. */ -+ mkdir_mode = src_mode & CHMOD_MODE_BITS & ~omitted_permissions; -+ if (mkdir (dir, mkdir_mode) != 0) -+ { -+ error (0, errno, _("cannot make directory %s"), -+ quote (dir)); -+ return false; -+ } -+ else -+ { -+ if (verbose_fmt_string != NULL) -+ printf (verbose_fmt_string, src, dir); -+ } -+ -+ /* We need search and write permissions to the new directory -+ for writing the directory's contents. Check if these -+ permissions are there. */ -+ -+ if (lstat (dir, &stats)) -+ { -+ error (0, errno, _("failed to get attributes of %s"), -+ quote (dir)); -+ return false; -+ } -+ -+ -+ if (! x->preserve_mode) -+ { -+ if (omitted_permissions & ~stats.st_mode) -+ omitted_permissions &= ~ cached_umask (); -+ if (omitted_permissions & ~stats.st_mode -+ || (stats.st_mode & S_IRWXU) != S_IRWXU) -+ { -+ new->st.st_mode = stats.st_mode | omitted_permissions; -+ new->restore_mode = true; -+ } -+ } -+ -+ if ((stats.st_mode & S_IRWXU) != S_IRWXU) -+ { -+ /* Make the new directory searchable and writable. -+ The original permissions will be restored later. */ -+ -+ if (lchmod (dir, stats.st_mode | S_IRWXU) != 0) -+ { -+ error (0, errno, _("setting permissions for %s"), -+ quote (dir)); -+ return false; -+ } -+ } -+ } -+ else if (!S_ISDIR (stats.st_mode)) -+ { -+ error (0, 0, _("%s exists but is not a directory"), -+ quote (dir)); -+ return false; -+ } -+ else -+ *new_dst = false; -+ *slash++ = '/'; -+ -+ /* Avoid unnecessary calls to `stat' when given -+ file names containing multiple adjacent slashes. */ -+ while (*slash == '/') -+ slash++; -+ } -+ } -+ -+ /* We get here if the parent of DIR already exists. */ -+ -+ else if (!S_ISDIR (stats.st_mode)) -+ { -+ error (0, 0, _("%s exists but is not a directory"), quote (dst_dir)); -+ return false; -+ } -+ else -+ { -+ *new_dst = false; -+ } -+ return true; -+} -+ -+/* FILE is the last operand of this command. -+ Return true if FILE is a directory. -+ But report an error and exit if there is a problem accessing FILE, -+ or if FILE does not exist but would have to refer to an existing -+ directory if it referred to anything at all. -+ -+ If the file exists, store the file's status into *ST. -+ Otherwise, set *NEW_DST. */ -+ -+static bool -+target_directory_operand (char const *file, struct stat *st, bool *new_dst) -+{ -+ int err = (stat (file, st) == 0 ? 0 : errno); -+ bool is_a_dir = !err && S_ISDIR (st->st_mode); -+ if (err) -+ { -+ if (err != ENOENT) -+ error (EXIT_FAILURE, err, _("accessing %s"), quote (file)); -+ *new_dst = true; -+ } -+ return is_a_dir; -+} -+ -+/* Scan the arguments, and copy each by calling copy. -+ Return true if successful. */ -+ -+static bool -+do_copy (int n_files, char **file, const char *target_directory, -+ bool no_target_directory, struct cp_options *x) -+{ -+ struct stat sb; -+ bool new_dst = false; -+ bool ok = true; -+ -+ if (n_files <= !target_directory) -+ { -+ if (n_files <= 0) -+ error (0, 0, _("missing file operand")); -+ else -+ error (0, 0, _("missing destination file operand after %s"), -+ quote (file[0])); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (no_target_directory) -+ { -+ if (target_directory) -+ error (EXIT_FAILURE, 0, -+ _("cannot combine --target-directory (-t) " -+ "and --no-target-directory (-T)")); -+ if (2 < n_files) -+ { -+ error (0, 0, _("extra operand %s"), quote (file[2])); -+ usage (EXIT_FAILURE); -+ } -+ } -+ else if (!target_directory) -+ { -+ if (2 <= n_files -+ && target_directory_operand (file[n_files - 1], &sb, &new_dst)) -+ target_directory = file[--n_files]; -+ else if (2 < n_files) -+ error (EXIT_FAILURE, 0, _("target %s is not a directory"), -+ quote (file[n_files - 1])); -+ } -+ -+ if (target_directory) -+ { -+ /* cp file1...filen edir -+ Copy the files `file1' through `filen' -+ to the existing directory `edir'. */ -+ int i; -+ -+ /* Initialize these hash tables only if we'll need them. -+ The problems they're used to detect can arise only if -+ there are two or more files to copy. */ -+ if (2 <= n_files) -+ { -+ dest_info_init (x); -+ src_info_init (x); -+ } -+ -+ for (i = 0; i < n_files; i++) -+ { -+ char *dst_name; -+ bool parent_exists = true; /* True if dir_name (dst_name) exists. */ -+ struct dir_attr *attr_list; -+ char *arg_in_concat = NULL; -+ char *arg = file[i]; -+ -+ /* Trailing slashes are meaningful (i.e., maybe worth preserving) -+ only in the source file names. */ -+ if (remove_trailing_slashes) -+ strip_trailing_slashes (arg); -+ -+ if (parents_option) -+ { -+ char *arg_no_trailing_slash; -+ -+ /* Use `arg' without trailing slashes in constructing destination -+ file names. Otherwise, we can end up trying to create a -+ directory via `mkdir ("dst/foo/"...', which is not portable. -+ It fails, due to the trailing slash, on at least -+ NetBSD 1.[34] systems. */ -+ ASSIGN_STRDUPA (arg_no_trailing_slash, arg); -+ strip_trailing_slashes (arg_no_trailing_slash); -+ -+ /* Append all of `arg' (minus any trailing slash) to `dest'. */ -+ dst_name = file_name_concat (target_directory, -+ arg_no_trailing_slash, -+ &arg_in_concat); -+ -+ /* For --parents, we have to make sure that the directory -+ dir_name (dst_name) exists. We may have to create a few -+ leading directories. */ -+ parent_exists = -+ (make_dir_parents_private -+ (dst_name, arg_in_concat - dst_name, -+ (x->verbose ? "%s -> %s\n" : NULL), -+ &attr_list, &new_dst, x)); -+ } -+ else -+ { -+ char *arg_base; -+ /* Append the last component of `arg' to `target_directory'. */ -+ -+ ASSIGN_BASENAME_STRDUPA (arg_base, arg); -+ /* For `cp -R source/.. dest', don't copy into `dest/..'. */ -+ dst_name = (STREQ (arg_base, "..") -+ ? xstrdup (target_directory) -+ : file_name_concat (target_directory, arg_base, -+ NULL)); -+ } -+ -+ if (!parent_exists) -+ { -+ /* make_dir_parents_private failed, so don't even -+ attempt the copy. */ -+ ok = false; -+ } -+ else -+ { -+ bool copy_into_self; -+ ok &= copy (arg, dst_name, new_dst, x, ©_into_self, NULL); -+ -+ if (parents_option) -+ ok &= re_protect (dst_name, arg_in_concat - dst_name, -+ attr_list, x); -+ } -+ -+ if (parents_option) -+ { -+ while (attr_list) -+ { -+ struct dir_attr *p = attr_list; -+ attr_list = attr_list->next; -+ free (p); -+ } -+ } -+ -+ free (dst_name); -+ } -+ } -+ else /* !target_directory */ -+ { -+ char const *new_dest; -+ char const *source = file[0]; -+ char const *dest = file[1]; -+ bool unused; -+ -+ if (parents_option) -+ { -+ error (0, 0, -+ _("with --parents, the destination must be a directory")); -+ usage (EXIT_FAILURE); -+ } -+ -+ /* When the force and backup options have been specified and -+ the source and destination are the same name for an existing -+ regular file, convert the user's command, e.g., -+ `cp --force --backup foo foo' to `cp --force foo fooSUFFIX' -+ where SUFFIX is determined by any version control options used. */ -+ -+ if (x->unlink_dest_after_failed_open -+ && x->backup_type != no_backups -+ && STREQ (source, dest) -+ && !new_dst && S_ISREG (sb.st_mode)) -+ { -+ static struct cp_options x_tmp; -+ -+ new_dest = find_backup_file_name (dest, x->backup_type); -+ /* Set x->backup_type to `no_backups' so that the normal backup -+ mechanism is not used when performing the actual copy. -+ backup_type must be set to `no_backups' only *after* the above -+ call to find_backup_file_name -- that function uses -+ backup_type to determine the suffix it applies. */ -+ x_tmp = *x; -+ x_tmp.backup_type = no_backups; -+ x = &x_tmp; -+ } -+ else -+ { -+ new_dest = dest; -+ } -+ -+ ok = copy (source, new_dest, 0, x, &unused, NULL); -+ } -+ -+ return ok; -+} -+ -+static void -+cp_option_init (struct cp_options *x) -+{ -+ cp_options_default (x); -+ x->copy_as_regular = true; -+ x->dereference = DEREF_UNDEFINED; -+ x->unlink_dest_before_opening = false; -+ x->unlink_dest_after_failed_open = false; -+ x->hard_link = false; -+ x->interactive = I_UNSPECIFIED; -+ x->move_mode = false; -+ x->one_file_system = false; -+ x->reflink_mode = REFLINK_NEVER; -+ -+ x->preserve_ownership = false; -+ x->preserve_links = false; -+ x->preserve_mode = false; -+ x->preserve_timestamps = false; -+ x->preserve_security_context = false; -+ x->require_preserve_context = false; -+ x->preserve_xattr = false; -+ x->reduce_diagnostics = false; -+ x->require_preserve_xattr = false; -+ -+ x->require_preserve = false; -+ x->recursive = false; -+ x->sparse_mode = SPARSE_AUTO; -+ x->symbolic_link = false; -+ x->set_mode = false; -+ x->mode = 0; -+ -+ /* Not used. */ -+ x->stdin_tty = false; -+ -+ x->update = false; -+ x->verbose = false; -+ -+ /* By default, refuse to open a dangling destination symlink, because -+ in general one cannot do that safely, give the current semantics of -+ open's O_EXCL flag, (which POSIX doesn't even allow cp to use, btw). -+ But POSIX requires it. */ -+ x->open_dangling_dest_symlink = getenv ("POSIXLY_CORRECT") != NULL; -+ -+ x->dest_info = NULL; -+ x->src_info = NULL; -+} -+ -+/* Given a string, ARG, containing a comma-separated list of arguments -+ to the --preserve option, set the appropriate fields of X to ON_OFF. */ -+static void -+decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off) -+{ -+ enum File_attribute -+ { -+ PRESERVE_MODE, -+ PRESERVE_TIMESTAMPS, -+ PRESERVE_OWNERSHIP, -+ PRESERVE_LINK, -+ PRESERVE_CONTEXT, -+ PRESERVE_XATTR, -+ PRESERVE_ALL -+ }; -+ static enum File_attribute const preserve_vals[] = -+ { -+ PRESERVE_MODE, PRESERVE_TIMESTAMPS, -+ PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_XATTR, -+ PRESERVE_ALL -+ }; -+ /* Valid arguments to the `--preserve' option. */ -+ static char const* const preserve_args[] = -+ { -+ "mode", "timestamps", -+ "ownership", "links", "context", "xattr", "all", NULL -+ }; -+ ARGMATCH_VERIFY (preserve_args, preserve_vals); -+ -+ char *arg_writable = xstrdup (arg); -+ char *s = arg_writable; -+ do -+ { -+ /* find next comma */ -+ char *comma = strchr (s, ','); -+ enum File_attribute val; -+ -+ /* If we found a comma, put a NUL in its place and advance. */ -+ if (comma) -+ *comma++ = 0; -+ -+ /* process S. */ -+ val = XARGMATCH ("--preserve", s, preserve_args, preserve_vals); -+ switch (val) -+ { -+ case PRESERVE_MODE: -+ x->preserve_mode = on_off; -+ break; -+ -+ case PRESERVE_TIMESTAMPS: -+ x->preserve_timestamps = on_off; -+ break; -+ -+ case PRESERVE_OWNERSHIP: -+ x->preserve_ownership = on_off; -+ break; -+ -+ case PRESERVE_LINK: -+ x->preserve_links = on_off; -+ break; -+ -+ case PRESERVE_CONTEXT: -+ x->preserve_security_context = on_off; -+ x->require_preserve_context = on_off; -+ break; -+ -+ case PRESERVE_XATTR: -+ x->preserve_xattr = on_off; -+ x->require_preserve_xattr = 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; -+ if (selinux_enabled) -+ x->preserve_security_context = on_off; -+ x->preserve_xattr = on_off; -+ break; -+ -+ default: -+ abort (); -+ } -+ s = comma; -+ } -+ while (s); -+ -+ free (arg_writable); -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int c; -+ bool ok; -+ bool make_backups = false; -+ char *backup_suffix_string; -+ char *version_control_string = NULL; -+ struct cp_options x; -+ bool copy_contents = false; -+ char *target_directory = NULL; -+ bool no_target_directory = false; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdin); -+ -+ selinux_enabled = (0 < is_selinux_enabled ()); -+ cp_option_init (&x); -+ -+ /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless -+ we'll actually use backup_suffix_string. */ -+ backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); -+ -+ while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:T", -+ long_opts, NULL)) -+ != -1) -+ { -+ switch (c) -+ { -+ case SPARSE_OPTION: -+ x.sparse_mode = XARGMATCH ("--sparse", optarg, -+ sparse_type_string, sparse_type); -+ break; -+ -+ case REFLINK_OPTION: -+ if (optarg == NULL) -+ x.reflink_mode = REFLINK_ALWAYS; -+ else -+ x.reflink_mode = XARGMATCH ("--reflink", optarg, -+ reflink_type_string, reflink_type); -+ break; -+ -+ case 'a': /* Like -dR --preserve=all with reduced failure diagnostics. */ -+ x.dereference = DEREF_NEVER; -+ x.preserve_links = true; -+ x.preserve_ownership = true; -+ x.preserve_mode = true; -+ x.preserve_timestamps = true; -+ x.require_preserve = true; -+ if (selinux_enabled) -+ x.preserve_security_context = true; -+ x.preserve_xattr = true; -+ x.reduce_diagnostics = true; -+ x.recursive = true; -+ break; -+ -+ case 'b': -+ make_backups = true; -+ if (optarg) -+ version_control_string = optarg; -+ break; -+ -+ case COPY_CONTENTS_OPTION: -+ copy_contents = true; -+ break; -+ -+ case 'd': -+ x.preserve_links = true; -+ x.dereference = DEREF_NEVER; -+ break; -+ -+ case 'f': -+ x.unlink_dest_after_failed_open = true; -+ break; -+ -+ case 'H': -+ x.dereference = DEREF_COMMAND_LINE_ARGUMENTS; -+ break; -+ -+ case 'i': -+ x.interactive = I_ASK_USER; -+ break; -+ -+ case 'l': -+ x.hard_link = true; -+ break; -+ -+ case 'L': -+ x.dereference = DEREF_ALWAYS; -+ break; -+ -+ case 'n': -+ x.interactive = I_ALWAYS_NO; -+ break; -+ -+ case 'P': -+ x.dereference = DEREF_NEVER; -+ break; -+ -+ case NO_PRESERVE_ATTRIBUTES_OPTION: -+ decode_preserve_arg (optarg, &x, false); -+ break; -+ -+ case PRESERVE_ATTRIBUTES_OPTION: -+ if (optarg == NULL) -+ { -+ /* Fall through to the case for `p' below. */ -+ } -+ else -+ { -+ decode_preserve_arg (optarg, &x, true); -+ x.require_preserve = true; -+ break; -+ } -+ -+ case 'p': -+ x.preserve_ownership = true; -+ x.preserve_mode = true; -+ x.preserve_timestamps = true; -+ x.require_preserve = true; -+ break; -+ -+ case PARENTS_OPTION: -+ parents_option = true; -+ break; -+ -+ case 'r': -+ case 'R': -+ x.recursive = true; -+ break; -+ -+ case UNLINK_DEST_BEFORE_OPENING: -+ x.unlink_dest_before_opening = true; -+ break; -+ -+ case STRIP_TRAILING_SLASHES_OPTION: -+ remove_trailing_slashes = true; -+ break; -+ -+ case 's': -+ x.symbolic_link = true; -+ break; -+ -+ case 't': -+ if (target_directory) -+ error (EXIT_FAILURE, 0, -+ _("multiple target directories specified")); -+ else -+ { -+ struct stat st; -+ if (stat (optarg, &st) != 0) -+ error (EXIT_FAILURE, errno, _("accessing %s"), quote (optarg)); -+ if (! S_ISDIR (st.st_mode)) -+ error (EXIT_FAILURE, 0, _("target %s is not a directory"), -+ quote (optarg)); -+ } -+ target_directory = optarg; -+ break; -+ -+ case 'T': -+ no_target_directory = true; -+ break; -+ -+ case 'u': -+ x.update = true; -+ break; -+ -+ case 'v': -+ x.verbose = true; -+ break; -+ -+ case 'x': -+ x.one_file_system = true; -+ break; -+ -+ case 'S': -+ make_backups = true; -+ backup_suffix_string = optarg; -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ if (x.hard_link && x.symbolic_link) -+ { -+ error (0, 0, _("cannot make both hard and symbolic links")); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (make_backups && x.interactive == I_ALWAYS_NO) -+ { -+ error (0, 0, -+ _("options --backup and --no-clobber are mutually exclusive")); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (x.reflink_mode == REFLINK_ALWAYS && x.sparse_mode != SPARSE_AUTO) -+ { -+ error (0, 0, _("--reflink can be used only with --sparse=auto")); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (backup_suffix_string) -+ simple_backup_suffix = xstrdup (backup_suffix_string); -+ -+ x.backup_type = (make_backups -+ ? xget_version (_("backup type"), -+ version_control_string) -+ : no_backups); -+ -+ if (x.dereference == DEREF_UNDEFINED) -+ { -+ if (x.recursive) -+ /* This is compatible with FreeBSD. */ -+ x.dereference = DEREF_NEVER; -+ else -+ x.dereference = DEREF_ALWAYS; -+ } -+ -+ if (x.recursive) -+ x.copy_as_regular = copy_contents; -+ -+ /* If --force (-f) was specified and we're in link-creation mode, -+ first remove any existing destination file. */ -+ if (x.unlink_dest_after_failed_open && (x.hard_link || x.symbolic_link)) -+ x.unlink_dest_before_opening = true; -+ -+ if (x.preserve_security_context) -+ { -+ if (!selinux_enabled) -+ error (EXIT_FAILURE, 0, -+ _("cannot preserve security context " -+ "without an SELinux-enabled kernel")); -+ } -+ -+#if !USE_XATTR -+ if (x.require_preserve_xattr) -+ error (EXIT_FAILURE, 0, _("cannot preserve extended attributes, cp is " -+ "built without xattr support")); -+#endif -+ -+ /* Allocate space for remembering copied and created files. */ -+ -+ hash_init (); -+ -+ ok = do_copy (argc - optind, argv + optind, -+ target_directory, no_target_directory, &x); -+ -+ forget_all (); -+ -+ exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); -+} -diff -urNp coreutils-8.0-orig/src/chcon.c coreutils-8.0/src/chcon.c ---- coreutils-8.0-orig/src/chcon.c 2009-10-06 10:55:34.000000000 +0200 -+++ coreutils-8.0/src/chcon.c 2009-10-07 10:10:11.000000000 +0200 -@@ -348,7 +348,7 @@ Usage: %s [OPTION]... CONTEXT FILE...\n\ - "), - program_name, program_name, program_name); - fputs (_("\ --Change the security context of each FILE to CONTEXT.\n\ -+Change the SELinux security context of each FILE to CONTEXT.\n\ - With --reference, change the security context of each FILE to that of RFILE.\n\ - \n\ - -h, --no-dereference affect symbolic links instead of any referenced file\n\ -@@ -523,6 +523,10 @@ main (int argc, char **argv) - error (EXIT_FAILURE, 0, - _("%s may be used only on a SELinux kernel"), program_name); - -+ if (is_selinux_enabled () != 1) -+ error (EXIT_FAILURE, 0, -+ _("%s may be used only on a SELinux kernel"), program_name); -+ - if (reference_file) - { - if (getfilecon (reference_file, &ref_context) < 0) -diff -urNp coreutils-8.0-orig/src/chcon.c.orig coreutils-8.0/src/chcon.c.orig ---- coreutils-8.0-orig/src/chcon.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/chcon.c.orig 2009-10-06 10:55:34.000000000 +0200 -@@ -0,0 +1,572 @@ -+/* chcon -- change security context of files -+ Copyright (C) 2005-2009 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 . */ -+ -+#include -+#include -+#include -+#include -+ -+#include "system.h" -+#include "dev-ino.h" -+#include "error.h" -+#include "ignore-value.h" -+#include "quote.h" -+#include "quotearg.h" -+#include "root-dev-ino.h" -+#include "selinux-at.h" -+#include "xfts.h" -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "chcon" -+ -+#define AUTHORS \ -+ proper_name ("Russell Coker"), \ -+ proper_name ("Jim Meyering") -+ -+/* If nonzero, and the systems has support for it, change the context -+ of symbolic links rather than any files they point to. */ -+static bool affect_symlink_referent; -+ -+/* If true, change the modes of directories recursively. */ -+static bool recurse; -+ -+/* Level of verbosity. */ -+static bool verbose; -+ -+/* Pointer to the device and inode numbers of `/', when --recursive. -+ Otherwise NULL. */ -+static struct dev_ino *root_dev_ino; -+ -+/* The name of the context file is being given. */ -+static char const *specified_context; -+ -+/* Specific components of the context */ -+static char const *specified_user; -+static char const *specified_role; -+static char const *specified_range; -+static char const *specified_type; -+ -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ DEREFERENCE_OPTION = CHAR_MAX + 1, -+ NO_PRESERVE_ROOT, -+ PRESERVE_ROOT, -+ REFERENCE_FILE_OPTION -+}; -+ -+static struct option const long_options[] = -+{ -+ {"recursive", no_argument, NULL, 'R'}, -+ {"dereference", no_argument, NULL, DEREFERENCE_OPTION}, -+ {"no-dereference", no_argument, NULL, 'h'}, -+ {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT}, -+ {"preserve-root", no_argument, NULL, PRESERVE_ROOT}, -+ {"reference", required_argument, NULL, REFERENCE_FILE_OPTION}, -+ {"user", required_argument, NULL, 'u'}, -+ {"role", required_argument, NULL, 'r'}, -+ {"type", required_argument, NULL, 't'}, -+ {"range", required_argument, NULL, 'l'}, -+ {"verbose", no_argument, NULL, 'v'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+/* Given a security context, CONTEXT, derive a context_t (*RET), -+ setting any portions selected via the global variables, specified_user, -+ specified_role, etc. */ -+static int -+compute_context_from_mask (security_context_t context, context_t *ret) -+{ -+ bool ok = true; -+ context_t new_context = context_new (context); -+ if (!new_context) -+ { -+ error (0, errno, _("failed to create security context: %s"), -+ quotearg_colon (context)); -+ return 1; -+ } -+ -+#define SET_COMPONENT(C, comp) \ -+ do \ -+ { \ -+ if (specified_ ## comp \ -+ && context_ ## comp ## _set ((C), specified_ ## comp)) \ -+ { \ -+ error (0, errno, \ -+ _("failed to set %s security context component to %s"), \ -+ #comp, quote (specified_ ## comp)); \ -+ ok = false; \ -+ } \ -+ } \ -+ while (0) -+ -+ SET_COMPONENT (new_context, user); -+ SET_COMPONENT (new_context, range); -+ SET_COMPONENT (new_context, role); -+ SET_COMPONENT (new_context, type); -+ -+ if (!ok) -+ { -+ int saved_errno = errno; -+ context_free (new_context); -+ errno = saved_errno; -+ return 1; -+ } -+ -+ *ret = new_context; -+ return 0; -+} -+ -+/* 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 (int fd, char const *file) -+{ -+ security_context_t file_context = NULL; -+ context_t context; -+ security_context_t context_string; -+ int errors = 0; -+ -+ if (specified_context == NULL) -+ { -+ int status = (affect_symlink_referent -+ ? getfileconat (fd, file, &file_context) -+ : lgetfileconat (fd, file, &file_context)); -+ -+ if (status < 0 && errno != ENODATA) -+ { -+ error (0, errno, _("failed to get security context of %s"), -+ quote (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) -+ { -+ error (0, 0, _("can't apply partial context to unlabeled file %s"), -+ quote (file)); -+ return 1; -+ } -+ -+ if (compute_context_from_mask (file_context, &context)) -+ return 1; -+ } -+ else -+ { -+ /* FIXME: this should be done exactly once, in main. */ -+ context = context_new (specified_context); -+ if (!context) -+ abort (); -+ } -+ -+ context_string = context_str (context); -+ -+ if (file_context == NULL || ! STREQ (context_string, file_context)) -+ { -+ int fail = (affect_symlink_referent -+ ? setfileconat (fd, file, context_string) -+ : lsetfileconat (fd, file, context_string)); -+ -+ if (fail) -+ { -+ errors = 1; -+ error (0, errno, _("failed to change context of %s to %s"), -+ quote_n (0, file), quote_n (1, context_string)); -+ } -+ } -+ -+ context_free (context); -+ freecon (file_context); -+ -+ return errors; -+} -+ -+/* Change the context of FILE. -+ Return true if successful. This function is called -+ once for every file system object that fts encounters. */ -+ -+static bool -+process_file (FTS *fts, FTSENT *ent) -+{ -+ char const *file_full_name = ent->fts_path; -+ char const *file = ent->fts_accpath; -+ const struct stat *file_stats = ent->fts_statp; -+ bool ok = true; -+ -+ switch (ent->fts_info) -+ { -+ case FTS_D: -+ if (recurse) -+ { -+ if (ROOT_DEV_INO_CHECK (root_dev_ino, ent->fts_statp)) -+ { -+ /* This happens e.g., with "chcon -R --preserve-root ... /" -+ and with "chcon -RH --preserve-root ... symlink-to-root". */ -+ ROOT_DEV_INO_WARN (file_full_name); -+ /* Tell fts not to traverse into this hierarchy. */ -+ fts_set (fts, ent, FTS_SKIP); -+ /* Ensure that we do not process "/" on the second visit. */ -+ ignore_ptr (fts_read (fts)); -+ return false; -+ } -+ return true; -+ } -+ break; -+ -+ case FTS_DP: -+ if (! recurse) -+ return true; -+ break; -+ -+ case FTS_NS: -+ /* For a top-level file or directory, this FTS_NS (stat failed) -+ indicator is determined at the time of the initial fts_open call. -+ With programs like chmod, chown, and chgrp, that modify -+ permissions, it is possible that the file in question is -+ accessible when control reaches this point. So, if this is -+ the first time we've seen the FTS_NS for this file, tell -+ fts_read to stat it "again". */ -+ if (ent->fts_level == 0 && ent->fts_number == 0) -+ { -+ ent->fts_number = 1; -+ fts_set (fts, ent, FTS_AGAIN); -+ return true; -+ } -+ error (0, ent->fts_errno, _("cannot access %s"), quote (file_full_name)); -+ ok = false; -+ break; -+ -+ case FTS_ERR: -+ error (0, ent->fts_errno, _("%s"), quote (file_full_name)); -+ ok = false; -+ break; -+ -+ case FTS_DNR: -+ error (0, ent->fts_errno, _("cannot read directory %s"), -+ quote (file_full_name)); -+ ok = false; -+ break; -+ -+ default: -+ break; -+ } -+ -+ if (ent->fts_info == FTS_DP -+ && ok && ROOT_DEV_INO_CHECK (root_dev_ino, file_stats)) -+ { -+ ROOT_DEV_INO_WARN (file_full_name); -+ ok = false; -+ } -+ -+ if (ok) -+ { -+ if (verbose) -+ printf (_("changing security context of %s\n"), -+ quote (file_full_name)); -+ -+ if (change_file_context (fts->fts_cwd_fd, file) != 0) -+ ok = false; -+ } -+ -+ if ( ! recurse) -+ fts_set (fts, ent, FTS_SKIP); -+ -+ return ok; -+} -+ -+/* Recursively operate on the specified FILES (the last entry -+ of which is NULL). BIT_FLAGS controls how fts works. -+ Return true if successful. */ -+ -+static bool -+process_files (char **files, int bit_flags) -+{ -+ bool ok = true; -+ -+ FTS *fts = xfts_open (files, bit_flags, NULL); -+ -+ while (1) -+ { -+ FTSENT *ent; -+ -+ ent = fts_read (fts); -+ if (ent == NULL) -+ { -+ if (errno != 0) -+ { -+ /* FIXME: try to give a better message */ -+ error (0, errno, _("fts_read failed")); -+ ok = false; -+ } -+ break; -+ } -+ -+ ok &= process_file (fts, ent); -+ } -+ -+ if (fts_close (fts) != 0) -+ { -+ error (0, errno, _("fts_close failed")); -+ ok = false; -+ } -+ -+ return ok; -+} -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ 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); -+ fputs (_("\ -+Change the security context of each FILE to CONTEXT.\n\ -+With --reference, change the security context of each FILE to that of RFILE.\n\ -+\n\ -+ -h, --no-dereference affect symbolic links instead of any referenced file\n\ -+"), stdout); -+ fputs (_("\ -+ --reference=RFILE use RFILE's security context rather than specifying\n\ -+ a CONTEXT value\n\ -+ -R, --recursive operate on files and directories recursively\n\ -+ -v, --verbose output a diagnostic for every file processed\n\ -+"), stdout); -+ fputs (_("\ -+ -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\ -+\n\ -+"), stdout); -+ fputs (_("\ -+The following options modify how a hierarchy is traversed when the -R\n\ -+option is also specified. If more than one is specified, only the final\n\ -+one takes effect.\n\ -+\n\ -+ -H if a command line argument is a symbolic link\n\ -+ to a directory, traverse it\n\ -+ -L traverse every symbolic link to a directory\n\ -+ encountered\n\ -+ -P do not traverse any symbolic links (default)\n\ -+\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+int -+main (int argc, char **argv) -+{ -+ security_context_t ref_context = NULL; -+ -+ /* Bit flags that control how fts works. */ -+ int bit_flags = FTS_PHYSICAL; -+ -+ /* 1 if --dereference, 0 if --no-dereference, -1 if neither has been -+ specified. */ -+ int dereference = -1; -+ -+ bool ok; -+ bool preserve_root = false; -+ bool component_specified = false; -+ char *reference_file = NULL; -+ int optc; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdout); -+ -+ while ((optc = getopt_long (argc, argv, "HLPRhvu:r:t:l:", long_options, NULL)) -+ != -1) -+ { -+ switch (optc) -+ { -+ case 'H': /* Traverse command-line symlinks-to-directories. */ -+ bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL; -+ break; -+ -+ case 'L': /* Traverse all symlinks-to-directories. */ -+ bit_flags = FTS_LOGICAL; -+ break; -+ -+ case 'P': /* Traverse no symlinks-to-directories. */ -+ bit_flags = FTS_PHYSICAL; -+ break; -+ -+ case 'h': /* --no-dereference: affect symlinks */ -+ dereference = 0; -+ break; -+ -+ case DEREFERENCE_OPTION: /* --dereference: affect the referent -+ of each symlink */ -+ dereference = 1; -+ break; -+ -+ case NO_PRESERVE_ROOT: -+ preserve_root = false; -+ break; -+ -+ case PRESERVE_ROOT: -+ preserve_root = true; -+ break; -+ -+ case REFERENCE_FILE_OPTION: -+ reference_file = optarg; -+ break; -+ -+ case 'R': -+ recurse = true; -+ break; -+ -+ case 'f': -+ /* ignore */ -+ break; -+ -+ case 'v': -+ verbose = true; -+ break; -+ -+ case 'u': -+ specified_user = optarg; -+ component_specified = true; -+ break; -+ -+ case 'r': -+ specified_role = optarg; -+ component_specified = true; -+ break; -+ -+ case 't': -+ specified_type = optarg; -+ component_specified = true; -+ break; -+ -+ case 'l': -+ specified_range = optarg; -+ component_specified = true; -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ if (recurse) -+ { -+ if (bit_flags == FTS_PHYSICAL) -+ { -+ if (dereference == 1) -+ error (EXIT_FAILURE, 0, -+ _("-R --dereference requires either -H or -L")); -+ affect_symlink_referent = false; -+ } -+ else -+ { -+ if (dereference == 0) -+ error (EXIT_FAILURE, 0, _("-R -h requires -P")); -+ affect_symlink_referent = true; -+ } -+ } -+ else -+ { -+ bit_flags = FTS_PHYSICAL; -+ affect_symlink_referent = (dereference != 0); -+ } -+ -+ if (argc - optind < (reference_file || component_specified ? 1 : 2)) -+ { -+ if (argc <= optind) -+ error (0, 0, _("missing operand")); -+ else -+ error (0, 0, _("missing operand after %s"), quote (argv[argc - 1])); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (is_selinux_enabled () != 1) -+ error (EXIT_FAILURE, 0, -+ _("%s may be used only on a SELinux kernel"), program_name); -+ -+ if (reference_file) -+ { -+ if (getfilecon (reference_file, &ref_context) < 0) -+ error (EXIT_FAILURE, errno, _("failed to get security context of %s"), -+ quote (reference_file)); -+ -+ specified_context = ref_context; -+ } -+ else if (component_specified) -+ { -+ /* FIXME: it's already null, so this is a no-op. */ -+ specified_context = NULL; -+ } -+ else -+ { -+ context_t context; -+ specified_context = argv[optind++]; -+ context = context_new (specified_context); -+ if (!context) -+ error (EXIT_FAILURE, 0, _("invalid context: %s"), -+ quotearg_colon (specified_context)); -+ context_free (context); -+ } -+ -+ if (reference_file && component_specified) -+ { -+ error (0, 0, _("conflicting security context specifiers given")); -+ usage (1); -+ } -+ -+ if (recurse && preserve_root) -+ { -+ static struct dev_ino dev_ino_buf; -+ root_dev_ino = get_root_dev_ino (&dev_ino_buf); -+ if (root_dev_ino == NULL) -+ error (EXIT_FAILURE, errno, _("failed to get attributes of %s"), -+ quote ("/")); -+ } -+ else -+ { -+ root_dev_ino = NULL; -+ } -+ -+ ok = process_files (argv + optind, bit_flags | FTS_NOSTAT); -+ -+ exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); -+} -diff -urNp coreutils-8.0-orig/src/id.c coreutils-8.0/src/id.c ---- coreutils-8.0-orig/src/id.c 2009-09-29 15:27:54.000000000 +0200 -+++ coreutils-8.0/src/id.c 2009-10-07 10:10:11.000000000 +0200 -@@ -107,7 +107,7 @@ int - main (int argc, char **argv) - { - int optc; -- int selinux_enabled = (is_selinux_enabled () > 0); -+ bool selinux_enabled = (is_selinux_enabled () > 0); - - /* If true, output the list of all group IDs. -G */ - bool just_group_list = false; -diff -urNp coreutils-8.0-orig/src/install.c coreutils-8.0/src/install.c ---- coreutils-8.0-orig/src/install.c 2009-09-29 15:27:54.000000000 +0200 -+++ coreutils-8.0/src/install.c 2009-10-07 10:10:11.000000000 +0200 -@@ -284,6 +284,7 @@ cp_option_init (struct cp_options *x) - x->reduce_diagnostics=false; - x->require_preserve = false; - x->require_preserve_context = false; -+ x->set_security_context = false; - x->require_preserve_xattr = false; - x->recursive = false; - x->sparse_mode = SPARSE_AUTO; -@@ -461,7 +462,7 @@ main (int argc, char **argv) - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); - -- while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z:", long_options, -+ while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pPt:TvS:Z:", long_options, - NULL)) != -1) - { - switch (optc) -@@ -535,6 +536,7 @@ main (int argc, char **argv) - error (0, 0, _("WARNING: --preserve_context is deprecated; " - "use --preserve-context instead")); - /* fall through */ -+ case 'P': - case PRESERVE_CONTEXT_OPTION: - if ( ! selinux_enabled) - { -@@ -542,6 +544,10 @@ main (int argc, char **argv) - "this kernel is not SELinux-enabled")); - 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 = false; - break; -@@ -553,6 +559,7 @@ main (int argc, char **argv) - break; - } - scontext = optarg; -+ x.set_security_context = true; - use_default_selinux_context = false; - break; - case_GETOPT_HELP_CHAR; -@@ -986,8 +993,8 @@ Mandatory arguments to long options are - -v, --verbose print the name of each directory as it is created\n\ - "), stdout); - fputs (_("\ -- --preserve-context preserve SELinux security context\n\ -- -Z, --context=CONTEXT set SELinux security context of files and directories\n\ -+ -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); -diff -urNp coreutils-8.0-orig/src/install.c.orig coreutils-8.0/src/install.c.orig ---- coreutils-8.0-orig/src/install.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/install.c.orig 2009-09-29 15:27:54.000000000 +0200 -@@ -0,0 +1,1011 @@ -+/* install - copy files and set attributes -+ Copyright (C) 89, 90, 91, 1995-2009 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 . */ -+ -+/* Written by David MacKenzie */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "system.h" -+#include "backupfile.h" -+#include "error.h" -+#include "cp-hash.h" -+#include "copy.h" -+#include "filenamecat.h" -+#include "full-read.h" -+#include "mkancesdirs.h" -+#include "mkdir-p.h" -+#include "modechange.h" -+#include "prog-fprintf.h" -+#include "quote.h" -+#include "quotearg.h" -+#include "savewd.h" -+#include "stat-time.h" -+#include "utimens.h" -+#include "xstrtol.h" -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "install" -+ -+#define AUTHORS proper_name ("David MacKenzie") -+ -+#if HAVE_SYS_WAIT_H -+# include -+#endif -+ -+static int selinux_enabled = 0; -+static bool use_default_selinux_context = true; -+ -+#if ! HAVE_ENDGRENT -+# define endgrent() ((void) 0) -+#endif -+ -+#if ! HAVE_ENDPWENT -+# define endpwent() ((void) 0) -+#endif -+ -+#if ! HAVE_LCHOWN -+# define lchown(name, uid, gid) chown (name, uid, gid) -+#endif -+ -+#if ! HAVE_MATCHPATHCON_INIT_PREFIX -+# define matchpathcon_init_prefix(a, p) /* empty */ -+#endif -+ -+static bool change_timestamps (struct stat const *from_sb, char const *to); -+static bool change_attributes (char const *name); -+static bool copy_file (const char *from, const char *to, -+ const struct cp_options *x); -+static bool install_file_in_file_parents (char const *from, char *to, -+ struct cp_options *x); -+static bool install_file_in_dir (const char *from, const char *to_dir, -+ const struct cp_options *x); -+static bool install_file_in_file (const char *from, const char *to, -+ const struct cp_options *x); -+static void get_ids (void); -+static void strip (char const *name); -+static void announce_mkdir (char const *dir, void *options); -+static int make_ancestor (char const *dir, char const *component, -+ void *options); -+void usage (int status); -+ -+/* The user name that will own the files, or NULL to make the owner -+ the current user ID. */ -+static char *owner_name; -+ -+/* The user ID corresponding to `owner_name'. */ -+static uid_t owner_id; -+ -+/* The group name that will own the files, or NULL to make the group -+ the current group ID. */ -+static char *group_name; -+ -+/* The group ID corresponding to `group_name'. */ -+static gid_t group_id; -+ -+#define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) -+ -+/* The file mode bits to which non-directory files will be set. The umask has -+ no effect. */ -+static mode_t mode = DEFAULT_MODE; -+ -+/* Similar, but for directories. */ -+static mode_t dir_mode = DEFAULT_MODE; -+ -+/* The file mode bits that the user cares about. This should be a -+ superset of DIR_MODE and a subset of CHMOD_MODE_BITS. This matters -+ for directories, since otherwise directories may keep their S_ISUID -+ or S_ISGID bits. */ -+static mode_t dir_mode_bits = CHMOD_MODE_BITS; -+ -+/* Compare files before installing (-C) */ -+static bool copy_only_if_needed; -+ -+/* If true, strip executable files after copying them. */ -+static bool strip_files; -+ -+/* If true, install a directory instead of a regular file. */ -+static bool dir_arg; -+ -+/* Program used to strip binaries, "strip" is default */ -+static char const *strip_program = "strip"; -+ -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1, -+ PRESERVE_CONTEXT_OPTION_DEPRECATED, -+ STRIP_PROGRAM_OPTION -+}; -+ -+static struct option const long_options[] = -+{ -+ {"backup", optional_argument, NULL, 'b'}, -+ {"compare", no_argument, NULL, 'C'}, -+ {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, -+ {"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'}, -+ {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION}, -+ /* --preserve_context was silently supported until Apr 2009. -+ FIXME: disable altogether in a year or so. */ -+ {"preserve_context", no_argument, NULL, PRESERVE_CONTEXT_OPTION_DEPRECATED}, -+ {"strip", no_argument, NULL, 's'}, -+ {"strip-program", required_argument, NULL, STRIP_PROGRAM_OPTION}, -+ {"suffix", required_argument, NULL, 'S'}, -+ {"target-directory", required_argument, NULL, 't'}, -+ {"verbose", no_argument, NULL, 'v'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+/* Compare content of opened files using file descriptors A_FD and B_FD. Return -+ true if files are equal. */ -+static bool -+have_same_content (int a_fd, int b_fd) -+{ -+ enum { CMP_BLOCK_SIZE = 4096 }; -+ static char a_buff[CMP_BLOCK_SIZE]; -+ static char b_buff[CMP_BLOCK_SIZE]; -+ -+ size_t size; -+ while (0 < (size = full_read (a_fd, a_buff, sizeof a_buff))) { -+ if (size != full_read (b_fd, b_buff, sizeof b_buff)) -+ return false; -+ -+ if (memcmp (a_buff, b_buff, size) != 0) -+ return false; -+ } -+ -+ return size == 0; -+} -+ -+/* Return true for mode with non-permission bits. */ -+static bool -+extra_mode (mode_t input) -+{ -+ const mode_t mask = ~S_IRWXUGO & ~S_IFMT; -+ return !! (input & mask); -+} -+ -+/* Return true if copy of file SRC_NAME to file DEST_NAME is necessary. */ -+static bool -+need_copy (const char *src_name, const char *dest_name, -+ const struct cp_options *x) -+{ -+ struct stat src_sb, dest_sb; -+ int src_fd, dest_fd; -+ bool content_match; -+ -+ if (extra_mode (mode)) -+ return true; -+ -+ /* compare files using stat */ -+ if (lstat (src_name, &src_sb) != 0) -+ return true; -+ -+ if (lstat (dest_name, &dest_sb) != 0) -+ return true; -+ -+ if (!S_ISREG (src_sb.st_mode) || !S_ISREG (dest_sb.st_mode) -+ || extra_mode (src_sb.st_mode) || extra_mode (dest_sb.st_mode)) -+ return true; -+ -+ if (src_sb.st_size != dest_sb.st_size -+ || (dest_sb.st_mode & CHMOD_MODE_BITS) != mode -+ || dest_sb.st_uid != (owner_id == (uid_t) -1 ? getuid () : owner_id) -+ || dest_sb.st_gid != (group_id == (gid_t) -1 ? getgid () : group_id)) -+ return true; -+ -+ /* compare SELinux context if preserving */ -+ if (selinux_enabled && x->preserve_security_context) -+ { -+ security_context_t file_scontext = NULL; -+ security_context_t to_scontext = NULL; -+ bool scontext_match; -+ -+ if (getfilecon (src_name, &file_scontext) == -1) -+ return true; -+ -+ if (getfilecon (dest_name, &to_scontext) == -1) -+ { -+ freecon (file_scontext); -+ return true; -+ } -+ -+ scontext_match = STREQ (file_scontext, to_scontext); -+ -+ freecon (file_scontext); -+ freecon (to_scontext); -+ if (!scontext_match) -+ return true; -+ } -+ -+ /* compare files content */ -+ src_fd = open (src_name, O_RDONLY | O_BINARY); -+ if (src_fd < 0) -+ return true; -+ -+ dest_fd = open (dest_name, O_RDONLY | O_BINARY); -+ if (dest_fd < 0) -+ { -+ close (src_fd); -+ return true; -+ } -+ -+ content_match = have_same_content (src_fd, dest_fd); -+ -+ close (src_fd); -+ close (dest_fd); -+ return !content_match; -+} -+ -+static void -+cp_option_init (struct cp_options *x) -+{ -+ cp_options_default (x); -+ x->copy_as_regular = true; -+ x->reflink_mode = REFLINK_NEVER; -+ x->dereference = DEREF_ALWAYS; -+ x->unlink_dest_before_opening = true; -+ x->unlink_dest_after_failed_open = false; -+ x->hard_link = false; -+ x->interactive = I_UNSPECIFIED; -+ x->move_mode = false; -+ x->one_file_system = false; -+ x->preserve_ownership = false; -+ x->preserve_links = false; -+ x->preserve_mode = false; -+ x->preserve_timestamps = false; -+ x->reduce_diagnostics=false; -+ x->require_preserve = false; -+ x->require_preserve_context = false; -+ x->require_preserve_xattr = false; -+ x->recursive = false; -+ x->sparse_mode = SPARSE_AUTO; -+ x->symbolic_link = false; -+ x->backup_type = no_backups; -+ -+ /* Create destination files initially writable so we can run strip on them. -+ Although GNU strip works fine on read-only files, some others -+ would fail. */ -+ x->set_mode = true; -+ x->mode = S_IRUSR | S_IWUSR; -+ x->stdin_tty = false; -+ -+ x->open_dangling_dest_symlink = false; -+ x->update = false; -+ x->preserve_security_context = false; -+ x->preserve_xattr = false; -+ x->verbose = false; -+ x->dest_info = NULL; -+ x->src_info = NULL; -+} -+ -+#ifdef ENABLE_MATCHPATHCON -+/* Modify file context to match the specified policy. -+ If an error occurs the file will remain with the default directory -+ context. */ -+static void -+setdefaultfilecon (char const *file) -+{ -+ struct stat st; -+ security_context_t scontext = NULL; -+ static bool first_call = true; -+ -+ if (selinux_enabled != 1) -+ { -+ /* Indicate no context found. */ -+ return; -+ } -+ if (lstat (file, &st) != 0) -+ return; -+ -+ if (first_call && IS_ABSOLUTE_FILE_NAME (file)) -+ { -+ /* Calling matchpathcon_init_prefix (NULL, "/first_component/") -+ is an optimization to minimize the expense of the following -+ matchpathcon call. Do it only once, just before the first -+ matchpathcon call. We *could* call matchpathcon_fini after -+ the final matchpathcon call, but that's not necessary, since -+ by then we're about to exit, and besides, the buffers it -+ would free are still reachable. */ -+ char const *p0; -+ char const *p = file + 1; -+ while (ISSLASH (*p)) -+ ++p; -+ -+ /* Record final leading slash, for when FILE starts with two or more. */ -+ p0 = p - 1; -+ -+ if (*p) -+ { -+ char *prefix; -+ do -+ { -+ ++p; -+ } -+ while (*p && !ISSLASH (*p)); -+ -+ prefix = malloc (p - p0 + 2); -+ if (prefix) -+ { -+ stpcpy (stpncpy (prefix, p0, p - p0), "/"); -+ matchpathcon_init_prefix (NULL, prefix); -+ free (prefix); -+ } -+ } -+ } -+ first_call = false; -+ -+ /* If there's an error determining the context, or it has none, -+ return to allow default context */ -+ if ((matchpathcon (file, st.st_mode, &scontext) != 0) || -+ STREQ (scontext, "<>")) -+ { -+ if (scontext != NULL) -+ freecon (scontext); -+ return; -+ } -+ -+ if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP) -+ error (0, errno, -+ _("warning: %s: failed to change context to %s"), -+ quotearg_colon (file), scontext); -+ -+ freecon (scontext); -+ return; -+} -+#else -+static void -+setdefaultfilecon (char const *file) -+{ -+ (void) file; -+} -+#endif -+ -+/* FILE is the last operand of this command. Return true if FILE is a -+ directory. But report an error there is a problem accessing FILE, -+ or if FILE does not exist but would have to refer to an existing -+ directory if it referred to anything at all. */ -+ -+static bool -+target_directory_operand (char const *file) -+{ -+ char const *b = last_component (file); -+ size_t blen = strlen (b); -+ bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1])); -+ struct stat st; -+ int err = (stat (file, &st) == 0 ? 0 : errno); -+ bool is_a_dir = !err && S_ISDIR (st.st_mode); -+ if (err && err != ENOENT) -+ error (EXIT_FAILURE, err, _("accessing %s"), quote (file)); -+ if (is_a_dir < looks_like_a_dir) -+ error (EXIT_FAILURE, err, _("target %s is not a directory"), quote (file)); -+ return is_a_dir; -+} -+ -+/* Process a command-line file name, for the -d option. */ -+static int -+process_dir (char *dir, struct savewd *wd, void *options) -+{ -+ return (make_dir_parents (dir, wd, -+ make_ancestor, options, -+ dir_mode, announce_mkdir, -+ dir_mode_bits, owner_id, group_id, false) -+ ? EXIT_SUCCESS -+ : EXIT_FAILURE); -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int optc; -+ int exit_status = EXIT_SUCCESS; -+ const char *specified_mode = NULL; -+ bool make_backups = false; -+ char *backup_suffix_string; -+ char *version_control_string = NULL; -+ bool mkdir_and_install = false; -+ struct cp_options x; -+ char const *target_directory = NULL; -+ bool no_target_directory = false; -+ int n_files; -+ char **file; -+ bool strip_program_specified = false; -+ security_context_t scontext = NULL; -+ /* set iff kernel has extra selinux system calls */ -+ selinux_enabled = (0 < is_selinux_enabled ()); -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdin); -+ -+ cp_option_init (&x); -+ -+ owner_name = NULL; -+ group_name = NULL; -+ strip_files = false; -+ dir_arg = false; -+ umask (0); -+ -+ /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless -+ we'll actually use backup_suffix_string. */ -+ backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); -+ -+ while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z:", long_options, -+ NULL)) != -1) -+ { -+ switch (optc) -+ { -+ case 'b': -+ make_backups = true; -+ if (optarg) -+ version_control_string = optarg; -+ break; -+ case 'c': -+ break; -+ case 'C': -+ copy_only_if_needed = true; -+ break; -+ case 's': -+ strip_files = true; -+#ifdef SIGCHLD -+ /* System V fork+wait does not work if SIGCHLD is ignored. */ -+ signal (SIGCHLD, SIG_DFL); -+#endif -+ break; -+ case STRIP_PROGRAM_OPTION: -+ strip_program = xstrdup (optarg); -+ strip_program_specified = true; -+ break; -+ case 'd': -+ dir_arg = true; -+ break; -+ case 'D': -+ mkdir_and_install = true; -+ break; -+ case 'v': -+ x.verbose = true; -+ break; -+ case 'g': -+ group_name = optarg; -+ break; -+ case 'm': -+ specified_mode = optarg; -+ break; -+ case 'o': -+ owner_name = optarg; -+ break; -+ case 'p': -+ x.preserve_timestamps = true; -+ break; -+ case 'S': -+ make_backups = true; -+ backup_suffix_string = optarg; -+ break; -+ case 't': -+ if (target_directory) -+ error (EXIT_FAILURE, 0, -+ _("multiple target directories specified")); -+ else -+ { -+ struct stat st; -+ if (stat (optarg, &st) != 0) -+ error (EXIT_FAILURE, errno, _("accessing %s"), quote (optarg)); -+ if (! S_ISDIR (st.st_mode)) -+ error (EXIT_FAILURE, 0, _("target %s is not a directory"), -+ quote (optarg)); -+ } -+ target_directory = optarg; -+ break; -+ case 'T': -+ no_target_directory = true; -+ break; -+ -+ case PRESERVE_CONTEXT_OPTION_DEPRECATED: -+ error (0, 0, _("WARNING: --preserve_context is deprecated; " -+ "use --preserve-context instead")); -+ /* fall through */ -+ case PRESERVE_CONTEXT_OPTION: -+ if ( ! selinux_enabled) -+ { -+ error (0, 0, _("WARNING: ignoring --preserve-context; " -+ "this kernel is not SELinux-enabled")); -+ break; -+ } -+ x.preserve_security_context = true; -+ use_default_selinux_context = false; -+ break; -+ case 'Z': -+ if ( ! selinux_enabled) -+ { -+ error (0, 0, _("WARNING: ignoring --context (-Z); " -+ "this kernel is not SELinux-enabled")); -+ break; -+ } -+ scontext = optarg; -+ use_default_selinux_context = false; -+ break; -+ case_GETOPT_HELP_CHAR; -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ /* Check for invalid combinations of arguments. */ -+ if (dir_arg && strip_files) -+ error (EXIT_FAILURE, 0, -+ _("the strip option may not be used when installing a directory")); -+ if (dir_arg && target_directory) -+ error (EXIT_FAILURE, 0, -+ _("target directory not allowed when installing a directory")); -+ -+ if (x.preserve_security_context && scontext != NULL) -+ error (EXIT_FAILURE, 0, -+ _("cannot force target context to %s and preserve it"), -+ quote (scontext)); -+ -+ if (backup_suffix_string) -+ simple_backup_suffix = xstrdup (backup_suffix_string); -+ -+ x.backup_type = (make_backups -+ ? xget_version (_("backup type"), -+ version_control_string) -+ : no_backups); -+ -+ if (scontext && setfscreatecon (scontext) < 0) -+ error (EXIT_FAILURE, errno, -+ _("failed to set default file creation context to %s"), -+ quote (scontext)); -+ -+ n_files = argc - optind; -+ file = argv + optind; -+ -+ if (n_files <= ! (dir_arg || target_directory)) -+ { -+ if (n_files <= 0) -+ error (0, 0, _("missing file operand")); -+ else -+ error (0, 0, _("missing destination file operand after %s"), -+ quote (file[0])); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (no_target_directory) -+ { -+ if (target_directory) -+ error (EXIT_FAILURE, 0, -+ _("cannot combine --target-directory (-t) " -+ "and --no-target-directory (-T)")); -+ if (2 < n_files) -+ { -+ error (0, 0, _("extra operand %s"), quote (file[2])); -+ usage (EXIT_FAILURE); -+ } -+ } -+ else if (! (dir_arg || target_directory)) -+ { -+ if (2 <= n_files && target_directory_operand (file[n_files - 1])) -+ target_directory = file[--n_files]; -+ else if (2 < n_files) -+ error (EXIT_FAILURE, 0, _("target %s is not a directory"), -+ quote (file[n_files - 1])); -+ } -+ -+ if (specified_mode) -+ { -+ struct mode_change *change = mode_compile (specified_mode); -+ if (!change) -+ error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode)); -+ mode = mode_adjust (0, false, 0, change, NULL); -+ dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits); -+ free (change); -+ } -+ -+ if (strip_program_specified && !strip_files) -+ error (0, 0, _("WARNING: ignoring --strip-program option as -s option was " -+ "not specified")); -+ -+ if (copy_only_if_needed && x.preserve_timestamps) -+ { -+ error (0, 0, _("options --compare (-C) and --preserve-timestamps are " -+ "mutually exclusive")); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (copy_only_if_needed && strip_files) -+ { -+ error (0, 0, _("options --compare (-C) and --strip are mutually " -+ "exclusive")); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (copy_only_if_needed && extra_mode (mode)) -+ error (0, 0, _("the --compare (-C) option is ignored when you" -+ " specify a mode with non-permission bits")); -+ -+ get_ids (); -+ -+ if (dir_arg) -+ exit_status = savewd_process_files (n_files, file, process_dir, &x); -+ else -+ { -+ /* FIXME: it's a little gross that this initialization is -+ required by copy.c::copy. */ -+ hash_init (); -+ -+ if (!target_directory) -+ { -+ if (! (mkdir_and_install -+ ? install_file_in_file_parents (file[0], file[1], &x) -+ : install_file_in_file (file[0], file[1], &x))) -+ exit_status = EXIT_FAILURE; -+ } -+ else -+ { -+ int i; -+ dest_info_init (&x); -+ for (i = 0; i < n_files; i++) -+ if (! install_file_in_dir (file[i], target_directory, &x)) -+ exit_status = EXIT_FAILURE; -+ } -+ } -+ -+ exit (exit_status); -+} -+ -+/* Copy file FROM onto file TO, creating any missing parent directories of TO. -+ Return true if successful. */ -+ -+static bool -+install_file_in_file_parents (char const *from, char *to, -+ struct cp_options *x) -+{ -+ bool save_working_directory = -+ ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to)); -+ int status = EXIT_SUCCESS; -+ -+ struct savewd wd; -+ savewd_init (&wd); -+ if (! save_working_directory) -+ savewd_finish (&wd); -+ -+ if (mkancesdirs (to, &wd, make_ancestor, x) == -1) -+ { -+ error (0, errno, _("cannot create directory %s"), to); -+ status = EXIT_FAILURE; -+ } -+ -+ if (save_working_directory) -+ { -+ int restore_result = savewd_restore (&wd, status); -+ int restore_errno = errno; -+ savewd_finish (&wd); -+ if (EXIT_SUCCESS < restore_result) -+ return false; -+ if (restore_result < 0 && status == EXIT_SUCCESS) -+ { -+ error (0, restore_errno, _("cannot create directory %s"), to); -+ return false; -+ } -+ } -+ -+ return (status == EXIT_SUCCESS && install_file_in_file (from, to, x)); -+} -+ -+/* Copy file FROM onto file TO and give TO the appropriate -+ attributes. -+ Return true if successful. */ -+ -+static bool -+install_file_in_file (const char *from, const char *to, -+ const struct cp_options *x) -+{ -+ struct stat from_sb; -+ if (x->preserve_timestamps && stat (from, &from_sb) != 0) -+ { -+ error (0, errno, _("cannot stat %s"), quote (from)); -+ return false; -+ } -+ if (! copy_file (from, to, x)) -+ return false; -+ if (strip_files) -+ strip (to); -+ if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode)) -+ && ! change_timestamps (&from_sb, to)) -+ return false; -+ return change_attributes (to); -+} -+ -+/* Copy file FROM into directory TO_DIR, keeping its same name, -+ and give the copy the appropriate attributes. -+ Return true if successful. */ -+ -+static bool -+install_file_in_dir (const char *from, const char *to_dir, -+ const struct cp_options *x) -+{ -+ const char *from_base = last_component (from); -+ char *to = file_name_concat (to_dir, from_base, NULL); -+ bool ret = install_file_in_file (from, to, x); -+ free (to); -+ return ret; -+} -+ -+/* Copy file FROM onto file TO, creating TO if necessary. -+ Return true if successful. */ -+ -+static bool -+copy_file (const char *from, const char *to, const struct cp_options *x) -+{ -+ bool copy_into_self; -+ -+ if (copy_only_if_needed && !need_copy (from, to, x)) -+ return true; -+ -+ /* Allow installing from non-regular files like /dev/null. -+ Charles Karney reported that some Sun version of install allows that -+ and that sendmail's installation process relies on the behavior. -+ However, since !x->recursive, the call to "copy" will fail if FROM -+ is a directory. */ -+ -+ return copy (from, to, false, x, ©_into_self, NULL); -+} -+ -+/* Set the attributes of file or directory NAME. -+ Return true if successful. */ -+ -+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. -+ On System V, users can give away files with chown and then not -+ be able to chmod them. So don't give files away. -+ -+ We don't normally ignore errors from chown because the idea of -+ the install command is that the file is supposed to end up with -+ precisely the attributes that the user specified (or defaulted). -+ If the file doesn't end up with the group they asked for, they'll -+ want to know. */ -+ -+ if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1) -+ && lchown (name, owner_id, group_id) != 0) -+ error (0, errno, _("cannot change ownership of %s"), quote (name)); -+ else if (chmod (name, mode) != 0) -+ error (0, errno, _("cannot change permissions of %s"), quote (name)); -+ else -+ ok = true; -+ -+ if (use_default_selinux_context) -+ setdefaultfilecon (name); -+ -+ return ok; -+} -+ -+/* Set the timestamps of file TO to match those of file FROM. -+ Return true if successful. */ -+ -+static bool -+change_timestamps (struct stat const *from_sb, char const *to) -+{ -+ struct timespec timespec[2]; -+ timespec[0] = get_stat_atime (from_sb); -+ timespec[1] = get_stat_mtime (from_sb); -+ -+ if (utimens (to, timespec)) -+ { -+ error (0, errno, _("cannot set time stamps for %s"), quote (to)); -+ return false; -+ } -+ return true; -+} -+ -+/* Strip the symbol table from the file NAME. -+ We could dig the magic number out of the file first to -+ determine whether to strip it, but the header files and -+ magic numbers vary so much from system to system that making -+ it portable would be very difficult. Not worth the effort. */ -+ -+static void -+strip (char const *name) -+{ -+ int status; -+ pid_t pid = fork (); -+ -+ switch (pid) -+ { -+ case -1: -+ error (EXIT_FAILURE, errno, _("fork system call failed")); -+ break; -+ case 0: /* Child. */ -+ execlp (strip_program, strip_program, name, NULL); -+ error (EXIT_FAILURE, errno, _("cannot run %s"), strip_program); -+ break; -+ default: /* Parent. */ -+ if (waitpid (pid, &status, 0) < 0) -+ error (EXIT_FAILURE, errno, _("waiting for strip")); -+ else if (! WIFEXITED (status) || WEXITSTATUS (status)) -+ error (EXIT_FAILURE, 0, _("strip process terminated abnormally")); -+ break; -+ } -+} -+ -+/* Initialize the user and group ownership of the files to install. */ -+ -+static void -+get_ids (void) -+{ -+ struct passwd *pw; -+ struct group *gr; -+ -+ if (owner_name) -+ { -+ pw = getpwnam (owner_name); -+ if (pw == NULL) -+ { -+ unsigned long int tmp; -+ if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK -+ || UID_T_MAX < tmp) -+ error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name)); -+ owner_id = tmp; -+ } -+ else -+ owner_id = pw->pw_uid; -+ endpwent (); -+ } -+ else -+ owner_id = (uid_t) -1; -+ -+ if (group_name) -+ { -+ gr = getgrnam (group_name); -+ if (gr == NULL) -+ { -+ unsigned long int tmp; -+ if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK -+ || GID_T_MAX < tmp) -+ error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name)); -+ group_id = tmp; -+ } -+ else -+ group_id = gr->gr_gid; -+ endgrent (); -+ } -+ else -+ group_id = (gid_t) -1; -+} -+ -+/* Report that directory DIR was made, if OPTIONS requests this. */ -+static void -+announce_mkdir (char const *dir, void *options) -+{ -+ struct cp_options const *x = options; -+ if (x->verbose) -+ prog_fprintf (stdout, _("creating directory %s"), quote (dir)); -+} -+ -+/* Make ancestor directory DIR, whose last file name component is -+ COMPONENT, with options OPTIONS. Assume the working directory is -+ COMPONENT's parent. */ -+static int -+make_ancestor (char const *dir, char const *component, void *options) -+{ -+ int r = mkdir (component, DEFAULT_MODE); -+ if (r == 0) -+ announce_mkdir (dir, options); -+ return r; -+} -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [-T] SOURCE DEST\n\ -+ or: %s [OPTION]... SOURCE... DIRECTORY\n\ -+ or: %s [OPTION]... -t DIRECTORY SOURCE...\n\ -+ or: %s [OPTION]... -d DIRECTORY...\n\ -+"), -+ program_name, program_name, program_name, program_name); -+ fputs (_("\ -+\n\ -+This install program copies files (often just compiled) into destination\n\ -+locations you choose. If you want to download and install a ready-to-use\n\ -+package on a GNU/Linux system, you should instead be using a package manager\n\ -+like yum(1) or apt-get(1).\n\ -+\n\ -+In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\ -+the existing DIRECTORY, while setting permission modes and owner/group.\n\ -+In the 4th form, create all components of the given DIRECTORY(ies).\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ --backup[=CONTROL] make a backup of each existing destination file\n\ -+ -b like --backup but does not accept an argument\n\ -+ -c (ignored)\n\ -+ -C, --compare compare each pair of source and destination files, and\n\ -+ in some cases, do not modify the destination at all\n\ -+ -d, --directory treat all arguments as directory names; create all\n\ -+ components of the specified directories\n\ -+"), stdout); -+ fputs (_("\ -+ -D create all leading components of DEST except the last,\n\ -+ then copy SOURCE to DEST\n\ -+ -g, --group=GROUP set group ownership, instead of process' current group\n\ -+ -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\ -+ -o, --owner=OWNER set ownership (super-user only)\n\ -+"), stdout); -+ fputs (_("\ -+ -p, --preserve-timestamps apply access/modification times of SOURCE files\n\ -+ to corresponding destination files\n\ -+ -s, --strip strip symbol tables\n\ -+ --strip-program=PROGRAM program used to strip binaries\n\ -+ -S, --suffix=SUFFIX override the usual backup suffix\n\ -+ -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\ -+ -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 (_("\ -+ --preserve-context preserve SELinux security context\n\ -+ -Z, --context=CONTEXT set SELinux security context of files and directories\n\ -+"), stdout); -+ -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ -+The version control method may be selected via the --backup option or through\n\ -+the VERSION_CONTROL environment variable. Here are the values:\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+ none, off never make backups (even if --backup is given)\n\ -+ numbered, t make numbered backups\n\ -+ existing, nil numbered if numbered backups exist, simple otherwise\n\ -+ simple, never always make simple backups\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -diff -urNp coreutils-8.0-orig/src/ls.c coreutils-8.0/src/ls.c ---- coreutils-8.0-orig/src/ls.c 2009-10-07 10:09:43.000000000 +0200 -+++ coreutils-8.0/src/ls.c 2009-10-07 10:10:11.000000000 +0200 -@@ -162,7 +162,8 @@ enum filetype - symbolic_link, - sock, - whiteout, -- arg_directory -+ arg_directory, -+ command_line - }; - - /* Display letters and indicators for each filetype. -@@ -279,6 +280,7 @@ static void queue_directory (char const - static void sort_files (void); - static void parse_ls_color (void); - void usage (int status); -+static void print_scontext_format (const struct fileinfo *f); - - /* Initial size of hash table. - Most hierarchies are likely to be shallower than this. */ -@@ -348,7 +350,7 @@ static struct pending *pending_dirs; - - static struct timespec current_time; - --static bool print_scontext; -+static int print_scontext = 0; - static char UNKNOWN_SECURITY_CONTEXT[] = "?"; - - /* Whether any of the files has an ACL. This affects the width of the -@@ -388,7 +390,9 @@ enum format - one_per_line, /* -1 */ - many_per_line, /* -C */ - horizontal, /* -x */ -- with_commas /* -m */ -+ with_commas, /* -m */ -+ security_format, /* -Z */ -+ invalid_format - }; - - static enum format format; -@@ -790,6 +794,9 @@ enum - SHOW_CONTROL_CHARS_OPTION, - SI_OPTION, - SORT_OPTION, -+ CONTEXT_OPTION, -+ LCONTEXT_OPTION, -+ SCONTEXT_OPTION, - TIME_OPTION, - TIME_STYLE_OPTION - }; -@@ -835,7 +842,9 @@ static struct option const long_options[ - {"time-style", required_argument, NULL, TIME_STYLE_OPTION}, - {"color", optional_argument, NULL, COLOR_OPTION}, - {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, -- {"context", no_argument, 0, 'Z'}, -+ {"context", no_argument, 0, CONTEXT_OPTION}, -+ {"lcontext", no_argument, 0, LCONTEXT_OPTION}, -+ {"scontext", no_argument, 0, SCONTEXT_OPTION}, - {"author", no_argument, NULL, AUTHOR_OPTION}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, -@@ -845,12 +854,12 @@ static struct option const long_options[ - static char const *const format_args[] = - { - "verbose", "long", "commas", "horizontal", "across", -- "vertical", "single-column", NULL -+ "vertical", "single-column", "context", NULL - }; - static enum format const format_types[] = - { - long_format, long_format, with_commas, horizontal, horizontal, -- many_per_line, one_per_line -+ many_per_line, one_per_line, security_format - }; - ARGMATCH_VERIFY (format_args, format_types); - -@@ -1281,7 +1290,8 @@ main (int argc, char **argv) - /* Avoid following symbolic links when possible. */ - if (is_colored (C_ORPHAN) - || (is_colored (C_EXEC) && color_symlink_as_referent) -- || (is_colored (C_MISSING) && format == long_format)) -+ || (is_colored (C_MISSING) && (format == long_format -+ || format == security_format))) - check_symlink_color = true; - - /* If the standard output is a controlling terminal, watch out -@@ -1328,7 +1338,7 @@ main (int argc, char **argv) - if (dereference == DEREF_UNDEFINED) - dereference = ((immediate_dirs - || indicator_style == classify -- || format == long_format) -+ || format == long_format || format == security_format) - ? DEREF_NEVER - : DEREF_COMMAND_LINE_SYMLINK_TO_DIR); - -@@ -1348,7 +1358,7 @@ main (int argc, char **argv) - - format_needs_stat = sort_type == sort_time || sort_type == sort_size - || format == long_format -- || print_scontext -+ || format == security_format || print_scontext - || print_block_size; - format_needs_type = (! format_needs_stat - && (recursive -@@ -1379,7 +1389,7 @@ main (int argc, char **argv) - } - 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) -@@ -1542,7 +1552,7 @@ decode_switches (int argc, char **argv) - ignore_mode = IGNORE_DEFAULT; - ignore_patterns = NULL; - hide_patterns = NULL; -- print_scontext = false; -+ print_scontext = 0; - - /* FIXME: put this in a function. */ - { -@@ -1924,13 +1934,27 @@ decode_switches (int argc, char **argv) - break; - - case 'Z': -- print_scontext = true; -+ print_scontext = 1; -+ format = security_format; - break; - - case_GETOPT_HELP_CHAR; - - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - -+ case CONTEXT_OPTION: /* default security context 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; -+ - default: - usage (LS_FAILURE); - } -@@ -2651,8 +2675,10 @@ clear_files (void) - struct fileinfo *f = sorted_file[i]; - free (f->name); - free (f->linkname); -- if (f->scontext != UNKNOWN_SECURITY_CONTEXT) -- freecon (f->scontext); -+ if (f->scontext != UNKNOWN_SECURITY_CONTEXT) { -+ freecon (f->scontext); -+ f->scontext = NULL; -+ } - } - - cwd_n_used = 0; -@@ -2694,6 +2720,7 @@ gobble_file (char const *name, enum file - memset (f, '\0', sizeof *f); - f->stat.st_ino = inode; - f->filetype = type; -+ f->scontext = NULL; - - if (command_line_arg - || format_needs_stat -@@ -2793,7 +2820,7 @@ gobble_file (char const *name, enum file - - f->stat_ok = true; - -- if (format == long_format || print_scontext) -+ if (format == long_format || format == security_format || print_scontext) - { - bool have_selinux = false; - bool have_acl = false; -@@ -2827,7 +2854,7 @@ gobble_file (char const *name, enum file - err = 0; - } - -- if (err == 0 && format == long_format) -+ if (err == 0 && (format == long_format || format == security_format)) - { - int n = file_has_acl (absolute_name, &f->stat); - err = (n < 0); -@@ -2846,7 +2873,8 @@ gobble_file (char const *name, enum file - } - - if (S_ISLNK (f->stat.st_mode) -- && (format == long_format || check_symlink_color)) -+ && (format == long_format || format == security_format -+ || check_symlink_color)) - { - char *linkname; - struct stat linkstats; -@@ -2866,6 +2894,7 @@ gobble_file (char const *name, enum file - command line are automatically traced if not being - listed as files. */ - if (!command_line_arg || format == long_format -+ || format == security_format - || !S_ISDIR (linkstats.st_mode)) - { - /* Get the linked-to file's mode for the filetype indicator -@@ -2905,7 +2934,7 @@ gobble_file (char const *name, enum file - block_size_width = len; - } - -- if (format == long_format) -+ if (format == long_format || format == security_format) - { - if (print_owner) - { -@@ -3406,6 +3435,13 @@ print_current_files (void) - print_long_format (sorted_file[i]); - DIRED_PUTCHAR ('\n'); - } -+ break; -+ case security_format: -+ for (i = 0; i < cwd_n_used; i++) -+ { -+ print_scontext_format (sorted_file[i]); -+ DIRED_PUTCHAR ('\n'); -+ } - break; - } - } -@@ -3568,6 +3604,69 @@ format_inode (char *buf, size_t buflen, - : (char *) "?"); - } - -+/* Print info about f in scontext format */ -+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; -+ char *p; -+ -+ p = buf; -+ -+ if ( print_scontext ) { /* zero means terse listing */ -+ filemodestring (&f->stat, modebuf); -+ if (! any_has_acl) -+ modebuf[10] = '\0'; -+ else if (f->acl_type == ACL_T_SELINUX_ONLY) -+ modebuf[10] = '.'; -+ else if (f->acl_type == ACL_T_YES) -+ modebuf[10] = '+'; -+ 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); -+ size_t w = print_name_with_quoting (f->name, FILE_OR_LINK_MODE(f), f->linkok, -+ f->stat_ok, f->filetype, &dired_obstack, f->stat.st_nlink, p - buf); -+ -+ 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, f->stat.st_nlink, (p-buf) + w + 4 ); -+ 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); -+ } -+} -+ - /* Print information about F in long format. */ - static void - print_long_format (const struct fileinfo *f) -@@ -3659,9 +3758,15 @@ print_long_format (const struct fileinfo - The latter is wrong when nlink_width is zero. */ - p += strlen (p); - -+ if (print_scontext) -+ { -+ sprintf (p, "%-32s ", f->scontext ? f->scontext : ""); -+ p += strlen (p); -+ } -+ - DIRED_INDENT (); - -- if (print_owner || print_group || print_author || print_scontext) -+ if (print_owner || print_group || print_author) - { - DIRED_FPUTS (buf, stdout, p - buf); - -@@ -3674,9 +3779,6 @@ print_long_format (const struct fileinfo - if (print_author) - format_user (f->stat.st_author, author_width, f->stat_ok); - -- if (print_scontext) -- format_user_or_group (f->scontext, 0, scontext_width); -- - p = buf; - } - -@@ -4020,9 +4122,6 @@ print_file_name_and_frills (const struct - : human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts, - ST_NBLOCKSIZE, output_block_size)); - -- if (print_scontext) -- printf ("%*s ", format == with_commas ? 0 : scontext_width, f->scontext); -- - size_t width = print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), - f->linkok, f->stat_ok, f->filetype, - NULL, f->stat.st_nlink, start_col); -@@ -4241,9 +4340,6 @@ length_of_file_name_and_frills (const st - output_block_size)) - : block_size_width); - -- if (print_scontext) -- len += 1 + (format == with_commas ? strlen (f->scontext) : scontext_width); -- - quote_name (NULL, f->name, filename_quoting_options, &name_width); - len += name_width; - -@@ -4674,9 +4770,16 @@ Mandatory arguments to long options are - -w, --width=COLS assume screen width instead of current value\n\ - -x list entries by lines instead of by columns\n\ - -X sort alphabetically by entry extension\n\ -- -Z, --context print any SELinux security context of each file\n\ - -1 list one file per line\n\ - "), stdout); -+ fputs(_("\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\ -+"), stdout); - fputs (HELP_OPTION_DESCRIPTION, stdout); - fputs (VERSION_OPTION_DESCRIPTION, stdout); - emit_size_note (); -diff -urNp coreutils-8.0-orig/src/ls.c.orig coreutils-8.0/src/ls.c.orig ---- coreutils-8.0-orig/src/ls.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/ls.c.orig 2009-10-07 10:09:43.000000000 +0200 -@@ -0,0 +1,4700 @@ -+/* `dir', `vdir' and `ls' directory listing programs for GNU. -+ Copyright (C) 85, 88, 90, 91, 1995-2009 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 ls_mode is LS_MULTI_COL, -+ the multi-column format is the default regardless -+ of the type of output device. -+ This is for the `dir' program. -+ -+ If ls_mode is LS_LONG_FORMAT, -+ the long format is the default regardless of the -+ type of output device. -+ This is for the `vdir' program. -+ -+ If ls_mode is LS_LS, -+ the output format depends on whether the output -+ device is a terminal. -+ This is for the `ls' program. */ -+ -+/* Written by Richard Stallman and David MacKenzie. */ -+ -+/* Color support by Peter Anvin and Dennis -+ Flaherty based on original patches by -+ Greg Lee . */ -+ -+#include -+#include -+ -+#if HAVE_TERMIOS_H -+# include -+#endif -+#if HAVE_STROPTS_H -+# include -+#endif -+#if HAVE_SYS_IOCTL_H -+# include -+#endif -+ -+#ifdef WINSIZE_IN_PTEM -+# include -+# include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if HAVE_LANGINFO_CODESET -+# include -+#endif -+ -+/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is -+ present. */ -+#ifndef SA_NOCLDSTOP -+# define SA_NOCLDSTOP 0 -+# define sigprocmask(How, Set, Oset) /* empty */ -+# define sigset_t int -+# if ! HAVE_SIGINTERRUPT -+# define siginterrupt(sig, flag) /* empty */ -+# endif -+#endif -+#ifndef SA_RESTART -+# define SA_RESTART 0 -+#endif -+ -+#include "system.h" -+#include -+ -+#ifdef HAVE_CAP -+# include -+#endif -+ -+#include "acl.h" -+#include "argmatch.h" -+#include "dev-ino.h" -+#include "error.h" -+#include "filenamecat.h" -+#include "hard-locale.h" -+#include "hash.h" -+#include "human.h" -+#include "filemode.h" -+#include "filevercmp.h" -+#include "idcache.h" -+#include "ls.h" -+#include "mbswidth.h" -+#include "mpsort.h" -+#include "obstack.h" -+#include "quote.h" -+#include "quotearg.h" -+#include "same.h" -+#include "stat-time.h" -+#include "strftime.h" -+#include "xstrtol.h" -+#include "areadlink.h" -+#include "mbsalign.h" -+ -+#define PROGRAM_NAME (ls_mode == LS_LS ? "ls" \ -+ : (ls_mode == LS_MULTI_COL \ -+ ? "dir" : "vdir")) -+ -+#define AUTHORS \ -+ proper_name ("Richard M. Stallman"), \ -+ proper_name ("David MacKenzie") -+ -+#define obstack_chunk_alloc malloc -+#define obstack_chunk_free free -+ -+/* Return an int indicating the result of comparing two integers. -+ Subtracting doesn't always work, due to overflow. */ -+#define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b)) -+ -+/* Unix-based readdir implementations have historically returned a dirent.d_ino -+ value that is sometimes not equal to the stat-obtained st_ino value for -+ that same entry. This error occurs for a readdir entry that refers -+ to a mount point. readdir's error is to return the inode number of -+ the underlying directory -- one that typically cannot be stat'ed, as -+ long as a file system is mounted on that directory. RELIABLE_D_INO -+ encapsulates whether we can use the more efficient approach of relying -+ on readdir-supplied d_ino values, or whether we must incur the cost of -+ calling stat or lstat to obtain each guaranteed-valid inode number. */ -+ -+#ifndef READDIR_LIES_ABOUT_MOUNTPOINT_D_INO -+# define READDIR_LIES_ABOUT_MOUNTPOINT_D_INO 1 -+#endif -+ -+#if READDIR_LIES_ABOUT_MOUNTPOINT_D_INO -+# define RELIABLE_D_INO(dp) NOT_AN_INODE_NUMBER -+#else -+# define RELIABLE_D_INO(dp) D_INO (dp) -+#endif -+ -+#if ! HAVE_STRUCT_STAT_ST_AUTHOR -+# define st_author st_uid -+#endif -+ -+enum filetype -+ { -+ unknown, -+ fifo, -+ chardev, -+ directory, -+ blockdev, -+ normal, -+ symbolic_link, -+ sock, -+ whiteout, -+ arg_directory -+ }; -+ -+/* Display letters and indicators for each filetype. -+ Keep these in sync with enum filetype. */ -+static char const filetype_letter[] = "?pcdb-lswd"; -+ -+/* Ensure that filetype and filetype_letter have the same -+ number of elements. */ -+verify (sizeof filetype_letter - 1 == arg_directory + 1); -+ -+#define FILETYPE_INDICATORS \ -+ { \ -+ C_ORPHAN, C_FIFO, C_CHR, C_DIR, C_BLK, C_FILE, \ -+ C_LINK, C_SOCK, C_FILE, C_DIR \ -+ } -+ -+enum acl_type -+ { -+ ACL_T_NONE, -+ ACL_T_SELINUX_ONLY, -+ ACL_T_YES -+ }; -+ -+struct fileinfo -+ { -+ /* The file name. */ -+ char *name; -+ -+ /* For symbolic link, name of the file linked to, otherwise zero. */ -+ char *linkname; -+ -+ struct stat stat; -+ -+ enum filetype filetype; -+ -+ /* For symbolic link and long listing, st_mode of file linked to, otherwise -+ zero. */ -+ mode_t linkmode; -+ -+ /* SELinux security context. */ -+ security_context_t scontext; -+ -+ bool stat_ok; -+ -+ /* For symbolic link and color printing, true if linked-to file -+ exists, otherwise false. */ -+ bool linkok; -+ -+ /* For long listings, true if the file has an access control list, -+ or an SELinux security context. */ -+ enum acl_type acl_type; -+ }; -+ -+#define LEN_STR_PAIR(s) sizeof (s) - 1, s -+ -+/* Null is a valid character in a color indicator (think about Epson -+ printers, for example) so we have to use a length/buffer string -+ type. */ -+ -+struct bin_str -+ { -+ size_t len; /* Number of bytes */ -+ const char *string; /* Pointer to the same */ -+ }; -+ -+#if ! HAVE_TCGETPGRP -+# define tcgetpgrp(Fd) 0 -+#endif -+ -+static size_t quote_name (FILE *out, const char *name, -+ struct quoting_options const *options, -+ size_t *width); -+static char *make_link_name (char const *name, char const *linkname); -+static int decode_switches (int argc, char **argv); -+static bool file_ignored (char const *name); -+static uintmax_t gobble_file (char const *name, enum filetype type, -+ ino_t inode, bool command_line_arg, -+ char const *dirname); -+static bool print_color_indicator (const char *name, mode_t mode, int linkok, -+ bool stat_ok, enum filetype type, -+ nlink_t nlink); -+static void put_indicator (const struct bin_str *ind); -+static void add_ignore_pattern (const char *pattern); -+static void attach (char *dest, const char *dirname, const char *name); -+static void clear_files (void); -+static void extract_dirs_from_files (char const *dirname, -+ bool command_line_arg); -+static void get_link_name (char const *filename, struct fileinfo *f, -+ bool command_line_arg); -+static void indent (size_t from, size_t to); -+static size_t calculate_columns (bool by_columns); -+static void print_current_files (void); -+static void print_dir (char const *name, char const *realname, -+ bool command_line_arg); -+static size_t print_file_name_and_frills (const struct fileinfo *f, -+ size_t start_col); -+static void print_horizontal (void); -+static int format_user_width (uid_t u); -+static int format_group_width (gid_t g); -+static void print_long_format (const struct fileinfo *f); -+static void print_many_per_line (void); -+static size_t print_name_with_quoting (const char *p, mode_t mode, -+ int linkok, bool stat_ok, -+ enum filetype type, -+ struct obstack *stack, -+ nlink_t nlink, -+ size_t start_col); -+static void prep_non_filename_text (void); -+static bool print_type_indicator (bool stat_ok, mode_t mode, -+ enum filetype type); -+static void print_with_commas (void); -+static void queue_directory (char const *name, char const *realname, -+ bool command_line_arg); -+static void sort_files (void); -+static void parse_ls_color (void); -+void usage (int status); -+ -+/* Initial size of hash table. -+ Most hierarchies are likely to be shallower than this. */ -+#define INITIAL_TABLE_SIZE 30 -+ -+/* The set of `active' directories, from the current command-line argument -+ to the level in the hierarchy at which files are being listed. -+ A directory is represented by its device and inode numbers (struct dev_ino). -+ A directory is added to this set when ls begins listing it or its -+ entries, and it is removed from the set just after ls has finished -+ processing it. This set is used solely to detect loops, e.g., with -+ mkdir loop; cd loop; ln -s ../loop sub; ls -RL */ -+static Hash_table *active_dir_set; -+ -+#define LOOP_DETECT (!!active_dir_set) -+ -+/* The table of files in the current directory: -+ -+ `cwd_file' points to a vector of `struct fileinfo', one per file. -+ `cwd_n_alloc' is the number of elements space has been allocated for. -+ `cwd_n_used' is the number actually in use. */ -+ -+/* Address of block containing the files that are described. */ -+static struct fileinfo *cwd_file; -+ -+/* Length of block that `cwd_file' points to, measured in files. */ -+static size_t cwd_n_alloc; -+ -+/* Index of first unused slot in `cwd_file'. */ -+static size_t cwd_n_used; -+ -+/* Vector of pointers to files, in proper sorted order, and the number -+ of entries allocated for it. */ -+static void **sorted_file; -+static size_t sorted_file_alloc; -+ -+/* When true, in a color listing, color each symlink name according to the -+ type of file it points to. Otherwise, color them according to the `ln' -+ directive in LS_COLORS. Dangling (orphan) symlinks are treated specially, -+ regardless. This is set when `ln=target' appears in LS_COLORS. */ -+ -+static bool color_symlink_as_referent; -+ -+/* mode of appropriate file for colorization */ -+#define FILE_OR_LINK_MODE(File) \ -+ ((color_symlink_as_referent && (File)->linkok) \ -+ ? (File)->linkmode : (File)->stat.st_mode) -+ -+ -+/* Record of one pending directory waiting to be listed. */ -+ -+struct pending -+ { -+ char *name; -+ /* If the directory is actually the file pointed to by a symbolic link we -+ were told to list, `realname' will contain the name of the symbolic -+ link, otherwise zero. */ -+ char *realname; -+ bool command_line_arg; -+ struct pending *next; -+ }; -+ -+static struct pending *pending_dirs; -+ -+/* Current time in seconds and nanoseconds since 1970, updated as -+ needed when deciding whether a file is recent. */ -+ -+static struct timespec current_time; -+ -+static bool print_scontext; -+static char UNKNOWN_SECURITY_CONTEXT[] = "?"; -+ -+/* Whether any of the files has an ACL. This affects the width of the -+ mode column. */ -+ -+static bool any_has_acl; -+ -+/* The number of columns to use for columns containing inode numbers, -+ block sizes, link counts, owners, groups, authors, major device -+ numbers, minor device numbers, and file sizes, respectively. */ -+ -+static int inode_number_width; -+static int block_size_width; -+static int nlink_width; -+static int scontext_width; -+static int owner_width; -+static int group_width; -+static int author_width; -+static int major_device_number_width; -+static int minor_device_number_width; -+static int file_size_width; -+ -+/* Option flags */ -+ -+/* long_format for lots of info, one per line. -+ one_per_line for just names, one per line. -+ many_per_line for just names, many per line, sorted vertically. -+ horizontal for just names, many per line, sorted horizontally. -+ with_commas for just names, many per line, separated by commas. -+ -+ -l (and other options that imply -l), -1, -C, -x and -m control -+ this parameter. */ -+ -+enum format -+ { -+ long_format, /* -l and other options that imply -l */ -+ one_per_line, /* -1 */ -+ many_per_line, /* -C */ -+ horizontal, /* -x */ -+ with_commas /* -m */ -+ }; -+ -+static enum format format; -+ -+/* `full-iso' uses full ISO-style dates and times. `long-iso' uses longer -+ ISO-style time stamps, though shorter than `full-iso'. `iso' uses shorter -+ ISO-style time stamps. `locale' uses locale-dependent time stamps. */ -+enum time_style -+ { -+ full_iso_time_style, /* --time-style=full-iso */ -+ long_iso_time_style, /* --time-style=long-iso */ -+ iso_time_style, /* --time-style=iso */ -+ locale_time_style /* --time-style=locale */ -+ }; -+ -+static char const *const time_style_args[] = -+{ -+ "full-iso", "long-iso", "iso", "locale", NULL -+}; -+static enum time_style const time_style_types[] = -+{ -+ full_iso_time_style, long_iso_time_style, iso_time_style, -+ locale_time_style -+}; -+ARGMATCH_VERIFY (time_style_args, time_style_types); -+ -+/* Type of time to print or sort by. Controlled by -c and -u. -+ The values of each item of this enum are important since they are -+ used as indices in the sort functions array (see sort_files()). */ -+ -+enum time_type -+ { -+ time_mtime, /* default */ -+ time_ctime, /* -c */ -+ time_atime, /* -u */ -+ time_numtypes /* the number of elements of this enum */ -+ }; -+ -+static enum time_type time_type; -+ -+/* The file characteristic to sort by. Controlled by -t, -S, -U, -X, -v. -+ The values of each item of this enum are important since they are -+ used as indices in the sort functions array (see sort_files()). */ -+ -+enum sort_type -+ { -+ sort_none = -1, /* -U */ -+ sort_name, /* default */ -+ sort_extension, /* -X */ -+ sort_size, /* -S */ -+ sort_version, /* -v */ -+ sort_time, /* -t */ -+ sort_numtypes /* the number of elements of this enum */ -+ }; -+ -+static enum sort_type sort_type; -+ -+/* Direction of sort. -+ false means highest first if numeric, -+ lowest first if alphabetic; -+ these are the defaults. -+ true means the opposite order in each case. -r */ -+ -+static bool sort_reverse; -+ -+/* True means to display owner information. -g turns this off. */ -+ -+static bool print_owner = true; -+ -+/* True means to display author information. */ -+ -+static bool print_author; -+ -+/* True means to display group information. -G and -o turn this off. */ -+ -+static bool print_group = true; -+ -+/* True means print the user and group id's as numbers rather -+ than as names. -n */ -+ -+static bool numeric_ids; -+ -+/* True means mention the size in blocks of each file. -s */ -+ -+static bool print_block_size; -+ -+/* Human-readable options for output. */ -+static int human_output_opts; -+ -+/* The units to use when printing sizes other than file sizes. */ -+static uintmax_t output_block_size; -+ -+/* Likewise, but for file sizes. */ -+static uintmax_t file_output_block_size = 1; -+ -+/* Follow the output with a special string. Using this format, -+ Emacs' dired mode starts up twice as fast, and can handle all -+ strange characters in file names. */ -+static bool dired; -+ -+/* `none' means don't mention the type of files. -+ `slash' means mention directories only, with a '/'. -+ `file_type' means mention file types. -+ `classify' means mention file types and mark executables. -+ -+ Controlled by -F, -p, and --indicator-style. */ -+ -+enum indicator_style -+ { -+ none, /* --indicator-style=none */ -+ slash, /* -p, --indicator-style=slash */ -+ file_type, /* --indicator-style=file-type */ -+ classify /* -F, --indicator-style=classify */ -+ }; -+ -+static enum indicator_style indicator_style; -+ -+/* Names of indicator styles. */ -+static char const *const indicator_style_args[] = -+{ -+ "none", "slash", "file-type", "classify", NULL -+}; -+static enum indicator_style const indicator_style_types[] = -+{ -+ none, slash, file_type, classify -+}; -+ARGMATCH_VERIFY (indicator_style_args, indicator_style_types); -+ -+/* True means use colors to mark types. Also define the different -+ colors as well as the stuff for the LS_COLORS environment variable. -+ The LS_COLORS variable is now in a termcap-like format. */ -+ -+static bool print_with_color; -+ -+/* Whether we used any colors in the output so far. If so, we will -+ need to restore the default color later. If not, we will need to -+ call prep_non_filename_text before using color for the first time. */ -+ -+static bool used_color = false; -+ -+enum color_type -+ { -+ color_never, /* 0: default or --color=never */ -+ color_always, /* 1: --color=always */ -+ color_if_tty /* 2: --color=tty */ -+ }; -+ -+enum Dereference_symlink -+ { -+ DEREF_UNDEFINED = 1, -+ DEREF_NEVER, -+ DEREF_COMMAND_LINE_ARGUMENTS, /* -H */ -+ DEREF_COMMAND_LINE_SYMLINK_TO_DIR, /* the default, in certain cases */ -+ DEREF_ALWAYS /* -L */ -+ }; -+ -+enum indicator_no -+ { -+ C_LEFT, C_RIGHT, C_END, C_RESET, C_NORM, C_FILE, C_DIR, C_LINK, -+ C_FIFO, C_SOCK, -+ C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR, C_SETUID, C_SETGID, -+ C_STICKY, C_OTHER_WRITABLE, C_STICKY_OTHER_WRITABLE, C_CAP, C_MULTIHARDLINK, -+ C_CLR_TO_EOL -+ }; -+ -+static const char *const indicator_name[]= -+ { -+ "lc", "rc", "ec", "rs", "no", "fi", "di", "ln", "pi", "so", -+ "bd", "cd", "mi", "or", "ex", "do", "su", "sg", "st", -+ "ow", "tw", "ca", "mh", "cl", NULL -+ }; -+ -+struct color_ext_type -+ { -+ struct bin_str ext; /* The extension we're looking for */ -+ struct bin_str seq; /* The sequence to output when we do */ -+ struct color_ext_type *next; /* Next in list */ -+ }; -+ -+static struct bin_str color_indicator[] = -+ { -+ { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */ -+ { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ -+ { 0, NULL }, /* ec: End color (replaces lc+no+rc) */ -+ { LEN_STR_PAIR ("0") }, /* rs: Reset to ordinary colors */ -+ { 0, NULL }, /* no: Normal */ -+ { 0, NULL }, /* fi: File: default */ -+ { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */ -+ { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */ -+ { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */ -+ { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */ -+ { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */ -+ { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */ -+ { 0, NULL }, /* mi: Missing file: undefined */ -+ { 0, NULL }, /* or: Orphaned symlink: undefined */ -+ { LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */ -+ { LEN_STR_PAIR ("01;35") }, /* do: Door: bright magenta */ -+ { LEN_STR_PAIR ("37;41") }, /* su: setuid: white on red */ -+ { LEN_STR_PAIR ("30;43") }, /* sg: setgid: black on yellow */ -+ { LEN_STR_PAIR ("37;44") }, /* st: sticky: black on blue */ -+ { LEN_STR_PAIR ("34;42") }, /* ow: other-writable: blue on green */ -+ { LEN_STR_PAIR ("30;42") }, /* tw: ow w/ sticky: black on green */ -+ { LEN_STR_PAIR ("30;41") }, /* ca: black on red */ -+ { 0, NULL }, /* mh: disabled by default */ -+ { LEN_STR_PAIR ("\033[K") }, /* cl: clear to end of line */ -+ }; -+ -+/* FIXME: comment */ -+static struct color_ext_type *color_ext_list = NULL; -+ -+/* Buffer for color sequences */ -+static char *color_buf; -+ -+/* True means to check for orphaned symbolic link, for displaying -+ colors. */ -+ -+static bool check_symlink_color; -+ -+/* True means mention the inode number of each file. -i */ -+ -+static bool print_inode; -+ -+/* What to do with symbolic links. Affected by -d, -F, -H, -l (and -+ other options that imply -l), and -L. */ -+ -+static enum Dereference_symlink dereference; -+ -+/* True means when a directory is found, display info on its -+ contents. -R */ -+ -+static bool recursive; -+ -+/* True means when an argument is a directory name, display info -+ on it itself. -d */ -+ -+static bool immediate_dirs; -+ -+/* True means that directories are grouped before files. */ -+ -+static bool directories_first; -+ -+/* Which files to ignore. */ -+ -+static enum -+{ -+ /* Ignore files whose names start with `.', and files specified by -+ --hide and --ignore. */ -+ IGNORE_DEFAULT, -+ -+ /* Ignore `.', `..', and files specified by --ignore. */ -+ IGNORE_DOT_AND_DOTDOT, -+ -+ /* Ignore only files specified by --ignore. */ -+ IGNORE_MINIMAL -+} ignore_mode; -+ -+/* A linked list of shell-style globbing patterns. If a non-argument -+ file name matches any of these patterns, it is ignored. -+ Controlled by -I. Multiple -I options accumulate. -+ The -B option adds `*~' and `.*~' to this list. */ -+ -+struct ignore_pattern -+ { -+ const char *pattern; -+ struct ignore_pattern *next; -+ }; -+ -+static struct ignore_pattern *ignore_patterns; -+ -+/* Similar to IGNORE_PATTERNS, except that -a or -A causes this -+ variable itself to be ignored. */ -+static struct ignore_pattern *hide_patterns; -+ -+/* True means output nongraphic chars in file names as `?'. -+ (-q, --hide-control-chars) -+ qmark_funny_chars and the quoting style (-Q, --quoting-style=WORD) are -+ independent. The algorithm is: first, obey the quoting style to get a -+ string representing the file name; then, if qmark_funny_chars is set, -+ replace all nonprintable chars in that string with `?'. It's necessary -+ to replace nonprintable chars even in quoted strings, because we don't -+ want to mess up the terminal if control chars get sent to it, and some -+ quoting methods pass through control chars as-is. */ -+static bool qmark_funny_chars; -+ -+/* Quoting options for file and dir name output. */ -+ -+static struct quoting_options *filename_quoting_options; -+static struct quoting_options *dirname_quoting_options; -+ -+/* The number of chars per hardware tab stop. Setting this to zero -+ inhibits the use of TAB characters for separating columns. -T */ -+static size_t tabsize; -+ -+/* True means print each directory name before listing it. */ -+ -+static bool print_dir_name; -+ -+/* The line length to use for breaking lines in many-per-line format. -+ Can be set with -w. */ -+ -+static size_t line_length; -+ -+/* If true, the file listing format requires that stat be called on -+ each file. */ -+ -+static bool format_needs_stat; -+ -+/* Similar to `format_needs_stat', but set if only the file type is -+ needed. */ -+ -+static bool format_needs_type; -+ -+/* An arbitrary limit on the number of bytes in a printed time stamp. -+ This is set to a relatively small value to avoid the need to worry -+ about denial-of-service attacks on servers that run "ls" on behalf -+ of remote clients. 1000 bytes should be enough for any practical -+ time stamp format. */ -+ -+enum { TIME_STAMP_LEN_MAXIMUM = MAX (1000, INT_STRLEN_BOUND (time_t)) }; -+ -+/* strftime formats for non-recent and recent files, respectively, in -+ -l output. */ -+ -+static char const *long_time_format[2] = -+ { -+ /* strftime format for non-recent files (older than 6 months), in -+ -l output. This should contain the year, month and day (at -+ least), in an order that is understood by people in your -+ locale's territory. Please try to keep the number of used -+ screen columns small, because many people work in windows with -+ only 80 columns. But make this as wide as the other string -+ below, for recent files. */ -+ /* TRANSLATORS: ls output needs to be aligned for ease of reading, -+ so be wary of using variable width fields from the locale. -+ Note %b is handled specially by ls and aligned correctly. -+ Note also that specifying a width as in %5b is erroneous as strftime -+ will count bytes rather than characters in multibyte locales. */ -+ N_("%b %e %Y"), -+ /* strftime format for recent files (younger than 6 months), in -l -+ output. This should contain the month, day and time (at -+ least), in an order that is understood by people in your -+ locale's territory. Please try to keep the number of used -+ screen columns small, because many people work in windows with -+ only 80 columns. But make this as wide as the other string -+ above, for non-recent files. */ -+ /* TRANSLATORS: ls output needs to be aligned for ease of reading, -+ so be wary of using variable width fields from the locale. -+ Note %b is handled specially by ls and aligned correctly. -+ Note also that specifying a width as in %5b is erroneous as strftime -+ will count bytes rather than characters in multibyte locales. */ -+ N_("%b %e %H:%M") -+ }; -+ -+/* The set of signals that are caught. */ -+ -+static sigset_t caught_signals; -+ -+/* If nonzero, the value of the pending fatal signal. */ -+ -+static sig_atomic_t volatile interrupt_signal; -+ -+/* A count of the number of pending stop signals that have been received. */ -+ -+static sig_atomic_t volatile stop_signal_count; -+ -+/* Desired exit status. */ -+ -+static int exit_status; -+ -+/* Exit statuses. */ -+enum -+ { -+ /* "ls" had a minor problem. E.g., while processing a directory, -+ ls obtained the name of an entry via readdir, yet was later -+ unable to stat that name. This happens when listing a directory -+ in which entries are actively being removed or renamed. */ -+ LS_MINOR_PROBLEM = 1, -+ -+ /* "ls" had more serious trouble (e.g., memory exhausted, invalid -+ option or failure to stat a command line argument. */ -+ LS_FAILURE = 2 -+ }; -+ -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ AUTHOR_OPTION = CHAR_MAX + 1, -+ BLOCK_SIZE_OPTION, -+ COLOR_OPTION, -+ DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION, -+ FILE_TYPE_INDICATOR_OPTION, -+ FORMAT_OPTION, -+ FULL_TIME_OPTION, -+ GROUP_DIRECTORIES_FIRST_OPTION, -+ HIDE_OPTION, -+ INDICATOR_STYLE_OPTION, -+ QUOTING_STYLE_OPTION, -+ SHOW_CONTROL_CHARS_OPTION, -+ SI_OPTION, -+ SORT_OPTION, -+ TIME_OPTION, -+ TIME_STYLE_OPTION -+}; -+ -+static struct option const long_options[] = -+{ -+ {"all", no_argument, NULL, 'a'}, -+ {"escape", no_argument, NULL, 'b'}, -+ {"directory", no_argument, NULL, 'd'}, -+ {"dired", no_argument, NULL, 'D'}, -+ {"full-time", no_argument, NULL, FULL_TIME_OPTION}, -+ {"group-directories-first", no_argument, NULL, -+ GROUP_DIRECTORIES_FIRST_OPTION}, -+ {"human-readable", no_argument, NULL, 'h'}, -+ {"inode", no_argument, NULL, 'i'}, -+ {"numeric-uid-gid", no_argument, NULL, 'n'}, -+ {"no-group", no_argument, NULL, 'G'}, -+ {"hide-control-chars", no_argument, NULL, 'q'}, -+ {"reverse", no_argument, NULL, 'r'}, -+ {"size", no_argument, NULL, 's'}, -+ {"width", required_argument, NULL, 'w'}, -+ {"almost-all", no_argument, NULL, 'A'}, -+ {"ignore-backups", no_argument, NULL, 'B'}, -+ {"classify", no_argument, NULL, 'F'}, -+ {"file-type", no_argument, NULL, FILE_TYPE_INDICATOR_OPTION}, -+ {"si", no_argument, NULL, SI_OPTION}, -+ {"dereference-command-line", no_argument, NULL, 'H'}, -+ {"dereference-command-line-symlink-to-dir", no_argument, NULL, -+ DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION}, -+ {"hide", required_argument, NULL, HIDE_OPTION}, -+ {"ignore", required_argument, NULL, 'I'}, -+ {"indicator-style", required_argument, NULL, INDICATOR_STYLE_OPTION}, -+ {"dereference", no_argument, NULL, 'L'}, -+ {"literal", no_argument, NULL, 'N'}, -+ {"quote-name", no_argument, NULL, 'Q'}, -+ {"quoting-style", required_argument, NULL, QUOTING_STYLE_OPTION}, -+ {"recursive", no_argument, NULL, 'R'}, -+ {"format", required_argument, NULL, FORMAT_OPTION}, -+ {"show-control-chars", no_argument, NULL, SHOW_CONTROL_CHARS_OPTION}, -+ {"sort", required_argument, NULL, SORT_OPTION}, -+ {"tabsize", required_argument, NULL, 'T'}, -+ {"time", required_argument, NULL, TIME_OPTION}, -+ {"time-style", required_argument, NULL, TIME_STYLE_OPTION}, -+ {"color", optional_argument, NULL, COLOR_OPTION}, -+ {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, -+ {"context", no_argument, 0, 'Z'}, -+ {"author", no_argument, NULL, AUTHOR_OPTION}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+static char const *const format_args[] = -+{ -+ "verbose", "long", "commas", "horizontal", "across", -+ "vertical", "single-column", NULL -+}; -+static enum format const format_types[] = -+{ -+ long_format, long_format, with_commas, horizontal, horizontal, -+ many_per_line, one_per_line -+}; -+ARGMATCH_VERIFY (format_args, format_types); -+ -+static char const *const sort_args[] = -+{ -+ "none", "time", "size", "extension", "version", NULL -+}; -+static enum sort_type const sort_types[] = -+{ -+ sort_none, sort_time, sort_size, sort_extension, sort_version -+}; -+ARGMATCH_VERIFY (sort_args, sort_types); -+ -+static char const *const time_args[] = -+{ -+ "atime", "access", "use", "ctime", "status", NULL -+}; -+static enum time_type const time_types[] = -+{ -+ time_atime, time_atime, time_atime, time_ctime, time_ctime -+}; -+ARGMATCH_VERIFY (time_args, time_types); -+ -+static char const *const color_args[] = -+{ -+ /* force and none are for compatibility with another color-ls version */ -+ "always", "yes", "force", -+ "never", "no", "none", -+ "auto", "tty", "if-tty", NULL -+}; -+static enum color_type const color_types[] = -+{ -+ color_always, color_always, color_always, -+ color_never, color_never, color_never, -+ color_if_tty, color_if_tty, color_if_tty -+}; -+ARGMATCH_VERIFY (color_args, color_types); -+ -+/* Information about filling a column. */ -+struct column_info -+{ -+ bool valid_len; -+ size_t line_len; -+ size_t *col_arr; -+}; -+ -+/* Array with information about column filledness. */ -+static struct column_info *column_info; -+ -+/* Maximum number of columns ever possible for this display. */ -+static size_t max_idx; -+ -+/* The minimum width of a column is 3: 1 character for the name and 2 -+ for the separating white space. */ -+#define MIN_COLUMN_WIDTH 3 -+ -+ -+/* This zero-based index is used solely with the --dired option. -+ When that option is in effect, this counter is incremented for each -+ byte of output generated by this program so that the beginning -+ and ending indices (in that output) of every file name can be recorded -+ and later output themselves. */ -+static size_t dired_pos; -+ -+#define DIRED_PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0) -+ -+/* Write S to STREAM and increment DIRED_POS by S_LEN. */ -+#define DIRED_FPUTS(s, stream, s_len) \ -+ do {fputs (s, stream); dired_pos += s_len;} while (0) -+ -+/* Like DIRED_FPUTS, but for use when S is a literal string. */ -+#define DIRED_FPUTS_LITERAL(s, stream) \ -+ do {fputs (s, stream); dired_pos += sizeof (s) - 1;} while (0) -+ -+#define DIRED_INDENT() \ -+ do \ -+ { \ -+ if (dired) \ -+ DIRED_FPUTS_LITERAL (" ", stdout); \ -+ } \ -+ while (0) -+ -+/* With --dired, store pairs of beginning and ending indices of filenames. */ -+static struct obstack dired_obstack; -+ -+/* With --dired, store pairs of beginning and ending indices of any -+ directory names that appear as headers (just before `total' line) -+ for lists of directory entries. Such directory names are seen when -+ listing hierarchies using -R and when a directory is listed with at -+ least one other command line argument. */ -+static struct obstack subdired_obstack; -+ -+/* Save the current index on the specified obstack, OBS. */ -+#define PUSH_CURRENT_DIRED_POS(obs) \ -+ do \ -+ { \ -+ if (dired) \ -+ obstack_grow (obs, &dired_pos, sizeof (dired_pos)); \ -+ } \ -+ while (0) -+ -+/* With -R, this stack is used to help detect directory cycles. -+ The device/inode pairs on this stack mirror the pairs in the -+ active_dir_set hash table. */ -+static struct obstack dev_ino_obstack; -+ -+/* Push a pair onto the device/inode stack. */ -+#define DEV_INO_PUSH(Dev, Ino) \ -+ do \ -+ { \ -+ struct dev_ino *di; \ -+ obstack_blank (&dev_ino_obstack, sizeof (struct dev_ino)); \ -+ di = -1 + (struct dev_ino *) obstack_next_free (&dev_ino_obstack); \ -+ di->st_dev = (Dev); \ -+ di->st_ino = (Ino); \ -+ } \ -+ while (0) -+ -+/* Pop a dev/ino struct off the global dev_ino_obstack -+ and return that struct. */ -+static struct dev_ino -+dev_ino_pop (void) -+{ -+ assert (sizeof (struct dev_ino) <= obstack_object_size (&dev_ino_obstack)); -+ obstack_blank (&dev_ino_obstack, -(int) (sizeof (struct dev_ino))); -+ return *(struct dev_ino *) obstack_next_free (&dev_ino_obstack); -+} -+ -+/* Note the use commented out below: -+#define ASSERT_MATCHING_DEV_INO(Name, Di) \ -+ do \ -+ { \ -+ struct stat sb; \ -+ assert (Name); \ -+ assert (0 <= stat (Name, &sb)); \ -+ assert (sb.st_dev == Di.st_dev); \ -+ assert (sb.st_ino == Di.st_ino); \ -+ } \ -+ while (0) -+*/ -+ -+/* Write to standard output PREFIX, followed by the quoting style and -+ a space-separated list of the integers stored in OS all on one line. */ -+ -+static void -+dired_dump_obstack (const char *prefix, struct obstack *os) -+{ -+ size_t n_pos; -+ -+ n_pos = obstack_object_size (os) / sizeof (dired_pos); -+ if (n_pos > 0) -+ { -+ size_t i; -+ size_t *pos; -+ -+ pos = (size_t *) obstack_finish (os); -+ fputs (prefix, stdout); -+ for (i = 0; i < n_pos; i++) -+ printf (" %lu", (unsigned long int) pos[i]); -+ putchar ('\n'); -+ } -+} -+ -+/* Read the abbreviated month names from the locale, to align them -+ and to determine the max width of the field and to truncate names -+ greater than our max allowed. -+ Note even though this handles multibyte locales correctly -+ it's not restricted to them as single byte locales can have -+ variable width abbreviated months and also precomputing/caching -+ the names was seen to increase the performance of ls significantly. */ -+ -+/* max number of display cells to use */ -+enum { MAX_MON_WIDTH = 5 }; -+/* In the unlikely event that the abmon[] storage is not big enough -+ an error message will be displayed, and we revert to using -+ unmodified abbreviated month names from the locale database. */ -+static char abmon[12][MAX_MON_WIDTH * 2 * MB_LEN_MAX + 1]; -+/* minimum width needed to align %b, 0 => don't use precomputed values. */ -+static size_t required_mon_width; -+ -+static size_t -+abmon_init (void) -+{ -+#ifdef HAVE_NL_LANGINFO -+ required_mon_width = MAX_MON_WIDTH; -+ size_t curr_max_width; -+ do -+ { -+ curr_max_width = required_mon_width; -+ required_mon_width = 0; -+ for (int i = 0; i < 12; i++) -+ { -+ size_t width = curr_max_width; -+ -+ size_t req = mbsalign (nl_langinfo (ABMON_1 + i), -+ abmon[i], sizeof (abmon[i]), -+ &width, MBS_ALIGN_LEFT, 0); -+ -+ if (req == (size_t) -1 || req >= sizeof (abmon[i])) -+ { -+ required_mon_width = 0; /* ignore precomputed strings. */ -+ return required_mon_width; -+ } -+ -+ required_mon_width = MAX (required_mon_width, width); -+ } -+ } -+ while (curr_max_width > required_mon_width); -+#endif -+ -+ return required_mon_width; -+} -+ -+static size_t -+dev_ino_hash (void const *x, size_t table_size) -+{ -+ struct dev_ino const *p = x; -+ return (uintmax_t) p->st_ino % table_size; -+} -+ -+static bool -+dev_ino_compare (void const *x, void const *y) -+{ -+ struct dev_ino const *a = x; -+ struct dev_ino const *b = y; -+ return SAME_INODE (*a, *b) ? true : false; -+} -+ -+static void -+dev_ino_free (void *x) -+{ -+ free (x); -+} -+ -+/* Add the device/inode pair (P->st_dev/P->st_ino) to the set of -+ active directories. Return true if there is already a matching -+ entry in the table. */ -+ -+static bool -+visit_dir (dev_t dev, ino_t ino) -+{ -+ struct dev_ino *ent; -+ struct dev_ino *ent_from_table; -+ bool found_match; -+ -+ ent = xmalloc (sizeof *ent); -+ ent->st_ino = ino; -+ ent->st_dev = dev; -+ -+ /* Attempt to insert this entry into the table. */ -+ ent_from_table = hash_insert (active_dir_set, ent); -+ -+ if (ent_from_table == NULL) -+ { -+ /* Insertion failed due to lack of memory. */ -+ xalloc_die (); -+ } -+ -+ found_match = (ent_from_table != ent); -+ -+ if (found_match) -+ { -+ /* ent was not inserted, so free it. */ -+ free (ent); -+ } -+ -+ return found_match; -+} -+ -+static void -+free_pending_ent (struct pending *p) -+{ -+ free (p->name); -+ free (p->realname); -+ free (p); -+} -+ -+static bool -+is_colored (enum indicator_no type) -+{ -+ size_t len = color_indicator[type].len; -+ char const *s = color_indicator[type].string; -+ return ! (len == 0 -+ || (len == 1 && strncmp (s, "0", 1) == 0) -+ || (len == 2 && strncmp (s, "00", 2) == 0)); -+} -+ -+static void -+restore_default_color (void) -+{ -+ put_indicator (&color_indicator[C_LEFT]); -+ put_indicator (&color_indicator[C_RIGHT]); -+} -+ -+/* An ordinary signal was received; arrange for the program to exit. */ -+ -+static void -+sighandler (int sig) -+{ -+ if (! SA_NOCLDSTOP) -+ signal (sig, SIG_IGN); -+ if (! interrupt_signal) -+ interrupt_signal = sig; -+} -+ -+/* A SIGTSTP was received; arrange for the program to suspend itself. */ -+ -+static void -+stophandler (int sig) -+{ -+ if (! SA_NOCLDSTOP) -+ signal (sig, stophandler); -+ if (! interrupt_signal) -+ stop_signal_count++; -+} -+ -+/* Process any pending signals. If signals are caught, this function -+ should be called periodically. Ideally there should never be an -+ unbounded amount of time when signals are not being processed. -+ Signal handling can restore the default colors, so callers must -+ immediately change colors after invoking this function. */ -+ -+static void -+process_signals (void) -+{ -+ while (interrupt_signal || stop_signal_count) -+ { -+ int sig; -+ int stops; -+ sigset_t oldset; -+ -+ if (used_color) -+ restore_default_color (); -+ fflush (stdout); -+ -+ sigprocmask (SIG_BLOCK, &caught_signals, &oldset); -+ -+ /* Reload interrupt_signal and stop_signal_count, in case a new -+ signal was handled before sigprocmask took effect. */ -+ sig = interrupt_signal; -+ stops = stop_signal_count; -+ -+ /* SIGTSTP is special, since the application can receive that signal -+ more than once. In this case, don't set the signal handler to the -+ default. Instead, just raise the uncatchable SIGSTOP. */ -+ if (stops) -+ { -+ stop_signal_count = stops - 1; -+ sig = SIGSTOP; -+ } -+ else -+ signal (sig, SIG_DFL); -+ -+ /* Exit or suspend the program. */ -+ raise (sig); -+ sigprocmask (SIG_SETMASK, &oldset, NULL); -+ -+ /* If execution reaches here, then the program has been -+ continued (after being suspended). */ -+ } -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int i; -+ struct pending *thispend; -+ int n_files; -+ -+ /* The signals that are trapped, and the number of such signals. */ -+ static int const sig[] = -+ { -+ /* This one is handled specially. */ -+ SIGTSTP, -+ -+ /* The usual suspects. */ -+ SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM, -+#ifdef SIGPOLL -+ SIGPOLL, -+#endif -+#ifdef SIGPROF -+ SIGPROF, -+#endif -+#ifdef SIGVTALRM -+ SIGVTALRM, -+#endif -+#ifdef SIGXCPU -+ SIGXCPU, -+#endif -+#ifdef SIGXFSZ -+ SIGXFSZ, -+#endif -+ }; -+ enum { nsigs = ARRAY_CARDINALITY (sig) }; -+ -+#if ! SA_NOCLDSTOP -+ bool caught_sig[nsigs]; -+#endif -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ initialize_exit_failure (LS_FAILURE); -+ atexit (close_stdout); -+ -+ assert (ARRAY_CARDINALITY (color_indicator) + 1 -+ == ARRAY_CARDINALITY (indicator_name)); -+ -+ exit_status = EXIT_SUCCESS; -+ print_dir_name = true; -+ pending_dirs = NULL; -+ -+ current_time.tv_sec = TYPE_MINIMUM (time_t); -+ current_time.tv_nsec = -1; -+ -+ i = decode_switches (argc, argv); -+ -+ if (print_with_color) -+ parse_ls_color (); -+ -+ /* Test print_with_color again, because the call to parse_ls_color -+ may have just reset it -- e.g., if LS_COLORS is invalid. */ -+ if (print_with_color) -+ { -+ /* Avoid following symbolic links when possible. */ -+ if (is_colored (C_ORPHAN) -+ || (is_colored (C_EXEC) && color_symlink_as_referent) -+ || (is_colored (C_MISSING) && format == long_format)) -+ check_symlink_color = true; -+ -+ /* If the standard output is a controlling terminal, watch out -+ for signals, so that the colors can be restored to the -+ default state if "ls" is suspended or interrupted. */ -+ -+ if (0 <= tcgetpgrp (STDOUT_FILENO)) -+ { -+ int j; -+#if SA_NOCLDSTOP -+ struct sigaction act; -+ -+ sigemptyset (&caught_signals); -+ for (j = 0; j < nsigs; j++) -+ { -+ sigaction (sig[j], NULL, &act); -+ if (act.sa_handler != SIG_IGN) -+ sigaddset (&caught_signals, sig[j]); -+ } -+ -+ act.sa_mask = caught_signals; -+ act.sa_flags = SA_RESTART; -+ -+ for (j = 0; j < nsigs; j++) -+ if (sigismember (&caught_signals, sig[j])) -+ { -+ act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler; -+ sigaction (sig[j], &act, NULL); -+ } -+#else -+ for (j = 0; j < nsigs; j++) -+ { -+ caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN); -+ if (caught_sig[j]) -+ { -+ signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler); -+ siginterrupt (sig[j], 0); -+ } -+ } -+#endif -+ } -+ } -+ -+ if (dereference == DEREF_UNDEFINED) -+ dereference = ((immediate_dirs -+ || indicator_style == classify -+ || format == long_format) -+ ? DEREF_NEVER -+ : DEREF_COMMAND_LINE_SYMLINK_TO_DIR); -+ -+ /* When using -R, initialize a data structure we'll use to -+ detect any directory cycles. */ -+ if (recursive) -+ { -+ active_dir_set = hash_initialize (INITIAL_TABLE_SIZE, NULL, -+ dev_ino_hash, -+ dev_ino_compare, -+ dev_ino_free); -+ if (active_dir_set == NULL) -+ xalloc_die (); -+ -+ obstack_init (&dev_ino_obstack); -+ } -+ -+ format_needs_stat = sort_type == sort_time || sort_type == sort_size -+ || format == long_format -+ || print_scontext -+ || print_block_size; -+ format_needs_type = (! format_needs_stat -+ && (recursive -+ || print_with_color -+ || indicator_style != none -+ || directories_first)); -+ -+ if (dired) -+ { -+ obstack_init (&dired_obstack); -+ obstack_init (&subdired_obstack); -+ } -+ -+ cwd_n_alloc = 100; -+ cwd_file = xnmalloc (cwd_n_alloc, sizeof *cwd_file); -+ cwd_n_used = 0; -+ -+ clear_files (); -+ -+ n_files = argc - i; -+ -+ if (n_files <= 0) -+ { -+ if (immediate_dirs) -+ gobble_file (".", directory, NOT_AN_INODE_NUMBER, true, ""); -+ else -+ queue_directory (".", NULL, true); -+ } -+ else -+ do -+ gobble_file (argv[i++], unknown, NOT_AN_INODE_NUMBER, true, ""); -+ while (i < argc); -+ -+ if (cwd_n_used) -+ { -+ sort_files (); -+ if (!immediate_dirs) -+ extract_dirs_from_files (NULL, true); -+ /* `cwd_n_used' might be zero now. */ -+ } -+ -+ /* In the following if/else blocks, it is sufficient to test `pending_dirs' -+ (and not pending_dirs->name) because there may be no markers in the queue -+ at this point. A marker may be enqueued when extract_dirs_from_files is -+ called with a non-empty string or via print_dir. */ -+ if (cwd_n_used) -+ { -+ print_current_files (); -+ if (pending_dirs) -+ DIRED_PUTCHAR ('\n'); -+ } -+ else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0) -+ print_dir_name = false; -+ -+ while (pending_dirs) -+ { -+ thispend = pending_dirs; -+ pending_dirs = pending_dirs->next; -+ -+ if (LOOP_DETECT) -+ { -+ if (thispend->name == NULL) -+ { -+ /* thispend->name == NULL means this is a marker entry -+ indicating we've finished processing the directory. -+ Use its dev/ino numbers to remove the corresponding -+ entry from the active_dir_set hash table. */ -+ struct dev_ino di = dev_ino_pop (); -+ struct dev_ino *found = hash_delete (active_dir_set, &di); -+ /* ASSERT_MATCHING_DEV_INO (thispend->realname, di); */ -+ assert (found); -+ dev_ino_free (found); -+ free_pending_ent (thispend); -+ continue; -+ } -+ } -+ -+ print_dir (thispend->name, thispend->realname, -+ thispend->command_line_arg); -+ -+ free_pending_ent (thispend); -+ print_dir_name = true; -+ } -+ -+ if (print_with_color) -+ { -+ int j; -+ -+ if (used_color) -+ restore_default_color (); -+ fflush (stdout); -+ -+ /* Restore the default signal handling. */ -+#if SA_NOCLDSTOP -+ for (j = 0; j < nsigs; j++) -+ if (sigismember (&caught_signals, sig[j])) -+ signal (sig[j], SIG_DFL); -+#else -+ for (j = 0; j < nsigs; j++) -+ if (caught_sig[j]) -+ signal (sig[j], SIG_DFL); -+#endif -+ -+ /* Act on any signals that arrived before the default was restored. -+ This can process signals out of order, but there doesn't seem to -+ be an easy way to do them in order, and the order isn't that -+ important anyway. */ -+ for (j = stop_signal_count; j; j--) -+ raise (SIGSTOP); -+ j = interrupt_signal; -+ if (j) -+ raise (j); -+ } -+ -+ if (dired) -+ { -+ /* No need to free these since we're about to exit. */ -+ dired_dump_obstack ("//DIRED//", &dired_obstack); -+ dired_dump_obstack ("//SUBDIRED//", &subdired_obstack); -+ printf ("//DIRED-OPTIONS// --quoting-style=%s\n", -+ quoting_style_args[get_quoting_style (filename_quoting_options)]); -+ } -+ -+ if (LOOP_DETECT) -+ { -+ assert (hash_get_n_entries (active_dir_set) == 0); -+ hash_free (active_dir_set); -+ } -+ -+ exit (exit_status); -+} -+ -+/* Set all the option flags according to the switches specified. -+ Return the index of the first non-option argument. */ -+ -+static int -+decode_switches (int argc, char **argv) -+{ -+ char *time_style_option = NULL; -+ -+ /* Record whether there is an option specifying sort type. */ -+ bool sort_type_specified = false; -+ -+ qmark_funny_chars = false; -+ -+ /* initialize all switches to default settings */ -+ -+ switch (ls_mode) -+ { -+ case LS_MULTI_COL: -+ /* This is for the `dir' program. */ -+ format = many_per_line; -+ set_quoting_style (NULL, escape_quoting_style); -+ break; -+ -+ case LS_LONG_FORMAT: -+ /* This is for the `vdir' program. */ -+ format = long_format; -+ set_quoting_style (NULL, escape_quoting_style); -+ break; -+ -+ case LS_LS: -+ /* This is for the `ls' program. */ -+ if (isatty (STDOUT_FILENO)) -+ { -+ format = many_per_line; -+ /* See description of qmark_funny_chars, above. */ -+ qmark_funny_chars = true; -+ } -+ else -+ { -+ format = one_per_line; -+ qmark_funny_chars = false; -+ } -+ break; -+ -+ default: -+ abort (); -+ } -+ -+ time_type = time_mtime; -+ sort_type = sort_name; -+ sort_reverse = false; -+ numeric_ids = false; -+ print_block_size = false; -+ indicator_style = none; -+ print_inode = false; -+ dereference = DEREF_UNDEFINED; -+ recursive = false; -+ immediate_dirs = false; -+ ignore_mode = IGNORE_DEFAULT; -+ ignore_patterns = NULL; -+ hide_patterns = NULL; -+ print_scontext = false; -+ -+ /* FIXME: put this in a function. */ -+ { -+ char const *q_style = getenv ("QUOTING_STYLE"); -+ if (q_style) -+ { -+ int i = ARGMATCH (q_style, quoting_style_args, quoting_style_vals); -+ if (0 <= i) -+ set_quoting_style (NULL, quoting_style_vals[i]); -+ else -+ error (0, 0, -+ _("ignoring invalid value of environment variable QUOTING_STYLE: %s"), -+ quotearg (q_style)); -+ } -+ } -+ -+ { -+ char const *ls_block_size = getenv ("LS_BLOCK_SIZE"); -+ human_options (ls_block_size, -+ &human_output_opts, &output_block_size); -+ if (ls_block_size || getenv ("BLOCK_SIZE")) -+ file_output_block_size = output_block_size; -+ } -+ -+ line_length = 80; -+ { -+ char const *p = getenv ("COLUMNS"); -+ if (p && *p) -+ { -+ unsigned long int tmp_ulong; -+ if (xstrtoul (p, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK -+ && 0 < tmp_ulong && tmp_ulong <= SIZE_MAX) -+ { -+ line_length = tmp_ulong; -+ } -+ else -+ { -+ error (0, 0, -+ _("ignoring invalid width in environment variable COLUMNS: %s"), -+ quotearg (p)); -+ } -+ } -+ } -+ -+#ifdef TIOCGWINSZ -+ { -+ struct winsize ws; -+ -+ if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 -+ && 0 < ws.ws_col && ws.ws_col == (size_t) ws.ws_col) -+ line_length = ws.ws_col; -+ } -+#endif -+ -+ { -+ char const *p = getenv ("TABSIZE"); -+ tabsize = 8; -+ if (p) -+ { -+ unsigned long int tmp_ulong; -+ if (xstrtoul (p, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK -+ && tmp_ulong <= SIZE_MAX) -+ { -+ tabsize = tmp_ulong; -+ } -+ else -+ { -+ error (0, 0, -+ _("ignoring invalid tab size in environment variable TABSIZE: %s"), -+ quotearg (p)); -+ } -+ } -+ } -+ -+ for (;;) -+ { -+ int oi = -1; -+ int c = getopt_long (argc, argv, -+ "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1", -+ long_options, &oi); -+ if (c == -1) -+ break; -+ -+ switch (c) -+ { -+ case 'a': -+ ignore_mode = IGNORE_MINIMAL; -+ break; -+ -+ case 'b': -+ set_quoting_style (NULL, escape_quoting_style); -+ break; -+ -+ case 'c': -+ time_type = time_ctime; -+ break; -+ -+ case 'd': -+ immediate_dirs = true; -+ break; -+ -+ case 'f': -+ /* Same as enabling -a -U and disabling -l -s. */ -+ ignore_mode = IGNORE_MINIMAL; -+ sort_type = sort_none; -+ sort_type_specified = true; -+ /* disable -l */ -+ if (format == long_format) -+ format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line); -+ print_block_size = false; /* disable -s */ -+ print_with_color = false; /* disable --color */ -+ break; -+ -+ case FILE_TYPE_INDICATOR_OPTION: /* --file-type */ -+ indicator_style = file_type; -+ break; -+ -+ case 'g': -+ format = long_format; -+ print_owner = false; -+ break; -+ -+ case 'h': -+ human_output_opts = human_autoscale | human_SI | human_base_1024; -+ file_output_block_size = output_block_size = 1; -+ break; -+ -+ case 'i': -+ print_inode = true; -+ break; -+ -+ case 'k': -+ human_output_opts = 0; -+ file_output_block_size = output_block_size = 1024; -+ break; -+ -+ case 'l': -+ format = long_format; -+ break; -+ -+ case 'm': -+ format = with_commas; -+ break; -+ -+ case 'n': -+ numeric_ids = true; -+ format = long_format; -+ break; -+ -+ case 'o': /* Just like -l, but don't display group info. */ -+ format = long_format; -+ print_group = false; -+ break; -+ -+ case 'p': -+ indicator_style = slash; -+ break; -+ -+ case 'q': -+ qmark_funny_chars = true; -+ break; -+ -+ case 'r': -+ sort_reverse = true; -+ break; -+ -+ case 's': -+ print_block_size = true; -+ break; -+ -+ case 't': -+ sort_type = sort_time; -+ sort_type_specified = true; -+ break; -+ -+ case 'u': -+ time_type = time_atime; -+ break; -+ -+ case 'v': -+ sort_type = sort_version; -+ sort_type_specified = true; -+ break; -+ -+ case 'w': -+ { -+ unsigned long int tmp_ulong; -+ if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK -+ || ! (0 < tmp_ulong && tmp_ulong <= SIZE_MAX)) -+ error (LS_FAILURE, 0, _("invalid line width: %s"), -+ quotearg (optarg)); -+ line_length = tmp_ulong; -+ break; -+ } -+ -+ case 'x': -+ format = horizontal; -+ break; -+ -+ case 'A': -+ if (ignore_mode == IGNORE_DEFAULT) -+ ignore_mode = IGNORE_DOT_AND_DOTDOT; -+ break; -+ -+ case 'B': -+ add_ignore_pattern ("*~"); -+ add_ignore_pattern (".*~"); -+ break; -+ -+ case 'C': -+ format = many_per_line; -+ break; -+ -+ case 'D': -+ dired = true; -+ break; -+ -+ case 'F': -+ indicator_style = classify; -+ break; -+ -+ case 'G': /* inhibit display of group info */ -+ print_group = false; -+ break; -+ -+ case 'H': -+ dereference = DEREF_COMMAND_LINE_ARGUMENTS; -+ break; -+ -+ case DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION: -+ dereference = DEREF_COMMAND_LINE_SYMLINK_TO_DIR; -+ break; -+ -+ case 'I': -+ add_ignore_pattern (optarg); -+ break; -+ -+ case 'L': -+ dereference = DEREF_ALWAYS; -+ break; -+ -+ case 'N': -+ set_quoting_style (NULL, literal_quoting_style); -+ break; -+ -+ case 'Q': -+ set_quoting_style (NULL, c_quoting_style); -+ break; -+ -+ case 'R': -+ recursive = true; -+ break; -+ -+ case 'S': -+ sort_type = sort_size; -+ sort_type_specified = true; -+ break; -+ -+ case 'T': -+ { -+ unsigned long int tmp_ulong; -+ if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK -+ || SIZE_MAX < tmp_ulong) -+ error (LS_FAILURE, 0, _("invalid tab size: %s"), -+ quotearg (optarg)); -+ tabsize = tmp_ulong; -+ break; -+ } -+ -+ case 'U': -+ sort_type = sort_none; -+ sort_type_specified = true; -+ break; -+ -+ case 'X': -+ sort_type = sort_extension; -+ sort_type_specified = true; -+ break; -+ -+ case '1': -+ /* -1 has no effect after -l. */ -+ if (format != long_format) -+ format = one_per_line; -+ break; -+ -+ case AUTHOR_OPTION: -+ print_author = true; -+ break; -+ -+ case HIDE_OPTION: -+ { -+ struct ignore_pattern *hide = xmalloc (sizeof *hide); -+ hide->pattern = optarg; -+ hide->next = hide_patterns; -+ hide_patterns = hide; -+ } -+ break; -+ -+ case SORT_OPTION: -+ sort_type = XARGMATCH ("--sort", optarg, sort_args, sort_types); -+ sort_type_specified = true; -+ break; -+ -+ case GROUP_DIRECTORIES_FIRST_OPTION: -+ directories_first = true; -+ break; -+ -+ case TIME_OPTION: -+ time_type = XARGMATCH ("--time", optarg, time_args, time_types); -+ break; -+ -+ case FORMAT_OPTION: -+ format = XARGMATCH ("--format", optarg, format_args, format_types); -+ break; -+ -+ case FULL_TIME_OPTION: -+ format = long_format; -+ time_style_option = bad_cast ("full-iso"); -+ break; -+ -+ case COLOR_OPTION: -+ { -+ int i; -+ if (optarg) -+ i = XARGMATCH ("--color", optarg, color_args, color_types); -+ else -+ /* Using --color with no argument is equivalent to using -+ --color=always. */ -+ i = color_always; -+ -+ print_with_color = (i == color_always -+ || (i == color_if_tty -+ && isatty (STDOUT_FILENO))); -+ -+ if (print_with_color) -+ { -+ /* Don't use TAB characters in output. Some terminal -+ emulators can't handle the combination of tabs and -+ color codes on the same line. */ -+ tabsize = 0; -+ } -+ break; -+ } -+ -+ case INDICATOR_STYLE_OPTION: -+ indicator_style = XARGMATCH ("--indicator-style", optarg, -+ indicator_style_args, -+ indicator_style_types); -+ break; -+ -+ case QUOTING_STYLE_OPTION: -+ set_quoting_style (NULL, -+ XARGMATCH ("--quoting-style", optarg, -+ quoting_style_args, -+ quoting_style_vals)); -+ break; -+ -+ case TIME_STYLE_OPTION: -+ time_style_option = optarg; -+ break; -+ -+ case SHOW_CONTROL_CHARS_OPTION: -+ qmark_funny_chars = false; -+ break; -+ -+ case BLOCK_SIZE_OPTION: -+ { -+ enum strtol_error e = human_options (optarg, &human_output_opts, -+ &output_block_size); -+ if (e != LONGINT_OK) -+ xstrtol_fatal (e, oi, 0, long_options, optarg); -+ file_output_block_size = output_block_size; -+ } -+ break; -+ -+ case SI_OPTION: -+ human_output_opts = human_autoscale | human_SI; -+ file_output_block_size = output_block_size = 1; -+ break; -+ -+ case 'Z': -+ print_scontext = true; -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (LS_FAILURE); -+ } -+ } -+ -+ max_idx = MAX (1, line_length / MIN_COLUMN_WIDTH); -+ -+ filename_quoting_options = clone_quoting_options (NULL); -+ if (get_quoting_style (filename_quoting_options) == escape_quoting_style) -+ set_char_quoting (filename_quoting_options, ' ', 1); -+ if (file_type <= indicator_style) -+ { -+ char const *p; -+ for (p = "*=>@|" + indicator_style - file_type; *p; p++) -+ set_char_quoting (filename_quoting_options, *p, 1); -+ } -+ -+ dirname_quoting_options = clone_quoting_options (NULL); -+ set_char_quoting (dirname_quoting_options, ':', 1); -+ -+ /* --dired is meaningful only with --format=long (-l). -+ Otherwise, ignore it. FIXME: warn about this? -+ Alternatively, make --dired imply --format=long? */ -+ if (dired && format != long_format) -+ dired = false; -+ -+ /* If -c or -u is specified and not -l (or any other option that implies -l), -+ and no sort-type was specified, then sort by the ctime (-c) or atime (-u). -+ The behavior of ls when using either -c or -u but with neither -l nor -t -+ appears to be unspecified by POSIX. So, with GNU ls, `-u' alone means -+ sort by atime (this is the one that's not specified by the POSIX spec), -+ -lu means show atime and sort by name, -lut means show atime and sort -+ by atime. */ -+ -+ if ((time_type == time_ctime || time_type == time_atime) -+ && !sort_type_specified && format != long_format) -+ { -+ sort_type = sort_time; -+ } -+ -+ if (format == long_format) -+ { -+ char *style = time_style_option; -+ static char const posix_prefix[] = "posix-"; -+ -+ if (! style) -+ if (! (style = getenv ("TIME_STYLE"))) -+ style = bad_cast ("locale"); -+ -+ while (strncmp (style, posix_prefix, sizeof posix_prefix - 1) == 0) -+ { -+ if (! hard_locale (LC_TIME)) -+ return optind; -+ style += sizeof posix_prefix - 1; -+ } -+ -+ if (*style == '+') -+ { -+ char *p0 = style + 1; -+ char *p1 = strchr (p0, '\n'); -+ if (! p1) -+ p1 = p0; -+ else -+ { -+ if (strchr (p1 + 1, '\n')) -+ error (LS_FAILURE, 0, _("invalid time style format %s"), -+ quote (p0)); -+ *p1++ = '\0'; -+ } -+ long_time_format[0] = p0; -+ long_time_format[1] = p1; -+ } -+ else -+ switch (XARGMATCH ("time style", style, -+ time_style_args, -+ time_style_types)) -+ { -+ case full_iso_time_style: -+ long_time_format[0] = long_time_format[1] = -+ "%Y-%m-%d %H:%M:%S.%N %z"; -+ break; -+ -+ case long_iso_time_style: -+ case_long_iso_time_style: -+ long_time_format[0] = long_time_format[1] = "%Y-%m-%d %H:%M"; -+ break; -+ -+ case iso_time_style: -+ long_time_format[0] = "%Y-%m-%d "; -+ long_time_format[1] = "%m-%d %H:%M"; -+ break; -+ -+ case locale_time_style: -+ if (hard_locale (LC_TIME)) -+ { -+ /* Ensure that the locale has translations for both -+ formats. If not, fall back on long-iso format. */ -+ int i; -+ for (i = 0; i < 2; i++) -+ { -+ char const *locale_format = -+ dcgettext (NULL, long_time_format[i], LC_TIME); -+ if (locale_format == long_time_format[i]) -+ goto case_long_iso_time_style; -+ long_time_format[i] = locale_format; -+ } -+ } -+ } -+ /* Note we leave %5b etc. alone so user widths/flags are honored. */ -+ if (strstr (long_time_format[0],"%b") || strstr (long_time_format[1],"%b")) -+ if (!abmon_init ()) -+ error (0, 0, _("error initializing month strings")); -+ } -+ -+ return optind; -+} -+ -+/* Parse a string as part of the LS_COLORS variable; this may involve -+ decoding all kinds of escape characters. If equals_end is set an -+ unescaped equal sign ends the string, otherwise only a : or \0 -+ does. Set *OUTPUT_COUNT to the number of bytes output. Return -+ true if successful. -+ -+ The resulting string is *not* null-terminated, but may contain -+ embedded nulls. -+ -+ Note that both dest and src are char **; on return they point to -+ the first free byte after the array and the character that ended -+ the input string, respectively. */ -+ -+static bool -+get_funky_string (char **dest, const char **src, bool equals_end, -+ size_t *output_count) -+{ -+ char num; /* For numerical codes */ -+ size_t count; /* Something to count with */ -+ enum { -+ ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR -+ } state; -+ const char *p; -+ char *q; -+ -+ p = *src; /* We don't want to double-indirect */ -+ q = *dest; /* the whole darn time. */ -+ -+ count = 0; /* No characters counted in yet. */ -+ num = 0; -+ -+ state = ST_GND; /* Start in ground state. */ -+ while (state < ST_END) -+ { -+ switch (state) -+ { -+ case ST_GND: /* Ground state (no escapes) */ -+ switch (*p) -+ { -+ case ':': -+ case '\0': -+ state = ST_END; /* End of string */ -+ break; -+ case '\\': -+ state = ST_BACKSLASH; /* Backslash scape sequence */ -+ ++p; -+ break; -+ case '^': -+ state = ST_CARET; /* Caret escape */ -+ ++p; -+ break; -+ case '=': -+ if (equals_end) -+ { -+ state = ST_END; /* End */ -+ break; -+ } -+ /* else fall through */ -+ default: -+ *(q++) = *(p++); -+ ++count; -+ break; -+ } -+ break; -+ -+ case ST_BACKSLASH: /* Backslash escaped character */ -+ switch (*p) -+ { -+ case '0': -+ case '1': -+ case '2': -+ case '3': -+ case '4': -+ case '5': -+ case '6': -+ case '7': -+ state = ST_OCTAL; /* Octal sequence */ -+ num = *p - '0'; -+ break; -+ case 'x': -+ case 'X': -+ state = ST_HEX; /* Hex sequence */ -+ num = 0; -+ break; -+ case 'a': /* Bell */ -+ num = '\a'; -+ break; -+ case 'b': /* Backspace */ -+ num = '\b'; -+ break; -+ case 'e': /* Escape */ -+ num = 27; -+ break; -+ case 'f': /* Form feed */ -+ num = '\f'; -+ break; -+ case 'n': /* Newline */ -+ num = '\n'; -+ break; -+ case 'r': /* Carriage return */ -+ num = '\r'; -+ break; -+ case 't': /* Tab */ -+ num = '\t'; -+ break; -+ case 'v': /* Vtab */ -+ num = '\v'; -+ break; -+ case '?': /* Delete */ -+ num = 127; -+ break; -+ case '_': /* Space */ -+ num = ' '; -+ break; -+ case '\0': /* End of string */ -+ state = ST_ERROR; /* Error! */ -+ break; -+ default: /* Escaped character like \ ^ : = */ -+ num = *p; -+ break; -+ } -+ if (state == ST_BACKSLASH) -+ { -+ *(q++) = num; -+ ++count; -+ state = ST_GND; -+ } -+ ++p; -+ break; -+ -+ case ST_OCTAL: /* Octal sequence */ -+ if (*p < '0' || *p > '7') -+ { -+ *(q++) = num; -+ ++count; -+ state = ST_GND; -+ } -+ else -+ num = (num << 3) + (*(p++) - '0'); -+ break; -+ -+ case ST_HEX: /* Hex sequence */ -+ switch (*p) -+ { -+ case '0': -+ case '1': -+ case '2': -+ case '3': -+ case '4': -+ case '5': -+ case '6': -+ case '7': -+ case '8': -+ case '9': -+ num = (num << 4) + (*(p++) - '0'); -+ break; -+ case 'a': -+ case 'b': -+ case 'c': -+ case 'd': -+ case 'e': -+ case 'f': -+ num = (num << 4) + (*(p++) - 'a') + 10; -+ break; -+ case 'A': -+ case 'B': -+ case 'C': -+ case 'D': -+ case 'E': -+ case 'F': -+ num = (num << 4) + (*(p++) - 'A') + 10; -+ break; -+ default: -+ *(q++) = num; -+ ++count; -+ state = ST_GND; -+ break; -+ } -+ break; -+ -+ case ST_CARET: /* Caret escape */ -+ state = ST_GND; /* Should be the next state... */ -+ if (*p >= '@' && *p <= '~') -+ { -+ *(q++) = *(p++) & 037; -+ ++count; -+ } -+ else if (*p == '?') -+ { -+ *(q++) = 127; -+ ++count; -+ } -+ else -+ state = ST_ERROR; -+ break; -+ -+ default: -+ abort (); -+ } -+ } -+ -+ *dest = q; -+ *src = p; -+ *output_count = count; -+ -+ return state != ST_ERROR; -+} -+ -+static void -+parse_ls_color (void) -+{ -+ const char *p; /* Pointer to character being parsed */ -+ char *buf; /* color_buf buffer pointer */ -+ int state; /* State of parser */ -+ int ind_no; /* Indicator number */ -+ char label[3]; /* Indicator label */ -+ struct color_ext_type *ext; /* Extension we are working on */ -+ -+ if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0') -+ return; -+ -+ ext = NULL; -+ strcpy (label, "??"); -+ -+ /* This is an overly conservative estimate, but any possible -+ LS_COLORS string will *not* generate a color_buf longer than -+ itself, so it is a safe way of allocating a buffer in -+ advance. */ -+ buf = color_buf = xstrdup (p); -+ -+ state = 1; -+ while (state > 0) -+ { -+ switch (state) -+ { -+ case 1: /* First label character */ -+ switch (*p) -+ { -+ case ':': -+ ++p; -+ break; -+ -+ case '*': -+ /* Allocate new extension block and add to head of -+ linked list (this way a later definition will -+ override an earlier one, which can be useful for -+ having terminal-specific defs override global). */ -+ -+ ext = xmalloc (sizeof *ext); -+ ext->next = color_ext_list; -+ color_ext_list = ext; -+ -+ ++p; -+ ext->ext.string = buf; -+ -+ state = (get_funky_string (&buf, &p, true, &ext->ext.len) -+ ? 4 : -1); -+ break; -+ -+ case '\0': -+ state = 0; /* Done! */ -+ break; -+ -+ default: /* Assume it is file type label */ -+ label[0] = *(p++); -+ state = 2; -+ break; -+ } -+ break; -+ -+ case 2: /* Second label character */ -+ if (*p) -+ { -+ label[1] = *(p++); -+ state = 3; -+ } -+ else -+ state = -1; /* Error */ -+ break; -+ -+ case 3: /* Equal sign after indicator label */ -+ state = -1; /* Assume failure... */ -+ if (*(p++) == '=')/* It *should* be... */ -+ { -+ for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) -+ { -+ if (STREQ (label, indicator_name[ind_no])) -+ { -+ color_indicator[ind_no].string = buf; -+ state = (get_funky_string (&buf, &p, false, -+ &color_indicator[ind_no].len) -+ ? 1 : -1); -+ break; -+ } -+ } -+ if (state == -1) -+ error (0, 0, _("unrecognized prefix: %s"), quotearg (label)); -+ } -+ break; -+ -+ case 4: /* Equal sign after *.ext */ -+ if (*(p++) == '=') -+ { -+ ext->seq.string = buf; -+ state = (get_funky_string (&buf, &p, false, &ext->seq.len) -+ ? 1 : -1); -+ } -+ else -+ state = -1; -+ break; -+ } -+ } -+ -+ if (state < 0) -+ { -+ struct color_ext_type *e; -+ struct color_ext_type *e2; -+ -+ error (0, 0, -+ _("unparsable value for LS_COLORS environment variable")); -+ free (color_buf); -+ for (e = color_ext_list; e != NULL; /* empty */) -+ { -+ e2 = e; -+ e = e->next; -+ free (e2); -+ } -+ print_with_color = false; -+ } -+ -+ if (color_indicator[C_LINK].len == 6 -+ && !strncmp (color_indicator[C_LINK].string, "target", 6)) -+ color_symlink_as_referent = true; -+} -+ -+/* Set the exit status to report a failure. If SERIOUS, it is a -+ serious failure; otherwise, it is merely a minor problem. */ -+ -+static void -+set_exit_status (bool serious) -+{ -+ if (serious) -+ exit_status = LS_FAILURE; -+ else if (exit_status == EXIT_SUCCESS) -+ exit_status = LS_MINOR_PROBLEM; -+} -+ -+/* Assuming a failure is serious if SERIOUS, use the printf-style -+ MESSAGE to report the failure to access a file named FILE. Assume -+ errno is set appropriately for the failure. */ -+ -+static void -+file_failure (bool serious, char const *message, char const *file) -+{ -+ error (0, errno, message, quotearg_colon (file)); -+ set_exit_status (serious); -+} -+ -+/* Request that the directory named NAME have its contents listed later. -+ If REALNAME is nonzero, it will be used instead of NAME when the -+ directory name is printed. This allows symbolic links to directories -+ to be treated as regular directories but still be listed under their -+ real names. NAME == NULL is used to insert a marker entry for the -+ directory named in REALNAME. -+ If NAME is non-NULL, we use its dev/ino information to save -+ a call to stat -- when doing a recursive (-R) traversal. -+ COMMAND_LINE_ARG means this directory was mentioned on the command line. */ -+ -+static void -+queue_directory (char const *name, char const *realname, bool command_line_arg) -+{ -+ struct pending *new = xmalloc (sizeof *new); -+ new->realname = realname ? xstrdup (realname) : NULL; -+ new->name = name ? xstrdup (name) : NULL; -+ new->command_line_arg = command_line_arg; -+ new->next = pending_dirs; -+ pending_dirs = new; -+} -+ -+/* Read directory NAME, and list the files in it. -+ If REALNAME is nonzero, print its name instead of NAME; -+ this is used for symbolic links to directories. -+ COMMAND_LINE_ARG means this directory was mentioned on the command line. */ -+ -+static void -+print_dir (char const *name, char const *realname, bool command_line_arg) -+{ -+ DIR *dirp; -+ struct dirent *next; -+ uintmax_t total_blocks = 0; -+ static bool first = true; -+ -+ errno = 0; -+ dirp = opendir (name); -+ if (!dirp) -+ { -+ file_failure (command_line_arg, _("cannot open directory %s"), name); -+ return; -+ } -+ -+ if (LOOP_DETECT) -+ { -+ struct stat dir_stat; -+ int fd = dirfd (dirp); -+ -+ /* If dirfd failed, endure the overhead of using stat. */ -+ if ((0 <= fd -+ ? fstat (fd, &dir_stat) -+ : stat (name, &dir_stat)) < 0) -+ { -+ file_failure (command_line_arg, -+ _("cannot determine device and inode of %s"), name); -+ closedir (dirp); -+ return; -+ } -+ -+ /* If we've already visited this dev/inode pair, warn that -+ we've found a loop, and do not process this directory. */ -+ if (visit_dir (dir_stat.st_dev, dir_stat.st_ino)) -+ { -+ error (0, 0, _("%s: not listing already-listed directory"), -+ quotearg_colon (name)); -+ closedir (dirp); -+ set_exit_status (true); -+ return; -+ } -+ -+ DEV_INO_PUSH (dir_stat.st_dev, dir_stat.st_ino); -+ } -+ -+ if (recursive || print_dir_name) -+ { -+ if (!first) -+ DIRED_PUTCHAR ('\n'); -+ first = false; -+ DIRED_INDENT (); -+ PUSH_CURRENT_DIRED_POS (&subdired_obstack); -+ dired_pos += quote_name (stdout, realname ? realname : name, -+ dirname_quoting_options, NULL); -+ PUSH_CURRENT_DIRED_POS (&subdired_obstack); -+ DIRED_FPUTS_LITERAL (":\n", stdout); -+ } -+ -+ /* Read the directory entries, and insert the subfiles into the `cwd_file' -+ table. */ -+ -+ clear_files (); -+ -+ while (1) -+ { -+ /* Set errno to zero so we can distinguish between a readdir failure -+ and when readdir simply finds that there are no more entries. */ -+ errno = 0; -+ next = readdir (dirp); -+ if (next) -+ { -+ if (! file_ignored (next->d_name)) -+ { -+ enum filetype type = unknown; -+ -+#if HAVE_STRUCT_DIRENT_D_TYPE -+ switch (next->d_type) -+ { -+ case DT_BLK: type = blockdev; break; -+ case DT_CHR: type = chardev; break; -+ case DT_DIR: type = directory; break; -+ case DT_FIFO: type = fifo; break; -+ case DT_LNK: type = symbolic_link; break; -+ case DT_REG: type = normal; break; -+ case DT_SOCK: type = sock; break; -+# ifdef DT_WHT -+ case DT_WHT: type = whiteout; break; -+# endif -+ } -+#endif -+ total_blocks += gobble_file (next->d_name, type, -+ RELIABLE_D_INO (next), -+ false, name); -+ -+ /* In this narrow case, print out each name right away, so -+ ls uses constant memory while processing the entries of -+ this directory. Useful when there are many (millions) -+ of entries in a directory. */ -+ if (format == one_per_line && sort_type == sort_none -+ && !print_block_size && !recursive) -+ { -+ /* We must call sort_files in spite of -+ "sort_type == sort_none" for its initialization -+ of the sorted_file vector. */ -+ sort_files (); -+ print_current_files (); -+ clear_files (); -+ } -+ } -+ } -+ else if (errno != 0) -+ { -+ file_failure (command_line_arg, _("reading directory %s"), name); -+ if (errno != EOVERFLOW) -+ break; -+ } -+ else -+ break; -+ } -+ -+ if (closedir (dirp) != 0) -+ { -+ file_failure (command_line_arg, _("closing directory %s"), name); -+ /* Don't return; print whatever we got. */ -+ } -+ -+ /* Sort the directory contents. */ -+ sort_files (); -+ -+ /* If any member files are subdirectories, perhaps they should have their -+ contents listed rather than being mentioned here as files. */ -+ -+ if (recursive) -+ extract_dirs_from_files (name, command_line_arg); -+ -+ if (format == long_format || print_block_size) -+ { -+ const char *p; -+ char buf[LONGEST_HUMAN_READABLE + 1]; -+ -+ DIRED_INDENT (); -+ p = _("total"); -+ DIRED_FPUTS (p, stdout, strlen (p)); -+ DIRED_PUTCHAR (' '); -+ p = human_readable (total_blocks, buf, human_output_opts, -+ ST_NBLOCKSIZE, output_block_size); -+ DIRED_FPUTS (p, stdout, strlen (p)); -+ DIRED_PUTCHAR ('\n'); -+ } -+ -+ if (cwd_n_used) -+ print_current_files (); -+} -+ -+/* Add `pattern' to the list of patterns for which files that match are -+ not listed. */ -+ -+static void -+add_ignore_pattern (const char *pattern) -+{ -+ struct ignore_pattern *ignore; -+ -+ ignore = xmalloc (sizeof *ignore); -+ ignore->pattern = pattern; -+ /* Add it to the head of the linked list. */ -+ ignore->next = ignore_patterns; -+ ignore_patterns = ignore; -+} -+ -+/* Return true if one of the PATTERNS matches FILE. */ -+ -+static bool -+patterns_match (struct ignore_pattern const *patterns, char const *file) -+{ -+ struct ignore_pattern const *p; -+ for (p = patterns; p; p = p->next) -+ if (fnmatch (p->pattern, file, FNM_PERIOD) == 0) -+ return true; -+ return false; -+} -+ -+/* Return true if FILE should be ignored. */ -+ -+static bool -+file_ignored (char const *name) -+{ -+ return ((ignore_mode != IGNORE_MINIMAL -+ && name[0] == '.' -+ && (ignore_mode == IGNORE_DEFAULT || ! name[1 + (name[1] == '.')])) -+ || (ignore_mode == IGNORE_DEFAULT -+ && patterns_match (hide_patterns, name)) -+ || patterns_match (ignore_patterns, name)); -+} -+ -+/* POSIX requires that a file size be printed without a sign, even -+ when negative. Assume the typical case where negative sizes are -+ actually positive values that have wrapped around. */ -+ -+static uintmax_t -+unsigned_file_size (off_t size) -+{ -+ return size + (size < 0) * ((uintmax_t) OFF_T_MAX - OFF_T_MIN + 1); -+} -+ -+/* Enter and remove entries in the table `cwd_file'. */ -+ -+/* Empty the table of files. */ -+ -+static void -+clear_files (void) -+{ -+ size_t i; -+ -+ for (i = 0; i < cwd_n_used; i++) -+ { -+ struct fileinfo *f = sorted_file[i]; -+ free (f->name); -+ free (f->linkname); -+ if (f->scontext != UNKNOWN_SECURITY_CONTEXT) -+ freecon (f->scontext); -+ } -+ -+ cwd_n_used = 0; -+ any_has_acl = false; -+ inode_number_width = 0; -+ block_size_width = 0; -+ nlink_width = 0; -+ owner_width = 0; -+ group_width = 0; -+ author_width = 0; -+ scontext_width = 0; -+ major_device_number_width = 0; -+ minor_device_number_width = 0; -+ file_size_width = 0; -+} -+ -+/* Add a file to the current table of files. -+ Verify that the file exists, and print an error message if it does not. -+ Return the number of blocks that the file occupies. */ -+ -+static uintmax_t -+gobble_file (char const *name, enum filetype type, ino_t inode, -+ bool command_line_arg, char const *dirname) -+{ -+ uintmax_t blocks = 0; -+ struct fileinfo *f; -+ -+ /* An inode value prior to gobble_file necessarily came from readdir, -+ which is not used for command line arguments. */ -+ assert (! command_line_arg || inode == NOT_AN_INODE_NUMBER); -+ -+ if (cwd_n_used == cwd_n_alloc) -+ { -+ cwd_file = xnrealloc (cwd_file, cwd_n_alloc, 2 * sizeof *cwd_file); -+ cwd_n_alloc *= 2; -+ } -+ -+ f = &cwd_file[cwd_n_used]; -+ memset (f, '\0', sizeof *f); -+ f->stat.st_ino = inode; -+ f->filetype = type; -+ -+ if (command_line_arg -+ || format_needs_stat -+ /* When coloring a directory (we may know the type from -+ direct.d_type), we have to stat it in order to indicate -+ sticky and/or other-writable attributes. */ -+ || (type == directory && print_with_color) -+ /* When dereferencing symlinks, the inode and type must come from -+ stat, but readdir provides the inode and type of lstat. */ -+ || ((print_inode || format_needs_type) -+ && (type == symbolic_link || type == unknown) -+ && (dereference == DEREF_ALWAYS -+ || (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) -+ || (format_needs_type -+ && (type == unknown || command_line_arg -+ /* --indicator-style=classify (aka -F) -+ requires that we stat each regular file -+ to see if it's executable. */ -+ || (type == normal && (indicator_style == classify -+ /* This is so that --color ends up -+ highlighting files with the executable -+ bit set even when options like -F are -+ not specified. */ -+ || (print_with_color -+ && is_colored (C_EXEC)) -+ ))))) -+ -+ { -+ /* Absolute name of this file. */ -+ char *absolute_name; -+ bool do_deref; -+ int err; -+ -+ if (name[0] == '/' || dirname[0] == 0) -+ absolute_name = (char *) name; -+ else -+ { -+ absolute_name = alloca (strlen (name) + strlen (dirname) + 2); -+ attach (absolute_name, dirname, name); -+ } -+ -+ switch (dereference) -+ { -+ case DEREF_ALWAYS: -+ err = stat (absolute_name, &f->stat); -+ do_deref = true; -+ break; -+ -+ case DEREF_COMMAND_LINE_ARGUMENTS: -+ case DEREF_COMMAND_LINE_SYMLINK_TO_DIR: -+ if (command_line_arg) -+ { -+ bool need_lstat; -+ err = stat (absolute_name, &f->stat); -+ do_deref = true; -+ -+ if (dereference == DEREF_COMMAND_LINE_ARGUMENTS) -+ break; -+ -+ need_lstat = (err < 0 -+ ? errno == ENOENT -+ : ! S_ISDIR (f->stat.st_mode)); -+ if (!need_lstat) -+ break; -+ -+ /* stat failed because of ENOENT, maybe indicating a dangling -+ symlink. Or stat succeeded, ABSOLUTE_NAME does not refer to a -+ directory, and --dereference-command-line-symlink-to-dir is -+ in effect. Fall through so that we call lstat instead. */ -+ } -+ -+ default: /* DEREF_NEVER */ -+ err = lstat (absolute_name, &f->stat); -+ do_deref = false; -+ break; -+ } -+ -+ if (err != 0) -+ { -+ /* Failure to stat a command line argument leads to -+ an exit status of 2. For other files, stat failure -+ provokes an exit status of 1. */ -+ file_failure (command_line_arg, -+ _("cannot access %s"), absolute_name); -+ if (command_line_arg) -+ return 0; -+ -+ f->name = xstrdup (name); -+ cwd_n_used++; -+ -+ return 0; -+ } -+ -+ f->stat_ok = true; -+ -+ if (format == long_format || print_scontext) -+ { -+ bool have_selinux = false; -+ bool have_acl = false; -+ int attr_len = (do_deref -+ ? getfilecon (absolute_name, &f->scontext) -+ : lgetfilecon (absolute_name, &f->scontext)); -+ err = (attr_len < 0); -+ -+ /* Contrary to its documented API, getfilecon may return 0, -+ yet set f->scontext to NULL (on at least Debian's libselinux1 -+ 2.0.15-2+b1), so work around that bug. -+ FIXME: remove this work-around in 2011, or whenever affected -+ versions of libselinux are long gone. */ -+ if (attr_len == 0) -+ { -+ err = 0; -+ f->scontext = xstrdup ("unlabeled"); -+ } -+ -+ if (err == 0) -+ have_selinux = ! STREQ ("unlabeled", f->scontext); -+ else -+ { -+ f->scontext = UNKNOWN_SECURITY_CONTEXT; -+ -+ /* When requesting security context information, don't make -+ ls fail just because the file (even a command line argument) -+ isn't on the right type of file system. I.e., a getfilecon -+ failure isn't in the same class as a stat failure. */ -+ if (errno == ENOTSUP || errno == EOPNOTSUPP || errno == ENODATA) -+ err = 0; -+ } -+ -+ if (err == 0 && format == long_format) -+ { -+ int n = file_has_acl (absolute_name, &f->stat); -+ err = (n < 0); -+ have_acl = (0 < n); -+ } -+ -+ f->acl_type = (!have_selinux && !have_acl -+ ? ACL_T_NONE -+ : (have_selinux && !have_acl -+ ? ACL_T_SELINUX_ONLY -+ : ACL_T_YES)); -+ any_has_acl |= f->acl_type != ACL_T_NONE; -+ -+ if (err) -+ error (0, errno, "%s", quotearg_colon (absolute_name)); -+ } -+ -+ if (S_ISLNK (f->stat.st_mode) -+ && (format == long_format || check_symlink_color)) -+ { -+ char *linkname; -+ struct stat linkstats; -+ -+ get_link_name (absolute_name, f, command_line_arg); -+ linkname = make_link_name (absolute_name, f->linkname); -+ -+ /* Avoid following symbolic links when possible, ie, when -+ they won't be traced and when no indicator is needed. */ -+ if (linkname -+ && (file_type <= indicator_style || check_symlink_color) -+ && stat (linkname, &linkstats) == 0) -+ { -+ f->linkok = true; -+ -+ /* Symbolic links to directories that are mentioned on the -+ command line are automatically traced if not being -+ listed as files. */ -+ if (!command_line_arg || format == long_format -+ || !S_ISDIR (linkstats.st_mode)) -+ { -+ /* Get the linked-to file's mode for the filetype indicator -+ in long listings. */ -+ f->linkmode = linkstats.st_mode; -+ } -+ } -+ 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)) -+ { -+ if (command_line_arg && !immediate_dirs) -+ f->filetype = arg_directory; -+ else -+ f->filetype = directory; -+ } -+ else -+ f->filetype = normal; -+ -+ blocks = ST_NBLOCKS (f->stat); -+ if (format == long_format || print_block_size) -+ { -+ char buf[LONGEST_HUMAN_READABLE + 1]; -+ int len = mbswidth (human_readable (blocks, buf, human_output_opts, -+ ST_NBLOCKSIZE, output_block_size), -+ 0); -+ if (block_size_width < len) -+ block_size_width = len; -+ } -+ -+ if (format == long_format) -+ { -+ if (print_owner) -+ { -+ int len = format_user_width (f->stat.st_uid); -+ if (owner_width < len) -+ owner_width = len; -+ } -+ -+ if (print_group) -+ { -+ int len = format_group_width (f->stat.st_gid); -+ if (group_width < len) -+ group_width = len; -+ } -+ -+ if (print_author) -+ { -+ int len = format_user_width (f->stat.st_author); -+ if (author_width < len) -+ author_width = len; -+ } -+ } -+ -+ if (print_scontext) -+ { -+ int len = strlen (f->scontext); -+ if (scontext_width < len) -+ scontext_width = len; -+ } -+ -+ if (format == long_format) -+ { -+ char b[INT_BUFSIZE_BOUND (uintmax_t)]; -+ int b_len = strlen (umaxtostr (f->stat.st_nlink, b)); -+ if (nlink_width < b_len) -+ nlink_width = b_len; -+ -+ if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)) -+ { -+ char buf[INT_BUFSIZE_BOUND (uintmax_t)]; -+ int len = strlen (umaxtostr (major (f->stat.st_rdev), buf)); -+ if (major_device_number_width < len) -+ major_device_number_width = len; -+ len = strlen (umaxtostr (minor (f->stat.st_rdev), buf)); -+ if (minor_device_number_width < len) -+ minor_device_number_width = len; -+ len = major_device_number_width + 2 + minor_device_number_width; -+ if (file_size_width < len) -+ file_size_width = len; -+ } -+ else -+ { -+ char buf[LONGEST_HUMAN_READABLE + 1]; -+ uintmax_t size = unsigned_file_size (f->stat.st_size); -+ int len = mbswidth (human_readable (size, buf, human_output_opts, -+ 1, file_output_block_size), -+ 0); -+ if (file_size_width < len) -+ file_size_width = len; -+ } -+ } -+ } -+ -+ if (print_inode) -+ { -+ char buf[INT_BUFSIZE_BOUND (uintmax_t)]; -+ int len = strlen (umaxtostr (f->stat.st_ino, buf)); -+ if (inode_number_width < len) -+ inode_number_width = len; -+ } -+ -+ f->name = xstrdup (name); -+ cwd_n_used++; -+ -+ return blocks; -+} -+ -+/* Return true if F refers to a directory. */ -+static bool -+is_directory (const struct fileinfo *f) -+{ -+ return f->filetype == directory || f->filetype == arg_directory; -+} -+ -+/* Put the name of the file that FILENAME is a symbolic link to -+ into the LINKNAME field of `f'. COMMAND_LINE_ARG indicates whether -+ FILENAME is a command-line argument. */ -+ -+static void -+get_link_name (char const *filename, struct fileinfo *f, bool command_line_arg) -+{ -+ f->linkname = areadlink_with_size (filename, f->stat.st_size); -+ if (f->linkname == NULL) -+ file_failure (command_line_arg, _("cannot read symbolic link %s"), -+ filename); -+} -+ -+/* If `linkname' is a relative name and `name' contains one or more -+ leading directories, return `linkname' with those directories -+ prepended; otherwise, return a copy of `linkname'. -+ If `linkname' is zero, return zero. */ -+ -+static char * -+make_link_name (char const *name, char const *linkname) -+{ -+ char *linkbuf; -+ size_t bufsiz; -+ -+ if (!linkname) -+ return NULL; -+ -+ if (*linkname == '/') -+ return xstrdup (linkname); -+ -+ /* The link is to a relative name. Prepend any leading directory -+ in `name' to the link name. */ -+ linkbuf = strrchr (name, '/'); -+ if (linkbuf == 0) -+ return xstrdup (linkname); -+ -+ bufsiz = linkbuf - name + 1; -+ linkbuf = xmalloc (bufsiz + strlen (linkname) + 1); -+ strncpy (linkbuf, name, bufsiz); -+ strcpy (linkbuf + bufsiz, linkname); -+ return linkbuf; -+} -+ -+/* Return true if the last component of NAME is `.' or `..' -+ This is so we don't try to recurse on `././././. ...' */ -+ -+static bool -+basename_is_dot_or_dotdot (const char *name) -+{ -+ char const *base = last_component (name); -+ return dot_or_dotdot (base); -+} -+ -+/* Remove any entries from CWD_FILE that are for directories, -+ and queue them to be listed as directories instead. -+ DIRNAME is the prefix to prepend to each dirname -+ to make it correct relative to ls's working dir; -+ if it is null, no prefix is needed and "." and ".." should not be ignored. -+ If COMMAND_LINE_ARG is true, this directory was mentioned at the top level, -+ This is desirable when processing directories recursively. */ -+ -+static void -+extract_dirs_from_files (char const *dirname, bool command_line_arg) -+{ -+ size_t i; -+ size_t j; -+ bool ignore_dot_and_dot_dot = (dirname != NULL); -+ -+ if (dirname && LOOP_DETECT) -+ { -+ /* Insert a marker entry first. When we dequeue this marker entry, -+ we'll know that DIRNAME has been processed and may be removed -+ from the set of active directories. */ -+ queue_directory (NULL, dirname, false); -+ } -+ -+ /* Queue the directories last one first, because queueing reverses the -+ order. */ -+ for (i = cwd_n_used; i-- != 0; ) -+ { -+ struct fileinfo *f = sorted_file[i]; -+ -+ if (is_directory (f) -+ && (! ignore_dot_and_dot_dot -+ || ! basename_is_dot_or_dotdot (f->name))) -+ { -+ if (!dirname || f->name[0] == '/') -+ queue_directory (f->name, f->linkname, command_line_arg); -+ else -+ { -+ char *name = file_name_concat (dirname, f->name, NULL); -+ queue_directory (name, f->linkname, command_line_arg); -+ free (name); -+ } -+ if (f->filetype == arg_directory) -+ free (f->name); -+ } -+ } -+ -+ /* Now delete the directories from the table, compacting all the remaining -+ entries. */ -+ -+ for (i = 0, j = 0; i < cwd_n_used; i++) -+ { -+ struct fileinfo *f = sorted_file[i]; -+ sorted_file[j] = f; -+ j += (f->filetype != arg_directory); -+ } -+ cwd_n_used = j; -+} -+ -+/* Use strcoll to compare strings in this locale. If an error occurs, -+ report an error and longjmp to failed_strcoll. */ -+ -+static jmp_buf failed_strcoll; -+ -+static int -+xstrcoll (char const *a, char const *b) -+{ -+ int diff; -+ errno = 0; -+ diff = strcoll (a, b); -+ if (errno) -+ { -+ error (0, errno, _("cannot compare file names %s and %s"), -+ quote_n (0, a), quote_n (1, b)); -+ set_exit_status (false); -+ longjmp (failed_strcoll, 1); -+ } -+ return diff; -+} -+ -+/* Comparison routines for sorting the files. */ -+ -+typedef void const *V; -+typedef int (*qsortFunc)(V a, V b); -+ -+/* Used below in DEFINE_SORT_FUNCTIONS for _df_ sort function variants. -+ The do { ... } while(0) makes it possible to use the macro more like -+ a statement, without violating C89 rules: */ -+#define DIRFIRST_CHECK(a, b) \ -+ do \ -+ { \ -+ bool a_is_dir = is_directory ((struct fileinfo const *) a); \ -+ bool b_is_dir = is_directory ((struct fileinfo const *) b); \ -+ if (a_is_dir && !b_is_dir) \ -+ return -1; /* a goes before b */ \ -+ if (!a_is_dir && b_is_dir) \ -+ return 1; /* b goes before a */ \ -+ } \ -+ while (0) -+ -+/* Define the 8 different sort function variants required for each sortkey. -+ KEY_NAME is a token describing the sort key, e.g., ctime, atime, size. -+ KEY_CMP_FUNC is a function to compare records based on that key, e.g., -+ ctime_cmp, atime_cmp, size_cmp. Append KEY_NAME to the string, -+ '[rev_][x]str{cmp|coll}[_df]_', to create each function name. */ -+#define DEFINE_SORT_FUNCTIONS(key_name, key_cmp_func) \ -+ /* direct, non-dirfirst versions */ \ -+ static int xstrcoll_##key_name (V a, V b) \ -+ { return key_cmp_func (a, b, xstrcoll); } \ -+ static int strcmp_##key_name (V a, V b) \ -+ { return key_cmp_func (a, b, strcmp); } \ -+ \ -+ /* reverse, non-dirfirst versions */ \ -+ static int rev_xstrcoll_##key_name (V a, V b) \ -+ { return key_cmp_func (b, a, xstrcoll); } \ -+ static int rev_strcmp_##key_name (V a, V b) \ -+ { return key_cmp_func (b, a, strcmp); } \ -+ \ -+ /* direct, dirfirst versions */ \ -+ static int xstrcoll_df_##key_name (V a, V b) \ -+ { DIRFIRST_CHECK (a, b); return key_cmp_func (a, b, xstrcoll); } \ -+ static int strcmp_df_##key_name (V a, V b) \ -+ { DIRFIRST_CHECK (a, b); return key_cmp_func (a, b, strcmp); } \ -+ \ -+ /* reverse, dirfirst versions */ \ -+ static int rev_xstrcoll_df_##key_name (V a, V b) \ -+ { DIRFIRST_CHECK (a, b); return key_cmp_func (b, a, xstrcoll); } \ -+ static int rev_strcmp_df_##key_name (V a, V b) \ -+ { DIRFIRST_CHECK (a, b); return key_cmp_func (b, a, strcmp); } -+ -+static inline int -+cmp_ctime (struct fileinfo const *a, struct fileinfo const *b, -+ int (*cmp) (char const *, char const *)) -+{ -+ int diff = timespec_cmp (get_stat_ctime (&b->stat), -+ get_stat_ctime (&a->stat)); -+ return diff ? diff : cmp (a->name, b->name); -+} -+ -+static inline int -+cmp_mtime (struct fileinfo const *a, struct fileinfo const *b, -+ int (*cmp) (char const *, char const *)) -+{ -+ int diff = timespec_cmp (get_stat_mtime (&b->stat), -+ get_stat_mtime (&a->stat)); -+ return diff ? diff : cmp (a->name, b->name); -+} -+ -+static inline int -+cmp_atime (struct fileinfo const *a, struct fileinfo const *b, -+ int (*cmp) (char const *, char const *)) -+{ -+ int diff = timespec_cmp (get_stat_atime (&b->stat), -+ get_stat_atime (&a->stat)); -+ return diff ? diff : cmp (a->name, b->name); -+} -+ -+static inline int -+cmp_size (struct fileinfo const *a, struct fileinfo const *b, -+ int (*cmp) (char const *, char const *)) -+{ -+ int diff = longdiff (b->stat.st_size, a->stat.st_size); -+ return diff ? diff : cmp (a->name, b->name); -+} -+ -+static inline int -+cmp_name (struct fileinfo const *a, struct fileinfo const *b, -+ int (*cmp) (char const *, char const *)) -+{ -+ return cmp (a->name, b->name); -+} -+ -+/* Compare file extensions. Files with no extension are `smallest'. -+ If extensions are the same, compare by filenames instead. */ -+ -+static inline int -+cmp_extension (struct fileinfo const *a, struct fileinfo const *b, -+ int (*cmp) (char const *, char const *)) -+{ -+ char const *base1 = strrchr (a->name, '.'); -+ char const *base2 = strrchr (b->name, '.'); -+ int diff = cmp (base1 ? base1 : "", base2 ? base2 : ""); -+ return diff ? diff : cmp (a->name, b->name); -+} -+ -+DEFINE_SORT_FUNCTIONS (ctime, cmp_ctime) -+DEFINE_SORT_FUNCTIONS (mtime, cmp_mtime) -+DEFINE_SORT_FUNCTIONS (atime, cmp_atime) -+DEFINE_SORT_FUNCTIONS (size, cmp_size) -+DEFINE_SORT_FUNCTIONS (name, cmp_name) -+DEFINE_SORT_FUNCTIONS (extension, cmp_extension) -+ -+/* Compare file versions. -+ Unlike all other compare functions above, cmp_version depends only -+ on filevercmp, which does not fail (even for locale reasons), and does not -+ need a secondary sort key. See lib/filevercmp.h for function description. -+ -+ All the other sort options, in fact, need xstrcoll and strcmp variants, -+ because they all use a string comparison (either as the primary or secondary -+ sort key), and xstrcoll has the ability to do a longjmp if strcoll fails for -+ locale reasons. Last, strverscmp is ALWAYS available in coreutils, -+ thanks to the gnulib library. */ -+static inline int -+cmp_version (struct fileinfo const *a, struct fileinfo const *b) -+{ -+ return filevercmp (a->name, b->name); -+} -+ -+static int xstrcoll_version (V a, V b) -+{ return cmp_version (a, b); } -+static int rev_xstrcoll_version (V a, V b) -+{ return cmp_version (b, a); } -+static int xstrcoll_df_version (V a, V b) -+{ DIRFIRST_CHECK (a, b); return cmp_version (a, b); } -+static int rev_xstrcoll_df_version (V a, V b) -+{ DIRFIRST_CHECK (a, b); return cmp_version (b, a); } -+ -+ -+/* We have 2^3 different variants for each sortkey function -+ (for 3 independent sort modes). -+ The function pointers stored in this array must be dereferenced as: -+ -+ sort_variants[sort_key][use_strcmp][reverse][dirs_first] -+ -+ Note that the order in which sortkeys are listed in the function pointer -+ array below is defined by the order of the elements in the time_type and -+ sort_type enums! */ -+ -+#define LIST_SORTFUNCTION_VARIANTS(key_name) \ -+ { \ -+ { \ -+ { xstrcoll_##key_name, xstrcoll_df_##key_name }, \ -+ { rev_xstrcoll_##key_name, rev_xstrcoll_df_##key_name }, \ -+ }, \ -+ { \ -+ { strcmp_##key_name, strcmp_df_##key_name }, \ -+ { rev_strcmp_##key_name, rev_strcmp_df_##key_name }, \ -+ } \ -+ } -+ -+static qsortFunc const sort_functions[][2][2][2] = -+ { -+ LIST_SORTFUNCTION_VARIANTS (name), -+ LIST_SORTFUNCTION_VARIANTS (extension), -+ LIST_SORTFUNCTION_VARIANTS (size), -+ -+ { -+ { -+ { xstrcoll_version, xstrcoll_df_version }, -+ { rev_xstrcoll_version, rev_xstrcoll_df_version }, -+ }, -+ -+ /* We use NULL for the strcmp variants of version comparison -+ since as explained in cmp_version definition, version comparison -+ does not rely on xstrcoll, so it will never longjmp, and never -+ need to try the strcmp fallback. */ -+ { -+ { NULL, NULL }, -+ { NULL, NULL }, -+ } -+ }, -+ -+ /* last are time sort functions */ -+ LIST_SORTFUNCTION_VARIANTS (mtime), -+ LIST_SORTFUNCTION_VARIANTS (ctime), -+ LIST_SORTFUNCTION_VARIANTS (atime) -+ }; -+ -+/* The number of sortkeys is calculated as -+ the number of elements in the sort_type enum (i.e. sort_numtypes) + -+ the number of elements in the time_type enum (i.e. time_numtypes) - 1 -+ This is because when sort_type==sort_time, we have up to -+ time_numtypes possible sortkeys. -+ -+ This line verifies at compile-time that the array of sort functions has been -+ initialized for all possible sortkeys. */ -+verify (ARRAY_CARDINALITY (sort_functions) -+ == sort_numtypes + time_numtypes - 1 ); -+ -+/* Set up SORTED_FILE to point to the in-use entries in CWD_FILE, in order. */ -+ -+static void -+initialize_ordering_vector (void) -+{ -+ size_t i; -+ for (i = 0; i < cwd_n_used; i++) -+ sorted_file[i] = &cwd_file[i]; -+} -+ -+/* Sort the files now in the table. */ -+ -+static void -+sort_files (void) -+{ -+ bool use_strcmp; -+ -+ if (sorted_file_alloc < cwd_n_used + cwd_n_used / 2) -+ { -+ free (sorted_file); -+ sorted_file = xnmalloc (cwd_n_used, 3 * sizeof *sorted_file); -+ sorted_file_alloc = 3 * cwd_n_used; -+ } -+ -+ initialize_ordering_vector (); -+ -+ if (sort_type == sort_none) -+ return; -+ -+ /* Try strcoll. If it fails, fall back on strcmp. We can't safely -+ ignore strcoll failures, as a failing strcoll might be a -+ comparison function that is not a total order, and if we ignored -+ the failure this might cause qsort to dump core. */ -+ -+ if (! setjmp (failed_strcoll)) -+ use_strcmp = false; /* strcoll() succeeded */ -+ else -+ { -+ use_strcmp = true; -+ assert (sort_type != sort_version); -+ initialize_ordering_vector (); -+ } -+ -+ /* When sort_type == sort_time, use time_type as subindex. */ -+ mpsort ((void const **) sorted_file, cwd_n_used, -+ sort_functions[sort_type + (sort_type == sort_time ? time_type : 0)] -+ [use_strcmp][sort_reverse] -+ [directories_first]); -+} -+ -+/* List all the files now in the table. */ -+ -+static void -+print_current_files (void) -+{ -+ size_t i; -+ -+ switch (format) -+ { -+ case one_per_line: -+ for (i = 0; i < cwd_n_used; i++) -+ { -+ print_file_name_and_frills (sorted_file[i], 0); -+ putchar ('\n'); -+ } -+ break; -+ -+ case many_per_line: -+ print_many_per_line (); -+ break; -+ -+ case horizontal: -+ print_horizontal (); -+ break; -+ -+ case with_commas: -+ print_with_commas (); -+ break; -+ -+ case long_format: -+ for (i = 0; i < cwd_n_used; i++) -+ { -+ print_long_format (sorted_file[i]); -+ DIRED_PUTCHAR ('\n'); -+ } -+ break; -+ } -+} -+ -+/* Replace the first %b with precomputed aligned month names. -+ Note on glibc-2.7 at least, this speeds up the whole `ls -lU` -+ process by around 17%, compared to letting strftime() handle the %b. */ -+ -+static size_t -+align_nstrftime (char *buf, size_t size, char const *fmt, struct tm const *tm, -+ int __utc, int __ns) -+{ -+ const char *nfmt = fmt; -+ /* In the unlikely event that rpl_fmt below is not large enough, -+ the replacement is not done. A malloc here slows ls down by 2% */ -+ char rpl_fmt[sizeof (abmon[0]) + 100]; -+ const char *pb; -+ if (required_mon_width && (pb = strstr (fmt, "%b"))) -+ { -+ if (strlen (fmt) < (sizeof (rpl_fmt) - sizeof (abmon[0]) + 2)) -+ { -+ char *pfmt = rpl_fmt; -+ nfmt = rpl_fmt; -+ -+ pfmt = mempcpy (pfmt, fmt, pb - fmt); -+ pfmt = stpcpy (pfmt, abmon[tm->tm_mon]); -+ strcpy (pfmt, pb + 2); -+ } -+ } -+ size_t ret = nstrftime (buf, size, nfmt, tm, __utc, __ns); -+ return ret; -+} -+ -+/* Return the expected number of columns in a long-format time stamp, -+ or zero if it cannot be calculated. */ -+ -+static int -+long_time_expected_width (void) -+{ -+ static int width = -1; -+ -+ if (width < 0) -+ { -+ time_t epoch = 0; -+ struct tm const *tm = localtime (&epoch); -+ char buf[TIME_STAMP_LEN_MAXIMUM + 1]; -+ -+ /* In case you're wondering if localtime can fail with an input time_t -+ value of 0, let's just say it's very unlikely, but not inconceivable. -+ The TZ environment variable would have to specify a time zone that -+ is 2**31-1900 years or more ahead of UTC. This could happen only on -+ a 64-bit system that blindly accepts e.g., TZ=UTC+20000000000000. -+ However, this is not possible with Solaris 10 or glibc-2.3.5, since -+ their implementations limit the offset to 167:59 and 24:00, resp. */ -+ if (tm) -+ { -+ size_t len = -+ align_nstrftime (buf, sizeof buf, long_time_format[0], tm, 0, 0); -+ if (len != 0) -+ width = mbsnwidth (buf, len, 0); -+ } -+ -+ if (width < 0) -+ width = 0; -+ } -+ -+ return width; -+} -+ -+/* Print the user or group name NAME, with numeric id ID, using a -+ print width of WIDTH columns. */ -+ -+static void -+format_user_or_group (char const *name, unsigned long int id, int width) -+{ -+ size_t len; -+ -+ if (name) -+ { -+ int width_gap = width - mbswidth (name, 0); -+ int pad = MAX (0, width_gap); -+ fputs (name, stdout); -+ len = strlen (name) + pad; -+ -+ do -+ putchar (' '); -+ while (pad--); -+ } -+ else -+ { -+ printf ("%*lu ", width, id); -+ len = width; -+ } -+ -+ dired_pos += len + 1; -+} -+ -+/* Print the name or id of the user with id U, using a print width of -+ WIDTH. */ -+ -+static void -+format_user (uid_t u, int width, bool stat_ok) -+{ -+ format_user_or_group (! stat_ok ? "?" : -+ (numeric_ids ? NULL : getuser (u)), u, width); -+} -+ -+/* Likewise, for groups. */ -+ -+static void -+format_group (gid_t g, int width, bool stat_ok) -+{ -+ format_user_or_group (! stat_ok ? "?" : -+ (numeric_ids ? NULL : getgroup (g)), g, width); -+} -+ -+/* Return the number of columns that format_user_or_group will print. */ -+ -+static int -+format_user_or_group_width (char const *name, unsigned long int id) -+{ -+ if (name) -+ { -+ int len = mbswidth (name, 0); -+ return MAX (0, len); -+ } -+ else -+ { -+ char buf[INT_BUFSIZE_BOUND (unsigned long int)]; -+ sprintf (buf, "%lu", id); -+ return strlen (buf); -+ } -+} -+ -+/* Return the number of columns that format_user will print. */ -+ -+static int -+format_user_width (uid_t u) -+{ -+ return format_user_or_group_width (numeric_ids ? NULL : getuser (u), u); -+} -+ -+/* Likewise, for groups. */ -+ -+static int -+format_group_width (gid_t g) -+{ -+ return format_user_or_group_width (numeric_ids ? NULL : getgroup (g), g); -+} -+ -+/* Return a pointer to a formatted version of F->stat.st_ino, -+ possibly using buffer, BUF, of length BUFLEN, which must be at least -+ INT_BUFSIZE_BOUND (uintmax_t) bytes. */ -+static char * -+format_inode (char *buf, size_t buflen, const struct fileinfo *f) -+{ -+ assert (INT_BUFSIZE_BOUND (uintmax_t) <= buflen); -+ return (f->stat_ok && f->stat.st_ino != NOT_AN_INODE_NUMBER -+ ? umaxtostr (f->stat.st_ino, buf) -+ : (char *) "?"); -+} -+ -+/* Print information about F in long format. */ -+static void -+print_long_format (const struct fileinfo *f) -+{ -+ char modebuf[12]; -+ char buf -+ [LONGEST_HUMAN_READABLE + 1 /* inode */ -+ + LONGEST_HUMAN_READABLE + 1 /* size in blocks */ -+ + sizeof (modebuf) - 1 + 1 /* mode string */ -+ + INT_BUFSIZE_BOUND (uintmax_t) /* st_nlink */ -+ + LONGEST_HUMAN_READABLE + 2 /* major device number */ -+ + LONGEST_HUMAN_READABLE + 1 /* minor device number */ -+ + TIME_STAMP_LEN_MAXIMUM + 1 /* max length of time/date */ -+ ]; -+ size_t s; -+ char *p; -+ struct timespec when_timespec; -+ struct tm *when_local; -+ -+ /* Compute the mode string, except remove the trailing space if no -+ file in this directory has an ACL or SELinux security context. */ -+ if (f->stat_ok) -+ filemodestring (&f->stat, modebuf); -+ else -+ { -+ modebuf[0] = filetype_letter[f->filetype]; -+ memset (modebuf + 1, '?', 10); -+ modebuf[11] = '\0'; -+ } -+ if (! any_has_acl) -+ modebuf[10] = '\0'; -+ else if (f->acl_type == ACL_T_SELINUX_ONLY) -+ modebuf[10] = '.'; -+ else if (f->acl_type == ACL_T_YES) -+ modebuf[10] = '+'; -+ -+ switch (time_type) -+ { -+ case time_ctime: -+ when_timespec = get_stat_ctime (&f->stat); -+ break; -+ case time_mtime: -+ when_timespec = get_stat_mtime (&f->stat); -+ break; -+ case time_atime: -+ when_timespec = get_stat_atime (&f->stat); -+ break; -+ default: -+ abort (); -+ } -+ -+ p = buf; -+ -+ if (print_inode) -+ { -+ char hbuf[INT_BUFSIZE_BOUND (uintmax_t)]; -+ sprintf (p, "%*s ", inode_number_width, -+ format_inode (hbuf, sizeof hbuf, f)); -+ /* Increment by strlen (p) here, rather than by inode_number_width + 1. -+ The latter is wrong when inode_number_width is zero. */ -+ p += strlen (p); -+ } -+ -+ if (print_block_size) -+ { -+ char hbuf[LONGEST_HUMAN_READABLE + 1]; -+ char const *blocks = -+ (! f->stat_ok -+ ? "?" -+ : human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts, -+ ST_NBLOCKSIZE, output_block_size)); -+ int pad; -+ for (pad = block_size_width - mbswidth (blocks, 0); 0 < pad; pad--) -+ *p++ = ' '; -+ while ((*p++ = *blocks++)) -+ continue; -+ p[-1] = ' '; -+ } -+ -+ /* The last byte of the mode string is the POSIX -+ "optional alternate access method flag". */ -+ { -+ char hbuf[INT_BUFSIZE_BOUND (uintmax_t)]; -+ sprintf (p, "%s %*s ", modebuf, nlink_width, -+ ! f->stat_ok ? "?" : umaxtostr (f->stat.st_nlink, hbuf)); -+ } -+ /* Increment by strlen (p) here, rather than by, e.g., -+ sizeof modebuf - 2 + any_has_acl + 1 + nlink_width + 1. -+ The latter is wrong when nlink_width is zero. */ -+ p += strlen (p); -+ -+ DIRED_INDENT (); -+ -+ if (print_owner || print_group || print_author || print_scontext) -+ { -+ DIRED_FPUTS (buf, stdout, p - buf); -+ -+ if (print_owner) -+ format_user (f->stat.st_uid, owner_width, f->stat_ok); -+ -+ if (print_group) -+ format_group (f->stat.st_gid, group_width, f->stat_ok); -+ -+ if (print_author) -+ format_user (f->stat.st_author, author_width, f->stat_ok); -+ -+ if (print_scontext) -+ format_user_or_group (f->scontext, 0, scontext_width); -+ -+ p = buf; -+ } -+ -+ if (f->stat_ok -+ && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))) -+ { -+ char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)]; -+ char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)]; -+ int blanks_width = (file_size_width -+ - (major_device_number_width + 2 -+ + minor_device_number_width)); -+ sprintf (p, "%*s, %*s ", -+ major_device_number_width + MAX (0, blanks_width), -+ umaxtostr (major (f->stat.st_rdev), majorbuf), -+ minor_device_number_width, -+ umaxtostr (minor (f->stat.st_rdev), minorbuf)); -+ p += file_size_width + 1; -+ } -+ else -+ { -+ char hbuf[LONGEST_HUMAN_READABLE + 1]; -+ char const *size = -+ (! f->stat_ok -+ ? "?" -+ : human_readable (unsigned_file_size (f->stat.st_size), -+ hbuf, human_output_opts, 1, file_output_block_size)); -+ int pad; -+ for (pad = file_size_width - mbswidth (size, 0); 0 < pad; pad--) -+ *p++ = ' '; -+ while ((*p++ = *size++)) -+ continue; -+ p[-1] = ' '; -+ } -+ -+ when_local = localtime (&when_timespec.tv_sec); -+ s = 0; -+ *p = '\1'; -+ -+ if (f->stat_ok && when_local) -+ { -+ struct timespec six_months_ago; -+ bool recent; -+ char const *fmt; -+ -+ /* If the file appears to be in the future, update the current -+ time, in case the file happens to have been modified since -+ the last time we checked the clock. */ -+ if (timespec_cmp (current_time, when_timespec) < 0) -+ { -+ /* Note that gettime may call gettimeofday which, on some non- -+ compliant systems, clobbers the buffer used for localtime's result. -+ But it's ok here, because we use a gettimeofday wrapper that -+ saves and restores the buffer around the gettimeofday call. */ -+ gettime (¤t_time); -+ } -+ -+ /* Consider a time to be recent if it is within the past six -+ months. A Gregorian year has 365.2425 * 24 * 60 * 60 == -+ 31556952 seconds on the average. Write this value as an -+ integer constant to avoid floating point hassles. */ -+ six_months_ago.tv_sec = current_time.tv_sec - 31556952 / 2; -+ six_months_ago.tv_nsec = current_time.tv_nsec; -+ -+ recent = (timespec_cmp (six_months_ago, when_timespec) < 0 -+ && (timespec_cmp (when_timespec, current_time) < 0)); -+ fmt = long_time_format[recent]; -+ -+ /* We assume here that all time zones are offset from UTC by a -+ whole number of seconds. */ -+ s = align_nstrftime (p, TIME_STAMP_LEN_MAXIMUM + 1, fmt, -+ when_local, 0, when_timespec.tv_nsec); -+ } -+ -+ if (s || !*p) -+ { -+ p += s; -+ *p++ = ' '; -+ -+ /* NUL-terminate the string -- fputs (via DIRED_FPUTS) requires it. */ -+ *p = '\0'; -+ } -+ else -+ { -+ /* The time cannot be converted using the desired format, so -+ print it as a huge integer number of seconds. */ -+ char hbuf[INT_BUFSIZE_BOUND (intmax_t)]; -+ sprintf (p, "%*s ", long_time_expected_width (), -+ (! f->stat_ok -+ ? "?" -+ : timetostr (when_timespec.tv_sec, hbuf))); -+ /* FIXME: (maybe) We discarded when_timespec.tv_nsec. */ -+ p += strlen (p); -+ } -+ -+ DIRED_FPUTS (buf, stdout, p - buf); -+ size_t w = print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, -+ f->stat_ok, f->filetype, &dired_obstack, -+ f->stat.st_nlink, p - buf); -+ -+ 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, -+ f->stat.st_nlink, (p - buf) + w + 4); -+ if (indicator_style != none) -+ print_type_indicator (true, f->linkmode, unknown); -+ } -+ } -+ else if (indicator_style != none) -+ print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype); -+} -+ -+/* Output to OUT a quoted representation of the file name NAME, -+ using OPTIONS to control quoting. Produce no output if OUT is NULL. -+ Store the number of screen columns occupied by NAME's quoted -+ representation into WIDTH, if non-NULL. Return the number of bytes -+ produced. */ -+ -+static size_t -+quote_name (FILE *out, const char *name, struct quoting_options const *options, -+ size_t *width) -+{ -+ char smallbuf[BUFSIZ]; -+ size_t len = quotearg_buffer (smallbuf, sizeof smallbuf, name, -1, options); -+ char *buf; -+ size_t displayed_width IF_LINT (= 0); -+ -+ if (len < sizeof smallbuf) -+ buf = smallbuf; -+ else -+ { -+ buf = alloca (len + 1); -+ quotearg_buffer (buf, len + 1, name, -1, options); -+ } -+ -+ if (qmark_funny_chars) -+ { -+ if (MB_CUR_MAX > 1) -+ { -+ char const *p = buf; -+ char const *plimit = buf + len; -+ char *q = buf; -+ displayed_width = 0; -+ -+ while (p < plimit) -+ switch (*p) -+ { -+ case ' ': case '!': case '"': case '#': case '%': -+ case '&': case '\'': case '(': case ')': case '*': -+ case '+': case ',': case '-': case '.': case '/': -+ case '0': case '1': case '2': case '3': case '4': -+ case '5': case '6': case '7': case '8': case '9': -+ case ':': case ';': case '<': case '=': case '>': -+ case '?': -+ case 'A': case 'B': case 'C': case 'D': case 'E': -+ case 'F': case 'G': case 'H': case 'I': case 'J': -+ case 'K': case 'L': case 'M': case 'N': case 'O': -+ case 'P': case 'Q': case 'R': case 'S': case 'T': -+ case 'U': case 'V': case 'W': case 'X': case 'Y': -+ case 'Z': -+ case '[': case '\\': case ']': case '^': case '_': -+ case 'a': case 'b': case 'c': case 'd': case 'e': -+ case 'f': case 'g': case 'h': case 'i': case 'j': -+ case 'k': case 'l': case 'm': case 'n': case 'o': -+ case 'p': case 'q': case 'r': case 's': case 't': -+ case 'u': case 'v': case 'w': case 'x': case 'y': -+ case 'z': case '{': case '|': case '}': case '~': -+ /* These characters are printable ASCII characters. */ -+ *q++ = *p++; -+ displayed_width += 1; -+ break; -+ default: -+ /* If we have a multibyte sequence, copy it until we -+ reach its end, replacing each non-printable multibyte -+ character with a single question mark. */ -+ { -+ DECLARE_ZEROED_AGGREGATE (mbstate_t, mbstate); -+ do -+ { -+ wchar_t wc; -+ size_t bytes; -+ int w; -+ -+ bytes = mbrtowc (&wc, p, plimit - p, &mbstate); -+ -+ if (bytes == (size_t) -1) -+ { -+ /* An invalid multibyte sequence was -+ encountered. Skip one input byte, and -+ put a question mark. */ -+ p++; -+ *q++ = '?'; -+ displayed_width += 1; -+ break; -+ } -+ -+ if (bytes == (size_t) -2) -+ { -+ /* An incomplete multibyte character -+ at the end. Replace it entirely with -+ a question mark. */ -+ p = plimit; -+ *q++ = '?'; -+ displayed_width += 1; -+ break; -+ } -+ -+ if (bytes == 0) -+ /* A null wide character was encountered. */ -+ bytes = 1; -+ -+ w = wcwidth (wc); -+ if (w >= 0) -+ { -+ /* A printable multibyte character. -+ Keep it. */ -+ for (; bytes > 0; --bytes) -+ *q++ = *p++; -+ displayed_width += w; -+ } -+ else -+ { -+ /* An unprintable multibyte character. -+ Replace it entirely with a question -+ mark. */ -+ p += bytes; -+ *q++ = '?'; -+ displayed_width += 1; -+ } -+ } -+ while (! mbsinit (&mbstate)); -+ } -+ break; -+ } -+ -+ /* The buffer may have shrunk. */ -+ len = q - buf; -+ } -+ else -+ { -+ char *p = buf; -+ char const *plimit = buf + len; -+ -+ while (p < plimit) -+ { -+ if (! isprint (to_uchar (*p))) -+ *p = '?'; -+ p++; -+ } -+ displayed_width = len; -+ } -+ } -+ else if (width != NULL) -+ { -+ if (MB_CUR_MAX > 1) -+ displayed_width = mbsnwidth (buf, len, 0); -+ else -+ { -+ char const *p = buf; -+ char const *plimit = buf + len; -+ -+ displayed_width = 0; -+ while (p < plimit) -+ { -+ if (isprint (to_uchar (*p))) -+ displayed_width++; -+ p++; -+ } -+ } -+ } -+ -+ if (out != NULL) -+ fwrite (buf, 1, len, out); -+ if (width != NULL) -+ *width = displayed_width; -+ return len; -+} -+ -+static size_t -+print_name_with_quoting (const char *p, mode_t mode, int linkok, -+ bool stat_ok, enum filetype type, -+ struct obstack *stack, nlink_t nlink, -+ size_t start_col) -+{ -+ bool used_color_this_time -+ = (print_with_color -+ && print_color_indicator (p, mode, linkok, stat_ok, type, nlink)); -+ -+ if (stack) -+ PUSH_CURRENT_DIRED_POS (stack); -+ -+ size_t width = quote_name (stdout, p, filename_quoting_options, NULL); -+ dired_pos += width; -+ -+ if (stack) -+ PUSH_CURRENT_DIRED_POS (stack); -+ -+ if (used_color_this_time) -+ { -+ process_signals (); -+ prep_non_filename_text (); -+ if (start_col / line_length != (start_col + width - 1) / line_length) -+ put_indicator (&color_indicator[C_CLR_TO_EOL]); -+ } -+ -+ return width; -+} -+ -+static void -+prep_non_filename_text (void) -+{ -+ if (color_indicator[C_END].string != NULL) -+ put_indicator (&color_indicator[C_END]); -+ else -+ { -+ put_indicator (&color_indicator[C_LEFT]); -+ put_indicator (&color_indicator[C_RESET]); -+ put_indicator (&color_indicator[C_RIGHT]); -+ } -+} -+ -+/* Print the file name of `f' with appropriate quoting. -+ Also print file size, inode number, and filetype indicator character, -+ as requested by switches. */ -+ -+static size_t -+print_file_name_and_frills (const struct fileinfo *f, size_t start_col) -+{ -+ char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))]; -+ -+ if (print_inode) -+ printf ("%*s ", format == with_commas ? 0 : inode_number_width, -+ format_inode (buf, sizeof buf, f)); -+ -+ if (print_block_size) -+ printf ("%*s ", format == with_commas ? 0 : block_size_width, -+ ! f->stat_ok ? "?" -+ : human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts, -+ ST_NBLOCKSIZE, output_block_size)); -+ -+ if (print_scontext) -+ printf ("%*s ", format == with_commas ? 0 : scontext_width, f->scontext); -+ -+ size_t width = print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), -+ f->linkok, f->stat_ok, f->filetype, -+ NULL, f->stat.st_nlink, start_col); -+ -+ if (indicator_style != none) -+ width += print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype); -+ -+ return width; -+} -+ -+/* Given these arguments describing a file, return the single-byte -+ type indicator, or 0. */ -+static char -+get_type_indicator (bool stat_ok, mode_t mode, enum filetype type) -+{ -+ char c; -+ -+ if (stat_ok ? S_ISREG (mode) : type == normal) -+ { -+ if (stat_ok && indicator_style == classify && (mode & S_IXUGO)) -+ c = '*'; -+ else -+ c = 0; -+ } -+ else -+ { -+ if (stat_ok ? S_ISDIR (mode) : type == directory || type == arg_directory) -+ c = '/'; -+ else if (indicator_style == slash) -+ c = 0; -+ else if (stat_ok ? S_ISLNK (mode) : type == symbolic_link) -+ c = '@'; -+ else if (stat_ok ? S_ISFIFO (mode) : type == fifo) -+ c = '|'; -+ else if (stat_ok ? S_ISSOCK (mode) : type == sock) -+ c = '='; -+ else if (stat_ok && S_ISDOOR (mode)) -+ c = '>'; -+ else -+ c = 0; -+ } -+ return c; -+} -+ -+static bool -+print_type_indicator (bool stat_ok, mode_t mode, enum filetype type) -+{ -+ char c = get_type_indicator (stat_ok, mode, type); -+ if (c) -+ DIRED_PUTCHAR (c); -+ return !!c; -+} -+ -+#ifdef HAVE_CAP -+/* Return true if NAME has a capability (see linux/capability.h) */ -+static bool -+has_capability (char const *name) -+{ -+ char *result; -+ bool has_cap; -+ -+ cap_t cap_d = cap_get_file (name); -+ if (cap_d == NULL) -+ return false; -+ -+ result = cap_to_text (cap_d, NULL); -+ cap_free (cap_d); -+ if (!result) -+ return false; -+ -+ /* check if human-readable capability string is empty */ -+ has_cap = !!*result; -+ -+ cap_free (result); -+ return has_cap; -+} -+#else -+static bool -+has_capability (char const *name ATTRIBUTE_UNUSED) -+{ -+ return false; -+} -+#endif -+ -+/* Returns whether any color sequence was printed. */ -+static bool -+print_color_indicator (const char *name, mode_t mode, int linkok, -+ bool stat_ok, enum filetype filetype, -+ nlink_t nlink) -+{ -+ enum indicator_no type; -+ struct color_ext_type *ext; /* Color extension */ -+ size_t len; /* Length of name */ -+ -+ /* Is this a nonexistent file? If so, linkok == -1. */ -+ -+ if (linkok == -1 && color_indicator[C_MISSING].string != NULL) -+ type = C_MISSING; -+ else if (! stat_ok) -+ { -+ static enum indicator_no filetype_indicator[] = FILETYPE_INDICATORS; -+ type = filetype_indicator[filetype]; -+ } -+ else -+ { -+ if (S_ISREG (mode)) -+ { -+ type = C_FILE; -+ -+ if ((mode & S_ISUID) != 0 && is_colored (C_SETUID)) -+ type = C_SETUID; -+ else if ((mode & S_ISGID) != 0 && is_colored (C_SETGID)) -+ type = C_SETGID; -+ /* has_capability() called second for performance. */ -+ else if (is_colored (C_CAP) && has_capability (name)) -+ type = C_CAP; -+ else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC)) -+ type = C_EXEC; -+ else if ((1 < nlink) && is_colored (C_MULTIHARDLINK)) -+ type = C_MULTIHARDLINK; -+ } -+ else if (S_ISDIR (mode)) -+ { -+ type = C_DIR; -+ -+ if ((mode & S_ISVTX) && (mode & S_IWOTH) -+ && is_colored (C_STICKY_OTHER_WRITABLE)) -+ type = C_STICKY_OTHER_WRITABLE; -+ else if ((mode & S_IWOTH) != 0 && is_colored (C_OTHER_WRITABLE)) -+ type = C_OTHER_WRITABLE; -+ else if ((mode & S_ISVTX) != 0 && is_colored (C_STICKY)) -+ type = C_STICKY; -+ } -+ else if (S_ISLNK (mode)) -+ type = ((!linkok && color_indicator[C_ORPHAN].string) -+ ? C_ORPHAN : C_LINK); -+ else if (S_ISFIFO (mode)) -+ type = C_FIFO; -+ else if (S_ISSOCK (mode)) -+ type = C_SOCK; -+ else if (S_ISBLK (mode)) -+ type = C_BLK; -+ else if (S_ISCHR (mode)) -+ type = C_CHR; -+ else if (S_ISDOOR (mode)) -+ type = C_DOOR; -+ else -+ { -+ /* Classify a file of some other type as C_ORPHAN. */ -+ type = C_ORPHAN; -+ } -+ } -+ -+ /* Check the file's suffix only if still classified as C_FILE. */ -+ ext = NULL; -+ if (type == C_FILE) -+ { -+ /* Test if NAME has a recognized suffix. */ -+ -+ len = strlen (name); -+ name += len; /* Pointer to final \0. */ -+ for (ext = color_ext_list; ext != NULL; ext = ext->next) -+ { -+ if (ext->ext.len <= len -+ && strncmp (name - ext->ext.len, ext->ext.string, -+ ext->ext.len) == 0) -+ break; -+ } -+ } -+ -+ { -+ const struct bin_str *const s -+ = ext ? &(ext->seq) : &color_indicator[type]; -+ if (s->string != NULL) -+ { -+ put_indicator (&color_indicator[C_LEFT]); -+ put_indicator (s); -+ put_indicator (&color_indicator[C_RIGHT]); -+ return true; -+ } -+ else -+ return false; -+ } -+} -+ -+/* Output a color indicator (which may contain nulls). */ -+static void -+put_indicator (const struct bin_str *ind) -+{ -+ if (! used_color) -+ { -+ used_color = true; -+ prep_non_filename_text (); -+ } -+ -+ fwrite (ind->string, ind->len, 1, stdout); -+} -+ -+static size_t -+length_of_file_name_and_frills (const struct fileinfo *f) -+{ -+ size_t len = 0; -+ size_t name_width; -+ char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))]; -+ -+ if (print_inode) -+ len += 1 + (format == with_commas -+ ? strlen (umaxtostr (f->stat.st_ino, buf)) -+ : inode_number_width); -+ -+ if (print_block_size) -+ len += 1 + (format == with_commas -+ ? strlen (! f->stat_ok ? "?" -+ : human_readable (ST_NBLOCKS (f->stat), buf, -+ human_output_opts, ST_NBLOCKSIZE, -+ output_block_size)) -+ : block_size_width); -+ -+ if (print_scontext) -+ len += 1 + (format == with_commas ? strlen (f->scontext) : scontext_width); -+ -+ quote_name (NULL, f->name, filename_quoting_options, &name_width); -+ len += name_width; -+ -+ if (indicator_style != none) -+ { -+ char c = get_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype); -+ len += (c != 0); -+ } -+ -+ return len; -+} -+ -+static void -+print_many_per_line (void) -+{ -+ size_t row; /* Current row. */ -+ size_t cols = calculate_columns (true); -+ struct column_info const *line_fmt = &column_info[cols - 1]; -+ -+ /* Calculate the number of rows that will be in each column except possibly -+ for a short column on the right. */ -+ size_t rows = cwd_n_used / cols + (cwd_n_used % cols != 0); -+ -+ for (row = 0; row < rows; row++) -+ { -+ size_t col = 0; -+ size_t filesno = row; -+ size_t pos = 0; -+ -+ /* Print the next row. */ -+ while (1) -+ { -+ struct fileinfo const *f = sorted_file[filesno]; -+ size_t name_length = length_of_file_name_and_frills (f); -+ size_t max_name_length = line_fmt->col_arr[col++]; -+ print_file_name_and_frills (f, pos); -+ -+ filesno += rows; -+ if (filesno >= cwd_n_used) -+ break; -+ -+ indent (pos + name_length, pos + max_name_length); -+ pos += max_name_length; -+ } -+ putchar ('\n'); -+ } -+} -+ -+static void -+print_horizontal (void) -+{ -+ size_t filesno; -+ size_t pos = 0; -+ size_t cols = calculate_columns (false); -+ struct column_info const *line_fmt = &column_info[cols - 1]; -+ 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 (f, 0); -+ -+ /* Now the rest. */ -+ for (filesno = 1; filesno < cwd_n_used; ++filesno) -+ { -+ size_t col = filesno % cols; -+ -+ if (col == 0) -+ { -+ putchar ('\n'); -+ pos = 0; -+ } -+ else -+ { -+ indent (pos + name_length, pos + max_name_length); -+ pos += max_name_length; -+ } -+ -+ f = sorted_file[filesno]; -+ print_file_name_and_frills (f, pos); -+ -+ name_length = length_of_file_name_and_frills (f); -+ max_name_length = line_fmt->col_arr[col]; -+ } -+ putchar ('\n'); -+} -+ -+static void -+print_with_commas (void) -+{ -+ size_t filesno; -+ size_t pos = 0; -+ -+ for (filesno = 0; filesno < cwd_n_used; filesno++) -+ { -+ struct fileinfo const *f = sorted_file[filesno]; -+ size_t len = length_of_file_name_and_frills (f); -+ -+ if (filesno != 0) -+ { -+ char separator; -+ -+ if (pos + len + 2 < line_length) -+ { -+ pos += 2; -+ separator = ' '; -+ } -+ else -+ { -+ pos = 0; -+ separator = '\n'; -+ } -+ -+ putchar (','); -+ putchar (separator); -+ } -+ -+ print_file_name_and_frills (f, pos); -+ pos += len; -+ } -+ putchar ('\n'); -+} -+ -+/* Assuming cursor is at position FROM, indent up to position TO. -+ Use a TAB character instead of two or more spaces whenever possible. */ -+ -+static void -+indent (size_t from, size_t to) -+{ -+ while (from < to) -+ { -+ if (tabsize != 0 && to / tabsize > (from + 1) / tabsize) -+ { -+ putchar ('\t'); -+ from += tabsize - from % tabsize; -+ } -+ else -+ { -+ putchar (' '); -+ from++; -+ } -+ } -+} -+ -+/* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */ -+/* FIXME: maybe remove this function someday. See about using a -+ non-malloc'ing version of file_name_concat. */ -+ -+static void -+attach (char *dest, const char *dirname, const char *name) -+{ -+ const char *dirnamep = dirname; -+ -+ /* Copy dirname if it is not ".". */ -+ if (dirname[0] != '.' || dirname[1] != 0) -+ { -+ while (*dirnamep) -+ *dest++ = *dirnamep++; -+ /* Add '/' if `dirname' doesn't already end with it. */ -+ if (dirnamep > dirname && dirnamep[-1] != '/') -+ *dest++ = '/'; -+ } -+ while (*name) -+ *dest++ = *name++; -+ *dest = 0; -+} -+ -+/* Allocate enough column info suitable for the current number of -+ files and display columns, and initialize the info to represent the -+ narrowest possible columns. */ -+ -+static void -+init_column_info (void) -+{ -+ size_t i; -+ size_t max_cols = MIN (max_idx, cwd_n_used); -+ -+ /* Currently allocated columns in column_info. */ -+ static size_t column_info_alloc; -+ -+ if (column_info_alloc < max_cols) -+ { -+ size_t new_column_info_alloc; -+ size_t *p; -+ -+ if (max_cols < max_idx / 2) -+ { -+ /* The number of columns is far less than the display width -+ allows. Grow the allocation, but only so that it's -+ double the current requirements. If the display is -+ extremely wide, this avoids allocating a lot of memory -+ that is never needed. */ -+ column_info = xnrealloc (column_info, max_cols, -+ 2 * sizeof *column_info); -+ new_column_info_alloc = 2 * max_cols; -+ } -+ else -+ { -+ column_info = xnrealloc (column_info, max_idx, sizeof *column_info); -+ new_column_info_alloc = max_idx; -+ } -+ -+ /* Allocate the new size_t objects by computing the triangle -+ formula n * (n + 1) / 2, except that we don't need to -+ allocate the part of the triangle that we've already -+ allocated. Check for address arithmetic overflow. */ -+ { -+ size_t column_info_growth = new_column_info_alloc - column_info_alloc; -+ size_t s = column_info_alloc + 1 + new_column_info_alloc; -+ size_t t = s * column_info_growth; -+ if (s < new_column_info_alloc || t / column_info_growth != s) -+ xalloc_die (); -+ p = xnmalloc (t / 2, sizeof *p); -+ } -+ -+ /* Grow the triangle by parceling out the cells just allocated. */ -+ for (i = column_info_alloc; i < new_column_info_alloc; i++) -+ { -+ column_info[i].col_arr = p; -+ p += i + 1; -+ } -+ -+ column_info_alloc = new_column_info_alloc; -+ } -+ -+ for (i = 0; i < max_cols; ++i) -+ { -+ size_t j; -+ -+ column_info[i].valid_len = true; -+ column_info[i].line_len = (i + 1) * MIN_COLUMN_WIDTH; -+ for (j = 0; j <= i; ++j) -+ column_info[i].col_arr[j] = MIN_COLUMN_WIDTH; -+ } -+} -+ -+/* Calculate the number of columns needed to represent the current set -+ of files in the current display width. */ -+ -+static size_t -+calculate_columns (bool by_columns) -+{ -+ size_t filesno; /* Index into cwd_file. */ -+ size_t cols; /* Number of files across. */ -+ -+ /* Normally the maximum number of columns is determined by the -+ screen width. But if few files are available this might limit it -+ as well. */ -+ size_t max_cols = MIN (max_idx, cwd_n_used); -+ -+ init_column_info (); -+ -+ /* Compute the maximum number of possible columns. */ -+ for (filesno = 0; filesno < cwd_n_used; ++filesno) -+ { -+ struct fileinfo const *f = sorted_file[filesno]; -+ size_t name_length = length_of_file_name_and_frills (f); -+ size_t i; -+ -+ for (i = 0; i < max_cols; ++i) -+ { -+ if (column_info[i].valid_len) -+ { -+ size_t idx = (by_columns -+ ? filesno / ((cwd_n_used + i) / (i + 1)) -+ : filesno % (i + 1)); -+ size_t real_length = name_length + (idx == i ? 0 : 2); -+ -+ if (column_info[i].col_arr[idx] < real_length) -+ { -+ column_info[i].line_len += (real_length -+ - column_info[i].col_arr[idx]); -+ column_info[i].col_arr[idx] = real_length; -+ column_info[i].valid_len = (column_info[i].line_len -+ < line_length); -+ } -+ } -+ } -+ } -+ -+ /* Find maximum allowed columns. */ -+ for (cols = max_cols; 1 < cols; --cols) -+ { -+ if (column_info[cols - 1].valid_len) -+ break; -+ } -+ -+ return cols; -+} -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); -+ fputs (_("\ -+List information about the FILEs (the current directory by default).\n\ -+Sort entries alphabetically if none of -cftuvSUX nor --sort.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ -a, --all do not ignore entries starting with .\n\ -+ -A, --almost-all do not list implied . and ..\n\ -+ --author with -l, print the author of each file\n\ -+ -b, --escape print octal escapes for nongraphic characters\n\ -+"), stdout); -+ fputs (_("\ -+ --block-size=SIZE use SIZE-byte blocks. See SIZE format below\n\ -+ -B, --ignore-backups do not list implied entries ending with ~\n\ -+ -c with -lt: sort by, and show, ctime (time of last\n\ -+ modification of file status information)\n\ -+ with -l: show ctime and sort by name\n\ -+ otherwise: sort by ctime\n\ -+"), stdout); -+ fputs (_("\ -+ -C list entries by columns\n\ -+ --color[=WHEN] colorize the output. WHEN defaults to `always'\n\ -+ or can be `never' or `auto'. More info below\n\ -+ -d, --directory list directory entries instead of contents,\n\ -+ and do not dereference symbolic links\n\ -+ -D, --dired generate output designed for Emacs' dired mode\n\ -+"), stdout); -+ fputs (_("\ -+ -f do not sort, enable -aU, disable -ls --color\n\ -+ -F, --classify append indicator (one of */=>@|) to entries\n\ -+ --file-type likewise, except do not append `*'\n\ -+ --format=WORD across -x, commas -m, horizontal -x, long -l,\n\ -+ single-column -1, verbose -l, vertical -C\n\ -+ --full-time like -l --time-style=full-iso\n\ -+"), stdout); -+ fputs (_("\ -+ -g like -l, but do not list owner\n\ -+"), stdout); -+ fputs (_("\ -+ --group-directories-first\n\ -+ group directories before files.\n\ -+ augment with a --sort option, but any\n\ -+ use of --sort=none (-U) disables grouping\n\ -+"), stdout); -+ fputs (_("\ -+ -G, --no-group in a long listing, don't print group names\n\ -+ -h, --human-readable with -l, print sizes in human readable format\n\ -+ (e.g., 1K 234M 2G)\n\ -+ --si likewise, but use powers of 1000 not 1024\n\ -+"), stdout); -+ fputs (_("\ -+ -H, --dereference-command-line\n\ -+ follow symbolic links listed on the command line\n\ -+ --dereference-command-line-symlink-to-dir\n\ -+ follow each command line symbolic link\n\ -+ that points to a directory\n\ -+ --hide=PATTERN do not list implied entries matching shell PATTERN\n\ -+ (overridden by -a or -A)\n\ -+"), stdout); -+ fputs (_("\ -+ --indicator-style=WORD append indicator with style WORD to entry names:\n\ -+ none (default), slash (-p),\n\ -+ file-type (--file-type), classify (-F)\n\ -+ -i, --inode print the index number of each file\n\ -+ -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\n\ -+ -k like --block-size=1K\n\ -+"), stdout); -+ fputs (_("\ -+ -l use a long listing format\n\ -+ -L, --dereference when showing file information for a symbolic\n\ -+ link, show information for the file the link\n\ -+ references rather than for the link itself\n\ -+ -m fill width with a comma separated list of entries\n\ -+"), stdout); -+ fputs (_("\ -+ -n, --numeric-uid-gid like -l, but list numeric user and group IDs\n\ -+ -N, --literal print raw entry names (don't treat e.g. control\n\ -+ characters specially)\n\ -+ -o like -l, but do not list group information\n\ -+ -p, --indicator-style=slash\n\ -+ append / indicator to directories\n\ -+"), stdout); -+ fputs (_("\ -+ -q, --hide-control-chars print ? instead of non graphic characters\n\ -+ --show-control-chars show non graphic characters as-is (default\n\ -+ unless program is `ls' and output is a terminal)\n\ -+ -Q, --quote-name enclose entry names in double quotes\n\ -+ --quoting-style=WORD use quoting style WORD for entry names:\n\ -+ literal, locale, shell, shell-always, c, escape\n\ -+"), stdout); -+ fputs (_("\ -+ -r, --reverse reverse order while sorting\n\ -+ -R, --recursive list subdirectories recursively\n\ -+ -s, --size print the allocated size of each file, in blocks\n\ -+"), stdout); -+ fputs (_("\ -+ -S sort by file size\n\ -+ --sort=WORD sort by WORD instead of name: none -U,\n\ -+ extension -X, size -S, time -t, version -v\n\ -+ --time=WORD with -l, show time as WORD instead of modification\n\ -+ time: atime -u, access -u, use -u, ctime -c,\n\ -+ or status -c; use specified time as sort key\n\ -+ if --sort=time\n\ -+"), stdout); -+ fputs (_("\ -+ --time-style=STYLE with -l, show times using style STYLE:\n\ -+ full-iso, long-iso, iso, locale, +FORMAT.\n\ -+ FORMAT is interpreted like `date'; if FORMAT is\n\ -+ FORMAT1FORMAT2, FORMAT1 applies to\n\ -+ non-recent files and FORMAT2 to recent files;\n\ -+ if STYLE is prefixed with `posix-', STYLE\n\ -+ takes effect only outside the POSIX locale\n\ -+"), stdout); -+ fputs (_("\ -+ -t sort by modification time\n\ -+ -T, --tabsize=COLS assume tab stops at each COLS instead of 8\n\ -+"), stdout); -+ fputs (_("\ -+ -u with -lt: sort by, and show, access time\n\ -+ with -l: show access time and sort by name\n\ -+ otherwise: sort by access time\n\ -+ -U do not sort; list entries in directory order\n\ -+ -v natural sort of (version) numbers within text\n\ -+"), stdout); -+ fputs (_("\ -+ -w, --width=COLS assume screen width instead of current value\n\ -+ -x list entries by lines instead of by columns\n\ -+ -X sort alphabetically by entry extension\n\ -+ -Z, --context print any SELinux security context of each file\n\ -+ -1 list one file per line\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ emit_size_note (); -+ fputs (_("\ -+\n\ -+Using color to distinguish file types is disabled both by default and\n\ -+with --color=never. With --color=auto, ls emits color codes only when\n\ -+standard output is connected to a terminal. The LS_COLORS environment\n\ -+variable can change the settings. Use the dircolors command to set it.\n\ -+"), stdout); -+ fputs (_("\ -+\n\ -+Exit status:\n\ -+ 0 if OK,\n\ -+ 1 if minor problems (e.g., cannot access subdirectory),\n\ -+ 2 if serious trouble (e.g., cannot access command-line argument).\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -diff -urNp coreutils-8.0-orig/src/mkdir.c coreutils-8.0/src/mkdir.c ---- coreutils-8.0-orig/src/mkdir.c 2009-09-23 10:25:44.000000000 +0200 -+++ coreutils-8.0/src/mkdir.c 2009-10-07 10:10:11.000000000 +0200 -@@ -38,6 +38,7 @@ - static struct option const longopts[] = + case 'S': + make_backups = true; + backup_suffix_string = optarg; +diff -urNp coreutils-8.0-orig/src/chcon.c coreutils-8.0/src/chcon.c +--- coreutils-8.0-orig/src/chcon.c 2009-10-06 10:55:34.000000000 +0200 ++++ coreutils-8.0/src/chcon.c 2009-10-07 10:10:11.000000000 +0200 +@@ -348,7 +348,7 @@ Usage: %s [OPTION]... CONTEXT FILE...\n\ + "), + program_name, program_name, program_name); + fputs (_("\ +-Change the security context of each FILE to CONTEXT.\n\ ++Change the SELinux security context of each FILE to CONTEXT.\n\ + With --reference, change the security context of each FILE to that of RFILE.\n\ + \n\ + -h, --no-dereference affect symbolic links instead of any referenced file\n\ +diff -urNp coreutils-8.0-orig/src/id.c coreutils-8.0/src/id.c +--- coreutils-8.0-orig/src/id.c 2009-09-29 15:27:54.000000000 +0200 ++++ coreutils-8.0/src/id.c 2009-10-07 10:10:11.000000000 +0200 +@@ -107,7 +107,7 @@ int + main (int argc, char **argv) { - {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, -+ {"context", required_argument, NULL, 'Z'}, - {"mode", required_argument, NULL, 'm'}, - {"parents", no_argument, NULL, 'p'}, - {"verbose", no_argument, NULL, 'v'}, -diff -urNp coreutils-8.0-orig/src/mknod.c coreutils-8.0/src/mknod.c ---- coreutils-8.0-orig/src/mknod.c 2009-09-23 10:25:44.000000000 +0200 -+++ coreutils-8.0/src/mknod.c 2009-10-07 10:10:11.000000000 +0200 -@@ -35,7 +35,7 @@ + int optc; +- int selinux_enabled = (is_selinux_enabled () > 0); ++ bool selinux_enabled = (is_selinux_enabled () > 0); - static struct option const longopts[] = - { -- {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, -+ {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, - {"mode", required_argument, NULL, 'm'}, + /* If true, output the list of all group IDs. -G */ + bool just_group_list = false; +diff -urNp coreutils-8.0-orig/src/install.c coreutils-8.0/src/install.c +--- coreutils-8.0-orig/src/install.c 2009-09-29 15:27:54.000000000 +0200 ++++ coreutils-8.0/src/install.c 2009-10-07 10:10:11.000000000 +0200 +@@ -284,6 +284,7 @@ cp_option_init (struct cp_options *x) + x->reduce_diagnostics=false; + x->require_preserve = false; + x->require_preserve_context = false; ++ x->set_security_context = false; + x->require_preserve_xattr = false; + x->recursive = false; + x->sparse_mode = SPARSE_AUTO; +@@ -461,7 +462,7 @@ main (int argc, char **argv) + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + +- while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z:", long_options, ++ while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pPt:TvS:Z:", long_options, + NULL)) != -1) + { + switch (optc) +@@ -535,6 +536,7 @@ main (int argc, char **argv) + error (0, 0, _("WARNING: --preserve_context is deprecated; " + "use --preserve-context instead")); + /* fall through */ ++ case 'P': + case PRESERVE_CONTEXT_OPTION: + if ( ! selinux_enabled) + { +@@ -542,6 +544,10 @@ main (int argc, char **argv) + "this kernel is not SELinux-enabled")); + 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 = false; + break; +@@ -553,6 +559,7 @@ main (int argc, char **argv) + break; + } + scontext = optarg; ++ x.set_security_context = true; + use_default_selinux_context = false; + break; + case_GETOPT_HELP_CHAR; +@@ -986,8 +993,8 @@ Mandatory arguments to long options are + -v, --verbose print the name of each directory as it is created\n\ + "), stdout); + fputs (_("\ +- --preserve-context preserve SELinux security context\n\ +- -Z, --context=CONTEXT set SELinux security context of files and directories\n\ ++ -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); +diff -urNp coreutils-8.0-orig/src/ls.c coreutils-8.0/src/ls.c +--- coreutils-8.0-orig/src/ls.c 2009-10-07 10:09:43.000000000 +0200 ++++ coreutils-8.0/src/ls.c 2009-10-07 10:10:11.000000000 +0200 +@@ -162,7 +162,8 @@ enum filetype + symbolic_link, + sock, + whiteout, +- arg_directory ++ arg_directory, ++ command_line + }; + + /* Display letters and indicators for each filetype. +@@ -279,6 +280,7 @@ static void queue_directory (char const + static void sort_files (void); + static void parse_ls_color (void); + void usage (int status); ++static void print_scontext_format (const struct fileinfo *f); + + /* Initial size of hash table. + Most hierarchies are likely to be shallower than this. */ +@@ -348,7 +350,7 @@ static struct pending *pending_dirs; + + static struct timespec current_time; + +-static bool print_scontext; ++static int print_scontext = 0; + static char UNKNOWN_SECURITY_CONTEXT[] = "?"; + + /* Whether any of the files has an ACL. This affects the width of the +@@ -388,7 +390,9 @@ enum format + one_per_line, /* -1 */ + many_per_line, /* -C */ + horizontal, /* -x */ +- with_commas /* -m */ ++ with_commas, /* -m */ ++ security_format, /* -Z */ ++ invalid_format + }; + + static enum format format; +@@ -790,6 +794,9 @@ enum + SHOW_CONTROL_CHARS_OPTION, + SI_OPTION, + SORT_OPTION, ++ CONTEXT_OPTION, ++ LCONTEXT_OPTION, ++ SCONTEXT_OPTION, + TIME_OPTION, + TIME_STYLE_OPTION + }; +@@ -835,7 +842,9 @@ static struct option const long_options[ + {"time-style", required_argument, NULL, TIME_STYLE_OPTION}, + {"color", optional_argument, NULL, COLOR_OPTION}, + {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, +- {"context", no_argument, 0, 'Z'}, ++ {"context", no_argument, 0, CONTEXT_OPTION}, ++ {"lcontext", no_argument, 0, LCONTEXT_OPTION}, ++ {"scontext", no_argument, 0, SCONTEXT_OPTION}, + {"author", no_argument, NULL, AUTHOR_OPTION}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, -diff -urNp coreutils-8.0-orig/src/mv.c coreutils-8.0/src/mv.c ---- coreutils-8.0-orig/src/mv.c 2009-09-23 10:25:44.000000000 +0200 -+++ coreutils-8.0/src/mv.c 2009-10-07 10:10:11.000000000 +0200 -@@ -118,6 +118,7 @@ cp_option_init (struct cp_options *x) - x->preserve_mode = true; - x->preserve_timestamps = true; - x->preserve_security_context = selinux_enabled; -+ x->set_security_context = false; - x->reduce_diagnostics = false; - x->require_preserve = false; /* FIXME: maybe make this an option */ - x->require_preserve_context = false; -diff -urNp coreutils-8.0-orig/src/mv.c.orig coreutils-8.0/src/mv.c.orig ---- coreutils-8.0-orig/src/mv.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/mv.c.orig 2009-09-23 10:25:44.000000000 +0200 -@@ -0,0 +1,495 @@ -+/* mv -- move or rename files -+ Copyright (C) 86, 89, 90, 91, 1995-2009 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 . */ -+ -+/* Written by Mike Parker, David MacKenzie, and Jim Meyering */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "system.h" -+#include "backupfile.h" -+#include "copy.h" -+#include "cp-hash.h" -+#include "error.h" -+#include "filenamecat.h" -+#include "quote.h" -+#include "remove.h" -+#include "root-dev-ino.h" -+#include "priv-set.h" -+ -+/* The official name of this program (e.g., no `g' prefix). */ -+#define PROGRAM_NAME "mv" -+ -+#define AUTHORS \ -+ proper_name ("Mike Parker"), \ -+ proper_name ("David MacKenzie"), \ -+ proper_name ("Jim Meyering") -+ -+/* For long options that have no equivalent short option, use a -+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -+enum -+{ -+ STRIP_TRAILING_SLASHES_OPTION = CHAR_MAX + 1 -+}; -+ -+/* Remove any trailing slashes from each SOURCE argument. */ -+static bool remove_trailing_slashes; -+ -+static struct option const long_options[] = -+{ -+ {"backup", optional_argument, NULL, 'b'}, -+ {"force", no_argument, NULL, 'f'}, -+ {"interactive", no_argument, NULL, 'i'}, -+ {"no-clobber", no_argument, NULL, 'n'}, -+ {"no-target-directory", no_argument, NULL, 'T'}, -+ {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, -+ {"suffix", required_argument, NULL, 'S'}, -+ {"target-directory", required_argument, NULL, 't'}, -+ {"update", no_argument, NULL, 'u'}, -+ {"verbose", no_argument, NULL, 'v'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+static void -+rm_option_init (struct rm_options *x) -+{ -+ x->ignore_missing_files = false; -+ x->recursive = true; -+ x->one_file_system = false; -+ -+ /* Should we prompt for removal, too? No. Prompting for the `move' -+ part is enough. It implies removal. */ -+ x->interactive = RMI_NEVER; -+ x->stdin_tty = false; -+ -+ x->verbose = false; -+ -+ /* Since this program may well have to process additional command -+ line arguments after any call to `rm', that function must preserve -+ the initial working directory, in case one of those is a -+ `.'-relative name. */ -+ x->require_restore_cwd = true; -+ -+ { -+ static struct dev_ino dev_ino_buf; -+ x->root_dev_ino = get_root_dev_ino (&dev_ino_buf); -+ if (x->root_dev_ino == NULL) -+ error (EXIT_FAILURE, errno, _("failed to get attributes of %s"), -+ quote ("/")); -+ } -+} +@@ -845,12 +854,12 @@ static struct option const long_options[ + static char const *const format_args[] = + { + "verbose", "long", "commas", "horizontal", "across", +- "vertical", "single-column", NULL ++ "vertical", "single-column", "context", NULL + }; + static enum format const format_types[] = + { + long_format, long_format, with_commas, horizontal, horizontal, +- many_per_line, one_per_line ++ many_per_line, one_per_line, security_format + }; + ARGMATCH_VERIFY (format_args, format_types); + +@@ -1281,7 +1290,8 @@ main (int argc, char **argv) + /* Avoid following symbolic links when possible. */ + if (is_colored (C_ORPHAN) + || (is_colored (C_EXEC) && color_symlink_as_referent) +- || (is_colored (C_MISSING) && format == long_format)) ++ || (is_colored (C_MISSING) && (format == long_format ++ || format == security_format))) + check_symlink_color = true; + + /* If the standard output is a controlling terminal, watch out +@@ -1328,7 +1338,7 @@ main (int argc, char **argv) + if (dereference == DEREF_UNDEFINED) + dereference = ((immediate_dirs + || indicator_style == classify +- || format == long_format) ++ || format == long_format || format == security_format) + ? DEREF_NEVER + : DEREF_COMMAND_LINE_SYMLINK_TO_DIR); + +@@ -1348,7 +1358,7 @@ main (int argc, char **argv) + + format_needs_stat = sort_type == sort_time || sort_type == sort_size + || format == long_format +- || print_scontext ++ || format == security_format || print_scontext + || print_block_size; + format_needs_type = (! format_needs_stat + && (recursive +@@ -1379,7 +1389,7 @@ main (int argc, char **argv) + } + 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) +@@ -1542,7 +1552,7 @@ decode_switches (int argc, char **argv) + ignore_mode = IGNORE_DEFAULT; + ignore_patterns = NULL; + hide_patterns = NULL; +- print_scontext = false; ++ print_scontext = 0; + + /* FIXME: put this in a function. */ + { +@@ -1924,13 +1934,27 @@ decode_switches (int argc, char **argv) + break; + + case 'Z': +- print_scontext = true; ++ print_scontext = 1; ++ format = security_format; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + ++ case CONTEXT_OPTION: /* default security context 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; + + default: + usage (LS_FAILURE); + } +@@ -2651,8 +2675,10 @@ clear_files (void) + struct fileinfo *f = sorted_file[i]; + free (f->name); + free (f->linkname); +- if (f->scontext != UNKNOWN_SECURITY_CONTEXT) +- freecon (f->scontext); ++ if (f->scontext != UNKNOWN_SECURITY_CONTEXT) { ++ freecon (f->scontext); ++ f->scontext = NULL; ++ } + } + + cwd_n_used = 0; +@@ -2694,6 +2720,7 @@ gobble_file (char const *name, enum file + memset (f, '\0', sizeof *f); + f->stat.st_ino = inode; + f->filetype = type; ++ f->scontext = NULL; + + if (command_line_arg + || format_needs_stat +@@ -2793,7 +2820,7 @@ gobble_file (char const *name, enum file + + f->stat_ok = true; + +- if (format == long_format || print_scontext) ++ if (format == long_format || format == security_format || print_scontext) + { + bool have_selinux = false; + bool have_acl = false; +@@ -2827,7 +2854,7 @@ gobble_file (char const *name, enum file + err = 0; + } + +- if (err == 0 && format == long_format) ++ if (err == 0 && (format == long_format || format == security_format)) + { + int n = file_has_acl (absolute_name, &f->stat); + err = (n < 0); +@@ -2846,7 +2873,8 @@ gobble_file (char const *name, enum file + } + + if (S_ISLNK (f->stat.st_mode) +- && (format == long_format || check_symlink_color)) ++ && (format == long_format || format == security_format ++ || check_symlink_color)) + { + char *linkname; + struct stat linkstats; +@@ -2866,6 +2894,7 @@ gobble_file (char const *name, enum file + command line are automatically traced if not being + listed as files. */ + if (!command_line_arg || format == long_format ++ || format == security_format + || !S_ISDIR (linkstats.st_mode)) + { + /* Get the linked-to file's mode for the filetype indicator +@@ -2905,7 +2934,7 @@ gobble_file (char const *name, enum file + block_size_width = len; + } + +- if (format == long_format) ++ if (format == long_format || format == security_format) + { + if (print_owner) + { +@@ -3406,6 +3435,13 @@ print_current_files (void) + print_long_format (sorted_file[i]); + DIRED_PUTCHAR ('\n'); + } ++ break; ++ case security_format: ++ for (i = 0; i < cwd_n_used; i++) ++ { ++ print_scontext_format (sorted_file[i]); ++ DIRED_PUTCHAR ('\n'); ++ } + break; + } + } +@@ -3568,6 +3604,69 @@ format_inode (char *buf, size_t buflen, + : (char *) "?"); + } + ++/* Print info about f in scontext format */ +static void -+cp_option_init (struct cp_options *x) -+{ -+ bool selinux_enabled = (0 < is_selinux_enabled ()); -+ -+ cp_options_default (x); -+ x->copy_as_regular = false; /* FIXME: maybe make this an option */ -+ x->reflink_mode = REFLINK_NEVER; -+ x->dereference = DEREF_NEVER; -+ x->unlink_dest_before_opening = false; -+ x->unlink_dest_after_failed_open = false; -+ x->hard_link = false; -+ x->interactive = I_UNSPECIFIED; -+ x->move_mode = true; -+ x->one_file_system = false; -+ x->preserve_ownership = true; -+ x->preserve_links = true; -+ x->preserve_mode = true; -+ x->preserve_timestamps = true; -+ x->preserve_security_context = selinux_enabled; -+ x->reduce_diagnostics = false; -+ x->require_preserve = false; /* FIXME: maybe make this an option */ -+ x->require_preserve_context = false; -+ x->preserve_xattr = true; -+ x->require_preserve_xattr = false; -+ x->recursive = true; -+ x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */ -+ x->symbolic_link = false; -+ x->set_mode = false; -+ x->mode = 0; -+ x->stdin_tty = isatty (STDIN_FILENO); -+ -+ x->open_dangling_dest_symlink = false; -+ x->update = false; -+ x->verbose = false; -+ x->dest_info = NULL; -+ x->src_info = NULL; -+} -+ -+/* FILE is the last operand of this command. Return true if FILE is a -+ directory. But report an error if there is a problem accessing FILE, other -+ than nonexistence (errno == ENOENT). */ -+ -+static bool -+target_directory_operand (char const *file) -+{ -+ struct stat st; -+ int err = (stat (file, &st) == 0 ? 0 : errno); -+ bool is_a_dir = !err && S_ISDIR (st.st_mode); -+ if (err && err != ENOENT) -+ error (EXIT_FAILURE, err, _("accessing %s"), quote (file)); -+ return is_a_dir; -+} -+ -+/* Move SOURCE onto DEST. Handles cross-file-system moves. -+ If SOURCE is a directory, DEST must not exist. -+ Return true if successful. */ -+ -+static bool -+do_move (const char *source, const char *dest, const struct cp_options *x) ++print_scontext_format (const struct fileinfo *f) +{ -+ bool copy_into_self; -+ bool rename_succeeded; -+ bool ok = copy (source, dest, false, x, ©_into_self, &rename_succeeded); -+ -+ if (ok) -+ { -+ char const *dir_to_remove; -+ if (copy_into_self) -+ { -+ /* In general, when copy returns with copy_into_self set, SOURCE is -+ the same as, or a parent of DEST. In this case we know it's a -+ parent. It doesn't make sense to move a directory into itself, and -+ besides in some situations doing so would give highly nonintuitive -+ results. Run this `mkdir b; touch a c; mv * b' in an empty -+ directory. Here's the result of running echo `find b -print`: -+ b b/a b/b b/b/a b/c. Notice that only file `a' was copied -+ into b/b. Handle this by giving a diagnostic, removing the -+ copied-into-self directory, DEST (`b/b' in the example), -+ and failing. */ -+ -+ dir_to_remove = NULL; -+ ok = false; -+ } -+ else if (rename_succeeded) -+ { -+ /* No need to remove anything. SOURCE was successfully -+ renamed to DEST. Or the user declined to rename a file. */ -+ dir_to_remove = NULL; -+ } -+ else -+ { -+ /* This may mean SOURCE and DEST referred to different devices. -+ It may also conceivably mean that even though they referred -+ to the same device, rename wasn't implemented for that device. -+ -+ E.g., (from Joel N. Weber), -+ [...] there might someday be cases where you can't rename -+ but you can copy where the device name is the same, especially -+ on Hurd. Consider an ftpfs with a primitive ftp server that -+ supports uploading, downloading and deleting, but not renaming. -+ -+ Also, note that comparing device numbers is not a reliable -+ check for `can-rename'. Some systems can be set up so that -+ files from many different physical devices all have the same -+ st_dev field. This is a feature of some NFS mounting -+ configurations. -+ -+ We reach this point if SOURCE has been successfully copied -+ to DEST. Now we have to remove SOURCE. -+ -+ This function used to resort to copying only when rename -+ failed and set errno to EXDEV. */ -+ -+ dir_to_remove = source; -+ } ++ char modebuf[12]; + -+ if (dir_to_remove != NULL) -+ { -+ struct rm_options rm_options; -+ enum RM_status status; -+ char const *dir[2]; ++ /* 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. */ + -+ rm_option_init (&rm_options); -+ rm_options.verbose = x->verbose; -+ dir[0] = dir_to_remove; -+ dir[1] = NULL; ++ char init_bigbuf[7 * LONGEST_HUMAN_READABLE + 10 + 9 + 1]; ++ char *buf = init_bigbuf; ++ char *p; + -+ status = rm ((void*) dir, &rm_options); -+ assert (VALID_STATUS (status)); -+ if (status == RM_ERROR) -+ ok = false; -+ } -+ } ++ p = buf; + -+ return ok; -+} ++ if ( print_scontext ) { /* zero means terse listing */ ++ filemodestring (&f->stat, modebuf); ++ if (! any_has_acl) ++ modebuf[10] = '\0'; ++ else if (f->acl_type == ACL_T_SELINUX_ONLY) ++ modebuf[10] = '.'; ++ else if (f->acl_type == ACL_T_YES) ++ modebuf[10] = '+'; ++ modebuf[11] = '\0'; + -+/* Move file SOURCE onto DEST. Handles the case when DEST is a directory. -+ Treat DEST as a directory if DEST_IS_DIR. -+ Return true if successful. */ ++ /* print mode */ + -+static bool -+movefile (char *source, char *dest, bool dest_is_dir, -+ const struct cp_options *x) -+{ -+ bool ok; ++ (void) sprintf (p, "%s ", modebuf); ++ p += strlen (p); + -+ /* This code was introduced to handle the ambiguity in the semantics -+ of mv that is induced by the varying semantics of the rename function. -+ Some systems (e.g., GNU/Linux) have a rename function that honors a -+ trailing slash, while others (like Solaris 5,6,7) have a rename -+ function that ignores a trailing slash. I believe the GNU/Linux -+ rename semantics are POSIX and susv2 compliant. */ ++ /* print standard user and group */ + -+ if (remove_trailing_slashes) -+ strip_trailing_slashes (source); ++ 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; ++ } + -+ if (dest_is_dir) -+ { -+ /* Treat DEST as a directory; build the full filename. */ -+ char const *src_basename = last_component (source); -+ char *new_dest = file_name_concat (dest, src_basename, NULL); -+ strip_trailing_slashes (new_dest); -+ ok = do_move (source, new_dest, x); -+ free (new_dest); -+ } -+ else -+ { -+ ok = do_move (source, dest, x); -+ } ++ (void) sprintf (p, "%-32s ", f->scontext ?: ""); ++ p += strlen (p); + -+ return ok; -+} ++ DIRED_INDENT (); ++ DIRED_FPUTS (buf, stdout, p - buf); ++ size_t w = print_name_with_quoting (f->name, FILE_OR_LINK_MODE(f), f->linkok, ++ f->stat_ok, f->filetype, &dired_obstack, f->stat.st_nlink, p - buf); + -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("\ -+Usage: %s [OPTION]... [-T] SOURCE DEST\n\ -+ or: %s [OPTION]... SOURCE... DIRECTORY\n\ -+ or: %s [OPTION]... -t DIRECTORY SOURCE...\n\ -+"), -+ program_name, program_name, program_name); -+ fputs (_("\ -+Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+Mandatory arguments to long options are mandatory for short options too.\n\ -+"), stdout); -+ fputs (_("\ -+ --backup[=CONTROL] make a backup of each existing destination file\n\ -+ -b like --backup but does not accept an argument\n\ -+ -f, --force do not prompt before overwriting\n\ -+ -i, --interactive prompt before overwrite\n\ -+ -n, --no-clobber do not overwrite an existing file\n\ -+If you specify more than one of -i, -f, -n, only the final one takes effect.\n\ -+"), stdout); -+ fputs (_("\ -+ --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\ -+ argument\n\ -+ -S, --suffix=SUFFIX override the usual backup suffix\n\ -+"), stdout); -+ fputs (_("\ -+ -t, --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\ -+ -T, --no-target-directory treat DEST as a normal file\n\ -+ -u, --update move only when the SOURCE file is newer\n\ -+ than the destination file or when the\n\ -+ destination file is missing\n\ -+ -v, --verbose explain what is being done\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ fputs (_("\ -+\n\ -+The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ -+The version control method may be selected via the --backup option or through\n\ -+the VERSION_CONTROL environment variable. Here are the values:\n\ -+\n\ -+"), stdout); -+ fputs (_("\ -+ none, off never make backups (even if --backup is given)\n\ -+ numbered, t make numbered backups\n\ -+ existing, nil numbered if numbered backups exist, simple otherwise\n\ -+ simple, never always make simple backups\n\ -+"), stdout); -+ emit_ancillary_info (); -+ } -+ exit (status); ++ 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, f->stat.st_nlink, (p-buf) + w + 4 ); ++ 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); ++ } +} + -+int -+main (int argc, char **argv) -+{ -+ int c; -+ bool ok; -+ bool make_backups = false; -+ char *backup_suffix_string; -+ char *version_control_string = NULL; -+ struct cp_options x; -+ char *target_directory = NULL; -+ bool no_target_directory = false; -+ int n_files; -+ char **file; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdin); -+ -+ cp_option_init (&x); -+ -+ /* Try to disable the ability to unlink a directory. */ -+ priv_set_remove_linkdir (); -+ -+ /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless -+ we'll actually use backup_suffix_string. */ -+ backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); -+ -+ while ((c = getopt_long (argc, argv, "bfint:uvS:T", long_options, NULL)) -+ != -1) -+ { -+ switch (c) -+ { -+ case 'b': -+ make_backups = true; -+ if (optarg) -+ version_control_string = optarg; -+ break; -+ case 'f': -+ x.interactive = I_ALWAYS_YES; -+ break; -+ case 'i': -+ x.interactive = I_ASK_USER; -+ break; -+ case 'n': -+ x.interactive = I_ALWAYS_NO; -+ break; -+ case STRIP_TRAILING_SLASHES_OPTION: -+ remove_trailing_slashes = true; -+ break; -+ case 't': -+ if (target_directory) -+ error (EXIT_FAILURE, 0, _("multiple target directories specified")); -+ else -+ { -+ struct stat st; -+ if (stat (optarg, &st) != 0) -+ error (EXIT_FAILURE, errno, _("accessing %s"), quote (optarg)); -+ if (! S_ISDIR (st.st_mode)) -+ error (EXIT_FAILURE, 0, _("target %s is not a directory"), -+ quote (optarg)); -+ } -+ target_directory = optarg; -+ break; -+ case 'T': -+ no_target_directory = true; -+ break; -+ case 'u': -+ x.update = true; -+ break; -+ case 'v': -+ x.verbose = true; -+ break; -+ case 'S': -+ make_backups = true; -+ backup_suffix_string = optarg; -+ break; -+ case_GETOPT_HELP_CHAR; -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ n_files = argc - optind; -+ file = argv + optind; -+ -+ if (n_files <= !target_directory) -+ { -+ if (n_files <= 0) -+ error (0, 0, _("missing file operand")); -+ else -+ error (0, 0, _("missing destination file operand after %s"), -+ quote (file[0])); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (no_target_directory) -+ { -+ if (target_directory) -+ error (EXIT_FAILURE, 0, -+ _("cannot combine --target-directory (-t) " -+ "and --no-target-directory (-T)")); -+ if (2 < n_files) -+ { -+ error (0, 0, _("extra operand %s"), quote (file[2])); -+ usage (EXIT_FAILURE); -+ } -+ } -+ else if (!target_directory) -+ { -+ assert (2 <= n_files); -+ if (target_directory_operand (file[n_files - 1])) -+ target_directory = file[--n_files]; -+ else if (2 < n_files) -+ error (EXIT_FAILURE, 0, _("target %s is not a directory"), -+ quote (file[n_files - 1])); -+ } -+ -+ if (make_backups && x.interactive == I_ALWAYS_NO) -+ { -+ error (0, 0, -+ _("options --backup and --no-clobber are mutually exclusive")); -+ usage (EXIT_FAILURE); -+ } -+ -+ if (backup_suffix_string) -+ simple_backup_suffix = xstrdup (backup_suffix_string); -+ -+ x.backup_type = (make_backups -+ ? xget_version (_("backup type"), -+ version_control_string) -+ : no_backups); -+ -+ hash_init (); -+ -+ if (target_directory) + /* Print information about F in long format. */ + static void + print_long_format (const struct fileinfo *f) +@@ -3659,9 +3758,15 @@ print_long_format (const struct fileinfo + The latter is wrong when nlink_width is zero. */ + p += strlen (p); + ++ if (print_scontext) + { -+ int i; -+ -+ /* Initialize the hash table only if we'll need it. -+ The problem it is used to detect can arise only if there are -+ two or more files to move. */ -+ if (2 <= n_files) -+ dest_info_init (&x); -+ -+ ok = true; -+ for (i = 0; i < n_files; ++i) -+ ok &= movefile (file[i], target_directory, true, &x); ++ sprintf (p, "%-32s ", f->scontext ? f->scontext : ""); ++ p += strlen (p); + } -+ else -+ ok = movefile (file[0], file[1], false, &x); + -+ exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); -+} + DIRED_INDENT (); + +- if (print_owner || print_group || print_author || print_scontext) ++ if (print_owner || print_group || print_author) + { + DIRED_FPUTS (buf, stdout, p - buf); + +@@ -3674,9 +3779,6 @@ print_long_format (const struct fileinfo + if (print_author) + format_user (f->stat.st_author, author_width, f->stat_ok); + +- if (print_scontext) +- format_user_or_group (f->scontext, 0, scontext_width); +- + p = buf; + } + +@@ -4020,9 +4122,6 @@ print_file_name_and_frills (const struct + : human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts, + ST_NBLOCKSIZE, output_block_size)); + +- if (print_scontext) +- printf ("%*s ", format == with_commas ? 0 : scontext_width, f->scontext); +- + size_t width = print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), + f->linkok, f->stat_ok, f->filetype, + NULL, f->stat.st_nlink, start_col); +@@ -4241,9 +4340,6 @@ length_of_file_name_and_frills (const st + output_block_size)) + : block_size_width); + +- if (print_scontext) +- len += 1 + (format == with_commas ? strlen (f->scontext) : scontext_width); +- + quote_name (NULL, f->name, filename_quoting_options, &name_width); + len += name_width; + +@@ -4674,9 +4770,16 @@ Mandatory arguments to long options are + -w, --width=COLS assume screen width instead of current value\n\ + -x list entries by lines instead of by columns\n\ + -X sort alphabetically by entry extension\n\ +- -Z, --context print any SELinux security context of each file\n\ + -1 list one file per line\n\ + "), stdout); ++ fputs(_("\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\ ++"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + emit_size_note (); +diff -urNp coreutils-8.0-orig/src/mkdir.c coreutils-8.0/src/mkdir.c +--- coreutils-8.0-orig/src/mkdir.c 2009-09-23 10:25:44.000000000 +0200 ++++ coreutils-8.0/src/mkdir.c 2009-10-07 10:10:11.000000000 +0200 +@@ -38,6 +38,7 @@ + static struct option const longopts[] = + { + {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, ++ {"context", required_argument, NULL, 'Z'}, + {"mode", required_argument, NULL, 'm'}, + {"parents", no_argument, NULL, 'p'}, + {"verbose", no_argument, NULL, 'v'}, +diff -urNp coreutils-8.0-orig/src/mknod.c coreutils-8.0/src/mknod.c +--- coreutils-8.0-orig/src/mknod.c 2009-09-23 10:25:44.000000000 +0200 ++++ coreutils-8.0/src/mknod.c 2009-10-07 10:10:11.000000000 +0200 +@@ -35,7 +35,7 @@ + + static struct option const longopts[] = + { +- {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, ++ {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, + {"mode", required_argument, NULL, 'm'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, +diff -urNp coreutils-8.0-orig/src/mv.c coreutils-8.0/src/mv.c +--- coreutils-8.0-orig/src/mv.c 2009-09-23 10:25:44.000000000 +0200 ++++ coreutils-8.0/src/mv.c 2009-10-07 10:10:11.000000000 +0200 +@@ -118,6 +118,7 @@ cp_option_init (struct cp_options *x) + x->preserve_mode = true; + x->preserve_timestamps = true; + x->preserve_security_context = selinux_enabled; ++ x->set_security_context = false; + x->reduce_diagnostics = false; + x->require_preserve = false; /* FIXME: maybe make this an option */ + x->require_preserve_context = false; diff -urNp coreutils-8.0-orig/src/runcon.c coreutils-8.0/src/runcon.c --- coreutils-8.0-orig/src/runcon.c 2009-10-06 10:55:34.000000000 +0200 +++ coreutils-8.0/src/runcon.c 2009-10-07 10:10:11.000000000 +0200 @@ -11442,1092 +796,6 @@ diff -urNp coreutils-8.0-orig/src/stat.c coreutils-8.0/src/stat.c exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } -diff -urNp coreutils-8.0-orig/src/stat.c.orig coreutils-8.0/src/stat.c.orig ---- coreutils-8.0-orig/src/stat.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ coreutils-8.0/src/stat.c.orig 2009-09-29 16:25:44.000000000 +0200 -@@ -0,0 +1,1082 @@ -+/* stat.c -- display file or file system status -+ Copyright (C) 2001-2009 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 . -+ -+ Written by Michael Meskes. */ -+ -+#include -+ -+/* Keep this conditional in sync with the similar conditional in -+ ../m4/stat-prog.m4. */ -+#if (STAT_STATVFS \ -+ && (HAVE_STRUCT_STATVFS_F_BASETYPE || HAVE_STRUCT_STATVFS_F_FSTYPENAME \ -+ || (! HAVE_STRUCT_STATFS_F_FSTYPENAME && HAVE_STRUCT_STATVFS_F_TYPE))) -+# define USE_STATVFS 1 -+#else -+# define USE_STATVFS 0 -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#if USE_STATVFS -+# include -+#elif HAVE_SYS_VFS_H -+# include -+#elif HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H -+/* NOTE: freebsd5.0 needs sys/param.h and sys/mount.h for statfs. -+ It does have statvfs.h, but shouldn't use it, since it doesn't -+ HAVE_STRUCT_STATVFS_F_BASETYPE. So find a clean way to fix it. */ -+/* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */ -+# include -+# include -+# if HAVE_NETINET_IN_H && HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H -+/* Ultrix 4.4 needs these for the declaration of struct statfs. */ -+# include -+# include -+# include -+# endif -+#elif HAVE_OS_H /* BeOS */ -+# include -+#endif -+#include -+ -+#include "system.h" -+ -+#include "error.h" -+#include "filemode.h" -+#include "file-type.h" -+#include "fs.h" -+#include "getopt.h" -+#include "quote.h" -+#include "quotearg.h" -+#include "stat-time.h" -+#include "strftime.h" -+#include "areadlink.h" -+ -+#define alignof(type) offsetof (struct { char c; type x; }, x) -+ -+#if USE_STATVFS -+# define STRUCT_STATVFS struct statvfs -+# define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER -+# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE -+# if HAVE_STRUCT_STATVFS_F_NAMEMAX -+# define SB_F_NAMEMAX(S) ((S)->f_namemax) -+# endif -+# define STATFS statvfs -+# define STATFS_FRSIZE(S) ((S)->f_frsize) -+#else -+# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE -+# if HAVE_STRUCT_STATFS_F_NAMELEN -+# define SB_F_NAMEMAX(S) ((S)->f_namelen) -+# endif -+# define STATFS statfs -+# if HAVE_OS_H /* BeOS */ -+/* BeOS has a statvfs function, but it does not return sensible values -+ for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and -+ f_fstypename. Use 'struct fs_info' instead. */ -+static int -+statfs (char const *filename, struct fs_info *buf) -+{ -+ dev_t device = dev_for_path (filename); -+ if (device < 0) -+ { -+ errno = (device == B_ENTRY_NOT_FOUND ? ENOENT -+ : device == B_BAD_VALUE ? EINVAL -+ : device == B_NAME_TOO_LONG ? ENAMETOOLONG -+ : device == B_NO_MEMORY ? ENOMEM -+ : device == B_FILE_ERROR ? EIO -+ : 0); -+ return -1; -+ } -+ /* If successful, buf->dev will be == device. */ -+ return fs_stat_dev (device, buf); -+} -+# define f_fsid dev -+# define f_blocks total_blocks -+# define f_bfree free_blocks -+# define f_bavail free_blocks -+# define f_bsize io_size -+# define f_files total_nodes -+# define f_ffree free_nodes -+# define STRUCT_STATVFS struct fs_info -+# define STRUCT_STATXFS_F_FSID_IS_INTEGER true -+# define STATFS_FRSIZE(S) ((S)->block_size) -+# else -+# define STRUCT_STATVFS struct statfs -+# define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER -+# define STATFS_FRSIZE(S) 0 -+# endif -+#endif -+ -+#ifdef SB_F_NAMEMAX -+# define OUT_NAMEMAX out_uint -+#else -+/* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */ -+# define SB_F_NAMEMAX(S) "*" -+# define OUT_NAMEMAX out_string -+#endif -+ -+#if HAVE_STRUCT_STATVFS_F_BASETYPE -+# define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype -+#else -+# if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME -+# define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename -+# elif HAVE_OS_H /* BeOS */ -+# define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name -+# endif -+#endif -+ -+/* FIXME: these are used by printf.c, too */ -+#define isodigit(c) ('0' <= (c) && (c) <= '7') -+#define octtobin(c) ((c) - '0') -+#define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \ -+ (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0') -+ -+#define PROGRAM_NAME "stat" -+ -+#define AUTHORS proper_name ("Michael Meskes") -+ -+enum -+{ -+ PRINTF_OPTION = CHAR_MAX + 1 -+}; -+ -+static struct option const long_options[] = -+{ -+ {"context", no_argument, 0, 'Z'}, -+ {"dereference", no_argument, NULL, 'L'}, -+ {"file-system", no_argument, NULL, 'f'}, -+ {"format", required_argument, NULL, 'c'}, -+ {"printf", required_argument, NULL, PRINTF_OPTION}, -+ {"terse", no_argument, NULL, 't'}, -+ {GETOPT_HELP_OPTION_DECL}, -+ {GETOPT_VERSION_OPTION_DECL}, -+ {NULL, 0, NULL, 0} -+}; -+ -+/* Whether to follow symbolic links; True for --dereference (-L). */ -+static bool follow_links; -+ -+/* Whether to interpret backslash-escape sequences. -+ True for --printf=FMT, not for --format=FMT (-c). */ -+static bool interpret_backslash_escapes; -+ -+/* The trailing delimiter string: -+ "" for --printf=FMT, "\n" for --format=FMT (-c). */ -+static char const *trailing_delim = ""; -+ -+/* Return the type of the specified file system. -+ Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris). -+ Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0). -+ Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2). -+ Still others have neither and have to get by with f_type (GNU/Linux). -+ But f_type may only exist in statfs (Cygwin). */ -+static char const * -+human_fstype (STRUCT_STATVFS const *statfsbuf) -+{ -+#ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME -+ return statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME; -+#else -+ switch (statfsbuf->f_type) -+ { -+# if defined __linux__ -+ -+ /* Compare with what's in libc: -+ f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h -+ sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \ -+ | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \ -+ -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \ -+ | sort > sym_libc -+ perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \ -+ -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \ -+ | sort > sym_stat -+ diff -u sym_stat sym_libc -+ */ -+ -+ /* Also sync from the list in "man 2 statfs". */ -+ -+ /* IMPORTANT NOTE: Each of the following `case S_MAGIC_...:' -+ statements must be followed by a hexadecimal constant in -+ a comment. The S_MAGIC_... name and constant are automatically -+ combined to produce the #define directives in fs.h. */ -+ -+ case S_MAGIC_ADFS: /* 0xADF5 */ -+ return "adfs"; -+ case S_MAGIC_AFFS: /* 0xADFF */ -+ return "affs"; -+ case S_MAGIC_AUTOFS: /* 0x187 */ -+ return "autofs"; -+ case S_MAGIC_BEFS: /* 0x42465331 */ -+ return "befs"; -+ case S_MAGIC_BFS: /* 0x1BADFACE */ -+ return "bfs"; -+ case S_MAGIC_BINFMT_MISC: /* 0x42494e4d */ -+ return "binfmt_misc"; -+ case S_MAGIC_CODA: /* 0x73757245 */ -+ return "coda"; -+ case S_MAGIC_COH: /* 0x012FF7B7 */ -+ return "coh"; -+ case S_MAGIC_CRAMFS: /* 0x28CD3D45 */ -+ return "cramfs"; -+ case S_MAGIC_DEVFS: /* 0x1373 */ -+ return "devfs"; -+ case S_MAGIC_DEVPTS: /* 0x1CD1 */ -+ return "devpts"; -+ case S_MAGIC_EFS: /* 0x414A53 */ -+ return "efs"; -+ case S_MAGIC_EXT: /* 0x137D */ -+ return "ext"; -+ case S_MAGIC_EXT2: /* 0xEF53 */ -+ return "ext2/ext3"; -+ case S_MAGIC_EXT2_OLD: /* 0xEF51 */ -+ return "ext2"; -+ case S_MAGIC_FAT: /* 0x4006 */ -+ return "fat"; -+ case S_MAGIC_FUSECTL: /* 0x65735543 */ -+ return "fusectl"; -+ case S_MAGIC_HPFS: /* 0xF995E849 */ -+ return "hpfs"; -+ case S_MAGIC_HUGETLBFS: /* 0x958458f6 */ -+ return "hugetlbfs"; -+ case S_MAGIC_ISOFS: /* 0x9660 */ -+ return "isofs"; -+ case S_MAGIC_ISOFS_R_WIN: /* 0x4004 */ -+ return "isofs"; -+ case S_MAGIC_ISOFS_WIN: /* 0x4000 */ -+ return "isofs"; -+ case S_MAGIC_JFFS2: /* 0x72B6 */ -+ return "jffs2"; -+ case S_MAGIC_JFFS: /* 0x07C0 */ -+ return "jffs"; -+ case S_MAGIC_JFS: /* 0x3153464A */ -+ return "jfs"; -+ case S_MAGIC_LUSTRE: /* 0x0BD00BD0 */ -+ return "lustre"; -+ case S_MAGIC_MINIX: /* 0x137F */ -+ return "minix"; -+ case S_MAGIC_MINIX_30: /* 0x138F */ -+ return "minix (30 char.)"; -+ case S_MAGIC_MINIX_V2: /* 0x2468 */ -+ return "minix v2"; -+ case S_MAGIC_MINIX_V2_30: /* 0x2478 */ -+ return "minix v2 (30 char.)"; -+ case S_MAGIC_MSDOS: /* 0x4D44 */ -+ return "msdos"; -+ case S_MAGIC_NCP: /* 0x564C */ -+ return "novell"; -+ case S_MAGIC_NFS: /* 0x6969 */ -+ return "nfs"; -+ case S_MAGIC_NFSD: /* 0x6E667364 */ -+ return "nfsd"; -+ case S_MAGIC_NTFS: /* 0x5346544E */ -+ return "ntfs"; -+ case S_MAGIC_OPENPROM: /* 0x9fa1 */ -+ return "openprom"; -+ case S_MAGIC_PROC: /* 0x9FA0 */ -+ return "proc"; -+ case S_MAGIC_QNX4: /* 0x002F */ -+ return "qnx4"; -+ case S_MAGIC_RAMFS: /* 0x858458F6 */ -+ return "ramfs"; -+ case S_MAGIC_REISERFS: /* 0x52654973 */ -+ return "reiserfs"; -+ case S_MAGIC_ROMFS: /* 0x7275 */ -+ return "romfs"; -+ case S_MAGIC_SMB: /* 0x517B */ -+ return "smb"; -+ case S_MAGIC_SQUASHFS: /* 0x73717368 */ -+ return "squashfs"; -+ case S_MAGIC_SYSFS: /* 0x62656572 */ -+ return "sysfs"; -+ case S_MAGIC_SYSV2: /* 0x012FF7B6 */ -+ return "sysv2"; -+ case S_MAGIC_SYSV4: /* 0x012FF7B5 */ -+ return "sysv4"; -+ case S_MAGIC_TMPFS: /* 0x1021994 */ -+ return "tmpfs"; -+ case S_MAGIC_UDF: /* 0x15013346 */ -+ return "udf"; -+ case S_MAGIC_UFS: /* 0x00011954 */ -+ return "ufs"; -+ case S_MAGIC_UFS_BYTESWAPPED: /* 0x54190100 */ -+ return "ufs"; -+ case S_MAGIC_USBDEVFS: /* 0x9FA2 */ -+ return "usbdevfs"; -+ case S_MAGIC_VXFS: /* 0xA501FCF5 */ -+ return "vxfs"; -+ case S_MAGIC_XENIX: /* 0x012FF7B4 */ -+ return "xenix"; -+ case S_MAGIC_XFS: /* 0x58465342 */ -+ return "xfs"; -+ case S_MAGIC_XIAFS: /* 0x012FD16D */ -+ return "xia"; -+ -+# elif __GNU__ -+ case FSTYPE_UFS: -+ return "ufs"; -+ case FSTYPE_NFS: -+ return "nfs"; -+ case FSTYPE_GFS: -+ return "gfs"; -+ case FSTYPE_LFS: -+ return "lfs"; -+ case FSTYPE_SYSV: -+ return "sysv"; -+ case FSTYPE_FTP: -+ return "ftp"; -+ case FSTYPE_TAR: -+ return "tar"; -+ case FSTYPE_AR: -+ return "ar"; -+ case FSTYPE_CPIO: -+ return "cpio"; -+ case FSTYPE_MSLOSS: -+ return "msloss"; -+ case FSTYPE_CPM: -+ return "cpm"; -+ case FSTYPE_HFS: -+ return "hfs"; -+ case FSTYPE_DTFS: -+ return "dtfs"; -+ case FSTYPE_GRFS: -+ return "grfs"; -+ case FSTYPE_TERM: -+ return "term"; -+ case FSTYPE_DEV: -+ return "dev"; -+ case FSTYPE_PROC: -+ return "proc"; -+ case FSTYPE_IFSOCK: -+ return "ifsock"; -+ case FSTYPE_AFS: -+ return "afs"; -+ case FSTYPE_DFS: -+ return "dfs"; -+ case FSTYPE_PROC9: -+ return "proc9"; -+ case FSTYPE_SOCKET: -+ return "socket"; -+ case FSTYPE_MISC: -+ return "misc"; -+ case FSTYPE_EXT2FS: -+ return "ext2/ext3"; -+ case FSTYPE_HTTP: -+ return "http"; -+ case FSTYPE_MEMFS: -+ return "memfs"; -+ case FSTYPE_ISO9660: -+ return "iso9660"; -+# endif -+ default: -+ { -+ unsigned long int type = statfsbuf->f_type; -+ static char buf[sizeof "UNKNOWN (0x%lx)" - 3 -+ + (sizeof type * CHAR_BIT + 3) / 4]; -+ sprintf (buf, "UNKNOWN (0x%lx)", type); -+ return buf; -+ } -+ } -+#endif -+} -+ -+static char * -+human_access (struct stat const *statbuf) -+{ -+ static char modebuf[12]; -+ filemodestring (statbuf, modebuf); -+ modebuf[10] = 0; -+ return modebuf; -+} -+ -+static char * -+human_time (struct timespec t) -+{ -+ static char str[MAX (INT_BUFSIZE_BOUND (intmax_t), -+ (INT_STRLEN_BOUND (int) /* YYYY */ -+ + 1 /* because YYYY might equal INT_MAX + 1900 */ -+ + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))]; -+ struct tm const *tm = localtime (&t.tv_sec); -+ if (tm == NULL) -+ return timetostr (t.tv_sec, str); -+ nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, t.tv_nsec); -+ return str; -+} -+ -+static void -+out_string (char *pformat, size_t prefix_len, char const *arg) -+{ -+ strcpy (pformat + prefix_len, "s"); -+ printf (pformat, arg); -+} -+static void -+out_int (char *pformat, size_t prefix_len, intmax_t arg) -+{ -+ strcpy (pformat + prefix_len, PRIdMAX); -+ printf (pformat, arg); -+} -+static void -+out_uint (char *pformat, size_t prefix_len, uintmax_t arg) -+{ -+ strcpy (pformat + prefix_len, PRIuMAX); -+ printf (pformat, arg); -+} -+static void -+out_uint_o (char *pformat, size_t prefix_len, uintmax_t arg) -+{ -+ strcpy (pformat + prefix_len, PRIoMAX); -+ printf (pformat, arg); -+} -+static void -+out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg) -+{ -+ strcpy (pformat + prefix_len, PRIxMAX); -+ 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) -+{ -+ STRUCT_STATVFS const *statfsbuf = data; -+ -+ switch (m) -+ { -+ case 'n': -+ out_string (pformat, prefix_len, filename); -+ break; -+ -+ case 'i': -+ { -+#if STRUCT_STATXFS_F_FSID_IS_INTEGER -+ uintmax_t fsid = statfsbuf->f_fsid; -+#else -+ typedef unsigned int fsid_word; -+ verify (alignof (STRUCT_STATVFS) % alignof (fsid_word) == 0); -+ verify (offsetof (STRUCT_STATVFS, f_fsid) % alignof (fsid_word) == 0); -+ verify (sizeof statfsbuf->f_fsid % alignof (fsid_word) == 0); -+ fsid_word const *p = (fsid_word *) &statfsbuf->f_fsid; -+ -+ /* Assume a little-endian word order, as that is compatible -+ with glibc's statvfs implementation. */ -+ uintmax_t fsid = 0; -+ int words = sizeof statfsbuf->f_fsid / sizeof *p; -+ int i; -+ for (i = 0; i < words && i * sizeof *p < sizeof fsid; i++) -+ { -+ uintmax_t u = p[words - 1 - i]; -+ fsid |= u << (i * CHAR_BIT * sizeof *p); -+ } -+#endif -+ out_uint_x (pformat, prefix_len, fsid); -+ } -+ break; -+ -+ case 'l': -+ OUT_NAMEMAX (pformat, prefix_len, SB_F_NAMEMAX (statfsbuf)); -+ break; -+ case 't': -+#if HAVE_STRUCT_STATXFS_F_TYPE -+ out_uint_x (pformat, prefix_len, statfsbuf->f_type); -+#else -+ fputc ('?', stdout); -+#endif -+ break; -+ case 'T': -+ out_string (pformat, prefix_len, human_fstype (statfsbuf)); -+ break; -+ case 'b': -+ out_int (pformat, prefix_len, statfsbuf->f_blocks); -+ break; -+ case 'f': -+ out_int (pformat, prefix_len, statfsbuf->f_bfree); -+ break; -+ case 'a': -+ out_int (pformat, prefix_len, statfsbuf->f_bavail); -+ break; -+ case 's': -+ out_uint (pformat, prefix_len, statfsbuf->f_bsize); -+ break; -+ case 'S': -+ { -+ uintmax_t frsize = STATFS_FRSIZE (statfsbuf); -+ if (! frsize) -+ frsize = statfsbuf->f_bsize; -+ out_uint (pformat, prefix_len, frsize); -+ } -+ break; -+ case 'c': -+ out_uint (pformat, prefix_len, statfsbuf->f_files); -+ break; -+ case 'd': -+ out_int (pformat, prefix_len, statfsbuf->f_ffree); -+ break; -+ case 'C': -+ out_file_context (filename, pformat, prefix_len); -+ break; -+ default: -+ fputc ('?', stdout); -+ break; -+ } -+} -+ -+/* print stat info */ -+static void -+print_stat (char *pformat, size_t prefix_len, char m, -+ char const *filename, void const *data) -+{ -+ struct stat *statbuf = (struct stat *) data; -+ struct passwd *pw_ent; -+ struct group *gw_ent; -+ -+ switch (m) -+ { -+ case 'n': -+ out_string (pformat, prefix_len, filename); -+ break; -+ case 'N': -+ out_string (pformat, prefix_len, quote (filename)); -+ if (S_ISLNK (statbuf->st_mode)) -+ { -+ char *linkname = areadlink_with_size (filename, statbuf->st_size); -+ if (linkname == NULL) -+ { -+ error (0, errno, _("cannot read symbolic link %s"), -+ quote (filename)); -+ return; -+ } -+ printf (" -> "); -+ out_string (pformat, prefix_len, quote (linkname)); -+ } -+ break; -+ case 'd': -+ out_uint (pformat, prefix_len, statbuf->st_dev); -+ break; -+ case 'D': -+ out_uint_x (pformat, prefix_len, statbuf->st_dev); -+ break; -+ case 'i': -+ out_uint (pformat, prefix_len, statbuf->st_ino); -+ break; -+ case 'a': -+ out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS); -+ break; -+ case 'A': -+ out_string (pformat, prefix_len, human_access (statbuf)); -+ break; -+ case 'f': -+ out_uint_x (pformat, prefix_len, statbuf->st_mode); -+ break; -+ case 'F': -+ out_string (pformat, prefix_len, file_type (statbuf)); -+ break; -+ case 'h': -+ out_uint (pformat, prefix_len, statbuf->st_nlink); -+ break; -+ case 'u': -+ out_uint (pformat, prefix_len, statbuf->st_uid); -+ break; -+ case 'U': -+ setpwent (); -+ pw_ent = getpwuid (statbuf->st_uid); -+ out_string (pformat, prefix_len, -+ pw_ent ? pw_ent->pw_name : "UNKNOWN"); -+ break; -+ case 'g': -+ out_uint (pformat, prefix_len, statbuf->st_gid); -+ break; -+ case 'G': -+ setgrent (); -+ gw_ent = getgrgid (statbuf->st_gid); -+ out_string (pformat, prefix_len, -+ gw_ent ? gw_ent->gr_name : "UNKNOWN"); -+ break; -+ case 't': -+ out_uint_x (pformat, prefix_len, major (statbuf->st_rdev)); -+ break; -+ case 'T': -+ out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev)); -+ break; -+ case 's': -+ out_uint (pformat, prefix_len, statbuf->st_size); -+ break; -+ case 'B': -+ out_uint (pformat, prefix_len, ST_NBLOCKSIZE); -+ break; -+ case 'b': -+ out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf)); -+ break; -+ case 'o': -+ out_uint (pformat, prefix_len, statbuf->st_blksize); -+ break; -+ case 'x': -+ out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf))); -+ break; -+ case 'X': -+ if (TYPE_SIGNED (time_t)) -+ out_int (pformat, prefix_len, statbuf->st_atime); -+ else -+ out_uint (pformat, prefix_len, statbuf->st_atime); -+ break; -+ case 'y': -+ out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf))); -+ break; -+ case 'Y': -+ if (TYPE_SIGNED (time_t)) -+ out_int (pformat, prefix_len, statbuf->st_mtime); -+ else -+ out_uint (pformat, prefix_len, statbuf->st_mtime); -+ break; -+ case 'z': -+ out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf))); -+ break; -+ case 'Z': -+ if (TYPE_SIGNED (time_t)) -+ out_int (pformat, prefix_len, statbuf->st_ctime); -+ else -+ out_uint (pformat, prefix_len, statbuf->st_ctime); -+ break; -+ case 'C': -+ out_file_context (filename, pformat, prefix_len); -+ break; -+ default: -+ fputc ('?', stdout); -+ break; -+ } -+} -+ -+/* Output a single-character \ escape. */ -+ -+static void -+print_esc_char (char c) -+{ -+ switch (c) -+ { -+ case 'a': /* Alert. */ -+ c ='\a'; -+ break; -+ case 'b': /* Backspace. */ -+ c ='\b'; -+ break; -+ case 'f': /* Form feed. */ -+ c ='\f'; -+ break; -+ case 'n': /* New line. */ -+ c ='\n'; -+ break; -+ case 'r': /* Carriage return. */ -+ c ='\r'; -+ break; -+ case 't': /* Horizontal tab. */ -+ c ='\t'; -+ break; -+ case 'v': /* Vertical tab. */ -+ c ='\v'; -+ break; -+ case '"': -+ case '\\': -+ break; -+ default: -+ error (0, 0, _("warning: unrecognized escape `\\%c'"), c); -+ break; -+ } -+ putchar (c); -+} -+ -+static void -+print_it (char const *format, char const *filename, -+ 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. */ -+ enum -+ { -+ MAX_ADDITIONAL_BYTES = -+ (MAX (sizeof PRIdMAX, -+ MAX (sizeof PRIoMAX, MAX (sizeof PRIuMAX, sizeof PRIxMAX))) -+ - 1) -+ }; -+ size_t n_alloc = strlen (format) + MAX_ADDITIONAL_BYTES + 1; -+ char *dest = xmalloc (n_alloc); -+ char const *b; -+ for (b = format; *b; b++) -+ { -+ switch (*b) -+ { -+ case '%': -+ { -+ size_t len = strspn (b + 1, "#-+.I 0123456789"); -+ char const *fmt_char = b + len + 1; -+ memcpy (dest, b, len + 1); -+ -+ b = fmt_char; -+ switch (*fmt_char) -+ { -+ case '\0': -+ --b; -+ /* fall through */ -+ case '%': -+ if (0 < len) -+ { -+ dest[len + 1] = *fmt_char; -+ dest[len + 2] = '\0'; -+ error (EXIT_FAILURE, 0, _("%s: invalid directive"), -+ quotearg_colon (dest)); -+ } -+ putchar ('%'); -+ break; -+ default: -+ print_func (dest, len + 1, *fmt_char, filename, data); -+ break; -+ } -+ break; -+ } -+ -+ case '\\': -+ if ( ! interpret_backslash_escapes) -+ { -+ putchar ('\\'); -+ break; -+ } -+ ++b; -+ if (isodigit (*b)) -+ { -+ int esc_value = octtobin (*b); -+ int esc_length = 1; /* number of octal digits */ -+ for (++b; esc_length < 3 && isodigit (*b); -+ ++esc_length, ++b) -+ { -+ esc_value = esc_value * 8 + octtobin (*b); -+ } -+ putchar (esc_value); -+ --b; -+ } -+ else if (*b == 'x' && isxdigit (to_uchar (b[1]))) -+ { -+ int esc_value = hextobin (b[1]); /* Value of \xhh escape. */ -+ /* A hexadecimal \xhh escape sequence must have -+ 1 or 2 hex. digits. */ -+ ++b; -+ if (isxdigit (to_uchar (b[1]))) -+ { -+ ++b; -+ esc_value = esc_value * 16 + hextobin (*b); -+ } -+ putchar (esc_value); -+ } -+ else if (*b == '\0') -+ { -+ error (0, 0, _("warning: backslash at end of format")); -+ putchar ('\\'); -+ /* Arrange to exit the loop. */ -+ --b; -+ } -+ else -+ { -+ print_esc_char (*b); -+ } -+ break; -+ -+ default: -+ putchar (*b); -+ break; -+ } -+ } -+ free (dest); -+ -+ fputs (trailing_delim, stdout); -+} -+ -+/* Stat the file system and print what we find. */ -+static bool -+do_statfs (char const *filename, bool terse, char const *format) -+{ -+ STRUCT_STATVFS statfsbuf; -+ -+ if (STREQ (filename, "-")) -+ { -+ error (0, 0, _("using %s to denote standard input does not work" -+ " in file system mode"), quote (filename)); -+ return false; -+ } -+ -+ if (STATFS (filename, &statfsbuf) != 0) -+ { -+ error (0, errno, _("cannot read file system information for %s"), -+ quote (filename)); -+ return false; -+ } -+ -+ 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"); -+ } -+ -+ 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 terse, char const *format) -+{ -+ struct stat statbuf; -+ -+ if (STREQ (filename, "-")) -+ { -+ if (fstat (STDIN_FILENO, &statbuf) != 0) -+ { -+ error (0, errno, _("cannot stat standard input")); -+ return false; -+ } -+ } -+ else if ((follow_links ? stat : lstat) (filename, &statbuf) != 0) -+ { -+ error (0, errno, _("cannot stat %s"), quote (filename)); -+ return false; -+ } -+ -+ if (format == NULL) -+ { -+ if (terse) -+ { -+ format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; -+ } -+ else -+ { -+ /* Temporary hack to match original output until conditional -+ implemented. */ -+ if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode)) -+ { -+ 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" -+ "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); -+ return true; -+} -+ -+void -+usage (int status) -+{ -+ if (status != EXIT_SUCCESS) -+ fprintf (stderr, _("Try `%s --help' for more information.\n"), -+ program_name); -+ else -+ { -+ printf (_("Usage: %s [OPTION]... FILE...\n"), program_name); -+ fputs (_("\ -+Display file or file system status.\n\ -+\n\ -+ -L, --dereference follow links\n\ -+ -f, --file-system display file system status instead of file status\n\ -+"), stdout); -+ fputs (_("\ -+ -c --format=FORMAT use the specified FORMAT instead of the default;\n\ -+ output a newline after each use of FORMAT\n\ -+ --printf=FORMAT like --format, but interpret backslash escapes,\n\ -+ and do not output a mandatory trailing newline.\n\ -+ If you want a newline, include \\n in FORMAT.\n\ -+ -t, --terse print the information in terse form\n\ -+"), stdout); -+ fputs (HELP_OPTION_DESCRIPTION, stdout); -+ fputs (VERSION_OPTION_DESCRIPTION, stdout); -+ -+ fputs (_("\n\ -+The valid format sequences for files (without --file-system):\n\ -+\n\ -+ %a Access rights in octal\n\ -+ %A Access rights in human readable form\n\ -+ %b Number of blocks allocated (see %B)\n\ -+ %B The size in bytes of each block reported by %b\n\ -+ %C SELinux security context string\n\ -+"), stdout); -+ fputs (_("\ -+ %d Device number in decimal\n\ -+ %D Device number in hex\n\ -+ %f Raw mode in hex\n\ -+ %F File type\n\ -+ %g Group ID of owner\n\ -+ %G Group name of owner\n\ -+"), stdout); -+ fputs (_("\ -+ %h Number of hard links\n\ -+ %i Inode number\n\ -+ %n File name\n\ -+ %N Quoted file name with dereference if symbolic link\n\ -+ %o I/O block size\n\ -+ %s Total size, in bytes\n\ -+ %t Major device type in hex\n\ -+ %T Minor device type in hex\n\ -+"), stdout); -+ fputs (_("\ -+ %u User ID of owner\n\ -+ %U User name of owner\n\ -+ %x Time of last access\n\ -+ %X Time of last access as seconds since Epoch\n\ -+ %y Time of last modification\n\ -+ %Y Time of last modification as seconds since Epoch\n\ -+ %z Time of last change\n\ -+ %Z Time of last change as seconds since Epoch\n\ -+\n\ -+"), stdout); -+ -+ fputs (_("\ -+Valid format sequences for file systems:\n\ -+\n\ -+ %a Free blocks available to non-superuser\n\ -+ %b Total data blocks in file system\n\ -+ %c Total file nodes in file system\n\ -+ %d Free file nodes in file system\n\ -+ %f Free blocks in file system\n\ -+ %C SELinux security context string\n\ -+"), stdout); -+ fputs (_("\ -+ %i File System ID in hex\n\ -+ %l Maximum length of filenames\n\ -+ %n File name\n\ -+ %s Block size (for faster transfers)\n\ -+ %S Fundamental block size (for block counts)\n\ -+ %t Type in hex\n\ -+ %T Type in human readable form\n\ -+"), stdout); -+ printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME); -+ emit_ancillary_info (); -+ } -+ exit (status); -+} -+ -+int -+main (int argc, char *argv[]) -+{ -+ int c; -+ int i; -+ bool fs = false; -+ bool terse = false; -+ char *format = NULL; -+ bool ok = true; -+ -+ initialize_main (&argc, &argv); -+ set_program_name (argv[0]); -+ setlocale (LC_ALL, ""); -+ bindtextdomain (PACKAGE, LOCALEDIR); -+ textdomain (PACKAGE); -+ -+ atexit (close_stdout); -+ -+ while ((c = getopt_long (argc, argv, "c:fLtZ", long_options, NULL)) != -1) -+ { -+ switch (c) -+ { -+ case PRINTF_OPTION: -+ format = optarg; -+ interpret_backslash_escapes = true; -+ trailing_delim = ""; -+ break; -+ -+ case 'c': -+ format = optarg; -+ interpret_backslash_escapes = false; -+ trailing_delim = "\n"; -+ break; -+ -+ case 'L': -+ follow_links = true; -+ break; -+ -+ case 'f': -+ fs = true; -+ break; -+ -+ case 't': -+ terse = true; -+ break; -+ -+ case 'Z': /* FIXME: remove in 2010 */ -+ /* Ignore, for compatibility with distributions -+ that implemented this before upstream. -+ But warn of impending removal. */ -+ error (0, 0, -+ _("the --context (-Z) option is obsolete and will be removed\n" -+ "in a future release")); -+ break; -+ -+ case_GETOPT_HELP_CHAR; -+ -+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); -+ -+ default: -+ usage (EXIT_FAILURE); -+ } -+ } -+ -+ if (argc == optind) -+ { -+ error (0, 0, _("missing operand")); -+ usage (EXIT_FAILURE); -+ } -+ -+ for (i = optind; i < argc; i++) -+ ok &= (fs -+ ? do_statfs (argv[i], terse, format) -+ : do_stat (argv[i], terse, format)); -+ -+ exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); -+} diff -urNp coreutils-8.0-orig/tests/misc/selinux coreutils-8.0/tests/misc/selinux --- coreutils-8.0-orig/tests/misc/selinux 2009-09-01 13:01:16.000000000 +0200 +++ coreutils-8.0/tests/misc/selinux 2009-10-07 10:10:11.000000000 +0200 diff --git a/coreutils.spec b/coreutils.spec index 1937dff..cb36081 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -6,7 +6,7 @@ License: GPLv3+ 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.xz +Source0: ftp://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz Source101: coreutils-DIR_COLORS Source102: coreutils-DIR_COLORS.lightbgcolor Source103: coreutils-DIR_COLORS.256color