diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-09-30 18:22:54 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-09-30 18:22:54 +0400 |
commit | 08bc9e01c274a01d107b348f921e1c74dd04bd3a (patch) | |
tree | 25348bff03c29d9dd6c6dd96bf82c7c9f9265ccf /src | |
parent | b9c7373f203ab77c58cb6b131f8b58236ea337a2 (diff) | |
parent | c18578632fd3c9e513e613a86ba2b7c4ebee6c45 (diff) | |
download | coreutils-08bc9e01c274a01d107b348f921e1c74dd04bd3a.tar.gz |
Merge tag 'upstream/8.23'
Upstream version 8.23
Diffstat (limited to 'src')
-rw-r--r-- | src/base64.c | 41 | ||||
-rw-r--r-- | src/basename.c | 7 | ||||
-rw-r--r-- | src/cat.c | 2 | ||||
-rw-r--r-- | src/chcon.c | 43 | ||||
-rw-r--r-- | src/chgrp.c | 2 | ||||
-rw-r--r-- | src/chmod.c | 13 | ||||
-rw-r--r-- | src/chown-core.c | 4 | ||||
-rw-r--r-- | src/chown-core.h | 2 | ||||
-rw-r--r-- | src/chown.c | 5 | ||||
-rw-r--r-- | src/chroot.c | 253 | ||||
-rw-r--r-- | src/cksum.c | 2 | ||||
-rw-r--r-- | src/comm.c | 2 | ||||
-rw-r--r-- | src/copy.c | 386 | ||||
-rw-r--r-- | src/copy.h | 5 | ||||
-rw-r--r-- | src/coreutils-arch.c | 32 | ||||
-rw-r--r-- | src/coreutils-dir.c | 32 | ||||
-rw-r--r-- | src/coreutils-vdir.c | 32 | ||||
-rw-r--r-- | src/coreutils.c | 205 | ||||
-rw-r--r-- | src/cp-hash.c | 2 | ||||
-rw-r--r-- | src/cp.c | 72 | ||||
-rw-r--r-- | src/csplit.c | 41 | ||||
-rw-r--r-- | src/cu-progs.mk | 1 | ||||
-rw-r--r-- | src/cut.c | 436 | ||||
-rw-r--r-- | src/date.c | 4 | ||||
-rwxr-xr-x | src/dcgen | 2 | ||||
-rw-r--r-- | src/dd.c | 213 | ||||
-rw-r--r-- | src/df.c | 358 | ||||
-rw-r--r-- | src/dircolors.c | 2 | ||||
-rw-r--r-- | src/dircolors.h | 15 | ||||
-rw-r--r-- | src/dircolors.hin | 15 | ||||
-rw-r--r-- | src/dirname.c | 4 | ||||
-rw-r--r-- | src/du.c | 81 | ||||
-rw-r--r-- | src/echo.c | 2 | ||||
-rw-r--r-- | src/env.c | 4 | ||||
-rw-r--r-- | src/expand.c | 2 | ||||
-rw-r--r-- | src/expr.c | 16 | ||||
-rw-r--r-- | src/extent-scan.c | 8 | ||||
-rw-r--r-- | src/extent-scan.h | 2 | ||||
-rw-r--r-- | src/extract-magic | 2 | ||||
-rw-r--r-- | src/factor.c | 32 | ||||
-rw-r--r-- | src/find-mount-point.c | 2 | ||||
-rw-r--r-- | src/find-mount-point.h | 2 | ||||
-rw-r--r-- | src/fmt.c | 2 | ||||
-rw-r--r-- | src/fold.c | 2 | ||||
-rw-r--r-- | src/fs-is-local.h | 13 | ||||
-rw-r--r-- | src/fs.h | 15 | ||||
-rw-r--r-- | src/getlimits.c | 20 | ||||
-rw-r--r-- | src/group-list.c | 8 | ||||
-rw-r--r-- | src/group-list.h | 4 | ||||
-rw-r--r-- | src/groups.c | 8 | ||||
-rw-r--r-- | src/head.c | 307 | ||||
-rw-r--r-- | src/hostid.c | 2 | ||||
-rw-r--r-- | src/hostname.c | 2 | ||||
-rw-r--r-- | src/id.c | 116 | ||||
-rw-r--r-- | src/install.c | 133 | ||||
-rw-r--r-- | src/ioblksize.h | 46 | ||||
-rw-r--r-- | src/join.c | 21 | ||||
-rw-r--r-- | src/kill.c | 8 | ||||
-rw-r--r-- | src/libstdbuf.c | 5 | ||||
-rw-r--r-- | src/link.c | 2 | ||||
-rw-r--r-- | src/ln.c | 47 | ||||
-rw-r--r-- | src/local.mk | 126 | ||||
-rw-r--r-- | src/logname.c | 2 | ||||
-rw-r--r-- | src/longlong.h | 266 | ||||
-rw-r--r-- | src/ls.c | 200 | ||||
-rw-r--r-- | src/make-prime-list.c | 2 | ||||
-rw-r--r-- | src/md5sum.c | 37 | ||||
-rw-r--r-- | src/mkdir.c | 137 | ||||
-rw-r--r-- | src/mkfifo.c | 74 | ||||
-rw-r--r-- | src/mknod.c | 63 | ||||
-rw-r--r-- | src/mktemp.c | 60 | ||||
-rw-r--r-- | src/mv.c | 18 | ||||
-rw-r--r-- | src/nice.c | 2 | ||||
-rw-r--r-- | src/nl.c | 2 | ||||
-rw-r--r-- | src/nohup.c | 2 | ||||
-rw-r--r-- | src/nproc.c | 2 | ||||
-rw-r--r-- | src/numfmt.c | 193 | ||||
-rw-r--r-- | src/od.c | 85 | ||||
-rw-r--r-- | src/operand2sig.c | 2 | ||||
-rw-r--r-- | src/operand2sig.h | 2 | ||||
-rw-r--r-- | src/paste.c | 4 | ||||
-rw-r--r-- | src/pathchk.c | 2 | ||||
-rw-r--r-- | src/pinky.c | 6 | ||||
-rw-r--r-- | src/pr.c | 5 | ||||
-rw-r--r-- | src/printenv.c | 4 | ||||
-rw-r--r-- | src/printf.c | 2 | ||||
-rw-r--r-- | src/prog-fprintf.c | 2 | ||||
-rw-r--r-- | src/prog-fprintf.h | 2 | ||||
-rw-r--r-- | src/ptx.c | 75 | ||||
-rw-r--r-- | src/pwd.c | 9 | ||||
-rw-r--r-- | src/readlink.c | 6 | ||||
-rw-r--r-- | src/realpath.c | 6 | ||||
-rw-r--r-- | src/relpath.c | 2 | ||||
-rw-r--r-- | src/relpath.h | 2 | ||||
-rw-r--r-- | src/remove.c | 23 | ||||
-rw-r--r-- | src/remove.h | 2 | ||||
-rw-r--r-- | src/rm.c | 18 | ||||
-rw-r--r-- | src/rmdir.c | 2 | ||||
-rw-r--r-- | src/runcon.c | 17 | ||||
-rw-r--r-- | src/selinux.c | 341 | ||||
-rw-r--r-- | src/selinux.h | 47 | ||||
-rw-r--r-- | src/seq.c | 6 | ||||
-rw-r--r-- | src/setuidgid.c | 215 | ||||
-rw-r--r-- | src/shred.c | 320 | ||||
-rw-r--r-- | src/shuf.c | 365 | ||||
-rw-r--r-- | src/single-binary.mk | 480 | ||||
-rw-r--r-- | src/sleep.c | 2 | ||||
-rw-r--r-- | src/sort.c | 79 | ||||
-rw-r--r-- | src/split.c | 172 | ||||
-rw-r--r-- | src/stat.c | 122 | ||||
-rw-r--r-- | src/stdbuf.c | 49 | ||||
-rw-r--r-- | src/stty.c | 10 | ||||
-rw-r--r-- | src/sum.c | 2 | ||||
-rw-r--r-- | src/sync.c | 2 | ||||
-rw-r--r-- | src/system.h | 45 | ||||
-rw-r--r-- | src/tac-pipe.c | 2 | ||||
-rw-r--r-- | src/tac.c | 4 | ||||
-rw-r--r-- | src/tail.c | 148 | ||||
-rw-r--r-- | src/tee.c | 2 | ||||
-rw-r--r-- | src/test.c | 2 | ||||
-rw-r--r-- | src/timeout.c | 39 | ||||
-rw-r--r-- | src/touch.c | 2 | ||||
-rw-r--r-- | src/tr.c | 2 | ||||
-rw-r--r-- | src/true.c | 4 | ||||
-rw-r--r-- | src/truncate.c | 6 | ||||
-rw-r--r-- | src/tsort.c | 7 | ||||
-rw-r--r-- | src/tty.c | 2 | ||||
-rw-r--r-- | src/uname.c | 6 | ||||
-rw-r--r-- | src/unexpand.c | 2 | ||||
-rw-r--r-- | src/uniq.c | 127 | ||||
-rw-r--r-- | src/unlink.c | 2 | ||||
-rw-r--r-- | src/uptime.c | 6 | ||||
-rw-r--r-- | src/users.c | 2 | ||||
-rw-r--r-- | src/wc.c | 2 | ||||
-rw-r--r-- | src/who.c | 2 | ||||
-rw-r--r-- | src/whoami.c | 2 | ||||
-rw-r--r-- | src/yes.c | 2 |
137 files changed, 5037 insertions, 2204 deletions
diff --git a/src/base64.c b/src/base64.c index 0a400680..b0656043 100644 --- a/src/base64.c +++ b/src/base64.c @@ -1,5 +1,5 @@ /* Base64 encode/decode strings or files. - Copyright (C) 2004-2013 Free Software Foundation, Inc. + Copyright (C) 2004-2014 Free Software Foundation, Inc. This file is part of Base64. @@ -89,15 +89,16 @@ from any other non-alphabet bytes in the encoded stream.\n"), exit (status); } +#define ENC_BLOCKSIZE (1024*3*10) +#define ENC_B64BLOCKSIZE BASE64_LENGTH (ENC_BLOCKSIZE) /* Note that increasing this may decrease performance if --ignore-garbage - is used, because of the memmove operation below. */ -#define BLOCKSIZE 3072 -#define B64BLOCKSIZE BASE64_LENGTH (BLOCKSIZE) + is used, because of the memmove operation below. */ +#define DEC_BLOCKSIZE (1024*3) +#define DEC_B64BLOCKSIZE BASE64_LENGTH (DEC_BLOCKSIZE) /* Ensure that BLOCKSIZE is a multiple of 3 and 4. */ -#if BLOCKSIZE % 12 != 0 -# error "invalid BLOCKSIZE" -#endif +verify (ENC_BLOCKSIZE % 12 == 0); +verify (DEC_BLOCKSIZE % 12 == 0); static void wrap_write (const char *buffer, size_t len, @@ -120,7 +121,7 @@ wrap_write (const char *buffer, size_t len, if (to_write == 0) { - if (fputs ("\n", out) < 0) + if (fputc ('\n', out) == EOF) error (EXIT_FAILURE, errno, _("write error")); *current_column = 0; } @@ -138,8 +139,8 @@ static void do_encode (FILE *in, FILE *out, uintmax_t wrap_column) { size_t current_column = 0; - char inbuf[BLOCKSIZE]; - char outbuf[B64BLOCKSIZE]; + char inbuf[ENC_BLOCKSIZE]; + char outbuf[ENC_B64BLOCKSIZE]; size_t sum; do @@ -149,14 +150,14 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column) sum = 0; do { - n = fread (inbuf + sum, 1, BLOCKSIZE - sum, in); + n = fread (inbuf + sum, 1, ENC_BLOCKSIZE - sum, in); sum += n; } - while (!feof (in) && !ferror (in) && sum < BLOCKSIZE); + while (!feof (in) && !ferror (in) && sum < ENC_BLOCKSIZE); if (sum > 0) { - /* Process input one block at a time. Note that BLOCKSIZE % + /* Process input one block at a time. Note that ENC_BLOCKSIZE % 3 == 0, so that no base64 pads will appear in output. */ base64_encode (inbuf, sum, outbuf, BASE64_LENGTH (sum)); @@ -164,10 +165,10 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column) ¤t_column, out); } } - while (!feof (in) && !ferror (in) && sum == BLOCKSIZE); + while (!feof (in) && !ferror (in) && sum == ENC_BLOCKSIZE); /* When wrapping, terminate last line. */ - if (wrap_column && current_column > 0 && fputs ("\n", out) < 0) + if (wrap_column && current_column > 0 && fputc ('\n', out) == EOF) error (EXIT_FAILURE, errno, _("write error")); if (ferror (in)) @@ -177,8 +178,8 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column) static void do_decode (FILE *in, FILE *out, bool ignore_garbage) { - char inbuf[B64BLOCKSIZE]; - char outbuf[BLOCKSIZE]; + char inbuf[DEC_B64BLOCKSIZE]; + char outbuf[DEC_BLOCKSIZE]; size_t sum; struct base64_decode_context ctx; @@ -193,7 +194,7 @@ do_decode (FILE *in, FILE *out, bool ignore_garbage) sum = 0; do { - n = fread (inbuf + sum, 1, B64BLOCKSIZE - sum, in); + n = fread (inbuf + sum, 1, DEC_B64BLOCKSIZE - sum, in); if (ignore_garbage) { @@ -210,7 +211,7 @@ do_decode (FILE *in, FILE *out, bool ignore_garbage) if (ferror (in)) error (EXIT_FAILURE, errno, _("read error")); } - while (sum < B64BLOCKSIZE && !feof (in)); + while (sum < DEC_B64BLOCKSIZE && !feof (in)); /* The following "loop" is usually iterated just once. However, when it processes the final input buffer, we want @@ -220,7 +221,7 @@ do_decode (FILE *in, FILE *out, bool ignore_garbage) { if (k == 1 && ctx.i == 0) break; - n = BLOCKSIZE; + n = DEC_BLOCKSIZE; ok = base64_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n); if (fwrite (outbuf, 1, n, out) < n) diff --git a/src/basename.c b/src/basename.c index 074d284d..95215399 100644 --- a/src/basename.c +++ b/src/basename.c @@ -1,5 +1,5 @@ /* basename -- strip directory and suffix from file names - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 @@ -59,8 +59,8 @@ If specified, also remove a trailing SUFFIX.\n\ fputs (_("\ -a, --multiple support multiple arguments and treat each as a NAME\n\ - -s, --suffix=SUFFIX remove a trailing SUFFIX\n\ - -z, --zero separate output with NUL rather than newline\n\ + -s, --suffix=SUFFIX remove a trailing SUFFIX; implies -a\n\ + -z, --zero end each output line with NUL, not newline\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -146,6 +146,7 @@ main (int argc, char **argv) { case 's': suffix = optarg; + /* Fall through: -s implies -a. */ case 'a': multiple_names = true; @@ -1,5 +1,5 @@ /* cat -- concatenate files and print on the standard output. - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 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 diff --git a/src/chcon.c b/src/chcon.c index 56f2caa5..cda06612 100644 --- a/src/chcon.c +++ b/src/chcon.c @@ -1,5 +1,5 @@ /* chcon -- change security context of files - Copyright (C) 2005-2013 Free Software Foundation, Inc. + Copyright (C) 2005-2014 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 @@ -91,7 +91,7 @@ static struct option const long_options[] = 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) +compute_context_from_mask (char const *context, context_t *ret) { bool ok = true; context_t new_context = context_new (context); @@ -140,9 +140,9 @@ compute_context_from_mask (security_context_t context, context_t *ret) static int change_file_context (int fd, char const *file) { - security_context_t file_context = NULL; - context_t context; - security_context_t context_string; + char *file_context = NULL; + context_t context IF_LINT (= 0); + char const * context_string; int errors = 0; if (specified_context == NULL) @@ -170,22 +170,19 @@ change_file_context (int fd, char const *file) if (compute_context_from_mask (file_context, &context)) return 1; + + context_string = context_str (context); } else { - /* FIXME: this should be done exactly once, in main. */ - context = context_new (specified_context); - if (!context) - abort (); + context_string = specified_context; } - 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)); + ? setfileconat (fd, file, se_const (context_string)) + : lsetfileconat (fd, file, se_const (context_string))); if (fail) { @@ -195,8 +192,11 @@ change_file_context (int fd, char const *file) } } - context_free (context); - freecon (file_context); + if (specified_context == NULL) + { + context_free (context); + freecon (file_context); + } return errors; } @@ -355,7 +355,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\ "), stdout); @@ -409,8 +409,6 @@ one takes effect.\n\ int main (int argc, char **argv) { - security_context_t ref_context = NULL; - /* Bit flags that control how fts works. */ int bit_flags = FTS_PHYSICAL; @@ -542,6 +540,8 @@ main (int argc, char **argv) if (reference_file) { + char *ref_context = NULL; + if (getfilecon (reference_file, &ref_context) < 0) error (EXIT_FAILURE, errno, _("failed to get security context of %s"), quote (reference_file)); @@ -555,13 +555,10 @@ main (int argc, char **argv) } else { - context_t context; specified_context = argv[optind++]; - context = context_new (specified_context); - if (!context) - error (EXIT_FAILURE, 0, _("invalid context: %s"), + if (security_check_context (se_const (specified_context)) < 0) + error (EXIT_FAILURE, errno, _("invalid context: %s"), quotearg_colon (specified_context)); - context_free (context); } if (reference_file && component_specified) diff --git a/src/chgrp.c b/src/chgrp.c index c70855d3..c7297c81 100644 --- a/src/chgrp.c +++ b/src/chgrp.c @@ -1,5 +1,5 @@ /* chgrp -- change group ownership of files - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 diff --git a/src/chmod.c b/src/chmod.c index 2c25ce6d..756ec5a4 100644 --- a/src/chmod.c +++ b/src/chmod.c @@ -1,5 +1,5 @@ /* chmod -- change permission modes of files - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -111,7 +111,8 @@ static struct option const long_options[] = The old mode was OLD_MODE, but it was changed to NEW_MODE. */ static bool -mode_changed (char const *file, mode_t old_mode, mode_t new_mode) +mode_changed (int dir_fd, char const *file, char const *file_full_name, + mode_t old_mode, mode_t new_mode) { if (new_mode & (S_ISUID | S_ISGID | S_ISVTX)) { @@ -120,10 +121,11 @@ mode_changed (char const *file, mode_t old_mode, mode_t new_mode) struct stat new_stats; - if (stat (file, &new_stats) != 0) + if (fstatat (dir_fd, file, &new_stats, 0) != 0) { if (! force_silent) - error (0, errno, _("getting new attributes of %s"), quote (file)); + error (0, errno, _("getting new attributes of %s"), + quote (file_full_name)); return false; } @@ -283,7 +285,8 @@ process_file (FTS *fts, FTSENT *ent) if (verbosity != V_off) { bool changed = (chmod_succeeded - && mode_changed (file, old_mode, new_mode)); + && mode_changed (fts->fts_cwd_fd, file, file_full_name, + old_mode, new_mode)); if (changed || verbosity == V_high) { diff --git a/src/chown-core.c b/src/chown-core.c index 3a3044e0..cdcd53aa 100644 --- a/src/chown-core.c +++ b/src/chown-core.c @@ -1,5 +1,5 @@ /* chown-core.c -- core functions for changing ownership. - Copyright (C) 2000-2013 Free Software Foundation, Inc. + Copyright (C) 2000-2014 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 @@ -68,7 +68,7 @@ chopt_init (struct Chown_option *chopt) } extern void -chopt_free (struct Chown_option *chopt ATTRIBUTE_UNUSED) +chopt_free (struct Chown_option *chopt _GL_UNUSED) { /* Deliberately do not free chopt->user_name or ->group_name. They're not always allocated. */ diff --git a/src/chown-core.h b/src/chown-core.h index f6c808bc..86b33cd2 100644 --- a/src/chown-core.h +++ b/src/chown-core.h @@ -1,6 +1,6 @@ /* chown-core.h -- types and prototypes shared by chown and chgrp. - Copyright (C) 2000-2013 Free Software Foundation, Inc. + Copyright (C) 2000-2014 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 diff --git a/src/chown.c b/src/chown.c index 9db0a569..13a19233 100644 --- a/src/chown.c +++ b/src/chown.c @@ -1,5 +1,5 @@ /* chown -- change user and group ownership of files - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -226,10 +226,9 @@ main (int argc, char **argv) case FROM_OPTION: { - char *u_dummy, *g_dummy; const char *e = parse_user_spec (optarg, &required_uid, &required_gid, - &u_dummy, &g_dummy); + NULL, NULL); if (e) error (EXIT_FAILURE, 0, "%s: %s", e, quote (optarg)); break; diff --git a/src/chroot.c b/src/chroot.c index 1c1a9769..fff0b533 100644 --- a/src/chroot.c +++ b/src/chroot.c @@ -1,5 +1,5 @@ /* chroot -- run command or shell with special root directory - Copyright (C) 1995-2013 Free Software Foundation, Inc. + Copyright (C) 1995-2014 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 @@ -20,11 +20,15 @@ #include <getopt.h> #include <stdio.h> #include <sys/types.h> +#include <pwd.h> #include <grp.h> #include "system.h" #include "error.h" +#include "ignore-value.h" +#include "mgetgroups.h" #include "quote.h" +#include "root-dev-ino.h" #include "userspec.h" #include "xstrtol.h" @@ -37,6 +41,11 @@ # define MAXGID GID_T_MAX #endif +static inline bool uid_unset (uid_t uid) { return uid == (uid_t) -1; } +static inline bool gid_unset (gid_t gid) { return gid == (gid_t) -1; } +#define uid_set(x) (!uid_unset (x)) +#define gid_set(x) (!gid_unset (x)) + enum { GROUPS = UCHAR_MAX + 1, @@ -53,23 +62,36 @@ static struct option const long_opts[] = }; #if ! HAVE_SETGROUPS -/* At least Interix lacks supplemental group support. Define an - always-successful replacement to avoid checking for setgroups - availability everywhere, just to support broken platforms. */ +/* At least Interix lacks supplemental group support. */ static int -setgroups (size_t size ATTRIBUTE_UNUSED, gid_t const *list ATTRIBUTE_UNUSED) +setgroups (size_t size, gid_t const *list _GL_UNUSED) { - return 0; + if (size == 0) + { + /* Return success when clearing supplemental groups + as ! HAVE_SETGROUPS should only be the case on + platforms that don't support supplemental groups. */ + return 0; + } + else + { + errno = ENOTSUP; + return -1; + } } #endif -/* Call setgroups to set the supplementary groups to those listed in GROUPS. - GROUPS is a comma separated list of supplementary groups (names or numbers). - Parse that list, converting any names to numbers, and call setgroups on the - resulting numbers. Upon any failure give a diagnostic and return nonzero. +/* Determine the group IDs for the specified supplementary GROUPS, + which is a comma separated list of supplementary groups (names or numbers). + Allocate an array for the parsed IDs and store it in PGIDS, + which may be allocated even on parse failure. + Update the number of parsed groups in PN_GIDS on success. + Upon any failure return nonzero, and issue diagnostic if SHOW_ERRORS is true. Otherwise return zero. */ + static int -set_additional_groups (char const *groups) +parse_additional_groups (char const *groups, GETGROUPS_T **pgids, + size_t *pn_gids, bool show_errors) { GETGROUPS_T *gids = NULL; size_t n_gids_allocated = 0; @@ -84,7 +106,19 @@ set_additional_groups (char const *groups) unsigned long int value; if (xstrtoul (tmp, NULL, 10, &value, "") == LONGINT_OK && value <= MAXGID) - g = getgrgid (value); + { + while (isspace (to_uchar (*tmp))) + tmp++; + if (*tmp != '+') + { + /* Handle the case where the name is numeric. */ + g = getgrnam (tmp); + if (g != NULL) + value = g->gr_gid; + } + /* Flag that we've got a group from the number. */ + g = (struct group *) (intptr_t) ! NULL; + } else { g = getgrnam (tmp); @@ -94,9 +128,15 @@ set_additional_groups (char const *groups) if (g == NULL) { - error (0, errno, _("invalid group %s"), quote (tmp)); ret = -1; - continue; + + if (show_errors) + { + error (0, errno, _("invalid group %s"), quote (tmp)); + continue; + } + + break; } if (n_gids == n_gids_allocated) @@ -106,22 +146,36 @@ set_additional_groups (char const *groups) if (ret == 0 && n_gids == 0) { - error (0, 0, _("invalid group list %s"), quote (groups)); + if (show_errors) + error (0, 0, _("invalid group list %s"), quote (groups)); ret = -1; } + *pgids = gids; + if (ret == 0) - { - ret = setgroups (n_gids, gids); - if (ret) - error (0, errno, _("failed to set additional groups")); - } + *pn_gids = n_gids; free (buffer); - free (gids); return ret; } +static bool +is_root (const char* dir) +{ + struct dev_ino root_ino; + if (! get_root_dev_ino (&root_ino)) + error (EXIT_CANCELED, errno, _("failed to get attributes of %s"), + quote ("/")); + + struct stat arg_st; + if (stat (dir, &arg_st) == -1) + error (EXIT_CANCELED, errno, _("failed to get attributes of %s"), + quote (dir)); + + return SAME_INODE (root_ino, arg_st); +} + void usage (int status) { @@ -159,9 +213,18 @@ int main (int argc, char **argv) { int c; - char const *userspec = NULL; + + /* Input user and groups spec. */ + char *userspec = NULL; + char const *username = NULL; char const *groups = NULL; + /* Parsed user and group IDs. */ + uid_t uid = -1; + gid_t gid = -1; + GETGROUPS_T *out_gids = NULL; + size_t n_gids = 0; + initialize_main (&argc, &argv); set_program_name (argv[0]); setlocale (LC_ALL, ""); @@ -176,8 +239,16 @@ main (int argc, char **argv) switch (c) { case USERSPEC: - userspec = optarg; - break; + { + userspec = optarg; + /* Treat 'user:' just like 'user' + as we lookup the primary group by default + (and support doing so for UIDs as well as names. */ + size_t userlen = strlen (userspec); + if (userlen && userspec[userlen - 1] == ':') + userspec[userlen - 1] = '\0'; + break; + } case GROUPS: groups = optarg; @@ -198,12 +269,51 @@ main (int argc, char **argv) usage (EXIT_CANCELED); } - if (chroot (argv[optind]) != 0) - error (EXIT_CANCELED, errno, _("cannot change root directory to %s"), - argv[optind]); + /* Only do chroot specific actions if actually changing root. + The main difference here is that we don't change working dir. */ + if (! is_root (argv[optind])) + { + /* We have to look up users and groups twice. + - First, outside the chroot to load potentially necessary passwd/group + parsing plugins (e.g. NSS); + - Second, inside chroot to redo parsing in case IDs are different. + Within chroot lookup is the main justification for having + the --user option supported by the chroot command itself. */ + if (userspec) + ignore_value (parse_user_spec (userspec, &uid, &gid, NULL, NULL)); + + /* If no gid is supplied or looked up, do so now. + Also lookup the username for use with getgroups. */ + if (uid_set (uid) && (! groups || gid_unset (gid))) + { + const struct passwd *pwd; + if ((pwd = getpwuid (uid))) + { + if (gid_unset (gid)) + gid = pwd->pw_gid; + username = pwd->pw_name; + } + } - if (chdir ("/")) - error (EXIT_CANCELED, errno, _("cannot chdir to root directory")); + if (groups && *groups) + ignore_value (parse_additional_groups (groups, &out_gids, &n_gids, + false)); +#if HAVE_SETGROUPS + else if (! groups && gid_set (gid) && username) + { + int ngroups = xgetgroups (username, gid, &out_gids); + if (0 < ngroups) + n_gids = ngroups; + } +#endif + + if (chroot (argv[optind]) != 0) + error (EXIT_CANCELED, errno, _("cannot change root directory to %s"), + argv[optind]); + + if (chdir ("/")) + error (EXIT_CANCELED, errno, _("cannot chdir to root directory")); + } if (argc == optind + 1) { @@ -221,51 +331,78 @@ main (int argc, char **argv) argv += optind + 1; } - bool fail = false; - /* Attempt to set all three: supplementary groups, group ID, user ID. Diagnose any failures. If any have failed, exit before execvp. */ if (userspec) { - uid_t uid = -1; - gid_t gid = -1; - char *user; - char *group; - char const *err = parse_user_spec (userspec, &uid, &gid, &user, &group); + char const *err = parse_user_spec (userspec, &uid, &gid, NULL, NULL); - if (err) + if (err && uid_unset (uid) && gid_unset (gid)) error (EXIT_CANCELED, errno, "%s", err); + } - free (user); - free (group); - - if (groups && set_additional_groups (groups)) - fail = true; - - if (gid != (gid_t) -1 && setgid (gid)) + /* If no gid is supplied or looked up, do so now. + Also lookup the username for use with getgroups. */ + if (uid_set (uid) && (! groups || gid_unset (gid))) + { + const struct passwd *pwd; + if ((pwd = getpwuid (uid))) + { + if (gid_unset (gid)) + gid = pwd->pw_gid; + username = pwd->pw_name; + } + else if (gid_unset (gid)) { - error (0, errno, _("failed to set group-ID")); - fail = true; + error (EXIT_CANCELED, errno, + _("no group specified for unknown uid: %d"), (int) uid); } + } - if (uid != (uid_t) -1 && setuid (uid)) + GETGROUPS_T *gids = out_gids; + GETGROUPS_T *in_gids = NULL; + if (groups && *groups) + { + if (parse_additional_groups (groups, &in_gids, &n_gids, !n_gids) != 0) { - error (0, errno, _("failed to set user-ID")); - fail = true; + if (! n_gids) + exit (EXIT_CANCELED); + /* else look-up outside the chroot worked, then go with those. */ } + else + gids = in_gids; } - else +#if HAVE_SETGROUPS + else if (! groups && gid_set (gid) && username) { - /* Yes, this call is identical to the one above. - However, when --userspec and --groups groups are used together, - we don't want to call this function until after parsing USER:GROUP, - and it must be called before setuid. */ - if (groups && set_additional_groups (groups)) - fail = true; + int ngroups = xgetgroups (username, gid, &in_gids); + if (ngroups <= 0) + { + if (! n_gids) + error (EXIT_CANCELED, errno, + _("failed to get supplemental groups")); + /* else look-up outside the chroot worked, then go with those. */ + } + else + { + n_gids = ngroups; + gids = in_gids; + } } +#endif + + if ((uid_set (uid) || groups) && setgroups (n_gids, gids) != 0) + error (EXIT_CANCELED, errno, _("failed to %s supplemental groups"), + gids ? "set" : "clear"); + + free (in_gids); + free (out_gids); + + if (gid_set (gid) && setgid (gid)) + error (EXIT_CANCELED, errno, _("failed to set group-ID")); - if (fail) - exit (EXIT_CANCELED); + if (uid_set (uid) && setuid (uid)) + error (EXIT_CANCELED, errno, _("failed to set user-ID")); /* Execute the given command. */ execvp (argv[0], argv); diff --git a/src/cksum.c b/src/cksum.c index 26571c7c..8db39a48 100644 --- a/src/cksum.c +++ b/src/cksum.c @@ -1,5 +1,5 @@ /* cksum -- calculate and print POSIX checksums and sizes of files - Copyright (C) 1992-2013 Free Software Foundation, Inc. + Copyright (C) 1992-2014 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 @@ -1,5 +1,5 @@ /* comm -- compare two sorted files line by line. - Copyright (C) 1986-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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 @@ -1,5 +1,5 @@ /* copy.c -- core functions for copying files and directories - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -51,6 +51,7 @@ #include "ignore-value.h" #include "ioblksize.h" #include "quote.h" +#include "root-uid.h" #include "same.h" #include "savedir.h" #include "stat-size.h" @@ -60,6 +61,7 @@ #include "write-any-file.h" #include "areadlink.h" #include "yesno.h" +#include "selinux.h" #if USE_XATTR # include <attr/error_context.h> @@ -96,6 +98,14 @@ rpl_mkfifo (char const *file, mode_t mode) #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)) +/* LINK_FOLLOWS_SYMLINKS is tri-state; if it is -1, we don't know + how link() behaves, so assume we can't hardlink symlinks in that case. */ +#if defined HAVE_LINKAT || ! LINK_FOLLOWS_SYMLINKS +# define CAN_HARDLINK_SYMLINKS 1 +#else +# define CAN_HARDLINK_SYMLINKS 0 +#endif + struct dir_list { struct dir_list *parent; @@ -107,7 +117,7 @@ struct dir_list #define DEST_INFO_INITIAL_CAPACITY 61 static bool copy_internal (char const *src_name, char const *dst_name, - bool new_dst, dev_t device, + bool new_dst, struct stat const *parent, struct dir_list *ancestors, const struct cp_options *x, bool command_line_arg, @@ -471,7 +481,7 @@ errno_unsupported (int err) #if USE_XATTR static void -copy_attr_error (struct error_context *ctx ATTRIBUTE_UNUSED, +copy_attr_error (struct error_context *ctx _GL_UNUSED, char const *fmt, ...) { if (!errno_unsupported (errno)) @@ -487,7 +497,7 @@ copy_attr_error (struct error_context *ctx ATTRIBUTE_UNUSED, } static void -copy_attr_allerror (struct error_context *ctx ATTRIBUTE_UNUSED, +copy_attr_allerror (struct error_context *ctx _GL_UNUSED, char const *fmt, ...) { int err = errno; @@ -500,15 +510,27 @@ copy_attr_allerror (struct error_context *ctx ATTRIBUTE_UNUSED, } static char const * -copy_attr_quote (struct error_context *ctx ATTRIBUTE_UNUSED, char const *str) +copy_attr_quote (struct error_context *ctx _GL_UNUSED, char const *str) { return quote (str); } static void -copy_attr_free (struct error_context *ctx ATTRIBUTE_UNUSED, - char const *str ATTRIBUTE_UNUSED) +copy_attr_free (struct error_context *ctx _GL_UNUSED, + char const *str _GL_UNUSED) +{ +} + +/* Exclude SELinux extended attributes that are otherwise handled, + and are problematic to copy again. Also honor attributes + configured for exclusion in /etc/xattr.conf. + FIXME: Should we handle POSIX ACLs similarly? + Return zero to skip. */ +static int +check_selinux_attr (const char *name, struct error_context *ctx) { + return STRNCMP_LIT (name, "security.selinux") + && attr_copy_check_permissions (name, ctx); } /* If positive SRC_FD and DST_FD descriptors are passed, @@ -521,6 +543,7 @@ copy_attr (char const *src_path, int src_fd, int ret; bool all_errors = (!x->data_copy_required || x->require_preserve_xattr); bool some_errors = (!all_errors && !x->reduce_diagnostics); + bool selinux_done = (x->preserve_security_context || x->set_security_context); struct error_context ctx = { .error = all_errors ? copy_attr_allerror : copy_attr_error, @@ -528,10 +551,12 @@ copy_attr (char const *src_path, int src_fd, .quote_free = copy_attr_free }; if (0 <= src_fd && 0 <= dst_fd) - ret = attr_copy_fd (src_path, src_fd, dst_path, dst_fd, 0, + ret = attr_copy_fd (src_path, src_fd, dst_path, dst_fd, + selinux_done ? check_selinux_attr : NULL, (all_errors || some_errors ? &ctx : NULL)); else - ret = attr_copy_file (src_path, dst_path, 0, + ret = attr_copy_file (src_path, dst_path, + selinux_done ? check_selinux_attr : NULL, (all_errors || some_errors ? &ctx : NULL)); return ret == 0; @@ -539,11 +564,11 @@ copy_attr (char const *src_path, int src_fd, #else /* USE_XATTR */ static bool -copy_attr (char const *src_path ATTRIBUTE_UNUSED, - int src_fd ATTRIBUTE_UNUSED, - char const *dst_path ATTRIBUTE_UNUSED, - int dst_fd ATTRIBUTE_UNUSED, - struct cp_options const *x ATTRIBUTE_UNUSED) +copy_attr (char const *src_path _GL_UNUSED, + int src_fd _GL_UNUSED, + char const *dst_path _GL_UNUSED, + int dst_fd _GL_UNUSED, + struct cp_options const *x _GL_UNUSED) { return true; } @@ -573,7 +598,7 @@ copy_dir (char const *src_name_in, char const *dst_name_in, bool new_dst, struct cp_options non_command_line_options = *x; bool ok = true; - name_space = savedir (src_name_in); + name_space = savedir (src_name_in, SAVEDIR_SORT_FASTREAD); if (name_space == NULL) { /* This diagnostic is a bit vague because savedir can fail in @@ -596,7 +621,7 @@ copy_dir (char const *src_name_in, char const *dst_name_in, bool new_dst, char *dst_name = file_name_concat (dst_name_in, namep, NULL); bool first_dir_created = *first_dir_created_per_command_line_arg; - ok &= copy_internal (src_name, dst_name, new_dst, src_sb->st_dev, + ok &= copy_internal (src_name, dst_name, new_dst, src_sb, ancestors, &non_command_line_options, false, &first_dir_created, &local_copy_into_self, NULL); @@ -736,6 +761,96 @@ set_author (const char *dst_name, int dest_desc, const struct stat *src_sb) #endif } +/* Set the default security context for the process. New files will + have this security context set. Also existing files can have their + context adjusted based on this process context, by + set_file_security_ctx() called with PROCESS_LOCAL=true. + This should be called before files are created so there is no race + where a file may be present without an appropriate security context. + Based on CP_OPTIONS, diagnose warnings and fail when appropriate. + Return FALSE on failure, TRUE on success. */ + +static bool +set_process_security_ctx (char const *src_name, char const *dst_name, + mode_t mode, bool new_dst, const struct cp_options *x) +{ + if (x->preserve_security_context) + { + /* Set the default context for the process to match the source. */ + bool all_errors = !x->data_copy_required || x->require_preserve_context; + bool some_errors = !all_errors && !x->reduce_diagnostics; + char *con; + + if (0 <= lgetfilecon (src_name, &con)) + { + if (setfscreatecon (con) < 0) + { + if (all_errors || (some_errors && !errno_unsupported (errno))) + 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 (all_errors || (some_errors && !errno_unsupported (errno))) + { + error (0, errno, + _("failed to get security context of %s"), + quote (src_name)); + } + if (x->require_preserve_context) + return false; + } + } + else if (x->set_security_context) + { + /* With -Z, adjust the default context for the process + to have the type component adjusted as per the destination path. */ + if (new_dst && defaultcon (dst_name, mode) < 0 + && ! ignorable_ctx_err (errno)) + { + error (0, errno, + _("failed to set default file creation context for %s"), + quote (dst_name)); + } + } + + return true; +} + +/* Reset the security context of DST_NAME, to that already set + as the process default if PROCESS_LOCAL is true. Otherwise + adjust the type component of DST_NAME's security context as + per the system default for that path. Issue warnings upon + failure, when allowed by various settings in CP_OPTIONS. + Return FALSE on failure, TRUE on success. */ + +static bool +set_file_security_ctx (char const *dst_name, bool process_local, + bool recurse, const struct cp_options *x) +{ + bool all_errors = (!x->data_copy_required + || x->require_preserve_context); + bool some_errors = !all_errors && !x->reduce_diagnostics; + + if (! restorecon (dst_name, recurse, process_local)) + { + if (all_errors || (some_errors && !errno_unsupported (errno))) + error (0, errno, _("failed to set the security context of %s"), + quote_n (0, dst_name)); + return false; + } + + return true; +} + /* 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. */ @@ -833,45 +948,24 @@ copy_reg (char const *src_name, char const *dst_name, 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) + reset the context as per the default context, which has already been + set according to the src. + When using the mutually exclusive -Z option, then adjust the type of + the existing context according to the system default for the dest. + Note we set the context here, _after_ the file is opened, lest the + new context disallow that. */ + if ((x->set_security_context || x->preserve_security_context) + && 0 <= dest_desc) { - bool all_errors = (!x->data_copy_required - || x->require_preserve_context); - bool some_errors = !all_errors && !x->reduce_diagnostics; - security_context_t con = NULL; - - if (getfscreatecon (&con) < 0) + if (! set_file_security_ctx (dst_name, x->preserve_security_context, + false, x)) { - if (all_errors || (some_errors && !errno_unsupported (errno))) - 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 (all_errors || (some_errors && !errno_unsupported (errno))) - 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) @@ -887,6 +981,18 @@ copy_reg (char const *src_name, char const *dst_name, /* Tell caller that the destination file was unlinked. */ *new_dst = true; + + /* Ensure there is no race where a file may be left without + an appropriate security context. */ + if (x->set_security_context) + { + if (! set_process_security_ctx (src_name, dst_name, dst_mode, + *new_dst, x)) + { + return_val = false; + goto close_src_desc; + } + } } } @@ -1127,7 +1233,7 @@ preserve_metadata: { bool access_changed = false; - if (!(sb.st_mode & S_IWUSR) && geteuid () != 0) + if (!(sb.st_mode & S_IWUSR) && geteuid () != ROOT_UID) access_changed = fchmod_or_lchmod (dest_desc, dst_name, 0600) == 0; if (!copy_attr (src_name, source_desc, dst_name, dest_desc, x) @@ -1459,8 +1565,9 @@ writable_destination (char const *file, mode_t mode) || euidaccess (file, W_OK) == 0); } -static void -overwrite_prompt (char const *dst_name, struct stat const *dst_sb) +static bool +overwrite_ok (struct cp_options const *x, char const *dst_name, + struct stat const *dst_sb) { if (! writable_destination (dst_name, dst_sb->st_mode)) { @@ -1468,7 +1575,10 @@ overwrite_prompt (char const *dst_name, struct stat const *dst_sb) strmode (dst_sb->st_mode, perms); perms[10] = '\0'; fprintf (stderr, - _("%s: try to overwrite %s, overriding mode %04lo (%s)? "), + (x->move_mode || x->unlink_dest_before_opening + || x->unlink_dest_after_failed_open) + ? _("%s: replace %s, overriding mode %04lo (%s)? ") + : _("%s: unwritable %s (mode %04lo, %s); try anyway? "), program_name, quote (dst_name), (unsigned long int) (dst_sb->st_mode & CHMOD_MODE_BITS), &perms[1]); @@ -1478,6 +1588,8 @@ overwrite_prompt (char const *dst_name, struct stat const *dst_sb) fprintf (stderr, _("%s: overwrite %s? "), program_name, quote (dst_name)); } + + return yesno (); } /* Initialize the hash table implementing a set of F_triple entries @@ -1532,8 +1644,7 @@ abandon_move (const struct cp_options *x, || (x->interactive == I_UNSPECIFIED && x->stdin_tty && ! writable_destination (dst_name, dst_sb->st_mode))) - && (overwrite_prompt (dst_name, dst_sb), 1) - && ! yesno ())); + && ! overwrite_ok (x, dst_name, dst_sb))); } /* Print --verbose output on standard output, e.g. 'new' -> 'old'. @@ -1557,18 +1668,23 @@ restore_default_fscreatecon_or_die (void) _("failed to restore the default file creation context")); } -/* Create a hard link DST_NAME to SRC_NAME, honoring the REPLACE and - VERBOSE settings. Return true upon success. Otherwise, diagnose - the failure and return false. - If SRC_NAME is a symbolic link it will not be followed. If the system - doesn't support hard links to symbolic links, then DST_NAME will - be created as a symbolic link to SRC_NAME. */ +/* Create a hard link DST_NAME to SRC_NAME, honoring the REPLACE, VERBOSE and + DEREFERENCE settings. Return true upon success. Otherwise, diagnose the + failure and return false. If SRC_NAME is a symbolic link, then it will not + be followed unless DEREFERENCE is true. + If the system doesn't support hard links to symbolic links, then DST_NAME + will be created as a symbolic link to SRC_NAME. */ static bool create_hard_link (char const *src_name, char const *dst_name, - bool replace, bool verbose) + bool replace, bool verbose, bool dereference) { - /* We want to guarantee that symlinks are not followed. */ - bool link_failed = (linkat (AT_FDCWD, src_name, AT_FDCWD, dst_name, 0) != 0); + /* We want to guarantee that symlinks are not followed, unless requested. */ + int flags = 0; + if (dereference) + flags = AT_SYMLINK_FOLLOW; + + bool link_failed = (linkat (AT_FDCWD, src_name, AT_FDCWD, dst_name, flags) + != 0); /* If the link failed because of an existing destination, remove that file and then call link again. */ @@ -1581,7 +1697,8 @@ create_hard_link (char const *src_name, char const *dst_name, } if (verbose) printf (_("removed %s\n"), quote (dst_name)); - link_failed = (linkat (AT_FDCWD, src_name, AT_FDCWD, dst_name, 0) != 0); + link_failed = (linkat (AT_FDCWD, src_name, AT_FDCWD, dst_name, flags) + != 0); } if (link_failed) @@ -1594,12 +1711,22 @@ create_hard_link (char const *src_name, char const *dst_name, return true; } +/* Return true if the current file should be (tried to be) dereferenced: + either for DEREF_ALWAYS or for DEREF_COMMAND_LINE_ARGUMENTS in the case + where the current file is a COMMAND_LINE_ARG; otherwise return false. */ +static inline bool _GL_ATTRIBUTE_PURE +should_dereference (const struct cp_options *x, bool command_line_arg) +{ + return x->dereference == DEREF_ALWAYS + || (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS + && command_line_arg); +} + /* 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 + be false if DST_NAME might already exist. A nonnull PARENT describes the + parent directory. 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. @@ -1609,7 +1736,7 @@ create_hard_link (char const *src_name, char const *dst_name, static bool copy_internal (char const *src_name, char const *dst_name, bool new_dst, - dev_t device, + struct stat const *parent, struct dir_list *ancestors, const struct cp_options *x, bool command_line_arg, @@ -1669,6 +1796,8 @@ copy_internal (char const *src_name, char const *dst_name, record_file (x->src_info, src_name, &src_sb); } + bool dereference = should_dereference (x, command_line_arg); + if (!new_dst) { /* Regular files can be created by writing through symbolic @@ -1747,7 +1876,7 @@ copy_internal (char const *src_name, char const *dst_name, /* Note we currently replace DST_NAME unconditionally, even if it was a newer separate file. */ if (! create_hard_link (earlier_file, dst_name, true, - x->verbose)) + x->verbose, dereference)) { goto un_backup; } @@ -1761,7 +1890,7 @@ copy_internal (char const *src_name, char const *dst_name, 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. + use of the --no-clobber option. cp and mv treat -i and -f differently. */ if (x->move_mode) @@ -1788,8 +1917,7 @@ copy_internal (char const *src_name, char const *dst_name, if (! S_ISDIR (src_mode) && (x->interactive == I_ALWAYS_NO || (x->interactive == I_ASK_USER - && (overwrite_prompt (dst_name, &dst_sb), 1) - && ! yesno ()))) + && ! overwrite_ok (x, dst_name, &dst_sb)))) return true; } @@ -2077,7 +2205,8 @@ copy_internal (char const *src_name, char const *dst_name, } else { - if (! create_hard_link (earlier_file, dst_name, true, x->verbose)) + if (! create_hard_link (earlier_file, dst_name, true, x->verbose, + dereference)) goto un_backup; return true; @@ -2092,6 +2221,12 @@ copy_internal (char const *src_name, char const *dst_name, emit_verbose (src_name, dst_name, backup_succeeded ? dst_backup : NULL); + if (x->set_security_context) + { + /* -Z failures are only warnings currently. */ + (void) set_file_security_ctx (dst_name, false, true, x); + } + if (rename_succeeded) *rename_succeeded = true; @@ -2171,8 +2306,12 @@ copy_internal (char const *src_name, char const *dst_name, /* 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) + the rename syscall. Note both src and dst must both be directories + or not, and this is enforced above. Therefore we check the src_mode + and operate on dst_name here as a tighter constraint and also because + src_mode is readily available here. */ + if ((S_ISDIR (src_mode) ? rmdir (dst_name) : unlink (dst_name)) != 0 + && errno != ENOENT) { error (0, errno, _("inter-device move failed: %s to %s; unable to remove target"), @@ -2197,40 +2336,12 @@ copy_internal (char const *src_name, char const *dst_name, delayed_ok = true; - if (x->preserve_security_context) - { - bool all_errors = !x->data_copy_required || x->require_preserve_context; - bool some_errors = !all_errors && !x->reduce_diagnostics; - security_context_t con; - - if (0 <= lgetfilecon (src_name, &con)) - { - if (setfscreatecon (con) < 0) - { - if (all_errors || (some_errors && !errno_unsupported (errno))) - 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 (all_errors || (some_errors && !errno_unsupported (errno))) - { - error (0, errno, - _("failed to get security context of %s"), - quote (src_name)); - } - if (x->require_preserve_context) - return false; - } - } + /* If required, set the default security context for new files. + Also for existing files this is used as a reference + when copying the context with --preserve=context. + FIXME: Do we need to consider dst_mode_bits here? */ + if (! set_process_security_ctx (src_name, dst_name, src_mode, new_dst, x)) + return false; if (S_ISDIR (src_mode)) { @@ -2308,10 +2419,21 @@ copy_internal (char const *src_name, char const *dst_name, else { omitted_permissions = 0; + + /* For directories, the process global context could be reset for + descendents, so use it to set the context for existing dirs here. + This will also give earlier indication of failure to set ctx. */ + if (x->set_security_context || x->preserve_security_context) + if (! set_file_security_ctx (dst_name, x->preserve_security_context, + false, x)) + { + if (x->require_preserve_context) + goto un_backup; + } } /* Decide whether to copy the contents of the directory. */ - if (x->one_file_system && device != 0 && device != src_sb.st_dev) + if (x->one_file_system && parent && parent->st_dev != 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. */ @@ -2373,18 +2495,16 @@ copy_internal (char const *src_name, char const *dst_name, should not follow the link. We can approximate the desired behavior by skipping this hard-link creating block and instead copying the symlink, via the 'S_ISLNK'- copying code below. - LINK_FOLLOWS_SYMLINKS is tri-state; if it is -1, we don't know - how link() behaves, so we use the fallback case for safety. Note gnulib's linkat module, guarantees that the symlink is not dereferenced. However its emulation currently doesn't maintain timestamps or ownership so we only call it when we know the emulation will not be needed. */ else if (x->hard_link - && !(LINK_FOLLOWS_SYMLINKS && S_ISLNK (src_mode) + && !(! CAN_HARDLINK_SYMLINKS && S_ISLNK (src_mode) && x->dereference == DEREF_NEVER)) { - if (! create_hard_link (src_name, dst_name, false, false)) + if (! create_hard_link (src_name, dst_name, false, false, dereference)) goto un_backup; } else if (S_ISREG (src_mode) @@ -2496,6 +2616,19 @@ copy_internal (char const *src_name, char const *dst_name, goto un_backup; } + /* With -Z or --preserve=context, set the context for existing files. + Note this is done already for copy_reg() for reasons described therein. */ + if (!new_dst && !x->copy_as_regular && !S_ISDIR (src_mode) + && (x->set_security_context || x->preserve_security_context)) + { + if (! set_file_security_ctx (dst_name, x->preserve_security_context, + false, x)) + { + if (x->require_preserve_context) + goto un_backup; + } + } + if (command_line_arg && x->dest_info) { /* Now that the destination file is very likely to exist, @@ -2508,7 +2641,7 @@ copy_internal (char const *src_name, char const *dst_name, /* 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) - && !(LINK_FOLLOWS_SYMLINKS && S_ISLNK (src_mode) + && !(! CAN_HARDLINK_SYMLINKS && S_ISLNK (src_mode) && x->dereference == DEREF_NEVER)) return delayed_ok; @@ -2544,12 +2677,8 @@ copy_internal (char const *src_name, char const *dst_name, } } - /* 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 + if (!dest_is_symlink && 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)) @@ -2563,12 +2692,17 @@ copy_internal (char const *src_name, char const *dst_name, } } - set_author (dst_name, -1, &src_sb); - + /* Set xattrs after ownership as changing owners will clear capabilities. */ if (x->preserve_xattr && ! copy_attr (src_name, -1, dst_name, -1, x) && x->require_preserve_xattr) return false; + /* The operations beyond this point may dereference a symlink. */ + if (dest_is_symlink) + return delayed_ok; + + set_author (dst_name, -1, &src_sb); + if (x->preserve_mode || x->move_mode) { if (copy_acl (src_name, -1, dst_name, -1, src_mode) != 0 @@ -2693,7 +2827,7 @@ copy (char const *src_name, char const *dst_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, + return copy_internal (src_name, dst_name, nonexistent_dst, NULL, NULL, options, true, &first_dir_created_per_command_line_arg, copy_into_self, rename_succeeded); @@ -2718,7 +2852,7 @@ cp_options_default (struct cp_options *x) priv_freeset (pset); } #else - x->chown_privileges = x->owner_privileges = (geteuid () == 0); + x->chown_privileges = x->owner_privileges = (geteuid () == ROOT_UID); #endif } @@ -2746,8 +2880,12 @@ owner_failure_ok (struct cp_options const *x) return ((errno == EPERM || errno == EINVAL) && !x->owner_privileges); } -/* Return the user's umask, caching the result. */ +/* Return the user's umask, caching the result. + FIXME: If the destination's parent directory has has a default ACL, + some operating systems (e.g., GNU/Linux's "POSIX" ACLs) use that + ACL's mask rather than the process umask. Currently, the callers + of cached_umask incorrectly assume that this situation cannot occur. */ extern mode_t cached_umask (void) { @@ -1,5 +1,5 @@ /* core functions for copying files and directories - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -159,6 +159,9 @@ struct cp_options bool preserve_timestamps; bool explicit_no_preserve_mode; + /* 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 --git a/src/coreutils-arch.c b/src/coreutils-arch.c new file mode 100644 index 00000000..899cc937 --- /dev/null +++ b/src/coreutils-arch.c @@ -0,0 +1,32 @@ +/* arch -- wrapper to uname with the right uname_mode. + Copyright (C) 2014 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 <http://www.gnu.org/licenses/>. */ + +/* Written by Alex Deymo <deymo@chromium.org>. */ + +#include <config.h> +#include "system.h" + +#include "uname.h" +/* Ensure that the main for uname is declared even if the tool is not being + built in this single-binary. */ +int _single_binary_main_uname (int argc, char** argv) ATTRIBUTE_NORETURN; +int _single_binary_main_arch (int argc, char** argv) ATTRIBUTE_NORETURN; + +int _single_binary_main_arch (int argc, char** argv) +{ + uname_mode = UNAME_ARCH; + _single_binary_main_uname (argc, argv); +} diff --git a/src/coreutils-dir.c b/src/coreutils-dir.c new file mode 100644 index 00000000..4b488f41 --- /dev/null +++ b/src/coreutils-dir.c @@ -0,0 +1,32 @@ +/* dir -- wrapper to ls with the right ls_mode. + Copyright (C) 2014 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 <http://www.gnu.org/licenses/>. */ + +/* Written by Alex Deymo <deymo@chromium.org>. */ + +#include <config.h> +#include "system.h" + +#include "ls.h" +/* Ensure that the main for ls is declared even if the tool is not being built + in this single-binary. */ +int _single_binary_main_ls (int argc, char** argv) ATTRIBUTE_NORETURN; +int _single_binary_main_dir (int argc, char** argv) ATTRIBUTE_NORETURN; + +int _single_binary_main_dir (int argc, char** argv) +{ + ls_mode = LS_MULTI_COL; + _single_binary_main_ls (argc, argv); +} diff --git a/src/coreutils-vdir.c b/src/coreutils-vdir.c new file mode 100644 index 00000000..036367f6 --- /dev/null +++ b/src/coreutils-vdir.c @@ -0,0 +1,32 @@ +/* vdir -- wrapper to ls with the right ls_mode. + Copyright (C) 2014 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 <http://www.gnu.org/licenses/>. */ + +/* Written by Alex Deymo <deymo@chromium.org>. */ + +#include <config.h> +#include "system.h" + +#include "ls.h" +/* Ensure that the main for ls is declared even if the tool is not being built + in this single-binary. */ +int _single_binary_main_ls (int argc, char** argv) ATTRIBUTE_NORETURN; +int _single_binary_main_vdir (int argc, char** argv) ATTRIBUTE_NORETURN; + +int _single_binary_main_vdir (int argc, char** argv) +{ + ls_mode = LS_LONG_FORMAT; + _single_binary_main_ls (argc, argv); +} diff --git a/src/coreutils.c b/src/coreutils.c new file mode 100644 index 00000000..c459b1d6 --- /dev/null +++ b/src/coreutils.c @@ -0,0 +1,205 @@ +/* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>. */ + +/* coreutils.c aggregates the functionality of every other tool into a single + binary multiplexed by the value of argv[0]. This is enabled by passing + --enable-single-binary to configure. + + Written by Alex Deymo <deymo@chromium.org>. */ + +#include <config.h> +#include <getopt.h> +#include <stdio.h> +#if HAVE_PRCTL +# include <sys/prctl.h> +#endif + +#include "system.h" +#include "error.h" +#include "quote.h" + +#ifdef SINGLE_BINARY +/* Declare the main function on each one of the selected tools. This name + needs to match the one passed as CFLAGS on single-binary.mk (generated + by gen-single-binary.sh). */ +# define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \ + int _single_binary_main_##main_name (int, char**) ATTRIBUTE_NORETURN; +# include "coreutils.h" +# undef SINGLE_BINARY_PROGRAM +#endif + +/* The official name of this program (e.g., no 'g' prefix). */ +#define PROGRAM_NAME "coreutils" + +#define AUTHORS \ + proper_name ("Alex Deymo") + +void +launch_program (const char *prog_name, int prog_argc, char **prog_argv); + +static struct option const long_options[] = +{ + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + + +void +usage (int status) +{ + if (status != EXIT_SUCCESS) + emit_try_help (); + else + { + printf (_("\ +Usage: %s --coreutils-prog=PROGRAM_NAME [PARAMETERS]... \n"), + program_name); + fputs (_("\ +Execute the PROGRAM_NAME built-in program with the given PARAMETERS.\n\ +\n"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + + printf ("\n\ +Built-in programs:\n" +#ifdef SINGLE_BINARY +/* XXX: Ideally we#d like to present "install" here, not "ginstall". */ +# define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) " " prog_name_str +# include "coreutils.h" +# undef SINGLE_BINARY_PROGRAM +#endif + "\n"); + + printf (_("\ +\n\ +Use: '%s --coreutils-prog=PROGRAM_NAME --help' for individual program help.\n"), + program_name); + emit_ancillary_info (); + } + exit (status); +} + +void +launch_program (const char *prog_name, int prog_argc, char **prog_argv) +{ + int (*prog_main)(int, char **) = NULL; + + /* Ensure that at least one parameter was passed. */ + if (!prog_argc || !prog_argv || !prog_argv[0] || !prog_name) + return; + +#ifdef SINGLE_BINARY + if (false); + /* Lookup the right main program. */ +# define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \ + else if (STREQ (prog_name_str, prog_name)) \ + prog_main = _single_binary_main_##main_name; +# include "coreutils.h" +# undef SINGLE_BINARY_PROGRAM +#endif + + if (! prog_main) + return; + +#if HAVE_PRCTL && defined PR_SET_NAME + /* Not being able to set the program name is not a fatal error. */ + prctl (PR_SET_NAME, prog_argv[0]); +#endif +#if HAVE_PRCTL && defined PR_SET_MM_ARG_START + /* Shift the beginning of the command line to prog_argv[0] (if set) so + /proc/pid/cmdline reflects the right value. */ + prctl (PR_SET_MM_ARG_START, prog_argv[0]); +#endif + + exit ((*prog_main) (prog_argc, prog_argv)); +} + +int +main (int argc, char **argv) +{ + char *prog_name = last_component (argv[0]); + int optc; + + /* Map external name to internal name. */ + char ginstall[] = "ginstall"; + if (STREQ (prog_name, "install")) + prog_name = ginstall; + + /* If this program is called directly as "coreutils" or if the value of + argv[0] is an unknown tool (which "coreutils" is), we proceed and parse + the options. */ + launch_program (prog_name, argc, argv); + + /* No known program was selected via argv[0]. Try parsing the first + argument as --coreutils-prog=PROGRAM to determine the program. The + invocation for this case should be: + path/to/coreutils --coreutils-prog=someprog someprog ... + The third argument is what the program will see as argv[0]. */ + + if (argc >= 2) + { + size_t nskip = 0; + char *arg_name = NULL; + + /* If calling coreutils directly, the "script" name isn't passed. + Distinguish the two cases with a -shebang suffix. */ + if (STRPREFIX (argv[1], "--coreutils-prog=")) + { + nskip = 1; + arg_name = prog_name = argv[1] + strlen ("--coreutils-prog="); + } + else if (STRPREFIX (argv[1], "--coreutils-prog-shebang=")) + { + nskip = 2; + prog_name = argv[1] + strlen ("--coreutils-prog-shebang="); + if (argc >= 3) + arg_name = last_component (argv[2]); + else + arg_name = prog_name; + } + + if (nskip) + { + argv[nskip] = arg_name; /* XXX: Discards any specified path. */ + launch_program (prog_name, argc - nskip, argv + nskip); + error (EXIT_FAILURE, 0, _("unknown program %s"), quote (prog_name)); + } + } + + /* No known program was selected. From here on, we behave like any other + coreutils program. */ + initialize_main (&argc, &argv); + set_program_name (argv[0]); + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + atexit (close_stdout); + + if ((optc = getopt_long (argc, argv, "", long_options, NULL)) != -1) + switch (optc) + { + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + } + + /* Only print the error message when no options have been passed + to coreutils. */ + if (optind == 1 && prog_name && !STREQ (prog_name, "coreutils")) + error (0, 0, _("unknown program %s"), quote (prog_name)); + + usage (EXIT_FAILURE); +} diff --git a/src/cp-hash.c b/src/cp-hash.c index 9ef23fc4..258aff76 100644 --- a/src/cp-hash.c +++ b/src/cp-hash.c @@ -1,5 +1,5 @@ /* cp-hash.c -- file copying (hash search routines) - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -1,5 +1,5 @@ /* cp.c -- file copying (main routines) - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -141,6 +141,7 @@ static struct option const long_opts[] = {"target-directory", required_argument, NULL, 't'}, {"update", no_argument, NULL, 'u'}, {"verbose", no_argument, NULL, 'v'}, + {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} @@ -228,6 +229,12 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\ -v, --verbose explain what is being done\n\ -x, --one-file-system stay on this file system\n\ "), stdout); + fputs (_("\ + -Z set SELinux security context of destination\n\ + file to default type\n\ + --context[=CTX] like -Z, or if CTX is specified then set the\n\ + SELinux or SMACK security context to CTX\n\ +"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); fputs (_("\ @@ -782,8 +789,9 @@ cp_option_init (struct cp_options *x) x->preserve_mode = false; x->preserve_timestamps = false; x->explicit_no_preserve_mode = false; - x->preserve_security_context = false; - x->require_preserve_context = false; + x->preserve_security_context = false; /* -a or --preserve=context. */ + x->require_preserve_context = false; /* --preserve=context. */ + x->set_security_context = false; /* -Z, set sys default context. */ x->preserve_xattr = false; x->reduce_diagnostics = false; x->require_preserve_xattr = false; @@ -854,7 +862,8 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off) *comma++ = 0; /* process S. */ - val = XARGMATCH ("--preserve", s, preserve_args, preserve_vals); + val = XARGMATCH (on_off ? "--preserve" : "--no-preserve", + s, preserve_args, preserve_vals); switch (val) { case PRESERVE_MODE: @@ -875,8 +884,8 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off) break; case PRESERVE_CONTEXT: - x->preserve_security_context = on_off; x->require_preserve_context = on_off; + x->preserve_security_context = on_off; break; case PRESERVE_XATTR: @@ -917,6 +926,7 @@ main (int argc, char **argv) bool copy_contents = false; char *target_directory = NULL; bool no_target_directory = false; + char const *scontext = NULL; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -933,7 +943,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, "abdfHilLnprst:uvxPRS:TZ", long_opts, NULL)) != -1) { @@ -1091,6 +1101,23 @@ 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) + { + if (optarg) + scontext = optarg; + else + x.set_security_context = true; + } + else if (optarg) + { + error (0, 0, + _("warning: ignoring --context; " + "it requires an SELinux-enabled kernel")); + } + break; + case 'S': make_backups = true; backup_suffix_string = optarg; @@ -1134,7 +1161,7 @@ main (int argc, char **argv) if (x.dereference == DEREF_UNDEFINED) { - if (x.recursive) + if (x.recursive && ! x.hard_link) /* This is compatible with FreeBSD. */ x.dereference = DEREF_NEVER; else @@ -1149,13 +1176,30 @@ main (int argc, char **argv) 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")); - } + /* Ensure -Z overrides -a. */ + if ((x.set_security_context || scontext) + && ! x.require_preserve_context) + x.preserve_security_context = false; + + if (x.preserve_security_context && (x.set_security_context || scontext)) + error (EXIT_FAILURE, 0, + _("cannot set target context and preserve it")); + + if (x.require_preserve_context && ! selinux_enabled) + error (EXIT_FAILURE, 0, + _("cannot preserve security context " + "without an SELinux-enabled kernel")); + + /* FIXME: This handles new files. But what about existing files? + I.E. if updating a tree, new files would have the specified context, + but shouldn't existing files be updated for consistency like this? + if (scontext) + restorecon (dst_path, 0, true); + */ + if (scontext && setfscreatecon (se_const (scontext)) < 0) + error (EXIT_FAILURE, errno, + _("failed to set default file creation context to %s"), + quote (scontext)); #if !USE_XATTR if (x.require_preserve_xattr) diff --git a/src/csplit.c b/src/csplit.c index 22f3ad4b..a30f09b7 100644 --- a/src/csplit.c +++ b/src/csplit.c @@ -1,5 +1,5 @@ /* csplit - split a file into sections determined by context lines - Copyright (C) 1991-2013 Free Software Foundation, Inc. + Copyright (C) 1991-2014 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 @@ -19,6 +19,7 @@ #include <config.h> +#include <assert.h> #include <getopt.h> #include <sys/types.h> #include <signal.h> @@ -166,6 +167,9 @@ static bool volatile remove_files; /* If true, remove all output files which have a zero length. */ static bool elide_empty_files; +/* If true, suppress the lines that match the PATTERN */ +static bool suppress_matched; + /* The compiled pattern arguments, which determine how to split the input file. */ static struct control *controls; @@ -176,6 +180,13 @@ static size_t control_used; /* The set of signals that are caught. */ static sigset_t caught_signals; +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + SUPPRESS_MATCHED_OPTION = CHAR_MAX + 1 +}; + static struct option const longopts[] = { {"digits", required_argument, NULL, 'n'}, @@ -185,6 +196,7 @@ static struct option const longopts[] = {"elide-empty-files", no_argument, NULL, 'z'}, {"prefix", required_argument, NULL, 'f'}, {"suffix-format", required_argument, NULL, 'b'}, + {"suppress-matched", no_argument, NULL, SUPPRESS_MATCHED_OPTION}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} @@ -601,6 +613,7 @@ find_line (uintmax_t linenum) for (b = head;;) { + assert (b); if (linenum < b->start_line + b->num_lines) { /* The line is in this buffer. */ @@ -717,15 +730,19 @@ process_line_count (const struct control *p, uintmax_t repetition) { uintmax_t linenum; uintmax_t last_line_to_save = p->lines_required * (repetition + 1); - struct cstring *line; create_output_file (); - linenum = get_first_line_in_buffer (); + /* Ensure that the line number specified is not 1 greater than + the number of lines in the file. + When suppressing matched lines, check before the loop. */ + if (no_more_lines () && suppress_matched) + handle_line_error (p, repetition); + linenum = get_first_line_in_buffer (); while (linenum++ < last_line_to_save) { - line = remove_line (); + struct cstring *line = remove_line (); if (line == NULL) handle_line_error (p, repetition); save_line_to_file (line); @@ -733,9 +750,12 @@ process_line_count (const struct control *p, uintmax_t repetition) close_output_file (); + if (suppress_matched) + remove_line (); + /* Ensure that the line number specified is not 1 greater than the number of lines in the file. */ - if (no_more_lines ()) + if (no_more_lines () && !suppress_matched) handle_line_error (p, repetition); } @@ -778,6 +798,9 @@ process_regexp (struct control *p, uintmax_t repetition) if (!ignore) create_output_file (); + if (suppress_matched && current_line > 0) + remove_line (); + /* If there is no offset for the regular expression, or it is positive, then it is not necessary to buffer the lines. */ @@ -1324,6 +1347,7 @@ main (int argc, char **argv) control_used = 0; suppress_count = false; remove_files = true; + suppress_matched = false; prefix = DEFAULT_PREFIX; while ((optc = getopt_long (argc, argv, "f:b:kn:sqz", longopts, NULL)) != -1) @@ -1357,6 +1381,10 @@ main (int argc, char **argv) elide_empty_files = true; break; + case SUPPRESS_MATCHED_OPTION: + suppress_matched = true; + break; + case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -1465,6 +1493,9 @@ and output byte counts of each piece to standard output.\n\ -k, --keep-files do not remove output files on errors\n\ "), stdout); fputs (_("\ + -m, --suppress-matched suppress the lines matching PATTERN\n\ +"), stdout); + fputs (_("\ -n, --digits=DIGITS use specified number of digits instead of 2\n\ -s, --quiet, --silent do not print counts of output file sizes\n\ -z, --elide-empty-files remove empty output files\n\ diff --git a/src/cu-progs.mk b/src/cu-progs.mk index dba03ad0..66ebd1b8 100644 --- a/src/cu-progs.mk +++ b/src/cu-progs.mk @@ -1,6 +1,7 @@ ## Automatically generated by gen-lists-of-programs.sh. DO NOT EDIT BY HAND! no_install__progs = no_install__progs += src/arch +no_install__progs += src/coreutils no_install__progs += src/hostname build_if_possible__progs = build_if_possible__progs += src/chroot @@ -1,5 +1,5 @@ /* cut - remove parts of lines of files - Copyright (C) 1997-2013 Free Software Foundation, Inc. + Copyright (C) 1997-2014 Free Software Foundation, Inc. Copyright (C) 1984 David M. Ihnat This program is free software: you can redistribute it and/or modify @@ -53,24 +53,6 @@ } \ while (0) -/* 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) struct range_pair { @@ -78,6 +60,36 @@ struct range_pair size_t hi; }; +/* Array of `struct range_pair' holding all the finite ranges. */ +static struct range_pair *rp; + +/* Pointer inside RP. When checking if a byte or field is selected + by a finite range, we check if it is between CURRENT_RP.LO + and CURRENT_RP.HI. If the byte or field index is greater than + CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */ +static struct range_pair *current_rp; + +/* Number of finite ranges specified by the user. */ +static size_t n_rp; + +/* Number of `struct range_pair's allocated. */ +static size_t n_rp_allocated; + + +/* Append LOW, HIGH to the list RP of range pairs, allocating additional + space if necessary. Update global variable N_RP. When allocating, + update global variable N_RP_ALLOCATED. */ + +static void +add_range_pair (size_t lo, size_t hi) +{ + if (n_rp == n_rp_allocated) + rp = X2NREALLOC (rp, &n_rp_allocated); + rp[n_rp].lo = lo; + rp[n_rp].hi = hi; + ++n_rp; +} + /* 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 @@ -90,26 +102,6 @@ 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; - enum operating_mode { undefined_mode, @@ -117,22 +109,22 @@ enum operating_mode /* Output characters that are in the given bytes. */ byte_mode, - /* Output the given delimeter-separated fields. */ + /* Output the given delimiter-separated fields. */ field_mode }; static enum operating_mode operating_mode; -/* If true do not output lines containing no delimeter characters. +/* If true do not output lines containing no delimiter characters. Otherwise, all such lines are printed. This option is valid only with field mode. */ static bool suppress_non_delimited; -/* If nonzero, print all bytes, characters, or fields _except_ +/* If true, print all bytes, characters, or fields _except_ those that were specified. */ static bool complement; -/* The delimeter character for field mode. */ +/* The delimiter character for field mode. */ static unsigned char delim; /* True if the --output-delimiter=STRING option was specified. */ @@ -148,15 +140,6 @@ static char *output_delimiter_string; /* True if we have ever read standard input. */ static bool have_read_stdin; -#define HT_RANGE_START_INDEX_INITIAL_CAPACITY 31 - -/* 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; - /* For long options that have no equivalent short option, use a non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum @@ -239,103 +222,57 @@ With no FILE, or when FILE is -, read standard input.\n\ 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); -} - -static inline void -mark_printable_field (size_t i) -{ - size_t n = i / CHAR_BIT; - printable_field[n] |= (1 << (i % CHAR_BIT)); -} - -static inline bool -is_printable_field (size_t i) +/* Comparison function for qsort to order the list of + struct range_pairs. */ +static int +compare_ranges (const void *a, const void *b) { - size_t n = i / CHAR_BIT; - return (printable_field[n] >> (i % CHAR_BIT)) & 1; + 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; } -static size_t -hash_int (const void *x, size_t tablesize) -{ -#ifdef UINTPTR_MAX - uintptr_t y = (uintptr_t) x; -#else - size_t y = (size_t) x; -#endif - return y % tablesize; -} +/* Reallocate Range Pair entries, with corresponding + entries outside the range of each specified entry. */ -static bool -hash_compare_ints (void const *x, void const *y) +static void +complement_rp (void) { - return (x == y) ? true : false; -} + if (complement) + { + struct range_pair *c = rp; + size_t n = n_rp; + size_t i; -static bool -is_range_start_index (size_t i) -{ - return hash_lookup (range_start_ht, (void *) i) ? true : false; -} + rp = NULL; + n_rp = 0; + n_rp_allocated = 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. */ + if (c[0].lo > 1) + add_range_pair (1, c[0].lo - 1); -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))); + for (i = 1; i < n; ++i) + { + if (c[i-1].hi + 1 == c[i].lo) + continue; - bool is_selected = k_selected ^ complement; - if (range_start && is_selected) - *range_start = is_range_start_index (k); + add_range_pair (c[i-1].hi + 1, c[i].lo - 1); + } - return is_selected; -} + if (c[n-1].hi < SIZE_MAX) + add_range_pair (c[n-1].hi + 1, SIZE_MAX); -/* 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; + free (c); + } } -/* 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. */ +/* Given the list of field or byte range specifications FIELDSTR, + allocate and initialize the RP array. 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. */ static bool set_fields (const char *fieldstr) @@ -348,14 +285,10 @@ set_fields (const char *fieldstr) 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. */ + /* Collect and store in RP the range end points. */ while (true) { @@ -390,10 +323,8 @@ set_fields (const char *fieldstr) In any case, 'initial' contains the start of the range. */ if (!rhs_specified) { - /* 'n-'. From 'initial' to end of line. If we've already - seen an M- range, ignore subsequent N- unless N < M. */ - if (eol_range_start == 0 || initial < eol_range_start) - eol_range_start = initial; + /* 'n-'. From 'initial' to end of line. */ + add_range_pair (initial, SIZE_MAX); field_found = true; } else @@ -402,54 +333,23 @@ set_fields (const char *fieldstr) if (value < initial) FATAL_ERROR (_("invalid decreasing range")); - /* 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); - } - - /* 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; + add_range_pair (initial, value); + field_found = true; } + value = 0; } else { /* A simple field number, not a range. */ - ADD_RANGE_PAIR (rp, value, value); + if (value == 0) + FATAL_ERROR (_("fields and positions are numbered from 1")); + add_range_pair (value, value); value = 0; field_found = true; } if (*fieldstr == '\0') - { - break; - } + break; fieldstr++; lhs_specified = false; @@ -470,7 +370,8 @@ set_fields (const char *fieldstr) lhs_specified = 1; /* Detect overflow. */ - if (!DECIMAL_DIGIT_ACCUMULATE (value, *fieldstr - '0', size_t)) + if (!DECIMAL_DIGIT_ACCUMULATE (value, *fieldstr - '0', size_t) + || value == SIZE_MAX) { /* In case the user specified -c$(echo 2^64|bc),22, complain only about the first number. */ @@ -493,51 +394,62 @@ set_fields (const char *fieldstr) FATAL_ERROR (_("invalid byte, character or field list")); } - max_range_endpoint = 0; - for (i = 0; i < n_rp; i++) + qsort (rp, n_rp, sizeof (rp[0]), compare_ranges); + + /* Merge range pairs (e.g. `2-5,3-4' becomes `2-5'). */ + for (i = 0; i < n_rp; ++i) { - if (rp[i].hi > max_range_endpoint) - max_range_endpoint = rp[i].hi; + for (size_t j = i + 1; j < n_rp; ++j) + { + if (rp[j].lo <= rp[i].hi) + { + rp[i].hi = MAX (rp[j].hi, rp[i].hi); + memmove (rp + j, rp + j + 1, (n_rp - j - 1) * sizeof *rp); + n_rp--; + j--; + } + else + break; + } } - /* 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. */ + complement_rp (); - if (max_range_endpoint) - printable_field = xzalloc (max_range_endpoint / CHAR_BIT + 1); + /* After merging, reallocate RP so we release memory to the system. + Also add a sentinel at the end of RP, to avoid out of bounds access + and for performance reasons. */ + ++n_rp; + rp = xrealloc (rp, n_rp * sizeof (struct range_pair)); + rp[n_rp - 1].lo = rp[n_rp - 1].hi = SIZE_MAX; - qsort (rp, n_rp, sizeof (rp[0]), compare_ranges); + return field_found; +} - /* Set the array entries corresponding to integers in the ranges of RP. */ - for (i = 0; i < n_rp; i++) - { - /* Ignore any range that is subsumed by the to-EOL range. */ - if (eol_range_start && eol_range_start <= rp[i].lo) - continue; - - /* Record the range-start indices, i.e., record each start - index that is not part of any other (lo..hi] range. */ - size_t 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 (size_t j = rp[i].lo; j <= rp[i].hi; j++) - mark_printable_field (j); - } +/* Increment *ITEM_IDX (i.e. a field or byte index), + and if required CURRENT_RP. */ - if (output_delimiter_specified - && !complement - && eol_range_start - && max_range_endpoint - && (max_range_endpoint < eol_range_start - || !is_printable_field (eol_range_start))) - mark_range_start (eol_range_start); +static inline void +next_item (size_t *item_idx) +{ + (*item_idx)++; + if ((*item_idx) > current_rp->hi) + current_rp++; +} - free (rp); +/* Return nonzero if the K'th field or byte is printable. */ - return field_found; +static inline bool +print_kth (size_t k) +{ + return current_rp->lo <= k; +} + +/* Return nonzero if K'th byte is the beginning of a range. */ + +static inline bool +is_range_start_index (size_t k) +{ + return k == current_rp->lo; } /* Read from stream STREAM, printing to standard output any selected bytes. */ @@ -552,7 +464,8 @@ cut_bytes (FILE *stream) byte_idx = 0; print_delimiter = false; - while (1) + current_rp = rp; + while (true) { int c; /* Each character from the file. */ @@ -563,6 +476,7 @@ cut_bytes (FILE *stream) putchar ('\n'); byte_idx = 0; print_delimiter = false; + current_rp = rp; } else if (c == EOF) { @@ -572,16 +486,19 @@ cut_bytes (FILE *stream) } else { - bool range_start; - bool *rs = output_delimiter_specified ? &range_start : NULL; - if (print_kth (++byte_idx, rs)) + next_item (&byte_idx); + if (print_kth (byte_idx)) { - if (rs && *rs && print_delimiter) + if (output_delimiter_specified) { - fwrite (output_delimiter_string, sizeof (char), - output_delimiter_length, stdout); + if (print_delimiter && is_range_start_index (byte_idx)) + { + fwrite (output_delimiter_string, sizeof (char), + output_delimiter_length, stdout); + } + print_delimiter = true; } - print_delimiter = true; + putchar (c); } } @@ -598,6 +515,8 @@ cut_fields (FILE *stream) bool found_any_selected_field = false; bool buffer_first_field; + current_rp = rp; + c = getc (stream); if (c == EOF) return; @@ -611,7 +530,7 @@ cut_fields (FILE *stream) 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)); + buffer_first_field = (suppress_non_delimited ^ !print_kth (1)); while (1) { @@ -619,7 +538,6 @@ cut_fields (FILE *stream) { ssize_t len; size_t n_bytes; - bool got_line; len = getndelim2 (&field_1_buffer, &field_1_bufsize, 0, GETNLINE_NO_LIMIT, delim, '\n', stream); @@ -636,14 +554,13 @@ cut_fields (FILE *stream) assert (n_bytes != 0); c = 0; - got_line = field_1_buffer[n_bytes - 1] == '\n'; /* 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 || got_line) + if (to_uchar (field_1_buffer[n_bytes - 1]) != delim) { - if (suppress_non_delimited && !(got_line && delim == '\n')) + if (suppress_non_delimited) { /* Empty. */ } @@ -651,24 +568,36 @@ cut_fields (FILE *stream) { fwrite (field_1_buffer, sizeof (char), n_bytes, stdout); /* Make sure the output line is newline terminated. */ - if (! got_line) + if (field_1_buffer[n_bytes - 1] != '\n') putchar ('\n'); c = '\n'; } continue; } - if (print_kth (1, NULL)) + if (print_kth (1)) { /* Print the field, but not the trailing delimiter. */ fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout); - found_any_selected_field = true; + + /* With -d$'\n' don't treat the last '\n' as a delimiter. */ + if (delim == '\n') + { + int last_c = getc (stream); + if (last_c != EOF) + { + ungetc (last_c, stream); + found_any_selected_field = true; + } + } + else + found_any_selected_field = true; } - ++field_idx; + next_item (&field_idx); } int prev_c = c; - if (print_kth (field_idx, NULL)) + if (print_kth (field_idx)) { if (found_any_selected_field) { @@ -691,21 +620,32 @@ cut_fields (FILE *stream) } } - if (c == '\n' || c == EOF) + /* With -d$'\n' don't treat the last '\n' as a delimiter. */ + if (delim == '\n' && c == delim) + { + int last_c = getc (stream); + if (last_c != EOF) + ungetc (last_c, stream); + else + c = last_c; + } + + if (c == delim) + next_item (&field_idx); + else if (c == '\n' || c == EOF) { if (found_any_selected_field || !(suppress_non_delimited && field_idx == 1)) { - if (c == '\n' || prev_c != '\n') + if (c == '\n' || prev_c != '\n' || delim == '\n') putchar ('\n'); } if (c == EOF) break; field_idx = 1; + current_rp = rp; found_any_selected_field = false; } - else if (c == delim) - field_idx++; } } @@ -854,16 +794,6 @@ main (int argc, char **argv) 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) @@ -890,8 +820,6 @@ main (int argc, char **argv) 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) { @@ -1,5 +1,5 @@ /* date - print or set the system date and time - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -151,7 +151,7 @@ Display the current time in the given FORMAT, or set the system date.\n\ Date and time components are separated by\n\ a single space: 2006-08-07 12:34:56-06:00\n\ -s, --set=STRING set time described by STRING\n\ - -u, --utc, --universal print or set Coordinated Universal Time\n\ + -u, --utc, --universal print or set Coordinated Universal Time (UTC)\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -1,7 +1,7 @@ #!/usr/bin/perl -w # dcgen -- convert dircolors.hin to dircolors.h. -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 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 @@ -1,5 +1,5 @@ /* dd -- convert a file while copying it. - Copyright (C) 1985-2013 Free Software Foundation, Inc. + Copyright (C) 1985-2014 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 @@ -136,9 +136,7 @@ enum enum { STATUS_NOXFER = 01, - STATUS_NOCOUNTS = 02, - STATUS_LAST = STATUS_NOCOUNTS, - STATUS_NONE = STATUS_LAST | (STATUS_LAST - 1) + STATUS_NONE = 02 }; /* The name of the input file, or NULL for the standard input. */ @@ -236,6 +234,9 @@ static uintmax_t r_truncate = 0; static char newline_character = '\n'; static char space_character = ' '; +/* Input buffer. */ +static char *ibuf; + /* Output buffer. */ static char *obuf; @@ -273,9 +274,9 @@ struct symbol_value /* Conversion symbols, for conv="...". */ static struct symbol_value const conversions[] = { - {"ascii", C_ASCII | C_TWOBUFS}, /* EBCDIC to ASCII. */ - {"ebcdic", C_EBCDIC | C_TWOBUFS}, /* ASCII to EBCDIC. */ - {"ibm", C_IBM | C_TWOBUFS}, /* Slightly different ASCII to EBCDIC. */ + {"ascii", C_ASCII | C_UNBLOCK | C_TWOBUFS}, /* EBCDIC to ASCII. */ + {"ebcdic", C_EBCDIC | C_BLOCK | C_TWOBUFS}, /* ASCII to EBCDIC. */ + {"ibm", C_IBM | C_BLOCK | C_TWOBUFS}, /* Different ASCII to EBCDIC. */ {"block", C_BLOCK | C_TWOBUFS}, /* Variable to fixed length records. */ {"unblock", C_UNBLOCK | C_TWOBUFS}, /* Fixed to variable length records. */ {"lcase", C_LCASE | C_TWOBUFS}, /* Translate upper to lower case. */ @@ -380,24 +381,29 @@ static struct symbol_value const statuses[] = /* Translation table formed by applying successive transformations. */ static unsigned char trans_table[256]; +/* Standard translation tables, taken from POSIX 1003.1-2013. + Beware of imitations; there are lots of ASCII<->EBCDIC tables + floating around the net, perhaps valid for some applications but + not correct here. */ + static char const ascii_to_ebcdic[] = { '\000', '\001', '\002', '\003', '\067', '\055', '\056', '\057', '\026', '\005', '\045', '\013', '\014', '\015', '\016', '\017', '\020', '\021', '\022', '\023', '\074', '\075', '\062', '\046', '\030', '\031', '\077', '\047', '\034', '\035', '\036', '\037', - '\100', '\117', '\177', '\173', '\133', '\154', '\120', '\175', + '\100', '\132', '\177', '\173', '\133', '\154', '\120', '\175', '\115', '\135', '\134', '\116', '\153', '\140', '\113', '\141', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\172', '\136', '\114', '\176', '\156', '\157', '\174', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\342', '\343', '\344', '\345', '\346', - '\347', '\350', '\351', '\112', '\340', '\132', '\137', '\155', + '\347', '\350', '\351', '\255', '\340', '\275', '\232', '\155', '\171', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\242', '\243', '\244', '\245', '\246', - '\247', '\250', '\251', '\300', '\152', '\320', '\241', '\007', + '\247', '\250', '\251', '\300', '\117', '\320', '\137', '\007', '\040', '\041', '\042', '\043', '\044', '\025', '\006', '\027', '\050', '\051', '\052', '\053', '\054', '\011', '\012', '\033', '\060', '\061', '\032', '\063', '\064', '\065', '\066', '\010', @@ -407,10 +413,10 @@ static char const ascii_to_ebcdic[] = '\130', '\131', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\200', '\212', '\213', '\214', '\215', - '\216', '\217', '\220', '\232', '\233', '\234', '\235', '\236', - '\237', '\240', '\252', '\253', '\254', '\255', '\256', '\257', + '\216', '\217', '\220', '\152', '\233', '\234', '\235', '\236', + '\237', '\240', '\252', '\253', '\254', '\112', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', - '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\270', '\271', '\272', '\273', '\274', '\241', '\276', '\277', '\312', '\313', '\314', '\315', '\316', '\317', '\332', '\333', '\334', '\335', '\336', '\337', '\352', '\353', '\354', '\355', '\356', '\357', '\372', '\373', '\374', '\375', '\376', '\377' @@ -463,21 +469,21 @@ static char const ebcdic_to_ascii[] = '\220', '\221', '\026', '\223', '\224', '\225', '\226', '\004', '\230', '\231', '\232', '\233', '\024', '\025', '\236', '\032', '\040', '\240', '\241', '\242', '\243', '\244', '\245', '\246', - '\247', '\250', '\133', '\056', '\074', '\050', '\053', '\041', + '\247', '\250', '\325', '\056', '\074', '\050', '\053', '\174', '\046', '\251', '\252', '\253', '\254', '\255', '\256', '\257', - '\260', '\261', '\135', '\044', '\052', '\051', '\073', '\136', + '\260', '\261', '\041', '\044', '\052', '\051', '\073', '\176', '\055', '\057', '\262', '\263', '\264', '\265', '\266', '\267', - '\270', '\271', '\174', '\054', '\045', '\137', '\076', '\077', + '\270', '\271', '\313', '\054', '\045', '\137', '\076', '\077', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', '\302', '\140', '\072', '\043', '\100', '\047', '\075', '\042', '\303', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\152', '\153', '\154', '\155', '\156', '\157', '\160', - '\161', '\162', '\313', '\314', '\315', '\316', '\317', '\320', - '\321', '\176', '\163', '\164', '\165', '\166', '\167', '\170', - '\171', '\172', '\322', '\323', '\324', '\325', '\326', '\327', + '\161', '\162', '\136', '\314', '\315', '\316', '\317', '\320', + '\321', '\345', '\163', '\164', '\165', '\166', '\167', '\170', + '\171', '\172', '\322', '\323', '\324', '\133', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', - '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\340', '\341', '\342', '\343', '\344', '\135', '\346', '\347', '\173', '\101', '\102', '\103', '\104', '\105', '\106', '\107', '\110', '\111', '\350', '\351', '\352', '\353', '\354', '\355', '\175', '\112', '\113', '\114', '\115', '\116', '\117', '\120', @@ -646,6 +652,65 @@ Options are:\n\ exit (status); } +static char * +human_size (size_t n) +{ + static char hbuf[LONGEST_HUMAN_READABLE + 1]; + int human_opts = + (human_autoscale | human_round_to_nearest | human_base_1024 + | human_space_before_unit | human_SI | human_B); + return human_readable (n, hbuf, human_opts, 1, 1); +} + +/* Ensure input buffer IBUF is allocated. */ + +static void +alloc_ibuf (void) +{ + if (ibuf) + return; + + char *real_buf = malloc (input_blocksize + INPUT_BLOCK_SLOP); + if (!real_buf) + error (EXIT_FAILURE, 0, + _("memory exhausted by input buffer of size %zu bytes (%s)"), + input_blocksize, human_size (input_blocksize)); + + real_buf += SWAB_ALIGN_OFFSET; /* allow space for swab */ + + ibuf = ptr_align (real_buf, page_size); +} + +/* Ensure output buffer OBUF is allocated/initialized. */ + +static void +alloc_obuf (void) +{ + if (obuf) + return; + + if (conversions_mask & C_TWOBUFS) + { + /* Page-align the output buffer, too. */ + char *real_obuf = malloc (output_blocksize + OUTPUT_BLOCK_SLOP); + if (!real_obuf) + error (EXIT_FAILURE, 0, + _("memory exhausted by output buffer of size %zu bytes (%s)"), + output_blocksize, human_size (output_blocksize)); + obuf = ptr_align (real_obuf, page_size); + } + else + { + alloc_ibuf (); + obuf = ibuf; + } + + /* Write a sentinel to the slop after the buffer, + to allow efficient checking for NUL blocks. */ + assert (sizeof (uintptr_t) <= OUTPUT_BLOCK_SLOP); + memset (obuf + output_blocksize, 1, sizeof (uintptr_t)); +} + static void translate_charset (char const *new_trans) { @@ -676,7 +741,7 @@ print_stats (void) double delta_s; char const *bytes_per_second; - if ((status_flags & STATUS_NONE) == STATUS_NONE) + if (status_flags & STATUS_NONE) return; fprintf (stderr, @@ -969,12 +1034,13 @@ iread (int fd, char *buf, size_t size) if (0 < prev_nread && prev_nread < size) { uintmax_t prev = prev_nread; - error (0, 0, ngettext (("warning: partial read (%"PRIuMAX" byte); " - "suggest iflag=fullblock"), - ("warning: partial read (%"PRIuMAX" bytes); " - "suggest iflag=fullblock"), - select_plural (prev)), - prev); + if (!(status_flags & STATUS_NONE)) + error (0, 0, ngettext (("warning: partial read (%"PRIuMAX" byte); " + "suggest iflag=fullblock"), + ("warning: partial read (%"PRIuMAX" bytes); " + "suggest iflag=fullblock"), + select_plural (prev)), + prev); warn_partial_read = false; } @@ -1018,7 +1084,8 @@ iwrite (int fd, char const *buf, size_t size) if ((output_flags & O_DIRECT) && size < output_blocksize) { int old_flags = fcntl (STDOUT_FILENO, F_GETFL); - if (fcntl (STDOUT_FILENO, F_SETFL, old_flags & ~O_DIRECT) != 0) + if (fcntl (STDOUT_FILENO, F_SETFL, old_flags & ~O_DIRECT) != 0 + && !(status_flags & STATUS_NONE)) error (0, errno, _("failed to turn off O_DIRECT: %s"), quote (output_file)); @@ -1511,9 +1578,11 @@ skip_via_lseek (char const *filename, int fdesc, off_t offset, int whence) && ioctl (fdesc, MTIOCGET, &s2) == 0 && MT_SAME_POSITION (s1, s2)) { - error (0, 0, _("warning: working around lseek kernel bug for file (%s)\n\ - of mt_type=0x%0lx -- see <sys/mtio.h> for the list of types"), - filename, s2.mt_type); + if (!(status_flags & STATUS_NONE)) + error (0, 0, _("warning: working around lseek kernel bug for file " + "(%s)\n of mt_type=0x%0lx -- " + "see <sys/mtio.h> for the list of types"), + filename, s2.mt_type); errno = 0; new_position = -1; } @@ -1526,7 +1595,7 @@ skip_via_lseek (char const *filename, int fdesc, off_t offset, int whence) /* Throw away RECORDS blocks of BLOCKSIZE bytes plus BYTES bytes on file descriptor FDESC, which is open with read permission for FILE. - Store up to BLOCKSIZE bytes of the data at a time in BUF, if + Store up to BLOCKSIZE bytes of the data at a time in IBUF or OBUF, if necessary. RECORDS or BYTES must be nonzero. If FDESC is STDIN_FILENO, advance the input offset. Return the number of records remaining, i.e., that were not skipped because EOF was @@ -1535,7 +1604,7 @@ skip_via_lseek (char const *filename, int fdesc, off_t offset, int whence) static uintmax_t skip (int fdesc, char const *file, uintmax_t records, size_t blocksize, - size_t *bytes, char *buf) + size_t *bytes) { uintmax_t offset = records * blocksize + *bytes; @@ -1607,6 +1676,18 @@ skip (int fdesc, char const *file, uintmax_t records, size_t blocksize, } /* else file_size && offset > OFF_T_MAX or file ! seekable */ + char *buf; + if (fdesc == STDIN_FILENO) + { + alloc_ibuf (); + buf = ibuf; + } + else + { + alloc_obuf (); + buf = obuf; + } + do { ssize_t nread = iread_fnc (fdesc, buf, records ? blocksize : *bytes); @@ -1671,7 +1752,7 @@ advance_input_after_read_error (size_t nbytes) if (offset == input_offset) return true; diff = input_offset - offset; - if (! (0 <= diff && diff <= nbytes)) + if (! (0 <= diff && diff <= nbytes) && !(status_flags & STATUS_NONE)) error (0, 0, _("warning: invalid file offset after failed read")); if (0 <= skip_via_lseek (input_file, STDIN_FILENO, diff, SEEK_CUR)) return true; @@ -1823,26 +1904,12 @@ set_fd_flags (int fd, int add_flags, char const *name) } } -static char * -human_size (size_t n) -{ - static char hbuf[LONGEST_HUMAN_READABLE + 1]; - int human_opts = - (human_autoscale | human_round_to_nearest | human_base_1024 - | human_space_before_unit | human_SI | human_B); - return human_readable (n, hbuf, human_opts, 1, 1); -} - /* The main loop. */ static int dd_copy (void) { - char *ibuf, *bufstart; /* Input buffer. */ - /* These are declared static so that even though we don't free the - buffers, valgrind will recognize that there is no "real" leak. */ - static char *real_buf; /* real buffer address before alignment */ - static char *real_obuf; + char *bufstart; /* Input buffer. */ ssize_t nread; /* Bytes read in the current block. */ /* If nonzero, then the previously read block was partial and @@ -1869,45 +1936,12 @@ dd_copy (void) It is necessary when accessing raw (i.e. character special) disk devices on Unixware or other SVR4-derived system. */ - real_buf = malloc (input_blocksize + INPUT_BLOCK_SLOP); - if (!real_buf) - error (EXIT_FAILURE, 0, - _("memory exhausted by input buffer of size %zu bytes (%s)"), - input_blocksize, human_size (input_blocksize)); - - ibuf = real_buf; - ibuf += SWAB_ALIGN_OFFSET; /* allow space for swab */ - - ibuf = ptr_align (ibuf, page_size); - - if (conversions_mask & C_TWOBUFS) - { - /* Page-align the output buffer, too. */ - real_obuf = malloc (output_blocksize + OUTPUT_BLOCK_SLOP); - if (!real_obuf) - error (EXIT_FAILURE, 0, - _("memory exhausted by output buffer of size %zu bytes (%s)"), - output_blocksize, human_size (output_blocksize)); - obuf = ptr_align (real_obuf, page_size); - } - else - { - real_obuf = NULL; - obuf = ibuf; - } - - /* Write a sentinel to the slop after the buffer, - to allow efficient checking for NUL blocks. */ - assert (sizeof (uintptr_t) <= OUTPUT_BLOCK_SLOP); - memset (obuf + output_blocksize, 1, sizeof (uintptr_t)); - if (skip_records != 0 || skip_bytes != 0) { uintmax_t us_bytes = input_offset + (skip_records * input_blocksize) + skip_bytes; uintmax_t us_blocks = skip (STDIN_FILENO, input_file, - skip_records, input_blocksize, &skip_bytes, - ibuf); + skip_records, input_blocksize, &skip_bytes); us_bytes -= input_offset; /* POSIX doesn't say what to do when dd detects it has been @@ -1916,7 +1950,8 @@ dd_copy (void) 1. file is too small 2. pipe has not enough data 3. partial reads */ - if (us_blocks || (!input_offset_overflow && us_bytes)) + if ((us_blocks || (!input_offset_overflow && us_bytes)) + && !(status_flags & STATUS_NONE)) { error (0, 0, _("%s: cannot skip to specified offset"), quote (input_file)); @@ -1927,8 +1962,7 @@ dd_copy (void) { size_t bytes = seek_bytes; uintmax_t write_records = skip (STDOUT_FILENO, output_file, - seek_records, output_blocksize, &bytes, - obuf); + seek_records, output_blocksize, &bytes); if (write_records != 0 || bytes != 0) { @@ -1955,6 +1989,9 @@ dd_copy (void) if (max_records == 0 && max_bytes == 0) return exit_status; + alloc_ibuf (); + alloc_obuf (); + while (1) { if (r_partial + r_full >= max_records + !!max_bytes) @@ -1981,7 +2018,9 @@ dd_copy (void) if (nread < 0) { - error (0, errno, _("error reading %s"), quote (input_file)); + if (!(conversions_mask & C_NOERROR) || !(status_flags & STATUS_NONE)) + error (0, errno, _("error reading %s"), quote (input_file)); + if (conversions_mask & C_NOERROR) { print_stats (); @@ -1,5 +1,5 @@ /* df - summarize free disk space - Copyright (C) 1991-2013 Free Software Foundation, Inc. + Copyright (C) 1991-2014 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 @@ -44,13 +44,13 @@ proper_name ("Paul Eggert") /* Filled with device numbers of examined file systems to avoid - duplicities in output. */ -struct devlist + duplicates in output. */ +static struct devlist { dev_t dev_num; struct mount_entry *me; struct devlist *next; -}; +} *device_list; /* If true, show even file systems with zero size or uninteresting types. */ @@ -143,7 +143,9 @@ typedef enum IUSED_FIELD, /* inodes used */ IAVAIL_FIELD, /* inodes available */ IPCENT_FIELD, /* inodes used in percent */ - TARGET_FIELD /* mount point */ + TARGET_FIELD, /* mount point */ + FILE_FIELD, /* specified file name */ + INVALID_FIELD /* validation marker */ } display_field_t; /* Flag if a field contains a block, an inode or another value. */ @@ -199,11 +201,15 @@ static struct field_data_t field_data[] = { "ipcent", INODE_FLD, N_("IUse%"), 4, MBS_ALIGN_RIGHT, false }, [TARGET_FIELD] = { TARGET_FIELD, - "target", OTHER_FLD, N_("Mounted on"), 0, MBS_ALIGN_LEFT, false } + "target", OTHER_FLD, N_("Mounted on"), 0, MBS_ALIGN_LEFT, false }, + + [FILE_FIELD] = { FILE_FIELD, + "file", OTHER_FLD, N_("File"), 0, MBS_ALIGN_LEFT, false } }; static char const *all_args_string = - "source,fstype,itotal,iused,iavail,ipcent,size,used,avail,pcent,target"; + "source,fstype,itotal,iused,iavail,ipcent,size," + "used,avail,pcent,file,target"; /* Storage for the definition of output columns. */ static struct field_data_t **columns; @@ -237,8 +243,7 @@ enum NO_SYNC_OPTION = CHAR_MAX + 1, SYNC_OPTION, TOTAL_OPTION, - OUTPUT_OPTION, - MEGABYTES_OPTION /* FIXME: remove long opt in Aug 2013 */ + OUTPUT_OPTION }; static struct option const long_options[] = @@ -249,7 +254,6 @@ static struct option const long_options[] = {"human-readable", no_argument, NULL, 'h'}, {"si", no_argument, NULL, 'H'}, {"local", no_argument, NULL, 'l'}, - {"megabytes", no_argument, NULL, MEGABYTES_OPTION}, /* obsolescent, */ {"output", optional_argument, NULL, OUTPUT_OPTION}, {"portability", no_argument, NULL, 'P'}, {"print-type", no_argument, NULL, 'T'}, @@ -287,7 +291,7 @@ static void alloc_table_row (void) { nrows++; - table = xnrealloc (table, nrows, sizeof (char *)); + table = xnrealloc (table, nrows, sizeof (char **)); table[nrows - 1] = xnmalloc (ncolumns, sizeof (char *)); } @@ -369,7 +373,7 @@ decode_output_arg (char const *arg) *comma++ = 0; /* process S. */ - display_field_t field = -1; + display_field_t field = INVALID_FIELD; for (unsigned int i = 0; i < ARRAY_CARDINALITY (field_data); i++) { if (STREQ (field_data[i].arg, s)) @@ -378,17 +382,17 @@ decode_output_arg (char const *arg) break; } } - if (field == -1) + if (field == INVALID_FIELD) { - error (0, 0, _("option --output: field '%s' unknown"), s); + error (0, 0, _("option --output: field %s unknown"), quote (s)); usage (EXIT_FAILURE); } if (field_data[field].used) { /* Prevent the fields from being used more than once. */ - error (0, 0, _("option --output: field '%s' used more than once"), - field_data[field].arg); + error (0, 0, _("option --output: field %s used more than once"), + quote (field_data[field].arg)); usage (EXIT_FAILURE); } @@ -403,6 +407,7 @@ decode_output_arg (char const *arg) case IAVAIL_FIELD: case IPCENT_FIELD: case TARGET_FIELD: + case FILE_FIELD: alloc_field (field, NULL); break; @@ -539,7 +544,7 @@ get_header (void) char *num = human_readable (output_block_size, buf, opts, 1, 1); /* Reset the header back to the default in OUTPUT_MODE. */ - header = N_("blocks"); + header = _("blocks"); /* TRANSLATORS: this is the "1K-blocks" header in "df" output. */ if (asprintf (&cell, _("%s-%s"), num, header) == -1) @@ -599,75 +604,115 @@ excluded_fstype (const char *fstype) } /* Filter mount list by skipping duplicate entries. - In the case of duplicities - based on to the device number - the mount entry + In the case of duplicates - based on the device number - the mount entry with a '/' in its me_devname (i.e. not pseudo name like tmpfs) wins. If both have a real devname (e.g. bind mounts), then that with the shorter - me_mountdir wins. */ + me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update + the global device_list, rather than filtering the global mount_list. */ static void -filter_mount_list (void) +filter_mount_list (bool devices_only) { struct mount_entry *me; - /* Store of already-processed device numbers. */ - struct devlist *devlist_head = NULL; - - /* Sort all 'wanted' entries into the list devlist_head. */ - for (me = mount_list; me; me = me->me_next) + /* Sort all 'wanted' entries into the list device_list. */ + for (me = mount_list; me;) { struct stat buf; struct devlist *devlist; + struct mount_entry *discard_me = NULL; + /* TODO: On Linux we might avoid this stat() and another in get_dev() + by using the device IDs available from /proc/self/mountinfo. + read_file_system_list() could populate me_dev from those + for efficiency and accuracy. */ if (-1 == stat (me->me_mountdir, &buf)) { - ; /* Stat failed - add ME to be able to complain about it later. */ + /* Stat failed - add ME to be able to complain about it later. */ + buf.st_dev = me->me_dev; } else { - /* If the device name is a real path name ... */ - if (strchr (me->me_devname, '/')) - { - /* ... try to find its device number in the devlist. */ - for (devlist = devlist_head; devlist; devlist = devlist->next) - if (devlist->dev_num == buf.st_dev) - break; + /* If we've already seen this device... */ + for (devlist = device_list; devlist; devlist = devlist->next) + if (devlist->dev_num == buf.st_dev) + break; - if (devlist) + if (devlist) + { + /* ...let the shorter mountdir win. */ + if ((strchr (me->me_devname, '/') + && ! strchr (devlist->me->me_devname, '/')) + || (strlen (devlist->me->me_mountdir) + > strlen (me->me_mountdir)) + /* or one overmounted on a different device. */ + || ! STREQ (devlist->me->me_devname, me->me_devname)) { - /* Let the shorter mountdir win. */ - if ( !strchr (devlist->me->me_devname, '/') - || ( strlen (devlist->me->me_mountdir) - > strlen (me->me_mountdir))) - { - /* FIXME: free ME - the others are also not free()d. */ - devlist->me = me; - } - continue; /* ... with the loop over the mount_list. */ + /* Discard mount entry for existing device. */ + discard_me = devlist->me; + devlist->me = me; + } + else + { + /* Discard mount entry currently being processed. */ + discard_me = me; } + } } - /* Add the device number to the global list devlist. */ - devlist = xmalloc (sizeof *devlist); - devlist->me = me; - devlist->dev_num = buf.st_dev; - devlist->next = devlist_head; - devlist_head = devlist; + if (discard_me) + { + me = me->me_next; + if (! devices_only) + free_mount_entry (discard_me); + } + else + { + /* Add the device number to the global list devlist. */ + devlist = xmalloc (sizeof *devlist); + devlist->me = me; + devlist->dev_num = buf.st_dev; + devlist->next = device_list; + device_list = devlist; + + me = me->me_next; + } } /* Finally rebuild the mount_list from the devlist. */ - mount_list = NULL; - while (devlist_head) + if (! devices_only) { + mount_list = NULL; + while (device_list) + { + /* Add the mount entry. */ + me = device_list->me; + me->me_next = mount_list; + mount_list = me; + /* Free devlist entry and advance. */ + struct devlist *devlist = device_list->next; + free (device_list); + device_list = devlist; + } + } +} + +/* Search a mount entry list for device id DEV. + Return the corresponding device name if found or NULL if not. */ + +static char const * _GL_ATTRIBUTE_PURE +devname_for_dev (dev_t dev) +{ + struct devlist *dl = device_list; + + while (dl) { - /* Add the mount entry. */ - me = devlist_head->me; - me->me_next = mount_list; - mount_list = me; - /* Free devlist entry and advance. */ - struct devlist *devlist = devlist_head->next; - free (devlist_head); - devlist_head = devlist; + if (dl->dev_num == dev) + return dl->me->me_devname; + dl = dl->next; } + + return NULL; } /* Return true if N is a known integer value. On many file systems, @@ -824,7 +869,7 @@ add_to_grand_total (struct field_values_t *bv, struct field_values_t *iv) when df is invoked with no non-option argument. See below for details. */ static void -get_dev (char const *disk, char const *mount_point, +get_dev (char const *disk, char const *mount_point, char const* file, char const *stat_file, char const *fstype, bool me_dummy, bool me_remote, const struct fs_usage *force_fsu, @@ -839,6 +884,11 @@ get_dev (char const *disk, char const *mount_point, if (!selected_fstype (fstype) || excluded_fstype (fstype)) return; + /* Ignore relative MOUNT_POINTs, which are present for example + in /proc/mounts on Linux with network namespaces. */ + if (!force_fsu && mount_point && ! IS_ABSOLUTE_FILE_NAME (mount_point)) + return; + /* If MOUNT_POINT is NULL, then the file system is not mounted, and this program reports on the file system that the special file is on. It would be better to report on the unmounted file system, @@ -851,9 +901,40 @@ get_dev (char const *disk, char const *mount_point, fsu = *force_fsu; else if (get_fs_usage (stat_file, disk, &fsu)) { - error (0, errno, "%s", quote (stat_file)); - exit_status = EXIT_FAILURE; - return; + /* If we can't access a system provided entry due + to it not being present (now), or due to permissions, + just output placeholder values rather than failing. */ + if (process_all && (errno == EACCES || errno == ENOENT)) + { + if (! show_all_fs) + return; + + fstype = "-"; + fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree = + fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX; + } + else + { + error (0, errno, "%s", quote (stat_file)); + exit_status = EXIT_FAILURE; + return; + } + } + else if (process_all && show_all_fs) + { + /* Ensure we don't output incorrect stats for over-mounted directories. + Discard stats when the device name doesn't match. */ + struct stat sb; + if (stat (stat_file, &sb) == 0) + { + char const * devname = devname_for_dev (sb.st_dev); + if (devname && ! STREQ (devname, disk)) + { + fstype = "-"; + fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree = + fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX; + } + } } if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs) @@ -867,6 +948,9 @@ get_dev (char const *disk, char const *mount_point, if (! disk) disk = "-"; /* unknown */ + if (! file) + file = "-"; /* unspecified */ + char *dev_name = xstrdup (disk); char *resolved_dev; @@ -914,6 +998,7 @@ get_dev (char const *disk, char const *mount_point, v = NULL; break; default: + v = NULL; /* Avoid warnings where assert() is not __noreturn__. */ assert (!"bad field_type"); } @@ -998,6 +1083,10 @@ get_dev (char const *disk, char const *mount_point, break; } + case FILE_FIELD: + cell = xstrdup (file); + break; + case TARGET_FIELD: #ifdef HIDE_AUTOMOUNT_PREFIX /* Don't print the first directory name in MOUNT_POINT if it's an @@ -1025,6 +1114,33 @@ get_dev (char const *disk, char const *mount_point, free (dev_name); } +/* Scan the mount list returning the _last_ device found for MOUNT. + NULL is returned if MOUNT not found. The result is malloced. */ +static char * +last_device_for_mount (char const* mount) +{ + struct mount_entry const *me; + struct mount_entry const *le = NULL; + + for (me = mount_list; me; me = me->me_next) + { + if (STREQ (me->me_mountdir, mount)) + le = me; + } + + if (le) + { + char *devname = le->me_devname; + char *canon_dev = canonicalize_file_name (devname); + if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev)) + return canon_dev; + free (canon_dev); + return xstrdup (le->me_devname); + } + else + return NULL; +} + /* If DISK corresponds to a mount point, show its usage and return true. Otherwise, return false. */ static bool @@ -1032,18 +1148,75 @@ get_disk (char const *disk) { struct mount_entry const *me; struct mount_entry const *best_match = NULL; + bool best_match_accessible = false; + bool eclipsed_device = false; + char const *file = disk; + char *resolved = canonicalize_file_name (disk); + if (resolved && IS_ABSOLUTE_FILE_NAME (resolved)) + disk = resolved; + + size_t best_match_len = SIZE_MAX; for (me = mount_list; me; me = me->me_next) - if (STREQ (disk, me->me_devname)) - best_match = me; + { + /* TODO: Should cache canon_dev in the mount_entry struct. */ + char *devname = me->me_devname; + char *canon_dev = canonicalize_file_name (me->me_devname); + if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev)) + devname = canon_dev; + + if (STREQ (disk, devname)) + { + char *last_device = last_device_for_mount (me->me_mountdir); + eclipsed_device = last_device && ! STREQ (last_device, devname); + size_t len = strlen (me->me_mountdir); + + if (! eclipsed_device + && (! best_match_accessible || len < best_match_len)) + { + struct stat disk_stats; + bool this_match_accessible = false; + + if (stat (me->me_mountdir, &disk_stats) == 0) + best_match_accessible = this_match_accessible = true; + + if (this_match_accessible + || (! best_match_accessible && len < best_match_len)) + { + best_match = me; + if (len == 1) /* Traditional root. */ + { + free (last_device); + free (canon_dev); + break; + } + else + best_match_len = len; + } + } + + free (last_device); + } + + free (canon_dev); + } + + free (resolved); if (best_match) { - get_dev (best_match->me_devname, best_match->me_mountdir, NULL, + get_dev (best_match->me_devname, best_match->me_mountdir, file, NULL, best_match->me_type, best_match->me_dummy, best_match->me_remote, NULL, false); return true; } + else if (eclipsed_device) + { + error (0, 0, _("cannot access %s: over-mounted by another device"), + quote (file)); + exit_status = EXIT_FAILURE; + return true; + } return false; } @@ -1068,17 +1241,19 @@ get_point (const char *point, const struct stat *statp) size_t best_match_len = 0; for (me = mount_list; me; me = me->me_next) - if (!STREQ (me->me_type, "lofs") - && (!best_match || best_match->me_dummy || !me->me_dummy)) { - size_t len = strlen (me->me_mountdir); - if (best_match_len <= len && len <= resolved_len - && (len == 1 /* root file system */ - || ((len == resolved_len || resolved[len] == '/') - && STREQ_LEN (me->me_mountdir, resolved, len)))) + if (!STREQ (me->me_type, "lofs") + && (!best_match || best_match->me_dummy || !me->me_dummy)) { - best_match = me; - best_match_len = len; + size_t len = strlen (me->me_mountdir); + if (best_match_len <= len && len <= resolved_len + && (len == 1 /* root file system */ + || ((len == resolved_len || resolved[len] == '/') + && STREQ_LEN (me->me_mountdir, resolved, len)))) + { + best_match = me; + best_match_len = len; + } } } } @@ -1125,7 +1300,7 @@ get_point (const char *point, const struct stat *statp) } if (best_match) - get_dev (best_match->me_devname, best_match->me_mountdir, point, + get_dev (best_match->me_devname, best_match->me_mountdir, point, point, best_match->me_type, best_match->me_dummy, best_match->me_remote, NULL, false); else @@ -1138,7 +1313,7 @@ get_point (const char *point, const struct stat *statp) char *mp = find_mount_point (point, statp); if (mp) { - get_dev (NULL, mp, NULL, NULL, false, false, NULL, false); + get_dev (NULL, mp, point, NULL, NULL, false, false, NULL, false); free (mp); } } @@ -1165,11 +1340,10 @@ get_all_entries (void) { struct mount_entry *me; - if (!show_all_fs) - filter_mount_list (); + filter_mount_list (show_all_fs); for (me = mount_list; me; me = me->me_next) - get_dev (me->me_devname, me->me_mountdir, NULL, me->me_type, + get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type, me->me_dummy, me->me_remote, NULL, true); } @@ -1214,15 +1388,16 @@ or all file systems by default.\n\ emit_mandatory_arg_note (); + /* TRANSLATORS: The thousands and decimal separators are best + adjusted to an appropriate default for your locale. */ fputs (_("\ -a, --all include dummy file systems\n\ - -B, --block-size=SIZE scale sizes by SIZE before printing them. E.g.,\n\ - '-BM' prints sizes in units of 1,048,576 bytes.\n\ - See SIZE format below.\n\ + -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ + '-BM' prints sizes in units of 1,048,576 bytes;\n\ + see SIZE format below\n\ --total produce a grand total\n\ - -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\ -\n\ - -H, --si likewise, but use powers of 1000 not 1024\n\ + -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\ + -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\ "), stdout); fputs (_("\ -i, --inodes list inode information instead of block usage\n\ @@ -1248,7 +1423,7 @@ or all file systems by default.\n\ fputs (_("\n\ FIELD_LIST is a comma-separated list of columns to be included. Valid\n\ field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\ -'size', 'used', 'avail', 'pcent' and 'target' (see info page).\n\ +'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).\n\ "), stdout); emit_ancillary_info (); } @@ -1328,13 +1503,6 @@ main (int argc, char **argv) case 'l': show_local_fs = true; break; - case MEGABYTES_OPTION: - /* Distinguish between the long and the short option. - As we want to remove the long option soon, - give a warning when the long form is used. */ - error (0, 0, "%s%s", _("warning: "), - _("long option '--megabytes' is deprecated" - " and will soon be removed")); case 'm': /* obsolescent, exists for BSD compatibility */ human_output_opts = 0; output_block_size = 1024 * 1024; @@ -1527,7 +1695,7 @@ main (int argc, char **argv) if (print_grand_total) get_dev ("total", (field_data[SOURCE_FIELD].used ? "-" : "total"), - NULL, NULL, false, false, &grand_fsu, false); + NULL, NULL, NULL, false, false, &grand_fsu, false); print_table (); } diff --git a/src/dircolors.c b/src/dircolors.c index 5610f083..99605367 100644 --- a/src/dircolors.c +++ b/src/dircolors.c @@ -1,5 +1,5 @@ /* dircolors - output commands to set the LS_COLOR environment variable - Copyright (C) 1996-2013 Free Software Foundation, Inc. + Copyright (C) 1996-2014 Free Software Foundation, Inc. Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000 H. Peter Anvin This program is free software: you can redistribute it and/or modify diff --git a/src/dircolors.h b/src/dircolors.h index f243c192..7b501079 100644 --- a/src/dircolors.h +++ b/src/dircolors.h @@ -2,7 +2,7 @@ static char const G_line[] = { '#',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',' ','f','i','l','e',' ','f','o','r',' ','d','i','r','c','o','l','o','r','s',',',' ','a',' ','u','t','i','l','i','t','y',' ','t','o',' ','h','e','l','p',' ','y','o','u',' ','s','e','t',' ','t','h','e',0, '#',' ','L','S','_','C','O','L','O','R','S',' ','e','n','v','i','r','o','n','m','e','n','t',' ','v','a','r','i','a','b','l','e',' ','u','s','e','d',' ','b','y',' ','G','N','U',' ','l','s',' ','w','i','t','h',' ','t','h','e',' ','-','-','c','o','l','o','r',' ','o','p','t','i','o','n','.',0, - '#',' ','C','o','p','y','r','i','g','h','t',' ','(','C',')',' ','1','9','9','6','-','2','0','1','3',' ','F','r','e','e',' ','S','o','f','t','w','a','r','e',' ','F','o','u','n','d','a','t','i','o','n',',',' ','I','n','c','.',0, + '#',' ','C','o','p','y','r','i','g','h','t',' ','(','C',')',' ','1','9','9','6','-','2','0','1','4',' ','F','r','e','e',' ','S','o','f','t','w','a','r','e',' ','F','o','u','n','d','a','t','i','o','n',',',' ','I','n','c','.',0, '#',' ','C','o','p','y','i','n','g',' ','a','n','d',' ','d','i','s','t','r','i','b','u','t','i','o','n',' ','o','f',' ','t','h','i','s',' ','f','i','l','e',',',' ','w','i','t','h',' ','o','r',' ','w','i','t','h','o','u','t',' ','m','o','d','i','f','i','c','a','t','i','o','n',',',0, '#',' ','a','r','e',' ','p','e','r','m','i','t','t','e','d',' ','p','r','o','v','i','d','e','d',' ','t','h','e',' ','c','o','p','y','r','i','g','h','t',' ','n','o','t','i','c','e',' ','a','n','d',' ','t','h','i','s',' ','n','o','t','i','c','e',' ','a','r','e',' ','p','r','e','s','e','r','v','e','d','.',0, '#',' ','T','h','e',' ','k','e','y','w','o','r','d','s',' ','C','O','L','O','R',',',' ','O','P','T','I','O','N','S',',',' ','a','n','d',' ','E','I','G','H','T','B','I','T',' ','(','h','o','n','o','r','e','d',' ','b','y',' ','t','h','e',0, @@ -28,14 +28,17 @@ static char const G_line[] = 'T','E','R','M',' ','e','t','e','r','m','-','c','o','l','o','r',0, 'T','E','R','M',' ','g','n','o','m','e',0, 'T','E','R','M',' ','g','n','o','m','e','-','2','5','6','c','o','l','o','r',0, + 'T','E','R','M',' ','h','u','r','d',0, 'T','E','R','M',' ','j','f','b','t','e','r','m',0, 'T','E','R','M',' ','k','o','n','s','o','l','e',0, 'T','E','R','M',' ','k','t','e','r','m',0, 'T','E','R','M',' ','l','i','n','u','x',0, 'T','E','R','M',' ','l','i','n','u','x','-','c',0, 'T','E','R','M',' ','m','a','c','h','-','c','o','l','o','r',0, + 'T','E','R','M',' ','m','a','c','h','-','g','n','u','-','c','o','l','o','r',0, 'T','E','R','M',' ','m','l','t','e','r','m',0, 'T','E','R','M',' ','p','u','t','t','y',0, + 'T','E','R','M',' ','p','u','t','t','y','-','2','5','6','c','o','l','o','r',0, 'T','E','R','M',' ','r','x','v','t',0, 'T','E','R','M',' ','r','x','v','t','-','2','5','6','c','o','l','o','r',0, 'T','E','R','M',' ','r','x','v','t','-','c','y','g','w','i','n',0, @@ -106,18 +109,25 @@ static char const G_line[] = ' ','#',' ','a','r','c','h','i','v','e','s',' ','o','r',' ','c','o','m','p','r','e','s','s','e','d',' ','(','b','r','i','g','h','t',' ','r','e','d',')',0, '.','t','a','r',' ','0','1',';','3','1',0, '.','t','g','z',' ','0','1',';','3','1',0, + '.','a','r','c',' ','0','1',';','3','1',0, '.','a','r','j',' ','0','1',';','3','1',0, '.','t','a','z',' ','0','1',';','3','1',0, + '.','l','h','a',' ','0','1',';','3','1',0, + '.','l','z','4',' ','0','1',';','3','1',0, '.','l','z','h',' ','0','1',';','3','1',0, '.','l','z','m','a',' ','0','1',';','3','1',0, '.','t','l','z',' ','0','1',';','3','1',0, '.','t','x','z',' ','0','1',';','3','1',0, + '.','t','z','o',' ','0','1',';','3','1',0, + '.','t','7','z',' ','0','1',';','3','1',0, '.','z','i','p',' ','0','1',';','3','1',0, '.','z',' ','0','1',';','3','1',0, '.','Z',' ','0','1',';','3','1',0, '.','d','z',' ','0','1',';','3','1',0, '.','g','z',' ','0','1',';','3','1',0, + '.','l','r','z',' ','0','1',';','3','1',0, '.','l','z',' ','0','1',';','3','1',0, + '.','l','z','o',' ','0','1',';','3','1',0, '.','x','z',' ','0','1',';','3','1',0, '.','b','z','2',' ','0','1',';','3','1',0, '.','b','z',' ','0','1',';','3','1',0, @@ -131,11 +141,13 @@ static char const G_line[] = '.','e','a','r',' ','0','1',';','3','1',0, '.','s','a','r',' ','0','1',';','3','1',0, '.','r','a','r',' ','0','1',';','3','1',0, + '.','a','l','z',' ','0','1',';','3','1',0, '.','a','c','e',' ','0','1',';','3','1',0, '.','z','o','o',' ','0','1',';','3','1',0, '.','c','p','i','o',' ','0','1',';','3','1',0, '.','7','z',' ','0','1',';','3','1',0, '.','r','z',' ','0','1',';','3','1',0, + '.','c','a','b',' ','0','1',';','3','1',0, '#',' ','i','m','a','g','e',' ','f','o','r','m','a','t','s',0, '.','j','p','g',' ','0','1',';','3','5',0, '.','j','p','e','g',' ','0','1',';','3','5',0, @@ -191,6 +203,7 @@ static char const G_line[] = '.','a','a','c',' ','0','0',';','3','6',0, '.','a','u',' ','0','0',';','3','6',0, '.','f','l','a','c',' ','0','0',';','3','6',0, + '.','m','4','a',' ','0','0',';','3','6',0, '.','m','i','d',' ','0','0',';','3','6',0, '.','m','i','d','i',' ','0','0',';','3','6',0, '.','m','k','a',' ','0','0',';','3','6',0, diff --git a/src/dircolors.hin b/src/dircolors.hin index 6dfd1136..89ebf5a1 100644 --- a/src/dircolors.hin +++ b/src/dircolors.hin @@ -1,7 +1,7 @@ # Configuration file for dircolors, a utility to help you set the # LS_COLORS environment variable used by GNU ls with the --color option. -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # Copying and distribution of this file, with or without modification, # are permitted provided the copyright notice and this notice are preserved. @@ -29,14 +29,17 @@ TERM dtterm TERM eterm-color TERM gnome TERM gnome-256color +TERM hurd TERM jfbterm TERM konsole TERM kterm TERM linux TERM linux-c TERM mach-color +TERM mach-gnu-color TERM mlterm TERM putty +TERM putty-256color TERM rxvt TERM rxvt-256color TERM rxvt-cygwin @@ -112,18 +115,25 @@ EXEC 01;32 # archives or compressed (bright red) .tar 01;31 .tgz 01;31 +.arc 01;31 .arj 01;31 .taz 01;31 +.lha 01;31 +.lz4 01;31 .lzh 01;31 .lzma 01;31 .tlz 01;31 .txz 01;31 +.tzo 01;31 +.t7z 01;31 .zip 01;31 .z 01;31 .Z 01;31 .dz 01;31 .gz 01;31 +.lrz 01;31 .lz 01;31 +.lzo 01;31 .xz 01;31 .bz2 01;31 .bz 01;31 @@ -137,11 +147,13 @@ EXEC 01;32 .ear 01;31 .sar 01;31 .rar 01;31 +.alz 01;31 .ace 01;31 .zoo 01;31 .cpio 01;31 .7z 01;31 .rz 01;31 +.cab 01;31 # image formats .jpg 01;35 @@ -200,6 +212,7 @@ EXEC 01;32 .aac 00;36 .au 00;36 .flac 00;36 +.m4a 00;36 .mid 00;36 .midi 00;36 .mka 00;36 diff --git a/src/dirname.c b/src/dirname.c index 94eec9de..e0599a36 100644 --- a/src/dirname.c +++ b/src/dirname.c @@ -1,6 +1,6 @@ /* dirname -- strip suffix from file name - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 @@ -57,7 +57,7 @@ removed; if NAME contains no /'s, output '.' (meaning the current directory).\n\ \n\ "), stdout); fputs (_("\ - -z, --zero separate output with NUL rather than newline\n\ + -z, --zero end each output line with NUL, not newline\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -1,5 +1,5 @@ /* du -- summarize disk usage - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 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 @@ -78,6 +78,9 @@ struct duinfo /* Size of files in directory. */ uintmax_t size; + /* Number of inodes in directory. */ + uintmax_t inodes; + /* Latest time stamp found. If tmax.tv_sec == TYPE_MINIMUM (time_t) && tmax.tv_nsec < 0, no time stamp has been found. */ struct timespec tmax; @@ -88,6 +91,7 @@ static inline void duinfo_init (struct duinfo *a) { a->size = 0; + a->inodes = 0; a->tmax.tv_sec = TYPE_MINIMUM (time_t); a->tmax.tv_nsec = -1; } @@ -97,6 +101,7 @@ static inline void duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax) { a->size = size; + a->inodes = 1; a->tmax = tmax; } @@ -106,6 +111,7 @@ duinfo_add (struct duinfo *a, struct duinfo const *b) { uintmax_t sum = a->size + b->size; a->size = a->size <= sum ? sum : UINTMAX_MAX; + a->inodes = a->inodes + b->inodes; if (timespec_cmp (a->tmax, b->tmax) < 0) a->tmax = b->tmax; } @@ -154,6 +160,9 @@ static intmax_t opt_threshold = 0; /* Human-readable options for output. */ static int human_output_opts; +/* Output inodes count instead of blocks used. */ +static bool opt_inodes = false; + /* If true, print most recently modified date, using the specified format. */ static bool opt_time = false; @@ -197,7 +206,8 @@ enum HUMAN_SI_OPTION, FTS_DEBUG, TIME_OPTION, - TIME_STYLE_OPTION + TIME_STYLE_OPTION, + INODES_OPTION }; static struct option const long_options[] = @@ -214,6 +224,7 @@ static struct option const long_options[] = {"exclude-from", required_argument, NULL, 'X'}, {"files0-from", required_argument, NULL, FILES0_FROM_OPTION}, {"human-readable", no_argument, NULL, 'h'}, + {"inodes", no_argument, NULL, INODES_OPTION}, {"si", no_argument, NULL, HUMAN_SI_OPTION}, {"max-depth", required_argument, NULL, 'd'}, {"null", no_argument, NULL, '0'}, @@ -278,7 +289,7 @@ Summarize disk usage of each FILE, recursively for directories.\n\ emit_mandatory_arg_note (); fputs (_("\ - -0, --null end each output line with 0 byte rather than newline\n\ + -0, --null end each output line with NUL, not newline\n\ -a, --all write counts for all files, not just directories\n\ --apparent-size print apparent sizes, rather than disk usage; although\ \n\ @@ -287,9 +298,9 @@ Summarize disk usage of each FILE, recursively for directories.\n\ fragmentation, indirect blocks, and the like\n\ "), stdout); fputs (_("\ - -B, --block-size=SIZE scale sizes by SIZE before printing them. E.g.,\n\ - '-BM' prints sizes in units of 1,048,576 bytes.\n\ - See SIZE format below.\n\ + -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ + '-BM' prints sizes in units of 1,048,576 bytes;\n\ + see SIZE format below\n\ -b, --bytes equivalent to '--apparent-size --block-size=1'\n\ -c, --total produce a grand total\n\ -D, --dereference-args dereference only symlinks that are listed on the\n\ @@ -300,12 +311,13 @@ Summarize disk usage of each FILE, recursively for directories.\n\ --summarize\n\ "), stdout); fputs (_("\ - --files0-from=F summarize disk usage of the NUL-terminated file\n\ - names specified in file F;\n\ - If F is - then read names from standard input\n\ + --files0-from=F summarize disk usage of the\n\ + NUL-terminated file names specified in file F;\n\ + if F is -, then read names from standard input\n\ -H equivalent to --dereference-args (-D)\n\ -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\ \n\ + --inodes list inode usage information instead of block usage\n\ "), stdout); fputs (_("\ -k like --block-size=1K\n\ @@ -315,7 +327,7 @@ Summarize disk usage of each FILE, recursively for directories.\n\ "), stdout); fputs (_("\ -P, --no-dereference don't follow any symbolic links (this is the default)\n\ - -S, --separate-dirs do not include size of subdirectories\n\ + -S, --separate-dirs for directories do not include size of subdirectories\n\ --si like -h, but use powers of 1000 not 1024\n\ -s, --summarize display only a total for each argument\n\ "), stdout); @@ -326,9 +338,9 @@ Summarize disk usage of each FILE, recursively for directories.\n\ directory, or any of its subdirectories\n\ --time=WORD show time as WORD instead of modification time:\n\ atime, access, use, ctime or status\n\ - --time-style=STYLE show times using style STYLE:\n\ - full-iso, long-iso, iso, +FORMAT\n\ - FORMAT is interpreted like 'date'\n\ + --time-style=STYLE show times using STYLE, which can be:\n\ + full-iso, long-iso, iso, or +FORMAT;\n\ + FORMAT is interpreted like in 'date'\n\ "), stdout); fputs (_("\ -X, --exclude-from=FILE exclude files that match any pattern in FILE\n\ @@ -394,7 +406,10 @@ print_only_size (uintmax_t n_bytes) static void print_size (const struct duinfo *pdui, const char *string) { - print_only_size (pdui->size); + print_only_size (opt_inodes + ? pdui->inodes + : pdui->size); + if (opt_time) { putchar ('\t'); @@ -499,15 +514,11 @@ process_file (FTS *fts, FTSENT *ent) break; case FTS_DC: - if (cycle_warning_required (fts, ent)) + /* If not following symlinks and not a (bind) mount point. */ + if (cycle_warning_required (fts, ent) + && ! di_set_lookup (di_mnt, sb->st_dev, sb->st_ino)) { - /* If this is a mount point, then diagnose it and avoid - the cycle. */ - if (di_set_lookup (di_mnt, sb->st_dev, sb->st_ino)) - error (0, 0, _("mount point %s already traversed"), - quote (file)); - else - emit_cycle_warning (file); + emit_cycle_warning (file); return false; } return true; @@ -589,9 +600,10 @@ process_file (FTS *fts, FTSENT *ent) || level == 0) { /* Print or elide this entry according to the --threshold option. */ + uintmax_t v = opt_inodes ? dui_to_print.inodes : dui_to_print.size; if (opt_threshold < 0 - ? dui_to_print.size <= -opt_threshold - : dui_to_print.size >= opt_threshold) + ? v <= -opt_threshold + : v >= opt_threshold) print_size (&dui_to_print, file); } @@ -670,12 +682,7 @@ fill_mount_table (void) mnt_free = mnt_ent; mnt_ent = mnt_ent->me_next; - - free (mnt_free->me_devname); - free (mnt_free->me_mountdir); - if (mnt_free->me_type_malloced) - free (mnt_free->me_type); - free (mnt_free); + free_mount_entry (mnt_free); } } @@ -858,6 +865,10 @@ main (int argc, char **argv) add_exclude (exclude, optarg, EXCLUDE_WILDCARDS); break; + case INODES_OPTION: + opt_inodes = true; + break; + case TIME_OPTION: opt_time = true; time_type = @@ -904,6 +915,16 @@ main (int argc, char **argv) if (opt_summarize_only) max_depth = 0; + if (opt_inodes) + { + if (apparent_size) + { + error (0, 0, _("warning: options --apparent-size and -b are " + "ineffective with --inodes")); + } + output_block_size = 1; + } + /* Process time style if printing last times. */ if (opt_time) { @@ -1,5 +1,5 @@ /* echo.c, derived from code echo.c in Bash. - Copyright (C) 1987-2013 Free Software Foundation, Inc. + Copyright (C) 1987-2014 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 @@ -1,5 +1,5 @@ /* env - run a program in a modified environment - Copyright (C) 1986-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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 @@ -60,7 +60,7 @@ Set each NAME to VALUE in the environment and run COMMAND.\n\ fputs (_("\ -i, --ignore-environment start with an empty environment\n\ - -0, --null end each output line with 0 byte rather than newline\n\ + -0, --null end each output line with NUL, not newline\n\ -u, --unset=NAME remove variable from the environment\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); diff --git a/src/expand.c b/src/expand.c index 0b12b025..082b5d4e 100644 --- a/src/expand.c +++ b/src/expand.c @@ -1,5 +1,5 @@ /* expand - convert tabs to spaces - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -1,5 +1,5 @@ /* expr -- evaluate expressions. - Copyright (C) 1986-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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 @@ -44,8 +44,6 @@ int, the widest unsigned type that GMP supports. */ verify (SIZE_MAX <= ULONG_MAX); -static void integer_overflow (char) ATTRIBUTE_NORETURN; - #ifndef HAVE_GMP # define HAVE_GMP 0 #endif @@ -53,6 +51,7 @@ static void integer_overflow (char) ATTRIBUTE_NORETURN; #if HAVE_GMP # include <gmp.h> #else +static void integer_overflow (char) ATTRIBUTE_NORETURN; /* Approximate gmp.h well enough for expr.c's purposes. */ typedef intmax_t mpz_t[1]; static void mpz_clear (mpz_t z) { (void) z; } @@ -278,6 +277,7 @@ syntax_error (void) error (EXPR_INVALID, 0, _("syntax error")); } +#if ! HAVE_GMP /* Report an integer overflow for operation OP and exit. */ static void integer_overflow (char op) @@ -285,15 +285,7 @@ integer_overflow (char op) error (EXPR_FAILURE, ERANGE, "%c", op); abort (); /* notreached */ } - -static void die (int errno_val, char const *msg) - ATTRIBUTE_NORETURN; -static void -die (int errno_val, char const *msg) -{ - error (EXPR_FAILURE, errno_val, "%s", msg); - abort (); /* notreached */ -} +#endif int main (int argc, char **argv) diff --git a/src/extent-scan.c b/src/extent-scan.c index 5d25b9aa..805997a7 100644 --- a/src/extent-scan.c +++ b/src/extent-scan.c @@ -1,5 +1,5 @@ /* extent-scan.c -- core functions for scanning extents - Copyright (C) 2010-2013 Free Software Foundation, Inc. + Copyright (C) 2010-2014 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 @@ -28,9 +28,7 @@ #include "xstrtol.h" -/* Work around Linux kernel issues on BTRFS and EXT4 before 2.6.39. - FIXME: remove in 2013, or whenever we're pretty confident - that the offending, unpatched kernels are no longer in use. */ +/* Work around Linux kernel issues on BTRFS and EXT4. */ static bool extent_need_sync (void) { @@ -218,7 +216,7 @@ extent_scan_read (struct extent_scan *scan) } #else extern bool -extent_scan_read (struct extent_scan *scan ATTRIBUTE_UNUSED) +extent_scan_read (struct extent_scan *scan _GL_UNUSED) { scan->initial_scan_failed = true; errno = ENOTSUP; diff --git a/src/extent-scan.h b/src/extent-scan.h index c2c318c9..fa800343 100644 --- a/src/extent-scan.h +++ b/src/extent-scan.h @@ -1,5 +1,5 @@ /* core functions for efficient reading sparse files - Copyright (C) 2010-2013 Free Software Foundation, Inc. + Copyright (C) 2010-2014 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 diff --git a/src/extract-magic b/src/extract-magic index 98e9d871..5b6f6185 100644 --- a/src/extract-magic +++ b/src/extract-magic @@ -1,7 +1,7 @@ #!/usr/bin/perl -w # Derive #define directives from specially formatted 'case ...:' statements. -# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# Copyright (C) 2003-2014 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 diff --git a/src/factor.c b/src/factor.c index 8f1542a2..63924d54 100644 --- a/src/factor.c +++ b/src/factor.c @@ -1,5 +1,5 @@ /* factor -- print prime factors of n. - Copyright (C) 1986-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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 @@ -689,22 +689,6 @@ verify (W <= WIDE_UINT_BITS); This flag is used only in the GMP code. */ static bool dev_debug = false; -/* Like error(0, 0, ...), but without an implicit newline. - Also a noop unless the global DEV_DEBUG is set. - TODO: Replace with variadic macro in system.h or - move to a separate module. */ -static inline void -devmsg (char const *fmt, ...) -{ - if (dev_debug) - { - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - } -} - /* Prove primality or run probabilistic tests. */ static bool flag_prove_primality = true; @@ -791,7 +775,7 @@ factor_using_division (uintmax_t *t1p, uintmax_t t1, uintmax_t t0, { for (;;) { - uintmax_t q1, q0, hi, lo ATTRIBUTE_UNUSED; + uintmax_t q1, q0, hi, lo _GL_UNUSED; q0 = t0 * primes_dtab[i].binv; umul_ppmm (hi, lo, q0, p); @@ -933,7 +917,7 @@ static const unsigned char binvert_table[128] = _q0 = (u0) * _di; \ if ((u1) >= (d)) \ { \ - uintmax_t _p1, _p0 ATTRIBUTE_UNUSED; \ + uintmax_t _p1, _p0 _GL_UNUSED; \ umul_ppmm (_p1, _p0, _q0, d); \ (q1) = ((u1) - _p1) * _di; \ (q0) = _q0; \ @@ -948,7 +932,7 @@ static const unsigned char binvert_table[128] = /* x B (mod n). */ #define redcify(r_prim, r, n) \ do { \ - uintmax_t _redcify_q ATTRIBUTE_UNUSED; \ + uintmax_t _redcify_q _GL_UNUSED; \ udiv_qrnnd (_redcify_q, r_prim, r, 0, n); \ } while (0) @@ -981,7 +965,7 @@ static const unsigned char binvert_table[128] = static inline uintmax_t mulredc (uintmax_t a, uintmax_t b, uintmax_t m, uintmax_t mi) { - uintmax_t rh, rl, q, th, tl ATTRIBUTE_UNUSED, xh; + uintmax_t rh, rl, q, th, tl _GL_UNUSED, xh; umul_ppmm (rh, rl, a, b); q = rl * mi; @@ -1001,7 +985,7 @@ mulredc2 (uintmax_t *r1p, uintmax_t a1, uintmax_t a0, uintmax_t b1, uintmax_t b0, uintmax_t m1, uintmax_t m0, uintmax_t mi) { - uintmax_t r1, r0, q, p1, p0 ATTRIBUTE_UNUSED, t1, t0, s1, s0; + uintmax_t r1, r0, q, p1, p0 _GL_UNUSED, t1, t0, s1, s0; mi = -mi; assert ( (a1 >> (W_TYPE_SIZE - 1)) == 0); assert ( (b1 >> (W_TYPE_SIZE - 1)) == 0); @@ -1271,7 +1255,7 @@ prime_p (uintmax_t n) a_prim = s0 % n; else { - uintmax_t dummy ATTRIBUTE_UNUSED; + uintmax_t dummy _GL_UNUSED; udiv_qrnnd (dummy, a_prim, s1, s0, n); } } @@ -1803,7 +1787,7 @@ isqrt2 (uintmax_t nh, uintmax_t nl) /* Do we need more than one iteration? */ for (;;) { - uintmax_t r ATTRIBUTE_UNUSED; + uintmax_t r _GL_UNUSED; uintmax_t q, y; udiv_qrnnd (q, r, nh, nl, x); y = (x + q) / 2; diff --git a/src/find-mount-point.c b/src/find-mount-point.c index 662e46fc..869d81c6 100644 --- a/src/find-mount-point.c +++ b/src/find-mount-point.c @@ -1,5 +1,5 @@ /* find-mount-point.c -- find the root mount point for a file. - Copyright (C) 2010-2013 Free Software Foundation, Inc. + Copyright (C) 2010-2014 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 diff --git a/src/find-mount-point.h b/src/find-mount-point.h index 52213db7..c8a66dd8 100644 --- a/src/find-mount-point.h +++ b/src/find-mount-point.h @@ -1,5 +1,5 @@ /* find-mount-point.h -- find the root mount point for a file. - Copyright (C) 2010-2013 Free Software Foundation, Inc. + Copyright (C) 2010-2014 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 @@ -1,5 +1,5 @@ /* GNU fmt -- simple text formatter. - Copyright (C) 1994-2013 Free Software Foundation, Inc. + Copyright (C) 1994-2014 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 @@ -1,5 +1,5 @@ /* fold -- wrap each input line to fit in specified width. - Copyright (C) 1991-2013 Free Software Foundation, Inc. + Copyright (C) 1991-2014 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 diff --git a/src/fs-is-local.h b/src/fs-is-local.h index f44f1e72..2a7deee0 100644 --- a/src/fs-is-local.h +++ b/src/fs-is-local.h @@ -22,16 +22,20 @@ is_local_fs_type (unsigned long int magic) case S_MAGIC_CIFS: return 0; case S_MAGIC_CODA: return 0; case S_MAGIC_COH: return 1; + case S_MAGIC_CONFIGFS: return 1; case S_MAGIC_CRAMFS: return 1; case S_MAGIC_CRAMFS_WEND: return 1; case S_MAGIC_DEBUGFS: return 1; case S_MAGIC_DEVFS: return 1; case S_MAGIC_DEVPTS: return 1; case S_MAGIC_ECRYPTFS: return 1; + case S_MAGIC_EFIVARFS: return 1; case S_MAGIC_EFS: return 1; + case S_MAGIC_EXOFS: return 1; case S_MAGIC_EXT: return 1; case S_MAGIC_EXT2: return 1; case S_MAGIC_EXT2_OLD: return 1; + case S_MAGIC_F2FS: return 1; case S_MAGIC_FAT: return 1; case S_MAGIC_FHGFS: return 0; case S_MAGIC_FUSEBLK: return 0; @@ -40,6 +44,9 @@ is_local_fs_type (unsigned long int magic) case S_MAGIC_GFS: return 0; case S_MAGIC_GPFS: return 0; case S_MAGIC_HFS: return 1; + case S_MAGIC_HFS_PLUS: return 1; + case S_MAGIC_HFS_X: return 1; + case S_MAGIC_HOSTFS: return 1; case S_MAGIC_HPFS: return 1; case S_MAGIC_HUGETLBFS: return 1; case S_MAGIC_MTD_INODE_FS: return 1; @@ -51,6 +58,7 @@ is_local_fs_type (unsigned long int magic) case S_MAGIC_JFFS2: return 1; case S_MAGIC_JFS: return 1; case S_MAGIC_KAFS: return 0; + case S_MAGIC_LOGFS: return 1; case S_MAGIC_LUSTRE: return 0; case S_MAGIC_MINIX: return 1; case S_MAGIC_MINIX_30: return 1; @@ -78,20 +86,23 @@ is_local_fs_type (unsigned long int magic) case S_MAGIC_RPC_PIPEFS: return 1; case S_MAGIC_SECURITYFS: return 1; case S_MAGIC_SELINUX: return 1; + case S_MAGIC_SMACK: return 1; case S_MAGIC_SMB: return 0; + case S_MAGIC_SNFS: return 0; case S_MAGIC_SOCKFS: return 1; case S_MAGIC_SQUASHFS: return 1; case S_MAGIC_SYSFS: return 1; case S_MAGIC_SYSV2: return 1; case S_MAGIC_SYSV4: return 1; case S_MAGIC_TMPFS: return 1; + case S_MAGIC_UBIFS: return 1; case S_MAGIC_UDF: return 1; case S_MAGIC_UFS: return 1; case S_MAGIC_UFS_BYTESWAPPED: return 1; case S_MAGIC_USBDEVFS: return 1; case S_MAGIC_V9FS: return 1; case S_MAGIC_VMHGFS: return 0; - case S_MAGIC_VXFS: return 1; + case S_MAGIC_VXFS: return 0; case S_MAGIC_VZFS: return 1; case S_MAGIC_XENFS: return 1; case S_MAGIC_XENIX: return 1; @@ -19,24 +19,31 @@ # define S_MAGIC_CIFS 0xFF534D42 # define S_MAGIC_CODA 0x73757245 # define S_MAGIC_COH 0x012FF7B7 +# define S_MAGIC_CONFIGFS 0x62656570 # define S_MAGIC_CRAMFS 0x28CD3D45 # define S_MAGIC_CRAMFS_WEND 0x453DCD28 # define S_MAGIC_DEBUGFS 0x64626720 # define S_MAGIC_DEVFS 0x1373 # define S_MAGIC_DEVPTS 0x1CD1 # define S_MAGIC_ECRYPTFS 0xF15F +# define S_MAGIC_EFIVARFS 0xDE5E81E4 # define S_MAGIC_EFS 0x00414A53 +# define S_MAGIC_EXOFS 0x5DF5 # define S_MAGIC_EXT 0x137D # define S_MAGIC_EXT2 0xEF53 # define S_MAGIC_EXT2_OLD 0xEF51 +# define S_MAGIC_F2FS 0xF2F52010 # define S_MAGIC_FAT 0x4006 # define S_MAGIC_FHGFS 0x19830326 # define S_MAGIC_FUSEBLK 0x65735546 # define S_MAGIC_FUSECTL 0x65735543 # define S_MAGIC_FUTEXFS 0x0BAD1DEA -# define S_MAGIC_GFS 0x1161970 +# define S_MAGIC_GFS 0x01161970 # define S_MAGIC_GPFS 0x47504653 # define S_MAGIC_HFS 0x4244 +# define S_MAGIC_HFS_PLUS 0x482B +# define S_MAGIC_HFS_X 0x4858 +# define S_MAGIC_HOSTFS 0x00C0FFEE # define S_MAGIC_HPFS 0xF995E849 # define S_MAGIC_HUGETLBFS 0x958458F6 # define S_MAGIC_MTD_INODE_FS 0x11307854 @@ -48,6 +55,7 @@ # define S_MAGIC_JFFS2 0x72B6 # define S_MAGIC_JFS 0x3153464A # define S_MAGIC_KAFS 0x6B414653 +# define S_MAGIC_LOGFS 0xC97E8168 # define S_MAGIC_LUSTRE 0x0BD00BD0 # define S_MAGIC_MINIX 0x137F # define S_MAGIC_MINIX_30 0x138F @@ -62,7 +70,7 @@ # define S_MAGIC_NILFS 0x3434 # define S_MAGIC_NTFS 0x5346544E # define S_MAGIC_OPENPROM 0x9FA1 -# define S_MAGIC_OCFS2 0x7461636f +# define S_MAGIC_OCFS2 0x7461636F # define S_MAGIC_PANFS 0xAAD7AAEA # define S_MAGIC_PIPEFS 0x50495045 # define S_MAGIC_PROC 0x9FA0 @@ -75,13 +83,16 @@ # define S_MAGIC_RPC_PIPEFS 0x67596969 # define S_MAGIC_SECURITYFS 0x73636673 # define S_MAGIC_SELINUX 0xF97CFF8C +# define S_MAGIC_SMACK 0x43415D53 # define S_MAGIC_SMB 0x517B +# define S_MAGIC_SNFS 0xBEEFDEAD # define S_MAGIC_SOCKFS 0x534F434B # define S_MAGIC_SQUASHFS 0x73717368 # define S_MAGIC_SYSFS 0x62656572 # define S_MAGIC_SYSV2 0x012FF7B6 # define S_MAGIC_SYSV4 0x012FF7B5 # define S_MAGIC_TMPFS 0x01021994 +# define S_MAGIC_UBIFS 0x24051905 # define S_MAGIC_UDF 0x15013346 # define S_MAGIC_UFS 0x00011954 # define S_MAGIC_UFS_BYTESWAPPED 0x54190100 diff --git a/src/getlimits.c b/src/getlimits.c index 7c1fbe26..597efd82 100644 --- a/src/getlimits.c +++ b/src/getlimits.c @@ -1,5 +1,5 @@ /* getlimits - print various platform dependent limits. - Copyright (C) 2008-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2014 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 @@ -21,6 +21,7 @@ #include <sys/types.h> #include <float.h> +#include "ftoastr.h" #include "system.h" #include "long-options.h" @@ -97,6 +98,19 @@ decimal_absval_add_one (char *buf) return result; } +#define PRINT_FLOATTYPE(N, T, FTOASTR, BUFSIZE) \ +static void \ +N (T x) \ +{ \ + char buf[BUFSIZE]; \ + FTOASTR (buf, sizeof buf, FTOASTR_LEFT_JUSTIFY, 0, x); \ + puts (buf); \ +} + +PRINT_FLOATTYPE (print_FLT, float, ftoastr, FLT_BUFSIZE_BOUND) +PRINT_FLOATTYPE (print_DBL, double, dtoastr, DBL_BUFSIZE_BOUND) +PRINT_FLOATTYPE (print_LDBL, long double, ldtoastr, LDBL_BUFSIZE_BOUND) + int main (int argc, char **argv) { @@ -127,8 +141,8 @@ main (int argc, char **argv) } #define print_float(TYPE) \ - printf (#TYPE"_MIN=%Le\n", (long double)TYPE##_MIN); \ - printf (#TYPE"_MAX=%Le\n", (long double)TYPE##_MAX); + printf (#TYPE"_MIN="); print_##TYPE (TYPE##_MIN); \ + printf (#TYPE"_MAX="); print_##TYPE (TYPE##_MAX); /* Variable sized ints */ print_int (CHAR); diff --git a/src/group-list.c b/src/group-list.c index 7d4995b5..823384f5 100644 --- a/src/group-list.c +++ b/src/group-list.c @@ -1,5 +1,5 @@ /* group-list.c --Print a list of group IDs or names. - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -35,7 +35,7 @@ extern bool print_group_list (const char *username, uid_t ruid, gid_t rgid, gid_t egid, - bool use_names) + bool use_names, char delim) { bool ok = true; struct passwd *pwd = NULL; @@ -52,7 +52,7 @@ print_group_list (const char *username, if (egid != rgid) { - putchar (' '); + putchar (delim); if (!print_group (egid, use_names)) ok = false; } @@ -79,7 +79,7 @@ print_group_list (const char *username, for (i = 0; i < n_groups; i++) if (groups[i] != rgid && groups[i] != egid) { - putchar (' '); + putchar (delim); if (!print_group (groups[i], use_names)) ok = false; } diff --git a/src/group-list.h b/src/group-list.h index 3fac8871..806f78fd 100644 --- a/src/group-list.h +++ b/src/group-list.h @@ -1,6 +1,6 @@ /* group-list.h -- prototypes shared by id and groups. - Copyright (C) 2008-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2014 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 @@ -16,4 +16,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ bool print_group (gid_t, bool); -bool print_group_list (const char *, uid_t, gid_t, gid_t, bool); +bool print_group_list (const char *, uid_t, gid_t, gid_t, bool, char); diff --git a/src/groups.c b/src/groups.c index 53332d56..f19ff0ac 100644 --- a/src/groups.c +++ b/src/groups.c @@ -1,5 +1,5 @@ /* groups -- print the groups a user is in - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -114,13 +114,13 @@ main (int argc, char **argv) if (rgid == NO_GID && errno) error (EXIT_FAILURE, errno, _("cannot get real GID")); - if (!print_group_list (NULL, ruid, rgid, egid, true)) + if (!print_group_list (NULL, ruid, rgid, egid, true, ' ')) ok = false; putchar ('\n'); } else { - /* At least one argument. Divulge the details of the specified users. */ + /* At least one argument. Divulge the details of the specified users. */ while (optind < argc) { struct passwd *pwd = getpwnam (argv[optind]); @@ -130,7 +130,7 @@ main (int argc, char **argv) rgid = egid = pwd->pw_gid; printf ("%s : ", argv[optind]); - if (!print_group_list (argv[optind++], ruid, rgid, egid, true)) + if (!print_group_list (argv[optind++], ruid, rgid, egid, true, ' ')) ok = false; putchar ('\n'); } @@ -1,5 +1,5 @@ /* head -- output first part of file(s) - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -34,6 +34,7 @@ #include "error.h" #include "full-read.h" #include "quote.h" +#include "quotearg.h" #include "safe-read.h" #include "xfreopen.h" #include "xstrtol.h" @@ -70,7 +71,6 @@ enum Copy_fd_status { COPY_FD_OK = 0, COPY_FD_READ_ERROR, - COPY_FD_WRITE_ERROR, COPY_FD_UNEXPECTED_EOF }; @@ -147,9 +147,6 @@ diagnose_copy_fd_failure (enum Copy_fd_status err, char const *filename) case COPY_FD_READ_ERROR: error (0, errno, _("error reading %s"), quote (filename)); break; - case COPY_FD_WRITE_ERROR: - error (0, errno, _("error writing %s"), quote (filename)); - break; case COPY_FD_UNEXPECTED_EOF: error (0, errno, _("%s: file has shrunk too much"), quote (filename)); break; @@ -167,11 +164,25 @@ write_header (const char *filename) first_file = false; } -/* Copy no more than N_BYTES from file descriptor SRC_FD to O_STREAM. - Return an appropriate indication of success or failure. */ +/* Write N_BYTES from BUFFER to stdout. + Exit immediately on error with a single diagnostic. */ + +static void +xwrite_stdout (char const *buffer, size_t n_bytes) +{ + if (n_bytes > 0 && fwrite (buffer, 1, n_bytes, stdout) < n_bytes) + { + clearerr (stdout); /* To avoid redundant close_stdout diagnostic. */ + error (EXIT_FAILURE, errno, _("error writing %s"), + quote ("standard output")); + } +} + +/* Copy no more than N_BYTES from file descriptor SRC_FD to stdout. + Return an appropriate indication of success or read failure. */ static enum Copy_fd_status -copy_fd (int src_fd, FILE *o_stream, uintmax_t n_bytes) +copy_fd (int src_fd, uintmax_t n_bytes) { char buf[BUFSIZ]; const size_t buf_size = sizeof (buf); @@ -189,14 +200,13 @@ copy_fd (int src_fd, FILE *o_stream, uintmax_t n_bytes) if (n_read == 0 && n_bytes != 0) return COPY_FD_UNEXPECTED_EOF; - if (fwrite (buf, 1, n_read, o_stream) < n_read) - return COPY_FD_WRITE_ERROR; + xwrite_stdout (buf, n_read); } return COPY_FD_OK; } -/* Print all but the last N_ELIDE lines from the input available via +/* Print all but the last N_ELIDE bytes from the input available via the non-seekable file descriptor FD. Return true upon success. Give a diagnostic and return false upon error. */ static bool @@ -282,22 +292,12 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0) /* Output any (but maybe just part of the) elided data from the previous round. */ - if ( ! first) - { - /* Don't bother checking for errors here. - If there's a failure, the test of the following - fwrite or in close_stdout will catch it. */ - fwrite (b[!i] + READ_BUFSIZE, 1, n_elide - delta, stdout); - } + if (! first) + xwrite_stdout (b[!i] + READ_BUFSIZE, n_elide - delta); first = false; - if (n_elide < n_read - && fwrite (b[i], 1, n_read - n_elide, stdout) < n_read - n_elide) - { - error (0, errno, _("write error")); - ok = false; - break; - } + if (n_elide < n_read) + xwrite_stdout (b[i], n_read - n_elide); } free (b[0]); @@ -313,18 +313,34 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0) size_t n_read; bool buffered_enough; size_t i, i_next; - char **b; + char **b = NULL; /* Round n_elide up to a multiple of READ_BUFSIZE. */ size_t rem = READ_BUFSIZE - (n_elide % READ_BUFSIZE); size_t n_elide_round = n_elide + rem; size_t n_bufs = n_elide_round / READ_BUFSIZE + 1; - b = xcalloc (n_bufs, sizeof *b); + size_t n_alloc = 0; + size_t n_array_alloc = 0; buffered_enough = false; for (i = 0, i_next = 1; !eof; i = i_next, i_next = (i_next + 1) % n_bufs) { - if (b[i] == NULL) - b[i] = xmalloc (READ_BUFSIZE); + if (n_array_alloc == i) + { + /* reallocate between 16 and n_bufs entries. */ + if (n_array_alloc == 0) + n_array_alloc = MIN (n_bufs, 16); + else if (n_array_alloc <= n_bufs / 2) + n_array_alloc *= 2; + else + n_array_alloc = n_bufs; + b = xnrealloc (b, n_array_alloc, sizeof *b); + } + + if (! buffered_enough) + { + b[i] = xmalloc (READ_BUFSIZE); + n_alloc = i + 1; + } n_read = full_read (fd, b[i], READ_BUFSIZE); if (n_read < READ_BUFSIZE) { @@ -341,14 +357,7 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0) buffered_enough = true; if (buffered_enough) - { - if (fwrite (b[i_next], 1, n_read, stdout) < n_read) - { - error (0, errno, _("write error")); - ok = false; - goto free_mem; - } - } + xwrite_stdout (b[i_next], n_read); } /* Output any remainder: rem bytes from b[i] + n_read. */ @@ -359,12 +368,12 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0) size_t n_bytes_left_in_b_i = READ_BUFSIZE - n_read; if (rem < n_bytes_left_in_b_i) { - fwrite (b[i] + n_read, 1, rem, stdout); + xwrite_stdout (b[i] + n_read, rem); } else { - fwrite (b[i] + n_read, 1, n_bytes_left_in_b_i, stdout); - fwrite (b[i_next], 1, rem - n_bytes_left_in_b_i, stdout); + xwrite_stdout (b[i] + n_read, n_bytes_left_in_b_i); + xwrite_stdout (b[i_next], rem - n_bytes_left_in_b_i); } } else if (i + 1 == n_bufs) @@ -383,12 +392,12 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0) */ size_t y = READ_BUFSIZE - rem; size_t x = n_read - y; - fwrite (b[i_next], 1, x, stdout); + xwrite_stdout (b[i_next], x); } } free_mem: - for (i = 0; i < n_bufs; i++) + for (i = 0; i < n_alloc; i++) free (b[i]); free (b); @@ -396,53 +405,53 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0) } } -/* Print all but the last N_ELIDE lines from the input available - via file descriptor FD. Return true upon success. +/* Call lseek (FD, OFFSET, WHENCE), where file descriptor FD + corresponds to the file FILENAME. WHENCE must be SEEK_SET or + SEEK_CUR. Return the resulting offset. Give a diagnostic and + return -1 if lseek fails. */ + +static off_t +elseek (int fd, off_t offset, int whence, char const *filename) +{ + off_t new_offset = lseek (fd, offset, whence); + char buf[INT_BUFSIZE_BOUND (offset)]; + + if (new_offset < 0) + error (0, errno, + _(whence == SEEK_SET + ? N_("%s: cannot seek to offset %s") + : N_("%s: cannot seek to relative offset %s")), + quotearg_colon (filename), + offtostr (offset, buf)); + + return new_offset; +} + +/* For the file FILENAME with descriptor FD, output all but the last N_ELIDE + bytes. If SIZE is nonnegative, this is a regular file positioned + at START_POS with SIZE bytes. Return true on success. Give a diagnostic and return false upon error. */ /* NOTE: if the input file shrinks by more than N_ELIDE bytes between the length determination and the actual reading, then head fails. */ static bool -elide_tail_bytes_file (const char *filename, int fd, uintmax_t n_elide) +elide_tail_bytes_file (const char *filename, int fd, uintmax_t n_elide, + off_t current_pos, off_t size) { - struct stat stats; - - if (presume_input_pipe || fstat (fd, &stats) || ! S_ISREG (stats.st_mode)) - { - return elide_tail_bytes_pipe (filename, fd, n_elide); - } + if (size < 0) + return elide_tail_bytes_pipe (filename, fd, n_elide); else { - off_t current_pos, end_pos; - uintmax_t bytes_remaining; - off_t diff; - enum Copy_fd_status err; - - if ((current_pos = lseek (fd, 0, SEEK_CUR)) == -1 - || (end_pos = lseek (fd, 0, SEEK_END)) == -1) - { - error (0, errno, _("cannot lseek %s"), quote (filename)); - return false; - } - /* Be careful here. The current position may actually be beyond the end of the file. */ - bytes_remaining = (diff = end_pos - current_pos) < 0 ? 0 : diff; + off_t diff = size - current_pos; + off_t bytes_remaining = diff < 0 ? 0 : diff; if (bytes_remaining <= n_elide) return true; - /* Seek back to 'current' position, then copy the required - number of bytes from fd. */ - if (lseek (fd, 0, current_pos) == -1) - { - error (0, errno, _("%s: cannot lseek back to original position"), - quote (filename)); - return false; - } - - err = copy_fd (fd, stdout, bytes_remaining - n_elide); + enum Copy_fd_status err = copy_fd (fd, bytes_remaining - n_elide); if (err == COPY_FD_OK) return true; @@ -485,6 +494,13 @@ elide_tail_lines_pipe (const char *filename, int fd, uintmax_t n_elide) n_read = safe_read (fd, tmp->buffer, BUFSIZ); if (n_read == 0 || n_read == SAFE_READ_ERROR) break; + + if (! n_elide) + { + xwrite_stdout (tmp->buffer, n_read); + continue; + } + tmp->nbytes = n_read; tmp->nlines = 0; tmp->next = NULL; @@ -520,7 +536,7 @@ elide_tail_lines_pipe (const char *filename, int fd, uintmax_t n_elide) last = last->next = tmp; if (n_elide < total_lines - first->nlines) { - fwrite (first->buffer, 1, first->nbytes, stdout); + xwrite_stdout (first->buffer, first->nbytes); tmp = first; total_lines -= first->nlines; first = first->next; @@ -549,7 +565,7 @@ elide_tail_lines_pipe (const char *filename, int fd, uintmax_t n_elide) for (tmp = first; n_elide < total_lines - tmp->nlines; tmp = tmp->next) { - fwrite (tmp->buffer, 1, tmp->nbytes, stdout); + xwrite_stdout (tmp->buffer, tmp->nbytes); total_lines -= tmp->nlines; } @@ -565,7 +581,7 @@ elide_tail_lines_pipe (const char *filename, int fd, uintmax_t n_elide) ++tmp->nlines; --n; } - fwrite (tmp->buffer, 1, p - tmp->buffer, stdout); + xwrite_stdout (tmp->buffer, p - tmp->buffer); } free_lbuffers: @@ -579,10 +595,10 @@ free_lbuffers: } /* Output all but the last N_LINES lines of the input stream defined by - FD, START_POS, and END_POS. + FD, START_POS, and SIZE. START_POS is the starting position of the read pointer for the file associated with FD (may be nonzero). - END_POS is the file offset of EOF (one larger than offset of last byte). + SIZE is the file size in bytes. Return true upon success. Give a diagnostic and return false upon error. @@ -592,11 +608,11 @@ free_lbuffers: static bool elide_tail_lines_seekable (const char *pretty_filename, int fd, uintmax_t n_lines, - off_t start_pos, off_t end_pos) + off_t start_pos, off_t size) { char buffer[BUFSIZ]; size_t bytes_read; - off_t pos = end_pos; + off_t pos = size; /* Set 'bytes_read' to the size of the last, probably partial, buffer; 0 < 'bytes_read' <= 'BUFSIZ'. */ @@ -606,13 +622,8 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd, /* Make 'pos' a multiple of 'BUFSIZ' (0 if the file is short), so that all reads will be on block boundaries, which might increase efficiency. */ pos -= bytes_read; - if (lseek (fd, pos, SEEK_SET) < 0) - { - char offset_buf[INT_BUFSIZE_BOUND (pos)]; - error (0, errno, _("%s: cannot seek to offset %s"), - pretty_filename, offtostr (pos, offset_buf)); - return false; - } + if (elseek (fd, pos, SEEK_SET, pretty_filename) < 0) + return false; bytes_read = safe_read (fd, buffer, bytes_read); if (bytes_read == SAFE_READ_ERROR) { @@ -620,8 +631,11 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd, return false; } + /* n_lines == 0 case needs special treatment. */ + const bool all_lines = !n_lines; + /* Count the incomplete line on files that don't end with a newline. */ - if (bytes_read && buffer[bytes_read - 1] != '\n') + if (n_lines && bytes_read && buffer[bytes_read - 1] != '\n') --n_lines; while (1) @@ -631,11 +645,16 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd, size_t n = bytes_read; while (n) { - char const *nl; - nl = memrchr (buffer, '\n', n); - if (nl == NULL) - break; - n = nl - buffer; + if (all_lines) + n -= 1; + else + { + char const *nl; + nl = memrchr (buffer, '\n', n); + if (nl == NULL) + break; + n = nl - buffer; + } if (n_lines-- == 0) { /* Found it. */ @@ -644,16 +663,10 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd, if (start_pos < pos) { enum Copy_fd_status err; - if (lseek (fd, start_pos, SEEK_SET) < 0) - { - /* Failed to reposition file pointer. */ - error (0, errno, - "%s: unable to restore file pointer to initial offset", - quote (pretty_filename)); - return false; - } + if (elseek (fd, start_pos, SEEK_SET, pretty_filename) < 0) + return false; - err = copy_fd (fd, stdout, pos - start_pos); + err = copy_fd (fd, pos - start_pos); if (err != COPY_FD_OK) { diagnose_copy_fd_failure (err, pretty_filename); @@ -662,19 +675,11 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd, } /* Output the initial portion of the buffer - in which we found the desired newline byte. - Don't bother testing for failure for such a small amount. - Any failure will be detected upon close. */ - fwrite (buffer, 1, n + 1, stdout); + in which we found the desired newline byte. */ + xwrite_stdout (buffer, n + 1); /* Set file pointer to the byte after what we've output. */ - if (lseek (fd, pos + n + 1, SEEK_SET) < 0) - { - error (0, errno, _("%s: failed to reset file pointer"), - quote (pretty_filename)); - return false; - } - return true; + return 0 <= elseek (fd, pos + n + 1, SEEK_SET, pretty_filename); } } @@ -685,13 +690,8 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd, return true; } pos -= BUFSIZ; - if (lseek (fd, pos, SEEK_SET) < 0) - { - char offset_buf[INT_BUFSIZE_BOUND (pos)]; - error (0, errno, _("%s: cannot seek to offset %s"), - pretty_filename, offtostr (pos, offset_buf)); - return false; - } + if (elseek (fd, pos, SEEK_SET, pretty_filename) < 0) + return false; bytes_read = safe_read (fd, buffer, BUFSIZ); if (bytes_read == SAFE_READ_ERROR) @@ -707,37 +707,28 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd, } } -/* Print all but the last N_ELIDE lines from the input available - via file descriptor FD. Return true upon success. +/* For the file FILENAME with descriptor FD, output all but the last N_ELIDE + lines. If SIZE is nonnegative, this is a regular file positioned + at START_POS with SIZE bytes. Return true on success. Give a diagnostic and return nonzero upon error. */ static bool -elide_tail_lines_file (const char *filename, int fd, uintmax_t n_elide) +elide_tail_lines_file (const char *filename, int fd, uintmax_t n_elide, + off_t current_pos, off_t size) { - if (!presume_input_pipe) + if (size < 0) + return elide_tail_lines_pipe (filename, fd, n_elide); + else { /* Find the offset, OFF, of the Nth newline from the end, but not counting the last byte of the file. If found, write from current position to OFF, inclusive. Otherwise, just return true. */ - off_t start_pos = lseek (fd, 0, SEEK_CUR); - off_t end_pos = lseek (fd, 0, SEEK_END); - if (0 <= start_pos && start_pos < end_pos) - { - /* If the file is empty, we're done. */ - if (end_pos == 0) - return true; - - return elide_tail_lines_seekable (filename, fd, n_elide, - start_pos, end_pos); - } - - /* lseek failed or the end offset precedes start. - Fall through. */ + return (size <= current_pos + || elide_tail_lines_seekable (filename, fd, n_elide, + current_pos, size)); } - - return elide_tail_lines_pipe (filename, fd, n_elide); } static bool @@ -759,8 +750,7 @@ head_bytes (const char *filename, int fd, uintmax_t bytes_to_write) } if (bytes_read == 0) break; - if (fwrite (buffer, 1, bytes_read, stdout) < bytes_read) - error (EXIT_FAILURE, errno, _("write error")); + xwrite_stdout (buffer, bytes_read); bytes_to_write -= bytes_read; } return true; @@ -792,16 +782,13 @@ head_lines (const char *filename, int fd, uintmax_t lines_to_write) gotten to had we been reading one byte at a time. */ if (lseek (fd, -n_bytes_past_EOL, SEEK_CUR) < 0) { - int e = errno; struct stat st; if (fstat (fd, &st) != 0 || S_ISREG (st.st_mode)) - error (0, e, _("cannot reposition file pointer for %s"), - quote (filename)); + elseek (fd, -n_bytes_past_EOL, SEEK_CUR, filename); } break; } - if (fwrite (buffer, 1, bytes_to_write, stdout) < bytes_to_write) - error (EXIT_FAILURE, errno, _("write error")); + xwrite_stdout (buffer, bytes_to_write); } return true; } @@ -815,14 +802,28 @@ head (const char *filename, int fd, uintmax_t n_units, bool count_lines, if (elide_from_end) { - if (count_lines) + off_t current_pos = -1, size = -1; + if (! presume_input_pipe) { - return elide_tail_lines_file (filename, fd, n_units); + struct stat st; + if (fstat (fd, &st) != 0) + { + error (0, errno, _("cannot fstat %s"), + quotearg_colon (filename)); + return false; + } + if (S_ISREG (st.st_mode)) + { + size = st.st_size; + current_pos = elseek (fd, 0, SEEK_CUR, filename); + if (current_pos < 0) + return false; + } } + if (count_lines) + return elide_tail_lines_file (filename, fd, n_units, current_pos, size); else - { - return elide_tail_bytes_file (filename, fd, n_units); - } + return elide_tail_bytes_file (filename, fd, n_units, current_pos, size); } if (count_lines) return head_lines (filename, fd, n_units); diff --git a/src/hostid.c b/src/hostid.c index b2d218cc..5b40eb01 100644 --- a/src/hostid.c +++ b/src/hostid.c @@ -1,6 +1,6 @@ /* print the hexadecimal identifier for the current host - Copyright (C) 1997-2013 Free Software Foundation, Inc. + Copyright (C) 1997-2014 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 diff --git a/src/hostname.c b/src/hostname.c index d0a4d754..bab51ae4 100644 --- a/src/hostname.c +++ b/src/hostname.c @@ -1,5 +1,5 @@ /* hostname - set or print the name of current host system - Copyright (C) 1994-2013 Free Software Foundation, Inc. + Copyright (C) 1994-2014 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 @@ -1,5 +1,5 @@ /* id -- print real and effective UIDs and GIDs - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -30,6 +30,8 @@ #include "mgetgroups.h" #include "quote.h" #include "group-list.h" +#include "smack.h" +#include "userspec.h" /* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "id" @@ -38,8 +40,8 @@ proper_name ("Arnold Robbins"), \ proper_name ("David MacKenzie") -/* If nonzero, output only the SELinux context. -Z */ -static int just_context = 0; +/* If nonzero, output only the SELinux context. */ +static bool just_context = 0; static void print_user (uid_t uid); static void print_full_info (const char *username); @@ -56,7 +58,7 @@ static bool ok = true; /* The SELinux context. Start with a known invalid value so print_full_info knows when 'context' has not been set to a meaningful value. */ -static security_context_t context = NULL; +static char *context = NULL; static struct option const longopts[] = { @@ -66,6 +68,7 @@ static struct option const longopts[] = {"name", no_argument, NULL, 'n'}, {"real", no_argument, NULL, 'r'}, {"user", no_argument, NULL, 'u'}, + {"zero", no_argument, NULL, 'z'}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} @@ -78,18 +81,22 @@ usage (int status) emit_try_help (); else { - printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name); + printf (_("Usage: %s [OPTION]... [USER]\n"), program_name); fputs (_("\ -Print user and group information for the specified USERNAME,\n\ -or (when USERNAME omitted) for the current user.\n\ -\n\ - -a ignore, for compatibility with other versions\n\ - -Z, --context print only the security context of the current user\n\ - -g, --group print only the effective group ID\n\ - -G, --groups print all group IDs\n\ - -n, --name print a name instead of a number, for -ugG\n\ - -r, --real print the real ID instead of the effective ID, with -ugG\n\ - -u, --user print only the effective user ID\n\ +Print user and group information for the specified USER,\n\ +or (when USER omitted) for the current user.\n\ +\n"), + stdout); + fputs (_("\ + -a ignore, for compatibility with other versions\n\ + -Z, --context print only the security context of the process\n\ + -g, --group print only the effective group ID\n\ + -G, --groups print all group IDs\n\ + -n, --name print a name instead of a number, for -ugG\n\ + -r, --real print the real ID instead of the effective ID, with -ugG\n\ + -u, --user print only the effective user ID\n\ + -z, --zero delimit entries with NUL characters, not whitespace;\n\ + not permitted in default format\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -107,6 +114,9 @@ main (int argc, char **argv) { int optc; int selinux_enabled = (is_selinux_enabled () > 0); + bool smack_enabled = is_smack_enabled (); + bool opt_zero = false; + char *pw_name = NULL; /* If true, output the list of all group IDs. -G */ bool just_group_list = false; @@ -125,7 +135,7 @@ main (int argc, char **argv) atexit (close_stdout); - while ((optc = getopt_long (argc, argv, "agnruGZ", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "agnruzGZ", longopts, NULL)) != -1) { switch (optc) { @@ -134,11 +144,18 @@ main (int argc, char **argv) break; case 'Z': - /* politely decline if we're not on a selinux-enabled kernel. */ + /* politely decline if we're not on a SELinux/SMACK-enabled kernel. */ +#ifdef HAVE_SMACK + if (!selinux_enabled && !smack_enabled) + error (EXIT_FAILURE, 0, + _("--context (-Z) works only on " + "an SELinux/SMACK-enabled kernel")); +#else if (!selinux_enabled) error (EXIT_FAILURE, 0, _("--context (-Z) works only on an SELinux-enabled kernel")); - just_context = 1; +#endif + just_context = true; break; case 'g': @@ -153,6 +170,9 @@ main (int argc, char **argv) case 'u': just_user = true; break; + case 'z': + opt_zero = true; + break; case 'G': just_group_list = true; break; @@ -184,26 +204,47 @@ main (int argc, char **argv) error (EXIT_FAILURE, 0, _("cannot print only names or real IDs in default format")); - /* If we are on a selinux-enabled kernel, no user is specified, and + if (default_format && opt_zero) + error (EXIT_FAILURE, 0, + _("option --zero not permitted in default format")); + + /* If we are on a SELinux/SMACK-enabled kernel, no user is specified, and either --context is specified or none of (-u,-g,-G) is specified, and we're not in POSIXLY_CORRECT mode, get our context. Otherwise, leave the context variable alone - it has been initialized to an invalid value that will be not displayed in print_full_info(). */ - if (selinux_enabled - && n_ids == 0 + if (n_ids == 0 && (just_context || (default_format && ! getenv ("POSIXLY_CORRECT")))) { /* Report failure only if --context (-Z) was explicitly requested. */ - if (getcon (&context) && just_context) + if ((selinux_enabled && getcon (&context) && just_context) + || (smack_enabled + && smack_new_label_from_self (&context) < 0 + && just_context)) error (EXIT_FAILURE, 0, _("can't get process context")); } if (n_ids == 1) { - struct passwd *pwd = getpwnam (argv[optind]); + struct passwd *pwd = NULL; + const char *spec = argv[optind]; + /* Disallow an empty spec here as parse_user_spec() doesn't + give an error for that as it seems it's a valid way to + specify a noop or "reset special bits" depending on the system. */ + if (*spec) + { + if (parse_user_spec (spec, &euid, NULL, NULL, NULL) == NULL) + { + /* parse_user_spec will only extract a numeric spec, + so we lookup that here to verify and also retrieve + the PW_NAME used subsequently in group lookup. */ + pwd = getpwuid (euid); + } + } if (pwd == NULL) - error (EXIT_FAILURE, 0, _("%s: no such user"), argv[optind]); + error (EXIT_FAILURE, 0, _("%s: no such user"), spec); + pw_name = xstrdup (pwd->pw_name); ruid = euid = pwd->pw_uid; rgid = egid = pwd->pw_gid; } @@ -258,7 +299,8 @@ main (int argc, char **argv) } else if (just_group_list) { - if (!print_group_list (argv[optind], ruid, rgid, egid, use_name)) + if (!print_group_list (pw_name, ruid, rgid, egid, use_name, + opt_zero ? '\0' : ' ')) ok = false; } else if (just_context) @@ -267,10 +309,11 @@ main (int argc, char **argv) } else { - print_full_info (argv[optind]); + print_full_info (pw_name); } - putchar ('\n'); + putchar (opt_zero ? '\0' : '\n'); + IF_LINT (free (pw_name)); exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } @@ -356,19 +399,20 @@ print_full_info (const char *username) gid_t *groups; int i; - int n_groups = xgetgroups (username, (pwd ? pwd->pw_gid : -1), - &groups); + gid_t primary_group; + if (username) + primary_group = pwd ? pwd->pw_gid : -1; + else + primary_group = egid; + + int n_groups = xgetgroups (username, primary_group, &groups); if (n_groups < 0) { if (username) - { - error (0, errno, _("failed to get groups for user %s"), - quote (username)); - } + error (0, errno, _("failed to get groups for user %s"), + quote (username)); else - { - error (0, errno, _("failed to get groups for the current process")); - } + error (0, errno, _("failed to get groups for the current process")); ok = false; return; } diff --git a/src/install.c b/src/install.c index 94374df3..c3424227 100644 --- a/src/install.c +++ b/src/install.c @@ -1,5 +1,5 @@ /* install - copy files and set attributes - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -218,8 +218,8 @@ need_copy (const char *src_name, const char *dest_name, /* compare SELinux context if preserving */ if (selinux_enabled && x->preserve_security_context) { - security_context_t file_scontext = NULL; - security_context_t to_scontext = NULL; + char *file_scontext = NULL; + char *to_scontext = NULL; bool scontext_match; if (getfilecon (src_name, &file_scontext) == -1) @@ -279,7 +279,6 @@ cp_option_init (struct cp_options *x) x->reduce_diagnostics=false; x->data_copy_required = true; x->require_preserve = false; - x->require_preserve_context = false; x->require_preserve_xattr = false; x->recursive = false; x->sparse_mode = SPARSE_AUTO; @@ -295,7 +294,9 @@ cp_option_init (struct cp_options *x) x->open_dangling_dest_symlink = false; x->update = false; - x->preserve_security_context = false; + x->require_preserve_context = false; /* Not used by install currently. */ + x->preserve_security_context = false; /* Whether to copy context from src. */ + x->set_security_context = false; /* Whether to set sys default context. */ x->preserve_xattr = false; x->verbose = false; x->dest_info = NULL; @@ -305,12 +306,13 @@ cp_option_init (struct cp_options *x) #ifdef ENABLE_MATCHPATHCON /* Modify file context to match the specified policy. If an error occurs the file will remain with the default directory - context. */ + context. Note this sets the context to that returned by matchpathcon, + and thus discards MLS levels and user identity of the FILE. */ static void setdefaultfilecon (char const *file) { struct stat st; - security_context_t scontext = NULL; + char *scontext = NULL; static bool first_call = true; if (selinux_enabled != 1) @@ -359,7 +361,8 @@ setdefaultfilecon (char const *file) first_call = false; /* If there's an error determining the context, or it has none, - return to allow default context */ + return to allow default context. Note the "<<none>>" check + is only needed for libselinux < 1.20 (2005-01-04). */ if ((matchpathcon (file, st.st_mode, &scontext) != 0) || STREQ (scontext, "<<none>>")) { @@ -515,16 +518,17 @@ change_timestamps (struct stat const *src_sb, char const *dest) magic numbers vary so much from system to system that making it portable would be very difficult. Not worth the effort. */ -static void +static bool strip (char const *name) { int status; + bool ok = false; pid_t pid = fork (); switch (pid) { case -1: - error (EXIT_FAILURE, errno, _("fork system call failed")); + error (0, errno, _("fork system call failed")); break; case 0: /* Child. */ execlp (strip_program, strip_program, name, NULL); @@ -532,11 +536,14 @@ strip (char const *name) break; default: /* Parent. */ if (waitpid (pid, &status, 0) < 0) - error (EXIT_FAILURE, errno, _("waiting for strip")); + error (0, errno, _("waiting for strip")); else if (! WIFEXITED (status) || WEXITSTATUS (status)) - error (EXIT_FAILURE, 0, _("strip process terminated abnormally")); + error (0, 0, _("strip process terminated abnormally")); + else + ok = true; /* strip succeeded */ break; } + return ok; } /* Initialize the user and group ownership of the files to install. */ @@ -640,8 +647,10 @@ In the 4th form, create all components of the given DIRECTORY(ies).\n\ "), stdout); fputs (_("\ --preserve-context preserve SELinux security context\n\ - -Z, --context=CONTEXT set SELinux security context of files and directories\ -\n\ + -Z set SELinux security context of destination\n\ + file to default type\n\ + --context[=CTX] like -Z, or if CTX is specified then set the\n\ + SELinux or SMACK security context to CTX\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); @@ -681,7 +690,12 @@ install_file_in_file (const char *from, const char *to, if (! copy_file (from, to, x)) return false; if (strip_files) - strip (to); + if (! strip (to)) + { + if (unlink (to) != 0) /* Cleanup. */ + error (EXIT_FAILURE, errno, _("cannot unlink %s"), to); + return false; + } if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode)) && ! change_timestamps (&from_sb, to)) return false; @@ -692,8 +706,7 @@ install_file_in_file (const char *from, const char *to, Return true if successful. */ static bool -install_file_in_file_parents (char const *from, char *to, - struct cp_options *x) +mkancesdirs_safe_wd (char const *from, char *to, struct cp_options *x) { bool save_working_directory = ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to)); @@ -723,8 +736,18 @@ install_file_in_file_parents (char const *from, char *to, return false; } } + return status == EXIT_SUCCESS; +} + +/* Copy file FROM onto file TO, creating any missing parent directories of TO. + Return true if successful. */ - return (status == EXIT_SUCCESS && install_file_in_file (from, to, x)); +static bool +install_file_in_file_parents (char const *from, char *to, + const struct cp_options *x) +{ + return (mkancesdirs_safe_wd (from, to, (struct cp_options *)x) + && install_file_in_file (from, to, x)); } /* Copy file FROM into directory TO_DIR, keeping its same name, @@ -733,11 +756,16 @@ install_file_in_file_parents (char const *from, char *to, static bool install_file_in_dir (const char *from, const char *to_dir, - const struct cp_options *x) + const struct cp_options *x, bool mkdir_and_install) { 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); + bool ret = true; + + if (mkdir_and_install) + ret = mkancesdirs_safe_wd (from, to, (struct cp_options *)x); + + ret = ret && install_file_in_file (from, to, x); free (to); return ret; } @@ -758,7 +786,7 @@ main (int argc, char **argv) int n_files; char **file; bool strip_program_specified = false; - security_context_t scontext = NULL; + char const *scontext = NULL; /* set iff kernel has extra selinux system calls */ selinux_enabled = (0 < is_selinux_enabled ()); @@ -782,7 +810,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:pt:TvS:Z", long_options, NULL)) != -1) { switch (optc) @@ -837,16 +865,6 @@ main (int argc, char **argv) if (target_directory) error (EXIT_FAILURE, 0, _("multiple target directories specified")); - else - { - struct stat st; - if (stat (optarg, &st) != 0) - error (EXIT_FAILURE, errno, _("failed to access %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': @@ -854,7 +872,7 @@ main (int argc, char **argv) break; case PRESERVE_CONTEXT_OPTION: - if ( ! selinux_enabled) + if (! selinux_enabled) { error (0, 0, _("WARNING: ignoring --preserve-context; " "this kernel is not SELinux-enabled")); @@ -864,14 +882,27 @@ main (int argc, char **argv) use_default_selinux_context = false; break; case 'Z': - if ( ! selinux_enabled) + if (selinux_enabled) { - error (0, 0, _("WARNING: ignoring --context (-Z); " - "this kernel is not SELinux-enabled")); - break; + /* Disable use of the install(1) specific setdefaultfilecon(). + Note setdefaultfilecon() is different from the newer and more + generic restorecon() in that the former sets the context of + the dest files to that returned by matchpathcon directly, + thus discarding MLS level and user identity of the file. + TODO: consider removing setdefaultfilecon() in future. */ + use_default_selinux_context = false; + + if (optarg) + scontext = optarg; + else + x.set_security_context = true; + } + else if (optarg) + { + error (0, 0, + _("warning: ignoring --context; " + "it requires an SELinux-enabled kernel")); } - scontext = optarg; - use_default_selinux_context = false; break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -888,10 +919,17 @@ main (int argc, char **argv) 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 (target_directory) + { + struct stat st; + bool stat_success = stat (target_directory, &st) == 0 ? true : false; + if (! mkdir_and_install && ! stat_success) + error (EXIT_FAILURE, errno, _("failed to access %s"), + quote (target_directory)); + if (stat_success && ! S_ISDIR (st.st_mode)) + error (EXIT_FAILURE, 0, _("target %s is not a directory"), + quote (target_directory)); + } if (backup_suffix_string) simple_backup_suffix = xstrdup (backup_suffix_string); @@ -901,7 +939,11 @@ main (int argc, char **argv) version_control_string) : no_backups); - if (scontext && setfscreatecon (scontext) < 0) + if (x.preserve_security_context && (x.set_security_context || scontext)) + error (EXIT_FAILURE, 0, + _("cannot set target context and preserve it")); + + if (scontext && setfscreatecon (se_const (scontext)) < 0) error (EXIT_FAILURE, errno, _("failed to set default file creation context to %s"), quote (scontext)); @@ -994,7 +1036,8 @@ main (int argc, char **argv) int i; dest_info_init (&x); for (i = 0; i < n_files; i++) - if (! install_file_in_dir (file[i], target_directory, &x)) + if (! install_file_in_dir (file[i], target_directory, &x, + mkdir_and_install)) exit_status = EXIT_FAILURE; } } diff --git a/src/ioblksize.h b/src/ioblksize.h index 1ae93255..55aaeae1 100644 --- a/src/ioblksize.h +++ b/src/ioblksize.h @@ -1,5 +1,5 @@ /* I/O block size definitions for coreutils - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -20,7 +20,7 @@ #include "stat-size.h" -/* As of Jul 2011, 64KiB is determined to be the minimium +/* As of May 2014, 128KiB is determined to be the minimium blksize to best minimize system call overhead. This can be tested with this script: @@ -33,23 +33,29 @@ done With the results shown for these systems: - system-1 = 1.7GHz pentium-m with 400MHz DDR2 RAM, arch=i686 - system-2 = 2.1GHz i3-2310M with 1333MHz DDR3 RAM, arch=x86_64 - system-3 = 3.2GHz i7-970 with 1333MHz DDR3, arch=x86_64 + system #1: 1.7GHz pentium-m with 400MHz DDR2 RAM, arch=i686 + system #2: 2.1GHz i3-2310M with 1333MHz DDR3 RAM, arch=x86_64 + system #3: 3.2GHz i7-970 with 1333MHz DDR3, arch=x86_64 + system #4: 2.20GHz Xeon E5-2660 with 1333MHz DDR3, arch=x86_64 + system #5: 2.30GHz i7-3615QM with 1600MHz DDR3, arch=x86_64 + system #6: 1.30GHz i5-4250U with 1-channel 1600MHz DDR3, arch=x86_64 + system #7: 3.55GHz IBM,8231-E2B with 1066MHz DDR3, POWER7 revision 2.1 + + per-system transfer rate (GB/s) + blksize #1 #2 #3 #4 #5 #6 #7 + ------------------------------------------------------------------------ + 1024 .73 1.7 2.6 .64 1.0 2.5 1.3 + 2048 1.3 3.0 4.4 1.2 2.0 4.4 2.5 + 4096 2.4 5.1 6.5 2.3 3.7 7.4 4.8 + 8192 3.5 7.3 8.5 4.0 6.0 10.4 9.2 + 16384 3.9 9.4 10.1 6.3 8.3 13.3 16.8 + 32768 5.2 9.9 11.1 8.1 10.7 13.2 28.0 + 65536 5.3 11.2 12.0 10.6 12.8 16.1 41.4 + 131072 5.5 11.8 12.3 12.1 14.0 16.7 54.8 + 262144 5.7 11.6 12.5 12.3 14.7 16.4 40.0 + 524288 5.7 11.4 12.5 12.1 14.7 15.5 34.5 + 1048576 5.8 11.4 12.6 12.2 14.9 15.7 36.5 - blksize system-1 system-2 system-3 - --------------------------------------- - 1024 734 MB/s 1.7 GB/s 2.6 GB/s - 2048 1.3 GB/s 3.0 GB/s 4.4 GB/s - 4096 2.4 GB/s 5.1 GB/s 6.5 GB/s - 8192 3.5 GB/s 7.3 GB/s 8.5 GB/s - 16384 3.9 GB/s 9.4 GB/s 10.1 GB/s - 32768 5.2 GB/s 9.9 GB/s 11.1 GB/s - 65536 5.3 GB/s 11.2 GB/s 12.0 GB/s - 131072 5.5 GB/s 11.8 GB/s 12.3 GB/s - 262144 5.7 GB/s 11.6 GB/s 12.5 GB/s - 524288 5.7 GB/s 11.4 GB/s 12.5 GB/s - 1048576 5.8 GB/s 11.4 GB/s 12.6 GB/s Note that this is to minimize system call overhead. Other values may be appropriate to minimize file system @@ -57,14 +63,14 @@ the readahead setting is 128KiB which was read using: file="." - device=$(df -P --local "$file" | tail -n1 | cut -d' ' -f1) + device=$(df --output=source --local "$file" | tail -n1) echo $(( $(blockdev --getra $device) * 512 )) However there isn't a portable way to get the above. In the future we could use the above method if available and default to io_blksize() if not. */ -enum { IO_BUFSIZE = 64*1024 }; +enum { IO_BUFSIZE = 128*1024 }; static inline size_t io_blksize (struct stat sb) { @@ -1,5 +1,5 @@ /* join - join lines of two files on a common field - Copyright (C) 1991-2013 Free Software Foundation, Inc. + Copyright (C) 1991-2014 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 @@ -161,6 +161,7 @@ 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}, + {"zero-terminated", no_argument, NULL, 'z'}, {"header", no_argument, NULL, HEADER_LINE_OPTION}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, @@ -177,6 +178,9 @@ static bool ignore_case; join them without checking for ordering */ static bool join_header_lines; +/* The character marking end of line. Default to \n. */ +static char eolchar = '\n'; + void usage (int status) { @@ -213,6 +217,9 @@ by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.\n\ --header treat the first line in each file as field headers,\n\ print them without trying to pair them\n\ "), stdout); + fputs (_("\ + -z, --zero-terminated line delimiter is NUL, not newline\n\ +"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); fputs (_("\ @@ -445,7 +452,7 @@ get_line (FILE *fp, struct line **linep, int which) else line = init_linep (linep); - if (! readlinebuffer (&line->buf, fp)) + if (! readlinebuffer_delim (&line->buf, fp, eolchar)) { if (ferror (fp)) error (EXIT_FAILURE, errno, _("read error")); @@ -614,7 +621,7 @@ prjoin (struct line const *line1, struct line const *line2) break; putchar (output_separator); } - putchar ('\n'); + putchar (eolchar); } else { @@ -636,7 +643,7 @@ prjoin (struct line const *line1, struct line const *line2) prfields (line1, join_field_1, autocount_1); prfields (line2, join_field_2, autocount_2); - putchar ('\n'); + putchar (eolchar); } } @@ -1017,7 +1024,7 @@ main (int argc, char **argv) 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:", + while ((optc = getopt_long (argc, argv, "-a:e:i1:2:j:o:t:v:z", longopts, NULL)) != -1) { @@ -1107,6 +1114,10 @@ main (int argc, char **argv) } break; + case 'z': + eolchar = 0; + break; + case NOCHECK_ORDER_OPTION: check_input_order = CHECK_ORDER_DISABLED; break; @@ -1,5 +1,5 @@ /* kill -- send a signal to a process - Copyright (C) 2002-2013 Free Software Foundation, Inc. + Copyright (C) 2002-2014 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 @@ -306,7 +306,7 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } - return (list - ? list_signals (table, optind < argc ? argv + optind : NULL) - : send_signals (signum, argv + optind)); + exit (list + ? list_signals (table, optind < argc ? argv + optind : NULL) + : send_signals (signum, argv + optind)); } diff --git a/src/libstdbuf.c b/src/libstdbuf.c index ac7a1339..1281b9de 100644 --- a/src/libstdbuf.c +++ b/src/libstdbuf.c @@ -1,5 +1,5 @@ /* libstdbuf -- a shared lib to preload to setup stdio buffering for a command - Copyright (C) 2009-2013 Free Software Foundation, Inc. + Copyright (C) 2009-2014 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 @@ -127,7 +127,8 @@ apply_mode (FILE *stream, const char *mode) } } -__attribute__ ((constructor)) static void +/* Use __attribute to avoid elision of __attribute__ on SUNPRO_C etc. */ +static void __attribute ((constructor)) stdbuf (void) { char *e_mode = getenv ("_STDBUF_E"); @@ -1,5 +1,5 @@ /* link utility for GNU. - Copyright (C) 2001-2013 Free Software Foundation, Inc. + Copyright (C) 2001-2014 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 @@ -1,5 +1,5 @@ /* 'ln' program to create links between files. - Copyright (C) 1986-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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 @@ -103,8 +103,18 @@ static struct option const long_options[] = {NULL, 0, NULL, 0} }; +/* Return true when the passed ERR implies + that a file does not or could not exist. */ + +static bool +errno_nonexisting (int err) +{ + return err == ENOENT || err == ENAMETOOLONG || err == ENOTDIR || err == ELOOP; +} + + /* 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, + directory. But report an error 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. */ @@ -119,7 +129,7 @@ target_directory_operand (char const *file) (dereference_dest_dir_symlinks ? stat (file, &st) : lstat (file, &st)); int err = (stat_result == 0 ? 0 : errno); bool is_a_dir = !err && S_ISDIR (st.st_mode); - if (err && err != ENOENT) + if (err && ! errno_nonexisting (errno)) error (EXIT_FAILURE, err, _("failed to access %s"), quote (file)); if (is_a_dir < looks_like_a_dir) error (EXIT_FAILURE, err, _("target %s is not a directory"), quote (file)); @@ -132,22 +142,28 @@ target_directory_operand (char const *file) static char * convert_abs_rel (const char *from, const char *target) { - char *realtarget = canonicalize_filename_mode (target, CAN_MISSING); - char *realfrom = canonicalize_filename_mode (from, CAN_MISSING); - - /* Write to a PATH_MAX buffer. */ - char *relative_from = xmalloc (PATH_MAX); + /* Get dirname to generate paths relative to. We don't resolve + the full TARGET as the last component could be an existing symlink. */ + char *targetdir = dir_name (target); - /* Get dirname to generate paths relative to. */ - realtarget[dir_len (realtarget)] = '\0'; + char *realdest = canonicalize_filename_mode (targetdir, CAN_MISSING); + char *realfrom = canonicalize_filename_mode (from, CAN_MISSING); - if (!relpath (realfrom, realtarget, relative_from, PATH_MAX)) + char *relative_from = NULL; + if (realdest && realfrom) { - free (relative_from); - relative_from = NULL; + /* Write to a PATH_MAX buffer. */ + relative_from = xmalloc (PATH_MAX); + + if (!relpath (realfrom, realdest, relative_from, PATH_MAX)) + { + free (relative_from); + relative_from = NULL; + } } - free (realtarget); + free (targetdir); + free (realdest); free (realfrom); return relative_from ? relative_from : xstrdup (from); @@ -327,7 +343,8 @@ do_link (const char *source, const char *dest) { /* Right after creating a hard link, do this: (note dest name and source_stats, which are also the just-linked-destinations stats) */ - record_file (dest_set, dest, &source_stats); + if (! symbolic_link) + record_file (dest_set, dest, &source_stats); if (verbose) { diff --git a/src/local.mk b/src/local.mk index 982cd4da..c0d04d68 100644 --- a/src/local.mk +++ b/src/local.mk @@ -1,7 +1,7 @@ # Make coreutils programs. -*-Makefile-*- # This is included by the top-level Makefile.am. -## Copyright (C) 1990-2013 Free Software Foundation, Inc. +## Copyright (C) 1990-2014 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 @@ -37,8 +37,7 @@ pkglibexec_PROGRAMS = @pkglibexec_PROGRAMS@ # Needed by the testsuite. noinst_PROGRAMS = \ src/getlimits \ - src/make-prime-list \ - src/setuidgid + src/make-prime-list noinst_HEADERS = \ src/chown-core.h \ @@ -106,6 +105,9 @@ src_cksum_LDADD = $(LDADD) src_comm_LDADD = $(LDADD) src_nproc_LDADD = $(LDADD) src_cp_LDADD = $(LDADD) +if !SINGLE_BINARY +src_coreutils_LDADD = $(LDADD) +endif src_csplit_LDADD = $(LDADD) src_cut_LDADD = $(LDADD) src_date_LDADD = $(LDADD) @@ -151,6 +153,7 @@ src_mv_LDADD = $(LDADD) src_nice_LDADD = $(LDADD) src_nl_LDADD = $(LDADD) src_nohup_LDADD = $(LDADD) +src_numfmt_LDADD = $(LDADD) src_od_LDADD = $(LDADD) src_paste_LDADD = $(LDADD) src_pathchk_LDADD = $(LDADD) @@ -166,7 +169,6 @@ src_rm_LDADD = $(LDADD) src_rmdir_LDADD = $(LDADD) src_runcon_LDADD = $(LDADD) src_seq_LDADD = $(LDADD) -src_setuidgid_LDADD = $(LDADD) src_sha1sum_LDADD = $(LDADD) src_sha224sum_LDADD = $(LDADD) src_sha256sum_LDADD = $(LDADD) @@ -228,13 +230,21 @@ copy_ldadd += $(LIB_SELINUX) src_chcon_LDADD += $(LIB_SELINUX) src_ginstall_LDADD += $(LIB_SELINUX) src_id_LDADD += $(LIB_SELINUX) +src_id_LDADD += $(LIB_SMACK) src_ls_LDADD += $(LIB_SELINUX) +src_ls_LDADD += $(LIB_SMACK) src_mkdir_LDADD += $(LIB_SELINUX) +src_mkdir_LDADD += $(LIB_SMACK) src_mkfifo_LDADD += $(LIB_SELINUX) +src_mkfifo_LDADD += $(LIB_SMACK) src_mknod_LDADD += $(LIB_SELINUX) +src_mknod_LDADD += $(LIB_SMACK) src_runcon_LDADD += $(LIB_SELINUX) src_stat_LDADD += $(LIB_SELINUX) +# for nvlist_lookup_uint64_array +src_stat_LDADD += $(LIB_NVPAIR) + # for gettime, settime, utimecmp, utimens copy_ldadd += $(LIB_CLOCK_GETTIME) src_date_LDADD += $(LIB_CLOCK_GETTIME) @@ -288,6 +298,15 @@ src_stdbuf_LDADD += $(LIBICONV) src_timeout_LDADD += $(LIBICONV) src_truncate_LDADD += $(LIBICONV) +# for libcrypto hash routines +src_md5sum_LDADD += $(LIB_CRYPTO) +src_sort_LDADD += $(LIB_CRYPTO) +src_sha1sum_LDADD += $(LIB_CRYPTO) +src_sha224sum_LDADD += $(LIB_CRYPTO) +src_sha256sum_LDADD += $(LIB_CRYPTO) +src_sha384sum_LDADD += $(LIB_CRYPTO) +src_sha512sum_LDADD += $(LIB_CRYPTO) + # for canon_host src_pinky_LDADD += $(GETADDRINFO_LIB) src_who_LDADD += $(GETADDRINFO_LIB) @@ -307,6 +326,10 @@ RELEASE_YEAR = \ `sed -n '/.*COPYRIGHT_YEAR = \([0-9][0-9][0-9][0-9]\) };/s//\1/p' \ $(top_srcdir)/lib/version-etc.c` +selinux_sources = \ + src/selinux.c \ + src/selinux.h + copy_sources = \ src/copy.c \ src/cp-hash.c \ @@ -318,12 +341,16 @@ copy_sources = \ # to install before applying any user-specified name transformations. transform = s/ginstall/install/; $(program_transform_name) -src_ginstall_SOURCES = src/install.c src/prog-fprintf.c $(copy_sources) +src_ginstall_SOURCES = src/install.c src/prog-fprintf.c $(copy_sources) \ + $(selinux_sources) # This is for the '[' program. Automake transliterates '[' and '/' to '_'. src___SOURCES = src/lbracket.c -src_cp_SOURCES = src/cp.c $(copy_sources) +nodist_src_coreutils_SOURCES = src/coreutils.h +src_coreutils_SOURCES = src/coreutils.c + +src_cp_SOURCES = src/cp.c $(copy_sources) $(selinux_sources) src_dir_SOURCES = src/ls.c src/ls-dir.c src_vdir_SOURCES = src/ls.c src/ls-vdir.c src_id_SOURCES = src/id.c src/group-list.c @@ -336,12 +363,15 @@ src_kill_SOURCES = src/kill.c src/operand2sig.c src_realpath_SOURCES = src/realpath.c src/relpath.c src/relpath.h src_timeout_SOURCES = src/timeout.c src/operand2sig.c -src_mv_SOURCES = src/mv.c src/remove.c $(copy_sources) +src_mv_SOURCES = src/mv.c src/remove.c $(copy_sources) $(selinux_sources) src_rm_SOURCES = src/rm.c src/remove.c -src_mkdir_SOURCES = src/mkdir.c src/prog-fprintf.c +src_mkdir_SOURCES = src/mkdir.c src/prog-fprintf.c $(selinux_sources) src_rmdir_SOURCES = src/rmdir.c src/prog-fprintf.c +src_mkfifo_SOURCES = src/mkfifo.c $(selinux_sources) +src_mknod_SOURCES = src/mknod.c $(selinux_sources) + src_df_SOURCES = src/df.c src/find-mount-point.c src_stat_SOURCES = src/stat.c src/find-mount-point.c @@ -364,7 +394,7 @@ src_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 -src_libstdbuf_so_LDADD = +src_libstdbuf_so_LDADD = $(LIBINTL) # Note libstdbuf is only compiled if GCC is available # (as per the check in configure.ac), so these flags should be available. @@ -372,6 +402,46 @@ src_libstdbuf_so_LDADD = src_libstdbuf_so_LDFLAGS = -shared src_libstdbuf_so_CFLAGS = -fPIC $(AM_CFLAGS) +BUILT_SOURCES += src/coreutils.h +if SINGLE_BINARY +# Single binary dependencies +src_coreutils_CFLAGS = -DSINGLE_BINARY $(AM_CFLAGS) +#src_coreutils_LDFLAGS = $(AM_LDFLAGS) +src_coreutils_LDADD = $(single_binary_deps) $(LDADD) $(single_binary_libs) +src_coreutils_DEPENDENCIES = $(LDADD) $(single_binary_deps) + +include $(top_srcdir)/src/single-binary.mk + +# Creates symlinks or shebangs to the installed programs when building +# coreutils single binary. +EXTRA_src_coreutils_DEPENDENCIES = src/coreutils_$(single_binary_install_type) +endif SINGLE_BINARY + +CLEANFILES += src/coreutils_symlinks +src/coreutils_symlinks: Makefile + $(AM_V_GEN)touch $@ + $(AM_V_at)for i in $(single_binary_progs); do \ + rm -f src/$$i$(EXEEXT) || exit $$?; \ + $(LN_S) -s coreutils$(EXEEXT) src/$$i$(EXEEXT) || exit $$?; \ + done + +CLEANFILES += src/coreutils_shebangs +src/coreutils_shebangs: Makefile + $(AM_V_GEN)touch $@ + $(AM_V_at)for i in $(single_binary_progs); do \ + rm -f src/$$i$(EXEEXT) || exit $$?; \ + printf '#!%s --coreutils-prog-shebang=%s\n' \ + $(abs_top_builddir)/src/coreutils$(EXEEXT) $$i \ + >src/$$i$(EXEEXT) || exit $$?; \ + chmod a+x,a-w src/$$i$(EXEEXT) || exit $$?; \ + done + +clean-local: + $(AM_V_at)for i in $(single_binary_progs); do \ + rm -f src/$$i$(EXEEXT) || exit $$?; \ + done + + BUILT_SOURCES += src/dircolors.h src/dircolors.h: src/dcgen src/dircolors.hin $(AM_V_GEN)rm -f $@ $@-t @@ -403,8 +473,8 @@ AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = src/false src/test # Also compare against /usr/include/linux/magic.h .PHONY: src/fs-magic-compare src/fs-magic-compare: src/fs-magic src/fs-kernel-magic src/fs-def - join -v1 -t@ src/fs-magic src/fs-def - join -v1 -t@ src/fs-kernel-magic src/fs-def + @join -v1 -t@ src/fs-magic src/fs-def + @join -v1 -t@ src/fs-kernel-magic src/fs-def CLEANFILES += src/fs-def src/fs-def: src/fs.h @@ -434,7 +504,7 @@ fs_normalize_perl_subst = \ CLEANFILES += src/fs-magic src/fs-magic: Makefile - man statfs \ + @MANPAGER= man statfs \ |perl -ne '/File system types:/.../Nobody kno/ and print' \ |grep 0x | perl -p \ $(fs_normalize_perl_subst) \ @@ -442,13 +512,23 @@ src/fs-magic: Makefile | $(ASSORT) \ > $@-t && mv $@-t $@ +DISTCLEANFILES += src/fs-latest-magic.h +# This rule currently gets the latest header, but probably isn't general +# enough to enable by default. +# @kgit='https://git.kernel.org/cgit/linux/kernel/git'; \ +# wget -q $$kgit/torvalds/linux.git/plain/include/uapi/linux/magic.h \ +# -O $@ +src/fs-latest-magic.h: + @touch $@ + CLEANFILES += src/fs-kernel-magic -src/fs-kernel-magic: Makefile - perl -ne '/^#define.*0x/ and print' /usr/include/linux/magic.h \ +src/fs-kernel-magic: Makefile src/fs-latest-magic.h + @perl -ne '/^#define.*0x/ and print' \ + /usr/include/linux/magic.h src/fs-latest-magic.h \ | perl -p \ $(fs_normalize_perl_subst) \ | grep -Ev 'S_MAGIC_EXT[34]|STACK_END' \ - | $(ASSORT) \ + | $(ASSORT) -u \ > $@-t && mv $@-t $@ BUILT_SOURCES += src/fs-is-local.h @@ -482,6 +562,22 @@ src/version.h: Makefile $(AM_V_at)chmod a-w $@t $(AM_V_at)mv $@t $@ +# Generates a list of macro invocations like: +# SINGLE_BINARY_PROGRAM(program_name_str, main_name) +# once for each program list on $(single_binary_progs). Note that +# for [ the macro invocation is: +# SINGLE_BINARY_PROGRAM("[", _) +DISTCLEANFILES += src/coreutils.h +src/coreutils.h: Makefile + $(AM_V_GEN)rm -f $@ + $(AM_V_at)for prog in $(single_binary_progs); do \ + prog=`basename $$prog`; \ + main=`echo $$prog | tr '[' '_'`; \ + echo "SINGLE_BINARY_PROGRAM(\"$$prog\", $$main)"; \ + done | sort > $@t + $(AM_V_at)chmod a-w $@t + $(AM_V_at)mv $@t $@ + DISTCLEANFILES += src/version.c src/version.h MAINTAINERCLEANFILES += $(BUILT_SOURCES) diff --git a/src/logname.c b/src/logname.c index b655e4a2..6afa1b50 100644 --- a/src/logname.c +++ b/src/logname.c @@ -1,5 +1,5 @@ /* logname -- print user's login name - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 diff --git a/src/longlong.h b/src/longlong.h index 46816429..25116130 100644 --- a/src/longlong.h +++ b/src/longlong.h @@ -1,6 +1,6 @@ /* longlong.h -- definitions for mixed size 32/64 bit arithmetic. -Copyright 1991-2013 Free Software Foundation, Inc. +Copyright 1991-2014 Free Software Foundation, Inc. This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free @@ -138,30 +138,30 @@ along with this file. If not, see http://www.gnu.org/licenses/. */ or want. */ #ifdef _LONG_LONG_LIMB -#define count_leading_zeros_gcc_clz(count,x) \ - do { \ - ASSERT ((x) != 0); \ - (count) = __builtin_clzll (x); \ +#define count_leading_zeros_gcc_clz(count,x) \ + do { \ + ASSERT ((x) != 0); \ + (count) = __builtin_clzll (x); \ } while (0) #else -#define count_leading_zeros_gcc_clz(count,x) \ - do { \ - ASSERT ((x) != 0); \ - (count) = __builtin_clzl (x); \ +#define count_leading_zeros_gcc_clz(count,x) \ + do { \ + ASSERT ((x) != 0); \ + (count) = __builtin_clzl (x); \ } while (0) #endif #ifdef _LONG_LONG_LIMB -#define count_trailing_zeros_gcc_ctz(count,x) \ - do { \ - ASSERT ((x) != 0); \ - (count) = __builtin_ctzll (x); \ +#define count_trailing_zeros_gcc_ctz(count,x) \ + do { \ + ASSERT ((x) != 0); \ + (count) = __builtin_ctzll (x); \ } while (0) #else -#define count_trailing_zeros_gcc_ctz(count,x) \ - do { \ - ASSERT ((x) != 0); \ - (count) = __builtin_ctzl (x); \ +#define count_trailing_zeros_gcc_ctz(count,x) \ + do { \ + ASSERT ((x) != 0); \ + (count) = __builtin_ctzl (x); \ } while (0) #endif @@ -222,27 +222,27 @@ along with this file. If not, see http://www.gnu.org/licenses/. */ __asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X)) #endif /* clz/ctz using cix */ -#if ! defined (count_leading_zeros) \ +#if ! defined (count_leading_zeros) \ && defined (__GNUC__) && ! defined (LONGLONG_STANDALONE) /* ALPHA_CMPBGE_0 gives "cmpbge $31,src,dst", ie. test src bytes == 0. "$31" is written explicitly in the asm, since an "r" constraint won't select reg 31. There seems no need to worry about "r31" syntax for cray, - since gcc itself (pre-release 3.4) emits just $31 in various places. */ -#define ALPHA_CMPBGE_0(dst, src) \ + since gcc itself (pre-release 3.4) emits just $31 in various places. */ +#define ALPHA_CMPBGE_0(dst, src) \ do { asm ("cmpbge $31, %1, %0" : "=r" (dst) : "r" (src)); } while (0) /* Zero bytes are turned into bits with cmpbge, a __clz_tab lookup counts them, locating the highest non-zero byte. A second __clz_tab lookup counts the leading zero bits in that byte, giving the result. */ -#define count_leading_zeros(count, x) \ - do { \ - UWtype __clz__b, __clz__c, __clz__x = (x); \ - ALPHA_CMPBGE_0 (__clz__b, __clz__x); /* zero bytes */ \ - __clz__b = __clz_tab [(__clz__b >> 1) ^ 0x7F]; /* 8 to 1 byte */ \ - __clz__b = __clz__b * 8 - 7; /* 57 to 1 shift */ \ - __clz__x >>= __clz__b; \ - __clz__c = __clz_tab [__clz__x]; /* 8 to 1 bit */ \ - __clz__b = 65 - __clz__b; \ - (count) = __clz__b - __clz__c; \ +#define count_leading_zeros(count, x) \ + do { \ + UWtype __clz__b, __clz__c, __clz__x = (x); \ + ALPHA_CMPBGE_0 (__clz__b, __clz__x); /* zero bytes */ \ + __clz__b = __clz_tab [(__clz__b >> 1) ^ 0x7F]; /* 8 to 1 byte */ \ + __clz__b = __clz__b * 8 - 7; /* 57 to 1 shift */ \ + __clz__x >>= __clz__b; \ + __clz__c = __clz_tab [__clz__x]; /* 8 to 1 bit */ \ + __clz__b = 65 - __clz__b; \ + (count) = __clz__b - __clz__c; \ } while (0) #define COUNT_LEADING_ZEROS_NEED_CLZ_TAB #endif /* clz using cmpbge */ @@ -298,14 +298,14 @@ long __MPN(count_leading_zeros) (UDItype); code using "al<bl" arithmetically comes out making an actual 0 or 1 in a register, which takes an extra cycle. */ #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - do { \ - UWtype __x; \ - __x = (al) - (bl); \ - if ((al) < (bl)) \ - (sh) = (ah) - (bh) - 1; \ - else \ - (sh) = (ah) - (bh); \ - (sl) = __x; \ + do { \ + UWtype __x; \ + __x = (al) - (bl); \ + if ((al) < (bl)) \ + (sh) = (ah) - (bh) - 1; \ + else \ + (sh) = (ah) - (bh); \ + (sl) = __x; \ } while (0) #if defined (__GNUC__) && ! defined (__INTEL_COMPILER) /* Do both product parts in assembly, since that gives better code with @@ -423,7 +423,7 @@ long __MPN(count_leading_zeros) (UDItype); "rIJ" ((USItype) (bl))) #endif -#if defined (__arm__) && W_TYPE_SIZE == 32 +#if defined (__arm__) && !defined (__thumb__) && W_TYPE_SIZE == 32 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("adds\t%1, %4, %5\n\tadc\t%0, %2, %3" \ : "=r" (sh), "=&r" (sl) \ @@ -513,7 +513,7 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); #define UDIV_TIME 200 #endif /* LONGLONG_STANDALONE */ #endif -/* This is a bizarre test, but GCC doesn't define useful common symbol. */ +/* This is a bizarre test, but GCC doesn't define any useful common symbol. */ #if defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5T__) || \ defined (__ARM_ARCH_5E__) || defined (__ARM_ARCH_5TE__)|| \ defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) || \ @@ -529,23 +529,16 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); #endif /* __arm__ */ #if defined (__aarch64__) && W_TYPE_SIZE == 64 +/* FIXME: Extend the immediate range for the low word by using both + ADDS and SUBS, since they set carry in the same way. */ #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ - __asm__ ("adds\t%1, %4, %5\n\tadc\t%0, %2, %3" \ + __asm__ ("adds\t%1, %x4, %5\n\tadc\t%0, %x2, %x3" \ : "=r" (sh), "=&r" (sl) \ - : "r" (ah), "rZ" (bh), "%r" (al), "rI" (bl) __CLOBBER_CC) + : "rZ" (ah), "rZ" (bh), "%r" (al), "rI" (bl) __CLOBBER_CC) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - do { \ - if (__builtin_constant_p (bl)) \ - { \ - __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3" \ - : "=r" (sh), "=&r" (sl) \ - : "r" (ah), "r" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \ - } \ - else /* only bh might be a constant */ \ - __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3" \ - : "=r" (sh), "=&r" (sl) \ - : "r" (ah), "rZ" (bh), "r" (al), "rI" (bl) __CLOBBER_CC);\ - } while (0) + __asm__ ("subs\t%1, %x4, %5\n\tsbc\t%0, %x2, %x3" \ + : "=r,r" (sh), "=&r,&r" (sl) \ + : "rZ,rZ" (ah), "rZ,rZ" (bh), "r,Z" (al), "rI,r" (bl) __CLOBBER_CC) #define umul_ppmm(ph, pl, m0, m1) \ do { \ UDItype __m0 = (m0), __m1 = (m1); \ @@ -554,6 +547,8 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); } while (0) #define count_leading_zeros(count, x) \ __asm__ ("clz\t%0, %1" : "=r" (count) : "r" (x)) +#define count_trailing_zeros(count, x) \ + __asm__ ("rbit\t%0, %1\n\tclz\t%0, %0" : "=r" (count) : "r" (x)) #define COUNT_LEADING_ZEROS_0 64 #endif /* __aarch64__ */ @@ -952,7 +947,7 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); being 1 code byte smaller. "31-__cbtmp" is a workaround, probably at the cost of one extra instruction. Do this for "i386" too, since that means generic x86. */ -#if ! defined (count_leading_zeros) && __GNUC__ < 3 \ +#if ! defined (count_leading_zeros) && __GNUC__ < 3 \ && (HAVE_HOST_CPU_i386 \ || HAVE_HOST_CPU_i686 \ || HAVE_HOST_CPU_pentiumpro \ @@ -1033,7 +1028,7 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); ASSERT ((x) != 0); \ __asm__ ("bsfq %1,%q0" : "=r" (count) : "rm" ((UDItype)(x))); \ } while (0) -#endif /* x86_64 */ +#endif /* __amd64__ */ #if defined (__i860__) && W_TYPE_SIZE == 32 #define rshift_rhlc(r,h,l,c) \ @@ -1162,7 +1157,7 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); || defined (__mc68030__) || defined (mc68030) \ || defined (__mc68040__) || defined (mc68040) \ || defined (__mc68060__) || defined (mc68060) \ - || defined (__NeXT__)) \ + || defined (__NeXT__)) \ && ! defined (__mcpu32__) #define count_leading_zeros(count, x) \ __asm__ ("bfffo %1{%b2:%b2},%0" \ @@ -1315,42 +1310,42 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); the system vendor compilers. (Is that vendor compilers with inline asm, or what?) */ -#if (HAVE_HOST_CPU_FAMILY_power || HAVE_HOST_CPU_FAMILY_powerpc) \ +#if (HAVE_HOST_CPU_FAMILY_power || HAVE_HOST_CPU_FAMILY_powerpc) \ && W_TYPE_SIZE == 32 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ do { \ if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ - : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl)); \ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ - __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ - : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl)); \ else \ - __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ } while (0) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ if (__builtin_constant_p (ah) && (ah) == 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ else \ - __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ } while (0) #define count_leading_zeros(count, x) \ - __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x)) + __asm__ ("cntlzw %0,%1" : "=r" (count) : "r" (x)) #define COUNT_LEADING_ZEROS_0 32 #if HAVE_HOST_CPU_FAMILY_powerpc #if __GMP_GNUC_PREREQ (4,4) @@ -1398,55 +1393,55 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ do { \ if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ - : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl)); \ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ - __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ - : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl)); \ else \ - __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ } while (0) /* We use "*rI" for the constant operand here, since with just "I", gcc barfs. This might seem strange, but gcc folds away the dead code late. */ #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - do { \ - if (__builtin_constant_p (bl) && bl > -0x8000 && bl <= 0x8000) { \ - if (__builtin_constant_p (ah) && (ah) == 0) \ - __asm__ ("{ai|addic} %1,%3,%4\n\t{sfze|subfze} %0,%2" \ + do { \ + if (__builtin_constant_p (bl) && bl > -0x8000 && bl <= 0x8000) { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("addic %1,%3,%4\n\tsubfze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "*rI" (-bl)); \ - else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ - __asm__ ("{ai|addic} %1,%3,%4\n\t{sfme|subfme} %0,%2" \ + else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ + __asm__ ("addic %1,%3,%4\n\tsubfme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "*rI" (-bl)); \ - else if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{ai|addic} %1,%3,%4\n\t{ame|addme} %0,%2" \ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("addic %1,%3,%4\n\taddme %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "*rI" (-bl)); \ - else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ - __asm__ ("{ai|addic} %1,%3,%4\n\t{aze|addze} %0,%2" \ + else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ + __asm__ ("addic %1,%3,%4\n\taddze %0,%2" \ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "*rI" (-bl)); \ - else \ - __asm__ ("{ai|addic} %1,%4,%5\n\t{sfe|subfe} %0,%3,%2" \ - : "=r" (sh), "=&r" (sl) \ - : "r" (ah), "r" (bh), "rI" (al), "*rI" (-bl)); \ - } else { \ - if (__builtin_constant_p (ah) && (ah) == 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ - : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl)); \ - else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ - : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl)); \ - else if (__builtin_constant_p (bh) && (bh) == 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ - : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl)); \ - else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ - __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ - : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl)); \ - else \ - __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ - : "=r" (sh), "=&r" (sl) \ - : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ - } \ + else \ + __asm__ ("addic %1,%4,%5\n\tsubfe %0,%3,%2" \ + : "=r" (sh), "=&r" (sl) \ + : "r" (ah), "r" (bh), "rI" (al), "*rI" (-bl)); \ + } else { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl)); \ + else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ + __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl)); \ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl)); \ + else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ + __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl)); \ + else \ + __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2" \ + : "=r" (sh), "=&r" (sl) \ + : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ + } \ } while (0) #endif /* ! _LONG_LONG_LIMB */ #define count_leading_zeros(count, x) \ @@ -1760,12 +1755,31 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); " subccc %r6,%7,%%g0\n" \ " subc %r2,%3,%0" \ : "=r" (sh), "=&r" (sl) \ - : "rJ" (ah), "rI" (bh), "rJ" (al), "rI" (bl), \ + : "rJ" (ah), "rI" (bh), "rJ" (al), "rI" (bl), \ "rJ" ((al) >> 32), "rI" ((bl) >> 32) \ __CLOBBER_CC) +#if __VIS__ >= 0x300 +#undef add_ssaaaa +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ( \ + "addcc %r4, %5, %1\n" \ + " addxc %r2, %r3, %0" \ + : "=r" (sh), "=&r" (sl) \ + : "rJ" (ah), "rJ" (bh), "%rJ" (al), "rI" (bl) __CLOBBER_CC) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + UDItype __m0 = (m0), __m1 = (m1); \ + (pl) = __m0 * __m1; \ + __asm__ ("umulxhi\t%2, %1, %0" \ + : "=r" (ph) \ + : "%r" (__m0), "r" (__m1)); \ + } while (0) +#define count_leading_zeros(count, x) \ + __asm__ ("lzd\t%1,%0" : "=r" (count) : "r" (x)) +#endif #endif -#if defined (__vax__) && W_TYPE_SIZE == 32 +#if (defined (__vax) || defined (__vax__)) && W_TYPE_SIZE == 32 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("addl2 %5,%1\n\tadwc %3,%0" \ : "=g" (sh), "=&g" (sl) \ @@ -1805,7 +1819,7 @@ extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype); : "g" ((USItype) (x))); \ } while (0) #endif -#endif /* __vax__ */ +#endif /* vax */ #if defined (__z8000__) && W_TYPE_SIZE == 16 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ @@ -1866,11 +1880,11 @@ extern UWtype mpn_umul_ppmm (UWtype *, UWtype, UWtype); #if ! defined (umul_ppmm) && HAVE_NATIVE_mpn_umul_ppmm \ && ! defined (LONGLONG_STANDALONE) -#define umul_ppmm(wh, wl, u, v) \ - do { \ - UWtype __umul_ppmm__p0; \ - (wh) = mpn_umul_ppmm (&__umul_ppmm__p0, (UWtype) (u), (UWtype) (v)); \ - (wl) = __umul_ppmm__p0; \ +#define umul_ppmm(wh, wl, u, v) \ + do { \ + UWtype __umul_ppmm__p0; \ + (wh) = mpn_umul_ppmm (&__umul_ppmm__p0, (UWtype) (u), (UWtype) (v));\ + (wl) = __umul_ppmm__p0; \ } while (0) #endif @@ -1879,11 +1893,11 @@ extern UWtype mpn_umul_ppmm_r (UWtype, UWtype, UWtype *); #if ! defined (umul_ppmm) && HAVE_NATIVE_mpn_umul_ppmm_r \ && ! defined (LONGLONG_STANDALONE) -#define umul_ppmm(wh, wl, u, v) \ - do { \ - UWtype __umul_ppmm__p0; \ - (wh) = mpn_umul_ppmm_r ((UWtype) (u), (UWtype) (v), &__umul_ppmm__p0); \ - (wl) = __umul_ppmm__p0; \ +#define umul_ppmm(wh, wl, u, v) \ + do { \ + UWtype __umul_p0; \ + (wh) = mpn_umul_ppmm_r ((UWtype) (u), (UWtype) (v), &__umul_p0); \ + (wl) = __umul_p0; \ } while (0) #endif @@ -1894,10 +1908,10 @@ extern UWtype mpn_udiv_qrnnd (UWtype *, UWtype, UWtype, UWtype); && ! defined (LONGLONG_STANDALONE) #define udiv_qrnnd(q, r, n1, n0, d) \ do { \ - UWtype __udiv_qrnnd__r; \ - (q) = mpn_udiv_qrnnd (&__udiv_qrnnd__r, \ + UWtype __udiv_qrnnd_r; \ + (q) = mpn_udiv_qrnnd (&__udiv_qrnnd_r, \ (UWtype) (n1), (UWtype) (n0), (UWtype) d); \ - (r) = __udiv_qrnnd__r; \ + (r) = __udiv_qrnnd_r; \ } while (0) #endif @@ -1908,10 +1922,10 @@ extern UWtype mpn_udiv_qrnnd_r (UWtype, UWtype, UWtype, UWtype *); && ! defined (LONGLONG_STANDALONE) #define udiv_qrnnd(q, r, n1, n0, d) \ do { \ - UWtype __udiv_qrnnd__r; \ + UWtype __udiv_qrnnd_r; \ (q) = mpn_udiv_qrnnd_r ((UWtype) (n1), (UWtype) (n0), (UWtype) d, \ - &__udiv_qrnnd__r); \ - (r) = __udiv_qrnnd__r; \ + &__udiv_qrnnd_r); \ + (r) = __udiv_qrnnd_r; \ } while (0) #endif @@ -1933,7 +1947,7 @@ extern UWtype mpn_udiv_qrnnd_r (UWtype, UWtype, UWtype, UWtype *); do { \ UWtype __x; \ __x = (al) - (bl); \ - (sh) = (ah) - (bh) - ((al) < (bl)); \ + (sh) = (ah) - (bh) - ((al) < (bl)); \ (sl) = __x; \ } while (0) #endif @@ -1,5 +1,5 @@ /* 'dir', 'vdir' and 'ls' directory listing programs for GNU. - Copyright (C) 1985-2013 Free Software Foundation, Inc. + Copyright (C) 1985-2014 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 @@ -101,12 +101,14 @@ #include "obstack.h" #include "quote.h" #include "quotearg.h" +#include "smack.h" #include "stat-size.h" #include "stat-time.h" #include "strftime.h" #include "xstrtol.h" #include "areadlink.h" #include "mbsalign.h" +#include "dircolors.h" /* Include <sys/capability.h> last to avoid a clash of <sys/types.h> include guards with some premature versions of libcap. @@ -185,7 +187,7 @@ verify (sizeof filetype_letter - 1 == arg_directory + 1); enum acl_type { ACL_T_NONE, - ACL_T_SELINUX_ONLY, + ACL_T_LSM_CONTEXT_ONLY, ACL_T_YES }; @@ -205,8 +207,8 @@ struct fileinfo zero. */ mode_t linkmode; - /* SELinux security context. */ - security_context_t scontext; + /* security context. */ + char *scontext; bool stat_ok; @@ -215,7 +217,7 @@ struct fileinfo bool linkok; /* For long listings, true if the file has an access control list, - or an SELinux security context. */ + or a security context. */ enum acl_type acl_type; /* For color listings, true if a regular file has capability info. */ @@ -962,25 +964,33 @@ static struct obstack subdired_obstack; 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) +static void +dev_ino_push (dev_t dev, ino_t ino) +{ + void *vdi; + struct dev_ino *di; + int dev_ino_size = sizeof *di; + obstack_blank (&dev_ino_obstack, dev_ino_size); + vdi = obstack_next_free (&dev_ino_obstack); + di = vdi; + di--; + di->st_dev = dev; + di->st_ino = ino; +} /* 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); + void *vdi; + struct dev_ino *di; + int dev_ino_size = sizeof *di; + assert (dev_ino_size <= obstack_object_size (&dev_ino_obstack)); + obstack_blank (&dev_ino_obstack, -dev_ino_size); + vdi = obstack_next_free (&dev_ino_obstack); + di = vdi; + return *di; } /* Note the use commented out below: @@ -1978,7 +1988,7 @@ decode_switches (int argc, char **argv) if (file_type <= indicator_style) { char const *p; - for (p = "*=>@|" + indicator_style - file_type; *p; p++) + for (p = &"*=>@|"[indicator_style - file_type]; *p; p++) set_char_quoting (filename_quoting_options, *p, 1); } @@ -2317,6 +2327,30 @@ enum parse_state PS_FAIL }; + +/* Check if the content of TERM is a valid name in dircolors. */ + +static bool +known_term_type (void) +{ + char const *term = getenv ("TERM"); + if (! term || ! *term) + return false; + + char const *line = G_line; + while (line - G_line < sizeof (G_line)) + { + if (STRNCMP_LIT (line, "TERM ") == 0) + { + if (STREQ (term, line + 5)) + return true; + } + line += strlen (line) + 1; + } + + return false; +} + static void parse_ls_color (void) { @@ -2327,7 +2361,16 @@ parse_ls_color (void) struct color_ext_type *ext; /* Extension we are working on */ if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0') - return; + { + /* LS_COLORS takes precedence, but if that's not set then + honor the COLORTERM and TERM env variables so that + we only go with the internal ANSI color codes if the + former is non empty or the latter is set to a known value. */ + char const *colorterm = getenv ("COLORTERM"); + if (! (colorterm && *colorterm) && ! known_term_type ()) + print_with_color = false; + return; + } ext = NULL; strcpy (label, "??"); @@ -2542,7 +2585,7 @@ print_dir (char const *name, char const *realname, bool command_line_arg) return; } - DEV_INO_PUSH (dir_stat.st_dev, dir_stat.st_ino); + dev_ino_push (dir_stat.st_dev, dir_stat.st_ino); } if (recursive || print_dir_name) @@ -2638,7 +2681,7 @@ print_dir (char const *name, char const *realname, bool command_line_arg) contents listed rather than being mentioned here as files. */ if (recursive) - extract_dirs_from_files (name, command_line_arg); + extract_dirs_from_files (name, false); if (format == long_format || print_block_size) { @@ -2734,7 +2777,7 @@ has_capability (char const *name) } #else static bool -has_capability (char const *name ATTRIBUTE_UNUSED) +has_capability (char const *name _GL_UNUSED) { errno = ENOTSUP; return false; @@ -2749,7 +2792,12 @@ free_ent (struct fileinfo *f) free (f->name); free (f->linkname); if (f->scontext != UNKNOWN_SECURITY_CONTEXT) - freecon (f->scontext); + { + if (is_smack_enabled ()) + free (f->scontext); + else + freecon (f->scontext); + } } /* Empty the table of files. */ @@ -2790,8 +2838,8 @@ errno_unsupported (int err) } /* Cache *getfilecon failure, when it's trivial to do so. - Like getfilecon/lgetfilecon, but when F's st_dev says it's on a known- - SELinux-challenged file system, fail with ENOTSUP immediately. */ + Like getfilecon/lgetfilecon, but when F's st_dev says it's doesn't + support getting the security context, fail with ENOTSUP immediately. */ static int getfilecon_cache (char const *file, struct fileinfo *f, bool deref) { @@ -2804,9 +2852,16 @@ getfilecon_cache (char const *file, struct fileinfo *f, bool deref) errno = ENOTSUP; return -1; } - int r = (deref - ? getfilecon (file, &f->scontext) - : lgetfilecon (file, &f->scontext)); + int r = 0; +#ifdef HAVE_SMACK + if (is_smack_enabled ()) + r = smack_new_label_from_path (file, "security.SMACK64", deref, + &f->scontext); + else +#endif + r = (deref + ? getfilecon (file, &f->scontext) + : lgetfilecon (file, &f->scontext)); if (r < 0 && errno_unsupported (errno)) unsupported_device = f->stat.st_dev; return r; @@ -2997,13 +3052,18 @@ gobble_file (char const *name, enum filetype type, ino_t inode, if (format == long_format || print_scontext) { - bool have_selinux = false; + bool have_scontext = false; bool have_acl = false; int attr_len = getfilecon_cache (absolute_name, f, do_deref); err = (attr_len < 0); if (err == 0) - have_selinux = ! STREQ ("unlabeled", f->scontext); + { + if (is_smack_enabled ()) + have_scontext = ! STREQ ("_", f->scontext); + else + have_scontext = ! STREQ ("unlabeled", f->scontext); + } else { f->scontext = UNKNOWN_SECURITY_CONTEXT; @@ -3023,10 +3083,10 @@ gobble_file (char const *name, enum filetype type, ino_t inode, have_acl = (0 < n); } - f->acl_type = (!have_selinux && !have_acl + f->acl_type = (!have_scontext && !have_acl ? ACL_T_NONE - : (have_selinux && !have_acl - ? ACL_T_SELINUX_ONLY + : (have_scontext && !have_acl + ? ACL_T_LSM_CONTEXT_ONLY : ACL_T_YES)); any_has_acl |= f->acl_type != ACL_T_NONE; @@ -3773,7 +3833,7 @@ print_long_format (const struct fileinfo *f) 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. */ + file in this directory has an ACL or security context. */ if (f->stat_ok) filemodestring (&f->stat, modebuf); else @@ -3784,7 +3844,7 @@ print_long_format (const struct fileinfo *f) } if (! any_has_acl) modebuf[10] = '\0'; - else if (f->acl_type == ACL_T_SELINUX_ONLY) + else if (f->acl_type == ACL_T_LSM_CONTEXT_ONLY) modebuf[10] = '.'; else if (f->acl_type == ACL_T_YES) modebuf[10] = '+'; @@ -4732,21 +4792,21 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\n\ -b, --escape print C-style escapes for nongraphic characters\n\ "), stdout); fputs (_("\ - --block-size=SIZE scale sizes by SIZE before printing them. E.g.,\n\ + --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ '--block-size=M' prints sizes in units of\n\ - 1,048,576 bytes. See SIZE format below.\n\ + 1,048,576 bytes; 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\ + modification of file status information);\n\ + with -l: show ctime and sort by name;\n\ otherwise: sort by ctime, newest first\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\ + --color[=WHEN] colorize the output; WHEN can be 'never', 'auto',\ +\n\ + or 'always' (the default); more info below\n\ + -d, --directory list directories themselves, not their contents\n\ -D, --dired generate output designed for Emacs' dired mode\n\ "), stdout); fputs (_("\ @@ -4762,13 +4822,13 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\n\ "), stdout); fputs (_("\ --group-directories-first\n\ - group directories before files.\n\ - augment with a --sort option, but any\n\ + group directories before files;\n\ + can be augmented 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\ + -h, --human-readable with -l and/or -s, print human readable sizes\n\ (e.g., 1K 234M 2G)\n\ --si likewise, but use powers of 1000 not 1024\n\ "), stdout); @@ -4777,7 +4837,7 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\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\ + that points to a directory\n\ --hide=PATTERN do not list implied entries matching shell PATTERN\ \n\ (overridden by -a or -A)\n\ @@ -4790,7 +4850,7 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\n\ -i, --inode print the index number of each file\n\ -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\ \n\ - -k, --kibibytes use 1024-byte blocks\n\ + -k, --kibibytes default to 1024-byte blocks for disk usage\n\ "), stdout); fputs (_("\ -l use a long listing format\n\ @@ -4809,9 +4869,10 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\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, --hide-control-chars print ? instead of nongraphic characters\n\ + --show-control-chars show nongraphic characters as-is (the 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\ @@ -4824,30 +4885,33 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\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\ + --sort=WORD sort by WORD instead of name: none (-U), size (-S)\ +,\n\ + time (-t), version (-v), extension (-X)\n\ + --time=WORD with -l, show time as WORD instead of default\n\ + modification time: atime or access or use (-u)\n\ + ctime or status (-c); also use specified time\n\ + as sort key 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\ - FORMAT1<newline>FORMAT2, 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\ + full-iso, long-iso, iso, locale, or +FORMAT;\n\ + FORMAT is interpreted like in 'date'; if FORMAT\ +\n\ + is FORMAT1<newline>FORMAT2, then FORMAT1 applies\ +\n\ + to 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, newest first\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\ + -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\ @@ -4856,7 +4920,7 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\n\ -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\ + -Z, --context print any security context of each file\n\ -1 list one file per line\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); diff --git a/src/make-prime-list.c b/src/make-prime-list.c index 4ec01cf3..c01b1200 100644 --- a/src/make-prime-list.c +++ b/src/make-prime-list.c @@ -3,7 +3,7 @@ Contributed to the GNU project by Torbjörn Granlund and Niels Möller Contains code from GNU MP. -Copyright 2012-2013 Free Software Foundation, Inc. +Copyright 2012-2014 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 diff --git a/src/md5sum.c b/src/md5sum.c index b4378115..cc6dd49e 100644 --- a/src/md5sum.c +++ b/src/md5sum.c @@ -1,5 +1,5 @@ /* Compute checksums of files or strings. - Copyright (C) 1995-2013 Free Software Foundation, Inc. + Copyright (C) 1995-2014 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 @@ -194,15 +194,13 @@ With no FILE, or when FILE is -, read standard input.\n\ "), stdout); fputs (_("\ \n\ -The following three options are useful only when verifying checksums:\n\ +The following four options are useful only when verifying checksums:\n\ --quiet don't print OK for each successfully verified file\n\ --status don't output anything, status code shows success\n\ + --strict exit non-zero for improperly formatted checksum lines\n\ -w, --warn warn about improperly formatted checksum lines\n\ \n\ "), stdout); - fputs (_("\ - --strict with --check, exit non-zero for any invalid input\n\ -"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); printf (_("\ @@ -657,11 +655,17 @@ digest_check (const char *checkfile_name) && (!strict || n_improperly_formatted_lines == 0)); } +/* If ESCAPE is true, then translate each NEWLINE byte to the string, "\\n", + and each backslash to "\\\\". */ static void -print_filename (char const *file) +print_filename (char const *file, bool escape) { - /* Translate each NEWLINE byte to the string, "\\n", - and each backslash to "\\\\". */ + if (! escape) + { + fputs (file, stdout); + return; + } + while (*file) { switch (*file) @@ -823,14 +827,23 @@ main (int argc, char **argv) ok = false; else { + /* We don't really need to escape, and hence detect, the '\\' + char, and not doing so should be both forwards and backwards + compatible, since only escaped lines would have a '\\' char at + the start. However just in case users are directly comparing + against old (hashed) outputs, in the presence of files + containing '\\' characters, we decided to not simplify the + output in this case. */ + bool needs_escape = strchr (file, '\\') || strchr (file, '\n'); + if (prefix_tag) { - if (strchr (file, '\n') || strchr (file, '\\')) + if (needs_escape) putchar ('\\'); fputs (DIGEST_TYPE_STRING, stdout); fputs (" (", stdout); - print_filename (file); + print_filename (file, needs_escape); fputs (") = ", stdout); } @@ -838,7 +851,7 @@ main (int argc, char **argv) /* Output a leading backslash if the file name contains a newline or backslash. */ - if (!prefix_tag && (strchr (file, '\n') || strchr (file, '\\'))) + if (!prefix_tag && needs_escape) putchar ('\\'); for (i = 0; i < (digest_hex_bytes / 2); ++i) @@ -850,7 +863,7 @@ main (int argc, char **argv) putchar (file_is_binary ? '*' : ' '); - print_filename (file); + print_filename (file, needs_escape); } putchar ('\n'); diff --git a/src/mkdir.c b/src/mkdir.c index a94f96e1..eb9693cc 100644 --- a/src/mkdir.c +++ b/src/mkdir.c @@ -1,5 +1,5 @@ /* mkdir -- make directories - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 @@ -29,6 +29,8 @@ #include "prog-fprintf.h" #include "quote.h" #include "savewd.h" +#include "selinux.h" +#include "smack.h" /* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "mkdir" @@ -64,8 +66,12 @@ Create the DIRECTORY(ies), if they do not already exist.\n\ -m, --mode=MODE set file mode (as in chmod), not a=rwx - umask\n\ -p, --parents no error if existing, make parent directories as needed\n\ -v, --verbose print a message for each created directory\n\ - -Z, --context=CTX set the SELinux security context of each created\n\ - directory to CTX\n\ +"), stdout); + fputs (_("\ + -Z set SELinux security context of each created directory\n\ + to the default type\n\ + --context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\ + or SMACK security context to CTX\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -81,8 +87,8 @@ struct mkdir_options made. */ int (*make_ancestor_function) (char const *, char const *, void *); - /* Mode for ancestor directory. */ - mode_t ancestor_mode; + /* Umask value in effect. */ + mode_t umask_value; /* Mode for directory itself. */ mode_t mode; @@ -90,6 +96,9 @@ struct mkdir_options /* File mode bits affected by MODE. */ mode_t mode_bits; + /* Set the SELinux File Context. */ + bool set_security_context; + /* If not null, format to use when reporting newly made directories. */ char const *created_directory_format; }; @@ -112,10 +121,26 @@ static int make_ancestor (char const *dir, char const *component, void *options) { struct mkdir_options const *o = options; - int r = mkdir (component, o->ancestor_mode); + + if (o->set_security_context && defaultcon (dir, S_IFDIR) < 0 + && ! ignorable_ctx_err (errno)) + error (0, errno, _("failed to set default creation context for %s"), + quote (dir)); + + mode_t user_wx = S_IWUSR | S_IXUSR; + bool self_denying_umask = (o->umask_value & user_wx) != 0; + if (self_denying_umask) + umask (o->umask_value & ~user_wx); + int r = mkdir (component, S_IRWXUGO); + if (self_denying_umask) + { + int mkdir_errno = errno; + umask (o->umask_value); + errno = mkdir_errno; + } if (r == 0) { - r = ! (o->ancestor_mode & S_IRUSR); + r = (o->umask_value & S_IRUSR) != 0; announce_mkdir (dir, options); } return r; @@ -126,11 +151,48 @@ static int process_dir (char *dir, struct savewd *wd, void *options) { struct mkdir_options const *o = options; - return (make_dir_parents (dir, wd, o->make_ancestor_function, options, - o->mode, announce_mkdir, - o->mode_bits, (uid_t) -1, (gid_t) -1, true) - ? EXIT_SUCCESS - : EXIT_FAILURE); + bool set_defaultcon = false; + + /* If possible set context before DIR created. */ + if (o->set_security_context) + { + if (! o->make_ancestor_function) + set_defaultcon = true; + else + { + char *pdir = dir_name (dir); + struct stat st; + if (STREQ (pdir, ".") + || (stat (pdir, &st) == 0 && S_ISDIR (st.st_mode))) + set_defaultcon = true; + free (pdir); + } + if (set_defaultcon && defaultcon (dir, S_IFDIR) < 0 + && ! ignorable_ctx_err (errno)) + error (0, errno, _("failed to set default creation context for %s"), + quote (dir)); + } + + int ret = (make_dir_parents (dir, wd, o->make_ancestor_function, options, + o->mode, announce_mkdir, + o->mode_bits, (uid_t) -1, (gid_t) -1, true) + ? EXIT_SUCCESS + : EXIT_FAILURE); + + /* FIXME: Due to the current structure of make_dir_parents() + we don't have the facility to call defaultcon() before the + final component of DIR is created. So for now, create the + final component with the context from previous component + and here we set the context for the final component. */ + if (ret == EXIT_SUCCESS && o->set_security_context && ! set_defaultcon) + { + if (! restorecon (last_component (dir), false, false) + && ! ignorable_ctx_err (errno)) + error (0, errno, _("failed to restore context for %s"), + quote (dir)); + } + + return ret; } int @@ -138,13 +200,14 @@ main (int argc, char **argv) { const char *specified_mode = NULL; int optc; - security_context_t scontext = NULL; + char const *scontext = NULL; struct mkdir_options options; options.make_ancestor_function = NULL; options.mode = S_IRWXUGO; options.mode_bits = 0; options.created_directory_format = NULL; + options.set_security_context = false; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -154,7 +217,7 @@ main (int argc, char **argv) atexit (close_stdout); - while ((optc = getopt_long (argc, argv, "pm:vZ:", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "pm:vZ", longopts, NULL)) != -1) { switch (optc) { @@ -168,7 +231,24 @@ main (int argc, char **argv) options.created_directory_format = _("created directory %s"); break; case 'Z': - scontext = optarg; + if (is_smack_enabled ()) + { + /* We don't yet support -Z to restore context with SMACK. */ + scontext = optarg; + } + else if (is_selinux_enabled () > 0) + { + if (optarg) + scontext = optarg; + else + options.set_security_context = true; + } + else if (optarg) + { + error (0, 0, + _("warning: ignoring --context; " + "it requires an SELinux/SMACK-enabled kernel")); + } break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -183,16 +263,29 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } - if (scontext && setfscreatecon (scontext) < 0) - error (EXIT_FAILURE, errno, - _("failed to set default file creation context to %s"), - quote (scontext)); + /* FIXME: This assumes mkdir() is done in the same process. + If that's not always the case we would need to call this + like we do when options.set_security_context == true. */ + if (scontext) + { + int ret = 0; + if (is_smack_enabled ()) + ret = smack_set_label_for_self (scontext); + else + ret = setfscreatecon (se_const (scontext)); + + if (ret < 0) + error (EXIT_FAILURE, errno, + _("failed to set default file creation context to %s"), + quote (scontext)); + } + if (options.make_ancestor_function || specified_mode) { mode_t umask_value = umask (0); - - options.ancestor_mode = (S_IRWXUGO & ~umask_value) | (S_IWUSR | S_IXUSR); + umask (umask_value); + options.umask_value = umask_value; if (specified_mode) { @@ -205,7 +298,7 @@ main (int argc, char **argv) free (change); } else - options.mode = S_IRWXUGO & ~umask_value; + options.mode = S_IRWXUGO; } exit (savewd_process_files (argc - optind, argv + optind, diff --git a/src/mkfifo.c b/src/mkfifo.c index 76291e5b..415ae562 100644 --- a/src/mkfifo.c +++ b/src/mkfifo.c @@ -1,5 +1,5 @@ /* mkfifo -- make fifo's (named pipes) - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 @@ -26,6 +26,8 @@ #include "error.h" #include "modechange.h" #include "quote.h" +#include "selinux.h" +#include "smack.h" /* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "mkfifo" @@ -59,7 +61,9 @@ Create named pipes (FIFOs) with the given NAMEs.\n\ -m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\ "), stdout); fputs (_("\ - -Z, --context=CTX set the SELinux security context of each NAME to CTX\n\ + -Z set the SELinux security context to default type\n\ + --context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\ + or SMACK security context to CTX\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -75,7 +79,8 @@ main (int argc, char **argv) char const *specified_mode = NULL; int exit_status = EXIT_SUCCESS; int optc; - security_context_t scontext = NULL; + char const *scontext = NULL; + bool set_security_context = false; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -85,7 +90,7 @@ main (int argc, char **argv) atexit (close_stdout); - while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "m:Z", longopts, NULL)) != -1) { switch (optc) { @@ -93,7 +98,24 @@ main (int argc, char **argv) specified_mode = optarg; break; case 'Z': - scontext = optarg; + if (is_smack_enabled ()) + { + /* We don't yet support -Z to restore context with SMACK. */ + scontext = optarg; + } + else if (is_selinux_enabled () > 0) + { + if (optarg) + scontext = optarg; + else + set_security_context = true; + } + else if (optarg) + { + error (0, 0, + _("warning: ignoring --context; " + "it requires an SELinux/SMACK-enabled kernel")); + } break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -108,18 +130,30 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } - if (scontext && setfscreatecon (scontext) < 0) - error (EXIT_FAILURE, errno, - _("failed to set default file creation context to %s"), - quote (scontext)); + if (scontext) + { + int ret = 0; + if (is_smack_enabled ()) + ret = smack_set_label_for_self (scontext); + else + ret = setfscreatecon (se_const (scontext)); + + if (ret < 0) + error (EXIT_FAILURE, errno, + _("failed to set default file creation context to %s"), + quote (scontext)); + } newmode = MODE_RW_UGO; if (specified_mode) { + mode_t umask_value; struct mode_change *change = mode_compile (specified_mode); if (!change) error (EXIT_FAILURE, 0, _("invalid mode")); - newmode = mode_adjust (newmode, false, umask (0), change, NULL); + umask_value = umask (0); + umask (umask_value); + newmode = mode_adjust (newmode, false, umask_value, change, NULL); free (change); if (newmode & ~S_IRWXUGO) error (EXIT_FAILURE, 0, @@ -127,11 +161,21 @@ main (int argc, char **argv) } for (; optind < argc; ++optind) - if (mkfifo (argv[optind], newmode) != 0) - { - error (0, errno, _("cannot create fifo %s"), quote (argv[optind])); - exit_status = EXIT_FAILURE; - } + { + if (set_security_context) + defaultcon (argv[optind], S_IFIFO); + if (mkfifo (argv[optind], newmode) != 0) + { + error (0, errno, _("cannot create fifo %s"), quote (argv[optind])); + exit_status = EXIT_FAILURE; + } + else if (specified_mode && lchmod (argv[optind], newmode) != 0) + { + error (0, errno, _("cannot set permissions of %s"), + quote (argv[optind])); + exit_status = EXIT_FAILURE; + } + } exit (exit_status); } diff --git a/src/mknod.c b/src/mknod.c index 7cfc708d..8f547e9c 100644 --- a/src/mknod.c +++ b/src/mknod.c @@ -1,5 +1,5 @@ /* mknod -- make special files - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 @@ -26,6 +26,8 @@ #include "error.h" #include "modechange.h" #include "quote.h" +#include "selinux.h" +#include "smack.h" #include "xstrtol.h" /* The official name of this program (e.g., no 'g' prefix). */ @@ -61,7 +63,9 @@ Create the special file NAME of the given TYPE.\n\ -m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\ "), stdout); fputs (_("\ - -Z, --context=CTX set the SELinux security context of NAME to CTX\n\ + -Z set the SELinux security context to default type\n\ + --context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\ + or SMACK security context to CTX\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -92,7 +96,8 @@ main (int argc, char **argv) int optc; int expected_operands; mode_t node_type; - security_context_t scontext = NULL; + char const *scontext = NULL; + bool set_security_context = false; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -102,7 +107,7 @@ main (int argc, char **argv) atexit (close_stdout); - while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "m:Z", longopts, NULL)) != -1) { switch (optc) { @@ -110,7 +115,24 @@ main (int argc, char **argv) specified_mode = optarg; break; case 'Z': - scontext = optarg; + if (is_smack_enabled ()) + { + /* We don't yet support -Z to restore context with SMACK. */ + scontext = optarg; + } + else if (is_selinux_enabled () > 0) + { + if (optarg) + scontext = optarg; + else + set_security_context = true; + } + else if (optarg) + { + error (0, 0, + _("warning: ignoring --context; " + "it requires an SELinux/SMACK-enabled kernel")); + } break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -122,10 +144,13 @@ main (int argc, char **argv) newmode = MODE_RW_UGO; if (specified_mode) { + mode_t umask_value; struct mode_change *change = mode_compile (specified_mode); if (!change) error (EXIT_FAILURE, 0, _("invalid mode")); - newmode = mode_adjust (newmode, false, umask (0), change, NULL); + umask_value = umask (0); + umask (umask_value); + newmode = mode_adjust (newmode, false, umask_value, change, NULL); free (change); if (newmode & ~S_IRWXUGO) error (EXIT_FAILURE, 0, @@ -161,10 +186,19 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } - if (scontext && setfscreatecon (scontext) < 0) - error (EXIT_FAILURE, errno, - _("failed to set default file creation context to %s"), - quote (scontext)); + if (scontext) + { + int ret = 0; + if (is_smack_enabled ()) + ret = smack_set_label_for_self (scontext); + else + ret = setfscreatecon (se_const (scontext)); + + if (ret < 0) + error (EXIT_FAILURE, errno, + _("failed to set default file creation context to %s"), + quote (scontext)); + } /* Only check the first character, to allow mnemonic usage like 'mknod /dev/rst0 character 18 0'. */ @@ -211,12 +245,17 @@ main (int argc, char **argv) error (EXIT_FAILURE, 0, _("invalid device %s %s"), s_major, s_minor); #endif + if (set_security_context) + defaultcon (argv[optind], node_type); + if (mknod (argv[optind], newmode | node_type, device) != 0) error (EXIT_FAILURE, errno, "%s", quote (argv[optind])); } break; case 'p': /* 'pipe' */ + if (set_security_context) + defaultcon (argv[optind], S_IFIFO); if (mkfifo (argv[optind], newmode) != 0) error (EXIT_FAILURE, errno, "%s", quote (argv[optind])); break; @@ -226,5 +265,9 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } + if (specified_mode && lchmod (argv[optind], newmode) != 0) + error (EXIT_FAILURE, errno, _("cannot set permissions of %s"), + quote (argv[optind])); + exit (EXIT_SUCCESS); } diff --git a/src/mktemp.c b/src/mktemp.c index aef140af..2bd80bae 100644 --- a/src/mktemp.c +++ b/src/mktemp.c @@ -1,5 +1,5 @@ /* Create a temporary file or directory, safely. - Copyright (C) 2007-2013 Free Software Foundation, Inc. + Copyright (C) 2007-2014 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 @@ -26,7 +26,6 @@ #include "error.h" #include "filenamecat.h" #include "quote.h" -#include "stdio--.h" #include "tempname.h" /* The official name of this program (e.g., no 'g' prefix). */ @@ -43,7 +42,6 @@ static const char *default_template = "tmp.XXXXXXXXXX"; enum { SUFFIX_OPTION = CHAR_MAX + 1, - TMPDIR_OPTION }; static struct option const longopts[] = @@ -52,7 +50,7 @@ static struct option const longopts[] = {"quiet", no_argument, NULL, 'q'}, {"dry-run", no_argument, NULL, 'u'}, {"suffix", required_argument, NULL, SUFFIX_OPTION}, - {"tmpdir", optional_argument, NULL, TMPDIR_OPTION}, + {"tmpdir", optional_argument, NULL, 'p'}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} @@ -81,24 +79,21 @@ Files are created u+rw, and directories u+rwx, minus umask restrictions.\n\ -q, --quiet suppress diagnostics about file/dir-creation failure\n\ "), stdout); fputs (_("\ - --suffix=SUFF append SUFF to TEMPLATE. SUFF must not contain slash.\n\ - This option is implied if TEMPLATE does not end in X.\n\ + --suffix=SUFF append SUFF to TEMPLATE; SUFF must not contain a slash.\n\ + This option is implied if TEMPLATE does not end in X\n\ "), stdout); fputs (_("\ - --tmpdir[=DIR] interpret TEMPLATE relative to DIR. If DIR is not\n\ + -p DIR, --tmpdir[=DIR] interpret TEMPLATE relative to DIR; if DIR is not\n\ specified, use $TMPDIR if set, else /tmp. With\n\ - this option, TEMPLATE must not be an absolute name.\n\ - Unlike with -t, TEMPLATE may contain slashes, but\n\ + this option, TEMPLATE must not be an absolute name;\n\ + unlike with -t, TEMPLATE may contain slashes, but\n\ mktemp creates only the final component\n\ "), stdout); - fputs ("\n", stdout); fputs (_("\ - -p DIR use DIR as a prefix; implies -t [deprecated]\n\ -t interpret TEMPLATE as a single file name component,\n\ relative to a directory: $TMPDIR, if set; else the\n\ directory specified via -p; else /tmp [deprecated]\n\ "), stdout); - fputs ("\n", stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); emit_ancillary_info (); @@ -151,7 +146,7 @@ main (int argc, char **argv) { char const *dest_dir; char const *dest_dir_arg = NULL; - bool suppress_stderr = false; + bool suppress_file_err = false; int c; unsigned int n_args; char *template; @@ -185,7 +180,7 @@ main (int argc, char **argv) use_dest_dir = true; break; case 'q': - suppress_stderr = true; + suppress_file_err = true; break; case 't': use_dest_dir = true; @@ -195,11 +190,6 @@ main (int argc, char **argv) dry_run = true; break; - case TMPDIR_OPTION: - use_dest_dir = true; - dest_dir_arg = optarg; - break; - case SUFFIX_OPTION: suffix = optarg; break; @@ -214,15 +204,6 @@ main (int argc, char **argv) } } - if (suppress_stderr) - { - /* From here on, redirect stderr to /dev/null. - A diagnostic from getopt_long, above, would still go to stderr. */ - if (!freopen ("/dev/null", "wb", stderr)) - error (EXIT_FAILURE, errno, - _("failed to redirect stderr to /dev/null")); - } - n_args = argc - optind; if (2 <= n_args) { @@ -283,9 +264,12 @@ main (int argc, char **argv) if (deprecated_t_option) { char *env = getenv ("TMPDIR"); - dest_dir = (env && *env - ? env - : (dest_dir_arg ? dest_dir_arg : "/tmp")); + if (env && *env) + dest_dir = env; + else if (dest_dir_arg && *dest_dir_arg) + dest_dir = dest_dir_arg; + else + dest_dir = "/tmp"; if (last_component (template) != template) error (EXIT_FAILURE, 0, @@ -323,8 +307,9 @@ main (int argc, char **argv) int err = mkdtemp_len (dest_name, suffix_len, x_count, dry_run); if (err != 0) { - error (0, errno, _("failed to create directory via template %s"), - quote (template)); + if (!suppress_file_err) + error (0, errno, _("failed to create directory via template %s"), + quote (template)); status = EXIT_FAILURE; } } @@ -333,8 +318,9 @@ main (int argc, char **argv) int fd = mkstemp_len (dest_name, suffix_len, x_count, dry_run); if (fd < 0 || (!dry_run && close (fd) != 0)) { - error (0, errno, _("failed to create file via template %s"), - quote (template)); + if (!suppress_file_err) + error (0, errno, _("failed to create file via template %s"), + quote (template)); status = EXIT_FAILURE; } } @@ -348,7 +334,9 @@ main (int argc, char **argv) { int saved_errno = errno; remove (dest_name); - error (EXIT_FAILURE, saved_errno, _("write error")); + if (!suppress_file_err) + error (0, saved_errno, _("write error")); + status = EXIT_FAILURE; } } @@ -1,5 +1,5 @@ /* mv -- move or rename files - Copyright (C) 1986-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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 @@ -55,6 +55,7 @@ static bool remove_trailing_slashes; static struct option const long_options[] = { {"backup", optional_argument, NULL, 'b'}, + {"context", no_argument, NULL, 'Z'}, {"force", no_argument, NULL, 'f'}, {"interactive", no_argument, NULL, 'i'}, {"no-clobber", no_argument, NULL, 'n'}, @@ -120,6 +121,7 @@ cp_option_init (struct cp_options *x) x->preserve_timestamps = true; x->explicit_no_preserve_mode= false; x->preserve_security_context = selinux_enabled; + x->set_security_context = false; x->reduce_diagnostics = false; x->data_copy_required = true; x->require_preserve = false; /* FIXME: maybe make this an option */ @@ -316,6 +318,8 @@ If you specify more than one of -i, -f, -n, only the final one takes effect.\n\ than the destination file or when the\n\ destination file is missing\n\ -v, --verbose explain what is being done\n\ + -Z, --context set SELinux security context of destination\n\ + file to default type\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -350,6 +354,7 @@ main (int argc, char **argv) bool no_target_directory = false; int n_files; char **file; + bool selinux_enabled = (0 < is_selinux_enabled ()); initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -368,7 +373,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, "bfint:uvS:T", long_options, NULL)) + while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, NULL)) != -1) { switch (c) @@ -418,6 +423,15 @@ main (int argc, char **argv) make_backups = true; backup_suffix_string = optarg; break; + case 'Z': + /* As a performance enhancement, don't even bother trying + to "restorecon" when not on an selinux-enabled kernel. */ + if (selinux_enabled) + { + x.preserve_security_context = false; + x.set_security_context = true; + } + break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: @@ -1,5 +1,5 @@ /* nice -- run a program with modified niceness - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 @@ -1,5 +1,5 @@ /* nl -- number lines of files - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 diff --git a/src/nohup.c b/src/nohup.c index 075c4cda..eca1f512 100644 --- a/src/nohup.c +++ b/src/nohup.c @@ -1,5 +1,5 @@ /* nohup -- run a command immune to hangups, with output to a non-tty - Copyright (C) 2003-2013 Free Software Foundation, Inc. + Copyright (C) 2003-2014 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 diff --git a/src/nproc.c b/src/nproc.c index 5bd6610d..9bfc8b39 100644 --- a/src/nproc.c +++ b/src/nproc.c @@ -1,5 +1,5 @@ /* nproc - print the number of processors. - Copyright (C) 2009-2013 Free Software Foundation, Inc. + Copyright (C) 2009-2014 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 diff --git a/src/numfmt.c b/src/numfmt.c index 8c21c2b3..206866ac 100644 --- a/src/numfmt.c +++ b/src/numfmt.c @@ -1,5 +1,5 @@ /* Reformat numbers like 11505426432 to the more human-readable 11G - Copyright (C) 2012 Free Software Foundation, Inc. + Copyright (C) 2012-2014 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 @@ -23,6 +23,7 @@ #include "mbsalign.h" #include "argmatch.h" +#include "c-ctype.h" #include "error.h" #include "quote.h" #include "system.h" @@ -169,6 +170,7 @@ static int grouping = 0; static char *padding_buffer = NULL; static size_t padding_buffer_size = 0; static long int padding_width = 0; +static long int zero_padding_width = 0; static const char *format_str = NULL; static char *format_str_prefix = NULL; static char *format_str_suffix = NULL; @@ -197,22 +199,6 @@ static int decimal_point_length; /* debugging for developers. Enables devmsg(). */ static bool dev_debug = false; -/* Like error(0, 0, ...), but without an implicit newline. - Also a noop unless the global DEV_DEBUG is set. - TODO: Replace with variadic macro in system.h or - move to a separate module. */ -static inline void -devmsg (char const *fmt, ...) -{ - if (dev_debug) - { - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - } -} - static inline int default_scale_base (enum scale_type scale) { @@ -272,7 +258,7 @@ suffix_power (const char suf) } static inline const char * -suffix_power_character (unsigned int power) +suffix_power_char (unsigned int power) { switch (power) { @@ -469,14 +455,10 @@ simple_strtod_int (const char *input_str, *negative = false; *endptr = (char *) input_str; - while (*endptr && isdigit (**endptr)) + while (*endptr && c_isdigit (**endptr)) { int digit = (**endptr) - '0'; - /* can this happen in some strange locale? */ - if (digit < 0 || digit > 9) - return SSE_INVALID_NUMBER; - if (digits > MAX_UNSCALED_DIGITS) e = SSE_OK_PRECISION_LOSS; @@ -598,8 +580,9 @@ simple_strtod_human (const char *input_str, /* 'scale_auto' is checked below. */ int scale_base = default_scale_base (allowed_scaling); - devmsg ("simple_strtod_human:\n input string: '%s'\n " - "locale decimal-point: '%s'\n", input_str, decimal_point); + devmsg ("simple_strtod_human:\n input string: %s\n " + "locale decimal-point: %s\n", + quote_n (0, input_str), quote_n (1, decimal_point)); enum simple_strtod_error e = simple_strtod_float (input_str, endptr, value, precision); @@ -614,7 +597,7 @@ simple_strtod_human (const char *input_str, /* process suffix. */ /* Skip any blanks between the number and suffix. */ - while (isblank (**endptr)) + while (isblank (to_uchar (**endptr))) (*endptr)++; if (!valid_suffix (**endptr)) @@ -673,29 +656,29 @@ simple_strtod_fatal (enum simple_strtod_error err, char const *input_str) abort (); case SSE_OVERFLOW: - msgid = N_("value too large to be converted: '%s'"); + msgid = N_("value too large to be converted: %s"); break; case SSE_INVALID_NUMBER: - msgid = N_("invalid number: '%s'"); + msgid = N_("invalid number: %s"); break; case SSE_VALID_BUT_FORBIDDEN_SUFFIX: - msgid = N_("rejecting suffix in input: '%s' (consider using --from)"); + msgid = N_("rejecting suffix in input: %s (consider using --from)"); break; case SSE_INVALID_SUFFIX: - msgid = N_("invalid suffix in input: '%s'"); + msgid = N_("invalid suffix in input: %s"); break; case SSE_MISSING_I_SUFFIX: - msgid = N_("missing 'i' suffix in input: '%s' (e.g Ki/Mi/Gi)"); + msgid = N_("missing 'i' suffix in input: %s (e.g Ki/Mi/Gi)"); break; } if (_invalid != inval_ignore) - error (conv_exit_code, 0, gettext (msgid), input_str); + error (conv_exit_code, 0, gettext (msgid), quote (input_str)); } /* Convert VAL to a human format string in BUF. */ @@ -704,6 +687,21 @@ double_to_human (long double val, int precision, char *buf, size_t buf_size, enum scale_type scale, int group, enum round_type round) { + int num_size; + char fmt[64]; + verify (sizeof (fmt) > (INT_BUFSIZE_BOUND (zero_padding_width) + + INT_BUFSIZE_BOUND (precision) + + 10 /* for %.Lf etc. */)); + + char *pfmt = fmt; + *pfmt++ = '%'; + + if (group) + *pfmt++ = '\''; + + if (zero_padding_width) + pfmt += snprintf (pfmt, sizeof (fmt) - 2, "0%ld", zero_padding_width); + devmsg ("double_to_human:\n"); if (scale == scale_none) @@ -716,9 +714,10 @@ double_to_human (long double val, int precision, " no scaling, returning (grouped) value: %'.*Lf\n" : " no scaling, returning value: %.*Lf\n", precision, val); - int i = snprintf (buf, buf_size, (group) ? "%'.*Lf" : "%.*Lf", - precision, val); - if (i < 0 || i >= (int) buf_size) + stpcpy (pfmt, ".*Lf"); + + num_size = snprintf (buf, buf_size, fmt, precision, val); + if (num_size < 0 || num_size >= (int) buf_size) error (EXIT_FAILURE, 0, _("failed to prepare value '%Lf' for printing"), val); return; @@ -760,13 +759,18 @@ double_to_human (long double val, int precision, devmsg (" after rounding, value=%Lf * %0.f ^ %d\n", val, scale_base, power); - snprintf (buf, buf_size, (show_decimal_point) ? "%.1Lf%s" : "%.0Lf%s", - val, suffix_power_character (power)); + stpcpy (pfmt, show_decimal_point ? ".1Lf%s" : ".0Lf%s"); + + /* buf_size - 1 used here to ensure place for possible scale_IEC_I suffix. */ + num_size = snprintf (buf, buf_size - 1, fmt, val, suffix_power_char (power)); + if (num_size < 0 || num_size >= (int) buf_size - 1) + error (EXIT_FAILURE, 0, + _("failed to prepare value '%Lf' for printing"), val); if (scale == scale_IEC_I && power > 0) - strncat (buf, "i", buf_size - strlen (buf) - 1); + strncat (buf, "i", buf_size - num_size - 1); - devmsg (" returning value: '%s'\n", buf); + devmsg (" returning value: %s\n", quote (buf)); return; } @@ -784,7 +788,7 @@ unit_to_umax (const char *n_string) s_err = xstrtoumax (n_string, &end, 10, &n, "KMGTPEZY"); if (s_err != LONGINT_OK || *end || n == 0) - error (EXIT_FAILURE, 0, _("invalid unit size: '%s'"), n_string); + error (EXIT_FAILURE, 0, _("invalid unit size: %s"), quote (n_string)); return n; } @@ -797,10 +801,7 @@ setup_padding_buffer (size_t min_size) return; padding_buffer_size = min_size + 1; - padding_buffer = realloc (padding_buffer, padding_buffer_size); - if (!padding_buffer) - error (EXIT_FAILURE, 0, _("out of memory (requested %zu bytes)"), - padding_buffer_size); + padding_buffer = xrealloc (padding_buffer, padding_buffer_size); } void @@ -905,8 +906,8 @@ UNIT options:\n"), stdout); fputs (_("\n\ FORMAT must be suitable for printing one floating-point argument '%f'.\n\ Optional quote (%'f) will enable --grouping (if supported by current locale).\n\ -Optional width value (%10f) will pad output. Optional negative width values\n\ -(%-10f) will left-pad output.\n\ +Optional width value (%10f) will pad output. Optional zero (%010f) width\n\ +will zero pad the number. Optional negative values (%-10f) will left align.\n\ "), stdout); printf (_("\n\ @@ -966,6 +967,7 @@ parse_format_string (char const *fmt) size_t suffix_pos; long int pad = 0; char *endptr = NULL; + bool zero_padding = false; for (i = 0; !(fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1) { @@ -976,13 +978,24 @@ parse_format_string (char const *fmt) } i++; - i += strspn (fmt + i, " "); - if (fmt[i] == '\'') + while (true) { - grouping = 1; - i++; + size_t skip = strspn (fmt + i, " "); + i += skip; + if (fmt[i] == '\'') + { + grouping = 1; + i++; + } + else if (fmt[i] == '0') + { + zero_padding = true; + i++; + } + else if (! skip) + break; } - i += strspn (fmt + i, " "); + errno = 0; pad = strtol (fmt + i, &endptr, 10); if (errno == ERANGE) @@ -991,6 +1004,9 @@ parse_format_string (char const *fmt) if (endptr != (fmt + i) && pad != 0) { + if (debug && padding_width && !(zero_padding && pad > 0)) + error (0, 0, _("--format padding overridding --padding")); + if (pad < 0) { padding_alignment = MBS_ALIGN_LEFT; @@ -998,8 +1014,12 @@ parse_format_string (char const *fmt) } else { - padding_width = pad; + if (zero_padding) + zero_padding_width = pad; + else + padding_width = pad; } + } i = endptr - fmt; @@ -1008,7 +1028,7 @@ parse_format_string (char const *fmt) if (fmt[i] != 'f') error (EXIT_FAILURE, 0, _("invalid format %s," - " directive must be %%['][-][N]f"), + " directive must be %%[0]['][-][N]f"), quote (fmt)); i++; suffix_pos = i; @@ -1019,27 +1039,18 @@ parse_format_string (char const *fmt) quote (fmt)); if (prefix_len) - { - format_str_prefix = xstrndup (fmt, prefix_len); - if (!format_str_prefix) - error (EXIT_FAILURE, 0, _("out of memory (requested %zu bytes)"), - prefix_len + 1); - } + format_str_prefix = xstrndup (fmt, prefix_len); if (fmt[suffix_pos] != '\0') - { - format_str_suffix = strdup (fmt + suffix_pos); - if (!format_str_suffix) - error (EXIT_FAILURE, 0, _("out of memory (requested %zu bytes)"), - strlen (fmt + suffix_pos)); - } + format_str_suffix = xstrdup (fmt + suffix_pos); devmsg ("format String:\n input: %s\n grouping: %s\n" " padding width: %ld\n alignment: %s\n" - " prefix: '%s'\n suffix: '%s'\n", - quote (fmt), (grouping) ? "yes" : "no", + " prefix: %s\n suffix: %s\n", + quote_n (0, fmt), (grouping) ? "yes" : "no", padding_width, (padding_alignment == MBS_ALIGN_LEFT) ? "Left" : "Right", - format_str_prefix, format_str_suffix); + quote_n (1, format_str_prefix ? format_str_prefix : ""), + quote_n (2, format_str_suffix ? format_str_suffix : "")); } /* Parse a numeric value (with optional suffix) from a string. @@ -1067,8 +1078,8 @@ parse_human_number (const char *str, long double /*output */ *value, if (ptr && *ptr != '\0') { if (_invalid != inval_ignore) - error (conv_exit_code, 0, _("invalid suffix in input '%s': '%s'"), - str, ptr); + error (conv_exit_code, 0, _("invalid suffix in input %s: %s"), + quote_n (0, str), quote_n (1, ptr)); e = SSE_INVALID_SUFFIX; } return e; @@ -1107,7 +1118,8 @@ prepare_padded_number (const long double val, size_t precision) if (suffix) strncat (buf, suffix, sizeof (buf) - strlen (buf) -1); - devmsg ("formatting output:\n value: %Lf\n humanized: '%s'\n", val, buf); + devmsg ("formatting output:\n value: %Lf\n humanized: %s\n", + val, quote (buf)); if (padding_width && strlen (buf) < padding_width) { @@ -1115,7 +1127,7 @@ prepare_padded_number (const long double val, size_t precision) mbsalign (buf, padding_buffer, padding_buffer_size, &w, padding_alignment, MBA_UNIBYTE_ONLY); - devmsg (" After padding: '%s'\n", padding_buffer); + devmsg (" After padding: %s\n", quote (padding_buffer)); } else { @@ -1151,7 +1163,7 @@ process_suffixed_number (char *text, long double *result, size_t *precision) { /* trim suffix, ONLY if it's at the end of the text. */ *possible_suffix = '\0'; - devmsg ("trimming suffix '%s'\n", suffix); + devmsg ("trimming suffix %s\n", quote (suffix)); } else devmsg ("no valid suffix found\n"); @@ -1159,7 +1171,7 @@ process_suffixed_number (char *text, long double *result, size_t *precision) /* Skip white space - always. */ char *p = text; - while (*p && isblank (*p)) + while (*p && isblank (to_uchar (*p))) ++p; const unsigned int skip_count = text - p; @@ -1181,7 +1193,8 @@ process_suffixed_number (char *text, long double *result, size_t *precision) long double val = 0; enum simple_strtod_error e = parse_human_number (p, &val, precision); if (e == SSE_OK_PRECISION_LOSS && debug) - error (0, 0, _("large input value '%s': possible precision loss"), p); + error (0, 0, _("large input value %s: possible precision loss"), + quote (p)); if (from_unit_size != 1 || to_unit_size != 1) val = (val * from_unit_size) / to_unit_size; @@ -1194,8 +1207,7 @@ process_suffixed_number (char *text, long double *result, size_t *precision) /* Skip the requested number of fields in the input string. Returns a pointer to the *delimiter* of the requested field, or a pointer to NUL (if reached the end of the string). */ -static inline char * -__attribute ((pure)) +static inline char * _GL_ATTRIBUTE_PURE skip_fields (char *buf, int fields) { char *ptr = buf; @@ -1214,9 +1226,9 @@ skip_fields (char *buf, int fields) else while (*ptr && fields--) { - while (*ptr && isblank (*ptr)) + while (*ptr && isblank (to_uchar (*ptr))) ++ptr; - while (*ptr && !isblank (*ptr)) + while (*ptr && !isblank (to_uchar (*ptr))) ++ptr; } return ptr; @@ -1242,7 +1254,8 @@ extract_fields (char *line, int _field, *_data = NULL; *_suffix = NULL; - devmsg ("extracting Fields:\n input: '%s'\n field: %d\n", line, _field); + devmsg ("extracting Fields:\n input: %s\n field: %d\n", + quote (line), _field); if (field > 1) { @@ -1252,7 +1265,7 @@ extract_fields (char *line, int _field, if (*ptr == '\0') { /* not enough fields in the input - print warning? */ - devmsg (" TOO FEW FIELDS!\n prefix: '%s'\n", *_prefix); + devmsg (" TOO FEW FIELDS!\n prefix: %s\n", quote (*_prefix)); return; } @@ -1272,8 +1285,10 @@ extract_fields (char *line, int _field, else *_suffix = NULL; - devmsg (" prefix: '%s'\n number: '%s'\n suffix: '%s'\n", - *_prefix, *_data, *_suffix); + devmsg (" prefix: %s\n number: %s\n suffix: %s\n", + quote_n (0, *_prefix ? *_prefix : ""), + quote_n (1, *_data), + quote_n (2, *_suffix ? *_suffix : "")); } @@ -1385,7 +1400,8 @@ main (int argc, char **argv) case PADDING_OPTION: if (xstrtol (optarg, NULL, 10, &padding_width, "") != LONGINT_OK || padding_width == 0) - error (EXIT_FAILURE, 0, _("invalid padding value '%s'"), optarg); + error (EXIT_FAILURE, 0, _("invalid padding value %s"), + quote (optarg)); if (padding_width < 0) { padding_alignment = MBS_ALIGN_LEFT; @@ -1398,7 +1414,8 @@ main (int argc, char **argv) case FIELD_OPTION: if (xstrtol (optarg, NULL, 10, &field, "") != LONGINT_OK || field <= 0) - error (EXIT_FAILURE, 0, _("invalid field value '%s'"), optarg); + error (EXIT_FAILURE, 0, _("invalid field value %s"), + quote (optarg)); break; case 'd': @@ -1427,8 +1444,8 @@ main (int argc, char **argv) { if (xstrtoumax (optarg, NULL, 10, &header, "") != LONGINT_OK || header == 0) - error (EXIT_FAILURE, 0, _("invalid header value '%s'"), - optarg); + error (EXIT_FAILURE, 0, _("invalid header value %s"), + quote (optarg)); } else { @@ -1454,8 +1471,6 @@ main (int argc, char **argv) if (format_str != NULL && grouping) error (EXIT_FAILURE, 0, _("--grouping cannot be combined with --format")); - if (format_str != NULL && padding_width > 0) - error (EXIT_FAILURE, 0, _("--padding cannot be combined with --format")); /* Warn about no-op. */ if (debug && scale_from == scale_none && scale_to == scale_none @@ -1,5 +1,5 @@ /* od -- dump files in octal and other formats - Copyright (C) 1992-2013 Free Software Foundation, Inc. + Copyright (C) 1992-2014 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 @@ -23,6 +23,7 @@ #include <getopt.h> #include <sys/types.h> #include "system.h" +#include "argmatch.h" #include "error.h" #include "ftoastr.h" #include "quote.h" @@ -259,13 +260,37 @@ static enum size_spec integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1]; #define MAX_FP_TYPE_SIZE sizeof (long double) static enum size_spec fp_type_size[MAX_FP_TYPE_SIZE + 1]; +#ifndef WORDS_BIGENDIAN +# define WORDS_BIGENDIAN 0 +#endif + +/* Use native endianess by default. */ +static bool input_swap; + static char const short_options[] = "A:aBbcDdeFfHhIij:LlN:OoS:st:vw::Xx"; /* For long options that have no equivalent short option, use a non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum { - TRADITIONAL_OPTION = CHAR_MAX + 1 + TRADITIONAL_OPTION = CHAR_MAX + 1, + ENDIAN_OPTION, +}; + +enum endian_type +{ + endian_little, + endian_big +}; + +static char const *const endian_args[] = +{ + "little", "big", NULL +}; + +static enum endian_type const endian_types[] = +{ + endian_little, endian_big }; static struct option const long_options[] = @@ -278,6 +303,7 @@ static struct option const long_options[] = {"strings", optional_argument, NULL, 'S'}, {"traditional", no_argument, NULL, TRADITIONAL_OPTION}, {"width", optional_argument, NULL, 'w'}, + {"endian", required_argument, NULL, ENDIAN_OPTION }, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, @@ -316,18 +342,19 @@ suffixes may be . for octal and b for multiply by 512.\n\ emit_mandatory_arg_note (); fputs (_("\ - -A, --address-radix=RADIX output format for file offsets. RADIX is one\n\ + -A, --address-radix=RADIX output format for file offsets; RADIX is one\n\ of [doxn], for Decimal, Octal, Hex or None\n\ + --endian={big|little} swap input bytes according the specified order\n\ -j, --skip-bytes=BYTES skip BYTES input bytes first\n\ "), stdout); fputs (_("\ -N, --read-bytes=BYTES limit dump to BYTES input bytes\n\ - -S BYTES, --strings[=BYTES] output strings of at least BYTES graphic chars.\ + -S BYTES, --strings[=BYTES] output strings of at least BYTES graphic chars;\ \n\ 3 is implied when BYTES is not specified\n\ -t, --format=TYPE select output format or formats\n\ -v, --output-duplicates do not use * to mark line suppression\n\ - -w[BYTES], --width[=BYTES] output BYTES bytes per output line.\n\ + -w[BYTES], --width[=BYTES] output BYTES bytes per output line;\n\ 32 is implied when BYTES is not specified\n\ --traditional accept arguments in third form above\n\ "), stdout); @@ -339,7 +366,7 @@ suffixes may be . for octal and b for multiply by 512.\n\ Traditional format specifications may be intermixed; they accumulate:\n\ -a same as -t a, select named characters, ignoring high-order bit\n\ -b same as -t o1, select octal bytes\n\ - -c same as -t c, select ASCII characters or backslash escapes\n\ + -c same as -t c, select printable characters or backslash escapes\n\ -d same as -t u2, select unsigned decimal 2-byte units\n\ "), stdout); fputs (_("\ @@ -355,7 +382,7 @@ Traditional format specifications may be intermixed; they accumulate:\n\ \n\ TYPE is made up of one or more of these specifications:\n\ a named character, ignoring high-order bit\n\ - c ASCII character or backslash escape\n\ + c printable character or backslash escape\n\ "), stdout); fputs (_("\ d[SIZE] signed decimal, SIZE bytes per integer\n\ @@ -400,13 +427,27 @@ N (size_t fields, size_t blank, void const *block, \ char const *FMT_STRING, int width, int pad) \ { \ T const *p = block; \ - size_t i; \ + uintmax_t i; \ int pad_remaining = pad; \ for (i = fields; blank < i; i--) \ { \ int next_pad = pad * (i - 1) / fields; \ int adjusted_width = pad_remaining - next_pad + width; \ - T x = *p++; \ + T x; \ + if (input_swap && sizeof (T) > 1) \ + { \ + size_t j; \ + union { \ + T x; \ + char b[sizeof (T)]; \ + } u; \ + for (j = 0; j < sizeof (T); j++) \ + u.b[j] = ((const char *) p)[sizeof (T) - 1 - j]; \ + x = u.x; \ + } \ + else \ + x = *p; \ + p++; \ ACTION; \ pad_remaining = next_pad; \ } \ @@ -416,7 +457,7 @@ N (size_t fields, size_t blank, void const *block, \ PRINT_FIELDS (N, T, fmt_string, xprintf (fmt_string, adjusted_width, x)) #define PRINT_FLOATTYPE(N, T, FTOASTR, BUFSIZE) \ - PRINT_FIELDS (N, T, fmt_string ATTRIBUTE_UNUSED, \ + PRINT_FIELDS (N, T, fmt_string _GL_UNUSED, \ char buf[BUFSIZE]; \ FTOASTR (buf, sizeof buf, 0, 0, x); \ xprintf ("%*s", adjusted_width, buf)) @@ -452,11 +493,11 @@ dump_hexl_mode_trailer (size_t n_bytes, const char *block) static void print_named_ascii (size_t fields, size_t blank, void const *block, - const char *unused_fmt_string ATTRIBUTE_UNUSED, + const char *unused_fmt_string _GL_UNUSED, int width, int pad) { unsigned char const *p = block; - size_t i; + uintmax_t i; int pad_remaining = pad; for (i = fields; blank < i; i--) { @@ -483,11 +524,11 @@ print_named_ascii (size_t fields, size_t blank, void const *block, static void print_ascii (size_t fields, size_t blank, void const *block, - const char *unused_fmt_string ATTRIBUTE_UNUSED, int width, + const char *unused_fmt_string _GL_UNUSED, int width, int pad) { unsigned char const *p = block; - size_t i; + uintmax_t i; int pad_remaining = pad; for (i = fields; blank < i; i--) { @@ -1056,8 +1097,8 @@ skip (uintmax_t n_skip) } static void -format_address_none (uintmax_t address ATTRIBUTE_UNUSED, - char c ATTRIBUTE_UNUSED) +format_address_none (uintmax_t address _GL_UNUSED, + char c _GL_UNUSED) { } @@ -1664,6 +1705,18 @@ main (int argc, char **argv) traditional = true; break; + case ENDIAN_OPTION: + switch (XARGMATCH ("--endian", optarg, endian_args, endian_types)) + { + case endian_big: + input_swap = ! WORDS_BIGENDIAN; + break; + case endian_little: + input_swap = WORDS_BIGENDIAN; + break; + } + break; + /* The next several cases map the traditional format specification options to the corresponding modern format specs. GNU od accepts any combination of old- and diff --git a/src/operand2sig.c b/src/operand2sig.c index 6936f1d2..eb40f364 100644 --- a/src/operand2sig.c +++ b/src/operand2sig.c @@ -1,5 +1,5 @@ /* operand2sig.c -- common function for parsing signal specifications - Copyright (C) 2008-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2014 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 diff --git a/src/operand2sig.h b/src/operand2sig.h index 4a799176..04d27d1a 100644 --- a/src/operand2sig.h +++ b/src/operand2sig.h @@ -1,6 +1,6 @@ /* operand2sig.h -- prototype for signal specification function - Copyright (C) 2008-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2014 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 diff --git a/src/paste.c b/src/paste.c index bc9fa76c..3663aaf6 100644 --- a/src/paste.c +++ b/src/paste.c @@ -1,5 +1,5 @@ /* paste - merge lines of files - Copyright (C) 1997-2013 Free Software Foundation, Inc. + Copyright (C) 1997-2014 Free Software Foundation, Inc. Copyright (C) 1984 David M. Ihnat This program is free software: you can redistribute it and/or modify @@ -62,7 +62,7 @@ static bool have_read_stdin; corresponding lines from each file in parallel. */ static bool serial_merge; -/* The delimeters between lines of input files (used cyclically). */ +/* The delimiters between lines of input files (used cyclically). */ static char *delims; /* A pointer to the character after the end of 'delims'. */ diff --git a/src/pathchk.c b/src/pathchk.c index 28567d08..4b3884fe 100644 --- a/src/pathchk.c +++ b/src/pathchk.c @@ -1,5 +1,5 @@ /* pathchk -- check whether file names are valid or portable - Copyright (C) 1991-2013 Free Software Foundation, Inc. + Copyright (C) 1991-2014 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 diff --git a/src/pinky.c b/src/pinky.c index e6838ae6..c48e1705 100644 --- a/src/pinky.c +++ b/src/pinky.c @@ -1,5 +1,5 @@ /* GNU's pinky. - Copyright (C) 1992-2013 Free Software Foundation, Inc. + Copyright (C) 1992-2014 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 @@ -466,12 +466,14 @@ short_pinky (const char *filename, const int argc_names, char *const argv_names[]) { size_t n_users; - STRUCT_UTMP *utmp_buf; + STRUCT_UTMP *utmp_buf = NULL; if (read_utmp (filename, &n_users, &utmp_buf, 0) != 0) error (EXIT_FAILURE, errno, "%s", filename); scan_entries (n_users, utmp_buf, argc_names, argv_names); + + IF_LINT (free (utmp_buf)); } static void @@ -1,5 +1,5 @@ /* pr -- convert text files for printing. - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 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 @@ -2820,7 +2820,8 @@ Paginate or columnate FILE(s) for printing.\n\ fputs (_("\ -s[CHAR], --separator[=CHAR]\n\ separate columns by a single character, default for CHAR\n\ - is the <TAB> character without -w and \'no char\' with -w\n\ + is the <TAB> 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); diff --git a/src/printenv.c b/src/printenv.c index 066649d3..e1faeb5f 100644 --- a/src/printenv.c +++ b/src/printenv.c @@ -1,5 +1,5 @@ /* printenv -- print all or part of environment - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -67,7 +67,7 @@ If no VARIABLE is specified, print name and value pairs for them all.\n\ "), program_name); fputs (_("\ - -0, --null end each output line with 0 byte rather than newline\n\ + -0, --null end each output line with NUL, not newline\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); diff --git a/src/printf.c b/src/printf.c index fd795a3d..7d523100 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1,5 +1,5 @@ /* printf - format and print data - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 diff --git a/src/prog-fprintf.c b/src/prog-fprintf.c index e800f867..4d3b449f 100644 --- a/src/prog-fprintf.c +++ b/src/prog-fprintf.c @@ -1,5 +1,5 @@ /* prog-fprintf.c - common formating output functions and definitions - Copyright (C) 2008-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2014 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 diff --git a/src/prog-fprintf.h b/src/prog-fprintf.h index 10282f07..93df75a7 100644 --- a/src/prog-fprintf.h +++ b/src/prog-fprintf.h @@ -1,5 +1,5 @@ /* prog-fprintf.h - common formating output functions and definitions - Copyright (C) 2008-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2014 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 @@ -1,5 +1,5 @@ /* Permuted index for GNU, with keywords in their context. - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 Free Software Foundation, Inc. François Pinard <pinard@iro.umontreal.ca>, 1988. This program is free software: you can redistribute it and/or modify @@ -166,7 +166,7 @@ static int total_line_count; /* total number of lines seen so far */ static const char **input_file_name; /* array of text input file names */ static int *file_line_count; /* array of 'total_line_count' values at end */ -static BLOCK text_buffer; /* file to study */ +static BLOCK *text_buffers; /* files to study */ /* SKIP_NON_WHITE used only for getting or skipping the reference. */ @@ -232,6 +232,7 @@ typedef struct DELTA left; /* distance to left context start */ DELTA right; /* distance to right context end */ int reference; /* reference descriptor */ + size_t file_index; /* corresponding file */ } OCCURS; @@ -744,7 +745,7 @@ digest_word_file (const char *file_name, WORD_TABLE *table) `----------------------------------------------------------------------*/ static void -find_occurs_in_text (void) +find_occurs_in_text (size_t file_index) { char *cursor; /* for scanning the source text */ char *scan; /* for scanning the source text also */ @@ -760,6 +761,8 @@ find_occurs_in_text (void) char *word_end; /* end of word */ char *next_context_start; /* next start of left context */ + const BLOCK *text_buffer = &text_buffers[file_index]; + /* reference_length is always used within 'if (input_reference)'. However, GNU C diagnoses that it may be used uninitialized. The following assignment is merely to shut it up. */ @@ -775,19 +778,19 @@ find_occurs_in_text (void) found inside it. Also, unconditionally assigning these variable has the happy effect of shutting up lint. */ - line_start = text_buffer.start; + line_start = text_buffer->start; line_scan = line_start; if (input_reference) { - SKIP_NON_WHITE (line_scan, text_buffer.end); + SKIP_NON_WHITE (line_scan, text_buffer->end); reference_length = line_scan - line_start; - SKIP_WHITE (line_scan, text_buffer.end); + SKIP_WHITE (line_scan, text_buffer->end); } /* Process the whole buffer, one line or one sentence at a time. */ - for (cursor = text_buffer.start; - cursor < text_buffer.end; + for (cursor = text_buffer->start; + cursor < text_buffer->end; cursor = next_context_start) { @@ -805,11 +808,11 @@ find_occurs_in_text (void) This test also accounts for the case of an incomplete line or sentence at the end of the buffer. */ - next_context_start = text_buffer.end; + next_context_start = text_buffer->end; if (context_regex.string) switch (re_search (&context_regex.pattern, cursor, - text_buffer.end - cursor, - 0, text_buffer.end - cursor, &context_regs)) + text_buffer->end - cursor, + 0, text_buffer->end - cursor, &context_regs)) { case -2: matcher_error (); @@ -915,7 +918,7 @@ find_occurs_in_text (void) total_line_count++; line_scan++; line_start = line_scan; - SKIP_NON_WHITE (line_scan, text_buffer.end); + SKIP_NON_WHITE (line_scan, text_buffer->end); reference_length = line_scan - line_start; } else @@ -956,7 +959,7 @@ find_occurs_in_text (void) occurs_cursor = occurs_table[0] + number_of_occurs[0]; - /* Define the refence field, if any. */ + /* Define the reference field, if any. */ if (auto_reference) { @@ -973,7 +976,7 @@ find_occurs_in_text (void) total_line_count++; line_scan++; line_start = line_scan; - SKIP_NON_WHITE (line_scan, text_buffer.end); + SKIP_NON_WHITE (line_scan, text_buffer->end); } else line_scan++; @@ -1007,6 +1010,7 @@ find_occurs_in_text (void) occurs_cursor->key = possible_key; occurs_cursor->left = context_start - possible_key.start; occurs_cursor->right = context_end - possible_key.start; + occurs_cursor->file_index = file_index; number_of_occurs[0]++; } @@ -1356,9 +1360,10 @@ define_all_fields (OCCURS *occurs) char *left_context_start; /* start of left context */ char *right_context_end; /* end of right context */ char *left_field_start; /* conservative start for 'head'/'before' */ - int file_index; /* index in text input file arrays */ const char *file_name; /* file name for reference */ int line_ordinal; /* line ordinal for reference */ + const char *buffer_start; /* start of buffered file for this occurs */ + const char *buffer_end; /* end of buffered file for this occurs */ /* Define 'keyafter', start of left context and end of right context. 'keyafter' starts at the saved position for keyword and extend to the @@ -1371,6 +1376,9 @@ define_all_fields (OCCURS *occurs) left_context_start = keyafter.start + occurs->left; right_context_end = keyafter.start + occurs->right; + buffer_start = text_buffers[occurs->file_index].start; + buffer_end = text_buffers[occurs->file_index].end; + cursor = keyafter.end; while (cursor < right_context_end && cursor <= keyafter.start + keyafter_max_width) @@ -1422,13 +1430,13 @@ define_all_fields (OCCURS *occurs) if (truncation_string) { cursor = before.start; - SKIP_WHITE_BACKWARDS (cursor, text_buffer.start); + SKIP_WHITE_BACKWARDS (cursor, buffer_start); before_truncation = cursor > left_context_start; } else before_truncation = 0; - SKIP_WHITE (before.start, text_buffer.end); + SKIP_WHITE (before.start, buffer_end); /* The tail could not take more columns than what has been left in the left context field, and a gap is mandatory. It starts after the @@ -1443,7 +1451,7 @@ define_all_fields (OCCURS *occurs) if (tail_max_width > 0) { tail.start = keyafter.end; - SKIP_WHITE (tail.start, text_buffer.end); + SKIP_WHITE (tail.start, buffer_end); tail.end = tail.start; cursor = tail.end; @@ -1489,7 +1497,7 @@ define_all_fields (OCCURS *occurs) if (head_max_width > 0) { head.end = before.start; - SKIP_WHITE_BACKWARDS (head.end, text_buffer.start); + SKIP_WHITE_BACKWARDS (head.end, buffer_start); head.start = left_field_start; while (head.start + head_max_width < head.end) @@ -1520,21 +1528,16 @@ define_all_fields (OCCURS *occurs) { /* Construct the reference text in preallocated space from the file - name and the line number. Find out in which file the reference - occurred. Standard input yields an empty file name. Insure line - numbers are one based, even if they are computed zero based. */ + name and the line number. Standard input yields an empty file name. + Ensure line numbers are 1 based, even if they are computed 0 based. */ - file_index = 0; - while (file_line_count[file_index] < occurs->reference) - file_index++; - - file_name = input_file_name[file_index]; + file_name = input_file_name[occurs->file_index]; if (!file_name) file_name = ""; line_ordinal = occurs->reference + 1; - if (file_index > 0) - line_ordinal -= file_line_count[file_index - 1]; + if (occurs->file_index > 0) + line_ordinal -= file_line_count[occurs->file_index - 1]; sprintf (reference.start, "%s:%d", file_name, line_ordinal); reference.end = reference.start + strlen (reference.start); @@ -1853,7 +1856,7 @@ Output a permuted index, including context, of the words in the input files.\n\ fputs (VERSION_OPTION_DESCRIPTION, stdout); fputs (_("\ \n\ -With no FILE or if FILE is -, read Standard Input. '-F /' by default.\n\ +With no FILE, or when FILE is -, read standard input. Default is '-F /'.\n\ "), stdout); emit_ancillary_info (); } @@ -2015,6 +2018,8 @@ main (int argc, char **argv) case 10: output_format = XARGMATCH ("--format", optarg, format_args, format_vals); + break; + case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -2032,6 +2037,7 @@ main (int argc, char **argv) input_file_name = xmalloc (sizeof *input_file_name); file_line_count = xmalloc (sizeof *file_line_count); + text_buffers = xmalloc (sizeof *text_buffers); number_input_files = 1; input_file_name[0] = NULL; } @@ -2040,6 +2046,7 @@ main (int argc, char **argv) number_input_files = argc - optind; input_file_name = xmalloc (number_input_files * sizeof *input_file_name); file_line_count = xmalloc (number_input_files * sizeof *file_line_count); + text_buffers = xmalloc (number_input_files * sizeof *text_buffers); for (file_index = 0; file_index < number_input_files; file_index++) { @@ -2058,6 +2065,7 @@ main (int argc, char **argv) number_input_files = 1; input_file_name = xmalloc (sizeof *input_file_name); file_line_count = xmalloc (sizeof *file_line_count); + text_buffers = xmalloc (sizeof *text_buffers); if (!*argv[optind] || STREQ (argv[optind], "-")) input_file_name[0] = NULL; else @@ -2124,11 +2132,12 @@ main (int argc, char **argv) for (file_index = 0; file_index < number_input_files; file_index++) { + BLOCK *text_buffer = text_buffers + file_index; - /* Read the file in core, than study it. */ + /* Read the file in core, then study it. */ - swallow_file_in_memory (input_file_name[file_index], &text_buffer); - find_occurs_in_text (); + swallow_file_in_memory (input_file_name[file_index], text_buffer); + find_occurs_in_text (file_index); /* Maintain for each file how many lines has been read so far when its end is reached. Incrementing the count first is a simple kludge to @@ -1,5 +1,5 @@ /* pwd - print current directory - Copyright (C) 1994-2013 Free Software Foundation, Inc. + Copyright (C) 1994-2014 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 @@ -64,6 +64,9 @@ Print the full filename of the current working directory.\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\n\ +If no option is specified, -P is assumed.\n\ +"), stdout); printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME); emit_ancillary_info (); } @@ -324,7 +327,9 @@ int main (int argc, char **argv) { char *wd; - /* POSIX requires a default of -L, but most scripts expect -P. */ + /* POSIX requires a default of -L, but most scripts expect -P. + Currently shells default to -L, while stand-alone + pwd implementations default to -P. */ bool logical = (getenv ("POSIXLY_CORRECT") != NULL); initialize_main (&argc, &argv); diff --git a/src/readlink.c b/src/readlink.c index 665a25cf..f46d948e 100644 --- a/src/readlink.c +++ b/src/readlink.c @@ -1,5 +1,5 @@ /* readlink -- display value of a symbolic link. - Copyright (C) 2002-2013 Free Software Foundation, Inc. + Copyright (C) 2002-2014 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 @@ -81,7 +81,7 @@ usage (int status) -q, --quiet,\n\ -s, --silent suppress most error messages\n\ -v, --verbose report error messages\n\ - -z, --zero separate output with NUL rather than newline\n\ + -z, --zero end each output line with NUL, not newline\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -174,5 +174,5 @@ main (int argc, char **argv) } } - return status; + exit (status); } diff --git a/src/realpath.c b/src/realpath.c index 292c8f3b..0c553271 100644 --- a/src/realpath.c +++ b/src/realpath.c @@ -1,5 +1,5 @@ /* realpath - print the resolved path - Copyright (C) 2011-2013 Free Software Foundation, Inc. + Copyright (C) 2011-2014 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 @@ -51,7 +51,7 @@ static struct option const longopts[] = {"relative-to", required_argument, NULL, RELATIVE_TO_OPTION}, {"relative-base", required_argument, NULL, RELATIVE_BASE_OPTION}, {"quiet", no_argument, NULL, 'q'}, - {"strip", no_argument, NULL, 's' /* FIXME: deprecate in 2013 or so */}, + {"strip", no_argument, NULL, 's'}, {"no-symlinks", no_argument, NULL, 's'}, {"zero", no_argument, NULL, 'z'}, {"logical", no_argument, NULL, 'L'}, @@ -83,7 +83,7 @@ all but the last component must exist\n\ --relative-to=FILE print the resolved path relative to FILE\n\ --relative-base=FILE print absolute paths unless paths below FILE\n\ -s, --strip, --no-symlinks don't expand symlinks\n\ - -z, --zero separate output with NUL rather than newline\n\ + -z, --zero end each output line with NUL, not newline\n\ \n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); diff --git a/src/relpath.c b/src/relpath.c index 5a93afe4..29472e57 100644 --- a/src/relpath.c +++ b/src/relpath.c @@ -1,5 +1,5 @@ /* relpath - print the relative path - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2014 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 diff --git a/src/relpath.h b/src/relpath.h index 0439d330..9017653a 100644 --- a/src/relpath.h +++ b/src/relpath.h @@ -1,5 +1,5 @@ /* relpath - print the relative path - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2014 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 diff --git a/src/remove.c b/src/remove.c index cdbbec5b..4cc4a081 100644 --- a/src/remove.c +++ b/src/remove.c @@ -1,5 +1,5 @@ /* remove.c -- core functions for removing files and directories - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 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 @@ -283,10 +283,11 @@ prompt (FTS const *fts, FTSENT const *ent, bool is_dir, fprintf (stderr, (write_protected - /* TRANSLATORS: You may find it more convenient to - translate "%s: remove %s (write-protected) %s? " - instead. It should avoid grammatical problems - with the output of file_type. */ + /* TRANSLATORS: In the next two strings the second %s is + replaced by the type of the file. To avoid grammatical + problems, it may be more convenient to translate these + strings instead as: "%1$s: %3$s is write-protected and + is of type '%2$s' -- remove it? ". */ ? _("%s: remove write-protected %s %s? ") : _("%s: remove %s %s? ")), program_name, file_type (sbuf), quoted_name); @@ -437,17 +438,21 @@ rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x) /* Perform checks that can apply only for command-line arguments. */ if (ent->fts_level == FTS_ROOTLEVEL) { - /* If the basename of a command line argument is "." or "..", + /* POSIX says: + If the basename of a command line argument is "." or "..", diagnose it and do nothing more with that argument. */ if (dot_or_dotdot (last_component (ent->fts_accpath))) { - error (0, 0, _("cannot remove directory: %s"), - quote (ent->fts_path)); + error (0, 0, + _("refusing to remove %s or %s directory: skipping %s"), + quote_n (0, "."), quote_n (1, ".."), + quote_n (2, ent->fts_path)); fts_skip_tree (fts, ent); return RM_ERROR; } - /* If a command line argument resolves to "/" (and --preserve-root + /* POSIX also says: + If a command line argument resolves to "/" (and --preserve-root is in effect -- default) diagnose and skip it. */ if (ROOT_DEV_INO_CHECK (x->root_dev_ino, ent->fts_statp)) { diff --git a/src/remove.h b/src/remove.h index 9ac54d43..2563553d 100644 --- a/src/remove.h +++ b/src/remove.h @@ -1,6 +1,6 @@ /* Remove directory entries. - Copyright (C) 1998-2013 Free Software Foundation, Inc. + Copyright (C) 1998-2014 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 @@ -1,5 +1,5 @@ /* 'rm' file deletion utility for GNU. - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 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 @@ -141,10 +141,10 @@ Remove (unlink) the FILE(s).\n\ "), stdout); fputs (_("\ -I prompt once before removing more than three files, or\n\ - when removing recursively. Less intrusive than -i,\n\ + when removing recursively; less intrusive than -i,\n\ while still giving protection against most mistakes\n\ --interactive[=WHEN] prompt according to WHEN: never, once (-I), or\n\ - always (-i). Without WHEN, prompt always\n\ + always (-i); without WHEN, prompt always\n\ "), stdout); fputs (_("\ --one-file-system when removing a hierarchy recursively, skip any\n\ @@ -244,7 +244,7 @@ main (int argc, char **argv) break; case 'I': - x.interactive = RMI_NEVER; + x.interactive = RMI_SOMETIMES; x.ignore_missing_files = false; prompt_once = true; break; @@ -339,9 +339,13 @@ main (int argc, char **argv) { fprintf (stderr, (x.recursive - ? _("%s: remove all arguments recursively? ") - : _("%s: remove all arguments? ")), - program_name); + ? ngettext ("%s: remove %zu argument recursively? ", + "%s: remove %zu arguments recursively? ", + select_plural (n_files)) + : ngettext ("%s: remove %zu argument? ", + "%s: remove %zu arguments? ", + select_plural (n_files))), + program_name, n_files); if (!yesno ()) exit (EXIT_SUCCESS); } diff --git a/src/rmdir.c b/src/rmdir.c index 81ef2a99..e67d3b00 100644 --- a/src/rmdir.c +++ b/src/rmdir.c @@ -1,6 +1,6 @@ /* rmdir -- remove directories - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 diff --git a/src/runcon.c b/src/runcon.c index 8a0b34e9..14ccc3d5 100644 --- a/src/runcon.c +++ b/src/runcon.c @@ -1,5 +1,5 @@ /* runcon -- run command with specified security context - Copyright (C) 2005-2013 Free Software Foundation, Inc. + Copyright (C) 2005-2014 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 @@ -85,7 +85,7 @@ Usage: %s CONTEXT COMMAND [args]\n\ or: %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\ "), program_name, program_name); fputs (_("\ -Run a program in a different security context.\n\ +Run a program in a different SELinux security context.\n\ With neither CONTEXT nor COMMAND, print the current security context.\n\ "), stdout); @@ -115,9 +115,9 @@ main (int argc, char **argv) char *user = NULL; char *type = NULL; char *context = NULL; - security_context_t cur_context = NULL; - security_context_t file_context = NULL; - security_context_t new_context = NULL; + char *cur_context = NULL; + char *file_context = NULL; + char *new_context = NULL; bool compute_trans = false; context_t con; @@ -197,8 +197,8 @@ main (int argc, char **argv) } if (is_selinux_enabled () != 1) - error (EXIT_FAILURE, 0, - _("%s may be used only on a SELinux kernel"), program_name); + error (EXIT_FAILURE, 0, _("%s may be used only on a SELinux kernel"), + program_name); if (context) { @@ -223,8 +223,7 @@ main (int argc, char **argv) /* compute result of process transition */ if (security_compute_create (cur_context, file_context, SECCLASS_PROCESS, &new_context) != 0) - error (EXIT_FAILURE, errno, - _("failed to compute a new context")); + error (EXIT_FAILURE, errno, _("failed to compute a new context")); /* free contexts */ freecon (file_context); freecon (cur_context); diff --git a/src/selinux.c b/src/selinux.c new file mode 100644 index 00000000..ae454f8a --- /dev/null +++ b/src/selinux.c @@ -0,0 +1,341 @@ +/* selinux - core functions for maintaining SELinux labeling + Copyright (C) 2012-2014 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 <http://www.gnu.org/licenses/>. */ + +/* Written by Daniel Walsh <dwalsh@redhat.com> */ + +#include <config.h> +#include <selinux/selinux.h> +#include <selinux/context.h> +#include <sys/types.h> + +#include "error.h" +#include "system.h" +#include "canonicalize.h" +#include "dosname.h" +#include "xfts.h" +#include "quote.h" +#include "selinux.h" + +#if HAVE_SELINUX_SELINUX_H + +# if ! HAVE_MODE_TO_SECURITY_CLASS +/* + This function has been added to libselinux-2.1.12-5, but is here + for support with older versions of SELinux + + Translates a mode into an Internal SELinux security_class definition. + Returns 0 on failure, with errno set to EINVAL. +*/ +static security_class_t +mode_to_security_class (mode_t m) +{ + + if (S_ISREG (m)) + return string_to_security_class ("file"); + if (S_ISDIR (m)) + return string_to_security_class ("dir"); + if (S_ISCHR (m)) + return string_to_security_class ("chr_file"); + if (S_ISBLK (m)) + return string_to_security_class ("blk_file"); + if (S_ISFIFO (m)) + return string_to_security_class ("fifo_file"); + if (S_ISLNK (m)) + return string_to_security_class ("lnk_file"); + if (S_ISSOCK (m)) + return string_to_security_class ("sock_file"); + + errno = EINVAL; + return 0; +} +# endif + +/* + This function takes a PATH and a MODE and then asks SELinux what the label + of the path object would be if the current process label created it. + It then returns the label. + + Returns -1 on failure. errno will be set appropriately. +*/ + +static int +computecon (char const *path, mode_t mode, char **con) +{ + char *scon = NULL; + char *tcon = NULL; + security_class_t tclass; + int rc = -1; + + char *dir = dir_name (path); + if (!dir) + goto quit; + if (getcon (&scon) < 0) + goto quit; + if (getfilecon (dir, &tcon) < 0) + goto quit; + tclass = mode_to_security_class (mode); + if (!tclass) + goto quit; + rc = security_compute_create (scon, tcon, tclass, con); + +quit: + free (dir); + freecon (scon); + freecon (tcon); + return rc; +} + +/* + This function takes a path and a mode, it calls computecon to get the + label of the path object if the current process created it, then it calls + matchpathcon to get the default type for the object. It substitutes the + default type into label. It tells the SELinux Kernel to label all new file + system objects created by the current process with this label. + + Returns -1 on failure. errno will be set appropriately. +*/ +int +defaultcon (char const *path, mode_t mode) +{ + int rc = -1; + char *scon = NULL; + char *tcon = NULL; + context_t scontext = 0, tcontext = 0; + const char *contype; + char *constr; + char *newpath = NULL; + + if (! IS_ABSOLUTE_FILE_NAME (path)) + { + /* Generate absolute path as required by subsequent matchpathcon(), + with libselinux < 2.1.5 2011-0826. */ + newpath = canonicalize_filename_mode (path, CAN_MISSING); + if (! newpath) + error (EXIT_FAILURE, errno, _("error canonicalizing %s"), + quote (path)); + path = newpath; + } + + if (matchpathcon (path, mode, &scon) < 0) + { + /* "No such file or directory" is a confusing error, + when processing files, when in fact it was the + associated default context that was not found. + Therefore map the error to something more appropriate + to the context in which we're using matchpathcon(). */ + if (errno == ENOENT) + errno = ENODATA; + goto quit; + } + if (computecon (path, mode, &tcon) < 0) + goto quit; + if (!(scontext = context_new (scon))) + goto quit; + if (!(tcontext = context_new (tcon))) + goto quit; + + if (!(contype = context_type_get (scontext))) + goto quit; + if (context_type_set (tcontext, contype)) + goto quit; + if (!(constr = context_str (tcontext))) + goto quit; + + rc = setfscreatecon (constr); + +quit: + context_free (scontext); + context_free (tcontext); + freecon (scon); + freecon (tcon); + free (newpath); + return rc; +} + +/* + This function takes a PATH of an existing file system object, and a LOCAL + boolean that indicates whether the function should set the object's label + to the default for the local process, or one using system wide settings. + If LOCAL == true, it will ask the SELinux Kernel what the default label + for all objects created should be and then sets the label on the object. + Otherwise it calls matchpathcon on the object to ask the system what the + default label should be, extracts the type field and then modifies the file + system object. Note only the type field is updated, thus preserving MLS + levels and user identity etc. of the PATH. + + Returns -1 on failure. errno will be set appropriately. +*/ +static int +restorecon_private (char const *path, bool local) +{ + int rc = -1; + struct stat sb; + char *scon = NULL; + char *tcon = NULL; + context_t scontext = 0, tcontext = 0; + const char *contype; + char *constr; + int fd; + + if (local) + { + if (getfscreatecon (&tcon) < 0) + return rc; + if (!tcon) + { + errno = ENODATA; + return rc; + } + rc = lsetfilecon (path, tcon); + freecon (tcon); + return rc; + } + + fd = open (path, O_RDONLY | O_NOFOLLOW); + if (fd == -1 && (errno != ELOOP)) + goto quit; + + if (fd != -1) + { + if (fstat (fd, &sb) < 0) + goto quit; + } + else + { + if (lstat (path, &sb) < 0) + goto quit; + } + + if (matchpathcon (path, sb.st_mode, &scon) < 0) + { + /* "No such file or directory" is a confusing error, + when processing files, when in fact it was the + associated default context that was not found. + Therefore map the error to something more appropriate + to the context in which we're using matchpathcon(). */ + if (errno == ENOENT) + errno = ENODATA; + goto quit; + } + if (!(scontext = context_new (scon))) + goto quit; + + if (fd != -1) + { + if (fgetfilecon (fd, &tcon) < 0) + goto quit; + } + else + { + if (lgetfilecon (path, &tcon) < 0) + goto quit; + } + + if (!(tcontext = context_new (tcon))) + goto quit; + + if (!(contype = context_type_get (scontext))) + goto quit; + if (context_type_set (tcontext, contype)) + goto quit; + if (!(constr = context_str (tcontext))) + goto quit; + + if (fd != -1) + rc = fsetfilecon (fd, constr); + else + rc = lsetfilecon (path, constr); + +quit: + if (fd != -1) + close (fd); + context_free (scontext); + context_free (tcontext); + freecon (scon); + freecon (tcon); + return rc; +} + +/* + This function takes three parameters: + + PATH of an existing file system object. + + A RECURSE boolean which if the file system object is a directory, will + call restorecon_private on every file system object in the directory. + + A LOCAL boolean that indicates whether the function should set object labels + to the default for the local process, or use system wide settings. + + Returns false on failure. errno will be set appropriately. +*/ +bool +restorecon (char const *path, bool recurse, bool local) +{ + char *newpath = NULL; + FTS *fts; + bool ok = true; + + if (! IS_ABSOLUTE_FILE_NAME (path) && ! local) + { + /* Generate absolute path as required by subsequent matchpathcon(), + with libselinux < 2.1.5 2011-0826. Also generating the absolute + path before the fts walk, will generate absolute paths in the + fts entries, which may be quicker to process in any case. */ + newpath = canonicalize_filename_mode (path, CAN_MISSING); + if (! newpath) + error (EXIT_FAILURE, errno, _("error canonicalizing %s"), + quote (path)); + } + + const char *ftspath[2] = { newpath ? newpath : path, NULL }; + + if (! recurse) + { + ok = restorecon_private (*ftspath, local) != -1; + free (newpath); + return ok; + } + + fts = xfts_open ((char *const *) ftspath, FTS_PHYSICAL, NULL); + while (1) + { + FTSENT *ent; + + ent = fts_read (fts); + if (ent == NULL) + { + if (errno != 0) + { + error (0, errno, _("fts_read failed")); + ok = false; + } + break; + } + + ok &= restorecon_private (fts->fts_path, local) != -1; + } + + if (fts_close (fts) != 0) + { + error (0, errno, _("fts_close failed")); + ok = false; + } + + free (newpath); + return ok; +} +#endif diff --git a/src/selinux.h b/src/selinux.h new file mode 100644 index 00000000..8afaa495 --- /dev/null +++ b/src/selinux.h @@ -0,0 +1,47 @@ +/* selinux - core functions for maintaining SELinux labeling + Copyright (C) 2012-2014 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 <http://www.gnu.org/licenses/>. */ + +/* Written by Daniel Walsh <dwalsh@redhat.com> */ + +#ifndef COREUTILS_SELINUX_H +# define COREUTILS_SELINUX_H + +/* Return true if ERR corresponds to an unsupported request, + or if there is no context or it's inaccessible. */ +static inline bool +ignorable_ctx_err (int err) +{ + return err == ENOTSUP || err == ENODATA; +} + +# if HAVE_SELINUX_SELINUX_H + +extern bool restorecon (char const *path, bool recurse, bool preserve); +extern int defaultcon (char const *path, mode_t mode); + +# else + +static inline bool +restorecon (char const *path, bool recurse, bool preserve) +{ errno = ENOTSUP; return false; } + +static inline int +defaultcon (char const *path, mode_t mode) +{ errno = ENOTSUP; return -1; } + +# endif + +#endif @@ -1,5 +1,5 @@ /* seq - print sequence of numbers to standard output. - Copyright (C) 1994-2013 Free Software Foundation, Inc. + Copyright (C) 1994-2014 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 @@ -87,6 +87,8 @@ Print numbers from FIRST to LAST, in steps of INCREMENT.\n\ \n\ If FIRST or INCREMENT is omitted, it defaults to 1. That is, an\n\ omitted INCREMENT defaults to 1 even when LAST is smaller than FIRST.\n\ +The sequence of numbers ends when the sum of the current number and\n\ +INCREMENT would become greater than LAST.\n\ FIRST, INCREMENT, and LAST are interpreted as floating point values.\n\ INCREMENT is usually positive if FIRST is smaller than LAST, and\n\ INCREMENT is usually negative if FIRST is greater than LAST.\n\ @@ -602,7 +604,7 @@ main (int argc, char **argv) if (asprintf (&s2, "%0.Lf", last.value) < 0) xalloc_die (); - if (seq_fast (s1, s2)) + if (*s1 != '-' && *s2 != '-' && seq_fast (s1, s2)) { IF_LINT (free (s1)); IF_LINT (free (s2)); diff --git a/src/setuidgid.c b/src/setuidgid.c deleted file mode 100644 index ed6b65d2..00000000 --- a/src/setuidgid.c +++ /dev/null @@ -1,215 +0,0 @@ -/* setuidgid - run a command with the UID and GID of a specified user - Copyright (C) 2003-2013 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 <http://www.gnu.org/licenses/>. */ - -/* Written by Jim Meyering */ - -#include <config.h> -#include <getopt.h> -#include <stdio.h> -#include <sys/types.h> -#include <pwd.h> -#include <grp.h> - -#include "system.h" - -#include "error.h" -#include "long-options.h" -#include "mgetgroups.h" -#include "quote.h" -#include "xstrtol.h" - -#define PROGRAM_NAME "setuidgid" - -/* I wrote this program from scratch, based on the description of - D.J. Bernstein's program: http://cr.yp.to/daemontools/setuidgid.html. */ -#define AUTHORS proper_name ("Jim Meyering") - -#define SETUIDGID_FAILURE 111 - -void -usage (int status) -{ - if (status != EXIT_SUCCESS) - emit_try_help (); - else - { - printf (_("\ -Usage: %s [SHORT-OPTION]... USER COMMAND [ARGUMENT]...\n\ - or: %s LONG-OPTION\n\ -"), - program_name, program_name); - - fputs (_("\ -Drop any supplemental groups, assume the user-ID and group-ID of the specified\ -\n\ -USER (numeric ID or user name), and run COMMAND with any specified ARGUMENTs.\n\ -Exit with status 111 if unable to assume the required user and group ID.\n\ -Otherwise, exit with the exit status of COMMAND.\n\ -This program is useful only when run by root (user ID zero).\n\ -\n\ -"), stdout); - fputs (_("\ - -g GID[,GID1...] also set the primary group-ID to the numeric GID, and\n\ - (if specified) supplemental group IDs to GID1, ...\n\ -"), stdout); - fputs (HELP_OPTION_DESCRIPTION, stdout); - fputs (VERSION_OPTION_DESCRIPTION, stdout); - emit_ancillary_info (); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - uid_t uid; - GETGROUPS_T *gids = NULL; - size_t n_gids = 0; - size_t n_gids_allocated = 0; - gid_t primary_gid; - - initialize_main (&argc, &argv); - set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - initialize_exit_failure (SETUIDGID_FAILURE); - atexit (close_stdout); - - parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version, - usage, AUTHORS, (char const *) NULL); - { - int c; - while ((c = getopt_long (argc, argv, "+g:", NULL, NULL)) != -1) - { - switch (c) - { - case 'g': - { - unsigned long int tmp_ul; - char *gr = optarg; - char *ptr; - while (true) - { - if (! (xstrtoul (gr, &ptr, 10, &tmp_ul, NULL) == LONGINT_OK - && tmp_ul <= GID_T_MAX)) - error (SETUIDGID_FAILURE, 0, _("invalid group %s"), - quote (gr)); - if (n_gids == n_gids_allocated) - gids = X2NREALLOC (gids, &n_gids_allocated); - gids[n_gids++] = tmp_ul; - - if (*ptr == '\0') - break; - if (*ptr != ',') - { - error (0, 0, _("invalid group %s"), quote (gr)); - usage (SETUIDGID_FAILURE); - } - gr = ptr + 1; - } - break; - } - - default: - usage (SETUIDGID_FAILURE); - } - } - } - - if (argc <= optind + 1) - { - if (argc < optind + 1) - error (0, 0, _("missing operand")); - else - error (0, 0, _("missing operand after %s"), quote (argv[optind])); - usage (SETUIDGID_FAILURE); - } - - { - const struct passwd *pwd; - unsigned long int tmp_ul; - char *user = argv[optind]; - char *ptr; - bool have_uid = false; - - if (xstrtoul (user, &ptr, 10, &tmp_ul, "") == LONGINT_OK - && tmp_ul <= UID_T_MAX) - { - uid = tmp_ul; - have_uid = true; - } - - if (!have_uid) - { - pwd = getpwnam (user); - if (pwd == NULL) - { - error (0, errno, _("unknown user-ID: %s"), quote (user)); - usage (SETUIDGID_FAILURE); - } - uid = pwd->pw_uid; - } - else if (n_gids == 0) - { - pwd = getpwuid (uid); - if (pwd == NULL) - { - error (0, errno, - _("to use user-ID %s you need to use -g too"), quote (user)); - usage (SETUIDGID_FAILURE); - } - } - -#if HAVE_SETGROUPS - if (n_gids == 0) - { - int n = xgetgroups (pwd->pw_name, pwd->pw_gid, &gids); - if (n <= 0) - error (SETUIDGID_FAILURE, errno, - _("failed to get groups for user %s"), quote (pwd->pw_name)); - n_gids = n; - } - - if (setgroups (n_gids, gids)) - error (SETUIDGID_FAILURE, errno, - _("failed to set supplemental group(s)")); - - primary_gid = gids[0]; -#else - primary_gid = pwd->pw_gid; -#endif - } - - if (setgid (primary_gid)) - error (SETUIDGID_FAILURE, errno, - _("cannot set group-ID to %lu"), (unsigned long int) primary_gid); - - if (setuid (uid)) - error (SETUIDGID_FAILURE, errno, - _("cannot set user-ID to %lu"), (unsigned long int) uid); - - { - char **cmd = argv + optind + 1; - int exit_status; - execvp (*cmd, cmd); - exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE); - - error (0, errno, _("failed to run command %s"), quote (*cmd)); - exit (exit_status); - } -} diff --git a/src/shred.c b/src/shred.c index 9b869cdc..bd88e383 100644 --- a/src/shred.c +++ b/src/shred.c @@ -1,6 +1,6 @@ /* shred.c - overwrite files and devices to make it harder to recover data - Copyright (C) 1999-2013 Free Software Foundation, Inc. + Copyright (C) 1999-2014 Free Software Foundation, Inc. Copyright (C) 1997, 1998, 1999 Colin Plumb. This program is free software: you can redistribute it and/or modify @@ -80,8 +80,12 @@ #include <assert.h> #include <setjmp.h> #include <sys/types.h> +#ifdef __linux__ +# include <sys/mtio.h> +#endif #include "system.h" +#include "argmatch.h" #include "xstrtol.h" #include "error.h" #include "fcntl--.h" @@ -104,12 +108,30 @@ enum { SECTOR_SIZE = 512 }; enum { SECTOR_MASK = SECTOR_SIZE - 1 }; verify (0 < SECTOR_SIZE && (SECTOR_SIZE & SECTOR_MASK) == 0); +enum remove_method +{ + remove_none = 0, /* the default: only wipe data. */ + remove_unlink, /* don't obfuscate name, just unlink. */ + remove_wipe, /* obfuscate name before unlink. */ + remove_wipesync /* obfuscate name, syncing each byte, before unlink. */ +}; + +static char const *const remove_args[] = +{ + "unlink", "wipe", "wipesync", NULL +}; + +static enum remove_method const remove_methods[] = +{ + remove_unlink, remove_wipe, remove_wipesync +}; + struct Options { bool force; /* -f flag: chmod files if necessary */ size_t n_iterations; /* -n flag: Number of iterations */ off_t size; /* -s flag: size of file */ - bool remove_file; /* -u flag: remove file after shredding */ + enum remove_method remove_file; /* -u flag: remove file after shredding */ bool verbose; /* -v flag: Print progress */ bool exact; /* -x flag: Do not round up file size */ bool zero_fill; /* -z flag: Add a final zero pass */ @@ -129,7 +151,7 @@ static struct option const long_opts[] = {"iterations", required_argument, NULL, 'n'}, {"size", required_argument, NULL, 's'}, {"random-source", required_argument, NULL, RANDOM_SOURCE_OPTION}, - {"remove", no_argument, NULL, 'u'}, + {"remove", optional_argument, NULL, 'u'}, {"verbose", no_argument, NULL, 'v'}, {"zero", no_argument, NULL, 'z'}, {GETOPT_HELP_OPTION_DECL}, @@ -159,7 +181,7 @@ for even very expensive hardware probing to recover the data.\n\ -s, --size=N shred this many bytes (suffixes like K, M, G accepted)\n\ "), DEFAULT_PASSES); fputs (_("\ - -u, --remove truncate and remove file after overwriting\n\ + -u, --remove[=HOW] truncate and remove file after overwriting; See below\n\ -v, --verbose show progress\n\ -x, --exact do not round file sizes up to the next full block;\n\ this is the default for non-regular files\n\ @@ -173,8 +195,12 @@ If FILE is -, shred standard output.\n\ \n\ Delete FILE(s) if --remove (-u) is specified. The default is not to remove\n\ the files because it is common to operate on device files like /dev/hda,\n\ -and those files usually should not be removed. When operating on regular\n\ -files, most people use the --remove option.\n\ +and those files usually should not be removed.\n\ +The optional HOW parameter indicates how to remove a directory entry:\n\ +'unlink' => use a standard unlink call.\n\ +'wipe' => also first obfuscate bytes in the name.\n\ +'wipesync' => also sync each obfuscated byte to disk.\n\ +The default mode is 'wipesync', but note it can be expensive.\n\ \n\ "), stdout); fputs (_("\ @@ -222,6 +248,25 @@ to be recovered later.\n\ exit (status); } +/* + * Determine if pattern type is periodic or not. + */ +static bool +periodic_pattern (int type) +{ + if (type <= 0) + return false; + + unsigned char r[3]; + unsigned int bits = type & 0xfff; + + bits |= bits << 12; + r[0] = (bits >> 4) & 255; + r[1] = (bits >> 8) & 255; + r[2] = bits & 255; + + return (r[0] != r[1]) || (r[0] != r[2]); +} /* * Fill a buffer with a fixed pattern. @@ -337,19 +382,43 @@ direct_mode (int fd, bool enable) #endif } +/* Rewind FD; its status is ST. */ +static bool +dorewind (int fd, struct stat const *st) +{ + if (S_ISCHR (st->st_mode)) + { +#ifdef __linux__ + /* In the Linux kernel, lseek does not work on tape devices; it + returns a randomish value instead. Try the low-level tape + rewind operation first. */ + struct mtop op; + op.mt_op = MTREW; + op.mt_count = 1; + if (ioctl (fd, MTIOCTOP, &op) == 0) + return true; +#endif + } + off_t offset = lseek (fd, 0, SEEK_SET); + if (0 < offset) + errno = EINVAL; + return offset == 0; +} + /* - * Do pass number k of n, writing "size" bytes of the given pattern "type" - * to the file descriptor fd. Qname, k and n are passed in only for verbose - * progress message purposes. If n == 0, no progress messages are printed. + * Do pass number K of N, writing *SIZEP bytes of the given pattern TYPE + * to the file descriptor FD. K and N are passed in only for verbose + * progress message purposes. If N == 0, no progress messages are printed. * - * If *sizep == -1, the size is unknown, and it will be filled in as soon - * as writing fails. + * If *SIZEP == -1, the size is unknown, and it will be filled in as soon + * as writing fails with ENOSPC. * * Return 1 on write error, -1 on other error, 0 on success. */ static int -dopass (int fd, char const *qname, off_t *sizep, int type, - struct randread_source *s, unsigned long int k, unsigned long int n) +dopass (int fd, struct stat const *st, char const *qname, off_t *sizep, + int type, struct randread_source *s, + unsigned long int k, unsigned long int n) { off_t size = *sizep; off_t offset; /* Current file posiiton */ @@ -359,37 +428,47 @@ dopass (int fd, char const *qname, off_t *sizep, int type, size_t soff; /* Offset into buffer for next write */ ssize_t ssize; /* Return value from write */ - /* Fill pattern buffer. Aligning it to a 32-bit boundary speeds up randread - in some cases. */ - typedef uint32_t fill_pattern_buffer[3 * 1024]; - union - { - fill_pattern_buffer buffer; - char c[sizeof (fill_pattern_buffer)]; - unsigned char u[sizeof (fill_pattern_buffer)]; - } r; - - off_t sizeof_r = sizeof r; + /* Fill pattern buffer. Aligning it to a page so we can do direct I/O. */ + size_t page_size = getpagesize (); +#define PERIODIC_OUTPUT_SIZE (60 * 1024) +#define NONPERIODIC_OUTPUT_SIZE (64 * 1024) + verify (PERIODIC_OUTPUT_SIZE % 3 == 0); + size_t output_size = periodic_pattern (type) + ? PERIODIC_OUTPUT_SIZE : NONPERIODIC_OUTPUT_SIZE; +#define PAGE_ALIGN_SLOP (page_size - 1) /* So directio works */ +#define FILLPATTERN_SIZE (((output_size + 2) / 3) * 3) /* Multiple of 3 */ +#define PATTERNBUF_SIZE (PAGE_ALIGN_SLOP + FILLPATTERN_SIZE) + void *fill_pattern_mem = xmalloc (PATTERNBUF_SIZE); + unsigned char *pbuf = ptr_align (fill_pattern_mem, page_size); + char pass_string[PASS_NAME_SIZE]; /* Name of current pass */ bool write_error = false; - bool first_write = true; + bool other_error = false; /* Printable previous offset into the file */ char previous_offset_buf[LONGEST_HUMAN_READABLE + 1]; char const *previous_human_offset IF_LINT ( = 0); - if (lseek (fd, 0, SEEK_SET) == -1) + /* As a performance tweak, avoid direct I/O for small sizes, + as it's just a performance rather then security consideration, + and direct I/O can often be unsupported for small non aligned sizes. */ + bool try_without_directio = 0 < size && size < output_size; + if (! try_without_directio) + direct_mode (fd, true); + + if (! dorewind (fd, st)) { error (0, errno, _("%s: cannot rewind"), qname); - return -1; + other_error = true; + goto free_pattern_mem; } /* Constant fill patterns need only be set up once. */ if (type >= 0) { - lim = (0 <= size && size < sizeof_r ? size : sizeof_r); - fillpattern (type, r.u, lim); - passname (r.u, pass_string); + lim = (0 <= size && size < FILLPATTERN_SIZE ? size : FILLPATTERN_SIZE); + fillpattern (type, pbuf, lim); + passname (pbuf, pass_string); } else { @@ -408,8 +487,8 @@ dopass (int fd, char const *qname, off_t *sizep, int type, while (true) { /* How much to write this time? */ - lim = sizeof r; - if (0 <= size && size - offset < sizeof_r) + lim = output_size; + if (0 <= size && size - offset < output_size) { if (size < offset) break; @@ -418,11 +497,11 @@ dopass (int fd, char const *qname, off_t *sizep, int type, break; } if (type < 0) - randread (s, &r, lim); + randread (s, pbuf, lim); /* Loop to retry partial writes. */ - for (soff = 0; soff < lim; soff += ssize, first_write = false) + for (soff = 0; soff < lim; soff += ssize) { - ssize = write (fd, r.c + soff, lim - soff); + ssize = write (fd, pbuf + soff, lim - soff); if (ssize <= 0) { if (size < 0 && (ssize == 0 || errno == ENOSPC)) @@ -436,17 +515,15 @@ dopass (int fd, char const *qname, off_t *sizep, int type, int errnum = errno; char buf[INT_BUFSIZE_BOUND (uintmax_t)]; - /* If the first write of the first pass for a given file - has just failed with EINVAL, turn off direct mode I/O - and try again. This works around a bug in Linux kernel - 2.4 whereby opening with O_DIRECT would succeed for some - file system types (e.g., ext3), but any attempt to - access a file through the resulting descriptor would - fail with EINVAL. */ - if (k == 1 && first_write && errno == EINVAL) + /* Retry without direct I/O since this may not be supported + at all on some (file) systems, or with the current size. + I.E. a specified --size that is not aligned, or when + dealing with slop at the end of a file with --exact. */ + if (! try_without_directio && errno == EINVAL) { direct_mode (fd, false); ssize = 0; + try_without_directio = true; continue; } error (0, errnum, _("%s: error writing at offset %s"), @@ -455,8 +532,10 @@ dopass (int fd, char const *qname, off_t *sizep, int type, /* 'shred' is often used on bad media, before throwing it out. Thus, it shouldn't give up on bad blocks. This code works because lim is always a multiple of - SECTOR_SIZE, except at the end. */ - verify (sizeof r % SECTOR_SIZE == 0); + SECTOR_SIZE, except at the end. This size constraint + also enables direct I/O on some (file) systems. */ + verify (PERIODIC_OUTPUT_SIZE % SECTOR_SIZE == 0); + verify (NONPERIODIC_OUTPUT_SIZE % SECTOR_SIZE == 0); if (errnum == EIO && 0 <= size && (soff | SECTOR_MASK) < lim) { size_t soff1 = (soff | SECTOR_MASK) + 1; @@ -469,7 +548,8 @@ dopass (int fd, char const *qname, off_t *sizep, int type, } error (0, errno, _("%s: lseek failed"), qname); } - return -1; + other_error = true; + goto free_pattern_mem; } } } @@ -479,7 +559,8 @@ dopass (int fd, char const *qname, off_t *sizep, int type, if (offset > OFF_T_MAX - (off_t) soff) { error (0, 0, _("%s: file too large"), qname); - return -1; + other_error = true; + goto free_pattern_mem; } offset += soff; @@ -536,7 +617,10 @@ dopass (int fd, char const *qname, off_t *sizep, int type, if (dosync (fd, qname) != 0) { if (errno != EIO) - return -1; + { + other_error = true; + goto free_pattern_mem; + } write_error = true; } } @@ -547,11 +631,18 @@ dopass (int fd, char const *qname, off_t *sizep, int type, if (dosync (fd, qname) != 0) { if (errno != EIO) - return -1; + { + other_error = true; + goto free_pattern_mem; + } write_error = true; } - return write_error; +free_pattern_mem: + memset (pbuf, 0, FILLPATTERN_SIZE); + free (fill_pattern_mem); + + return other_error ? -1 : write_error; } /* @@ -752,13 +843,14 @@ do_wipefd (int fd, char const *qname, struct randint_source *s, { size_t i; struct stat st; - off_t size; /* Size to write, size to read */ - unsigned long int n; /* Number of passes for printing purposes */ + off_t size; /* Size to write, size to read */ + off_t i_size = 0; /* For small files, initial size to overwrite inode */ + unsigned long int n; /* Number of passes for printing purposes */ int *passarray; bool ok = true; struct randread_source *rs; - n = 0; /* dopass takes n -- 0 to mean "don't print progress" */ + n = 0; /* dopass takes n == 0 to mean "don't print progress" */ if (flags->verbose) n = flags->n_iterations + flags->zero_fill; @@ -778,8 +870,11 @@ do_wipefd (int fd, char const *qname, struct randint_source *s, error (0, 0, _("%s: invalid file type"), qname); return false; } - - direct_mode (fd, true); + else if (S_ISREG (st.st_mode) && st.st_size < 0) + { + error (0, 0, _("%s: file has negative size"), qname); + return false; + } /* Allocate pass array */ passarray = xnmalloc (flags->n_iterations, sizeof *passarray); @@ -787,19 +882,28 @@ do_wipefd (int fd, char const *qname, struct randint_source *s, size = flags->size; if (size == -1) { - /* Accept a length of zero only if it's a regular file. - For any other type of file, try to get the size another way. */ if (S_ISREG (st.st_mode)) { size = st.st_size; - if (size < 0) + + if (! flags->exact) { - error (0, 0, _("%s: file has negative size"), qname); - return false; + /* Round up to the nearest block size to clear slack space. */ + off_t remainder = size % ST_BLKSIZE (st); + if (size && size < ST_BLKSIZE (st)) + i_size = size; + if (remainder != 0) + { + off_t size_incr = ST_BLKSIZE (st) - remainder; + size += MIN (size_incr, OFF_T_MAX - size); + } } } else { + /* The behavior of lseek is unspecified, but in practice if + it returns a positive number that's the size of this + device. */ size = lseek (fd, 0, SEEK_END); if (size <= 0) { @@ -808,63 +912,68 @@ do_wipefd (int fd, char const *qname, struct randint_source *s, size = -1; } } - - /* Allow 'rounding up' only for regular files. */ - if (0 <= size && !(flags->exact) && S_ISREG (st.st_mode)) - { - size += ST_BLKSIZE (st) - 1 - (size - 1) % ST_BLKSIZE (st); - - /* If in rounding up, we've just overflowed, use the maximum. */ - if (size < 0) - size = TYPE_MAXIMUM (off_t); - } } + else if (S_ISREG (st.st_mode) + && st.st_size < MIN (ST_BLKSIZE (st), size)) + i_size = st.st_size; /* Schedule the passes in random order. */ genpattern (passarray, flags->n_iterations, s); rs = randint_get_source (s); - /* Do the work */ - for (i = 0; i < flags->n_iterations; i++) + while (true) { - int err = dopass (fd, qname, &size, passarray[i], rs, i + 1, n); - if (err) + off_t pass_size; + unsigned long int pn = n; + + if (i_size) { - if (err < 0) - { - memset (passarray, 0, flags->n_iterations * sizeof (int)); - free (passarray); - return false; - } - ok = false; + pass_size = i_size; + i_size = 0; + pn = 0; } - } - - memset (passarray, 0, flags->n_iterations * sizeof (int)); - free (passarray); + else if (size) + { + pass_size = size; + size = 0; + } + /* TODO: consider handling tail packing by + writing the tail padding as a separate pass, + (that would not rewind). */ + else + break; - if (flags->zero_fill) - { - int err = dopass (fd, qname, &size, 0, rs, flags->n_iterations + 1, n); - if (err) + for (i = 0; i < flags->n_iterations + flags->zero_fill; i++) { - if (err < 0) - return false; - ok = false; + int err = 0; + int type = i < flags->n_iterations ? passarray[i] : 0; + + err = dopass (fd, &st, qname, &pass_size, type, rs, i + 1, pn); + + if (err) + { + ok = false; + if (err < 0) + goto wipefd_out; + } } } - /* Okay, now deallocate the data. The effect of ftruncate on + /* Now deallocate the data. The effect of ftruncate on non-regular files is unspecified, so don't worry about any errors reported for them. */ if (flags->remove_file && ftruncate (fd, 0) != 0 && S_ISREG (st.st_mode)) { error (0, errno, _("%s: error truncating"), qname); - return false; + ok = false; + goto wipefd_out; } +wipefd_out: + memset (passarray, 0, flags->n_iterations * sizeof (int)); + free (passarray); return ok; } @@ -926,8 +1035,8 @@ incname (char *name, size_t len) /* * Repeatedly rename a file with shorter and shorter names, - * to obliterate all traces of the file name on any system that - * adds a trailing delimiter to on-disk file names and reuses + * to obliterate all traces of the file name (and length) on any system + * that adds a trailing delimiter to on-disk file names and reuses * the same directory slot. Finally, unlink it. * The passed-in filename is modified in place to the new filename. * (Which is unlinked if this function succeeds, but is still present if @@ -960,13 +1069,15 @@ wipename (char *oldname, char const *qoldname, struct Options const *flags) char *qdir = xstrdup (quotearg_colon (dir)); bool first = true; bool ok = true; + int dir_fd = -1; - int dir_fd = open (dir, O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK); + if (flags->remove_file == remove_wipesync) + dir_fd = open (dir, O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK); if (flags->verbose) error (0, 0, _("%s: removing"), qoldname); - while (len) + while ((flags->remove_file != remove_unlink) && len) { memset (base, nameset[0], len); base[len] = 0; @@ -1120,7 +1231,7 @@ main (int argc, char **argv) { uintmax_t tmp; if (xstrtoumax (optarg, NULL, 10, &tmp, NULL) != LONGINT_OK - || MIN (UINT32_MAX, SIZE_MAX / sizeof (int)) < tmp) + || MIN (ULONG_MAX, SIZE_MAX / sizeof (int)) <= tmp) { error (EXIT_FAILURE, 0, _("%s: invalid number of passes"), quotearg_colon (optarg)); @@ -1136,14 +1247,19 @@ main (int argc, char **argv) break; case 'u': - flags.remove_file = true; + if (optarg == NULL) + flags.remove_file = remove_wipesync; + else + flags.remove_file = XARGMATCH ("--remove", optarg, + remove_args, remove_methods); break; case 's': { uintmax_t tmp; - if (xstrtoumax (optarg, NULL, 0, &tmp, "cbBkKMGTPEZY0") - != LONGINT_OK) + if ((xstrtoumax (optarg, NULL, 0, &tmp, "cbBkKMGTPEZY0") + != LONGINT_OK) + || OFF_T_MAX < tmp) { error (EXIT_FAILURE, 0, _("%s: invalid file size"), quotearg_colon (optarg)); @@ -1,6 +1,6 @@ /* Shuffle lines of text. - Copyright (C) 2006-2013 Free Software Foundation, Inc. + Copyright (C) 2006-2014 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 @@ -25,6 +25,7 @@ #include "error.h" #include "fadvise.h" #include "getopt.h" +#include "linebuffer.h" #include "quote.h" #include "quotearg.h" #include "randint.h" @@ -38,6 +39,18 @@ #define AUTHORS proper_name ("Paul Eggert") +/* For reservoir-sampling, allocate the reservoir lines in batches. */ +enum { RESERVOIR_LINES_INCREMENT = 1024 }; + +/* reservoir-sampling introduces CPU overhead for small inputs. + So only enable it for inputs >= this limit. + This limit was determined using these commands: + $ for p in $(seq 7); do src/seq $((10**$p)) > 10p$p.in; done + $ for p in $(seq 7); do time shuf-nores -n10 10p$p.in >/dev/null; done + $ for p in $(seq 7); do time shuf -n10 10p$p.in >/dev/null; done .*/ +enum { RESERVOIR_MIN_INPUT = 8192 * 1024 }; + + void usage (int status) { @@ -63,7 +76,10 @@ Write a random permutation of the input lines to standard output.\n\ -n, --head-count=COUNT output at most COUNT lines\n\ -o, --output=FILE write result to FILE instead of standard output\n\ --random-source=FILE get random bytes from FILE\n\ - -z, --zero-terminated end lines with 0 byte, not newline\n\ + -r, --repeat output lines can be repeated\n\ +"), stdout); + fputs (_("\ + -z, --zero-terminated line delimiter is NUL, not newline\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -91,18 +107,13 @@ static struct option const long_opts[] = {"head-count", required_argument, NULL, 'n'}, {"output", required_argument, NULL, 'o'}, {"random-source", required_argument, NULL, RANDOM_SOURCE_OPTION}, + {"repeat", no_argument, NULL, 'r'}, {"zero-terminated", no_argument, NULL, 'z'}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {0, 0, 0, 0}, }; -static bool -input_numbers_option_used (size_t lo_input, size_t hi_input) -{ - return ! (lo_input == SIZE_MAX && hi_input == 0); -} - static void input_from_argv (char **operand, int n_operands, char eolbyte) { @@ -135,6 +146,114 @@ next_line (char *line, char eolbyte, size_t n) return p + 1; } +/* Return the size of the input if possible or OFF_T_MAX if not. */ + +static off_t +input_size (void) +{ + off_t file_size; + + struct stat stat_buf; + if (fstat (STDIN_FILENO, &stat_buf) != 0) + return OFF_T_MAX; + if (usable_st_size (&stat_buf)) + file_size = stat_buf.st_size; + else + return OFF_T_MAX; + + off_t input_offset = lseek (STDIN_FILENO, 0, SEEK_CUR); + if (input_offset < 0) + return OFF_T_MAX; + + file_size -= input_offset; + + return file_size; +} + +/* Read all lines and store up to K permuted lines in *OUT_RSRV. + Return the number of lines read, up to a maximum of K. */ + +static size_t +read_input_reservoir_sampling (FILE *in, char eolbyte, size_t k, + struct randint_source *s, + struct linebuffer **out_rsrv) +{ + randint n_lines = 0; + size_t n_alloc_lines = MIN (k, RESERVOIR_LINES_INCREMENT); + struct linebuffer *line = NULL; + struct linebuffer *rsrv; + + rsrv = xcalloc (n_alloc_lines, sizeof (struct linebuffer)); + + /* Fill the first K lines, directly into the reservoir. */ + while (n_lines < k + && (line = + readlinebuffer_delim (&rsrv[n_lines], in, eolbyte)) != NULL) + { + n_lines++; + + /* Enlarge reservoir. */ + if (n_lines >= n_alloc_lines) + { + n_alloc_lines += RESERVOIR_LINES_INCREMENT; + rsrv = xnrealloc (rsrv, n_alloc_lines, sizeof (struct linebuffer)); + memset (&rsrv[n_lines], 0, + RESERVOIR_LINES_INCREMENT * sizeof (struct linebuffer)); + } + } + + /* last line wasn't NULL - so there may be more lines to read. */ + if (line != NULL) + { + struct linebuffer dummy; + initbuffer (&dummy); /* space for lines not put in reservoir. */ + + /* Choose the fate of the next line, with decreasing probability (as + n_lines increases in size). + + If the line will be used, store it directly in the reservoir. + Otherwise, store it in dummy space. + + With 'struct linebuffer', storing into existing buffer will reduce + re-allocations (will only re-allocate if the new line is longer than + the currently allocated space). */ + do + { + randint j = randint_choose (s, n_lines + 1); /* 0 .. n_lines. */ + line = (j < k) ? (&rsrv[j]) : (&dummy); + } + while (readlinebuffer_delim (line, in, eolbyte) != NULL && n_lines++); + + if (! n_lines) + error (EXIT_FAILURE, EOVERFLOW, _("too many input lines")); + + freebuffer (&dummy); + } + + /* no more input lines, or an input error. */ + if (ferror (in)) + error (EXIT_FAILURE, errno, _("read error")); + + *out_rsrv = rsrv; + return MIN (k, n_lines); +} + +static int +write_permuted_output_reservoir (size_t n_lines, struct linebuffer *lines, + size_t const *permutation) +{ + size_t i; + + for (i = 0; i < n_lines; i++) + { + const struct linebuffer *p = &lines[permutation[i]]; + if (fwrite (p->buffer, sizeof (char), p->length, stdout) != p->length) + return -1; + } + + return 0; +} + /* Read data from file IN. Input lines are delimited by EOLBYTE; silently append a trailing EOLBYTE if the file ends in some other byte. Store a pointer to the resulting array of lines into *PLINE. @@ -152,6 +271,15 @@ read_input (FILE *in, char eolbyte, char ***pline) size_t i; size_t n_lines; + /* TODO: We should limit the amount of data read here, + to less than RESERVOIR_MIN_INPUT. I.E. adjust fread_file() to support + taking a byte limit. We'd then need to ensure we handle a line spanning + this boundary. With that in place we could set use_reservoir_sampling + when used==RESERVOIR_MIN_INPUT, and have read_input_reservoir_sampling() + call a wrapper function to populate a linebuffer from the internal pline + or if none left, stdin. Doing that would give better performance by + avoiding the reservoir CPU overhead when reading < RESERVOIR_MIN_INPUT + from a pipe, and allow us to dispense with the input_size() function. */ if (!(buf = fread_file (in, &used))) error (EXIT_FAILURE, errno, _("read error")); @@ -173,27 +301,81 @@ read_input (FILE *in, char eolbyte, char ***pline) return n_lines; } +/* Output N_LINES lines to stdout from LINE array, + chosen by the indices in PERMUTATION. + PERMUTATION and LINE must have at least N_LINES elements. + Strings in LINE must include the line-terminator character. */ static int -write_permuted_output (size_t n_lines, char * const *line, size_t lo_input, - size_t const *permutation, char eolbyte) +write_permuted_lines (size_t n_lines, char *const *line, + size_t const *permutation) { size_t i; - if (line) - for (i = 0; i < n_lines; i++) - { - char * const *p = line + permutation[i]; - size_t len = p[1] - p[0]; - if (fwrite (p[0], sizeof *p[0], len, stdout) != len) - return -1; - } - else - for (i = 0; i < n_lines; i++) - { - unsigned long int n = lo_input + permutation[i]; - if (printf ("%lu%c", n, eolbyte) < 0) - return -1; - } + for (i = 0; i < n_lines; i++) + { + char *const *p = line + permutation[i]; + size_t len = p[1] - p[0]; + if (fwrite (p[0], sizeof *p[0], len, stdout) != len) + return -1; + } + + return 0; +} + +/* Output N_LINES of numbers to stdout, from PERMUTATION array. + PERMUTATION must have at least N_LINES elements. */ +static int +write_permuted_numbers (size_t n_lines, size_t lo_input, + size_t const *permutation, char eolbyte) +{ + size_t i; + + for (i = 0; i < n_lines; i++) + { + unsigned long int n = lo_input + permutation[i]; + if (printf ("%lu%c", n, eolbyte) < 0) + return -1; + } + + return 0; +} + +/* Output COUNT numbers to stdout, chosen randomly from range + LO_INPUT through HI_INPUT. */ +static int +write_random_numbers (struct randint_source *s, size_t count, + size_t lo_input, size_t hi_input, char eolbyte) +{ + size_t i; + const randint range = hi_input - lo_input + 1; + + for (i = 0; i < count; i++) + { + unsigned long int j = lo_input + randint_choose (s, range); + if (printf ("%lu%c", j, eolbyte) < 0) + return -1; + } + + return 0; +} + +/* Output COUNT lines to stdout from LINES array. + LINES must have at least N_LINES elements in it. + Strings in LINES_ must include the line-terminator character. */ +static int +write_random_lines (struct randint_source *s, size_t count, + char *const *lines, size_t n_lines) +{ + size_t i; + + for (i = 0; i < count; i++) + { + const randint j = randint_choose (s, n_lines); + char *const *p = lines + j; + size_t len = p[1] - p[0]; + if (fwrite (p[0], sizeof *p[0], len, stdout) != len) + return -1; + } return 0; } @@ -202,6 +384,7 @@ int main (int argc, char **argv) { bool echo = false; + bool input_range = false; size_t lo_input = SIZE_MAX; size_t hi_input = 0; size_t head_lines = SIZE_MAX; @@ -209,14 +392,18 @@ main (int argc, char **argv) char *random_source = NULL; char eolbyte = '\n'; char **input_lines = NULL; + bool use_reservoir_sampling = false; + bool repeat = false; int optc; int n_operands; char **operand; size_t n_lines; - char **line; + char **line = NULL; + struct linebuffer *reservoir = NULL; struct randint_source *randint_source; - size_t *permutation; + size_t *permutation = NULL; + int i; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -226,7 +413,7 @@ main (int argc, char **argv) atexit (close_stdout); - while ((optc = getopt_long (argc, argv, "ei:n:o:z", long_opts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "ei:n:o:rz", long_opts, NULL)) != -1) switch (optc) { case 'e': @@ -240,8 +427,9 @@ main (int argc, char **argv) char const *hi_optarg = optarg; bool invalid = !p; - if (input_numbers_option_used (lo_input, hi_input)) + if (input_range) error (EXIT_FAILURE, 0, _("multiple -i options specified")); + input_range = true; if (p) { @@ -291,6 +479,10 @@ main (int argc, char **argv) random_source = optarg; break; + case 'r': + repeat = true; + break; + case 'z': eolbyte = '\0'; break; @@ -304,67 +496,113 @@ main (int argc, char **argv) n_operands = argc - optind; operand = argv + optind; + /* Check invalid usage. */ + if (echo && input_range) + { + error (0, 0, _("cannot combine -e and -i options")); + usage (EXIT_FAILURE); + } + if (input_range ? 0 < n_operands : !echo && 1 < n_operands) + { + error (0, 0, _("extra operand %s"), quote (operand[1])); + usage (EXIT_FAILURE); + } + + /* Prepare input. */ if (echo) { - if (input_numbers_option_used (lo_input, hi_input)) - error (EXIT_FAILURE, 0, _("cannot combine -e and -i options")); input_from_argv (operand, n_operands, eolbyte); n_lines = n_operands; line = operand; } - else if (input_numbers_option_used (lo_input, hi_input)) + else if (input_range) { - if (n_operands) - { - error (0, 0, _("extra operand %s"), quote (operand[0])); - usage (EXIT_FAILURE); - } n_lines = hi_input - lo_input + 1; line = NULL; } else { - switch (n_operands) - { - case 0: - break; - - case 1: - if (! (STREQ (operand[0], "-") || freopen (operand[0], "r", stdin))) - error (EXIT_FAILURE, errno, "%s", operand[0]); - break; - - default: - error (0, 0, _("extra operand %s"), quote (operand[1])); - usage (EXIT_FAILURE); - } + /* If an input file is specified, re-open it as stdin. */ + if (n_operands == 1) + if (! (STREQ (operand[0], "-") || ! head_lines + || freopen (operand[0], "r", stdin))) + error (EXIT_FAILURE, errno, "%s", operand[0]); fadvise (stdin, FADVISE_SEQUENTIAL); - n_lines = read_input (stdin, eolbyte, &input_lines); - line = input_lines; + if (! repeat && head_lines != SIZE_MAX + && (! head_lines || input_size () > RESERVOIR_MIN_INPUT)) + { + use_reservoir_sampling = true; + n_lines = SIZE_MAX; /* unknown number of input lines, for now. */ + } + else + { + n_lines = read_input (stdin, eolbyte, &input_lines); + line = input_lines; + } } - head_lines = MIN (head_lines, n_lines); + if (! repeat) + head_lines = MIN (head_lines, n_lines); randint_source = randint_all_new (random_source, - randperm_bound (head_lines, n_lines)); + (use_reservoir_sampling || repeat + ? SIZE_MAX + : randperm_bound (head_lines, n_lines))); if (! randint_source) error (EXIT_FAILURE, errno, "%s", quotearg_colon (random_source)); + if (use_reservoir_sampling) + { + /* Instead of reading the entire file into 'line', + use reservoir-sampling to store just "head_lines" random lines. */ + n_lines = read_input_reservoir_sampling (stdin, eolbyte, head_lines, + randint_source, &reservoir); + head_lines = n_lines; + } + /* Close stdin now, rather than earlier, so that randint_all_new doesn't have to worry about opening something other than stdin. */ - if (! (echo || input_numbers_option_used (lo_input, hi_input)) + if (! (echo || input_range) && (fclose (stdin) != 0)) error (EXIT_FAILURE, errno, _("read error")); - permutation = randperm_new (randint_source, head_lines, n_lines); + if (!repeat) + permutation = randperm_new (randint_source, head_lines, n_lines); if (outfile && ! freopen (outfile, "w", stdout)) error (EXIT_FAILURE, errno, "%s", quotearg_colon (outfile)); - if (write_permuted_output (head_lines, line, lo_input, permutation, eolbyte) - != 0) + + /* Generate output according to requested method */ + if (repeat) + { + if (head_lines == 0) + i = 0; + else + { + if (n_lines == 0) + error (EXIT_FAILURE, 0, _("no lines to repeat")); + if (input_range) + i = write_random_numbers (randint_source, head_lines, + lo_input, hi_input, eolbyte); + else + i = write_random_lines (randint_source, head_lines, line, n_lines); + } + } + else + { + if (use_reservoir_sampling) + i = write_permuted_output_reservoir (n_lines, reservoir, permutation); + else if (input_range) + i = write_permuted_numbers (head_lines, lo_input, + permutation, eolbyte); + else + i = write_permuted_lines (head_lines, line, permutation); + } + + if (i != 0) error (EXIT_FAILURE, errno, _("write error")); #ifdef lint @@ -375,7 +613,14 @@ main (int argc, char **argv) free (input_lines[0]); free (input_lines); } + if (reservoir) + { + size_t j; + for (j = 0; j < n_lines; ++j) + freebuffer (&reservoir[j]); + free (reservoir); + } #endif - return EXIT_SUCCESS; + exit (EXIT_SUCCESS); } diff --git a/src/single-binary.mk b/src/single-binary.mk new file mode 100644 index 00000000..cc836d75 --- /dev/null +++ b/src/single-binary.mk @@ -0,0 +1,480 @@ +## Automatically generated by gen-single-binary.sh. DO NOT EDIT BY HAND! +src_libsinglebin_dir_a_DEPENDENCIES = src/libsinglebin_ls.a +src_libsinglebin_vdir_a_DEPENDENCIES = src/libsinglebin_ls.a +src_libsinglebin_arch_a_DEPENDENCIES = src/libsinglebin_uname.a +# Command arch +noinst_LIBRARIES += src/libsinglebin_arch.a +src_libsinglebin_arch_a_SOURCES = src/coreutils-arch.c +src_libsinglebin_arch_a_ldadd = src/libsinglebin_uname.a +src_libsinglebin_arch_a_CFLAGS = "-Dmain=_single_binary_main_arch(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_arch" -Dusage=_usage_arch $(src_coreutils_CFLAGS) +# Command hostname +noinst_LIBRARIES += src/libsinglebin_hostname.a +src_libsinglebin_hostname_a_SOURCES = src/hostname.c +src_libsinglebin_hostname_a_ldadd = $(GETHOSTNAME_LIB) +src_libsinglebin_hostname_a_CFLAGS = "-Dmain=_single_binary_main_hostname(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_hostname" -Dusage=_usage_hostname $(src_coreutils_CFLAGS) +# Command chroot +noinst_LIBRARIES += src/libsinglebin_chroot.a +src_libsinglebin_chroot_a_SOURCES = src/chroot.c +src_libsinglebin_chroot_a_CFLAGS = "-Dmain=_single_binary_main_chroot(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_chroot" -Dusage=_usage_chroot $(src_coreutils_CFLAGS) +# Command df +noinst_LIBRARIES += src/libsinglebin_df.a +src_libsinglebin_df_a_SOURCES = src/df.c src/find-mount-point.c +src_libsinglebin_df_a_ldadd = $(LIBICONV) +src_libsinglebin_df_a_CFLAGS = "-Dmain=_single_binary_main_df(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_df" -Dusage=_usage_df $(src_coreutils_CFLAGS) +# Command hostid +noinst_LIBRARIES += src/libsinglebin_hostid.a +src_libsinglebin_hostid_a_SOURCES = src/hostid.c +src_libsinglebin_hostid_a_CFLAGS = "-Dmain=_single_binary_main_hostid(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_hostid" -Dusage=_usage_hostid $(src_coreutils_CFLAGS) +# Command nice +noinst_LIBRARIES += src/libsinglebin_nice.a +src_libsinglebin_nice_a_SOURCES = src/nice.c +src_libsinglebin_nice_a_CFLAGS = "-Dmain=_single_binary_main_nice(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_nice" -Dusage=_usage_nice $(src_coreutils_CFLAGS) +# Command pinky +noinst_LIBRARIES += src/libsinglebin_pinky.a +src_libsinglebin_pinky_a_SOURCES = src/pinky.c +src_libsinglebin_pinky_a_ldadd = $(GETADDRINFO_LIB) +src_libsinglebin_pinky_a_CFLAGS = "-Dmain=_single_binary_main_pinky(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_pinky" -Dusage=_usage_pinky $(src_coreutils_CFLAGS) +# Command stdbuf +noinst_LIBRARIES += src/libsinglebin_stdbuf.a +src_libsinglebin_stdbuf_a_SOURCES = src/stdbuf.c +src_libsinglebin_stdbuf_a_ldadd = $(LIBICONV) +src_libsinglebin_stdbuf_a_CFLAGS = "-Dmain=_single_binary_main_stdbuf(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_stdbuf" -Dusage=_usage_stdbuf $(src_coreutils_CFLAGS) +# Command stty +noinst_LIBRARIES += src/libsinglebin_stty.a +src_libsinglebin_stty_a_SOURCES = src/stty.c +src_libsinglebin_stty_a_CFLAGS = "-Dmain=_single_binary_main_stty(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_stty" -Dusage=_usage_stty $(src_coreutils_CFLAGS) +# Command uptime +noinst_LIBRARIES += src/libsinglebin_uptime.a +src_libsinglebin_uptime_a_SOURCES = src/uptime.c +src_libsinglebin_uptime_a_ldadd = $(GETLOADAVG_LIBS) +src_libsinglebin_uptime_a_CFLAGS = "-Dmain=_single_binary_main_uptime(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_uptime" -Dusage=_usage_uptime $(src_coreutils_CFLAGS) +# Command users +noinst_LIBRARIES += src/libsinglebin_users.a +src_libsinglebin_users_a_SOURCES = src/users.c +src_libsinglebin_users_a_CFLAGS = "-Dmain=_single_binary_main_users(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_users" -Dusage=_usage_users $(src_coreutils_CFLAGS) +# Command who +noinst_LIBRARIES += src/libsinglebin_who.a +src_libsinglebin_who_a_SOURCES = src/who.c +src_libsinglebin_who_a_ldadd = $(GETADDRINFO_LIB) +src_libsinglebin_who_a_CFLAGS = "-Dmain=_single_binary_main_who(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_who" -Dusage=_usage_who $(src_coreutils_CFLAGS) +# Command _ +noinst_LIBRARIES += src/libsinglebin__.a +src_libsinglebin___a_SOURCES = src/lbracket.c +src_libsinglebin___a_ldadd = $(src_test_LDADD) +src_libsinglebin___a_CFLAGS = "-Dmain=_single_binary_main__(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main__" -Dusage=_usage__ $(src_coreutils_CFLAGS) +# Command base64 +noinst_LIBRARIES += src/libsinglebin_base64.a +src_libsinglebin_base64_a_SOURCES = src/base64.c +src_libsinglebin_base64_a_CFLAGS = "-Dmain=_single_binary_main_base64(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_base64" -Dusage=_usage_base64 $(src_coreutils_CFLAGS) +# Command basename +noinst_LIBRARIES += src/libsinglebin_basename.a +src_libsinglebin_basename_a_SOURCES = src/basename.c +src_libsinglebin_basename_a_CFLAGS = "-Dmain=_single_binary_main_basename(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_basename" -Dusage=_usage_basename $(src_coreutils_CFLAGS) +# Command cat +noinst_LIBRARIES += src/libsinglebin_cat.a +src_libsinglebin_cat_a_SOURCES = src/cat.c +src_libsinglebin_cat_a_ldadd = $(LIBICONV) +src_libsinglebin_cat_a_CFLAGS = "-Dmain=_single_binary_main_cat(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_cat" -Dusage=_usage_cat $(src_coreutils_CFLAGS) +# Command chcon +noinst_LIBRARIES += src/libsinglebin_chcon.a +src_libsinglebin_chcon_a_SOURCES = src/chcon.c +src_libsinglebin_chcon_a_ldadd = $(LIB_SELINUX) +src_libsinglebin_chcon_a_CFLAGS = "-Dmain=_single_binary_main_chcon(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_chcon" -Dusage=_usage_chcon $(src_coreutils_CFLAGS) +# Command chgrp +noinst_LIBRARIES += src/libsinglebin_chgrp.a +src_libsinglebin_chgrp_a_SOURCES = src/chgrp.c src/chown-core.c +src_libsinglebin_chgrp_a_CFLAGS = "-Dmain=_single_binary_main_chgrp(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_chgrp" -Dusage=_usage_chgrp $(src_coreutils_CFLAGS) +# Command chmod +noinst_LIBRARIES += src/libsinglebin_chmod.a +src_libsinglebin_chmod_a_SOURCES = src/chmod.c +src_libsinglebin_chmod_a_CFLAGS = "-Dmain=_single_binary_main_chmod(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_chmod" -Dusage=_usage_chmod $(src_coreutils_CFLAGS) +# Command chown +noinst_LIBRARIES += src/libsinglebin_chown.a +src_libsinglebin_chown_a_SOURCES = src/chown.c src/chown-core.c +src_libsinglebin_chown_a_CFLAGS = "-Dmain=_single_binary_main_chown(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_chown" -Dusage=_usage_chown $(src_coreutils_CFLAGS) +# Command cksum +noinst_LIBRARIES += src/libsinglebin_cksum.a +src_libsinglebin_cksum_a_SOURCES = src/cksum.c +src_libsinglebin_cksum_a_CFLAGS = "-Dmain=_single_binary_main_cksum(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_cksum" -Dusage=_usage_cksum $(src_coreutils_CFLAGS) +# Command comm +noinst_LIBRARIES += src/libsinglebin_comm.a +src_libsinglebin_comm_a_SOURCES = src/comm.c +src_libsinglebin_comm_a_CFLAGS = "-Dmain=_single_binary_main_comm(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_comm" -Dusage=_usage_comm $(src_coreutils_CFLAGS) +# Command cp +noinst_LIBRARIES += src/libsinglebin_cp.a +src_libsinglebin_cp_a_SOURCES = src/cp.c $(copy_sources) $(selinux_sources) +src_libsinglebin_cp_a_ldadd = $(copy_ldadd) $(LIBICONV) +src_libsinglebin_cp_a_CFLAGS = "-Dmain=_single_binary_main_cp(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_cp" -Dusage=_usage_cp $(src_coreutils_CFLAGS) +# Command csplit +noinst_LIBRARIES += src/libsinglebin_csplit.a +src_libsinglebin_csplit_a_SOURCES = src/csplit.c +src_libsinglebin_csplit_a_CFLAGS = "-Dmain=_single_binary_main_csplit(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_csplit" -Dusage=_usage_csplit $(src_coreutils_CFLAGS) +# Command cut +noinst_LIBRARIES += src/libsinglebin_cut.a +src_libsinglebin_cut_a_SOURCES = src/cut.c +src_libsinglebin_cut_a_CFLAGS = "-Dmain=_single_binary_main_cut(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_cut" -Dusage=_usage_cut $(src_coreutils_CFLAGS) +# Command date +noinst_LIBRARIES += src/libsinglebin_date.a +src_libsinglebin_date_a_SOURCES = src/date.c +src_libsinglebin_date_a_ldadd = $(LIB_CLOCK_GETTIME) +src_libsinglebin_date_a_CFLAGS = "-Dmain=_single_binary_main_date(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_date" -Dusage=_usage_date $(src_coreutils_CFLAGS) +# Command dd +noinst_LIBRARIES += src/libsinglebin_dd.a +src_libsinglebin_dd_a_SOURCES = src/dd.c +src_libsinglebin_dd_a_ldadd = $(LIB_GETHRXTIME) $(LIB_FDATASYNC) +src_libsinglebin_dd_a_CFLAGS = "-Dmain=_single_binary_main_dd(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_dd" -Dusage=_usage_dd $(src_coreutils_CFLAGS) +# Command dir +noinst_LIBRARIES += src/libsinglebin_dir.a +src_libsinglebin_dir_a_SOURCES = src/coreutils-dir.c +src_libsinglebin_dir_a_ldadd = $(src_ls_LDADD) src/libsinglebin_ls.a +src_libsinglebin_dir_a_CFLAGS = "-Dmain=_single_binary_main_dir(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_dir" -Dusage=_usage_dir $(src_coreutils_CFLAGS) +# Command dircolors +noinst_LIBRARIES += src/libsinglebin_dircolors.a +src_libsinglebin_dircolors_a_SOURCES = src/dircolors.c +src_libsinglebin_dircolors_a_CFLAGS = "-Dmain=_single_binary_main_dircolors(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_dircolors" -Dusage=_usage_dircolors $(src_coreutils_CFLAGS) +# Command dirname +noinst_LIBRARIES += src/libsinglebin_dirname.a +src_libsinglebin_dirname_a_SOURCES = src/dirname.c +src_libsinglebin_dirname_a_CFLAGS = "-Dmain=_single_binary_main_dirname(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_dirname" -Dusage=_usage_dirname $(src_coreutils_CFLAGS) +# Command du +noinst_LIBRARIES += src/libsinglebin_du.a +src_libsinglebin_du_a_SOURCES = src/du.c +src_libsinglebin_du_a_ldadd = $(LIBICONV) +src_libsinglebin_du_a_CFLAGS = "-Dmain=_single_binary_main_du(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_du" -Dusage=_usage_du $(src_coreutils_CFLAGS) +# Command echo +noinst_LIBRARIES += src/libsinglebin_echo.a +src_libsinglebin_echo_a_SOURCES = src/echo.c +src_libsinglebin_echo_a_CFLAGS = "-Dmain=_single_binary_main_echo(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_echo" -Dusage=_usage_echo $(src_coreutils_CFLAGS) +# Command env +noinst_LIBRARIES += src/libsinglebin_env.a +src_libsinglebin_env_a_SOURCES = src/env.c +src_libsinglebin_env_a_CFLAGS = "-Dmain=_single_binary_main_env(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_env" -Dusage=_usage_env $(src_coreutils_CFLAGS) +# Command expand +noinst_LIBRARIES += src/libsinglebin_expand.a +src_libsinglebin_expand_a_SOURCES = src/expand.c +src_libsinglebin_expand_a_CFLAGS = "-Dmain=_single_binary_main_expand(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_expand" -Dusage=_usage_expand $(src_coreutils_CFLAGS) +# Command expr +noinst_LIBRARIES += src/libsinglebin_expr.a +src_libsinglebin_expr_a_SOURCES = src/expr.c +src_libsinglebin_expr_a_ldadd = $(LIB_GMP) +src_libsinglebin_expr_a_CFLAGS = "-Dmain=_single_binary_main_expr(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_expr" -Dusage=_usage_expr $(src_coreutils_CFLAGS) +# Command factor +noinst_LIBRARIES += src/libsinglebin_factor.a +src_libsinglebin_factor_a_SOURCES = src/factor.c +src_libsinglebin_factor_a_ldadd = $(LIB_GMP) $(LIBICONV) +src_libsinglebin_factor_a_CFLAGS = "-Dmain=_single_binary_main_factor(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_factor" -Dusage=_usage_factor $(src_coreutils_CFLAGS) +# Command false +noinst_LIBRARIES += src/libsinglebin_false.a +src_libsinglebin_false_a_SOURCES = src/false.c +src_libsinglebin_false_a_CFLAGS = "-Dmain=_single_binary_main_false(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_false" -Dusage=_usage_false $(src_coreutils_CFLAGS) +# Command fmt +noinst_LIBRARIES += src/libsinglebin_fmt.a +src_libsinglebin_fmt_a_SOURCES = src/fmt.c +src_libsinglebin_fmt_a_CFLAGS = "-Dmain=_single_binary_main_fmt(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_fmt" -Dusage=_usage_fmt $(src_coreutils_CFLAGS) +# Command fold +noinst_LIBRARIES += src/libsinglebin_fold.a +src_libsinglebin_fold_a_SOURCES = src/fold.c +src_libsinglebin_fold_a_CFLAGS = "-Dmain=_single_binary_main_fold(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_fold" -Dusage=_usage_fold $(src_coreutils_CFLAGS) +# Command ginstall +noinst_LIBRARIES += src/libsinglebin_ginstall.a +src_libsinglebin_ginstall_a_SOURCES = src/install.c src/prog-fprintf.c $(copy_sources) $(selinux_sources) +src_libsinglebin_ginstall_a_ldadd = $(copy_ldadd) $(LIB_SELINUX) $(LIB_CLOCK_GETTIME) +src_libsinglebin_ginstall_a_CFLAGS = "-Dmain=_single_binary_main_ginstall(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_ginstall" -Dusage=_usage_ginstall $(src_coreutils_CFLAGS) +src_libsinglebin_ginstall_a_CPPFLAGS = -DENABLE_MATCHPATHCON=1 $(AM_CPPFLAGS) +# Command groups +noinst_LIBRARIES += src/libsinglebin_groups.a +src_libsinglebin_groups_a_SOURCES = src/groups.c src/group-list.c +src_libsinglebin_groups_a_CFLAGS = "-Dmain=_single_binary_main_groups(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_groups" -Dusage=_usage_groups $(src_coreutils_CFLAGS) +# Command head +noinst_LIBRARIES += src/libsinglebin_head.a +src_libsinglebin_head_a_SOURCES = src/head.c +src_libsinglebin_head_a_CFLAGS = "-Dmain=_single_binary_main_head(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_head" -Dusage=_usage_head $(src_coreutils_CFLAGS) +# Command id +noinst_LIBRARIES += src/libsinglebin_id.a +src_libsinglebin_id_a_SOURCES = src/id.c src/group-list.c +src_libsinglebin_id_a_ldadd = $(LIB_SELINUX) $(LIB_SMACK) +src_libsinglebin_id_a_CFLAGS = "-Dmain=_single_binary_main_id(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_id" -Dusage=_usage_id $(src_coreutils_CFLAGS) +# Command join +noinst_LIBRARIES += src/libsinglebin_join.a +src_libsinglebin_join_a_SOURCES = src/join.c +src_libsinglebin_join_a_CFLAGS = "-Dmain=_single_binary_main_join(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_join" -Dusage=_usage_join $(src_coreutils_CFLAGS) +# Command kill +noinst_LIBRARIES += src/libsinglebin_kill.a +src_libsinglebin_kill_a_SOURCES = src/kill.c src/operand2sig.c +src_libsinglebin_kill_a_ldadd = $(LIBTHREAD) +src_libsinglebin_kill_a_CFLAGS = "-Dmain=_single_binary_main_kill(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_kill" -Dusage=_usage_kill $(src_coreutils_CFLAGS) +# Command link +noinst_LIBRARIES += src/libsinglebin_link.a +src_libsinglebin_link_a_SOURCES = src/link.c +src_libsinglebin_link_a_CFLAGS = "-Dmain=_single_binary_main_link(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_link" -Dusage=_usage_link $(src_coreutils_CFLAGS) +# Command ln +noinst_LIBRARIES += src/libsinglebin_ln.a +src_libsinglebin_ln_a_SOURCES = src/ln.c src/relpath.c src/relpath.h +src_libsinglebin_ln_a_CFLAGS = "-Dmain=_single_binary_main_ln(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_ln" -Dusage=_usage_ln $(src_coreutils_CFLAGS) +# Command logname +noinst_LIBRARIES += src/libsinglebin_logname.a +src_libsinglebin_logname_a_SOURCES = src/logname.c +src_libsinglebin_logname_a_CFLAGS = "-Dmain=_single_binary_main_logname(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_logname" -Dusage=_usage_logname $(src_coreutils_CFLAGS) +# Command ls +noinst_LIBRARIES += src/libsinglebin_ls.a +src_libsinglebin_ls_a_SOURCES = src/ls.c src/ls-ls.c +src_libsinglebin_ls_a_ldadd = $(LIB_SELINUX) $(LIB_SMACK) $(LIB_CLOCK_GETTIME) $(LIB_CAP) $(LIB_ACL) +src_libsinglebin_ls_a_CFLAGS = "-Dmain=_single_binary_main_ls(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_ls" -Dusage=_usage_ls $(src_coreutils_CFLAGS) +# Command md5sum +noinst_LIBRARIES += src/libsinglebin_md5sum.a +src_libsinglebin_md5sum_a_SOURCES = src/md5sum.c +src_libsinglebin_md5sum_a_ldadd = $(LIB_CRYPTO) +src_libsinglebin_md5sum_a_CFLAGS = "-Dmain=_single_binary_main_md5sum(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_md5sum" -Dusage=_usage_md5sum $(src_coreutils_CFLAGS) +src_libsinglebin_md5sum_a_CPPFLAGS = -DHASH_ALGO_MD5=1 $(AM_CPPFLAGS) +# Command mkdir +noinst_LIBRARIES += src/libsinglebin_mkdir.a +src_libsinglebin_mkdir_a_SOURCES = src/mkdir.c src/prog-fprintf.c $(selinux_sources) +src_libsinglebin_mkdir_a_ldadd = $(LIB_SELINUX) $(LIB_SMACK) +src_libsinglebin_mkdir_a_CFLAGS = "-Dmain=_single_binary_main_mkdir(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_mkdir" -Dusage=_usage_mkdir $(src_coreutils_CFLAGS) +# Command mkfifo +noinst_LIBRARIES += src/libsinglebin_mkfifo.a +src_libsinglebin_mkfifo_a_SOURCES = src/mkfifo.c $(selinux_sources) +src_libsinglebin_mkfifo_a_ldadd = $(LIB_SELINUX) $(LIB_SMACK) +src_libsinglebin_mkfifo_a_CFLAGS = "-Dmain=_single_binary_main_mkfifo(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_mkfifo" -Dusage=_usage_mkfifo $(src_coreutils_CFLAGS) +# Command mknod +noinst_LIBRARIES += src/libsinglebin_mknod.a +src_libsinglebin_mknod_a_SOURCES = src/mknod.c $(selinux_sources) +src_libsinglebin_mknod_a_ldadd = $(LIB_SELINUX) $(LIB_SMACK) +src_libsinglebin_mknod_a_CFLAGS = "-Dmain=_single_binary_main_mknod(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_mknod" -Dusage=_usage_mknod $(src_coreutils_CFLAGS) +# Command mktemp +noinst_LIBRARIES += src/libsinglebin_mktemp.a +src_libsinglebin_mktemp_a_SOURCES = src/mktemp.c +src_libsinglebin_mktemp_a_CFLAGS = "-Dmain=_single_binary_main_mktemp(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_mktemp" -Dusage=_usage_mktemp $(src_coreutils_CFLAGS) +# Command mv +noinst_LIBRARIES += src/libsinglebin_mv.a +src_libsinglebin_mv_a_SOURCES = src/mv.c src/remove.c $(copy_sources) $(selinux_sources) +src_libsinglebin_mv_a_ldadd = $(copy_ldadd) $(remove_ldadd) +src_libsinglebin_mv_a_CFLAGS = "-Dmain=_single_binary_main_mv(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_mv" -Dusage=_usage_mv $(src_coreutils_CFLAGS) +# Command nl +noinst_LIBRARIES += src/libsinglebin_nl.a +src_libsinglebin_nl_a_SOURCES = src/nl.c +src_libsinglebin_nl_a_CFLAGS = "-Dmain=_single_binary_main_nl(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_nl" -Dusage=_usage_nl $(src_coreutils_CFLAGS) +# Command nproc +noinst_LIBRARIES += src/libsinglebin_nproc.a +src_libsinglebin_nproc_a_SOURCES = src/nproc.c +src_libsinglebin_nproc_a_CFLAGS = "-Dmain=_single_binary_main_nproc(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_nproc" -Dusage=_usage_nproc $(src_coreutils_CFLAGS) +# Command nohup +noinst_LIBRARIES += src/libsinglebin_nohup.a +src_libsinglebin_nohup_a_SOURCES = src/nohup.c +src_libsinglebin_nohup_a_CFLAGS = "-Dmain=_single_binary_main_nohup(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_nohup" -Dusage=_usage_nohup $(src_coreutils_CFLAGS) +# Command numfmt +noinst_LIBRARIES += src/libsinglebin_numfmt.a +src_libsinglebin_numfmt_a_SOURCES = src/numfmt.c +src_libsinglebin_numfmt_a_CFLAGS = "-Dmain=_single_binary_main_numfmt(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_numfmt" -Dusage=_usage_numfmt $(src_coreutils_CFLAGS) +# Command od +noinst_LIBRARIES += src/libsinglebin_od.a +src_libsinglebin_od_a_SOURCES = src/od.c +src_libsinglebin_od_a_CFLAGS = "-Dmain=_single_binary_main_od(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_od" -Dusage=_usage_od $(src_coreutils_CFLAGS) +# Command paste +noinst_LIBRARIES += src/libsinglebin_paste.a +src_libsinglebin_paste_a_SOURCES = src/paste.c +src_libsinglebin_paste_a_CFLAGS = "-Dmain=_single_binary_main_paste(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_paste" -Dusage=_usage_paste $(src_coreutils_CFLAGS) +# Command pathchk +noinst_LIBRARIES += src/libsinglebin_pathchk.a +src_libsinglebin_pathchk_a_SOURCES = src/pathchk.c +src_libsinglebin_pathchk_a_CFLAGS = "-Dmain=_single_binary_main_pathchk(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_pathchk" -Dusage=_usage_pathchk $(src_coreutils_CFLAGS) +# Command pr +noinst_LIBRARIES += src/libsinglebin_pr.a +src_libsinglebin_pr_a_SOURCES = src/pr.c +src_libsinglebin_pr_a_ldadd = $(LIB_CLOCK_GETTIME) +src_libsinglebin_pr_a_CFLAGS = "-Dmain=_single_binary_main_pr(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_pr" -Dusage=_usage_pr $(src_coreutils_CFLAGS) +# Command printenv +noinst_LIBRARIES += src/libsinglebin_printenv.a +src_libsinglebin_printenv_a_SOURCES = src/printenv.c +src_libsinglebin_printenv_a_CFLAGS = "-Dmain=_single_binary_main_printenv(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_printenv" -Dusage=_usage_printenv $(src_coreutils_CFLAGS) +# Command printf +noinst_LIBRARIES += src/libsinglebin_printf.a +src_libsinglebin_printf_a_SOURCES = src/printf.c +src_libsinglebin_printf_a_ldadd = $(LIBICONV) +src_libsinglebin_printf_a_CFLAGS = "-Dmain=_single_binary_main_printf(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_printf" -Dusage=_usage_printf $(src_coreutils_CFLAGS) +# Command ptx +noinst_LIBRARIES += src/libsinglebin_ptx.a +src_libsinglebin_ptx_a_SOURCES = src/ptx.c +src_libsinglebin_ptx_a_ldadd = $(LIBICONV) +src_libsinglebin_ptx_a_CFLAGS = "-Dmain=_single_binary_main_ptx(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_ptx" -Dusage=_usage_ptx $(src_coreutils_CFLAGS) +# Command pwd +noinst_LIBRARIES += src/libsinglebin_pwd.a +src_libsinglebin_pwd_a_SOURCES = src/pwd.c +src_libsinglebin_pwd_a_CFLAGS = "-Dmain=_single_binary_main_pwd(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_pwd" -Dusage=_usage_pwd $(src_coreutils_CFLAGS) +# Command readlink +noinst_LIBRARIES += src/libsinglebin_readlink.a +src_libsinglebin_readlink_a_SOURCES = src/readlink.c +src_libsinglebin_readlink_a_CFLAGS = "-Dmain=_single_binary_main_readlink(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_readlink" -Dusage=_usage_readlink $(src_coreutils_CFLAGS) +# Command realpath +noinst_LIBRARIES += src/libsinglebin_realpath.a +src_libsinglebin_realpath_a_SOURCES = src/realpath.c src/relpath.c src/relpath.h +src_libsinglebin_realpath_a_ldadd = $(LIBICONV) +src_libsinglebin_realpath_a_CFLAGS = "-Dmain=_single_binary_main_realpath(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_realpath" -Dusage=_usage_realpath $(src_coreutils_CFLAGS) +# Command rm +noinst_LIBRARIES += src/libsinglebin_rm.a +src_libsinglebin_rm_a_SOURCES = src/rm.c src/remove.c +src_libsinglebin_rm_a_ldadd = $(remove_ldadd) +src_libsinglebin_rm_a_CFLAGS = "-Dmain=_single_binary_main_rm(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_rm" -Dusage=_usage_rm $(src_coreutils_CFLAGS) +# Command rmdir +noinst_LIBRARIES += src/libsinglebin_rmdir.a +src_libsinglebin_rmdir_a_SOURCES = src/rmdir.c src/prog-fprintf.c +src_libsinglebin_rmdir_a_CFLAGS = "-Dmain=_single_binary_main_rmdir(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_rmdir" -Dusage=_usage_rmdir $(src_coreutils_CFLAGS) +# Command runcon +noinst_LIBRARIES += src/libsinglebin_runcon.a +src_libsinglebin_runcon_a_SOURCES = src/runcon.c +src_libsinglebin_runcon_a_ldadd = $(LIB_SELINUX) +src_libsinglebin_runcon_a_CFLAGS = "-Dmain=_single_binary_main_runcon(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_runcon" -Dusage=_usage_runcon $(src_coreutils_CFLAGS) +# Command seq +noinst_LIBRARIES += src/libsinglebin_seq.a +src_libsinglebin_seq_a_SOURCES = src/seq.c +src_libsinglebin_seq_a_CFLAGS = "-Dmain=_single_binary_main_seq(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_seq" -Dusage=_usage_seq $(src_coreutils_CFLAGS) +# Command sha1sum +noinst_LIBRARIES += src/libsinglebin_sha1sum.a +src_libsinglebin_sha1sum_a_SOURCES = src/md5sum.c +src_libsinglebin_sha1sum_a_ldadd = $(LIB_CRYPTO) +src_libsinglebin_sha1sum_a_CFLAGS = "-Dmain=_single_binary_main_sha1sum(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sha1sum" -Dusage=_usage_sha1sum $(src_coreutils_CFLAGS) +src_libsinglebin_sha1sum_a_CPPFLAGS = -DHASH_ALGO_SHA1=1 $(AM_CPPFLAGS) +# Command sha224sum +noinst_LIBRARIES += src/libsinglebin_sha224sum.a +src_libsinglebin_sha224sum_a_SOURCES = src/md5sum.c +src_libsinglebin_sha224sum_a_ldadd = $(LIB_CRYPTO) +src_libsinglebin_sha224sum_a_CFLAGS = "-Dmain=_single_binary_main_sha224sum(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sha224sum" -Dusage=_usage_sha224sum $(src_coreutils_CFLAGS) +src_libsinglebin_sha224sum_a_CPPFLAGS = -DHASH_ALGO_SHA224=1 $(AM_CPPFLAGS) +# Command sha256sum +noinst_LIBRARIES += src/libsinglebin_sha256sum.a +src_libsinglebin_sha256sum_a_SOURCES = src/md5sum.c +src_libsinglebin_sha256sum_a_ldadd = $(LIB_CRYPTO) +src_libsinglebin_sha256sum_a_CFLAGS = "-Dmain=_single_binary_main_sha256sum(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sha256sum" -Dusage=_usage_sha256sum $(src_coreutils_CFLAGS) +src_libsinglebin_sha256sum_a_CPPFLAGS = -DHASH_ALGO_SHA256=1 $(AM_CPPFLAGS) +# Command sha384sum +noinst_LIBRARIES += src/libsinglebin_sha384sum.a +src_libsinglebin_sha384sum_a_SOURCES = src/md5sum.c +src_libsinglebin_sha384sum_a_ldadd = $(LIB_CRYPTO) +src_libsinglebin_sha384sum_a_CFLAGS = "-Dmain=_single_binary_main_sha384sum(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sha384sum" -Dusage=_usage_sha384sum $(src_coreutils_CFLAGS) +src_libsinglebin_sha384sum_a_CPPFLAGS = -DHASH_ALGO_SHA384=1 $(AM_CPPFLAGS) +# Command sha512sum +noinst_LIBRARIES += src/libsinglebin_sha512sum.a +src_libsinglebin_sha512sum_a_SOURCES = src/md5sum.c +src_libsinglebin_sha512sum_a_ldadd = $(LIB_CRYPTO) +src_libsinglebin_sha512sum_a_CFLAGS = "-Dmain=_single_binary_main_sha512sum(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sha512sum" -Dusage=_usage_sha512sum $(src_coreutils_CFLAGS) +src_libsinglebin_sha512sum_a_CPPFLAGS = -DHASH_ALGO_SHA512=1 $(AM_CPPFLAGS) +# Command shred +noinst_LIBRARIES += src/libsinglebin_shred.a +src_libsinglebin_shred_a_SOURCES = src/shred.c +src_libsinglebin_shred_a_ldadd = $(LIB_FDATASYNC) +src_libsinglebin_shred_a_CFLAGS = "-Dmain=_single_binary_main_shred(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_shred" -Dusage=_usage_shred $(src_coreutils_CFLAGS) +# Command shuf +noinst_LIBRARIES += src/libsinglebin_shuf.a +src_libsinglebin_shuf_a_SOURCES = src/shuf.c +src_libsinglebin_shuf_a_CFLAGS = "-Dmain=_single_binary_main_shuf(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_shuf" -Dusage=_usage_shuf $(src_coreutils_CFLAGS) +# Command sleep +noinst_LIBRARIES += src/libsinglebin_sleep.a +src_libsinglebin_sleep_a_SOURCES = src/sleep.c +src_libsinglebin_sleep_a_ldadd = $(LIB_NANOSLEEP) +src_libsinglebin_sleep_a_CFLAGS = "-Dmain=_single_binary_main_sleep(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sleep" -Dusage=_usage_sleep $(src_coreutils_CFLAGS) +# Command sort +noinst_LIBRARIES += src/libsinglebin_sort.a +src_libsinglebin_sort_a_SOURCES = src/sort.c +src_libsinglebin_sort_a_ldadd = $(LIB_EACCESS) $(LIB_NANOSLEEP) $(LIB_CRYPTO) $(LIB_PTHREAD) +src_libsinglebin_sort_a_CFLAGS = "-Dmain=_single_binary_main_sort(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sort" -Dusage=_usage_sort $(src_coreutils_CFLAGS) +# Command split +noinst_LIBRARIES += src/libsinglebin_split.a +src_libsinglebin_split_a_SOURCES = src/split.c +src_libsinglebin_split_a_ldadd = $(LIBICONV) +src_libsinglebin_split_a_CFLAGS = "-Dmain=_single_binary_main_split(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_split" -Dusage=_usage_split $(src_coreutils_CFLAGS) +# Command stat +noinst_LIBRARIES += src/libsinglebin_stat.a +src_libsinglebin_stat_a_SOURCES = src/stat.c src/find-mount-point.c +src_libsinglebin_stat_a_ldadd = $(LIB_SELINUX) $(LIB_NVPAIR) +src_libsinglebin_stat_a_CFLAGS = "-Dmain=_single_binary_main_stat(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_stat" -Dusage=_usage_stat $(src_coreutils_CFLAGS) +# Command sum +noinst_LIBRARIES += src/libsinglebin_sum.a +src_libsinglebin_sum_a_SOURCES = src/sum.c +src_libsinglebin_sum_a_CFLAGS = "-Dmain=_single_binary_main_sum(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sum" -Dusage=_usage_sum $(src_coreutils_CFLAGS) +# Command sync +noinst_LIBRARIES += src/libsinglebin_sync.a +src_libsinglebin_sync_a_SOURCES = src/sync.c +src_libsinglebin_sync_a_CFLAGS = "-Dmain=_single_binary_main_sync(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_sync" -Dusage=_usage_sync $(src_coreutils_CFLAGS) +# Command tac +noinst_LIBRARIES += src/libsinglebin_tac.a +src_libsinglebin_tac_a_SOURCES = src/tac.c +src_libsinglebin_tac_a_CFLAGS = "-Dmain=_single_binary_main_tac(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_tac" -Dusage=_usage_tac $(src_coreutils_CFLAGS) +# Command tail +noinst_LIBRARIES += src/libsinglebin_tail.a +src_libsinglebin_tail_a_SOURCES = src/tail.c +src_libsinglebin_tail_a_ldadd = $(LIB_NANOSLEEP) +src_libsinglebin_tail_a_CFLAGS = "-Dmain=_single_binary_main_tail(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_tail" -Dusage=_usage_tail $(src_coreutils_CFLAGS) +# Command tee +noinst_LIBRARIES += src/libsinglebin_tee.a +src_libsinglebin_tee_a_SOURCES = src/tee.c +src_libsinglebin_tee_a_CFLAGS = "-Dmain=_single_binary_main_tee(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_tee" -Dusage=_usage_tee $(src_coreutils_CFLAGS) +# Command test +noinst_LIBRARIES += src/libsinglebin_test.a +src_libsinglebin_test_a_SOURCES = src/test.c +src_libsinglebin_test_a_ldadd = $(LIB_EACCESS) +src_libsinglebin_test_a_CFLAGS = "-Dmain=_single_binary_main_test(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_test" -Dusage=_usage_test $(src_coreutils_CFLAGS) +# Command timeout +noinst_LIBRARIES += src/libsinglebin_timeout.a +src_libsinglebin_timeout_a_SOURCES = src/timeout.c src/operand2sig.c +src_libsinglebin_timeout_a_ldadd = $(LIB_TIMER_TIME) $(LIBICONV) +src_libsinglebin_timeout_a_CFLAGS = "-Dmain=_single_binary_main_timeout(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_timeout" -Dusage=_usage_timeout $(src_coreutils_CFLAGS) +# Command touch +noinst_LIBRARIES += src/libsinglebin_touch.a +src_libsinglebin_touch_a_SOURCES = src/touch.c +src_libsinglebin_touch_a_ldadd = $(LIB_CLOCK_GETTIME) +src_libsinglebin_touch_a_CFLAGS = "-Dmain=_single_binary_main_touch(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_touch" -Dusage=_usage_touch $(src_coreutils_CFLAGS) +# Command tr +noinst_LIBRARIES += src/libsinglebin_tr.a +src_libsinglebin_tr_a_SOURCES = src/tr.c +src_libsinglebin_tr_a_CFLAGS = "-Dmain=_single_binary_main_tr(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_tr" -Dusage=_usage_tr $(src_coreutils_CFLAGS) +# Command true +noinst_LIBRARIES += src/libsinglebin_true.a +src_libsinglebin_true_a_SOURCES = src/true.c +src_libsinglebin_true_a_CFLAGS = "-Dmain=_single_binary_main_true(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_true" -Dusage=_usage_true $(src_coreutils_CFLAGS) +# Command truncate +noinst_LIBRARIES += src/libsinglebin_truncate.a +src_libsinglebin_truncate_a_SOURCES = src/truncate.c +src_libsinglebin_truncate_a_ldadd = $(LIBICONV) +src_libsinglebin_truncate_a_CFLAGS = "-Dmain=_single_binary_main_truncate(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_truncate" -Dusage=_usage_truncate $(src_coreutils_CFLAGS) +# Command tsort +noinst_LIBRARIES += src/libsinglebin_tsort.a +src_libsinglebin_tsort_a_SOURCES = src/tsort.c +src_libsinglebin_tsort_a_CFLAGS = "-Dmain=_single_binary_main_tsort(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_tsort" -Dusage=_usage_tsort $(src_coreutils_CFLAGS) +# Command tty +noinst_LIBRARIES += src/libsinglebin_tty.a +src_libsinglebin_tty_a_SOURCES = src/tty.c +src_libsinglebin_tty_a_CFLAGS = "-Dmain=_single_binary_main_tty(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_tty" -Dusage=_usage_tty $(src_coreutils_CFLAGS) +# Command uname +noinst_LIBRARIES += src/libsinglebin_uname.a +src_libsinglebin_uname_a_SOURCES = src/uname.c src/uname-uname.c +src_libsinglebin_uname_a_ldadd = $(GETHOSTNAME_LIB) +src_libsinglebin_uname_a_CFLAGS = "-Dmain=_single_binary_main_uname(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_uname" -Dusage=_usage_uname $(src_coreutils_CFLAGS) +# Command unexpand +noinst_LIBRARIES += src/libsinglebin_unexpand.a +src_libsinglebin_unexpand_a_SOURCES = src/unexpand.c +src_libsinglebin_unexpand_a_CFLAGS = "-Dmain=_single_binary_main_unexpand(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_unexpand" -Dusage=_usage_unexpand $(src_coreutils_CFLAGS) +# Command uniq +noinst_LIBRARIES += src/libsinglebin_uniq.a +src_libsinglebin_uniq_a_SOURCES = src/uniq.c +src_libsinglebin_uniq_a_CFLAGS = "-Dmain=_single_binary_main_uniq(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_uniq" -Dusage=_usage_uniq $(src_coreutils_CFLAGS) +# Command unlink +noinst_LIBRARIES += src/libsinglebin_unlink.a +src_libsinglebin_unlink_a_SOURCES = src/unlink.c +src_libsinglebin_unlink_a_CFLAGS = "-Dmain=_single_binary_main_unlink(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_unlink" -Dusage=_usage_unlink $(src_coreutils_CFLAGS) +# Command vdir +noinst_LIBRARIES += src/libsinglebin_vdir.a +src_libsinglebin_vdir_a_SOURCES = src/coreutils-vdir.c +src_libsinglebin_vdir_a_ldadd = $(src_ls_LDADD) src/libsinglebin_ls.a +src_libsinglebin_vdir_a_CFLAGS = "-Dmain=_single_binary_main_vdir(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_vdir" -Dusage=_usage_vdir $(src_coreutils_CFLAGS) +# Command wc +noinst_LIBRARIES += src/libsinglebin_wc.a +src_libsinglebin_wc_a_SOURCES = src/wc.c +src_libsinglebin_wc_a_CFLAGS = "-Dmain=_single_binary_main_wc(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_wc" -Dusage=_usage_wc $(src_coreutils_CFLAGS) +# Command whoami +noinst_LIBRARIES += src/libsinglebin_whoami.a +src_libsinglebin_whoami_a_SOURCES = src/whoami.c +src_libsinglebin_whoami_a_CFLAGS = "-Dmain=_single_binary_main_whoami(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_whoami" -Dusage=_usage_whoami $(src_coreutils_CFLAGS) +# Command yes +noinst_LIBRARIES += src/libsinglebin_yes.a +src_libsinglebin_yes_a_SOURCES = src/yes.c +src_libsinglebin_yes_a_CFLAGS = "-Dmain=_single_binary_main_yes(int, char**) ATTRIBUTE_NORETURN; int _single_binary_main_yes" -Dusage=_usage_yes $(src_coreutils_CFLAGS) diff --git a/src/sleep.c b/src/sleep.c index b9163bc4..e24c2512 100644 --- a/src/sleep.c +++ b/src/sleep.c @@ -1,5 +1,5 @@ /* sleep - delay for a specified amount of time. - Copyright (C) 1984-2013 Free Software Foundation, Inc. + Copyright (C) 1984-2014 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 @@ -1,5 +1,5 @@ /* sort - sort lines of text (with all kinds of options). - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 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 @@ -221,7 +221,7 @@ struct keyfield 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. */ + units with either SI or IEC prefixes. */ bool month; /* Flag for comparison by month name. */ bool reverse; /* Reverse the sense of comparison. */ bool version; /* sort by version number */ @@ -373,6 +373,34 @@ static bool debug; number are present, temp files will be used. */ static unsigned int nmerge = NMERGE_DEFAULT; +/* Output an error to stderr using async-signal-safe routines, and _exit(). + This can be used safely from signal handlers, + and between fork() and exec() of multithreaded processes. */ + +static void async_safe_die (int, const char *) ATTRIBUTE_NORETURN; +static void +async_safe_die (int errnum, const char *errstr) +{ + ignore_value (write (STDERR_FILENO, errstr, strlen (errstr))); + + /* Even if defined HAVE_STRERROR_R, we can't use it, + as it may return a translated string etc. and even if not + may malloc() which is unsafe. We might improve this + by testing for sys_errlist and using that if available. + For now just report the error number. */ + if (errnum) + { + char errbuf[INT_BUFSIZE_BOUND (errnum)]; + char *p = inttostr (errnum, errbuf); + ignore_value (write (STDERR_FILENO, ": errno ", 8)); + ignore_value (write (STDERR_FILENO, p, strlen (p))); + } + + ignore_value (write (STDERR_FILENO, "\n", 1)); + + _exit (SORT_FAILURE); +} + /* Report MESSAGE for FILE, then clean up and exit. If FILE is null, it represents standard output. */ @@ -476,7 +504,7 @@ Other options:\n\ \n\ "), DEFAULT_TMPDIR); fputs (_("\ - -z, --zero-terminated end lines with 0 byte, not newline\n\ + -z, --zero-terminated line delimiter is NUL, not newline\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -982,8 +1010,8 @@ move_fd_or_die (int oldfd, int newfd) { if (oldfd != newfd) { - if (dup2 (oldfd, newfd) < 0) - error (SORT_FAILURE, errno, _("dup2 failed")); + /* This should never fail for our usage. */ + dup2 (oldfd, newfd); close (oldfd); } } @@ -1095,13 +1123,15 @@ maybe_create_temp (FILE **pfp, bool survive_fd_exhaustion) } else if (node->pid == 0) { + /* Being the child of a multithreaded program before exec(), + we're restricted to calling async-signal-safe routines here. */ close (pipefds[1]); move_fd_or_die (tempfd, STDOUT_FILENO); move_fd_or_die (pipefds[0], STDIN_FILENO); - if (execlp (compress_program, compress_program, (char *) NULL) < 0) - error (SORT_FAILURE, errno, _("couldn't execute %s"), - compress_program); + execlp (compress_program, compress_program, (char *) NULL); + + async_safe_die (errno, "couldn't execute compress program"); } } @@ -1153,13 +1183,15 @@ open_temp (struct tempnode *temp) break; case 0: + /* Being the child of a multithreaded program before exec(), + we're restricted to calling async-signal-safe routines here. */ close (pipefds[0]); move_fd_or_die (tempfd, STDIN_FILENO); move_fd_or_die (pipefds[1], STDOUT_FILENO); execlp (compress_program, compress_program, "-d", (char *) NULL); - error (SORT_FAILURE, errno, _("couldn't execute %s -d"), - compress_program); + + async_safe_die (errno, "couldn't execute compress program (with -d)"); default: temp->pid = child; @@ -1557,7 +1589,8 @@ initbuf (struct buffer *buf, size_t line_bytes, size_t alloc) static inline struct line * buffer_linelim (struct buffer const *buf) { - return (struct line *) (buf->buf + buf->alloc); + void *linelim = buf->buf + buf->alloc; + return linelim; } /* Return a pointer to the first character of the field specified @@ -3204,8 +3237,17 @@ merge_tree_init (size_t nthreads, size_t nlines, struct line *dest) /* Destroy the merge tree. */ static void -merge_tree_destroy (struct merge_node *merge_tree) +merge_tree_destroy (size_t nthreads, struct merge_node *merge_tree) { + size_t n_nodes = nthreads * 2; + struct merge_node *node = merge_tree; + + while (n_nodes--) + { + pthread_mutex_destroy (&node->lock); + node++; + } + free (merge_tree); } @@ -3321,8 +3363,8 @@ queue_insert (struct merge_node_queue *queue, struct merge_node *node) pthread_mutex_lock (&queue->mutex); heap_insert (queue->priority_queue, node); node->queued = true; - pthread_mutex_unlock (&queue->mutex); pthread_cond_signal (&queue->cond); + pthread_mutex_unlock (&queue->mutex); } /* Pop the top node off the priority QUEUE, lock the node, return it. */ @@ -3607,8 +3649,6 @@ sortlines (struct line *restrict lines, size_t nthreads, queue_insert (queue, node); merge_loop (queue, total_lines, tfp, temp_output); } - - pthread_mutex_destroy (&node->lock); } /* Scan through FILES[NTEMPS .. NFILES-1] looking for files that are @@ -3912,13 +3952,14 @@ sort (char *const *files, size_t nfiles, char const *output_file, queue_init (&queue, nthreads); struct merge_node *merge_tree = merge_tree_init (nthreads, buf.nlines, line); - struct merge_node *root = merge_tree + 1; - sortlines (line, nthreads, buf.nlines, root, + sortlines (line, nthreads, buf.nlines, merge_tree + 1, &queue, tfp, temp_output); + +#ifdef lint + merge_tree_destroy (nthreads, merge_tree); queue_destroy (&queue); - pthread_mutex_destroy (&root->lock); - merge_tree_destroy (merge_tree); +#endif } else write_unique (line - 1, tfp, temp_output); diff --git a/src/split.c b/src/split.c index e5e75f0f..dacacaa8 100644 --- a/src/split.c +++ b/src/split.c @@ -1,5 +1,5 @@ /* split.c -- split a file into pieces. - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 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 @@ -33,7 +33,6 @@ #include "error.h" #include "fd-reopen.h" #include "fcntl--.h" -#include "full-read.h" #include "full-write.h" #include "ioblksize.h" #include "quote.h" @@ -215,15 +214,15 @@ is -, read standard input.\n\ fprintf (stdout, _("\ -a, --suffix-length=N generate suffixes of length N (default %d)\n\ - --additional-suffix=SUFFIX append an additional SUFFIX to file names.\n\ + --additional-suffix=SUFFIX append an additional SUFFIX to file names\n\ -b, --bytes=SIZE put SIZE bytes per output file\n\ -C, --line-bytes=SIZE put at most SIZE bytes of lines per output file\n\ - -d, --numeric-suffixes[=FROM] use numeric suffixes instead of alphabetic.\n\ - FROM changes the start value (default 0).\n\ + -d, --numeric-suffixes[=FROM] use numeric suffixes instead of alphabetic;\n\ + FROM changes the start value (default 0)\n\ -e, --elide-empty-files do not generate empty output files with '-n'\n\ --filter=COMMAND write to shell COMMAND; file name is $FILE\n\ -l, --lines=NUMBER put NUMBER lines per output file\n\ - -n, --number=CHUNKS generate CHUNKS output files. See below\n\ + -n, --number=CHUNKS generate CHUNKS output files; see explanation below\n\ -u, --unbuffered immediately copy input to output with '-n r/...'\n\ "), DEFAULT_SUFFIX_LENGTH); fputs (_("\ @@ -526,8 +525,8 @@ bytes_split (uintmax_t n_bytes, char *buf, size_t bufsize, uintmax_t max_files) do { - n_read = full_read (STDIN_FILENO, buf, bufsize); - if (n_read < bufsize && errno) + n_read = safe_read (STDIN_FILENO, buf, bufsize); + if (n_read == SAFE_READ_ERROR) error (EXIT_FAILURE, errno, "%s", infile); bp_out = buf; to_read = n_read; @@ -562,7 +561,7 @@ bytes_split (uintmax_t n_bytes, char *buf, size_t bufsize, uintmax_t max_files) } } } - while (n_read == bufsize); + while (n_read); /* Ensure NUMBER files are created, which truncates any existing files or notifies any consumers on fifos. @@ -584,8 +583,8 @@ lines_split (uintmax_t n_lines, char *buf, size_t bufsize) do { - n_read = full_read (STDIN_FILENO, buf, bufsize); - if (n_read < bufsize && errno) + n_read = safe_read (STDIN_FILENO, buf, bufsize); + if (n_read == SAFE_READ_ERROR) error (EXIT_FAILURE, errno, "%s", infile); bp = bp_out = buf; eob = bp + n_read; @@ -614,64 +613,117 @@ lines_split (uintmax_t n_lines, char *buf, size_t bufsize) } } } - while (n_read == bufsize); + while (n_read); } - + /* Split into pieces that are as large as possible while still not more than N_BYTES bytes, and are split on line boundaries except - where lines longer than N_BYTES bytes occur. - FIXME: Allow N_BYTES to be any uintmax_t value, and don't require a - buffer of size N_BYTES, in case N_BYTES is very large. */ + where lines longer than N_BYTES bytes occur. */ static void -line_bytes_split (size_t n_bytes) +line_bytes_split (uintmax_t n_bytes, char *buf, size_t bufsize) { - char *bp; - bool eof = false; - size_t n_buffered = 0; - char *buf = xmalloc (n_bytes); + size_t n_read; + uintmax_t n_out = 0; /* for each split. */ + size_t n_hold = 0; + char *hold = NULL; /* for lines > bufsize. */ + size_t hold_size = 0; + bool split_line = false; /* Whether a \n was output in a split. */ do { - /* Fill up the full buffer size from the input file. */ - - size_t to_read = n_bytes - n_buffered; - size_t n_read = full_read (STDIN_FILENO, buf + n_buffered, to_read); - if (n_read < to_read && errno) + n_read = safe_read (STDIN_FILENO, buf, bufsize); + if (n_read == SAFE_READ_ERROR) error (EXIT_FAILURE, errno, "%s", infile); - - n_buffered += n_read; - if (n_buffered != n_bytes) + size_t n_left = n_read; + char *sob = buf; + while (n_left) { - if (n_buffered == 0) - break; - eof = true; - } + size_t split_rest = 0; + char *eoc = NULL; + char *eol; - /* Find where to end this chunk. */ - bp = buf + n_buffered; - if (n_buffered == n_bytes) - { - while (bp > buf && bp[-1] != '\n') - bp--; - } + /* Determine End Of Chunk and/or End of Line, + which are used below to select what to write or buffer. */ + if (n_bytes - n_out - n_hold <= n_left) + { + /* Have enough for split. */ + split_rest = n_bytes - n_out - n_hold; + eoc = sob + split_rest - 1; + eol = memrchr (sob, '\n', split_rest); + } + else + eol = memrchr (sob, '\n', n_left); - /* If chunk has no newlines, use all the chunk. */ - if (bp == buf) - bp = buf + n_buffered; + /* Output hold space if possible. */ + if (n_hold && !(!eol && n_out)) + { + cwrite (n_out == 0, hold, n_hold); + n_out += n_hold; + if (n_hold > bufsize) + hold = xrealloc (hold, bufsize); + n_hold = 0; + hold_size = bufsize; + } - /* Output the chars as one output file. */ - cwrite (true, buf, bp - buf); + /* Output to eol if present. */ + if (eol) + { + split_line = true; + size_t n_write = eol - sob + 1; + cwrite (n_out == 0, sob, n_write); + n_out += n_write; + n_left -= n_write; + sob += n_write; + if (eoc) + split_rest -= n_write; + } - /* Discard the chars we just output; move rest of chunk - down to be the start of the next chunk. Source and - destination probably overlap. */ - n_buffered -= bp - buf; - if (n_buffered > 0) - memmove (buf, bp, n_buffered); + /* Output to eoc or eob if possible. */ + if (n_left && !split_line) + { + size_t n_write = eoc ? split_rest : n_left; + cwrite (n_out == 0, sob, n_write); + n_out += n_write; + n_left -= n_write; + sob += n_write; + if (eoc) + split_rest -= n_write; + } + + /* Update hold if needed. */ + if ((eoc && split_rest) || (!eoc && n_left)) + { + size_t n_buf = eoc ? split_rest : n_left; + if (hold_size - n_hold < n_buf) + { + if (hold_size <= SIZE_MAX - bufsize) + hold_size += bufsize; + else + xalloc_die (); + hold = xrealloc (hold, hold_size); + } + memcpy (hold + n_hold, sob, n_buf); + n_hold += n_buf; + n_left -= n_buf; + sob += n_buf; + } + + /* Reset for new split. */ + if (eoc) + { + n_out = 0; + split_line = false; + } + } } - while (!eof); - free (buf); + while (n_read); + + /* Handle no eol at end of file. */ + if (n_hold) + cwrite (n_out == 0, hold, n_hold); + + free (hold); } /* -n l/[K/]N: Write lines to files of approximately file size / N. @@ -709,8 +761,8 @@ lines_chunk_split (uintmax_t k, uintmax_t n, char *buf, size_t bufsize, while (n_written < file_size) { char *bp = buf, *eob; - size_t n_read = full_read (STDIN_FILENO, buf, bufsize); - if (n_read < bufsize && errno) + size_t n_read = safe_read (STDIN_FILENO, buf, bufsize); + if (n_read == SAFE_READ_ERROR) error (EXIT_FAILURE, errno, "%s", infile); else if (n_read == 0) break; /* eof. */ @@ -804,8 +856,8 @@ bytes_chunk_extract (uintmax_t k, uintmax_t n, char *buf, size_t bufsize, while (start < end) { - size_t n_read = full_read (STDIN_FILENO, buf, bufsize); - if (n_read < bufsize && errno) + size_t n_read = safe_read (STDIN_FILENO, buf, bufsize); + if (n_read == SAFE_READ_ERROR) error (EXIT_FAILURE, errno, "%s", infile); else if (n_read == 0) break; /* eof. */ @@ -926,7 +978,7 @@ lines_rr (uintmax_t k, uintmax_t n, char *buf, size_t bufsize) else { if (SIZE_MAX < n) - error (exit_failure, 0, "%s", _("memory exhausted")); + xalloc_die (); files = xnmalloc (n, sizeof *files); /* Generate output file names. */ @@ -945,8 +997,6 @@ lines_rr (uintmax_t k, uintmax_t n, char *buf, size_t bufsize) while (true) { char *bp = buf, *eob; - /* Use safe_read() rather than full_read() here - so that we process available data immediately. */ size_t n_read = safe_read (STDIN_FILENO, buf, bufsize); if (n_read == SAFE_READ_ERROR) error (EXIT_FAILURE, errno, "%s", infile); @@ -1408,7 +1458,7 @@ main (int argc, char **argv) break; case type_byteslines: - line_bytes_split (n_units); + line_bytes_split (n_units, buf, in_blk_size); break; case type_chunk_bytes: @@ -1,5 +1,5 @@ /* stat.c -- display file or file system status - Copyright (C) 2001-2013 Free Software Foundation, Inc. + Copyright (C) 2001-2014 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 @@ -152,6 +152,11 @@ statfs (char const *filename, struct fs_info *buf) # endif #endif +#if HAVE_GETATTRAT +# include <attr.h> +# include <sys/nvpair.h> +#endif + /* FIXME: these are used by printf.c, too */ #define isodigit(c) ('0' <= (c) && (c) <= '7') #define octtobin(c) ((c) - '0') @@ -179,7 +184,6 @@ enum 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'}, @@ -276,6 +280,8 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) return "coda"; case S_MAGIC_COH: /* 0x012FF7B7 local */ return "coh"; + case S_MAGIC_CONFIGFS: /* 0x62656570 local */ + return "configfs"; case S_MAGIC_CRAMFS: /* 0x28CD3D45 local */ return "cramfs"; case S_MAGIC_CRAMFS_WEND: /* 0x453DCD28 local */ @@ -288,14 +294,20 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) return "devpts"; case S_MAGIC_ECRYPTFS: /* 0xF15F local */ return "ecryptfs"; + case S_MAGIC_EFIVARFS: /* 0xDE5E81E4 local */ + return "efivarfs"; case S_MAGIC_EFS: /* 0x00414A53 local */ return "efs"; + case S_MAGIC_EXOFS: /* 0x5DF5 local */ + return "exofs"; case S_MAGIC_EXT: /* 0x137D local */ return "ext"; case S_MAGIC_EXT2: /* 0xEF53 local */ return "ext2/ext3"; case S_MAGIC_EXT2_OLD: /* 0xEF51 local */ return "ext2"; + case S_MAGIC_F2FS: /* 0xF2F52010 local */ + return "f2fs"; case S_MAGIC_FAT: /* 0x4006 local */ return "fat"; case S_MAGIC_FHGFS: /* 0x19830326 remote */ @@ -306,12 +318,18 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) return "fusectl"; case S_MAGIC_FUTEXFS: /* 0x0BAD1DEA local */ return "futexfs"; - case S_MAGIC_GFS: /* 0x1161970 remote */ + case S_MAGIC_GFS: /* 0x01161970 remote */ return "gfs/gfs2"; case S_MAGIC_GPFS: /* 0x47504653 remote */ return "gpfs"; case S_MAGIC_HFS: /* 0x4244 local */ return "hfs"; + case S_MAGIC_HFS_PLUS: /* 0x482B local */ + return "hfs+"; + case S_MAGIC_HFS_X: /* 0x4858 local */ + return "hfsx"; + case S_MAGIC_HOSTFS: /* 0x00C0FFEE local */ + return "hostfs"; case S_MAGIC_HPFS: /* 0xF995E849 local */ return "hpfs"; case S_MAGIC_HUGETLBFS: /* 0x958458F6 local */ @@ -334,6 +352,8 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) return "jfs"; case S_MAGIC_KAFS: /* 0x6B414653 remote */ return "k-afs"; + case S_MAGIC_LOGFS: /* 0xC97E8168 local */ + return "logfs"; case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */ return "lustre"; case S_MAGIC_MINIX: /* 0x137F local */ @@ -362,7 +382,7 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) return "ntfs"; case S_MAGIC_OPENPROM: /* 0x9FA1 local */ return "openprom"; - case S_MAGIC_OCFS2: /* 0x7461636f remote */ + case S_MAGIC_OCFS2: /* 0x7461636F remote */ return "ocfs2"; case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */ return "panfs"; @@ -391,8 +411,12 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) return "securityfs"; case S_MAGIC_SELINUX: /* 0xF97CFF8C local */ return "selinux"; + case S_MAGIC_SMACK: /* 0x43415D53 local */ + return "smackfs"; case S_MAGIC_SMB: /* 0x517B remote */ return "smb"; + case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */ + return "snfs"; case S_MAGIC_SOCKFS: /* 0x534F434B local */ return "sockfs"; case S_MAGIC_SQUASHFS: /* 0x73717368 local */ @@ -405,6 +429,8 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) return "sysv4"; case S_MAGIC_TMPFS: /* 0x01021994 local */ return "tmpfs"; + case S_MAGIC_UBIFS: /* 0x24051905 local */ + return "ubifs"; case S_MAGIC_UDF: /* 0x15013346 local */ return "udf"; case S_MAGIC_UFS: /* 0x00011954 local */ @@ -417,7 +443,9 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) return "v9fs"; case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */ return "vmhgfs"; - case S_MAGIC_VXFS: /* 0xA501FCF5 local */ + case S_MAGIC_VXFS: /* 0xA501FCF5 remote */ + /* Veritas File System can run in single instance or clustered mode, + so mark as remote to cater for the latter case. */ return "vxfs"; case S_MAGIC_VZFS: /* 0x565A4653 local */ return "vzfs"; @@ -583,7 +611,7 @@ out_minus_zero (char *pformat, size_t prefix_len) acts like printf's %f format. */ static void out_epoch_sec (char *pformat, size_t prefix_len, - struct stat const *statbuf ATTRIBUTE_UNUSED, + struct stat const *statbuf _GL_UNUSED, struct timespec arg) { char *dot = memchr (pformat, '.', prefix_len); @@ -714,7 +742,7 @@ out_file_context (char *pformat, size_t prefix_len, char const *filename) /* Print statfs info. Return zero upon success, nonzero upon failure. */ static bool ATTRIBUTE_WARN_UNUSED_RESULT print_statfs (char *pformat, size_t prefix_len, unsigned int m, - char const *filename, + int fd, char const *filename, void const *data) { STRUCT_STATVFS const *statfsbuf = data; @@ -815,17 +843,19 @@ find_bind_mount (char const * name) tried_mount_list = true; } + struct stat name_stats; + if (stat (name, &name_stats) != 0) + return NULL; + struct mount_entry *me; for (me = mount_list; me; me = me->me_next) { if (me->me_dummy && me->me_devname[0] == '/' && STREQ (me->me_mountdir, name)) { - struct stat name_stats; struct stat dev_stats; - if (stat (name, &name_stats) == 0 - && stat (me->me_devname, &dev_stats) == 0 + if (stat (me->me_devname, &dev_stats) == 0 && SAME_INODE (name_stats, dev_stats)) { bind_mount = me->me_devname; @@ -886,6 +916,38 @@ print_mount_point: return fail; } +static struct timespec +get_birthtime (int fd, char const *filename, struct stat const *st) +{ + struct timespec ts = get_stat_birthtime (st); + +#if HAVE_GETATTRAT + if (ts.tv_nsec < 0) + { + nvlist_t *response; + if ((fd < 0 + ? getattrat (AT_FDCWD, XATTR_VIEW_READWRITE, filename, &response) + : fgetattr (fd, XATTR_VIEW_READWRITE, &response)) + == 0) + { + uint64_t *val; + uint_t n; + if (nvlist_lookup_uint64_array (response, A_CRTIME, &val, &n) == 0 + && 2 <= n + && val[0] <= TYPE_MAXIMUM (time_t) + && val[1] < 1000000000 * 2 /* for leap seconds */) + { + ts.tv_sec = val[0]; + ts.tv_nsec = val[1]; + } + nvlist_free (response); + } + } +#endif + + return ts; +} + /* Map a TS with negative TS.tv_nsec to {0,0}. */ static inline struct timespec neg_to_zero (struct timespec ts) @@ -899,7 +961,7 @@ neg_to_zero (struct timespec ts) /* Print stat info. Return zero upon success, nonzero upon failure. */ static bool print_stat (char *pformat, size_t prefix_len, unsigned int m, - char const *filename, void const *data) + int fd, char const *filename, void const *data) { struct stat *statbuf = (struct stat *) data; struct passwd *pw_ent; @@ -955,7 +1017,6 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, 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"); @@ -964,7 +1025,6 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, 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"); @@ -992,7 +1052,7 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, break; case 'w': { - struct timespec t = get_stat_birthtime (statbuf); + struct timespec t = get_birthtime (fd, filename, statbuf); if (t.tv_nsec < 0) out_string (pformat, prefix_len, "-"); else @@ -1001,7 +1061,7 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, break; case 'W': out_epoch_sec (pformat, prefix_len, statbuf, - neg_to_zero (get_stat_birthtime (statbuf))); + neg_to_zero (get_birthtime (fd, filename, statbuf))); break; case 'x': out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf))); @@ -1076,9 +1136,9 @@ print_esc_char (char c) calling PRINT_FUNC for each %-directive encountered. Return zero upon success, nonzero upon failure. */ static bool ATTRIBUTE_WARN_UNUSED_RESULT -print_it (char const *format, char const *filename, +print_it (char const *format, int fd, char const *filename, bool (*print_func) (char *, size_t, unsigned int, - char const *, void const *), + int, char const *, void const *), void const *data) { bool fail = false; @@ -1127,7 +1187,8 @@ print_it (char const *format, char const *filename, putchar ('%'); break; default: - fail |= print_func (dest, len + 1, fmt_code, filename, data); + fail |= print_func (dest, len + 1, fmt_code, + fd, filename, data); break; } break; @@ -1210,7 +1271,7 @@ do_statfs (char const *filename, char const *format) return false; } - bool fail = print_it (format, filename, print_statfs, &statfsbuf); + bool fail = print_it (format, -1, filename, print_statfs, &statfsbuf); return ! fail; } @@ -1219,11 +1280,12 @@ static bool ATTRIBUTE_WARN_UNUSED_RESULT do_stat (char const *filename, char const *format, char const *format2) { + int fd = STREQ (filename, "-") ? 0 : -1; struct stat statbuf; - if (STREQ (filename, "-")) + if (0 <= fd) { - if (fstat (STDIN_FILENO, &statbuf) != 0) + if (fstat (fd, &statbuf) != 0) { error (0, errno, _("cannot stat standard input")); return false; @@ -1243,7 +1305,7 @@ do_stat (char const *filename, char const *format, if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode)) format = format2; - bool fail = print_it (format, filename, print_stat, &statbuf); + bool fail = print_it (format, fd, filename, print_stat, &statbuf); return ! fail; } @@ -1361,8 +1423,8 @@ Display file or file system status.\n\ -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\ + 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); @@ -1393,8 +1455,8 @@ The valid format sequences for files (without --file-system):\n\ %N quoted file name with dereference if symbolic link\n\ %o optimal I/O transfer size hint\n\ %s total size, in bytes\n\ - %t major device type in hex\n\ - %T minor device type in hex\n\ + %t major device type in hex, for character/block device special files\n\ + %T minor device type in hex, for character/block device special files\n\ "), stdout); fputs (_("\ %u user ID of owner\n\ @@ -1403,10 +1465,10 @@ The valid format sequences for files (without --file-system):\n\ %W time of file birth, seconds since Epoch; 0 if unknown\n\ %x time of last access, human-readable\n\ %X time of last access, seconds since Epoch\n\ - %y time of last modification, human-readable\n\ - %Y time of last modification, seconds since Epoch\n\ - %z time of last change, human-readable\n\ - %Z time of last change, seconds since Epoch\n\ + %y time of last data modification, human-readable\n\ + %Y time of last data modification, seconds since Epoch\n\ + %z time of last status change, human-readable\n\ + %Z time of last status change, seconds since Epoch\n\ \n\ "), stdout); diff --git a/src/stdbuf.c b/src/stdbuf.c index 38e9bee7..92ee2826 100644 --- a/src/stdbuf.c +++ b/src/stdbuf.c @@ -1,5 +1,5 @@ /* stdbuf -- setup the standard streams for a command - Copyright (C) 2009-2013 Free Software Foundation, Inc. + Copyright (C) 2009-2014 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 @@ -187,7 +187,12 @@ static void set_LD_PRELOAD (void) { int ret; - char *old_libs = getenv ("LD_PRELOAD"); +#ifdef __APPLE__ + char const *preload_env = "DYLD_INSERT_LIBRARIES"; +#else + char const *preload_env = "LD_PRELOAD"; +#endif + char *old_libs = getenv (preload_env); char *LD_PRELOAD; /* Note this would auto add the appropriate search path for "libstdbuf.so": @@ -195,7 +200,17 @@ set_LD_PRELOAD (void) However we want the lookup done for the exec'd command not stdbuf. Since we don't link against libstdbuf.so add it to PKGLIBEXECDIR - rather than to LIBDIR. */ + rather than to LIBDIR. + + Note we could add "" as the penultimate item in the following list + to enable searching for libstdbuf.so in the default system lib paths. + However that would not indicate an error if libstdbuf.so was not found. + Also while this could support auto selecting the right arch in a multilib + environment, what we really want is to auto select based on the arch of the + command being run, rather than that of stdbuf itself. This is currently + not supported due to the unusual need for controlling the stdio buffering + of programs that are a different architecture to the default on the + system (and that of stdbuf itself). */ char const *const search_path[] = { program_path, PKGLIBEXECDIR, @@ -229,9 +244,9 @@ set_LD_PRELOAD (void) /* FIXME: Do we need to support libstdbuf.dll, c:, '\' separators etc? */ if (old_libs) - ret = asprintf (&LD_PRELOAD, "LD_PRELOAD=%s:%s", old_libs, libstdbuf); + ret = asprintf (&LD_PRELOAD, "%s=%s:%s", preload_env, old_libs, libstdbuf); else - ret = asprintf (&LD_PRELOAD, "LD_PRELOAD=%s", libstdbuf); + ret = asprintf (&LD_PRELOAD, "%s=%s", preload_env, libstdbuf); if (ret < 0) xalloc_die (); @@ -239,6 +254,10 @@ set_LD_PRELOAD (void) free (libstdbuf); ret = putenv (LD_PRELOAD); +#ifdef __APPLE__ + if (ret == 0) + ret = putenv ("DYLD_FORCE_FLAT_NAMESPACE=y"); +#endif if (ret != 0) { @@ -248,12 +267,14 @@ set_LD_PRELOAD (void) } } -/* Populate environ with _STDBUF_I=$MODE _STDBUF_O=$MODE _STDBUF_E=$MODE */ +/* Populate environ with _STDBUF_I=$MODE _STDBUF_O=$MODE _STDBUF_E=$MODE. + Return TRUE if any environment variables set. */ -static void +static bool set_libstdbuf_options (void) { - unsigned int i; + bool env_set = false; + size_t i; for (i = 0; i < ARRAY_CARDINALITY (stdbuf); i++) { @@ -278,8 +299,12 @@ set_libstdbuf_options (void) _("failed to update the environment with %s"), quote (var)); } + + env_set = true; } } + + return env_set; } int @@ -346,9 +371,11 @@ main (int argc, char **argv) usage (EXIT_CANCELED); } - /* FIXME: Should we mandate at least one option? */ - - set_libstdbuf_options (); + if (! set_libstdbuf_options ()) + { + error (0, 0, _("you must specify a buffering mode option")); + usage (EXIT_CANCELED); + } /* Try to preload libstdbuf first from the same path as stdbuf is running from. */ @@ -1,5 +1,5 @@ /* stty -- change and print terminal line settings - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 @@ -205,6 +205,9 @@ static struct mode_info const mode_info[] = { {"parenb", control, REV, PARENB, 0}, {"parodd", control, REV, PARODD, 0}, +#ifdef CMSPAR + {"cmspar", control, REV, CMSPAR, 0}, +#endif {"cs5", control, 0, CS5, CSIZE}, {"cs6", control, 0, CS6, CSIZE}, {"cs7", control, 0, CS7, CSIZE}, @@ -593,6 +596,7 @@ Control settings:\n\ [-]hupcl same as [-]hup\n\ [-]parenb generate parity bit in output and expect parity bit in input\n\ [-]parodd set odd parity (or even parity with '-')\n\ + * [-]cmspar use \"stick\" (mark/space) parity\n\ "), stdout); fputs (_("\ \n\ @@ -630,7 +634,7 @@ Output settings:\n\ "), stdout); fputs (_("\ * [-]ocrnl translate carriage return to newline\n\ - * [-]ofdel use delete characters for fill instead of null characters\n\ + * [-]ofdel use delete characters for fill instead of NUL characters\n\ * [-]ofill use fill (padding) characters instead of timing for delays\n\ * [-]olcuc translate lowercase characters to uppercase\n\ * [-]onlcr translate newline to carriage return-newline\n\ @@ -745,7 +749,7 @@ main (int argc, char **argv) int argi = 0; int opti = 1; bool require_set_attr; - bool speed_was_set ATTRIBUTE_UNUSED; + bool speed_was_set _GL_UNUSED; bool verbose_output; bool recoverable_output; int k; @@ -1,5 +1,5 @@ /* sum -- checksum and count the blocks in a file - Copyright (C) 1986-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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 @@ -1,5 +1,5 @@ /* sync - update the super block - Copyright (C) 1994-2013 Free Software Foundation, Inc. + Copyright (C) 1994-2014 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 diff --git a/src/system.h b/src/system.h index 1677999e..162446c1 100644 --- a/src/system.h +++ b/src/system.h @@ -1,5 +1,5 @@ /* system-dependent definitions for coreutils - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -330,7 +330,7 @@ enum #define GETOPT_VERSION_OPTION_DECL \ "version", no_argument, NULL, GETOPT_VERSION_CHAR #define GETOPT_SELINUX_CONTEXT_OPTION_DECL \ - "context", required_argument, NULL, 'Z' + "context", optional_argument, NULL, 'Z' #define case_GETOPT_HELP_CHAR \ case GETOPT_HELP_CHAR: \ @@ -425,10 +425,6 @@ enum # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) #endif -#ifndef ATTRIBUTE_UNUSED -# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif - /* The warn_unused_result attribute appeared first in gcc-3.4.0 */ #undef ATTRIBUTE_WARN_UNUSED_RESULT #if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) @@ -500,21 +496,24 @@ ptr_align (void const *ptr, size_t alignment) Note the word after the buffer must be non NUL. */ static inline bool _GL_ATTRIBUTE_PURE -is_nul (const char *buf, size_t bufsize) +is_nul (void const *buf, size_t bufsize) { typedef uintptr_t word; + void const *vp; + char const *cbuf = buf; + word const *wp = buf; /* Find first nonzero *word*, or the word with the sentinel. */ - word *wp = (word *) buf; while (*wp++ == 0) continue; /* Find the first nonzero *byte*, or the sentinel. */ - char *cp = (char *) (wp - 1); + vp = wp - 1; + char const *cp = vp; while (*cp++ == 0) continue; - return cp > buf + bufsize; + return cbuf + bufsize < cp; } /* If 10*Accum + Digit_val is larger than the maximum value for Type, @@ -550,8 +549,8 @@ static inline void emit_size_note (void) { fputs (_("\n\ -SIZE is an integer and optional unit (example: 10M is 10*1024*1024). Units\n\ -are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB, ... (powers of 1000).\n\ +The SIZE argument is an integer and optional unit (example: 10K is 10*1024).\n\ +Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers of 1000).\n\ "), stdout); } @@ -568,11 +567,7 @@ Otherwise, units default to 1024 bytes (or 512 if POSIXLY_CORRECT is set).\n\ static inline void emit_ancillary_info (void) { - printf (_("\nReport %s bugs to %s\n"), last_component (program_name), - PACKAGE_BUGREPORT); - printf (_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); - fputs (_("General help using GNU software: <http://www.gnu.org/gethelp/>\n"), - stdout); + printf (_("\n%s online help: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); /* Don't output this redundant message for English locales. Note we still output for 'C' so that it gets included in the man page. */ const char *lc_messages = setlocale (LC_MESSAGES, NULL); @@ -622,6 +617,16 @@ usable_st_size (struct stat const *sb) void usage (int status) ATTRIBUTE_NORETURN; +/* Like error(0, 0, ...), but without an implicit newline. + Also a noop unless the global DEV_DEBUG is set. */ +#define devmsg(...) \ + do \ + { \ + if (dev_debug) \ + fprintf (stderr, __VA_ARGS__); \ + } \ + while (0) + #define emit_cycle_warning(file_name) \ do \ { \ @@ -652,3 +657,9 @@ stzncpy (char *restrict dest, char const *restrict src, size_t len) #ifndef ARRAY_CARDINALITY # define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array)) #endif + +/* Avoid const warnings by casting to more portable type. + This is to cater for the incorrect const function declarations + in selinux.h before libselinux-2.3 (May 2014). + When version >= 2.3 is ubiquitous remove this function. */ +static inline char * se_const (char const * sctx) { return (char *) sctx; } diff --git a/src/tac-pipe.c b/src/tac-pipe.c index f29db43c..8e634f3e 100644 --- a/src/tac-pipe.c +++ b/src/tac-pipe.c @@ -1,6 +1,6 @@ /* tac from a pipe. - Copyright (C) 1997-2013 Free Software Foundation, Inc. + Copyright (C) 1997-2014 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 @@ -1,5 +1,5 @@ /* tac - concatenate and print files in reverse - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 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 @@ -409,7 +409,7 @@ record_or_unlink_tempfile (char const *fn, FILE *fp) #else static void -record_or_unlink_tempfile (char const *fn, FILE *fp ATTRIBUTE_UNUSED) +record_or_unlink_tempfile (char const *fn, FILE *fp _GL_UNUSED) { unlink (fn); } @@ -1,5 +1,5 @@ /* tail -- output the last part of file(s) - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -268,25 +268,24 @@ With no FILE, or when FILE is -, read standard input.\n\ emit_mandatory_arg_note (); fputs (_("\ - -c, --bytes=K output the last K bytes; alternatively, use -c +K\n\ - to output bytes starting with the Kth of each file\n\ + -c, --bytes=K output the last K bytes; or use -c +K to output\n\ + bytes starting with the Kth of each file\n\ "), stdout); fputs (_("\ -f, --follow[={name|descriptor}]\n\ output appended data as the file grows;\n\ - -f, --follow, and --follow=descriptor are\n\ - equivalent\n\ + an absent option argument means 'descriptor'\n\ -F same as --follow=name --retry\n\ "), stdout); printf (_("\ -n, --lines=K output the last K lines, instead of the last %d;\n\ - or use -n +K to output lines starting with the Kth\n\ + or use -n +K to output starting with the Kth\n\ --max-unchanged-stats=N\n\ with --follow=name, reopen a FILE which has not\n\ - changed size after N (default %d) iterations\n\ - to see if it has been unlinked or renamed\n\ - (this is the usual case of rotated log files).\n\ - With inotify, this option is rarely useful.\n\ + changed size after N (default %d) iterations\n\ + to see if it has been unlinked or renamed\n\ + (this is the usual case of rotated log files);\n\ + with inotify, this option is rarely useful\n\ "), DEFAULT_N_LINES, DEFAULT_MAX_N_UNCHANGED_STATS_BETWEEN_OPENS @@ -294,15 +293,13 @@ With no FILE, or when FILE is -, read standard input.\n\ fputs (_("\ --pid=PID with -f, terminate after process ID, PID dies\n\ -q, --quiet, --silent never output headers giving file names\n\ - --retry keep trying to open a file even when it is or\n\ - becomes inaccessible; useful when following by\n\ - name, i.e., with --follow=name\n\ + --retry keep trying to open a file if it is inaccessible\n\ "), stdout); fputs (_("\ -s, --sleep-interval=N with -f, sleep for approximately N seconds\n\ - (default 1.0) between iterations.\n\ - With inotify and --pid=P, check process P at\n\ - least once every N seconds.\n\ + (default 1.0) between iterations;\n\ + with inotify and --pid=P, check process P at\n\ + least once every N seconds\n\ -v, --verbose always output headers giving file names\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); @@ -342,13 +339,6 @@ pretty_name (struct File_spec const *f) return (STREQ (f->name, "-") ? _("standard input") : f->name); } -static void -xwrite_stdout (char const *buffer, size_t n_bytes) -{ - if (n_bytes > 0 && fwrite (buffer, 1, n_bytes, stdout) == 0) - error (EXIT_FAILURE, errno, _("write error")); -} - /* Record a file F with descriptor FD, size SIZE, status ST, and blocking status BLOCKING. */ @@ -388,6 +378,20 @@ write_header (const char *pretty_filename) first_file = false; } +/* Write N_BYTES from BUFFER to stdout. + Exit immediately on error with a single diagnostic. */ + +static void +xwrite_stdout (char const *buffer, size_t n_bytes) +{ + if (n_bytes > 0 && fwrite (buffer, 1, n_bytes, stdout) < n_bytes) + { + clearerr (stdout); /* To avoid redundant close_stdout diagnostic. */ + error (EXIT_FAILURE, errno, _("error writing %s"), + quote ("standard output")); + } +} + /* Read and output N_BYTES of file PRETTY_FILENAME starting at the current position in FD. If N_BYTES is COPY_TO_EOF, then copy until end of file. If N_BYTES is COPY_A_BUFFER, then copy at most one buffer's worth. @@ -948,7 +952,20 @@ recheck (struct File_spec *f, bool blocking) then mark the file as not tailable. */ f->tailable = !(reopen_inaccessible_files && fd == -1); - if (fd == -1 || fstat (fd, &new_stats) < 0) + if (! disable_inotify && ! lstat (f->name, &new_stats) + && S_ISLNK (new_stats.st_mode)) + { + /* Diagnose the edge case where a regular file is changed + to a symlink. We avoid inotify with symlinks since + it's awkward to match between symlink name and target. */ + ok = false; + f->errnum = -1; + f->ignore = true; + + error (0, 0, _("%s has been replaced with a symbolic link. " + "giving up on this name"), quote (pretty_name (f))); + } + else if (fd == -1 || fstat (fd, &new_stats) < 0) { ok = false; f->errnum = errno; @@ -1054,16 +1071,32 @@ recheck (struct File_spec *f, bool blocking) } /* Return true if any of the N_FILES files in F are live, i.e., have - open file descriptors. */ + open file descriptors, or should be checked again (see --retry). + When following descriptors, checking should only continue when any + of the files is not yet ignored. */ static bool any_live_files (const struct File_spec *f, size_t n_files) { size_t i; + if (reopen_inaccessible_files && follow_mode == Follow_name) + return true; /* continue following for -F option */ + for (i = 0; i < n_files; i++) - if (0 <= f[i].fd) - return true; + { + if (0 <= f[i].fd) + { + return true; + } + else + { + if (reopen_inaccessible_files && follow_mode == Follow_descriptor) + if (! f[i].ignore) + return true; + } + } + return false; } @@ -1191,7 +1224,7 @@ tail_forever (struct File_spec *f, size_t n_files, double sleep_interval) f[i].size += bytes_read; } - if (! any_live_files (f, n_files) && ! reopen_inaccessible_files) + if (! any_live_files (f, n_files)) { error (0, 0, _("no files remaining")); break; @@ -1238,6 +1271,23 @@ any_remote_file (const struct File_spec *f, size_t n_files) return false; } +/* Return true if any of the N_FILES files in F is a symlink. + Note we don't worry about the edge case where "-" exists, + since that will have the same consequences for inotify, + which is the only context this function is currently used. */ + +static bool +any_symlinks (const struct File_spec *f, size_t n_files) +{ + size_t i; + + struct stat st; + for (i = 0; i < n_files; i++) + if (lstat (f[i].name, &st) == 0 && S_ISLNK (st.st_mode)) + return true; + return false; +} + /* Return true if any of the N_FILES files in F represents stdin and is tailable. */ @@ -1272,7 +1322,12 @@ static void check_fspec (struct File_spec *fspec, int wd, int *prev_wd) { struct stat stats; - char const *name = pretty_name (fspec); + char const *name; + + if (fspec->fd == -1) + return; + + name = pretty_name (fspec); if (fstat (fspec->fd, &stats) != 0) { @@ -1432,6 +1487,7 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files, { struct File_spec *fspec; struct inotify_event *ev; + void *void_ev; /* When following by name without --retry, and the last file has been unlinked or renamed-away, diagnose it and return. */ @@ -1493,7 +1549,8 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files, error (EXIT_FAILURE, errno, _("error reading inotify event")); } - ev = (struct inotify_event *) (evbuf + evbuf_off); + void_ev = evbuf + evbuf_off; + ev = void_ev; evbuf_off += sizeof (*ev) + ev->len; if (ev->len) /* event on ev->name in watched directory */ @@ -1516,6 +1573,7 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files, int new_wd = inotify_add_watch (wd, f[j].name, inotify_wd_mask); if (new_wd < 0) { + /* Can get ENOENT for a dangling symlink for example. */ error (0, errno, _("cannot watch %s"), quote (f[j].name)); continue; } @@ -2030,8 +2088,17 @@ parse_options (int argc, char **argv, } } - if (reopen_inaccessible_files && follow_mode != Follow_name) - error (0, 0, _("warning: --retry is useful mainly when following by name")); + if (reopen_inaccessible_files) + { + if (!forever) + { + reopen_inaccessible_files = false; + error (0, 0, _("warning: --retry ignored; --retry is useful" + " only when following")); + } + else if (follow_mode == Follow_descriptor) + error (0, 0, _("warning: --retry only effective for the initial open")); + } if (pid && !forever) error (0, 0, @@ -2149,6 +2216,10 @@ main (int argc, char **argv) " indefinitely is ineffective")); } + /* Don't read anything if we'll never output anything. */ + if (! n_units && ! forever && ! from_start) + exit (EXIT_SUCCESS); + F = xnmalloc (n_files, sizeof *F); for (i = 0; i < n_files; i++) F[i].name = file[i]; @@ -2178,6 +2249,15 @@ main (int argc, char **argv) in this case because it would miss any updates to the file that were not initiated from the local system. + any_symlinks() checks if the user has specified any symbolic links. + inotify is not used in this case because it returns updated _targets_ + which would not match the specified names. If we tried to always + use the target names, then we would miss changes to the symlink itself. + + ok is false when one of the files specified could not be opened for + reading. In this case and when following by descriptor, + tail_forever_inotify() cannot be used (in its current implementation). + FIXME: inotify doesn't give any notification when a new (remote) file or directory is mounted on top a watched file. When follow_mode == Follow_name we would ideally like to detect that. @@ -2189,7 +2269,9 @@ main (int argc, char **argv) is recreated, then we don't recheck any new file when follow_mode == Follow_name */ if (!disable_inotify && (tailable_stdin (F, n_files) - || any_remote_file (F, n_files))) + || any_remote_file (F, n_files) + || any_symlinks (F, n_files) + || (!ok && follow_mode == Follow_descriptor))) disable_inotify = true; if (!disable_inotify) @@ -1,5 +1,5 @@ /* tee - read from standard input and write to standard output and files. - Copyright (C) 1985-2013 Free Software Foundation, Inc. + Copyright (C) 1985-2014 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 @@ -2,7 +2,7 @@ /* Modified to run with the GNU shell by bfox. */ -/* Copyright (C) 1987-2013 Free Software Foundation, Inc. +/* Copyright (C) 1987-2014 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 diff --git a/src/timeout.c b/src/timeout.c index 2ffd2b11..68baa23c 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1,5 +1,5 @@ /* timeout -- run a command with bounded time - Copyright (C) 2008-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2014 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 @@ -118,7 +118,7 @@ unblock_signal (int sig) as that's more useful in practice than reporting an error. '0' means don't timeout. */ static void -settimeout (double duration) +settimeout (double duration, bool warn) { /* We configure timers below so that SIGALRM is sent on expiry. @@ -142,11 +142,12 @@ settimeout (double duration) return; else { - error (0, errno, _("warning: timer_settime")); + if (warn) + error (0, errno, _("warning: timer_settime")); timer_delete (timerid); } } - else if (errno != ENOSYS) + else if (warn && errno != ENOSYS) error (0, errno, _("warning: timer_create")); #endif @@ -190,10 +191,12 @@ cleanup (int sig) { if (kill_after) { + int saved_errno = errno; /* settimeout may reset. */ /* Start a new timeout after which we'll send SIGKILL. */ term_signal = SIGKILL; - settimeout (kill_after); + settimeout (kill_after, false); kill_after = 0; /* Don't let later signals reset kill alarm. */ + errno = saved_errno; } /* Send the signal directly to the monitored child, @@ -235,18 +238,18 @@ Start COMMAND, and kill it if still running after DURATION.\n\ fputs (_("\ --preserve-status\n\ exit with the same status as COMMAND, even when the\n\ - command times out\n\ + command times out\n\ --foreground\n\ - When not running timeout directly from a shell prompt,\n\ - allow COMMAND to read from the TTY and receive TTY signals.\n\ - In this mode, children of COMMAND will not be timed out.\n\ + when not running timeout directly from a shell prompt,\n\ + allow COMMAND to read from the TTY and get TTY signals;\n\ + in this mode, children of COMMAND will not be timed out\n\ -k, --kill-after=DURATION\n\ also send a KILL signal if COMMAND is still running\n\ - this long after the initial signal was sent.\n\ + this long after the initial signal was sent\n\ -s, --signal=SIGNAL\n\ - specify the signal to be sent on timeout.\n\ - SIGNAL may be a name like 'HUP' or a number.\n\ - See 'kill -l' for a list of signals\n"), stdout); + specify the signal to be sent on timeout;\n\ + SIGNAL may be a name like 'HUP' or a number;\n\ + see 'kill -l' for a list of signals\n"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -437,7 +440,7 @@ main (int argc, char **argv) if (monitored_pid == -1) { error (0, errno, _("fork system call failed")); - return EXIT_CANCELED; + exit (EXIT_CANCELED); } else if (monitored_pid == 0) { /* child */ @@ -452,14 +455,14 @@ main (int argc, char **argv) /* exit like sh, env, nohup, ... */ exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE); error (0, errno, _("failed to run command %s"), quote (argv[0])); - return exit_status; + exit (exit_status); } else { pid_t wait_result; int status; - settimeout (timeout); + settimeout (timeout, true); while ((wait_result = waitpid (monitored_pid, &status, 0)) < 0 && errno == EINTR) @@ -497,8 +500,8 @@ main (int argc, char **argv) } if (timed_out && !preserve_status) - return EXIT_TIMEDOUT; + exit (EXIT_TIMEDOUT); else - return status; + exit (status); } } diff --git a/src/touch.c b/src/touch.c index 3a3ffbe0..1ba24269 100644 --- a/src/touch.c +++ b/src/touch.c @@ -1,5 +1,5 @@ /* touch -- change modification and access times of files - Copyright (C) 1987-2013 Free Software Foundation, Inc. + Copyright (C) 1987-2014 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 @@ -1,5 +1,5 @@ /* tr -- a filter to translate characters - Copyright (C) 1991-2013 Free Software Foundation, Inc. + Copyright (C) 1991-2014 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 @@ -1,5 +1,5 @@ /* Exit with a status code indicating success. - Copyright (C) 1999-2013 Free Software Foundation, Inc. + Copyright (C) 1999-2014 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 @@ -64,6 +64,8 @@ main (int argc, char **argv) bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); + /* Note true(1) will return EXIT_FAILURE in the + edge case where writes fail with GNU specific options. */ atexit (close_stdout); if (STREQ (argv[1], "--help")) diff --git a/src/truncate.c b/src/truncate.c index 8349cb61..f3125092 100644 --- a/src/truncate.c +++ b/src/truncate.c @@ -1,5 +1,5 @@ /* truncate -- truncate or extend the length of files. - Copyright (C) 2008-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2014 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 @@ -114,7 +114,7 @@ reads as zero bytes.\n\ "), stdout); fputs (_("\ -r, --reference=RFILE base size on RFILE\n\ - -s, --size=SIZE set or adjust the file size by SIZE\n"), stdout); + -s, --size=SIZE set or adjust the file size by SIZE bytes\n"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); emit_size_note (); @@ -420,5 +420,5 @@ main (int argc, char **argv) } } - return errors ? EXIT_FAILURE : EXIT_SUCCESS; + exit (errors ? EXIT_FAILURE : EXIT_SUCCESS); } diff --git a/src/tsort.c b/src/tsort.c index d22f1f05..661c7173 100644 --- a/src/tsort.c +++ b/src/tsort.c @@ -1,5 +1,5 @@ /* tsort - topological sort. - Copyright (C) 1998-2013 Free Software Foundation, Inc. + Copyright (C) 1998-2014 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 @@ -280,7 +280,7 @@ record_relation (struct item *j, struct item *k) } static bool -count_items (struct item *unused ATTRIBUTE_UNUSED) +count_items (struct item *unused _GL_UNUSED) { n_strings++; return false; @@ -347,8 +347,7 @@ detect_loop (struct item *k) { struct item *tmp = loop->qlink; - fprintf (stderr, "%s: %s\n", program_name, - loop->str); + error (0, 0, "%s", loop->str); /* Until we encounter K again. */ if (loop == k) @@ -1,5 +1,5 @@ /* tty -- print the name of the terminal connected to standard input - Copyright (C) 1990-2013 Free Software Foundation, Inc. + Copyright (C) 1990-2014 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 diff --git a/src/uname.c b/src/uname.c index cfcd0a33..e3bed488 100644 --- a/src/uname.c +++ b/src/uname.c @@ -1,6 +1,6 @@ /* uname -- print system information - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -321,9 +321,9 @@ main (int argc, char **argv) if (element == unknown) { cpu_type_t cputype; - size_t s = sizeof cputype; + size_t cs = sizeof cputype; NXArchInfo const *ai; - if (sysctlbyname ("hw.cputype", &cputype, &s, NULL, 0) == 0 + if (sysctlbyname ("hw.cputype", &cputype, &cs, NULL, 0) == 0 && (ai = NXGetArchInfoFromCpuType (cputype, CPU_SUBTYPE_MULTIPLE)) != NULL) diff --git a/src/unexpand.c b/src/unexpand.c index 1803cd57..505e223c 100644 --- a/src/unexpand.c +++ b/src/unexpand.c @@ -1,5 +1,5 @@ /* unexpand - convert blanks to tabs - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -1,5 +1,5 @@ /* uniq -- remove duplicate lines from a sorted file - Copyright (C) 1986-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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 @@ -108,11 +108,47 @@ static enum delimit_method const delimit_method_map[] = /* Select whether/how to delimit groups of duplicate lines. */ static enum delimit_method delimit_groups; +enum grouping_method +{ + /* No grouping, when "--group" isn't used */ + GM_NONE, + + /* Delimiter preceges all groups. --group=prepend */ + GM_PREPEND, + + /* Delimiter follows all groups. --group=append */ + GM_APPEND, + + /* Delimiter between groups. --group[=separate] */ + GM_SEPARATE, + + /* Delimiter before and after each group. --group=both */ + GM_BOTH +}; + +static char const *const grouping_method_string[] = +{ + "prepend", "append", "separate", "both", NULL +}; + +static enum grouping_method const grouping_method_map[] = +{ + GM_PREPEND, GM_APPEND, GM_SEPARATE, GM_BOTH +}; + +static enum grouping_method grouping = GM_NONE; + +enum +{ + GROUP_OPTION = CHAR_MAX + 1 +}; + static struct option const longopts[] = { {"count", no_argument, NULL, 'c'}, {"repeated", no_argument, NULL, 'd'}, {"all-repeated", optional_argument, NULL, 'D'}, + {"group", optional_argument, NULL, GROUP_OPTION}, {"ignore-case", no_argument, NULL, 'i'}, {"unique", no_argument, NULL, 'u'}, {"skip-fields", required_argument, NULL, 'f'}, @@ -146,17 +182,27 @@ With no options, matching lines are merged to the first occurrence.\n\ fputs (_("\ -c, --count prefix lines by the number of occurrences\n\ - -d, --repeated only print duplicate lines\n\ + -d, --repeated only print duplicate lines, one for each group\n\ +"), stdout); + fputs (_("\ + -D, --all-repeated[=METHOD] print all duplicate lines\n\ + groups can be delimited with an empty line\n\ + METHOD={none(default),prepend,separate}\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\ +"), stdout); + fputs (_("\ + --group[=METHOD] show all items, separating groups with an empty line\n\ + METHOD={separate(default),prepend,append,both}\n\ +"), stdout); + fputs (_("\ -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 (_("\ + -z, --zero-terminated line delimiter is NUL, not newline\n\ "), stdout); fputs (_("\ -w, --check-chars=N compare no more than N characters in lines\n\ @@ -293,27 +339,48 @@ check_file (const char *infile, const char *outfile, char delimiter) 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. */ + optimization to distinguish between when we can print input + lines immediately (1. & 2.) or not. + + 1. --group => all input lines are printed. + checking for unique/duplicated lines is used only for printing + group separators. + 2. The default case in which none of these options has been specified: + --count, --repeated, --all-repeated, --unique + In the default case, this optimization lets uniq output each different + line right away, without waiting to see if the next one is different. + + 3. All other cases. + */ if (output_unique && output_first_repeated && countmode == count_none) { char *prevfield IF_LINT ( = NULL); size_t prevlen IF_LINT ( = 0); + bool first_group_printed = false; while (!feof (stdin)) { char *thisfield; size_t thislen; + bool new_group; + 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)) + + new_group = (prevline->length == 0 + || different (thisfield, prevfield, thislen, prevlen)); + + if (new_group && grouping != GM_NONE + && (grouping == GM_PREPEND || grouping == GM_BOTH + || (first_group_printed && (grouping == GM_APPEND + || grouping == GM_SEPARATE)))) + putchar (delimiter); + + if (new_group || grouping != GM_NONE) { fwrite (thisline->buffer, sizeof (char), thisline->length, stdout); @@ -321,8 +388,11 @@ check_file (const char *infile, const char *outfile, char delimiter) SWAP_LINES (prevline, thisline); prevfield = thisfield; prevlen = thislen; + first_group_printed = true; } } + if ((grouping == GM_BOTH || grouping == GM_APPEND) && first_group_printed) + putchar (delimiter); } else { @@ -415,6 +485,7 @@ main (int argc, char **argv) int nfiles = 0; char const *file[2]; char delimiter = '\n'; /* change with --zero-terminated, -z */ + bool output_option_used = false; /* if true, one of -u/-d/-D/-c was used */ file[0] = file[1] = "-"; initialize_main (&argc, &argv); @@ -498,10 +569,12 @@ main (int argc, char **argv) case 'c': countmode = count_occurrences; + output_option_used = true; break; case 'd': output_unique = false; + output_option_used = true; break; case 'D': @@ -513,6 +586,16 @@ main (int argc, char **argv) delimit_groups = XARGMATCH ("--all-repeated", optarg, delimit_method_string, delimit_method_map); + output_option_used = true; + break; + + case GROUP_OPTION: + if (optarg == NULL) + grouping = GM_SEPARATE; + else + grouping = XARGMATCH ("--group", optarg, + grouping_method_string, + grouping_method_map); break; case 'f': @@ -532,6 +615,7 @@ main (int argc, char **argv) case 'u': output_first_repeated = false; + output_option_used = true; break; case 'w': @@ -552,6 +636,23 @@ main (int argc, char **argv) } } + /* Note we could allow --group with -D at least, and that would + avoid the need to specify a grouping method to --all-repeated. + It was thought best to avoid deprecating those parameters though + and keep --group separate to other options. */ + if (grouping != GM_NONE && output_option_used) + { + error (0, 0, _("--group is mutually exclusive with -c/-d/-D/-u")); + usage (EXIT_FAILURE); + } + + if (grouping != GM_NONE && countmode != count_none) + { + error (0, 0, + _("grouping and printing repeat counts is meaningless")); + usage (EXIT_FAILURE); + } + if (countmode == count_occurrences && output_later_repeated) { error (0, 0, diff --git a/src/unlink.c b/src/unlink.c index e822fd69..260a5301 100644 --- a/src/unlink.c +++ b/src/unlink.c @@ -1,5 +1,5 @@ /* unlink utility for GNU. - Copyright (C) 2001-2013 Free Software Foundation, Inc. + Copyright (C) 2001-2014 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 diff --git a/src/uptime.c b/src/uptime.c index 8e8f2ca6..4ab914f3 100644 --- a/src/uptime.c +++ b/src/uptime.c @@ -1,5 +1,5 @@ /* GNU's uptime. - Copyright (C) 1992-2013 Free Software Foundation, Inc. + Copyright (C) 1992-2014 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 @@ -176,7 +176,7 @@ static void uptime (const char *filename, int options) { size_t n_users; - STRUCT_UTMP *utmp_buf; + STRUCT_UTMP *utmp_buf = NULL; #if HAVE_UTMPX_H || HAVE_UTMP_H if (read_utmp (filename, &n_users, &utmp_buf, options) != 0) @@ -184,6 +184,8 @@ uptime (const char *filename, int options) #endif print_uptime (n_users, utmp_buf); + + IF_LINT (free (utmp_buf)); } void diff --git a/src/users.c b/src/users.c index d1c8137f..ee44c815 100644 --- a/src/users.c +++ b/src/users.c @@ -1,5 +1,5 @@ /* GNU's users. - Copyright (C) 1992-2013 Free Software Foundation, Inc. + Copyright (C) 1992-2014 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 @@ -1,5 +1,5 @@ /* wc - print the number of lines, words, and bytes in files - Copyright (C) 1985-2013 Free Software Foundation, Inc. + Copyright (C) 1985-2014 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 @@ -1,5 +1,5 @@ /* GNU's who. - Copyright (C) 1992-2013 Free Software Foundation, Inc. + Copyright (C) 1992-2014 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 diff --git a/src/whoami.c b/src/whoami.c index dfa28da3..7301abb1 100644 --- a/src/whoami.c +++ b/src/whoami.c @@ -1,6 +1,6 @@ /* whoami -- print effective userid - Copyright (C) 1989-2013 Free Software Foundation, Inc. + Copyright (C) 1989-2014 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 @@ -1,5 +1,5 @@ /* yes - output a string repeatedly until killed - Copyright (C) 1991-2013 Free Software Foundation, Inc. + Copyright (C) 1991-2014 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 |