From 1929784f0c0077479e30db09e745df7b9e9862c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Fri, 18 Mar 2005 10:43:58 +0000 Subject: [PATCH] Removed unused files git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11902 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/bin/Jamfile | 2 - src/apps/bin/gnu/basename.c | 84 - src/apps/bin/gnu/chgrp.c | 233 --- src/apps/bin/gnu/chmod.c | 396 ---- src/apps/bin/gnu/chown-core.c | 366 ---- src/apps/bin/gnu/chown-core.h | 89 - src/apps/bin/gnu/chown.c | 247 --- src/apps/bin/gnu/copy.c | 1219 ------------ src/apps/bin/gnu/copy.h | 161 -- src/apps/bin/gnu/cp-hash.c | 235 --- src/apps/bin/gnu/cp-hash.h | 8 - src/apps/bin/gnu/cp.c | 911 --------- src/apps/bin/gnu/dd.c | 1202 ------------ src/apps/bin/gnu/df.c | 952 ---------- src/apps/bin/gnu/du.c | 794 -------- src/apps/bin/gnu/install.c | 643 ------- src/apps/bin/gnu/ln.c | 563 ------ src/apps/bin/gnu/ls-dir.c | 2 - src/apps/bin/gnu/ls-ls.c | 2 - src/apps/bin/gnu/ls-vdir.c | 2 - src/apps/bin/gnu/ls.c | 3338 --------------------------------- src/apps/bin/gnu/ls.h | 10 - src/apps/bin/gnu/mkdir.c | 205 -- src/apps/bin/gnu/mkfifo.c | 147 -- src/apps/bin/gnu/mknod.c | 238 --- src/apps/bin/gnu/mv.c | 495 ----- src/apps/bin/gnu/remove.c | 946 ---------- src/apps/bin/gnu/remove.h | 51 - src/apps/bin/gnu/rm.c | 205 -- src/apps/bin/gnu/rmdir.c | 239 --- src/apps/bin/gnu/sync.c | 74 - src/apps/bin/gnu/sys2.h | 606 ------ src/apps/bin/gnu/system.h | 278 --- src/apps/bin/gnu/touch.c | 366 ---- src/apps/bin/pwd/Jamfile | 3 - src/apps/bin/pwd/pwd.c | 146 -- 36 files changed, 15458 deletions(-) delete mode 100644 src/apps/bin/gnu/basename.c delete mode 100644 src/apps/bin/gnu/chgrp.c delete mode 100644 src/apps/bin/gnu/chmod.c delete mode 100644 src/apps/bin/gnu/chown-core.c delete mode 100644 src/apps/bin/gnu/chown-core.h delete mode 100644 src/apps/bin/gnu/chown.c delete mode 100644 src/apps/bin/gnu/copy.c delete mode 100644 src/apps/bin/gnu/copy.h delete mode 100644 src/apps/bin/gnu/cp-hash.c delete mode 100644 src/apps/bin/gnu/cp-hash.h delete mode 100644 src/apps/bin/gnu/cp.c delete mode 100644 src/apps/bin/gnu/dd.c delete mode 100644 src/apps/bin/gnu/df.c delete mode 100644 src/apps/bin/gnu/du.c delete mode 100644 src/apps/bin/gnu/install.c delete mode 100644 src/apps/bin/gnu/ln.c delete mode 100644 src/apps/bin/gnu/ls-dir.c delete mode 100644 src/apps/bin/gnu/ls-ls.c delete mode 100644 src/apps/bin/gnu/ls-vdir.c delete mode 100644 src/apps/bin/gnu/ls.c delete mode 100644 src/apps/bin/gnu/ls.h delete mode 100644 src/apps/bin/gnu/mkdir.c delete mode 100644 src/apps/bin/gnu/mkfifo.c delete mode 100644 src/apps/bin/gnu/mknod.c delete mode 100644 src/apps/bin/gnu/mv.c delete mode 100644 src/apps/bin/gnu/remove.c delete mode 100644 src/apps/bin/gnu/remove.h delete mode 100644 src/apps/bin/gnu/rm.c delete mode 100644 src/apps/bin/gnu/rmdir.c delete mode 100644 src/apps/bin/gnu/sync.c delete mode 100644 src/apps/bin/gnu/sys2.h delete mode 100644 src/apps/bin/gnu/system.h delete mode 100644 src/apps/bin/gnu/touch.c delete mode 100644 src/apps/bin/pwd/Jamfile delete mode 100644 src/apps/bin/pwd/pwd.c diff --git a/src/apps/bin/Jamfile b/src/apps/bin/Jamfile index 3ad71b03b5..a7d1655e4c 100644 --- a/src/apps/bin/Jamfile +++ b/src/apps/bin/Jamfile @@ -108,7 +108,6 @@ SubInclude OBOS_TOP src apps bin diffutils ; SubInclude OBOS_TOP src apps bin findutils ; SubInclude OBOS_TOP src apps bin flex ; SubInclude OBOS_TOP src apps bin gawk ; -#SubInclude OBOS_TOP src apps bin gnu ; SubInclude OBOS_TOP src apps bin grep ; SubInclude OBOS_TOP src apps bin keymap ; SubInclude OBOS_TOP src apps bin less ; @@ -118,7 +117,6 @@ SubInclude OBOS_TOP src apps bin makeudfimage ; SubInclude OBOS_TOP src apps bin mkdos ; SubInclude OBOS_TOP src apps bin patch ; SubInclude OBOS_TOP src apps bin pc ; -#SubInclude OBOS_TOP src apps bin sed ; SubInclude OBOS_TOP src apps bin sed ; SubInclude OBOS_TOP src apps bin sharutils ; SubInclude OBOS_TOP src apps bin strace ; diff --git a/src/apps/bin/gnu/basename.c b/src/apps/bin/gnu/basename.c deleted file mode 100644 index fa5c7d6a21..0000000000 --- a/src/apps/bin/gnu/basename.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - -basename(C) -- remove directory names from pathnames - -OBOS Release 1.0 -- 1st January 2003 - -Additional Code by Sikosis (sikosis@gravity24hr.com) - -*/ - -#include "stdio.h" - -#define USAGE "basename(C) -- remove directory names from pathnames - -Syntax - -basename string [ suffix ] - -Description -The basename command deletes any prefix ending in ``/'' and the suffix (if present in string) from string, and prints the result on the standard output. The result is the ``base'' name of the file, that is, the filename without any preceding directory path and without an extension. It is used inside substitution marks (` `) in shell procedures to construct new filenames. - -Note that the suffix is not deleted if it is identical to the resulting basename. - -The related command dirname deletes the last level from string and prints the resulting path on the standard output. -Exit values -basename returns the following values: - -0 - successful completion - ->0 - an error occurred - -Examples -The following command displays the filename memos on the standard output: - -basename /usr/johnh/memos.old .old - -The following shell procedure, when invoked with the argument /usr/src/cmd/cat.c, compiles the named file and moves the output to a file named cat in the current directory: - - cc $1 - mv a.out `basename $1 .c` - -See also -dirname(C), sh(C)" - - -main(argc, argv) -char **argv; -{ - register char *p1, *p2, *p3; - - p1 = argv[1]; - - if (!strcmp(p1,"--help")) - { - putchar('\n'); - puts(USAGE); - putchar('\n'); - exit(1); - } - - if (argc < 2) { - putchar('\n'); - exit(1); - } - - p2 = p1; - while (*p1) { - if (*p1++ == '/') - p2 = p1; - } - if (argc>2) { - for(p3=argv[2]; *p3; p3++) - ; - while(p1>p2 && p3>argv[2]) - if(*--p3 != *--p1) - goto output; - *p1 = '\0'; - } -output: - puts(p2); // original code was this:- puts(p2, stdout); - exit(0); -} \ No newline at end of file diff --git a/src/apps/bin/gnu/chgrp.c b/src/apps/bin/gnu/chgrp.c deleted file mode 100644 index 60a18a63d0..0000000000 --- a/src/apps/bin/gnu/chgrp.c +++ /dev/null @@ -1,233 +0,0 @@ -/* chgrp -- change group ownership of files - Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by David MacKenzie . */ - -#include -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "lchown.h" -#include "group-member.h" -#include "quote.h" -#include "savedir.h" -#include "xstrtol.h" -#include "chown-core.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "chgrp" - -#define AUTHORS "David MacKenzie" - -/* MAXUID may come from limits.h *or* sys/params.h (via system.h) above. */ -#ifndef MAXUID -# define MAXUID UID_T_MAX -#endif -#ifndef MAXGID -# define MAXGID GID_T_MAX -#endif - -#ifndef _POSIX_VERSION -struct group *getgrnam (); -#endif - -#if ! HAVE_ENDGRENT -# define endgrent() ((void) 0) -#endif - -/* The name the program was run with. */ -char *program_name; - -/* The argument to the --reference option. Use the group ID of this file. - This file must exist. */ -static char *reference_file; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - REFERENCE_FILE_OPTION = CHAR_MAX + 1, - DEREFERENCE_OPTION -}; - -static struct option const long_options[] = -{ - {"recursive", no_argument, 0, 'R'}, - {"changes", no_argument, 0, 'c'}, - {"dereference", no_argument, 0, DEREFERENCE_OPTION}, - {"no-dereference", no_argument, 0, 'h'}, - {"quiet", no_argument, 0, 'f'}, - {"silent", no_argument, 0, 'f'}, - {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, - {"verbose", no_argument, 0, 'v'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {0, 0, 0, 0} -}; - -/* Set *G according to NAME. */ - -static void -parse_group (const char *name, gid_t *g) -{ - struct group *grp; - - if (*name == '\0') - error (1, 0, _("cannot change to null group")); - - grp = getgrnam (name); - if (grp == NULL) - { - strtol_error s_err; - unsigned long int tmp_long; - - if (!ISDIGIT (*name)) - error (1, 0, _("invalid group name %s"), quote (name)); - - s_err = xstrtoul (name, NULL, 0, &tmp_long, NULL); - if (s_err != LONGINT_OK) - STRTOL_FATAL_ERROR (name, _("group number"), s_err); - - if (tmp_long > MAXGID) - error (1, 0, _("invalid group number %s"), quote (name)); - - *g = tmp_long; - } - else - *g = grp->gr_gid; - endgrent (); /* Save a file descriptor. */ -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("\ -Usage: %s [OPTION]... GROUP FILE...\n\ - or: %s [OPTION]... --reference=RFILE FILE...\n\ -"), - program_name, program_name); - printf (_("\ -Change the group membership of each FILE to GROUP.\n\ -\n\ - -c, --changes like verbose but report only when a change is made\n\ - --dereference affect the referent of each symbolic link, rather\n\ - than the symbolic link itself\n\ - -h, --no-dereference affect symbolic links instead of any referenced file\n\ - (available only on systems that can change the\n\ - ownership of a symlink)\n\ - -f, --silent, --quiet suppress most error messages\n\ - --reference=RFILE use RFILE's group rather than the specified\n\ - GROUP value\n\ - -R, --recursive operate on files and directories recursively\n\ - -v, --verbose output a diagnostic for every file processed\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - gid_t gid; - int errors = 0; - int optc; - struct Chown_option chopt; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - chopt_init (&chopt); - - while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1) - { - switch (optc) - { - case 0: - break; - case REFERENCE_FILE_OPTION: - reference_file = optarg; - break; - case DEREFERENCE_OPTION: - chopt.dereference = DEREF_ALWAYS; - break; - case 'R': - chopt.recurse = 1; - break; - case 'c': - chopt.verbosity = V_changes_only; - break; - case 'f': - chopt.force_silent = 1; - break; - case 'h': - chopt.dereference = DEREF_NEVER; - break; - case 'v': - chopt.verbosity = V_high; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - if (argc - optind + (reference_file ? 1 : 0) <= 1) - { - error (0, 0, _("too few arguments")); - usage (1); - } - - if (reference_file) - { - struct stat ref_stats; - if (stat (reference_file, &ref_stats)) - error (1, errno, _("getting attributes of %s"), quote (reference_file)); - - chopt.group_name = gid_to_name (ref_stats.st_gid); - gid = ref_stats.st_gid; - } - else - { - chopt.group_name = argv[optind++]; - parse_group (chopt.group_name, &gid); - } - - for (; optind < argc; ++optind) - errors |= change_file_owner (1, argv[optind], (uid_t) -1, gid, - (uid_t) -1, (gid_t) -1, &chopt); - - chopt_free (&chopt); - - exit (errors); -} diff --git a/src/apps/bin/gnu/chmod.c b/src/apps/bin/gnu/chmod.c deleted file mode 100644 index dd3c42dcdf..0000000000 --- a/src/apps/bin/gnu/chmod.c +++ /dev/null @@ -1,396 +0,0 @@ -/* chmod -- change permission modes of files - Copyright (C) 89, 90, 91, 1995-2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by David MacKenzie */ - -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "filemode.h" -#include "modechange.h" -#include "quote.h" -#include "savedir.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "chmod" - -#define AUTHORS "David MacKenzie" - -enum Change_status -{ - CH_SUCCEEDED, - CH_FAILED, - CH_NO_CHANGE_REQUESTED -}; - -enum Verbosity -{ - /* Print a message for each file that is processed. */ - V_high, - - /* Print a message for each file whose attributes we change. */ - V_changes_only, - - /* Do not be verbose. This is the default. */ - V_off -}; - -void strip_trailing_slashes (); - -static int change_dir_mode PARAMS ((const char *dir, - const struct mode_change *changes, - const struct stat *statp)); - -/* The name the program was run with. */ -char *program_name; - -/* If nonzero, change the modes of directories recursively. */ -static int recurse; - -/* If nonzero, force silence (no error messages). */ -static int force_silent; - -/* Level of verbosity. */ -static enum Verbosity verbosity = V_off; - -/* The argument to the --reference option. Use the owner and group IDs - of this file. This file must exist. */ -static char *reference_file; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - REFERENCE_FILE_OPTION = CHAR_MAX + 1 -}; - -static struct option const long_options[] = -{ - {"recursive", no_argument, 0, 'R'}, - {"changes", no_argument, 0, 'c'}, - {"silent", no_argument, 0, 'f'}, - {"quiet", no_argument, 0, 'f'}, - {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, - {"verbose", no_argument, 0, 'v'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {0, 0, 0, 0} -}; - -static int -mode_changed (const char *file, mode_t old_mode) -{ - struct stat new_stats; - - if (lstat (file, &new_stats)) - { - if (force_silent == 0) - error (0, errno, _("getting new attributes of %s"), quote (file)); - return 0; - } - -#ifdef S_ISLNK - if (S_ISLNK (new_stats.st_mode) - && stat (file, &new_stats)) - { - if (force_silent == 0) - error (0, errno, _("getting new attributes of %s"), quote (file)); - return 0; - } -#endif - - return old_mode != new_stats.st_mode; -} - -/* Tell the user how/if the MODE of FILE has been changed. - CHANGED describes what (if anything) has happened. */ - -static void -describe_change (const char *file, mode_t mode, - enum Change_status changed) -{ - char perms[11]; /* "-rwxrwxrwx" ls-style modes. */ - const char *fmt; - - mode_string (mode, perms); - perms[10] = '\0'; /* `mode_string' does not null terminate. */ - switch (changed) - { - case CH_SUCCEEDED: - fmt = _("mode of %s changed to %04lo (%s)\n"); - break; - case CH_FAILED: - fmt = _("failed to change mode of %s to %04lo (%s)\n"); - break; - case CH_NO_CHANGE_REQUESTED: - fmt = _("mode of %s retained as %04lo (%s)\n"); - break; - default: - abort (); - } - printf (fmt, quote (file), - (unsigned long) (mode & CHMOD_MODE_BITS), &perms[1]); -} - -/* Change the mode of FILE according to the list of operations CHANGES. - If DEREF_SYMLINK is nonzero and FILE is a symbolic link, change the - mode of the referenced file. If DEREF_SYMLINK is zero, ignore symbolic - links. Return 0 if successful, 1 if errors occurred. */ - -static int -change_file_mode (const char *file, const struct mode_change *changes, - const int deref_symlink) -{ - struct stat file_stats; - mode_t newmode; - int errors = 0; - int fail; - int saved_errno; - - if (lstat (file, &file_stats)) - { - if (force_silent == 0) - error (0, errno, _("getting attributes of %s"), quote (file)); - return 1; - } -#ifdef S_ISLNK - if (S_ISLNK (file_stats.st_mode)) - { - if (! deref_symlink) - return 0; - else - if (stat (file, &file_stats)) - { - if (force_silent == 0) - error (0, errno, _("getting attributes of %s"), quote (file)); - return 1; - } - } -#endif - - newmode = mode_adjust (file_stats.st_mode, changes); - - fail = chmod (file, newmode); - saved_errno = errno; - - if (verbosity == V_high - || (verbosity == V_changes_only - && !fail && mode_changed (file, file_stats.st_mode))) - describe_change (file, newmode, (fail ? CH_FAILED : CH_SUCCEEDED)); - - if (fail) - { - if (force_silent == 0) - error (0, saved_errno, _("changing permissions of %s"), - quote (file)); - errors = 1; - } - - if (recurse && S_ISDIR (file_stats.st_mode)) - errors |= change_dir_mode (file, changes, &file_stats); - return errors; -} - -/* Recursively change the modes of the files in directory DIR - according to the list of operations CHANGES. - STATP points to the results of lstat on DIR. - Return 0 if successful, 1 if errors occurred. */ - -static int -change_dir_mode (const char *dir, const struct mode_change *changes, - const struct stat *statp) -{ - char *name_space, *namep; - char *path; /* Full path of each entry to process. */ - unsigned dirlength; /* Length of DIR and '\0'. */ - unsigned filelength; /* Length of each pathname to process. */ - unsigned pathlength; /* Bytes allocated for `path'. */ - int errors = 0; - - name_space = savedir (dir, statp->st_size); - if (name_space == NULL) - { - if (force_silent == 0) - error (0, errno, "%s", quote (dir)); - return 1; - } - - dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */ - pathlength = dirlength + 1; - /* Give `path' a dummy value; it will be reallocated before first use. */ - path = xmalloc (pathlength); - strcpy (path, dir); - path[dirlength - 1] = '/'; - - for (namep = name_space; *namep; namep += filelength - dirlength) - { - filelength = dirlength + strlen (namep) + 1; - if (filelength > pathlength) - { - pathlength = filelength * 2; - path = xrealloc (path, pathlength); - } - strcpy (path + dirlength, namep); - errors |= change_file_mode (path, changes, 0); - } - free (path); - free (name_space); - return errors; -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("\ -Usage: %s [OPTION]... MODE[,MODE]... FILE...\n\ - or: %s [OPTION]... OCTAL-MODE FILE...\n\ - or: %s [OPTION]... --reference=RFILE FILE...\n\ -"), - program_name, program_name, program_name); - printf (_("\ -Change the mode of each FILE to MODE.\n\ -\n\ - -c, --changes like verbose but report only when a change is made\n\ - -f, --silent, --quiet suppress most error messages\n\ - -v, --verbose output a diagnostic for every file processed\n\ - --reference=RFILE use RFILE's mode instead of MODE values\n\ - -R, --recursive change files and directories recursively\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -Each MODE is one or more of the letters ugoa, one of the symbols +-= and\n\ -one or more of the letters rwxXstugo.\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -/* Parse the ASCII mode given on the command line into a linked list - of `struct mode_change' and apply that to each file argument. */ - -int -main (int argc, char **argv) -{ - struct mode_change *changes; - int errors = 0; - int modeind = 0; /* Index of the mode argument in `argv'. */ - int thisind; - int c; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - recurse = force_silent = 0; - - while (1) - { - thisind = optind ? optind : 1; - - c = getopt_long (argc, argv, "RcfvrwxXstugoa,+-=", long_options, NULL); - if (c == -1) - break; - - switch (c) - { - case 0: - break; - case 'r': - case 'w': - case 'x': - case 'X': - case 's': - case 't': - case 'u': - case 'g': - case 'o': - case 'a': - case ',': - case '+': - case '-': - case '=': - if (modeind != 0 && modeind != thisind) - { - static char char_string[2] = {0, 0}; - char_string[0] = c; - error (1, 0, _("invalid character %s in mode string %s"), - quote_n (0, char_string), quote_n (1, argv[thisind])); - } - modeind = thisind; - break; - case REFERENCE_FILE_OPTION: - reference_file = optarg; - break; - case 'R': - recurse = 1; - break; - case 'c': - verbosity = V_changes_only; - break; - case 'f': - force_silent = 1; - break; - case 'v': - verbosity = V_high; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - if (modeind == 0 && reference_file == NULL) - modeind = optind++; - - if (optind >= argc) - { - error (0, 0, _("too few arguments")); - usage (1); - } - - changes = (reference_file ? mode_create_from_ref (reference_file) - : mode_compile (argv[modeind], MODE_MASK_ALL)); - - if (changes == MODE_INVALID) - error (1, 0, _("invalid mode string: %s"), quote (argv[modeind])); - else if (changes == MODE_MEMORY_EXHAUSTED) - xalloc_die (); - else if (changes == MODE_BAD_REFERENCE) - error (1, errno, _("getting attributes of %s"), quote (reference_file)); - - for (; optind < argc; ++optind) - { - strip_trailing_slashes (argv[optind]); - errors |= change_file_mode (argv[optind], changes, 1); - } - - exit (errors); -} diff --git a/src/apps/bin/gnu/chown-core.c b/src/apps/bin/gnu/chown-core.c deleted file mode 100644 index cb6a45858c..0000000000 --- a/src/apps/bin/gnu/chown-core.c +++ /dev/null @@ -1,366 +0,0 @@ -/* chown-core.c -- core functions for changing ownership. - Copyright (C) 2000 Free Software Foundation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Extracted from chown.c/chgrp.c and librarified by Jim Meyering. */ - -#include -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "lchown.h" -#include "quote.h" -#include "savedir.h" -#include "chown-core.h" -#include "xalloc.h" - -/* The number of decimal digits required to represent the largest value of - type `unsigned int'. This is enough for an 8-byte unsigned int type. */ -#define UINT_MAX_DECIMAL_DIGITS 20 - -#ifndef _POSIX_VERSION -struct group *getgrnam (); -struct group *getgrgid (); -#endif - -int lstat (); - -void -chopt_init (struct Chown_option *chopt) -{ - chopt->verbosity = V_off; - chopt->dereference = DEREF_NEVER; - chopt->recurse = 0; - chopt->force_silent = 0; - chopt->user_name = 0; - chopt->group_name = 0; -} - -void -chopt_free (struct Chown_option *chopt) -{ - /* Deliberately do not free chopt->user_name or ->group_name. - They're not always allocated. */ -} - -/* Convert N to a string, and return a pointer to that string in memory - allocated from the heap. */ - -static char * -uint_to_string (unsigned int n) -{ - char buf[UINT_MAX_DECIMAL_DIGITS + 1]; - char *p = buf + sizeof buf; - - *--p = '\0'; - - do - *--p = '0' + (n % 10); - while ((n /= 10) != 0); - - return xstrdup (p); -} - -/* Convert the numeric group-id, GID, to a string stored in xmalloc'd memory, - and return it. If there's no corresponding group name, use the decimal - representation of the ID. */ - -char * -gid_to_name (gid_t gid) -{ - struct group *grp = getgrgid (gid); - return grp ? xstrdup (grp->gr_name) : uint_to_string (gid); -} - -/* Convert the numeric user-id, UID, to a string stored in xmalloc'd memory, - and return it. If there's no corresponding user name, use the decimal - representation of the ID. */ - -char * -uid_to_name (uid_t uid) -{ - struct passwd *pwd = getpwuid (uid); - return pwd ? xstrdup (pwd->pw_name) : uint_to_string (uid); -} - -/* Tell the user how/if the user and group of FILE have been changed. - If USER is NULL, give the group-oriented messages. - CHANGED describes what (if anything) has happened. */ - -static void -describe_change (const char *file, enum Change_status changed, - char const *user, char const *group) -{ - const char *fmt; - char *spec; - int spec_allocated = 0; - - if (changed == CH_NOT_APPLIED) - { - printf (_("neither symbolic link %s nor referent has been changed\n"), - quote (file)); - return; - } - - if (user) - { - if (group) - { - spec = xmalloc (strlen (user) + 1 + strlen (group) + 1); - stpcpy (stpcpy (stpcpy (spec, user), ":"), group); - spec_allocated = 1; - } - else - { - spec = (char *) user; - } - } - else - { - spec = (char *) group; - } - - switch (changed) - { - case CH_SUCCEEDED: - fmt = (user - ? _("changed ownership of %s to %s\n") - : _("changed group of %s to %s\n")); - break; - case CH_FAILED: - fmt = (user - ? _("failed to change ownership of %s to %s\n") - : _("failed to change group of %s to %s\n")); - break; - case CH_NO_CHANGE_REQUESTED: - fmt = (user - ? _("ownership of %s retained as %s\n") - : _("group of %s retained as %s\n")); - break; - default: - abort (); - } - - printf (fmt, quote (file), spec); - - if (spec_allocated) - free (spec); -} - -/* Recursively change the ownership of the files in directory DIR to user-id, - UID, and group-id, GID, according to the options specified by CHOPT. - STATP points to the results of lstat on DIR. - Return 0 if successful, 1 if errors occurred. */ - -static int -change_dir_owner (const char *dir, uid_t uid, gid_t gid, - uid_t old_uid, gid_t old_gid, - const struct stat *statp, - struct Chown_option const *chopt) -{ - char *name_space, *namep; - char *path; /* Full path of each entry to process. */ - unsigned dirlength; /* Length of `dir' and '\0'. */ - unsigned filelength; /* Length of each pathname to process. */ - unsigned pathlength; /* Bytes allocated for `path'. */ - int errors = 0; - - name_space = savedir (dir, statp->st_size); - if (name_space == NULL) - { - if (chopt->force_silent == 0) - error (0, errno, "%s", quote (dir)); - return 1; - } - - dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */ - pathlength = dirlength + 1; - /* Give `path' a dummy value; it will be reallocated before first use. */ - path = xmalloc (pathlength); - strcpy (path, dir); - path[dirlength - 1] = '/'; - - for (namep = name_space; *namep; namep += filelength - dirlength) - { - filelength = dirlength + strlen (namep) + 1; - if (filelength > pathlength) - { - pathlength = filelength * 2; - path = xrealloc (path, pathlength); - } - strcpy (path + dirlength, namep); - errors |= change_file_owner (0, path, uid, gid, old_uid, old_gid, - chopt); - } - free (path); - free (name_space); - return errors; -} - -/* Change the ownership of FILE to user-id, UID, and group-id, GID, - provided it presently has owner OLD_UID and group OLD_GID. - Honor the options specified by CHOPT. - If FILE is a directory and -R is given, recurse. - Return 0 if successful, 1 if errors occurred. */ - -int -change_file_owner (int cmdline_arg, const char *file, uid_t uid, gid_t gid, - uid_t old_uid, gid_t old_gid, - struct Chown_option const *chopt) -{ - struct stat file_stats; - uid_t new_uid; - gid_t new_gid; - int errors = 0; - int is_symlink; - int is_directory; - - if (lstat (file, &file_stats)) - { - if (chopt->force_silent == 0) - error (0, errno, _("getting attributes of %s"), quote (file)); - return 1; - } - - /* If it's a symlink and we're dereferencing, then use stat - to get the attributes of the referent. */ - if (S_ISLNK (file_stats.st_mode)) - { - if (chopt->dereference == DEREF_ALWAYS - && stat (file, &file_stats)) - { - if (chopt->force_silent == 0) - error (0, errno, _("getting attributes of %s"), quote (file)); - return 1; - } - - is_symlink = 1; - - /* With -R, don't traverse through symlinks-to-directories. - But of course, this will all change with POSIX's new - -H, -L, -P options. */ - is_directory = 0; - } - else - { - is_symlink = 0; - is_directory = S_ISDIR (file_stats.st_mode); - } - - if ((old_uid == (uid_t) -1 || file_stats.st_uid == old_uid) - && (old_gid == (gid_t) -1 || file_stats.st_gid == old_gid)) - { - new_uid = (uid == (uid_t) -1 ? file_stats.st_uid : uid); - new_gid = (gid == (gid_t) -1 ? file_stats.st_gid : gid); - if (new_uid != file_stats.st_uid || new_gid != file_stats.st_gid) - { - int fail; - int symlink_changed = 1; - int saved_errno; - int called_lchown = 0; - - if (is_symlink) - { - if (chopt->dereference == DEREF_NEVER) - { - called_lchown = 1; - fail = lchown (file, new_uid, new_gid); - - /* Ignore the failure if it's due to lack of support (ENOSYS) - and this is not a command line argument. */ - if (!cmdline_arg && fail && errno == ENOSYS) - { - fail = 0; - symlink_changed = 0; - } - } - else if (chopt->dereference == DEREF_ALWAYS) - { - /* Applying chown to a symlink and expecting it to affect - the referent is not portable. So instead, open the - file and use fchown on the resulting descriptor. */ - int fd = open (file, O_RDONLY | O_NONBLOCK | O_NOCTTY); - fail = (fd == -1 ? 1 : fchown (fd, new_uid, new_gid)); - } - else - { - /* FIXME */ - abort (); - } - } - else - { - fail = chown (file, new_uid, new_gid); - } - saved_errno = errno; - - if (chopt->verbosity == V_high - || (chopt->verbosity == V_changes_only && !fail)) - { - enum Change_status ch_status = (! symlink_changed - ? CH_NOT_APPLIED - : (fail - ? CH_FAILED : CH_SUCCEEDED)); - describe_change (file, ch_status, - chopt->user_name, chopt->group_name); - } - - if (fail) - { - if (chopt->force_silent == 0) - error (0, saved_errno, (uid != (uid_t) -1 - ? _("changing ownership of %s") - : _("changing group of %s")), - quote (file)); - errors = 1; - } - else - { - /* The change succeeded. On some systems, the chown function - resets the `special' permission bits. When run by a - `privileged' user, this program must ensure that at least - the set-uid and set-group ones are still set. */ - if (file_stats.st_mode & ~(S_IFMT | S_IRWXUGO) - /* If we called lchown above (which means this is a symlink), - then skip it. */ - && ! called_lchown) - { - if (chmod (file, file_stats.st_mode)) - { - error (0, saved_errno, - _("unable to restore permissions of %s"), - quote (file)); - fail = 1; - } - } - } - } - else if (chopt->verbosity == V_high) - { - describe_change (file, CH_NO_CHANGE_REQUESTED, - chopt->user_name, chopt->group_name); - } - } - - if (chopt->recurse && is_directory) - errors |= change_dir_owner (file, uid, gid, - old_uid, old_gid, &file_stats, chopt); - return errors; -} diff --git a/src/apps/bin/gnu/chown-core.h b/src/apps/bin/gnu/chown-core.h deleted file mode 100644 index 1da12a79c4..0000000000 --- a/src/apps/bin/gnu/chown-core.h +++ /dev/null @@ -1,89 +0,0 @@ -/* chown-core.h -- types and prototypes shared by chown and chgrp. - Copyright (C) 2000 Free Software Foundation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef CHOWN_CORE_H -# define CHOWN_CORE_H - -enum Change_status -{ - CH_NOT_APPLIED = 1, - CH_SUCCEEDED, - CH_FAILED, - CH_NO_CHANGE_REQUESTED -}; - -enum Verbosity -{ - /* Print a message for each file that is processed. */ - V_high, - - /* Print a message for each file whose attributes we change. */ - V_changes_only, - - /* Do not be verbose. This is the default. */ - V_off -}; - -enum Dereference_symlink -{ - DEREF_UNDEFINED = 1, - DEREF_NEVER, /* -P */ - DEREF_COMMAND_LINE_ARGUMENTS, /* -H */ - DEREF_ALWAYS /* -L */ -}; - -struct Chown_option -{ - /* Level of verbosity. */ - enum Verbosity verbosity; - - /* If nonzero, change the ownership of directories recursively. */ - int recurse; - - /* This is useful only on systems with support for changing the - ownership of symbolic links. */ - enum Dereference_symlink dereference; - - /* If nonzero, force silence (no error messages). */ - int force_silent; - - /* The name of the user to which ownership of the files is being given. */ - char *user_name; - - /* The name of the group to which ownership of the files is being given. */ - char *group_name; -}; - -void -chopt_init (struct Chown_option *); - -void -chopt_free (struct Chown_option *); - -char * -gid_to_name (gid_t); - -char * -uid_to_name (uid_t); - -int -change_file_owner PARAMS ((int, const char *, - uid_t, gid_t, - uid_t, gid_t, - struct Chown_option const *)); - -#endif /* CHOWN_CORE_H */ diff --git a/src/apps/bin/gnu/chown.c b/src/apps/bin/gnu/chown.c deleted file mode 100644 index 3b9a656de5..0000000000 --- a/src/apps/bin/gnu/chown.c +++ /dev/null @@ -1,247 +0,0 @@ -/* chown -- change user and group ownership of files - Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* - | user - | unchanged explicit - -------------|-------------------------+-------------------------| - g unchanged | --- | chown u | - r |-------------------------+-------------------------| - o explicit | chgrp g or chown .g | chown u.g | - u |-------------------------+-------------------------| - p from passwd| --- | chown u. | - |-------------------------+-------------------------| - - Written by David MacKenzie . */ - -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "lchown.h" -#include "quote.h" -#include "savedir.h" -#include "chown-core.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "chown" - -#define AUTHORS "David MacKenzie" - -#ifndef _POSIX_VERSION -struct passwd *getpwnam (); -struct group *getgrnam (); -struct group *getgrgid (); -#endif - -#if ! HAVE_ENDPWENT -# define endpwent() ((void) 0) -#endif - -char *parse_user_spec (); -void strip_trailing_slashes (); - -/* The name the program was run with. */ -char *program_name; - -/* The argument to the --reference option. Use the owner and group IDs - of this file. This file must exist. */ -static char *reference_file; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - REFERENCE_FILE_OPTION = CHAR_MAX + 1, - DEREFERENCE_OPTION, - FROM_OPTION -}; - -static struct option const long_options[] = -{ - {"recursive", no_argument, 0, 'R'}, - {"changes", no_argument, 0, 'c'}, - {"dereference", no_argument, 0, DEREFERENCE_OPTION}, - {"from", required_argument, 0, FROM_OPTION}, - {"no-dereference", no_argument, 0, 'h'}, - {"quiet", no_argument, 0, 'f'}, - {"silent", no_argument, 0, 'f'}, - {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, - {"verbose", no_argument, 0, 'v'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {0, 0, 0, 0} -}; - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("\ -Usage: %s [OPTION]... OWNER[:[GROUP]] FILE...\n\ - or: %s [OPTION]... :GROUP FILE...\n\ - or: %s [OPTION]... --reference=RFILE FILE...\n\ -"), - program_name, program_name, program_name); - printf (_("\ -Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\ -\n\ - -c, --changes like verbose but report only when a change is made\n\ - --dereference affect the referent of each symbolic link, rather\n\ - than the symbolic link itself\n\ - -h, --no-dereference affect symbolic links instead of any referenced file\n\ - (available only on systems that can change the\n\ - ownership of a symlink)\n\ - --from=CURRENT_OWNER:CURRENT_GROUP\n\ - change the owner and/or group of each file only if\n\ - its current owner and/or group match those specified\n\ - here. Either may be omitted, in which case a match\n\ - is not required for the omitted attribute.\n\ - -f, --silent, --quiet suppress most error messages\n\ - --reference=RFILE use RFILE's owner and group rather than\n\ - the specified OWNER:GROUP values\n\ - -R, --recursive operate on files and directories recursively\n\ - -v, --verbose output a diagnostic for every file processed\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -")); - printf (_("\ -Owner is unchanged if missing. Group is unchanged if missing, but changed\n\ -to login group if implied by a `:'. OWNER and GROUP may be numeric as well\n\ -as symbolic.\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - uid_t uid = (uid_t) -1; /* New uid; -1 if not to be changed. */ - gid_t gid = (uid_t) -1; /* New gid; -1 if not to be changed. */ - uid_t old_uid = (uid_t) -1; /* Old uid; -1 if unrestricted. */ - gid_t old_gid = (uid_t) -1; /* Old gid; -1 if unrestricted. */ - struct Chown_option chopt; - - int errors = 0; - int optc; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - chopt_init (&chopt); - - while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1) - { - switch (optc) - { - case 0: - break; - case REFERENCE_FILE_OPTION: - reference_file = optarg; - break; - case DEREFERENCE_OPTION: - chopt.dereference = DEREF_ALWAYS; - break; - case FROM_OPTION: - { - char *u_dummy, *g_dummy; - const char *e = parse_user_spec (argv[optind], - &old_uid, &old_gid, - &u_dummy, &g_dummy); - if (e) - error (1, 0, "%s: %s", quote (argv[optind]), e); - break; - } - case 'R': - chopt.recurse = 1; - break; - case 'c': - chopt.verbosity = V_changes_only; - break; - case 'f': - chopt.force_silent = 1; - break; - case 'h': - chopt.dereference = DEREF_NEVER; - break; - case 'v': - chopt.verbosity = V_high; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - if (argc - optind + (reference_file ? 1 : 0) <= 1) - { - error (0, 0, _("too few arguments")); - usage (1); - } - - if (reference_file) - { - struct stat ref_stats; - - if (stat (reference_file, &ref_stats)) - error (1, errno, _("getting attributes of %s"), quote (reference_file)); - - uid = ref_stats.st_uid; - gid = ref_stats.st_gid; - chopt.user_name = uid_to_name (ref_stats.st_uid); - chopt.group_name = gid_to_name (ref_stats.st_gid); - } - else - { - const char *e = parse_user_spec (argv[optind], &uid, &gid, - &chopt.user_name, &chopt.group_name); - if (e) - error (1, 0, "%s: %s", quote (argv[optind]), e); - - /* FIXME: set it to the empty string? */ - if (chopt.user_name == NULL) - chopt.user_name = ""; - - optind++; - } - - for (; optind < argc; ++optind) - { - strip_trailing_slashes (argv[optind]); - errors |= change_file_owner (1, argv[optind], uid, gid, - old_uid, old_gid, &chopt); - } - - chopt_free (&chopt); - - exit (errors); -} diff --git a/src/apps/bin/gnu/copy.c b/src/apps/bin/gnu/copy.c deleted file mode 100644 index 1f8c40a20b..0000000000 --- a/src/apps/bin/gnu/copy.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* copy.c -- core functions for copying files and directories - Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Extracted from cp.c and librarified by Jim Meyering. */ - -#ifdef _AIX - #pragma alloca -#endif - -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "backupfile.h" -#include "savedir.h" -#include "copy.h" -#include "cp-hash.h" -#include "dirname.h" -#include "path-concat.h" -#include "quote.h" -#include "same.h" - -#define DO_CHOWN(Chown, File, New_uid, New_gid) \ - (Chown (File, New_uid, New_gid) \ - /* If non-root uses -p, it's ok if we can't preserve ownership. \ - But root probably wants to know, e.g. if NFS disallows it, \ - or if the target system doesn't support file ownership. */ \ - && ((errno != EPERM && errno != EINVAL) || x->myeuid == 0)) - -#define SAME_OWNER(A, B) ((A).st_uid == (B).st_uid) -#define SAME_GROUP(A, B) ((A).st_gid == (B).st_gid) -#define SAME_OWNER_AND_GROUP(A, B) (SAME_OWNER (A, B) && SAME_GROUP (A, B)) - -struct dir_list -{ - struct dir_list *parent; - ino_t ino; - dev_t dev; -}; - -int full_write (); -int euidaccess (); -int yesno (); - -static int copy_internal PARAMS ((const char *src_path, const char *dst_path, - int new_dst, dev_t device, - struct dir_list *ancestors, - const struct cp_options *x, - int move_mode, - int *copy_into_self, - int *rename_succeeded)); - -/* Pointers to the file names: they're used in the diagnostic that is issued - when we detect the user is trying to copy a directory into itself. */ -static char const *top_level_src_path; -static char const *top_level_dst_path; - -/* The invocation name of this program. */ -extern char *program_name; - -/* Encapsulate selection of the file mode to be applied to - new non-directories. */ - -static mode_t -get_dest_mode (const struct cp_options *option, mode_t mode) -{ - /* In some applications (e.g., install), use precisely the - specified mode. */ - if (option->set_mode) - return option->mode; - - /* Honor the umask for `cp', but not for `mv' or `cp -p'. */ - if (!option->move_mode && !option->preserve_chmod_bits) - mode &= option->umask_kill; - - return mode; -} - -/* FIXME: describe */ -/* FIXME: rewrite this to use a hash table so we avoid the quadratic - performance hit that's probably noticeable only on trees deeper - than a few hundred levels. See use of active_dir_map in remove.c */ - -static int -is_ancestor (const struct stat *sb, const struct dir_list *ancestors) -{ - while (ancestors != 0) - { - if (ancestors->ino == sb->st_ino && ancestors->dev == sb->st_dev) - return 1; - ancestors = ancestors->parent; - } - return 0; -} - -/* Read the contents of the directory SRC_PATH_IN, and recursively - copy the contents to DST_PATH_IN. NEW_DST is nonzero if - DST_PATH_IN is a directory that was created previously in the - recursion. SRC_SB and ANCESTORS describe SRC_PATH_IN. - Set *COPY_INTO_SELF to nonzero if SRC_PATH_IN is a parent of - (or the same as) DST_PATH_IN; otherwise, set it to zero. - Return 0 if successful, -1 if an error occurs. */ - -static int -copy_dir (const char *src_path_in, const char *dst_path_in, int new_dst, - const struct stat *src_sb, struct dir_list *ancestors, - const struct cp_options *x, int *copy_into_self) -{ - char *name_space; - char *namep; - struct cp_options non_command_line_options = *x; - int ret = 0; - - name_space = savedir (src_path_in, src_sb->st_size); - if (name_space == NULL) - { - /* This diagnostic is a bit vague because savedir can fail in - several different ways. */ - error (0, errno, _("cannot access %s"), quote (src_path_in)); - return -1; - } - - /* For cp's -H option, dereference command line arguments, but do not - dereference symlinks that are found via recursive traversal. */ - if (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS) - non_command_line_options.xstat = lstat; - - namep = name_space; - while (*namep != '\0') - { - int local_copy_into_self; - char *src_path = path_concat (src_path_in, namep, NULL); - char *dst_path = path_concat (dst_path_in, namep, NULL); - - if (dst_path == NULL || src_path == NULL) - xalloc_die (); - - ret |= copy_internal (src_path, dst_path, new_dst, src_sb->st_dev, - ancestors, &non_command_line_options, 0, - &local_copy_into_self, NULL); - *copy_into_self |= local_copy_into_self; - - /* Free the memory for `src_path'. The memory for `dst_path' - cannot be deallocated, since it is used to create multiple - hard links. */ - - free (src_path); - - namep += strlen (namep) + 1; - } - free (name_space); - return -ret; -} - -/* Copy a regular file from SRC_PATH to DST_PATH. - If the source file contains holes, copies holes and blocks of zeros - in the source file as holes in the destination file. - (Holes are read as zeroes by the `read' system call.) - Use DST_MODE as the 3rd argument in the call to open. - X provides many option settings. - Return 0 if successful, -1 if an error occurred. - *NEW_DST is as in copy_internal. */ - -static int -copy_reg (const char *src_path, const char *dst_path, - const struct cp_options *x, mode_t dst_mode, int *new_dst) -{ - char *buf; - int buf_size; - int dest_desc; - int source_desc; - struct stat sb; - char *cp; - int *ip; - int return_val = 0; - off_t n_read_total = 0; - int last_write_made_hole = 0; - int make_holes = (x->sparse_mode == SPARSE_ALWAYS); - - source_desc = open (src_path, O_RDONLY); - if (source_desc < 0) - { - /* If SRC_PATH doesn't exist, then chances are good that the - user did something like this `cp --backup foo foo': and foo - existed to start with, but copy_internal renamed DST_PATH - with the backup suffix, thus also renaming SRC_PATH. */ - if (errno == ENOENT) - error (0, 0, _("%s and %s are the same file"), - quote_n (0, src_path), quote_n (1, dst_path)); - else - error (0, errno, _("cannot open %s for reading"), quote (src_path)); - - return -1; - } - - /* These semantics are required for cp. - The if-block will be taken in move_mode. */ - if (*new_dst) - { - dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode); - } - else - { - dest_desc = open (dst_path, O_WRONLY | O_TRUNC, dst_mode); - - if (dest_desc < 0 && x->unlink_dest_after_failed_open) - { - if (unlink (dst_path)) - { - error (0, errno, _("cannot remove %s"), quote (dst_path)); - return_val = -1; - goto close_src_desc; - } - - /* Tell caller that the destination file was unlinked. */ - *new_dst = 1; - - /* Try the open again, but this time with different flags. */ - dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode); - } - } - - if (dest_desc < 0) - { - error (0, errno, _("cannot create regular file %s"), quote (dst_path)); - return_val = -1; - goto close_src_desc; - } - - /* Find out the optimal buffer size. */ - - if (fstat (dest_desc, &sb)) - { - error (0, errno, _("cannot fstat %s"), quote (dst_path)); - return_val = -1; - goto close_src_and_dst_desc; - } - - buf_size = ST_BLKSIZE (sb); - -#if HAVE_STRUCT_STAT_ST_BLOCKS - if (x->sparse_mode == SPARSE_AUTO && S_ISREG (sb.st_mode)) - { - /* Use a heuristic to determine whether SRC_PATH contains any - sparse blocks. */ - - if (fstat (source_desc, &sb)) - { - error (0, errno, _("cannot fstat %s"), quote (src_path)); - return_val = -1; - goto close_src_and_dst_desc; - } - - /* If the file has fewer blocks than would normally - be needed for a file of its size, then - at least one of the blocks in the file is a hole. */ - if (S_ISREG (sb.st_mode) - && sb.st_size / ST_NBLOCKSIZE > ST_NBLOCKS (sb)) - make_holes = 1; - } -#endif - - /* Make a buffer with space for a sentinel at the end. */ - - buf = (char *) alloca (buf_size + sizeof (int)); - - for (;;) - { - int n_read = read (source_desc, buf, buf_size); - if (n_read < 0) - { -#ifdef EINTR - if (errno == EINTR) - continue; -#endif - error (0, errno, _("reading %s"), quote (src_path)); - return_val = -1; - goto close_src_and_dst_desc; - } - if (n_read == 0) - break; - - n_read_total += n_read; - - ip = 0; - if (make_holes) - { - buf[n_read] = 1; /* Sentinel to stop loop. */ - - /* Find first nonzero *word*, or the word with the sentinel. */ - - ip = (int *) buf; - while (*ip++ == 0) - ; - - /* Find the first nonzero *byte*, or the sentinel. */ - - cp = (char *) (ip - 1); - while (*cp++ == 0) - ; - - /* If we found the sentinel, the whole input block was zero, - and we can make a hole. */ - - if (cp > buf + n_read) - { - /* Make a hole. */ - if (lseek (dest_desc, (off_t) n_read, SEEK_CUR) < 0L) - { - error (0, errno, _("cannot lseek %s"), quote (dst_path)); - return_val = -1; - goto close_src_and_dst_desc; - } - last_write_made_hole = 1; - } - else - /* Clear to indicate that a normal write is needed. */ - ip = 0; - } - if (ip == 0) - { - if (full_write (dest_desc, buf, n_read) < 0) - { - error (0, errno, _("writing %s"), quote (dst_path)); - return_val = -1; - goto close_src_and_dst_desc; - } - last_write_made_hole = 0; - } - } - - /* If the file ends with a `hole', something needs to be written at - the end. Otherwise the kernel would truncate the file at the end - of the last write operation. */ - - if (last_write_made_hole) - { -#if HAVE_FTRUNCATE - /* Write a null character and truncate it again. */ - if (full_write (dest_desc, "", 1) < 0 - || ftruncate (dest_desc, n_read_total) < 0) -#else - /* Seek backwards one character and write a null. */ - if (lseek (dest_desc, (off_t) -1, SEEK_CUR) < 0L - || full_write (dest_desc, "", 1) < 0) -#endif - { - error (0, errno, _("writing %s"), quote (dst_path)); - return_val = -1; - } - } - -close_src_and_dst_desc: - if (close (dest_desc) < 0) - { - error (0, errno, _("closing %s"), quote (dst_path)); - return_val = -1; - } -close_src_desc: - if (close (source_desc) < 0) - { - error (0, errno, _("closing %s"), quote (src_path)); - return_val = -1; - } - - return return_val; -} - -/* Return nonzero if it's ok that the source and destination - files are the `same' by some measure. The goal is to avoid - making the `copy' operation remove both copies of the file - in that case, while still allowing the user to e.g., move or - copy a regular file onto a symlink that points to it. - Try to minimize the cost of this function in the common case. */ - -static int -same_file_ok (const char *src_path, const struct stat *src_sb, - const char *dst_path, const struct stat *dst_sb, - const struct cp_options *x, int *return_now) -{ - const struct stat *src_sb_link; - const struct stat *dst_sb_link; - struct stat tmp_dst_sb; - struct stat tmp_src_sb; - - int same_link; - int same = (SAME_INODE (*src_sb, *dst_sb)); - - *return_now = 0; - - /* FIXME: this should (at the very least) be moved into the following - if-block. More likely, it should be removed, because it inhibits - making backups. But removing it will result in a change in behavior - that will probably have to be documented -- and tests will have to - be updated. */ - if (same && x->hard_link) - { - *return_now = 1; - return 1; - } - - if (x->xstat == lstat) - { - same_link = same; - - /* If both the source and destination files are symlinks (and we'll - know this here IFF preserving symlinks (aka xstat == lstat), - then it's ok -- as long as they are distinct. */ - if (S_ISLNK (src_sb->st_mode) && S_ISLNK (dst_sb->st_mode)) - return ! same_name (src_path, dst_path); - - src_sb_link = src_sb; - dst_sb_link = dst_sb; - } - else - { - if (!same) - return 1; - - if (lstat (dst_path, &tmp_dst_sb) - || lstat (src_path, &tmp_src_sb)) - return 1; - - src_sb_link = &tmp_src_sb; - dst_sb_link = &tmp_dst_sb; - - same_link = SAME_INODE (*src_sb_link, *dst_sb_link); - - /* If both are symlinks, then it's ok, but only if the destination - will be unlinked before being opened. This is like the test - above, but with the addition of the unlink_dest_before_opening - conjunct because otherwise, with two symlinks to the same target, - we'd end up truncating the source file. */ - if (S_ISLNK (src_sb_link->st_mode) && S_ISLNK (dst_sb_link->st_mode) - && x->unlink_dest_before_opening) - return 1; - } - - /* The backup code ensures there's a copy, so it's ok to remove - any destination file. But there's one exception: when both - source and destination are the same directory entry. In that - case, moving the destination file aside (in making the backup) - would also rename the source file and result in an error. */ - if (x->backup_type != none) - { - if (!same_link) - return 1; - - return ! same_name (src_path, dst_path); - } - -#if 0 - /* FIXME: use or remove */ - - /* If we're making a backup, we'll detect the problem case in - copy_reg because SRC_PATH will no longer exist. Allowing - the test to be deferred lets cp do some useful things. - But when creating hardlinks and SRC_PATH is a symlink - but DST_PATH is not we must test anyway. */ - if (x->hard_link - || !S_ISLNK (src_sb_link->st_mode) - || S_ISLNK (dst_sb_link->st_mode)) - return 1; - - if (x->dereference != DEREF_NEVER) - return 1; -#endif - - /* They may refer to the same file if we're in move mode and the - target is a symlink. That is ok, since we remove any existing - destination file before opening it -- via `rename' if they're on - the same file system, via `unlink (DST_PATH)' otherwise. - It's also ok if they're distinct hard links to the same file. */ - if ((x->move_mode || x->unlink_dest_before_opening) - && (S_ISLNK (dst_sb_link->st_mode) - || (same_link && !same_name (src_path, dst_path)))) - return 1; - - /* If neither is a symlink, then it's ok as long as they aren't - hard links to the same file. */ - if (!S_ISLNK (src_sb_link->st_mode) && !S_ISLNK (dst_sb_link->st_mode)) - { - if (!SAME_INODE (*src_sb_link, *dst_sb_link)) - return 1; - - /* If they are the same file, it's ok if we're making hard links. */ - if (x->hard_link) - { - *return_now = 1; - return 1; - } - } - - /* It's ok to remove a destination symlink. But that works only when we - unlink before opening the destination and when the source and destination - files are on the same partition. */ - if (x->unlink_dest_before_opening - && S_ISLNK (dst_sb_link->st_mode)) - return dst_sb_link->st_dev == src_sb_link->st_dev; - - if (x->xstat == lstat) - { - if ( ! S_ISLNK (src_sb_link->st_mode)) - tmp_src_sb = *src_sb_link; - else if (stat (src_path, &tmp_src_sb)) - return 1; - - if ( ! S_ISLNK (dst_sb_link->st_mode)) - tmp_dst_sb = *dst_sb_link; - else if (stat (dst_path, &tmp_dst_sb)) - return 1; - - if ( ! SAME_INODE (tmp_src_sb, tmp_dst_sb)) - return 1; - - /* FIXME: shouldn't this be testing whether we're making symlinks? */ - if (x->hard_link) - { - *return_now = 1; - return 1; - } - } - - return 0; -} - -/* Copy the file SRC_PATH to the file DST_PATH. The files may be of - any type. NEW_DST should be nonzero if the file DST_PATH cannot - exist because its parent directory was just created; NEW_DST should - be zero if DST_PATH might already exist. DEVICE is the device - number of the parent directory, or 0 if the parent of this file is - not known. ANCESTORS points to a linked, null terminated list of - devices and inodes of parent directories of SRC_PATH. - Set *COPY_INTO_SELF to nonzero if SRC_PATH is a parent of (or the - same as) DST_PATH; otherwise, set it to zero. - Return 0 if successful, 1 if an error occurs. */ - -static int -copy_internal (const char *src_path, const char *dst_path, - int new_dst, - dev_t device, - struct dir_list *ancestors, - const struct cp_options *x, - int move_mode, - int *copy_into_self, - int *rename_succeeded) -{ - struct stat src_sb; - struct stat dst_sb; - mode_t src_mode; - mode_t src_type; - char *earlier_file; - char *dst_backup = NULL; - int backup_succeeded = 0; - int rename_errno; - int delayed_fail; - int copied_as_regular = 0; - int ran_chown = 0; - - if (move_mode && rename_succeeded) - *rename_succeeded = 0; - - *copy_into_self = 0; - if ((*(x->xstat)) (src_path, &src_sb)) - { - error (0, errno, _("cannot stat %s"), quote (src_path)); - return 1; - } - - /* We wouldn't insert a node unless nlink > 1, except that we need to - find created files so as to not copy infinitely if a directory is - copied into itself. */ - - /* Associate the destination path with the source device and inode - so that if we encounter a matching dev/ino pair in the source tree - we can arrange to create a hard link between the corresponding names - in the destination tree. */ - earlier_file = remember_copied (dst_path, src_sb.st_ino, src_sb.st_dev); - - src_mode = src_sb.st_mode; - src_type = src_sb.st_mode; - - if (S_ISDIR (src_type) && !x->recursive) - { - error (0, 0, _("omitting directory %s"), quote (src_path)); - return 1; - } - - if (!new_dst) - { - if ((*(x->xstat)) (dst_path, &dst_sb)) - { - if (errno != ENOENT) - { - error (0, errno, _("cannot stat %s"), quote (dst_path)); - return 1; - } - else - { - new_dst = 1; - } - } - else - { - int return_now; - int ok = same_file_ok (src_path, &src_sb, dst_path, &dst_sb, - x, &return_now); - if (return_now) - return 0; - - if (! ok) - { - error (0, 0, _("%s and %s are the same file"), - quote_n (0, src_path), quote_n (1, dst_path)); - return 1; - } - - if (S_ISDIR (src_type) && !S_ISDIR (dst_sb.st_mode)) - { - error (0, 0, - _("cannot overwrite non-directory %s with directory %s"), - quote_n (0, dst_path), quote_n (1, src_path)); - return 1; - } - - if (!S_ISDIR (src_type)) - { - if (S_ISDIR (dst_sb.st_mode)) - { - error (0, 0, - _("cannot overwrite directory %s with non-directory"), - quote (dst_path)); - return 1; - } - - if (x->update && MTIME_CMP (src_sb, dst_sb) <= 0) - return 0; - } - - if (!S_ISDIR (src_type) && x->interactive) - { - if (euidaccess (dst_path, W_OK) != 0) - { - fprintf (stderr, - _("%s: overwrite %s, overriding mode %04lo? "), - program_name, quote (dst_path), - (unsigned long) (dst_sb.st_mode & CHMOD_MODE_BITS)); - } - else - { - fprintf (stderr, _("%s: overwrite %s? "), - program_name, quote (dst_path)); - } - if (!yesno ()) - return (move_mode ? 1 : 0); - } - - if (move_mode) - { - /* In move_mode, DEST may not be an existing directory. */ - if (S_ISDIR (dst_sb.st_mode)) - { - error (0, 0, _("cannot overwrite directory %s"), - quote (dst_path)); - return 1; - } - - /* Don't allow user to move a directory onto a non-directory. */ - if (S_ISDIR (src_sb.st_mode) && !S_ISDIR (dst_sb.st_mode)) - { - error (0, 0, - _("cannot move directory onto non-directory: %s -> %s"), - quote_n (0, src_path), quote_n (0, dst_path)); - return 1; - } - } - - if (x->backup_type != none && !S_ISDIR (dst_sb.st_mode)) - { - char *tmp_backup = find_backup_file_name (dst_path, - x->backup_type); - if (tmp_backup == NULL) - xalloc_die (); - - /* Detect (and fail) when creating the backup file would - destroy the source file. Before, running the commands - cd /tmp; rm -f a a~; : > a; echo A > a~; cp -b -V simple a~ a - would leave two zero-length files: a and a~. */ - if (STREQ (tmp_backup, src_path)) - { - const char *fmt; - fmt = (move_mode - ? _("backing up %s would destroy source; %s not moved") - : _("backing up %s would destroy source; %s not copied")); - error (0, 0, fmt, - quote_n (0, dst_path), - quote_n (1, src_path)); - free (tmp_backup); - return 1; - } - - dst_backup = (char *) alloca (strlen (tmp_backup) + 1); - strcpy (dst_backup, tmp_backup); - free (tmp_backup); - if (rename (dst_path, dst_backup)) - { - if (errno != ENOENT) - { - error (0, errno, _("cannot backup %s"), quote (dst_path)); - return 1; - } - else - { - dst_backup = NULL; - } - } - else - { - backup_succeeded = 1; - } - new_dst = 1; - } - else if (! S_ISDIR (dst_sb.st_mode) - && (x->unlink_dest_before_opening - || (x->xstat == lstat - && ! S_ISREG (src_sb.st_mode)))) - { - if (unlink (dst_path) && errno != ENOENT) - { - error (0, errno, _("cannot remove %s"), quote (dst_path)); - return 1; - } - new_dst = 1; - } - } - } - - /* If the source is a directory, we don't always create the destination - directory. So --verbose should not announce anything until we're - sure we'll create a directory. */ - if (x->verbose && !S_ISDIR (src_type)) - { - printf ("%s -> %s", quote_n (0, src_path), quote_n (1, dst_path)); - if (backup_succeeded) - printf (_(" (backup: %s)"), quote (dst_backup)); - putchar ('\n'); - } - - /* Did we copy this inode somewhere else (in this command line argument) - and therefore this is a second hard link to the inode? */ - - if (x->dereference == DEREF_NEVER && src_sb.st_nlink > 1 && earlier_file) - { - /* Avoid damaging the destination filesystem by refusing to preserve - hard-linked directories (which are found at least in Netapp snapshot - directories). */ - if (S_ISDIR (src_type)) - { - /* If src_path and earlier_file refer to the same directory entry, - then warn about copying a directory into itself. */ - if (same_name (src_path, earlier_file)) - { - error (0, 0, _("cannot copy a directory, %s, into itself, %s"), - quote_n (0, top_level_src_path), - quote_n (1, top_level_dst_path)); - *copy_into_self = 1; - } - else - { - error (0, 0, _("will not create hard link %s to directory %s"), - quote_n (0, dst_path), quote_n (1, earlier_file)); - } - - goto un_backup; - } - - if (link (earlier_file, dst_path)) - { - error (0, errno, _("cannot create hard link %s to %s"), - quote_n (0, dst_path), quote_n (1, earlier_file)); - goto un_backup; - } - - return 0; - } - - if (move_mode) - { - if (rename (src_path, dst_path) == 0) - { - if (x->verbose && S_ISDIR (src_type)) - printf ("%s -> %s\n", quote_n (0, src_path), quote_n (1, dst_path)); - if (rename_succeeded) - *rename_succeeded = 1; - return 0; - } - - /* FIXME: someday, consider what to do when moving a directory into - itself but when source and destination are on different devices. */ - - /* This happens when attempting to rename a directory to a - subdirectory of itself. */ - if (errno == EINVAL - - /* When src_path is on an NFS file system, some types of - clients, e.g., SunOS4.1.4 and IRIX-5.3, set errno to EIO - instead. Testing for this here risks misinterpreting a real - I/O error as an attempt to move a directory into itself, so - FIXME: consider not doing this. */ - || errno == EIO - - /* And with SunOS-4.1.4 client and OpenBSD-2.3 server, - we get ENOTEMPTY. */ - || errno == ENOTEMPTY) - { - /* FIXME: this is a little fragile in that it relies on rename(2) - failing with a specific errno value. Expect problems on - non-POSIX systems. */ - error (0, 0, _("cannot move %s to a subdirectory of itself, %s"), - quote_n (0, top_level_src_path), - quote_n (1, top_level_dst_path)); - *copy_into_self = 1; - /* FIXME-cleanup: Don't return zero here; adjust mv.c accordingly. - The only caller that uses this code (mv.c) ends up setting its - exit status to nonzero when copy_into_self is nonzero. */ - return 0; - } - - /* Ignore other types of failure (e.g. EXDEV), since the following - code will try to perform a copy, then remove. */ - - /* Save this value of errno to use in case the unlink fails. */ - rename_errno = errno; - - /* 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_path) && errno != ENOENT) - { - /* Use the value of errno from the failed rename. */ - error (0, rename_errno, _("cannot move %s to %s"), - quote_n (0, src_path), quote_n (1, dst_path)); - return 1; - } - - new_dst = 1; - } - - delayed_fail = 0; - if (S_ISDIR (src_type)) - { - struct dir_list *dir; - - /* If this directory has been copied before during the - recursion, there is a symbolic link to an ancestor - directory of the symbolic link. It is impossible to - continue to copy this, unless we've got an infinite disk. */ - - if (is_ancestor (&src_sb, ancestors)) - { - error (0, 0, _("cannot copy cyclic symbolic link %s"), - quote (src_path)); - goto un_backup; - } - - /* Insert the current directory in the list of parents. */ - - dir = (struct dir_list *) alloca (sizeof (struct dir_list)); - dir->parent = ancestors; - dir->ino = src_sb.st_ino; - dir->dev = src_sb.st_dev; - - if (new_dst || !S_ISDIR (dst_sb.st_mode)) - { - /* Create the new directory writable and searchable, so - we can create new entries in it. */ - - if (mkdir (dst_path, (src_mode & x->umask_kill) | S_IRWXU)) - { - error (0, errno, _("cannot create directory %s"), - quote (dst_path)); - goto un_backup; - } - - /* Insert the created directory's inode and device - numbers into the search structure, so that we can - avoid copying it again. */ - - if (remember_created (dst_path)) - goto un_backup; - - if (x->verbose) - printf ("%s -> %s\n", quote_n (0, src_path), quote_n (1, dst_path)); - } - - /* Are we crossing a file system boundary? */ - if (x->one_file_system && device != 0 && device != src_sb.st_dev) - return 0; - - /* Copy the contents of the directory. */ - - if (copy_dir (src_path, dst_path, new_dst, &src_sb, dir, x, - copy_into_self)) - { - /* Don't just return here -- otherwise, the failure to read a - single file in a source directory would cause the containing - destination directory not to have owner/perms set properly. */ - delayed_fail = 1; - } - } -#ifdef S_ISLNK - else if (x->symbolic_link) - { - if (*src_path != '/') - { - /* Check that DST_PATH denotes a file in the current directory. */ - struct stat dot_sb; - struct stat dst_parent_sb; - char *dst_parent; - int in_current_dir; - - dst_parent = dir_name (dst_path); - if (dst_parent == NULL) - xalloc_die (); - - in_current_dir = (STREQ (".", dst_parent) - /* If either stat call fails, it's ok not to report - the failure and say dst_path is in the current - directory. Other things will fail later. */ - || stat (".", &dot_sb) - || stat (dst_parent, &dst_parent_sb) - || SAME_INODE (dot_sb, dst_parent_sb)); - free (dst_parent); - - if (! in_current_dir) - { - error (0, 0, - _("%s: can make relative symbolic links only in current directory"), - quote (dst_path)); - goto un_backup; - } - } - if (symlink (src_path, dst_path)) - { - error (0, errno, _("cannot create symbolic link %s to %s"), - quote_n (0, dst_path), quote_n (1, src_path)); - goto un_backup; - } - - return 0; - } -#endif - else if (x->hard_link) - { - if (link (src_path, dst_path)) - { - error (0, errno, _("cannot create link %s"), quote (dst_path)); - goto un_backup; - } - return 0; - } - else if (S_ISREG (src_type) - || (x->copy_as_regular && !S_ISDIR (src_type) -#ifdef S_ISLNK - && !S_ISLNK (src_type) -#endif - )) - { - copied_as_regular = 1; - /* POSIX says the permission bits of the source file must be - used as the 3rd argument in the open call, but that's not consistent - with historical practice. */ - if (copy_reg (src_path, dst_path, x, - get_dest_mode (x, src_mode), &new_dst)) - goto un_backup; - } - else -#ifdef S_ISFIFO - if (S_ISFIFO (src_type)) - { - if (mkfifo (dst_path, get_dest_mode (x, src_mode))) - { - error (0, errno, _("cannot create fifo %s"), quote (dst_path)); - goto un_backup; - } - } - else -#endif - if (S_ISBLK (src_type) || S_ISCHR (src_type) -#ifdef S_ISSOCK - || S_ISSOCK (src_type) -#endif - ) - { - if (mknod (dst_path, get_dest_mode (x, src_mode), src_sb.st_rdev)) - { - error (0, errno, _("cannot create special file %s"), - quote (dst_path)); - goto un_backup; - } - } - else -#ifdef S_ISLNK - if (S_ISLNK (src_type)) - { - char *link_val; - int link_size; - - link_val = (char *) alloca (PATH_MAX + 2); - link_size = readlink (src_path, link_val, PATH_MAX + 1); - if (link_size < 0) - { - error (0, errno, _("cannot read symbolic link %s"), quote (src_path)); - goto un_backup; - } - link_val[link_size] = '\0'; - - if (symlink (link_val, dst_path)) - { - int saved_errno = errno; - int same_link = 0; - if (x->update && !new_dst && S_ISLNK (dst_sb.st_mode)) - { - /* See if the destination is already the desired symlink. */ - char *dest_link_name = (char *) alloca (PATH_MAX + 2); - int dest_link_len = readlink (dst_path, dest_link_name, - PATH_MAX + 1); - if (dest_link_len > 0) - { - dest_link_name[dest_link_len] = '\0'; - if (STREQ (dest_link_name, link_val)) - same_link = 1; - } - } - - if (! same_link) - { - error (0, saved_errno, _("cannot create symbolic link %s"), - quote (dst_path)); - goto un_backup; - } - } - - if (x->preserve_owner_and_group) - { - /* Preserve the owner and group of the just-`copied' - symbolic link, if possible. */ -# if HAVE_LCHOWN - if (DO_CHOWN (lchown, dst_path, src_sb.st_uid, src_sb.st_gid)) - { - error (0, errno, _("preserving ownership for %s"), dst_path); - goto un_backup; - } -# else - /* Can't preserve ownership of symlinks. - FIXME: maybe give a warning or even error for symlinks - in directories with the sticky bit set -- there, not - preserving owner/group is a potential security problem. */ -# endif - } - - return 0; - } - else -#endif - { - error (0, 0, _("%s has unknown file type"), quote (src_path)); - goto un_backup; - } - - /* POSIX says that `cp -p' must restore the following: - - permission bits - - setuid, setgid bits - - owner and group - If it fails to restore any of those, we may give a warning but - the destination must not be removed. - FIXME: implement the above. */ - - /* Adjust the times (and if possible, ownership) for the copy. - chown turns off set[ug]id bits for non-root, - so do the chmod last. */ - - if (x->preserve_timestamps) - { - struct utimbuf utb; - - /* There's currently no interface to set file timestamps with - better than 1-second resolution, so discard any fractional - part of the source timestamp. */ - - utb.actime = src_sb.st_atime; - utb.modtime = src_sb.st_mtime; - - if (utime (dst_path, &utb)) - { - error (0, errno, _("preserving times for %s"), quote (dst_path)); - if (x->require_preserve) - return 1; - } - } - - /* Avoid calling chown if we know it's not necessary. */ - if (x->preserve_owner_and_group - && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) - { - ran_chown = 1; - if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid)) - { - error (0, errno, _("preserving ownership for %s"), quote (dst_path)); - if (x->require_preserve) - return 1; - } - } - - /* Permissions of newly-created regular files were set upon `open' in - copy_reg. But don't return early if there were any special bits and - we had to run chown, because the chown must have reset those bits. */ - if ((new_dst && copied_as_regular) - && !(ran_chown && (src_mode & ~S_IRWXUGO))) - return delayed_fail; - - if ((x->preserve_chmod_bits || new_dst) - && (x->copy_as_regular || S_ISREG (src_type) || S_ISDIR (src_type))) - { - if (chmod (dst_path, get_dest_mode (x, src_mode))) - { - error (0, errno, _("setting permissions for %s"), quote (dst_path)); - if (x->set_mode || x->require_preserve) - return 1; - } - } - - return delayed_fail; - -un_backup: - if (dst_backup) - { - if (rename (dst_backup, dst_path)) - error (0, errno, _("cannot un-backup %s"), quote (dst_path)); - else - { - if (x->verbose) - printf (_("%s -> %s (unbackup)\n"), - quote_n (0, dst_backup), quote_n (1, dst_path)); - } - } - return 1; -} - -static int -valid_options (const struct cp_options *co) -{ - assert (co != NULL); - - assert (VALID_BACKUP_TYPE (co->backup_type)); - - /* FIXME: for some reason this assertion always fails, - at least on Solaris2.5.1. Just disable it for now. */ - /* assert (co->xstat == lstat || co->xstat == stat); */ - - /* Make sure xstat and dereference are consistent. */ - /* FIXME */ - - assert (VALID_SPARSE_MODE (co->sparse_mode)); - - return 1; -} - -/* Copy the file SRC_PATH to the file DST_PATH. The files may be of - any type. NONEXISTENT_DST should be nonzero if the file DST_PATH - is known not to exist (e.g., because its parent directory was just - created); NONEXISTENT_DST should be zero if DST_PATH might already - exist. OPTIONS is ... FIXME-describe - Set *COPY_INTO_SELF to nonzero if SRC_PATH is a parent of (or the - same as) DST_PATH; otherwise, set it to zero. - Return 0 if successful, 1 if an error occurs. */ - -int -copy (const char *src_path, const char *dst_path, - int nonexistent_dst, const struct cp_options *options, - int *copy_into_self, int *rename_succeeded) -{ - /* move_mode is set to the value from the `options' parameter for the - first copy_internal call. For all subsequent calls (if any), it must - be zero. */ - int move_mode = options->move_mode; - - assert (valid_options (options)); - - /* Record the file names: they're used in case of error, when copying - a directory into itself. I don't like to make these tools do *any* - extra work in the common case when that work is solely to handle - exceptional cases, but in this case, I don't see a way to derive the - top level source and destination directory names where they're used. - An alternative is to use COPY_INTO_SELF and print the diagnostic - from every caller -- but I don't wan't to do that. */ - top_level_src_path = src_path; - top_level_dst_path = dst_path; - - return copy_internal (src_path, dst_path, nonexistent_dst, 0, NULL, - options, move_mode, copy_into_self, rename_succeeded); -} diff --git a/src/apps/bin/gnu/copy.h b/src/apps/bin/gnu/copy.h deleted file mode 100644 index 9cc4e4cd3e..0000000000 --- a/src/apps/bin/gnu/copy.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef COPY_H -# define COPY_H - -/* Control creation of sparse files (files with holes). */ -enum Sparse_type -{ - SPARSE_UNUSED, - - /* Never create holes in DEST. */ - SPARSE_NEVER, - - /* This is the default. Use a crude (and sometimes inaccurate) - heuristic to determine if SOURCE has holes. If so, try to create - holes in DEST. */ - SPARSE_AUTO, - - /* For every sufficiently long sequence of bytes in SOURCE, try to - create a corresponding hole in DEST. There is a performance penalty - here because CP has to search for holes in SRC. But if the holes are - big enough, that penalty can be offset by the decrease in the amount - of data written to disk. */ - SPARSE_ALWAYS -}; - -enum Dereference_symlink -{ - DEREF_UNDEFINED = 1, - DEREF_ALWAYS, - DEREF_NEVER, - DEREF_COMMAND_LINE_ARGUMENTS -}; - -# define VALID_SPARSE_MODE(Mode) \ - ((Mode) == SPARSE_NEVER \ - || (Mode) == SPARSE_AUTO \ - || (Mode) == SPARSE_ALWAYS) - -struct cp_options -{ - enum backup_type backup_type; - - /* If nonzero, copy all files except (directories and, if not dereferencing - them, symbolic links,) as if they were regular files. */ - int copy_as_regular; - - /* If nonzero, dereference symbolic links (copy the files they point to). */ - enum Dereference_symlink dereference; - - /* If nonzero, remove each existing destination nondirectory before - trying to open it. */ - int unlink_dest_before_opening; - - /* If nonzero, first try to open each existing destination nondirectory, - then, if the open fails, unlink and try again. - This option must be set for `cp -f', in case the destination file - exists when the open is attempted. It is irrelevant to `mv' since - any destination is sure to be removed before the open. */ - int unlink_dest_after_failed_open; - - /* Setting this member is meaningful only if FORCE is also set. - If nonzero, copy returns nonzero upon failed unlink. - Otherwise, the failure still elicits a diagnostic, but it doesn't - change copy's return value. This is nonzero for cp and mv, and zero - for install. */ - /* FIXME: this is now unused. */ - int failed_unlink_is_fatal; - - /* If nonzero, create hard links instead of copying files. - Create destination directories as usual. */ - int hard_link; - - /* If nonzero, query before overwriting existing destinations - with regular files. */ - int interactive; - - /* If nonzero, rather than copying, first attempt to use rename. - If that fails, then resort to copying. */ - int move_mode; - - /* This process's effective user ID. */ - uid_t myeuid; - - /* If nonzero, when copying recursively, skip any subdirectories that are - on different filesystems from the one we started on. */ - int one_file_system; - - /* If nonzero, attempt to give the copies the original files' permissions, - owner, group, and timestamps. */ - int preserve_owner_and_group; - int preserve_chmod_bits; - int preserve_timestamps; - - /* If nonzero and any of the above (for preserve) file attributes cannot - be applied to a destination file, treat it as a failure and return - nonzero immediately. E.g. cp -p requires this be nonzero, mv requires - it be zero. */ - int require_preserve; - - /* If nonzero, copy directories recursively and copy special files - as themselves rather than copying their contents. */ - int recursive; - - /* If nonzero, set file mode to value of MODE. Otherwise, - set it based on current umask modified by UMASK_KILL. */ - int set_mode; - - /* Set the mode of the destination file to exactly this value - if USE_MODE is nonzero. */ - mode_t mode; - - /* Control creation of sparse files. */ - enum Sparse_type sparse_mode; - - /* If nonzero, create symbolic links instead of copying files. - Create destination directories as usual. */ - int symbolic_link; - - /* The bits to preserve in created files' modes. */ - mode_t umask_kill; - - /* If nonzero, do not copy a nondirectory that has an existing destination - with the same or newer modification time. */ - int update; - - /* If nonzero, display the names of the files before copying them. */ - int verbose; - - /* A pointer to either lstat or stat, depending on - whether the copy should dereference symlinks. */ - int (*xstat) (); -}; - -int stat (); -int lstat (); - -/* Arrange to make lstat calls go through the wrapper function - on systems with an lstat function that does not dereference symlinks - that are specified with a trailing slash. */ -# if ! LSTAT_FOLLOWS_SLASHED_SYMLINK -int rpl_lstat PARAMS((const char *, struct stat *)); -# undef lstat -# define lstat rpl_lstat -# endif - -int rename (); - -/* Arrange to make rename calls go through the wrapper function - on systems with a rename function that fails for a source path - specified with a trailing slash. */ -# if RENAME_TRAILING_SLASH_BUG -int rpl_rename PARAMS((const char *, const char *)); -# undef rename -# define rename rpl_rename -# endif - -int -copy PARAMS ((const char *src_path, const char *dst_path, - int nonexistent_dst, const struct cp_options *options, - int *copy_into_self, int *rename_succeeded)); - -#endif diff --git a/src/apps/bin/gnu/cp-hash.c b/src/apps/bin/gnu/cp-hash.c deleted file mode 100644 index a064efcaeb..0000000000 --- a/src/apps/bin/gnu/cp-hash.c +++ /dev/null @@ -1,235 +0,0 @@ -/* cp-hash.c -- file copying (hash search routines) - Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - Written by Torbjorn Granlund, Sweden (tege@sics.se). */ - -#include - -#if HAVE_INTTYPES_H -# include -#endif -#include -#include -#include "system.h" -#include "error.h" -#include "cp-hash.h" -#include "quote.h" - -struct entry -{ - ino_t ino; - dev_t dev; - /* Destination path name (of non-directory or pre-existing directory) - corresponding to the dev/ino of a copied file, or the destination path - name corresponding to a dev/ino pair for a newly-created directory. */ - char *node; - - struct entry *coll_link; /* 0 = entry not occupied. */ -}; - -struct htab -{ - unsigned modulus; /* Size of the `hash' pointer vector. */ - struct entry *entry_tab; /* Pointer to dynamically growing vector. */ - unsigned entry_tab_size; /* Size of current `entry_tab' allocation. */ - unsigned first_free_entry; /* Index in `entry_tab'. */ - struct entry *hash[1]; /* Vector of pointers in `entry_tab'. */ -}; - -static struct htab *htab; - -static char *cph_hash_insert PARAMS ((ino_t ino, dev_t dev, const char *node)); - -/* Add PATH to the list of files that we have created. - Return 0 if successful, 1 if not. */ - -int -remember_created (const char *path) -{ - struct stat sb; - - if (stat (path, &sb) < 0) - { - error (0, errno, "%s", quote (path)); - return 1; - } - - cph_hash_insert (sb.st_ino, sb.st_dev, path); - return 0; -} - -/* Add path NODE, copied from inode number INO and device number DEV, - to the list of files we have copied. - Return NULL if inserted, otherwise non-NULL. */ - -char * -remember_copied (const char *node, ino_t ino, dev_t dev) -{ - return cph_hash_insert (ino, dev, node); -} - -/* Allocate space for the hash structures, and set the global - variable `htab' to point to it. The initial hash module is specified in - MODULUS, and the number of entries are specified in ENTRY_TAB_SIZE. (The - hash structure will be rebuilt when ENTRY_TAB_SIZE entries have been - inserted, and MODULUS and ENTRY_TAB_SIZE in the global `htab' will be - doubled.) */ - -void -hash_init (unsigned int modulus, unsigned int entry_tab_size) -{ - struct htab *htab_r; - - htab_r = (struct htab *) - xmalloc (sizeof (struct htab) + sizeof (struct entry *) * modulus); - - htab_r->entry_tab = (struct entry *) - xmalloc (sizeof (struct entry) * entry_tab_size); - - htab_r->modulus = modulus; - htab_r->entry_tab_size = entry_tab_size; - htab = htab_r; - - forget_all (); -} - -/* Reset the hash structure in the global variable `htab' to - contain no entries. */ - -void -forget_all (void) -{ - int i; - struct entry **p; - - htab->first_free_entry = 0; - - p = htab->hash; - for (i = htab->modulus; i > 0; i--) - *p++ = NULL; -} - -/* Insert path NODE, copied from inode number INO and device number DEV, - into the hash structure HTAB, if not already present. - Return NULL if inserted, otherwise non-NULL. */ - -static char * -hash_insert2 (struct htab *ht, ino_t ino, dev_t dev, const char *node) -{ - struct entry **hp, *ep2, *ep; - - /* The cast to uintmax_t prevents negative remainders if ino is negative. */ - hp = &ht->hash[(uintmax_t) ino % ht->modulus]; - - ep2 = *hp; - - /* Collision? */ - - if (ep2 != NULL) - { - ep = ep2; - - /* Search for an entry with the same data. */ - - do - { - if (ep->ino == ino && ep->dev == dev) - return ep->node; /* Found an entry with the same data. */ - ep = ep->coll_link; - } - while (ep != NULL); - - /* Did not find it. */ - - } - - ep = *hp = &ht->entry_tab[ht->first_free_entry++]; - ep->ino = ino; - ep->dev = dev; - ep->node = (char *) node; - ep->coll_link = ep2; /* ep2 is NULL if not collision. */ - - return NULL; -} - -/* Insert path NODE, copied from inode number INO and device number DEV, - into the hash structure in the global variable `htab', if an entry with - the same inode and device was not found already. - Return NULL if inserted, otherwise non-NULL. */ - -static char * -cph_hash_insert (ino_t ino, dev_t dev, const char *node) -{ - struct htab *htab_r = htab; - - if (htab_r->first_free_entry >= htab_r->entry_tab_size) - { - int i; - struct entry *ep; - unsigned modulus; - unsigned entry_tab_size; - - /* Increase the number of hash entries, and re-hash the data. - The method of shrinking and increasing is made to compactify - the heap. If twice as much data would be allocated - straightforwardly, we would never re-use a byte of memory. */ - - /* Let htab shrink. Keep only the header, not the pointer vector. */ - - htab_r = (struct htab *) - xrealloc ((char *) htab_r, sizeof (struct htab)); - - modulus = 2 * htab_r->modulus; - entry_tab_size = 2 * htab_r->entry_tab_size; - - /* Increase the number of possible entries. */ - - htab_r->entry_tab = (struct entry *) - xrealloc ((char *) htab_r->entry_tab, - sizeof (struct entry) * entry_tab_size); - - /* Increase the size of htab again. */ - - htab_r = (struct htab *) - xrealloc ((char *) htab_r, - sizeof (struct htab) + sizeof (struct entry *) * modulus); - - htab_r->modulus = modulus; - htab_r->entry_tab_size = entry_tab_size; - htab = htab_r; - - i = htab_r->first_free_entry; - - /* Make the increased hash table empty. The entries are still - available in htab->entry_tab. */ - - forget_all (); - - /* Go through the entries and install them in the pointer vector - htab->hash. The items are actually inserted in htab->entry_tab at - the position where they already are. The htab->coll_link need - however be updated. Could be made a little more efficient. */ - - for (ep = htab_r->entry_tab; i > 0; i--) - { - hash_insert2 (htab_r, ep->ino, ep->dev, ep->node); - ep++; - } - } - - return hash_insert2 (htab_r, ino, dev, node); -} diff --git a/src/apps/bin/gnu/cp-hash.h b/src/apps/bin/gnu/cp-hash.h deleted file mode 100644 index 6bde1cc9b6..0000000000 --- a/src/apps/bin/gnu/cp-hash.h +++ /dev/null @@ -1,8 +0,0 @@ -/* For created inodes, a pointer in the search structure to this - character identifies the inode as being new. */ -extern char new_file; - -void hash_init PARAMS ((unsigned int modulus, unsigned int entry_tab_size)); -void forget_all PARAMS ((void)); -char *remember_copied PARAMS ((const char *node, ino_t ino, dev_t dev)); -int remember_created PARAMS ((const char *path)); diff --git a/src/apps/bin/gnu/cp.c b/src/apps/bin/gnu/cp.c deleted file mode 100644 index d98dfd72e6..0000000000 --- a/src/apps/bin/gnu/cp.c +++ /dev/null @@ -1,911 +0,0 @@ -/* cp.c -- file copying (main routines) - Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering. */ - -#ifdef _AIX - #pragma alloca -#endif - -#include -#include -#include -#include -#include - -#include "system.h" -#include "argmatch.h" -#include "backupfile.h" -#include "copy.h" -#include "cp-hash.h" -#include "error.h" -#include "dirname.h" -#include "path-concat.h" -#include "quote.h" - -#define ASSIGN_BASENAME_STRDUPA(Dest, File_name) \ - do \ - { \ - char *tmp_abns_; \ - ASSIGN_STRDUPA (tmp_abns_, (File_name)); \ - strip_trailing_slashes (tmp_abns_); \ - Dest = base_name (tmp_abns_); \ - } \ - while (0) - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "cp" - -#define AUTHORS "Torbjorn Granlund, David MacKenzie, and Jim Meyering" - -#ifndef _POSIX_VERSION -uid_t geteuid (); -#endif - -/* Used by do_copy, make_path_private, and re_protect - to keep a list of leading directories whose protections - need to be fixed after copying. */ -struct dir_attr -{ - int is_new_dir; - int slash_offset; - struct dir_attr *next; -}; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - TARGET_DIRECTORY_OPTION = CHAR_MAX + 1, - SPARSE_OPTION, - STRIP_TRAILING_SLASHES_OPTION, - PARENTS_OPTION, - UNLINK_DEST_BEFORE_OPENING -}; - -void strip_trailing_slashes (); - -/* Initial number of entries in each hash table entry's table of inodes. */ -#define INITIAL_HASH_MODULE 100 - -/* Initial number of entries in the inode hash table. */ -#define INITIAL_ENTRY_TAB_SIZE 70 - -/* The invocation name of this program. */ -char *program_name; - -/* If nonzero, the command "cp x/e_file e_dir" uses "e_dir/x/e_file" - as its destination instead of the usual "e_dir/e_file." */ -static int flag_path = 0; - -/* Remove any trailing slashes from each SOURCE argument. */ -static int remove_trailing_slashes; - -static char const *const sparse_type_string[] = -{ - "never", "auto", "always", 0 -}; - -static enum Sparse_type const sparse_type[] = -{ - SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS -}; - -/* The error code to return to the system. */ -static int exit_status = 0; - -static struct option const long_opts[] = -{ - {"archive", no_argument, NULL, 'a'}, - {"backup", optional_argument, NULL, 'b'}, - {"dereference", no_argument, NULL, 'L'}, - {"force", no_argument, NULL, 'f'}, - {"sparse", required_argument, NULL, SPARSE_OPTION}, - {"interactive", no_argument, NULL, 'i'}, - {"link", no_argument, NULL, 'l'}, - {"no-dereference", no_argument, NULL, 'd'}, - {"one-file-system", no_argument, NULL, 'x'}, - {"parents", no_argument, NULL, PARENTS_OPTION}, - {"path", no_argument, NULL, PARENTS_OPTION}, /* Deprecated. */ - {"preserve", no_argument, NULL, 'p'}, - {"recursive", no_argument, NULL, 'R'}, - {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING}, - {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, - {"suffix", required_argument, NULL, 'S'}, - {"symbolic-link", no_argument, NULL, 's'}, - {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, - {"update", no_argument, NULL, 'u'}, - {"verbose", no_argument, NULL, 'v'}, - {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("\ -Usage: %s [OPTION]... SOURCE DEST\n\ - or: %s [OPTION]... SOURCE... DIRECTORY\n\ - or: %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\ -"), - program_name, program_name, program_name); - printf (_("\ -Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\ -\n\ - -a, --archive same as -dpR\n\ - --backup[=CONTROL] make a backup of each existing destination file\n\ - -b like --backup but does not accept an argument\n\ - -d, --no-dereference never follow symbolic links\n\ - -f, --force if an existing destination file cannot be\n\ - opened, remove it and try again\n\ - -i, --interactive prompt before overwrite\n\ - -H follow command-line symbolic links\n\ - -l, --link link files instead of copying\n\ - -L, --dereference always follow symbolic links\n\ - -p, --preserve preserve file attributes if possible\n\ - --parents append source path to DIRECTORY\n\ - -P same as `--parents' for now; soon to change to\n\ - `--no-dereference' to conform to POSIX\n\ - -r copy recursively, non-directories as files\n\ - WARNING: use -R instead when you might copy\n\ - special files like FIFOs or /dev/zero\n\ - --remove-destination remove each existing destination file before\n\ - attempting to open it (contrast with --force)\n\ -")); - printf (_("\ - --sparse=WHEN control creation of sparse files\n\ - -R, --recursive copy directories recursively\n\ - --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\ - argument\n\ - -s, --symbolic-link make symbolic links instead of copying\n\ - -S, --suffix=SUFFIX override the usual backup suffix\n\ - --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\ - -u, --update copy only when the SOURCE file is newer\n\ - than the destination file or when the\n\ - destination file is missing\n\ - -v, --verbose explain what is being done\n\ - -x, --one-file-system stay on this file system\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -By default, sparse SOURCE files are detected by a crude heuristic and the\n\ -corresponding DEST file is made sparse as well. That is the behavior\n\ -selected by --sparse=auto. Specify --sparse=always to create a sparse DEST\n\ -file whenever the SOURCE file contains a long enough sequence of zero bytes.\n\ -Use --sparse=never to inhibit creation of sparse files.\n\ -\n\ -")); - printf (_("\ -The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ -The version control method may be selected via the --backup option or through\n\ -the VERSION_CONTROL environment variable. Here are the values:\n\ -\n\ - none, off never make backups (even if --backup is given)\n\ - numbered, t make numbered backups\n\ - existing, nil numbered if numbered backups exist, simple otherwise\n\ - simple, never always make simple backups\n\ -")); - printf (_("\ -\n\ -As a special case, cp makes a backup of SOURCE when the force and backup\n\ -options are given and SOURCE and DEST are the same name for an existing,\n\ -regular file.\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -/* Ensure that the parent directories of CONST_DST_PATH have the - correct protections, for the --parents option. This is done - after all copying has been completed, to allow permissions - that don't include user write/execute. - - SRC_OFFSET is the index in CONST_DST_PATH of the beginning of the - source directory name. - - ATTR_LIST is a null-terminated linked list of structures that - indicates the end of the filename of each intermediate directory - in CONST_DST_PATH that may need to have its attributes changed. - The command `cp --parents --preserve a/b/c d/e_dir' changes the - attributes of the directories d/e_dir/a and d/e_dir/a/b to match - the corresponding source directories regardless of whether they - existed before the `cp' command was given. - - Return 0 if the parent of CONST_DST_PATH and any intermediate - directories specified by ATTR_LIST have the proper permissions - when done, otherwise 1. */ - -static int -re_protect (const char *const_dst_path, int src_offset, - struct dir_attr *attr_list, const struct cp_options *x) -{ - struct dir_attr *p; - char *dst_path; /* A copy of CONST_DST_PATH we can change. */ - char *src_path; /* The source name in `dst_path'. */ - uid_t myeuid = geteuid (); - - dst_path = (char *) alloca (strlen (const_dst_path) + 1); - strcpy (dst_path, const_dst_path); - src_path = dst_path + src_offset; - - for (p = attr_list; p; p = p->next) - { - struct stat src_sb; - - dst_path[p->slash_offset] = '\0'; - - if ((*(x->xstat)) (src_path, &src_sb)) - { - error (0, errno, _("getting attributes of %s"), - quote (src_path)); - return 1; - } - - /* Adjust the times (and if possible, ownership) for the copy. - chown turns off set[ug]id bits for non-root, - so do the chmod last. */ - - if (x->preserve_timestamps) - { - struct utimbuf utb; - - /* There's currently no interface to set file timestamps with - better than 1-second resolution, so discard any fractional - part of the source timestamp. */ - - utb.actime = src_sb.st_atime; - utb.modtime = src_sb.st_mtime; - - if (utime (dst_path, &utb)) - { - error (0, errno, _("preserving times for %s"), quote (dst_path)); - return 1; - } - } - - if (x->preserve_owner_and_group) - { - /* If non-root uses -p, it's ok if we can't preserve ownership. - But root probably wants to know, e.g. if NFS disallows it, - or if the target system doesn't support file ownership. */ - if (chown (dst_path, src_sb.st_uid, src_sb.st_gid) - && ((errno != EPERM && errno != EINVAL) || myeuid == 0)) - { - error (0, errno, _("preserving ownership for %s"), - quote (dst_path)); - return 1; - } - } - - if (x->preserve_chmod_bits || p->is_new_dir) - { - if (chmod (dst_path, src_sb.st_mode & x->umask_kill)) - { - error (0, errno, _("preserving permissions for %s"), - quote (dst_path)); - return 1; - } - } - - dst_path[p->slash_offset] = '/'; - } - return 0; -} - -/* Ensure that the parent directory of CONST_DIRPATH exists, for - the --parents option. - - SRC_OFFSET is the index in CONST_DIRPATH (which is a destination - path) of the beginning of the source directory name. - Create any leading directories that don't already exist, - giving them permissions MODE. - If VERBOSE_FMT_STRING is nonzero, use it as a printf format - string for printing a message after successfully making a directory. - The format should take two string arguments: the names of the - source and destination directories. - Creates a linked list of attributes of intermediate directories, - *ATTR_LIST, for re_protect to use after calling copy. - Sets *NEW_DST to 1 if this function creates parent of CONST_DIRPATH. - - Return 0 if parent of CONST_DIRPATH exists as a directory with the proper - permissions when done, otherwise 1. */ - -/* FIXME: find a way to synch this function with the one in lib/makepath.c. */ - -static int -make_path_private (const char *const_dirpath, int src_offset, int mode, - const char *verbose_fmt_string, struct dir_attr **attr_list, - int *new_dst, int (*xstat)()) -{ - struct stat stats; - char *dirpath; /* A copy of CONST_DIRPATH we can change. */ - char *src; /* Source name in `dirpath'. */ - char *tmp_dst_dirname; /* Leading path of `dirpath', malloc. */ - char *dst_dirname; /* Leading path of `dirpath', alloca. */ - - dirpath = (char *) alloca (strlen (const_dirpath) + 1); - strcpy (dirpath, const_dirpath); - - src = dirpath + src_offset; - - tmp_dst_dirname = dir_name (dirpath); - dst_dirname = (char *) alloca (strlen (tmp_dst_dirname) + 1); - strcpy (dst_dirname, tmp_dst_dirname); - free (tmp_dst_dirname); - - *attr_list = NULL; - - if ((*xstat) (dst_dirname, &stats)) - { - /* Parent of CONST_DIRNAME does not exist. - Make all missing intermediate directories. */ - char *slash; - - slash = src; - while (*slash == '/') - slash++; - while ((slash = strchr (slash, '/'))) - { - /* Add this directory to the list of directories whose modes need - fixing later. */ - struct dir_attr *new = - (struct dir_attr *) xmalloc (sizeof (struct dir_attr)); - new->slash_offset = slash - dirpath; - new->next = *attr_list; - *attr_list = new; - - *slash = '\0'; - if ((*xstat) (dirpath, &stats)) - { - /* This element of the path does not exist. We must set - *new_dst and new->is_new_dir inside this loop because, - for example, in the command `cp --parents ../a/../b/c e_dir', - make_path_private creates only e_dir/../a if ./b already - exists. */ - *new_dst = 1; - new->is_new_dir = 1; - if (mkdir (dirpath, mode)) - { - error (0, errno, _("cannot make directory %s"), - quote (dirpath)); - return 1; - } - else - { - if (verbose_fmt_string != NULL) - printf (verbose_fmt_string, src, dirpath); - } - } - else if (!S_ISDIR (stats.st_mode)) - { - error (0, 0, _("%s exists but is not a directory"), - quote (dirpath)); - return 1; - } - else - { - new->is_new_dir = 0; - *new_dst = 0; - } - *slash++ = '/'; - - /* Avoid unnecessary calls to `stat' when given - pathnames containing multiple adjacent slashes. */ - while (*slash == '/') - slash++; - } - } - - /* We get here if the parent of `dirpath' already exists. */ - - else if (!S_ISDIR (stats.st_mode)) - { - error (0, 0, _("%s exists but is not a directory"), quote (dst_dirname)); - return 1; - } - else - { - *new_dst = 0; - } - return 0; -} - -/* Scan the arguments, and copy each by calling copy. - Return 0 if successful, 1 if any errors occur. */ - -static int -do_copy (int n_files, char **file, const char *target_directory, - const struct cp_options *x) -{ - const char *dest; - struct stat sb; - int new_dst = 0; - int ret = 0; - int dest_is_dir = 0; - - if (n_files <= 0) - { - error (0, 0, _("missing file arguments")); - usage (1); - } - if (n_files == 1 && !target_directory) - { - error (0, 0, _("missing destination file")); - usage (1); - } - - if (target_directory) - dest = target_directory; - else - { - dest = file[n_files - 1]; - --n_files; - } - - if (lstat (dest, &sb)) - { - if (errno != ENOENT) - { - error (0, errno, _("accessing %s"), quote (dest)); - return 1; - } - - new_dst = 1; - } - else - { - struct stat sbx; - - /* If `dest' is not a symlink to a nonexistent file, use - the results of stat instead of lstat, so we can copy files - into symlinks to directories. */ - if (stat (dest, &sbx) == 0) - sb = sbx; - - dest_is_dir = S_ISDIR (sb.st_mode); - } - - if (!dest_is_dir) - { - if (target_directory) - { - error (0, 0, _("specified target, %s is not a directory"), - quote (dest)); - usage (1); - } - - if (n_files > 1) - { - error (0, 0, - _("copying multiple files, but last argument %s is not a directory"), - quote (dest)); - usage (1); - } - } - - if (dest_is_dir) - { - /* cp file1...filen edir - Copy the files `file1' through `filen' - to the existing directory `edir'. */ - int i; - - for (i = 0; i < n_files; i++) - { - char *dst_path; - int parent_exists = 1; /* True if dir_name (dst_path) exists. */ - struct dir_attr *attr_list; - char *arg_in_concat = NULL; - char *arg = file[i]; - - /* Trailing slashes are meaningful (i.e., maybe worth preserving) - only in the source file names. */ - if (remove_trailing_slashes) - strip_trailing_slashes (arg); - - if (flag_path) - { - char *arg_no_trailing_slash; - - /* Use `arg' without trailing slashes in constructing destination - file names. Otherwise, we can end up trying to create a - directory via `mkdir ("dst/foo/"...', which is not portable. - It fails, due to the trailing slash, on at least - NetBSD 1.[34] systems. */ - ASSIGN_STRDUPA (arg_no_trailing_slash, arg); - strip_trailing_slashes (arg_no_trailing_slash); - - /* Append all of `arg' (minus any trailing slash) to `dest'. */ - dst_path = path_concat (dest, arg_no_trailing_slash, - &arg_in_concat); - if (dst_path == NULL) - xalloc_die (); - - /* For --parents, we have to make sure that the directory - dir_name (dst_path) exists. We may have to create a few - leading directories. */ - parent_exists = !make_path_private (dst_path, - arg_in_concat - dst_path, - S_IRWXU, - (x->verbose - ? "%s -> %s\n" : NULL), - &attr_list, &new_dst, - x->xstat); - } - else - { - char *arg_base; - /* Append the last component of `arg' to `dest'. */ - - ASSIGN_BASENAME_STRDUPA (arg_base, arg); - /* For `cp -R source/.. dest', don't copy into `dest/..'. */ - dst_path = (STREQ (arg_base, "..") - ? xstrdup (dest) - : path_concat (dest, arg_base, NULL)); - } - - if (!parent_exists) - { - /* make_path_private failed, so don't even attempt the copy. */ - ret = 1; - } - else - { - int copy_into_self; - ret |= copy (arg, dst_path, new_dst, x, ©_into_self, NULL); - forget_all (); - - if (flag_path) - { - ret |= re_protect (dst_path, arg_in_concat - dst_path, - attr_list, x); - } - } - - free (dst_path); - } - return ret; - } - else /* if (n_files == 1) */ - { - char *new_dest; - char *source; - int unused; - struct stat source_stats; - - if (flag_path) - { - error (0, 0, - _("when preserving paths, the destination must be a directory")); - usage (1); - } - - source = file[0]; - - /* When the force and backup options have been specified and - the source and destination are the same name for an existing - regular file, convert the user's command, e.g., - `cp --force --backup foo foo' to `cp --force foo fooSUFFIX' - where SUFFIX is determined by any version control options used. */ - - if (x->unlink_dest_after_failed_open - && x->backup_type != none - && STREQ (source, dest) - && !new_dst && S_ISREG (sb.st_mode)) - { - static struct cp_options x_tmp; - - new_dest = find_backup_file_name (dest, x->backup_type); - /* Set x->backup_type to `none' so that the normal backup - mechanism is not used when performing the actual copy. - backup_type must be set to `none' only *after* the above - call to find_backup_file_name -- that function uses - backup_type to determine the suffix it applies. */ - x_tmp = *x; - x_tmp.backup_type = none; - x = &x_tmp; - - if (new_dest == NULL) - xalloc_die (); - } - - /* When the destination is specified with a trailing slash and the - source exists but is not a directory, convert the user's command - `cp source dest/' to `cp source dest/basename(source)'. Doing - this ensures that the command `cp non-directory file/' will now - fail rather than performing the copy. COPY diagnoses the case of - `cp directory non-directory'. */ - - else if (dest[strlen (dest) - 1] == '/' - && lstat (source, &source_stats) == 0 - && !S_ISDIR (source_stats.st_mode)) - { - char *source_base; - - ASSIGN_BASENAME_STRDUPA (source_base, source); - new_dest = (char *) alloca (strlen (dest) - + strlen (source_base) + 1); - stpcpy (stpcpy (new_dest, dest), source_base); - } - else - { - new_dest = (char *) dest; - } - - return copy (source, new_dest, new_dst, x, &unused, NULL); - } - - /* unreachable */ -} - -static void -cp_option_init (struct cp_options *x) -{ - x->copy_as_regular = 1; - x->dereference = DEREF_UNDEFINED; - x->unlink_dest_before_opening = 0; - x->unlink_dest_after_failed_open = 0; - x->failed_unlink_is_fatal = 1; - x->hard_link = 0; - x->interactive = 0; - x->myeuid = geteuid (); - x->move_mode = 0; - x->one_file_system = 0; - - x->preserve_owner_and_group = 0; - x->preserve_chmod_bits = 0; - x->preserve_timestamps = 0; - - x->require_preserve = 0; - x->recursive = 0; - x->sparse_mode = SPARSE_AUTO; - x->symbolic_link = 0; - x->set_mode = 0; - x->mode = 0; - - /* Find out the current file creation mask, to knock the right bits - when using chmod. The creation mask is set to be liberal, so - that created directories can be written, even if it would not - have been allowed with the mask this process was started with. */ - x->umask_kill = ~ umask (0); - - x->update = 0; - x->verbose = 0; -} - -int -main (int argc, char **argv) -{ - int c; - int make_backups = 0; - char *backup_suffix_string; - char *version_control_string = NULL; - struct cp_options x; - char *target_directory = NULL; - int used_P_option = 0; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - cp_option_init (&x); - - /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); - - while ((c = getopt_long (argc, argv, "abdfHilLprsuvxPRS:V:", long_opts, NULL)) - != -1) - { - switch (c) - { - case 0: - break; - - case SPARSE_OPTION: - x.sparse_mode = XARGMATCH ("--sparse", optarg, - sparse_type_string, sparse_type); - break; - - case 'a': /* Like -dpR. */ - x.dereference = DEREF_NEVER; - x.preserve_owner_and_group = 1; - x.preserve_chmod_bits = 1; - x.preserve_timestamps = 1; - x.require_preserve = 1; - x.recursive = 1; - x.copy_as_regular = 0; - break; - - case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ - error (0, 0, - _("warning: --version-control (-V) is obsolete; support for\ - it\nwill be removed in some future release. Use --backup=%s instead." - ), optarg); - /* Fall through. */ - - case 'b': - make_backups = 1; - if (optarg) - version_control_string = optarg; - break; - - case 'd': - x.dereference = DEREF_NEVER; - break; - - case 'f': - x.unlink_dest_after_failed_open = 1; - break; - - case 'H': - x.dereference = DEREF_COMMAND_LINE_ARGUMENTS; - break; - - case 'i': - x.interactive = 1; - break; - - case 'l': - x.hard_link = 1; - break; - - case 'L': - x.dereference = DEREF_ALWAYS; - break; - - case 'p': - x.preserve_owner_and_group = 1; - x.preserve_chmod_bits = 1; - x.preserve_timestamps = 1; - x.require_preserve = 1; - break; - - case 'P': - used_P_option = 1; - /* fall through */ - case PARENTS_OPTION: - flag_path = 1; - break; - - case 'r': - x.recursive = 1; - x.copy_as_regular = 1; - break; - - case 'R': - x.recursive = 1; - x.copy_as_regular = 0; - break; - - case UNLINK_DEST_BEFORE_OPENING: - x.unlink_dest_before_opening = 1; - break; - - case STRIP_TRAILING_SLASHES_OPTION: - remove_trailing_slashes = 1; - break; - - case 's': -#ifdef S_ISLNK - x.symbolic_link = 1; -#else - error (1, 0, _("symbolic links are not supported on this system")); -#endif - break; - - case TARGET_DIRECTORY_OPTION: - target_directory = optarg; - break; - - case 'u': - x.update = 1; - break; - - case 'v': - x.verbose = 1; - break; - - case 'x': - x.one_file_system = 1; - break; - - case 'S': - make_backups = 1; - backup_suffix_string = optarg; - break; - - case_GETOPT_HELP_CHAR; - - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - - default: - usage (1); - } - } - - if (x.hard_link && x.symbolic_link) - { - error (0, 0, _("cannot make both hard and symbolic links")); - usage (1); - } - - if (used_P_option) - { - error (0, 0, - _("\ -Warning: the meaning of `-P' will change in the future to conform to POSIX.\n\ -Use `--parents' for the old meaning, and `--no-dereference' for the new one.")); - } - - if (backup_suffix_string) - simple_backup_suffix = xstrdup (backup_suffix_string); - - x.backup_type = (make_backups - ? xget_version (_("backup type"), - version_control_string) - : none); - - if (x.preserve_chmod_bits == 1) - x.umask_kill = ~ (mode_t) 0; - - if (x.dereference == DEREF_UNDEFINED) - { - if (x.recursive) - /* This is compatible with FreeBSD. */ - x.dereference = DEREF_NEVER; - else - x.dereference = DEREF_ALWAYS; - } - - /* The key difference between -d (--no-dereference) and not is the version - of `stat' to call. */ - - if (x.dereference == DEREF_NEVER) - x.xstat = lstat; - else - { - /* For DEREF_COMMAND_LINE_ARGUMENTS, x.xstat must be stat for - each command line argument, but must later be `lstat' for - any symlinks that are found via recursive traversal. */ - x.xstat = stat; - } - - /* If --force (-f) was specified and we're in link-creation mode, - first remove any existing destination file. */ - if (x.unlink_dest_after_failed_open && (x.hard_link || x.symbolic_link)) - x.unlink_dest_before_opening = 1; - - /* Allocate space for remembering copied and created files. */ - - hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE); - - exit_status |= do_copy (argc - optind, argv + optind, target_directory, &x); - - exit (exit_status); -} diff --git a/src/apps/bin/gnu/dd.c b/src/apps/bin/gnu/dd.c deleted file mode 100644 index b493accf4b..0000000000 --- a/src/apps/bin/gnu/dd.c +++ /dev/null @@ -1,1202 +0,0 @@ -/* dd -- convert a file while copying it. - Copyright (C) 85, 90, 91, 1995-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by Paul Rubin, David MacKenzie, and Stuart Kemp. */ - -#include -#include - -#define SWAB_ALIGN_OFFSET 2 - -#if HAVE_INTTYPES_H -# include -#endif -#include -#include -#include - -#include "system.h" -#include "closeout.h" -#include "error.h" -#include "getpagesize.h" -#include "human.h" -#include "long-options.h" -#include "quote.h" -#include "safe-read.h" -#include "xstrtol.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "dd" - -#define AUTHORS "Paul Rubin, David MacKenzie, and Stuart Kemp" - -#ifndef SIGINFO -# define SIGINFO SIGUSR1 -#endif - -#ifndef S_TYPEISSHM -# define S_TYPEISSHM(Stat_ptr) 0 -#endif - -#define ROUND_UP_OFFSET(X, M) ((M) - 1 - (((X) + (M) - 1) % (M))) -#define PTR_ALIGN(Ptr, M) ((Ptr) \ - + ROUND_UP_OFFSET ((char *)(Ptr) - (char *)0, (M))) - -#define max(a, b) ((a) > (b) ? (a) : (b)) -#define output_char(c) \ - do \ - { \ - obuf[oc++] = (c); \ - if (oc >= output_blocksize) \ - write_output (); \ - } \ - while (0) - -/* Default input and output blocksize. */ -#define DEFAULT_BLOCKSIZE 512 - -/* Conversions bit masks. */ -#define C_ASCII 01 -#define C_EBCDIC 02 -#define C_IBM 04 -#define C_BLOCK 010 -#define C_UNBLOCK 020 -#define C_LCASE 040 -#define C_UCASE 0100 -#define C_SWAB 0200 -#define C_NOERROR 0400 -#define C_NOTRUNC 01000 -#define C_SYNC 02000 -/* Use separate input and output buffers, and combine partial input blocks. */ -#define C_TWOBUFS 04000 - -int full_write (); - -/* The name this program was run with. */ -char *program_name; - -/* The name of the input file, or NULL for the standard input. */ -static char *input_file = NULL; - -/* The name of the output file, or NULL for the standard output. */ -static char *output_file = NULL; - -/* The number of bytes in which atomic reads are done. */ -static size_t input_blocksize = 0; - -/* The number of bytes in which atomic writes are done. */ -static size_t output_blocksize = 0; - -/* Conversion buffer size, in bytes. 0 prevents conversions. */ -static size_t conversion_blocksize = 0; - -/* Skip this many records of `input_blocksize' bytes before input. */ -static uintmax_t skip_records = 0; - -/* Skip this many records of `output_blocksize' bytes before output. */ -static uintmax_t seek_records = 0; - -/* Copy only this many records. The default is effectively infinity. */ -static uintmax_t max_records = (uintmax_t) -1; - -/* Bit vector of conversions to apply. */ -static int conversions_mask = 0; - -/* If nonzero, filter characters through the translation table. */ -static int translation_needed = 0; - -/* Number of partial blocks written. */ -static uintmax_t w_partial = 0; - -/* Number of full blocks written. */ -static uintmax_t w_full = 0; - -/* Number of partial blocks read. */ -static uintmax_t r_partial = 0; - -/* Number of full blocks read. */ -static uintmax_t r_full = 0; - -/* Records truncated by conv=block. */ -static uintmax_t r_truncate = 0; - -/* Output representation of newline and space characters. - They change if we're converting to EBCDIC. */ -static unsigned char newline_character = '\n'; -static unsigned char space_character = ' '; - -/* Output buffer. */ -static unsigned char *obuf; - -/* Current index into `obuf'. */ -static size_t oc = 0; - -/* Index into current line, for `conv=block' and `conv=unblock'. */ -static size_t col = 0; - -struct conversion -{ - char *convname; - int conversion; -}; - -static struct conversion 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. */ - {"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. */ - {"ucase", C_UCASE | C_TWOBUFS}, /* Translate lower to upper case. */ - {"swab", C_SWAB | C_TWOBUFS}, /* Swap bytes of input. */ - {"noerror", C_NOERROR}, /* Ignore i/o errors. */ - {"notrunc", C_NOTRUNC}, /* Do not truncate output file. */ - {"sync", C_SYNC}, /* Pad input records to ibs with NULs. */ - {NULL, 0} -}; - -/* Translation table formed by applying successive transformations. */ -static unsigned char trans_table[256]; - -static unsigned char const ascii_to_ebcdic[] = -{ - 0, 01, 02, 03, 067, 055, 056, 057, - 026, 05, 045, 013, 014, 015, 016, 017, - 020, 021, 022, 023, 074, 075, 062, 046, - 030, 031, 077, 047, 034, 035, 036, 037, - 0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175, - 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, - 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, - 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, - 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, - 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, - 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, - 0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155, - 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, - 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, - 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, - 0247, 0250, 0251, 0300, 0152, 0320, 0241, 07, - 040, 041, 042, 043, 044, 025, 06, 027, - 050, 051, 052, 053, 054, 011, 012, 033, - 060, 061, 032, 063, 064, 065, 066, 010, - 070, 071, 072, 073, 04, 024, 076, 0341, - 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, - 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, - 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, - 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, - 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, - 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, - 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, - 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, - 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, - 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, - 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, - 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377 -}; - -static unsigned char const ascii_to_ibm[] = -{ - 0, 01, 02, 03, 067, 055, 056, 057, - 026, 05, 045, 013, 014, 015, 016, 017, - 020, 021, 022, 023, 074, 075, 062, 046, - 030, 031, 077, 047, 034, 035, 036, 037, - 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, - 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, - 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, - 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, - 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, - 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, - 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, - 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, - 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, - 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, - 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, - 0247, 0250, 0251, 0300, 0117, 0320, 0241, 07, - 040, 041, 042, 043, 044, 025, 06, 027, - 050, 051, 052, 053, 054, 011, 012, 033, - 060, 061, 032, 063, 064, 065, 066, 010, - 070, 071, 072, 073, 04, 024, 076, 0341, - 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, - 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, - 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, - 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, - 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, - 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, - 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, - 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, - 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, - 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, - 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, - 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377 -}; - -static unsigned char const ebcdic_to_ascii[] = -{ - 0, 01, 02, 03, 0234, 011, 0206, 0177, - 0227, 0215, 0216, 013, 014, 015, 016, 017, - 020, 021, 022, 023, 0235, 0205, 010, 0207, - 030, 031, 0222, 0217, 034, 035, 036, 037, - 0200, 0201, 0202, 0203, 0204, 012, 027, 033, - 0210, 0211, 0212, 0213, 0214, 05, 06, 07, - 0220, 0221, 026, 0223, 0224, 0225, 0226, 04, - 0230, 0231, 0232, 0233, 024, 025, 0236, 032, - 040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, - 0247, 0250, 0133, 056, 074, 050, 053, 041, - 046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, - 0260, 0261, 0135, 044, 052, 051, 073, 0136, - 055, 057, 0262, 0263, 0264, 0265, 0266, 0267, - 0270, 0271, 0174, 054, 045, 0137, 076, 077, - 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, - 0302, 0140, 072, 043, 0100, 047, 075, 042, - 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, - 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, - 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, - 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320, - 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170, - 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327, - 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, - 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, - 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, - 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, - 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, - 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, - 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, - 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, - 060, 061, 062, 063, 064, 065, 066, 067, - 070, 071, 0372, 0373, 0374, 0375, 0376, 0377 -}; - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]...\n"), program_name); - printf (_("\ -Copy a file, converting and formatting according to the options.\n\ -\n\ - bs=BYTES force ibs=BYTES and obs=BYTES\n\ - cbs=BYTES convert BYTES bytes at a time\n\ - conv=KEYWORDS convert the file as per the comma separated keyword list\n\ - count=BLOCKS copy only BLOCKS input blocks\n\ - ibs=BYTES read BYTES bytes at a time\n\ - if=FILE read from FILE instead of stdin\n\ - obs=BYTES write BYTES bytes at a time\n\ - of=FILE write to FILE instead of stdout\n\ - seek=BLOCKS skip BLOCKS obs-sized blocks at start of output\n\ - skip=BLOCKS skip BLOCKS ibs-sized blocks at start of input\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -BLOCKS and BYTES may be followed by the following multiplicative suffixes:\n\ -xM M, c 1, w 2, b 512, kD 1000, k 1024, MD 1,000,000, M 1,048,576,\n\ -GD 1,000,000,000, G 1,073,741,824, and so on for T, P, E, Z, Y.\n\ -Each KEYWORD may be:\n\ -\n\ - ascii from EBCDIC to ASCII\n\ - ebcdic from ASCII to EBCDIC\n\ - ibm from ASCII to alternated EBCDIC\n\ - block pad newline-terminated records with spaces to cbs-size\n\ - unblock replace trailing spaces in cbs-size records with newline\n\ - lcase change upper case to lower case\n\ - notrunc do not truncate the output file\n\ - ucase change lower case to upper case\n\ - swab swap every pair of input bytes\n\ - noerror continue after read errors\n\ - sync pad every input block with NULs to ibs-size; when used\n\ - with block or unblock, pad with spaces rather than NULs\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -static void -translate_charset (const unsigned char *new_trans) -{ - unsigned int i; - - for (i = 0; i < 256; i++) - trans_table[i] = new_trans[trans_table[i]]; - translation_needed = 1; -} - -/* Return the number of 1 bits in `i'. */ - -static int -bit_count (register unsigned int i) -{ - register int set_bits; - - for (set_bits = 0; i != 0; set_bits++) - i &= i - 1; - return set_bits; -} - -static void -print_stats (void) -{ - char buf[2][LONGEST_HUMAN_READABLE + 1]; - fprintf (stderr, _("%s+%s records in\n"), - human_readable (r_full, buf[0], 1, 1), - human_readable (r_partial, buf[1], 1, 1)); - fprintf (stderr, _("%s+%s records out\n"), - human_readable (w_full, buf[0], 1, 1), - human_readable (w_partial, buf[1], 1, 1)); - if (r_truncate > 0) - { - fprintf (stderr, "%s %s\n", - human_readable (r_truncate, buf[0], 1, 1), - (r_truncate == 1 - ? _("truncated record") - : _("truncated records"))); - } -} - -static void -cleanup (void) -{ - print_stats (); - if (close (STDIN_FILENO) < 0) - error (1, errno, _("closing input file %s"), quote (input_file)); - if (close (STDOUT_FILENO) < 0) - error (1, errno, _("closing output file %s"), quote (output_file)); -} - -static inline void -quit (int code) -{ - cleanup (); - exit (code); -} - -static RETSIGTYPE -interrupt_handler (int sig) -{ -#ifdef SA_NOCLDSTOP - struct sigaction sigact; - - sigact.sa_handler = SIG_DFL; - sigemptyset (&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction (sig, &sigact, NULL); -#else - signal (sig, SIG_DFL); -#endif - cleanup (); - kill (getpid (), sig); -} - -static RETSIGTYPE -siginfo_handler (int sig ATTRIBUTE_UNUSED) -{ - print_stats (); -} - -/* Encapsulate portability mess of establishing signal handlers. */ - -static void -install_handler (int sig_num, RETSIGTYPE (*sig_handler) (int sig)) -{ -#ifdef SA_NOCLDSTOP - struct sigaction sigact; - sigaction (sig_num, NULL, &sigact); - if (sigact.sa_handler != SIG_IGN) - { - sigact.sa_handler = sig_handler; - sigemptyset (&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction (sig_num, &sigact, NULL); - } -#else - if (signal (sig_num, SIG_IGN) != SIG_IGN) - signal (sig_num, sig_handler); -#endif -} - -/* Open a file to a particular file descriptor. This is like standard - `open', except it always returns DESIRED_FD if successful. */ -static int -open_fd (int desired_fd, char const *filename, int options, mode_t mode) -{ - int fd; - close (desired_fd); - fd = open (filename, options, mode); - if (fd < 0) - return -1; - - if (fd != desired_fd) - { - if (dup2 (fd, desired_fd) != desired_fd) - desired_fd = -1; - if (close (fd) != 0) - return -1; - } - - return desired_fd; -} - -/* Write, then empty, the output buffer `obuf'. */ - -static void -write_output (void) -{ - int nwritten = full_write (STDOUT_FILENO, obuf, output_blocksize); - if (nwritten != output_blocksize) - { - error (0, errno, _("writing to %s"), quote (output_file)); - if (nwritten > 0) - w_partial++; - quit (1); - } - else - w_full++; - oc = 0; -} - -/* Interpret one "conv=..." option. - As a by product, this function replaces each `,' in STR with a NUL byte. */ - -static void -parse_conversion (char *str) -{ - char *new; - unsigned int i; - - do - { - new = strchr (str, ','); - if (new != NULL) - *new++ = '\0'; - for (i = 0; conversions[i].convname != NULL; i++) - if (STREQ (conversions[i].convname, str)) - { - conversions_mask |= conversions[i].conversion; - break; - } - if (conversions[i].convname == NULL) - { - error (0, 0, _("invalid conversion: %s"), quote (str)); - usage (1); - } - str = new; - } while (new != NULL); -} - -/* Return the value of STR, interpreted as a non-negative decimal integer, - optionally multiplied by various values. - Assign nonzero to *INVALID if STR does not represent a number in - this format. */ - -static uintmax_t -parse_integer (const char *str, int *invalid) -{ - uintmax_t n; - char *suffix; - enum strtol_error e = xstrtoumax (str, &suffix, 10, &n, "bcEGkMPTwYZ0"); - - if (e == LONGINT_INVALID_SUFFIX_CHAR && *suffix == 'x') - { - uintmax_t multiplier = parse_integer (suffix + 1, invalid); - - if (multiplier != 0 && n * multiplier / multiplier != n) - { - *invalid = 1; - return 0; - } - - n *= multiplier; - } - else if (e != LONGINT_OK) - { - *invalid = 1; - return 0; - } - - return n; -} - -static void -scanargs (int argc, char **argv) -{ - int i; - - --argc; - ++argv; - - for (i = optind; i < argc; i++) - { - char *name, *val; - - name = argv[i]; - val = strchr (name, '='); - if (val == NULL) - { - error (0, 0, _("unrecognized option %s"), quote (name)); - usage (1); - } - *val++ = '\0'; - - if (STREQ (name, "if")) - input_file = val; - else if (STREQ (name, "of")) - output_file = val; - else if (STREQ (name, "conv")) - parse_conversion (val); - else - { - int invalid = 0; - uintmax_t n = parse_integer (val, &invalid); - - if (STREQ (name, "ibs")) - { - input_blocksize = n; - invalid |= input_blocksize != n || input_blocksize == 0; - conversions_mask |= C_TWOBUFS; - } - else if (STREQ (name, "obs")) - { - output_blocksize = n; - invalid |= output_blocksize != n || output_blocksize == 0; - conversions_mask |= C_TWOBUFS; - } - else if (STREQ (name, "bs")) - { - output_blocksize = input_blocksize = n; - invalid |= output_blocksize != n || output_blocksize == 0; - } - else if (STREQ (name, "cbs")) - { - conversion_blocksize = n; - invalid |= (conversion_blocksize != n - || conversion_blocksize == 0); - } - else if (STREQ (name, "skip")) - skip_records = n; - else if (STREQ (name, "seek")) - seek_records = n; - else if (STREQ (name, "count")) - max_records = n; - else - { - error (0, 0, _("unrecognized option %s=%s"), - quote_n (0, name), quote_n (1, val)); - usage (1); - } - - if (invalid) - error (1, 0, _("invalid number %s"), quote (val)); - } - } - - /* If bs= was given, both `input_blocksize' and `output_blocksize' will - have been set to positive values. If either has not been set, - bs= was not given, so make sure two buffers are used. */ - if (input_blocksize == 0 || output_blocksize == 0) - conversions_mask |= C_TWOBUFS; - if (input_blocksize == 0) - input_blocksize = DEFAULT_BLOCKSIZE; - if (output_blocksize == 0) - output_blocksize = DEFAULT_BLOCKSIZE; - if (conversion_blocksize == 0) - conversions_mask &= ~(C_BLOCK | C_UNBLOCK); -} - -/* Fix up translation table. */ - -static void -apply_translations (void) -{ - unsigned int i; - -#define MX(a) (bit_count (conversions_mask & (a))) - if ((MX (C_ASCII | C_EBCDIC | C_IBM) > 1) - || (MX (C_BLOCK | C_UNBLOCK) > 1) - || (MX (C_LCASE | C_UCASE) > 1) - || (MX (C_UNBLOCK | C_SYNC) > 1)) - { - error (1, 0, _("\ -only one conv in {ascii,ebcdic,ibm}, {lcase,ucase}, {block,unblock}, {unblock,sync}")); - } -#undef MX - - if (conversions_mask & C_ASCII) - translate_charset (ebcdic_to_ascii); - - if (conversions_mask & C_UCASE) - { - for (i = 0; i < 256; i++) - if (ISLOWER (trans_table[i])) - trans_table[i] = TOUPPER (trans_table[i]); - translation_needed = 1; - } - else if (conversions_mask & C_LCASE) - { - for (i = 0; i < 256; i++) - if (ISUPPER (trans_table[i])) - trans_table[i] = TOLOWER (trans_table[i]); - translation_needed = 1; - } - - if (conversions_mask & C_EBCDIC) - { - translate_charset (ascii_to_ebcdic); - newline_character = ascii_to_ebcdic['\n']; - space_character = ascii_to_ebcdic[' ']; - } - else if (conversions_mask & C_IBM) - { - translate_charset (ascii_to_ibm); - newline_character = ascii_to_ibm['\n']; - space_character = ascii_to_ibm[' ']; - } -} - -/* Apply the character-set translations specified by the user - to the NREAD bytes in BUF. */ - -static void -translate_buffer (unsigned char *buf, size_t nread) -{ - unsigned char *cp; - size_t i; - - for (i = nread, cp = buf; i; i--, cp++) - *cp = trans_table[*cp]; -} - -/* If nonnzero, the last char from the previous call to `swab_buffer' - is saved in `saved_char'. */ -static int char_is_saved = 0; - -/* Odd char from previous call. */ -static unsigned char saved_char; - -/* Swap NREAD bytes in BUF, plus possibly an initial char from the - previous call. If NREAD is odd, save the last char for the - next call. Return the new start of the BUF buffer. */ - -static unsigned char * -swab_buffer (unsigned char *buf, size_t *nread) -{ - unsigned char *bufstart = buf; - register unsigned char *cp; - register int i; - - /* Is a char left from last time? */ - if (char_is_saved) - { - *--bufstart = saved_char; - (*nread)++; - char_is_saved = 0; - } - - if (*nread & 1) - { - /* An odd number of chars are in the buffer. */ - saved_char = bufstart[--*nread]; - char_is_saved = 1; - } - - /* Do the byte-swapping by moving every second character two - positions toward the end, working from the end of the buffer - toward the beginning. This way we only move half of the data. */ - - cp = bufstart + *nread; /* Start one char past the last. */ - for (i = *nread / 2; i; i--, cp -= 2) - *cp = *(cp - 2); - - return ++bufstart; -} - -/* Return nonzero iff the file referenced by FDESC is of a type for - which lseek's return value is known to be invalid on some systems. - Otherwise, return zero. - For example, return nonzero if FDESC references a character device - (on any system) because the lseek on many Linux systems incorrectly - returns an offset implying it succeeds for tape devices, even though - the function fails to perform the requested operation. In that case, - lseek should return nonzero and set errno. */ - -static int -buggy_lseek_support (int fdesc) -{ - /* We have to resort to this because on some systems, lseek doesn't work - on some special files but doesn't return an error, either. - In particular, the Linux tape drivers are a problem. - For example, when I did the following using dd-4.0y or earlier on a - Linux-2.2.17 system with an Exabyte SCSI tape drive: - - dev=/dev/nst0 - reset='mt -f $dev rewind; mt -f $dev fsf 1' - eval $reset; dd if=$dev bs=32k of=out1 - eval $reset; dd if=$dev bs=32k of=out2 skip=1 - - the resulting files, out1 and out2, would compare equal. */ - - struct stat stats; - - return (fstat (fdesc, &stats) == 0 - && (S_ISCHR (stats.st_mode))); -} - -/* Throw away RECORDS blocks of BLOCKSIZE 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 necessary. RECORDS must be - nonzero. */ - -static void -skip (int fdesc, char *file, uintmax_t records, size_t blocksize, - unsigned char *buf) -{ - off_t offset = records * blocksize; - - /* Try lseek and if an error indicates it was an inappropriate - operation, fall back on using read. Some broken versions of - lseek may return zero, so count that as an error too as a valid - zero return is not possible here. */ - - if (offset / blocksize != records - || buggy_lseek_support (fdesc) - || lseek (fdesc, offset, SEEK_CUR) <= 0) - { - while (records--) - { - ssize_t nread = safe_read (fdesc, buf, blocksize); - if (nread < 0) - { - error (0, errno, _("reading %s"), quote (file)); - quit (1); - } - /* POSIX doesn't say what to do when dd detects it has been - asked to skip past EOF, so I assume it's non-fatal. - FIXME: maybe give a warning. */ - if (nread == 0) - break; - } - } -} - -/* Copy NREAD bytes of BUF, with no conversions. */ - -static void -copy_simple (unsigned char const *buf, int nread) -{ - int nfree; /* Number of unused bytes in `obuf'. */ - const unsigned char *start = buf; /* First uncopied char in BUF. */ - - do - { - nfree = output_blocksize - oc; - if (nfree > nread) - nfree = nread; - - memcpy ((char *) (obuf + oc), (char *) start, nfree); - - nread -= nfree; /* Update the number of bytes left to copy. */ - start += nfree; - oc += nfree; - if (oc >= output_blocksize) - write_output (); - } - while (nread > 0); -} - -/* Copy NREAD bytes of BUF, doing conv=block - (pad newline-terminated records to `conversion_blocksize', - replacing the newline with trailing spaces). */ - -static void -copy_with_block (unsigned char const *buf, size_t nread) -{ - size_t i; - - for (i = nread; i; i--, buf++) - { - if (*buf == newline_character) - { - if (col < conversion_blocksize) - { - size_t j; - for (j = col; j < conversion_blocksize; j++) - output_char (space_character); - } - col = 0; - } - else - { - if (col == conversion_blocksize) - r_truncate++; - else if (col < conversion_blocksize) - output_char (*buf); - col++; - } - } -} - -/* Copy NREAD bytes of BUF, doing conv=unblock - (replace trailing spaces in `conversion_blocksize'-sized records - with a newline). */ - -static void -copy_with_unblock (unsigned char const *buf, size_t nread) -{ - size_t i; - unsigned char c; - static int pending_spaces = 0; - - for (i = 0; i < nread; i++) - { - c = buf[i]; - - if (col++ >= conversion_blocksize) - { - col = pending_spaces = 0; /* Wipe out any pending spaces. */ - i--; /* Push the char back; get it later. */ - output_char (newline_character); - } - else if (c == space_character) - pending_spaces++; - else - { - /* `c' is the character after a run of spaces that were not - at the end of the conversion buffer. Output them. */ - while (pending_spaces) - { - output_char (space_character); - --pending_spaces; - } - output_char (c); - } - } -} - -/* The main loop. */ - -static int -dd_copy (void) -{ - unsigned char *ibuf, *bufstart; /* Input buffer. */ - unsigned char *real_buf; /* real buffer address before alignment */ - unsigned char *real_obuf; - ssize_t nread; /* Bytes read in the current block. */ - int exit_status = 0; - size_t page_size = getpagesize (); - size_t n_bytes_read; - - /* Leave at least one extra byte at the beginning and end of `ibuf' - for conv=swab, but keep the buffer address even. But some peculiar - device drivers work only with word-aligned buffers, so leave an - extra two bytes. */ - - /* Some devices require alignment on a sector or page boundary - (e.g. character disk devices). Align the input buffer to a - page boundary to cover all bases. Note that due to the swab - algorithm, we must have at least one byte in the page before - the input buffer; thus we allocate 2 pages of slop in the - real buffer. 8k above the blocksize shouldn't bother anyone. - - The page alignment is necessary on any linux system that supports - either the SGI raw I/O patch or Steven Tweedies raw I/O patch. - It is necessary when accessing raw (i.e. character special) disk - devices on Unixware or other SVR4-derived system. */ - - real_buf = (unsigned char *) xmalloc (input_blocksize - + 2 * SWAB_ALIGN_OFFSET - + 2 * page_size - 1); - 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 = (unsigned char *) xmalloc (output_blocksize + page_size - 1); - obuf = PTR_ALIGN (real_obuf, page_size); - } - else - { - real_obuf = NULL; - obuf = ibuf; - } - - if (skip_records != 0) - skip (STDIN_FILENO, input_file, skip_records, input_blocksize, ibuf); - - if (seek_records != 0) - { - /* FIXME: this loses for - % ./dd if=dd seek=1 |: - ./dd: standard output: Bad file descriptor - 0+0 records in - 0+0 records out - */ - - skip (STDOUT_FILENO, output_file, seek_records, output_blocksize, obuf); - } - - if (max_records == 0) - quit (exit_status); - - while (1) - { - if (r_partial + r_full >= max_records) - break; - - /* Zero the buffer before reading, so that if we get a read error, - whatever data we are able to read is followed by zeros. - This minimizes data loss. */ - if ((conversions_mask & C_SYNC) && (conversions_mask & C_NOERROR)) - memset ((char *) ibuf, - (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0', - input_blocksize); - - nread = safe_read (STDIN_FILENO, ibuf, input_blocksize); - - if (nread == 0) - break; /* EOF. */ - - if (nread < 0) - { - error (0, errno, _("reading %s"), quote (input_file)); - if (conversions_mask & C_NOERROR) - { - print_stats (); - /* Seek past the bad block if possible. */ - lseek (STDIN_FILENO, (off_t) input_blocksize, SEEK_CUR); - if (conversions_mask & C_SYNC) - /* Replace the missing input with null bytes and - proceed normally. */ - nread = 0; - else - continue; - } - else - { - /* Write any partial block. */ - exit_status = 2; - break; - } - } - - n_bytes_read = nread; - - if (n_bytes_read < input_blocksize) - { - r_partial++; - if (conversions_mask & C_SYNC) - { - if (!(conversions_mask & C_NOERROR)) - /* If C_NOERROR, we zeroed the block before reading. */ - memset ((char *) (ibuf + n_bytes_read), - (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0', - input_blocksize - n_bytes_read); - n_bytes_read = input_blocksize; - } - } - else - r_full++; - - if (ibuf == obuf) /* If not C_TWOBUFS. */ - { - int nwritten = full_write (STDOUT_FILENO, obuf, n_bytes_read); - if (nwritten < 0) - { - error (0, errno, _("writing %s"), quote (output_file)); - quit (1); - } - else if (n_bytes_read == input_blocksize) - w_full++; - else - w_partial++; - continue; - } - - /* Do any translations on the whole buffer at once. */ - - if (translation_needed) - translate_buffer (ibuf, n_bytes_read); - - if (conversions_mask & C_SWAB) - bufstart = swab_buffer (ibuf, &n_bytes_read); - else - bufstart = ibuf; - - if (conversions_mask & C_BLOCK) - copy_with_block (bufstart, n_bytes_read); - else if (conversions_mask & C_UNBLOCK) - copy_with_unblock (bufstart, n_bytes_read); - else - copy_simple (bufstart, n_bytes_read); - } - - /* If we have a char left as a result of conv=swab, output it. */ - if (char_is_saved) - { - if (conversions_mask & C_BLOCK) - copy_with_block (&saved_char, 1); - else if (conversions_mask & C_UNBLOCK) - copy_with_unblock (&saved_char, 1); - else - output_char (saved_char); - } - - if ((conversions_mask & C_BLOCK) && col > 0) - { - /* If the final input line didn't end with a '\n', pad - the output block to `conversion_blocksize' chars. */ - unsigned int i; - for (i = col; i < conversion_blocksize; i++) - output_char (space_character); - } - - if ((conversions_mask & C_UNBLOCK) && col == conversion_blocksize) - /* Add a final '\n' if there are exactly `conversion_blocksize' - characters in the final record. */ - output_char (newline_character); - - /* Write out the last block. */ - if (oc != 0) - { - int nwritten = full_write (STDOUT_FILENO, obuf, oc); - if (nwritten > 0) - w_partial++; - if (nwritten < 0) - { - error (0, errno, _("writing %s"), quote (output_file)); - quit (1); - } - } - - free (real_buf); - if (real_obuf) - free (real_obuf); - - return exit_status; -} - -/* This is gross, but necessary, because of the way close_stdout - works and because this program closes STDOUT_FILENO directly. */ -static void (*closeout_func) (void) = close_stdout; - -static void -close_stdout_wrapper (void) -{ - if (closeout_func) - (*closeout_func) (); -} - -int -main (int argc, char **argv) -{ - int i; - int exit_status; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - /* Arrange to close stdout if parse_long_options exits. */ - atexit (close_stdout_wrapper); - - parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, - AUTHORS, usage); - - /* Don't close stdout on exit from here on. */ - closeout_func = NULL; - - /* Initialize translation table to identity translation. */ - for (i = 0; i < 256; i++) - trans_table[i] = i; - - /* Decode arguments. */ - scanargs (argc, argv); - - apply_translations (); - - if (input_file != NULL) - { - if (open_fd (STDIN_FILENO, input_file, O_RDONLY, 0) < 0) - error (1, errno, _("opening %s"), quote (input_file)); - } - else - input_file = _("standard input"); - - if (output_file != NULL) - { - mode_t perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - int opts - = (O_CREAT - | (seek_records || (conversions_mask & C_NOTRUNC) ? 0 : O_TRUNC)); - - /* Open the output file with *read* access only if we might - need to read to satisfy a `seek=' request. If we can't read - the file, go ahead with write-only access; it might work. */ - if ((! seek_records - || open_fd (STDOUT_FILENO, output_file, O_RDWR | opts, perms) < 0) - && open_fd (STDOUT_FILENO, output_file, O_WRONLY | opts, perms) < 0) - error (1, errno, _("opening %s"), quote (output_file)); - -#if HAVE_FTRUNCATE - if (seek_records != 0 && !(conversions_mask & C_NOTRUNC)) - { - struct stat stdout_stat; - off_t o = seek_records * output_blocksize; - if (o / output_blocksize != seek_records) - error (1, 0, _("file offset out of range")); - - if (fstat (STDOUT_FILENO, &stdout_stat) != 0) - error (1, errno, _("cannot fstat %s"), quote (output_file)); - - /* Complain only when ftruncate fails on a regular file, a - directory, or a shared memory object, as the 2000-08 - POSIX draft specifies ftruncate's behavior only for these - file types. For example, do not complain when Linux 2.4 - ftruncate fails on /dev/fd0. */ - if (ftruncate (STDOUT_FILENO, o) != 0 - && (S_ISREG (stdout_stat.st_mode) - || S_ISDIR (stdout_stat.st_mode) - || S_TYPEISSHM (&stdout_stat))) - { - char buf[LONGEST_HUMAN_READABLE + 1]; - error (1, errno, _("advancing past %s bytes in output file %s"), - human_readable (o, buf, 1, 1), - quote (output_file)); - } - } -#endif - } - else - { - output_file = _("standard output"); - } - - install_handler (SIGINT, interrupt_handler); - install_handler (SIGQUIT, interrupt_handler); - install_handler (SIGPIPE, interrupt_handler); - install_handler (SIGINFO, siginfo_handler); - - exit_status = dd_copy (); - - quit (exit_status); -} diff --git a/src/apps/bin/gnu/df.c b/src/apps/bin/gnu/df.c deleted file mode 100644 index ad49e4244a..0000000000 --- a/src/apps/bin/gnu/df.c +++ /dev/null @@ -1,952 +0,0 @@ -/* df - summarize free disk space - Copyright (C) 91, 1995-2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by David MacKenzie . - --human-readable and --megabyte options added by lm@sgi.com. - --si and large file support added by eggert@twinsun.com. */ - -#ifdef _AIX - #pragma alloca -#endif - -#include -#if HAVE_INTTYPES_H -# include -#endif -#include -#include -#include -#include - -#include "system.h" -#include "dirname.h" -#include "error.h" -#include "fsusage.h" -#include "human.h" -#include "mountlist.h" -#include "path-concat.h" -#include "quote.h" -#include "save-cwd.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "df" - -#define AUTHORS \ - "Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert" - -void strip_trailing_slashes (); -char *xgetcwd (); - -/* Name this program was run with. */ -char *program_name; - -/* If nonzero, show inode information. */ -static int inode_format; - -/* If nonzero, show even filesystems with zero size or - uninteresting types. */ -static int show_all_fs; - -/* If nonzero, show only local filesystems. */ -static int show_local_fs; - -/* If nonzero, output data for each filesystem corresponding to a - command line argument -- even if it's a dummy (automounter) entry. */ -static int show_listed_fs; - -/* If positive, the units to use when printing sizes; - if negative, the human-readable base. */ -static int output_block_size; - -/* If nonzero, use the POSIX output format. */ -static int posix_format; - -/* If nonzero, invoke the `sync' system call before getting any usage data. - Using this option can make df very slow, especially with many or very - busy disks. Note that this may make a difference on some systems -- - SunOs4.1.3, for one. It is *not* necessary on Linux. */ -static int require_sync = 0; - -/* Nonzero if errors have occurred. */ -static int exit_status; - -/* A filesystem type to display. */ - -struct fs_type_list -{ - char *fs_name; - struct fs_type_list *fs_next; -}; - -/* Linked list of filesystem types to display. - If `fs_select_list' is NULL, list all types. - This table is generated dynamically from command-line options, - rather than hardcoding into the program what it thinks are the - valid filesystem types; let the user specify any filesystem type - they want to, and if there are any filesystems of that type, they - will be shown. - - Some filesystem types: - 4.2 4.3 ufs nfs swap ignore io vm efs dbg */ - -static struct fs_type_list *fs_select_list; - -/* Linked list of filesystem types to omit. - If the list is empty, don't exclude any types. */ - -static struct fs_type_list *fs_exclude_list; - -/* Linked list of mounted filesystems. */ -static struct mount_entry *mount_list; - -/* If nonzero, print filesystem type as well. */ -static int print_type; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - SYNC_OPTION = CHAR_MAX + 1, - NO_SYNC_OPTION, - BLOCK_SIZE_OPTION -}; - -static struct option const long_options[] = -{ - {"all", no_argument, NULL, 'a'}, - {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, - {"inodes", no_argument, NULL, 'i'}, - {"human-readable", no_argument, NULL, 'h'}, - {"si", no_argument, NULL, 'H'}, - {"kilobytes", no_argument, NULL, 'k'}, - {"local", no_argument, NULL, 'l'}, - {"megabytes", no_argument, NULL, 'm'}, - {"portability", no_argument, NULL, 'P'}, - {"print-type", no_argument, NULL, 'T'}, - {"sync", no_argument, NULL, SYNC_OPTION}, - {"no-sync", no_argument, NULL, NO_SYNC_OPTION}, - {"type", required_argument, NULL, 't'}, - {"exclude-type", required_argument, NULL, 'x'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -static void -print_header (void) -{ - printf (_("Filesystem ")); - - if (print_type) - printf (_(" Type")); - else - printf (" "); - - if (inode_format) - printf (_(" Inodes IUsed IFree IUse%%")); - else if (output_block_size < 0) - printf (_(" Size Used Avail Use%%")); - else if (posix_format) - printf (_(" %4d-blocks Used Available Capacity"), output_block_size); - else - { - char buf[LONGEST_HUMAN_READABLE + 1]; - char *p = human_readable (output_block_size, buf, 1, -1024); - - /* Replace e.g. "1.0k" by "1k". */ - size_t plen = strlen (p); - if (3 <= plen && strncmp (p + plen - 3, ".0", 2) == 0) - strcpy (p + plen - 3, p + plen - 1); - - printf (_(" %4s-blocks Used Available Use%%"), p); - } - - printf (_(" Mounted on\n")); -} - -/* If FSTYPE is a type of filesystem that should be listed, - return nonzero, else zero. */ - -static int -selected_fstype (const char *fstype) -{ - const struct fs_type_list *fsp; - - if (fs_select_list == NULL || fstype == NULL) - return 1; - for (fsp = fs_select_list; fsp; fsp = fsp->fs_next) - if (STREQ (fstype, fsp->fs_name)) - return 1; - return 0; -} - -/* If FSTYPE is a type of filesystem that should be omitted, - return nonzero, else zero. */ - -static int -excluded_fstype (const char *fstype) -{ - const struct fs_type_list *fsp; - - if (fs_exclude_list == NULL || fstype == NULL) - return 0; - for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next) - if (STREQ (fstype, fsp->fs_name)) - return 1; - return 0; -} - -/* Like human_readable_inexact, except return "-" if the argument is -1, - and if NEGATIVE is 1 then N represents a negative number, expressed - in two's complement. */ -static char const * -df_readable (int negative, uintmax_t n, char *buf, - int from_block_size, int t_output_block_size, - enum human_inexact_style s) -{ - if (n == -1) - return "-"; - else - { - char *p = human_readable_inexact (negative ? - n : n, - buf + negative, from_block_size, - t_output_block_size, - negative ? - s : s); - if (negative) - *--p = '-'; - return p; - } -} - -/* Display a space listing for the disk device with absolute path DISK. - If MOUNT_POINT is non-NULL, it is the path of the root of the - filesystem on DISK. - If FSTYPE is non-NULL, it is the type of the filesystem on DISK. - If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may - not be able to produce statistics in this case. - ME_DUMMY and ME_REMOTE are the mount entry flags. */ - -static void -show_dev (const char *disk, const char *mount_point, const char *fstype, - int me_dummy, int me_remote) -{ - struct fs_usage fsu; - const char *stat_file; - char buf[3][LONGEST_HUMAN_READABLE + 2]; - int width; - int use_width; - int input_units; - int output_units; - uintmax_t total; - uintmax_t available; - int negate_available; - uintmax_t available_to_root; - uintmax_t used; - int negate_used; - double pct = -1; - - if (me_remote && show_local_fs) - return; - - if (me_dummy && show_all_fs == 0 && !show_listed_fs) - return; - - if (!selected_fstype (fstype) || excluded_fstype (fstype)) - return; - - /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this - program reports on the filesystem that the special file is on. - It would be better to report on the unmounted filesystem, - but statfs doesn't do that on most systems. */ - stat_file = mount_point ? mount_point : disk; - - if (get_fs_usage (stat_file, disk, &fsu)) - { - error (0, errno, "%s", quote (stat_file)); - exit_status = 1; - return; - } - - if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs) - return; - - if (! disk) - disk = "-"; /* unknown */ - if (! fstype) - fstype = "-"; /* unknown */ - - /* df.c reserved 5 positions for fstype, - but that does not suffice for type iso9660 */ - if (print_type) - { - int disk_name_len = (int) strlen (disk); - int fstype_len = (int) strlen (fstype); - if (disk_name_len + fstype_len + 2 < 20) - printf ("%s%*s ", disk, 18 - disk_name_len, fstype); - else if (!posix_format) - printf ("%s\n%18s ", disk, fstype); - else - printf ("%s %s", disk, fstype); - } - else - { - if ((int) strlen (disk) > 20 && !posix_format) - printf ("%s\n%20s", disk, ""); - else - printf ("%-20s", disk); - } - - if (inode_format) - { - width = 7; - use_width = 5; - input_units = 1; - output_units = output_block_size < 0 ? output_block_size : 1; - total = fsu.fsu_files; - available = fsu.fsu_ffree; - negate_available = 0; - available_to_root = available; - } - else - { - width = output_block_size < 0 ? 5 : 9; - use_width = posix_format ? 8 : 4; - input_units = fsu.fsu_blocksize; - output_units = output_block_size; - total = fsu.fsu_blocks; - available = fsu.fsu_bavail; - negate_available = fsu.fsu_bavail_top_bit_set; - available_to_root = fsu.fsu_bfree; - } - - used = -1; - negate_used = 0; - if (total != -1 && available_to_root != -1) - { - used = total - available_to_root; - if (total < available_to_root) - { - negate_used = 1; - used = - used; - } - } - - printf (" %*s %*s %*s ", - width, df_readable (0, total, - buf[0], input_units, output_units, - (posix_format - ? human_ceiling - : human_round_to_even)), - width, df_readable (negate_used, used, - buf[1], input_units, output_units, - human_ceiling), - width, df_readable (negate_available, available, - buf[2], input_units, output_units, - posix_format ? human_ceiling : human_floor)); - - if (used == -1 || available == -1) - ; - else if (!negate_used - && used <= TYPE_MAXIMUM (uintmax_t) / 100 - && used + available != 0 - && (used + available < used) == negate_available) - { - uintmax_t u100 = used * 100; - uintmax_t nonroot_total = used + available; - pct = u100 / nonroot_total + (u100 % nonroot_total != 0); - } - else - { - /* The calculation cannot be done easily with integer - arithmetic. Fall back on floating point. This can suffer - from minor rounding errors, but doing it exactly requires - multiple precision arithmetic, and it's not worth the - aggravation. */ - double u = negate_used ? - (double) - used : used; - double a = negate_available ? - (double) - available : available; - double nonroot_total = u + a; - if (nonroot_total) - { - double ipct; - pct = u * 100 / nonroot_total; - ipct = (long) pct; - - /* Like `pct = ceil (dpct);', but avoid ceil so that - the math library needn't be linked. */ - if (ipct - 1 < pct && pct <= ipct + 1) - pct = ipct + (ipct < pct); - } - } - - if (0 <= pct) - printf ("%*.0f%%", use_width - 1, pct); - else - printf ("%*s", use_width, "- "); - - if (mount_point) - { -#ifdef HIDE_AUTOMOUNT_PREFIX - /* Don't print the first directory name in MOUNT_POINT if it's an - artifact of an automounter. This is a bit too aggressive to be - the default. */ - if (strncmp ("/auto/", mount_point, 6) == 0) - mount_point += 5; - else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0) - mount_point += 8; -#endif - printf (" %s", mount_point); - } - putchar ('\n'); -} - -/* Identify the directory, if any, that device - DISK is mounted on, and show its disk usage. */ - -static void -show_disk (const char *disk) -{ - struct mount_entry *me; - - for (me = mount_list; me; me = me->me_next) - if (STREQ (disk, me->me_devname)) - { - show_dev (me->me_devname, me->me_mountdir, me->me_type, - me->me_dummy, me->me_remote); - return; - } - /* No filesystem is mounted on DISK. */ - show_dev (disk, (char *) NULL, (char *) NULL, 0, 0); -} - -/* Return the root mountpoint of the filesystem on which FILE exists, in - malloced storage. FILE_STAT should be the result of stating FILE. */ -static char * -find_mount_point (const char *file, const struct stat *file_stat) -{ - struct saved_cwd cwd; - struct stat last_stat; - char *mp = 0; /* The malloced mount point path. */ - - if (save_cwd (&cwd)) - return NULL; - - if (S_ISDIR (file_stat->st_mode)) - /* FILE is a directory, so just chdir there directly. */ - { - last_stat = *file_stat; - if (chdir (file) < 0) - return NULL; - } - else - /* FILE is some other kind of file, we need to use its directory. */ - { - int rv; - char *tmp = xstrdup (file); - char *dir; - - strip_trailing_slashes (tmp); - dir = dir_name (tmp); - free (tmp); - rv = chdir (dir); - free (dir); - - if (rv < 0) - return NULL; - - if (stat (".", &last_stat) < 0) - goto done; - } - - /* Now walk up FILE's parents until we find another filesystem or /, - chdiring as we go. LAST_STAT holds stat information for the last place - we visited. */ - for (;;) - { - struct stat st; - if (stat ("..", &st) < 0) - goto done; - if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino) - /* cwd is the mount point. */ - break; - if (chdir ("..") < 0) - goto done; - last_stat = st; - } - - /* Finally reached a mount point, see what it's called. */ - mp = xgetcwd (); - -done: - /* Restore the original cwd. */ - { - int save_errno = errno; - if (restore_cwd (&cwd, 0, mp)) - exit (1); /* We're scrod. */ - free_cwd (&cwd); - errno = save_errno; - } - - return mp; -} - -/* Figure out which device file or directory POINT is mounted on - and show its disk usage. - STATP is the results of `stat' on POINT. */ -static void -show_point (const char *point, const struct stat *statp) -{ - struct stat disk_stats; - struct mount_entry *me; - struct mount_entry *matching_dummy = NULL; - char *needs_freeing = NULL; - - /* If POINT is an absolute path name, see if we can find the - mount point without performing any extra stat calls at all. */ - if (*point == '/') - { - for (me = mount_list; me; me = me->me_next) - { - if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs")) - { - /* Prefer non-dummy entries. */ - if (! me->me_dummy) - goto show_me; - matching_dummy = me; - } - } - - if (matching_dummy) - goto show_matching_dummy; - } - -#if HAVE_REALPATH || HAVE_RESOLVEPATH - /* Calculate the real absolute path for POINT, and use that to find - the mount point. This avoids statting unavailable mount points, - which can hang df. */ - { - char const *abspoint = point; - char *resolved; - ssize_t resolved_len; - struct mount_entry *best_match = NULL; - -# if HAVE_RESOLVEPATH - /* All known hosts with resolvepath (e.g. Solaris 7) don't turn - relative names into absolute ones, so prepend the working - directory if the path is not absolute. */ - - if (*point != '/') - { - static char const *wd; - - if (! wd) - { - struct stat pwd_stats; - struct stat dot_stats; - - /* Use PWD if it is correct; this is usually cheaper than - xgetcwd. */ - wd = getenv ("PWD"); - if (! (wd - && stat (wd, &pwd_stats) == 0 - && stat (".", &dot_stats) == 0 - && SAME_INODE (pwd_stats, dot_stats))) - wd = xgetcwd (); - } - - if (wd) - { - needs_freeing = path_concat (wd, point, NULL); - if (needs_freeing) - abspoint = needs_freeing; - } - } -# endif - -# if HAVE_RESOLVEPATH - { - size_t resolved_size = strlen (abspoint); - do - { - resolved_size = 2 * resolved_size + 1; - resolved = alloca (resolved_size); - resolved_len = resolvepath (abspoint, resolved, resolved_size); - } - while (resolved_len == resolved_size); - } -# else - resolved = alloca (PATH_MAX + 1); - resolved = (char *) realpath (abspoint, resolved); - resolved_len = resolved ? strlen (resolved) : -1; -# endif - - if (1 <= resolved_len && resolved[0] == '/') - { - size_t best_match_len = 0; - - for (me = mount_list; me; me = me->me_next) - if (! 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] == '/') - && strncmp (me->me_mountdir, resolved, len) == 0))) - { - best_match = me; - best_match_len = len; - } - } - } - - if (best_match && !STREQ (best_match->me_type, "lofs") - && stat (best_match->me_mountdir, &disk_stats) == 0 - && disk_stats.st_dev == statp->st_dev) - { - me = best_match; - goto show_me; - } - } -#endif - - for (me = mount_list; me; me = me->me_next) - { - if (me->me_dev == (dev_t) -1) - { - if (stat (me->me_mountdir, &disk_stats) == 0) - me->me_dev = disk_stats.st_dev; - else - { - error (0, errno, "%s", quote (me->me_mountdir)); - exit_status = 1; - /* So we won't try and fail repeatedly. */ - me->me_dev = (dev_t) -2; - } - } - - if (statp->st_dev == me->me_dev) - { - /* Skip bogus mtab entries. */ - if (stat (me->me_mountdir, &disk_stats) != 0 - || disk_stats.st_dev != me->me_dev) - { - me->me_dev = (dev_t) -2; - continue; - } - - /* Prefer non-dummy entries. */ - if (! me->me_dummy) - goto show_me; - matching_dummy = me; - } - } - - if (matching_dummy) - goto show_matching_dummy; - - /* We couldn't find the mount entry corresponding to POINT. Go ahead and - print as much info as we can; methods that require the device to be - present will fail at a later point. */ - { - /* Find the actual mount point. */ - char *mp = find_mount_point (point, statp); - if (mp) - { - show_dev (0, mp, 0, 0, 0); - free (mp); - } - else - error (0, errno, "%s", quote (point)); - } - - goto free_then_return; - - show_matching_dummy: - me = matching_dummy; - show_me: - show_dev (me->me_devname, me->me_mountdir, me->me_type, me->me_dummy, - me->me_remote); - free_then_return: - if (needs_freeing) - free (needs_freeing); -} - -/* Determine what kind of node PATH is and show the disk usage - for it. STATP is the results of `stat' on PATH. */ - -static void -show_entry (const char *path, const struct stat *statp) -{ - if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode)) - show_disk (path); - else - show_point (path, statp); -} - -/* Show all mounted filesystems, except perhaps those that are of - an unselected type or are empty. */ - -static void -show_all_entries (void) -{ - struct mount_entry *me; - - for (me = mount_list; me; me = me->me_next) - show_dev (me->me_devname, me->me_mountdir, me->me_type, - me->me_dummy, me->me_remote); -} - -/* Add FSTYPE to the list of filesystem types to display. */ - -static void -add_fs_type (const char *fstype) -{ - struct fs_type_list *fsp; - - fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list)); - fsp->fs_name = (char *) fstype; - fsp->fs_next = fs_select_list; - fs_select_list = fsp; -} - -/* Add FSTYPE to the list of filesystem types to be omitted. */ - -static void -add_excluded_fs_type (const char *fstype) -{ - struct fs_type_list *fsp; - - fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list)); - fsp->fs_name = (char *) fstype; - fsp->fs_next = fs_exclude_list; - fs_exclude_list = fsp; -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); - printf (_("\ -Show information about the filesystem on which each FILE resides,\n\ -or all filesystems by default.\n\ -\n\ - -a, --all include filesystems having 0 blocks\n\ - --block-size=SIZE use SIZE-byte blocks\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\ - -i, --inodes list inode information instead of block usage\n\ - -k, --kilobytes like --block-size=1024\n\ - -l, --local limit listing to local filesystems\n\ - -m, --megabytes like --block-size=1048576\n\ - --no-sync do not invoke sync before getting usage info (default)\n\ - -P, --portability use the POSIX output format\n\ - --sync invoke sync before getting usage info\n\ - -t, --type=TYPE limit listing to filesystems of type TYPE\n\ - -T, --print-type print filesystem type\n\ - -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\ - -v (ignored)\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - int c; - struct stat *stats IF_LINT (= 0); - int n_valid_args = 0; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - fs_select_list = NULL; - fs_exclude_list = NULL; - inode_format = 0; - show_all_fs = 0; - show_listed_fs = 0; - - human_block_size (getenv ("DF_BLOCK_SIZE"), 0, &output_block_size); - - print_type = 0; - posix_format = 0; - exit_status = 0; - - while ((c = getopt_long (argc, argv, "aiF:hHklmPTt:vx:", long_options, NULL)) - != -1) - { - switch (c) - { - case 0: /* Long option. */ - break; - case 'a': - show_all_fs = 1; - break; - case 'i': - inode_format = 1; - break; - case 'h': - output_block_size = -1024; - break; - case 'H': - output_block_size = -1000; - break; - case 'k': - output_block_size = 1024; - break; - case 'l': - show_local_fs = 1; - break; - case 'm': - output_block_size = 1024 * 1024; - break; - case 'T': - print_type = 1; - break; - case 'P': - posix_format = 1; - break; - case SYNC_OPTION: - require_sync = 1; - break; - case NO_SYNC_OPTION: - require_sync = 0; - break; - - case BLOCK_SIZE_OPTION: - human_block_size (optarg, 1, &output_block_size); - break; - - case 'F': - /* Accept -F as a synonym for -t for compatibility with Solaris. */ - case 't': - add_fs_type (optarg); - break; - - case 'v': /* For SysV compatibility. */ - /* ignore */ - break; - case 'x': - add_excluded_fs_type (optarg); - break; - - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - - default: - usage (1); - } - } - - /* Fail if the same file system type was both selected and excluded. */ - { - int match = 0; - struct fs_type_list *fs_incl; - for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next) - { - struct fs_type_list *fs_excl; - for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next) - { - if (STREQ (fs_incl->fs_name, fs_excl->fs_name)) - { - error (0, 0, - _("file system type %s both selected and excluded"), - quote (fs_incl->fs_name)); - match = 1; - break; - } - } - } - if (match) - exit (1); - } - - { - int i; - - /* stat all the given entries to make sure they get automounted, - if necessary, before reading the filesystem table. */ - stats = (struct stat *) - xmalloc ((argc - optind) * sizeof (struct stat)); - for (i = optind; i < argc; ++i) - { - if (stat (argv[i], &stats[i - optind])) - { - error (0, errno, "%s", quote (argv[i])); - exit_status = 1; - argv[i] = NULL; - } - else - { - ++n_valid_args; - } - } - } - - mount_list = - read_filesystem_list ((fs_select_list != NULL - || fs_exclude_list != NULL - || print_type - || show_local_fs)); - - if (mount_list == NULL) - { - /* Couldn't read the table of mounted filesystems. - Fail if df was invoked with no file name arguments; - Otherwise, merely give a warning and proceed. */ - const char *warning = (optind == argc ? "" : _("Warning: ")); - int status = (optind == argc ? 1 : 0); - error (status, errno, - _("%scannot read table of mounted filesystems"), warning); - } - - if (require_sync) - sync (); - - if (optind == argc) - { - print_header (); - show_all_entries (); - } - else - { - int i; - - /* Display explicitly requested empty filesystems. */ - show_listed_fs = 1; - - if (n_valid_args > 0) - print_header (); - - for (i = optind; i < argc; ++i) - if (argv[i]) - show_entry (argv[i], &stats[i - optind]); - } - - exit (exit_status); -} diff --git a/src/apps/bin/gnu/du.c b/src/apps/bin/gnu/du.c deleted file mode 100644 index ab47a620f9..0000000000 --- a/src/apps/bin/gnu/du.c +++ /dev/null @@ -1,794 +0,0 @@ -/* du -- summarize disk usage - Copyright (C) 88, 89, 90, 91, 1995-2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Differences from the Unix du: - * Doesn't simply ignore the names of regular files given as arguments - when -a is given. - * Additional options: - -l Count the size of all files, even if they have appeared - already in another hard link. - -x Do not cross file-system boundaries during the recursion. - -c Write a grand total of all of the arguments after all - arguments have been processed. This can be used to find - out the disk usage of a directory, with some files excluded. - -h Print sizes in human readable format (1k 234M 2G, etc). - -H Similar, but use powers of 1000 not 1024. - -k Print sizes in kilobytes. - -m Print sizes in megabytes. - -b Print sizes in bytes. - -S Count the size of each directory separately, not including - the sizes of subdirectories. - -D Dereference only symbolic links given on the command line. - -L Dereference all symbolic links. - --exclude=PAT Exclude files that match PAT. - -X FILE Exclude files that match patterns taken from FILE. - - By tege@sics.se, Torbjorn Granlund, - and djm@ai.mit.edu, David MacKenzie. - Variable blocks added by lm@sgi.com and eggert@twinsun.com. -*/ - -#include -#if HAVE_INTTYPES_H -# include -#endif -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "exclude.h" -#include "human.h" -#include "quote.h" -#include "save-cwd.h" -#include "savedir.h" -#include "xstrtol.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "du" - -#define AUTHORS \ - "Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert" - -/* Initial number of entries in each hash table entry's table of inodes. */ -#define INITIAL_HASH_MODULE 100 - -/* Initial number of entries in the inode hash table. */ -#define INITIAL_ENTRY_TAB_SIZE 70 - -/* Initial size to allocate for `path'. */ -#define INITIAL_PATH_SIZE 100 - -/* Hash structure for inode and device numbers. The separate entry - structure makes it easier to rehash "in place". */ - -struct entry -{ - ino_t ino; - dev_t dev; - struct entry *coll_link; -}; - -/* Structure for a hash table for inode numbers. */ - -struct htab -{ - unsigned modulus; /* Size of the `hash' pointer vector. */ - struct entry *entry_tab; /* Pointer to dynamically growing vector. */ - unsigned entry_tab_size; /* Size of current `entry_tab' allocation. */ - unsigned first_free_entry; /* Index in `entry_tab'. */ - struct entry *hash[1]; /* Vector of pointers in `entry_tab'. */ -}; - - -/* Structure for dynamically resizable strings. */ - -struct String -{ - unsigned alloc; /* Size of allocation for the text. */ - unsigned length; /* Length of the text currently. */ - char *text; /* Pointer to the text. */ -}; -typedef struct String String; - -int stat (); -int lstat (); - -/* Name under which this program was invoked. */ -char *program_name; - -/* If nonzero, display counts for all files, not just directories. */ -static int opt_all = 0; - -/* If nonzero, count each hard link of files with multiple links. */ -static int opt_count_all = 0; - -/* If nonzero, do not cross file-system boundaries. */ -static int opt_one_file_system = 0; - -/* If nonzero, print a grand total at the end. */ -static int print_totals = 0; - -/* If nonzero, do not add sizes of subdirectories. */ -static int opt_separate_dirs = 0; - -/* If nonzero, dereference symlinks that are command line arguments. */ -static int opt_dereference_arguments = 0; - -/* Show the total for each directory (and file if --all) that is at - most MAX_DEPTH levels down from the root of the hierarchy. The root - is at level 0, so `du --max-depth=0' is equivalent to `du -s'. */ -static int max_depth = INT_MAX; - -/* If positive, the units to use when printing sizes; - if negative, the human-readable base. */ -static int output_block_size; - -/* Accumulated path for file or directory being processed. */ -static String *path; - -/* Pointer to hash structure, used by the hash routines. */ -static struct htab *htab; - -/* A pointer to either lstat or stat, depending on whether - dereferencing of all symbolic links is to be done. */ -static int (*xstat) (); - -/* The exit status to use if we don't get any fatal errors. */ -static int exit_status; - -/* File name patterns to exclude. */ -static struct exclude *exclude; - -/* Grand total size of all args, in units of ST_NBLOCKSIZE-byte blocks. */ -static uintmax_t tot_size = 0; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - EXCLUDE_OPTION = CHAR_MAX + 1, - BLOCK_SIZE_OPTION, - MAX_DEPTH_OPTION -}; - -static struct option const long_options[] = -{ - {"all", no_argument, NULL, 'a'}, - {"block-size", required_argument, 0, BLOCK_SIZE_OPTION}, - {"bytes", no_argument, NULL, 'b'}, - {"count-links", no_argument, NULL, 'l'}, - {"dereference", no_argument, NULL, 'L'}, - {"dereference-args", no_argument, NULL, 'D'}, - {"exclude", required_argument, 0, EXCLUDE_OPTION}, - {"exclude-from", required_argument, 0, 'X'}, - {"human-readable", no_argument, NULL, 'h'}, - {"si", no_argument, 0, 'H'}, - {"kilobytes", no_argument, NULL, 'k'}, - {"max-depth", required_argument, NULL, MAX_DEPTH_OPTION}, - {"megabytes", no_argument, NULL, 'm'}, - {"one-file-system", no_argument, NULL, 'x'}, - {"separate-dirs", no_argument, NULL, 'S'}, - {"summarize", no_argument, NULL, 's'}, - {"total", no_argument, NULL, 'c'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); - printf (_("\ -Summarize disk usage of each FILE, recursively for directories.\n\ -\n\ - -a, --all write counts for all files, not just directories\n\ - --block-size=SIZE use SIZE-byte blocks\n\ - -b, --bytes print size in bytes\n\ - -c, --total produce a grand total\n\ - -D, --dereference-args dereference PATHs when symbolic link\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\ - -k, --kilobytes like --block-size=1024\n\ - -l, --count-links count sizes many times if hard linked\n\ - -L, --dereference dereference all symbolic links\n\ - -m, --megabytes like --block-size=1048576\n\ - -S, --separate-dirs do not include size of subdirectories\n\ - -s, --summarize display only a total for each argument\n\ - -x, --one-file-system skip directories on different filesystems\n\ - -X FILE, --exclude-from=FILE Exclude files that match any pattern in FILE.\n\ - --exclude=PAT Exclude files that match PAT.\n\ - --max-depth=N print the total for a directory (or file, with --all)\n\ - only if it is N or fewer levels below the command\n\ - line argument; --max-depth=0 is the same as\n\ - --summarize\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -/* Initialize string S1 to hold SIZE characters. */ - -static void -str_init (String **s1, unsigned int size) -{ - String *s; - - s = (String *) xmalloc (sizeof (struct String)); - s->text = xmalloc (size + 1); - - s->alloc = size; - *s1 = s; -} - -static void -ensure_space (String *s, unsigned int size) -{ - if (s->alloc < size) - { - s->text = xrealloc (s->text, size + 1); - s->alloc = size; - } -} - -/* Assign the null-terminated C-string CSTR to S1. */ - -static void -str_copyc (String *s1, const char *cstr) -{ - unsigned l = strlen (cstr); - ensure_space (s1, l); - strcpy (s1->text, cstr); - s1->length = l; -} - -static void -str_concatc (String *s1, const char *cstr) -{ - unsigned l1 = s1->length; - unsigned l2 = strlen (cstr); - unsigned l = l1 + l2; - - ensure_space (s1, l); - strcpy (s1->text + l1, cstr); - s1->length = l; -} - -/* Truncate the string S1 to have length LENGTH. */ - -static void -str_trunc (String *s1, unsigned int length) -{ - if (s1->length > length) - { - s1->text[length] = 0; - s1->length = length; - } -} - -/* Print N_BLOCKS followed by STRING on a line. NBLOCKS is the number of - ST_NBLOCKSIZE-byte blocks; convert it to OUTPUT_BLOCK_SIZE units before - printing. If OUTPUT_BLOCK_SIZE is negative, use a human readable - notation instead. */ - -static void -print_size (uintmax_t n_blocks, const char *string) -{ - char buf[LONGEST_HUMAN_READABLE + 1]; - printf ("%s\t%s\n", - human_readable_inexact (n_blocks, buf, ST_NBLOCKSIZE, - output_block_size, human_ceiling), - string); - fflush (stdout); -} - -/* Reset the hash structure in the global variable `htab' to - contain no entries. */ - -static void -hash_reset (void) -{ - int i; - struct entry **p; - - htab->first_free_entry = 0; - - p = htab->hash; - for (i = htab->modulus; i > 0; i--) - *p++ = NULL; -} - -/* Allocate space for the hash structures, and set the global - variable `htab' to point to it. The initial hash module is specified in - MODULUS, and the number of entries are specified in ENTRY_TAB_SIZE. (The - hash structure will be rebuilt when ENTRY_TAB_SIZE entries have been - inserted, and MODULUS and ENTRY_TAB_SIZE in the global `htab' will be - doubled.) */ - -static void -hash_init (unsigned int modulus, unsigned int entry_tab_size) -{ - struct htab *htab_r; - - htab_r = (struct htab *) - xmalloc (sizeof (struct htab) + sizeof (struct entry *) * modulus); - - htab_r->entry_tab = (struct entry *) - xmalloc (sizeof (struct entry) * entry_tab_size); - - htab_r->modulus = modulus; - htab_r->entry_tab_size = entry_tab_size; - htab = htab_r; - - hash_reset (); -} - -/* Insert INO and DEV in the hash structure HTAB, if not - already present. Return zero if inserted and nonzero if it - already existed. */ - -static int -hash_insert2 (struct htab *ht, ino_t ino, dev_t dev) -{ - struct entry **hp, *ep2, *ep; - hp = &ht->hash[ino % ht->modulus]; - ep2 = *hp; - - /* Collision? */ - - if (ep2 != NULL) - { - ep = ep2; - - /* Search for an entry with the same data. */ - - do - { - if (ep->ino == ino && ep->dev == dev) - return 1; /* Found an entry with the same data. */ - ep = ep->coll_link; - } - while (ep != NULL); - - /* Did not find it. */ - - } - - ep = *hp = &ht->entry_tab[ht->first_free_entry++]; - ep->ino = ino; - ep->dev = dev; - ep->coll_link = ep2; /* `ep2' is NULL if no collision. */ - - return 0; -} - -/* Insert an item (inode INO and device DEV) in the hash - structure in the global variable `htab', if an entry with the same data - was not found already. Return zero if the item was inserted and nonzero - if it wasn't. */ - -static int -hash_insert (ino_t ino, dev_t dev) -{ - struct htab *htab_r = htab; /* Initially a copy of the global `htab'. */ - - if (htab_r->first_free_entry >= htab_r->entry_tab_size) - { - int i; - struct entry *ep; - unsigned modulus; - unsigned entry_tab_size; - - /* Increase the number of hash entries, and re-hash the data. - The method of shrimping and increasing is made to compactify - the heap. If twice as much data would be allocated - straightforwardly, we would never re-use a byte of memory. */ - - /* Let `htab' shrimp. Keep only the header, not the pointer vector. */ - - htab_r = (struct htab *) - xrealloc ((char *) htab_r, sizeof (struct htab)); - - modulus = 2 * htab_r->modulus; - entry_tab_size = 2 * htab_r->entry_tab_size; - - /* Increase the number of possible entries. */ - - htab_r->entry_tab = (struct entry *) - xrealloc ((char *) htab_r->entry_tab, - sizeof (struct entry) * entry_tab_size); - - /* Increase the size of htab again. */ - - htab_r = (struct htab *) - xrealloc ((char *) htab_r, - sizeof (struct htab) + sizeof (struct entry *) * modulus); - - htab_r->modulus = modulus; - htab_r->entry_tab_size = entry_tab_size; - htab = htab_r; - - i = htab_r->first_free_entry; - - /* Make the increased hash table empty. The entries are still - available in htab->entry_tab. */ - - hash_reset (); - - /* Go through the entries and install them in the pointer vector - htab->hash. The items are actually inserted in htab->entry_tab at - the position where they already are. The htab->coll_link need - however be updated. Could be made a little more efficient. */ - - for (ep = htab_r->entry_tab; i > 0; i--) - { - hash_insert2 (htab_r, ep->ino, ep->dev); - ep++; - } - } - - return hash_insert2 (htab_r, ino, dev); -} - -/* Restore the previous working directory or exit. - If CWD is null, simply call `chdir ("..")'. Otherwise, - use CWD and free it. CURR_DIR_NAME is the name of the current directory - and is used solely in failure diagnostics. */ - -static void -pop_dir (struct saved_cwd *cwd, const char *curr_dir_name) -{ - if (cwd) - { - if (restore_cwd (cwd, "..", curr_dir_name)) - exit (1); - free_cwd (cwd); - } - else if (chdir ("..") < 0) - { - error (1, errno, _("cannot change to `..' from directory %s"), - quote (curr_dir_name)); - } -} - -/* Print (if appropriate) the size (in units determined by `output_block_size') - of file or directory ENT. Return the size of ENT in units of 512-byte - blocks. TOP is one for external calls, zero for recursive calls. - LAST_DEV is the device that the parent directory of ENT is on. - DEPTH is the number of levels (in hierarchy) down from a command - line argument. Don't print if DEPTH > max_depth. - An important invariant is that when this function returns, the current - working directory is the same as when it was called. */ - -static uintmax_t -count_entry (const char *ent, int top, dev_t last_dev, int depth) -{ - uintmax_t size; - struct stat stat_buf; - - if (((top && opt_dereference_arguments) - ? stat (ent, &stat_buf) - : (*xstat) (ent, &stat_buf)) < 0) - { - error (0, errno, "%s", quote (path->text)); - exit_status = 1; - return 0; - } - - if (!opt_count_all - && stat_buf.st_nlink > 1 - && hash_insert (stat_buf.st_ino, stat_buf.st_dev)) - return 0; /* Have counted this already. */ - - size = ST_NBLOCKS (stat_buf); - tot_size += size; - - if (S_ISDIR (stat_buf.st_mode)) - { - unsigned pathlen; - dev_t dir_dev; - char *name_space; - char *namep; - struct saved_cwd *cwd; - struct saved_cwd cwd_buf; - struct stat e_buf; - - dir_dev = stat_buf.st_dev; - - /* Return `0' here, not SIZE, since the SIZE bytes - would reside in the new filesystem. */ - if (opt_one_file_system && !top && last_dev != dir_dev) - return 0; /* Don't enter a new file system. */ - -#ifndef S_ISLNK -# define S_ISLNK(s) 0 -#endif - /* If we're traversing more than one level, or if we're - dereferencing symlinks and we're about to chdir through a - symlink, remember the current directory so we can return to - it later. In other cases, chdir ("..") works fine. - Treat `.' and `..' like multi-level paths, since `chdir ("..")' - wont't restore the current working directory after a `chdir' - to one of those. */ - if (strchr (ent, '/') - || DOT_OR_DOTDOT (ent) - || (xstat == stat - && lstat (ent, &e_buf) == 0 - && S_ISLNK (e_buf.st_mode))) - { - if (save_cwd (&cwd_buf)) - exit (1); - cwd = &cwd_buf; - } - else - cwd = NULL; - - if (chdir (ent) < 0) - { - error (0, errno, _("cannot change to directory %s"), - quote (path->text)); - if (cwd) - free_cwd (cwd); - exit_status = 1; - /* Do return SIZE, here, since even though we can't chdir into ENT, - we *can* count the blocks used by its directory entry. */ - return opt_separate_dirs ? 0 : size; - } - - name_space = savedir (".", stat_buf.st_size); - if (name_space == NULL) - { - error (0, errno, "%s", quote (path->text)); - pop_dir (cwd, path->text); - exit_status = 1; - /* Do count the SIZE bytes. */ - return opt_separate_dirs ? 0 : size; - } - - /* Remember the current path. */ - - str_concatc (path, "/"); - pathlen = path->length; - - for (namep = name_space; *namep; namep += strlen (namep) + 1) - { - if (!excluded_filename (exclude, namep, 0)) - { - str_concatc (path, namep); - size += count_entry (namep, 0, dir_dev, depth + 1); - str_trunc (path, pathlen); - } - } - - free (name_space); - pop_dir (cwd, path->text); - - str_trunc (path, pathlen - 1); /* Remove the "/" we added. */ - if (depth <= max_depth || top) - print_size (size, path->length > 0 ? path->text : "/"); - return opt_separate_dirs ? 0 : size; - } - else if ((opt_all && depth <= max_depth) || top) - { - /* FIXME: make this an option. */ - int print_only_dir_size = 0; - if (!print_only_dir_size) - print_size (size, path->length > 0 ? path->text : "/"); - } - - return size; -} - -/* Recursively print the sizes of the directories (and, if selected, files) - named in FILES, the last entry of which is NULL. */ - -static void -du_files (char **files) -{ - int i; /* Index in FILES. */ - - for (i = 0; files[i]; i++) - { - char *arg; - int s; - - arg = files[i]; - - /* Delete final slash in the argument, unless the slash is alone. */ - s = strlen (arg) - 1; - if (s != 0) - { - if (arg[s] == '/') - arg[s] = 0; - - str_copyc (path, arg); - } - else if (arg[0] == '/') - str_trunc (path, 0); /* Null path for root directory. */ - else - str_copyc (path, arg); - - if (!print_totals) - hash_reset (); - - count_entry (arg, 1, 0, 0); - } - - if (print_totals) - print_size (tot_size, _("total")); -} - -int -main (int argc, char **argv) -{ - int c; - char *cwd_only[2]; - int max_depth_specified = 0; - - /* If nonzero, display only a total for each argument. */ - int opt_summarize_only = 0; - - cwd_only[0] = "."; - cwd_only[1] = NULL; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - exclude = new_exclude (); - xstat = lstat; - - human_block_size (getenv ("DU_BLOCK_SIZE"), 0, &output_block_size); - - while ((c = getopt_long (argc, argv, "abchHklmsxDLSX:", long_options, NULL)) - != -1) - { - long int tmp_long; - switch (c) - { - case 0: /* Long option. */ - break; - - case 'a': - opt_all = 1; - break; - - case 'b': - output_block_size = 1; - break; - - case 'c': - print_totals = 1; - break; - - case 'h': - output_block_size = -1024; - break; - - case 'H': - output_block_size = -1000; - break; - - case 'k': - output_block_size = 1024; - break; - - case MAX_DEPTH_OPTION: /* --max-depth=N */ - if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK - || tmp_long < 0 || tmp_long > INT_MAX) - error (1, 0, _("invalid maximum depth %s"), quote (optarg)); - - max_depth_specified = 1; - max_depth = (int) tmp_long; - break; - - case 'm': - output_block_size = 1024 * 1024; - break; - - case 'l': - opt_count_all = 1; - break; - - case 's': - opt_summarize_only = 1; - break; - - case 'x': - opt_one_file_system = 1; - break; - - case 'D': - opt_dereference_arguments = 1; - break; - - case 'L': - xstat = stat; - break; - - case 'S': - opt_separate_dirs = 1; - break; - - case 'X': - if (add_exclude_file (add_exclude, exclude, optarg, '\n') != 0) - error (1, errno, "%s", quote (optarg)); - break; - - case EXCLUDE_OPTION: - add_exclude (exclude, optarg); - break; - - case BLOCK_SIZE_OPTION: - human_block_size (optarg, 1, &output_block_size); - break; - - case_GETOPT_HELP_CHAR; - - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - - default: - usage (1); - } - } - - if (opt_all && opt_summarize_only) - { - error (0, 0, _("cannot both summarize and show all entries")); - usage (1); - } - - if (opt_summarize_only && max_depth_specified && max_depth == 0) - { - error (0, 0, - _("warning: summarizing is the same as using --max-depth=0")); - } - - if (opt_summarize_only && max_depth_specified && max_depth != 0) - { - error (0, 0, - _("warning: summarizing conflicts with --max-depth=%d"), - max_depth); - usage (1); - } - - if (opt_summarize_only) - max_depth = 0; - - /* Initialize the hash structure for inode numbers. */ - hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE); - - str_init (&path, INITIAL_PATH_SIZE); - - du_files (optind == argc ? cwd_only : argv + optind); - - exit (exit_status); -} diff --git a/src/apps/bin/gnu/install.c b/src/apps/bin/gnu/install.c deleted file mode 100644 index 5b919c44df..0000000000 --- a/src/apps/bin/gnu/install.c +++ /dev/null @@ -1,643 +0,0 @@ -/* install - copy files and set attributes - Copyright (C) 89, 90, 91, 1995-2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by David MacKenzie */ - -#ifdef _AIX - #pragma alloca -#endif - -#include -#include -#include -#include -#include -#include - -#include "system.h" -#include "backupfile.h" -#include "error.h" -#include "cp-hash.h" -#include "copy.h" -#include "dirname.h" -#include "makepath.h" -#include "modechange.h" -#include "path-concat.h" -#include "quote.h" -#include "xstrtol.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "install" - -#define AUTHORS "David MacKenzie" - -#if HAVE_SYS_WAIT_H -# include -#endif - -#if HAVE_VALUES_H -# include -#endif - -struct passwd *getpwnam (); -struct group *getgrnam (); - -#ifndef _POSIX_VERSION -uid_t getuid (); -gid_t getgid (); -#endif - -#if ! HAVE_ENDGRENT -# define endgrent() ((void) 0) -#endif - -#if ! HAVE_ENDPWENT -# define endpwent() ((void) 0) -#endif - -/* Initial number of entries in each hash table entry's table of inodes. */ -#define INITIAL_HASH_MODULE 100 - -/* Initial number of entries in the inode hash table. */ -#define INITIAL_ENTRY_TAB_SIZE 70 - -/* Number of bytes of a file to copy at a time. */ -#define READ_SIZE (32 * 1024) - -int full_write (); -int isdir (); - -int stat (); - -static int change_timestamps PARAMS ((const char *from, const char *to)); -static int change_attributes PARAMS ((const char *path)); -static int copy_file PARAMS ((const char *from, const char *to, - const struct cp_options *x)); -static int install_file_to_path PARAMS ((const char *from, const char *to, - const struct cp_options *x)); -static int install_file_in_dir PARAMS ((const char *from, const char *to_dir, - const struct cp_options *x)); -static int install_file_in_file PARAMS ((const char *from, const char *to, - const struct cp_options *x)); -static void get_ids PARAMS ((void)); -static void strip PARAMS ((const char *path)); -void usage PARAMS ((int status)); - -/* The name this program was run with, for error messages. */ -char *program_name; - -/* The user name that will own the files, or NULL to make the owner - the current user ID. */ -static char *owner_name; - -/* The user ID corresponding to `owner_name'. */ -static uid_t owner_id; - -/* The group name that will own the files, or NULL to make the group - the current group ID. */ -static char *group_name; - -/* The group ID corresponding to `group_name'. */ -static gid_t group_id; - -/* The permissions to which the files will be set. The umask has - no effect. */ -static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; - -/* If nonzero, strip executable files after copying them. */ -static int strip_files; - -/* If nonzero, install a directory instead of a regular file. */ -static int dir_arg; - -static struct option const long_options[] = -{ - {"backup", optional_argument, NULL, 'b'}, - {"directory", no_argument, NULL, 'd'}, - {"group", required_argument, NULL, 'g'}, - {"mode", required_argument, NULL, 'm'}, - {"owner", required_argument, NULL, 'o'}, - {"preserve-timestamps", no_argument, NULL, 'p'}, - {"strip", no_argument, NULL, 's'}, - {"suffix", required_argument, NULL, 'S'}, - {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ - {"verbose", no_argument, NULL, 'v'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -static void -cp_option_init (struct cp_options *x) -{ - x->copy_as_regular = 1; - x->dereference = DEREF_ALWAYS; - x->unlink_dest_before_opening = 1; - x->unlink_dest_after_failed_open = 0; - - /* If unlink fails, try to proceed anyway. */ - x->failed_unlink_is_fatal = 0; - - x->hard_link = 0; - x->interactive = 0; - x->move_mode = 0; - x->myeuid = geteuid (); - x->one_file_system = 0; - x->preserve_owner_and_group = 0; - x->preserve_chmod_bits = 0; - x->preserve_timestamps = 0; - x->require_preserve = 0; - x->recursive = 0; - x->sparse_mode = SPARSE_AUTO; - x->symbolic_link = 0; - x->backup_type = none; - - /* Create destination files initially writable so we can run strip on them. - Although GNU strip works fine on read-only files, some others - would fail. */ - x->set_mode = 1; - x->mode = S_IRUSR | S_IWUSR; - - x->umask_kill = 0; - x->update = 0; - x->verbose = 0; - x->xstat = stat; -} - -int -main (int argc, char **argv) -{ - int optc; - int errors = 0; - const char *specified_mode = NULL; - int make_backups = 0; - char *backup_suffix_string; - char *version_control_string = NULL; - int mkdir_and_install = 0; - struct cp_options x; - int n_files; - char **file; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - cp_option_init (&x); - - owner_name = NULL; - group_name = NULL; - strip_files = 0; - dir_arg = 0; - umask (0); - - /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); - - while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pvV:S:", long_options, - NULL)) != -1) - { - switch (optc) - { - case 0: - break; - - case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ - error (0, 0, - _("warning: --version-control (-V) is obsolete; support for\ - it\nwill be removed in some future release. Use --backup=%s instead." - ), optarg); - /* Fall through. */ - - case 'b': - make_backups = 1; - if (optarg) - version_control_string = optarg; - break; - case 'c': - break; - case 's': - strip_files = 1; - break; - case 'd': - dir_arg = 1; - break; - case 'D': - mkdir_and_install = 1; - break; - case 'v': - x.verbose = 1; - break; - case 'g': - group_name = optarg; - break; - case 'm': - specified_mode = optarg; - break; - case 'o': - owner_name = optarg; - break; - case 'p': - x.preserve_timestamps = 1; - break; - case 'S': - make_backups = 1; - backup_suffix_string = optarg; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - /* Check for invalid combinations of arguments. */ - if (dir_arg && strip_files) - error (1, 0, - _("the strip option may not be used when installing a directory")); - - if (backup_suffix_string) - simple_backup_suffix = xstrdup (backup_suffix_string); - - x.backup_type = (make_backups - ? xget_version (_("backup type"), - version_control_string) - : none); - - n_files = argc - optind; - file = argv + optind; - - if (n_files == 0 || (n_files == 1 && !dir_arg)) - { - error (0, 0, _("too few arguments")); - usage (1); - } - - if (specified_mode) - { - struct mode_change *change = mode_compile (specified_mode, 0); - if (change == MODE_INVALID) - error (1, 0, _("invalid mode %s"), quote (specified_mode)); - else if (change == MODE_MEMORY_EXHAUSTED) - xalloc_die (); - mode = mode_adjust (0, change); - } - - get_ids (); - - if (dir_arg) - { - int i; - for (i = 0; i < n_files; i++) - { - errors |= - make_path (file[i], mode, mode, owner_id, group_id, 0, - (x.verbose ? _("creating directory %s") : NULL)); - } - } - else - { - /* FIXME: it's a little gross that this initialization is - required by copy.c::copy. */ - hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE); - - if (n_files == 2) - { - if (mkdir_and_install) - errors = install_file_to_path (file[0], file[1], &x); - else if (!isdir (file[1])) - errors = install_file_in_file (file[0], file[1], &x); - else - errors = install_file_in_dir (file[0], file[1], &x); - } - else - { - int i; - const char *dest = file[n_files - 1]; - if (!isdir (dest)) - { - error (0, 0, - _("installing multiple files, but last argument, %s \ -is not a directory"), - quote (dest)); - usage (1); - } - for (i = 0; i < n_files - 1; i++) - { - errors |= install_file_in_dir (file[i], dest, &x); - } - } - } - - exit (errors); -} - -/* Copy file FROM onto file TO, creating any missing parent directories of TO. - Return 0 if successful, 1 if an error occurs */ - -static int -install_file_to_path (const char *from, const char *to, - const struct cp_options *x) -{ - char *dest_dir; - int fail = 0; - - dest_dir = dir_name (to); - - /* check to make sure this is a path (not install a b ) */ - if (!STREQ (dest_dir, ".") - && !isdir (dest_dir)) - { - /* Someone will probably ask for a new option or three to specify - owner, group, and permissions for parent directories. Remember - that this option is intended mainly to help installers when the - distribution doesn't provide proper install rules. */ -#define DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) - fail = make_path (dest_dir, DIR_MODE, DIR_MODE, owner_id, group_id, 0, - (x->verbose ? _("creating directory %s") : NULL)); - } - - if (fail == 0) - fail = install_file_in_file (from, to, x); - - free (dest_dir); - - return fail; -} - -/* Copy file FROM onto file TO and give TO the appropriate - attributes. - Return 0 if successful, 1 if an error occurs. */ - -static int -install_file_in_file (const char *from, const char *to, - const struct cp_options *x) -{ - if (copy_file (from, to, x)) - return 1; - if (strip_files) - strip (to); - if (change_attributes (to)) - return 1; - if (x->preserve_timestamps) - return change_timestamps (from, to); - return 0; -} - -/* Copy file FROM into directory TO_DIR, keeping its same name, - and give the copy the appropriate attributes. - Return 0 if successful, 1 if not. */ - -static int -install_file_in_dir (const char *from, const char *to_dir, - const struct cp_options *x) -{ - const char *from_base; - char *to; - int ret; - - from_base = base_name (from); - to = path_concat (to_dir, from_base, NULL); - ret = install_file_in_file (from, to, x); - free (to); - return ret; -} - -/* Copy file FROM onto file TO, creating TO if necessary. - Return 0 if the copy is successful, 1 if not. */ - -static int -copy_file (const char *from, const char *to, const struct cp_options *x) -{ - int fail; - int nonexistent_dst = 0; - int copy_into_self; - - /* Allow installing from non-regular files like /dev/null. - Charles Karney reported that some Sun version of install allows that - and that sendmail's installation process relies on the behavior. */ - if (isdir (from)) - { - error (0, 0, _("%s is a directory"), quote (from)); - return 1; - } - - fail = copy (from, to, nonexistent_dst, x, ©_into_self, NULL); - - return fail; -} - -/* Set the attributes of file or directory PATH. - Return 0 if successful, 1 if not. */ - -static int -change_attributes (const char *path) -{ - int err = 0; - - /* chown must precede chmod because on some systems, - chown clears the set[ug]id bits for non-superusers, - resulting in incorrect permissions. - On System V, users can give away files with chown and then not - be able to chmod them. So don't give files away. - - We don't normally ignore errors from chown because the idea of - the install command is that the file is supposed to end up with - precisely the attributes that the user specified (or defaulted). - If the file doesn't end up with the group they asked for, they'll - want to know. But AFS returns EPERM when you try to change a - file's group; thus the kludge. */ - - if (chown (path, owner_id, group_id) -#ifdef AFS - && errno != EPERM -#endif - ) - { - error (0, errno, "cannot change ownership of %s", quote (path)); - err = 1; - } - - if (!err && chmod (path, mode)) - { - error (0, errno, "cannot change permissions of %s", quote (path)); - err = 1; - } - - return err; -} - -/* Set the timestamps of file TO to match those of file FROM. - Return 0 if successful, 1 if not. */ - -static int -change_timestamps (const char *from, const char *to) -{ - struct stat stb; - struct utimbuf utb; - - if (stat (from, &stb)) - { - error (0, errno, _("cannot obtain time stamps for %s"), quote (from)); - return 1; - } - - /* There's currently no interface to set file timestamps with - better than 1-second resolution, so discard any fractional - part of the source timestamp. */ - - utb.actime = stb.st_atime; - utb.modtime = stb.st_mtime; - if (utime (to, &utb)) - { - error (0, errno, _("cannot set time stamps for %s"), quote (to)); - return 1; - } - return 0; -} - -/* Strip the symbol table from the file PATH. - We could dig the magic number out of the file first to - determine whether to strip it, but the header files and - magic numbers vary so much from system to system that making - it portable would be very difficult. Not worth the effort. */ - -static void -strip (const char *path) -{ - int status; - pid_t pid = fork (); - - switch (pid) - { - case -1: - error (1, errno, _("cannot fork")); - break; - case 0: /* Child. */ - execlp ("strip", "strip", path, NULL); - error (1, errno, _("cannot run strip")); - break; - default: /* Parent. */ - /* Parent process. */ - while (pid != wait (&status)) /* Wait for kid to finish. */ - /* Do nothing. */ ; - if (status) - error (1, 0, _("strip failed")); - break; - } -} - -/* Initialize the user and group ownership of the files to install. */ - -static void -get_ids (void) -{ - struct passwd *pw; - struct group *gr; - - if (owner_name) - { - pw = getpwnam (owner_name); - if (pw == NULL) - { - long int tmp_long; - if (xstrtol (owner_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK - || tmp_long < 0 || tmp_long > UID_T_MAX) - error (1, 0, _("invalid user %s"), quote (owner_name)); - owner_id = (uid_t) tmp_long; - } - else - owner_id = pw->pw_uid; - endpwent (); - } - else - owner_id = (uid_t) -1; - - if (group_name) - { - gr = getgrnam (group_name); - if (gr == NULL) - { - long int tmp_long; - if (xstrtol (group_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK - || tmp_long < 0 || tmp_long > GID_T_MAX) - error (1, 0, _("invalid group %s"), quote (group_name)); - group_id = (gid_t) tmp_long; - } - else - group_id = gr->gr_gid; - endgrent (); - } - else - group_id = (gid_t) -1; -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("\ -Usage: %s [OPTION]... SOURCE DEST (1st format)\n\ - or: %s [OPTION]... SOURCE... DIRECTORY (2nd format)\n\ - or: %s -d [OPTION]... DIRECTORY... (3rd format)\n\ -"), - program_name, program_name, program_name); - printf (_("\ -In the first two formats, copy SOURCE to DEST or multiple SOURCE(s) to\n\ -the existing DIRECTORY, while setting permission modes and owner/group.\n\ -In the third format, create all components of the given DIRECTORY(ies).\n\ -\n\ - --backup[=CONTROL] make a backup of each existing destination file\n\ - -b like --backup but does not accept an argument\n\ - -c (ignored)\n\ - -d, --directory treat all arguments as directory names; create all\n\ - components of the specified directories\n\ - -D create all leading components of DEST except the last,\n\ - then copy SOURCE to DEST; useful in the 1st format\n\ - -g, --group=GROUP set group ownership, instead of process' current group\n\ - -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\ - -o, --owner=OWNER set ownership (super-user only)\n\ - -p, --preserve-timestamps apply access/modification times of SOURCE files\n\ - to corresponding destination files\n\ - -s, --strip strip symbol tables, only for 1st and 2nd formats\n\ - -S, --suffix=SUFFIX override the usual backup suffix\n\ - -v, --verbose print the name of each directory as it is created\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -")); - printf (_("\ -The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ -The version control method may be selected via the --backup option or through\n\ -the VERSION_CONTROL environment variable. Here are the values:\n\ -\n\ - none, off never make backups (even if --backup is given)\n\ - numbered, t make numbered backups\n\ - existing, nil numbered if numbered backups exist, simple otherwise\n\ - simple, never always make simple backups\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} diff --git a/src/apps/bin/gnu/ln.c b/src/apps/bin/gnu/ln.c deleted file mode 100644 index 21f55dcd6f..0000000000 --- a/src/apps/bin/gnu/ln.c +++ /dev/null @@ -1,563 +0,0 @@ -/* `ln' program to create links between files. - Copyright (C) 86, 89, 90, 91, 1995-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by Mike Parker and David MacKenzie. */ - -#ifdef _AIX - #pragma alloca -#endif - -#include -#include -#include -#include - -#include "system.h" -#include "same.h" -#include "backupfile.h" -#include "error.h" -#include "quote.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "ln" - -#define AUTHORS "Mike Parker and David MacKenzie" - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - TARGET_DIRECTORY_OPTION = CHAR_MAX + 1 -}; - -int link (); /* Some systems don't declare this anywhere. */ - -#ifdef S_ISLNK -int symlink (); -#endif - -/* In being careful not even to try to make hard links to directories, - we have to know whether link(2) follows symlinks. If it does, then - we have to *stat* the `source' to see if the resulting link would be - to a directory. Otherwise, we have to use *lstat* so that we allow - users to make hard links to symlinks-that-point-to-directories. */ - -#if LINK_FOLLOWS_SYMLINKS -# define STAT_LIKE_LINK(File, Stat_buf) \ - stat (File, Stat_buf) -#else -# define STAT_LIKE_LINK(File, Stat_buf) \ - lstat (File, Stat_buf) -#endif - -/* Construct a string NEW_DEST by concatenating DEST, a slash, and - basename(SOURCE) in alloca'd memory. Don't modify DEST or SOURCE. */ - -#define PATH_BASENAME_CONCAT(new_dest, dest, source) \ - do \ - { \ - const char *source_base; \ - char *tmp_source; \ - \ - tmp_source = (char *) alloca (strlen ((source)) + 1); \ - strcpy (tmp_source, (source)); \ - strip_trailing_slashes (tmp_source); \ - source_base = base_name (tmp_source); \ - \ - (new_dest) = (char *) alloca (strlen ((dest)) + 1 \ - + strlen (source_base) + 1); \ - stpcpy (stpcpy (stpcpy ((new_dest), (dest)), "/"), source_base);\ - } \ - while (0) - -int isdir (); -int yesno (); -void strip_trailing_slashes (); - -/* The name by which the program was run, for error messages. */ -char *program_name; - -/* FIXME: document */ -enum backup_type backup_type; - -/* A pointer to the function used to make links. This will point to either - `link' or `symlink'. */ -static int (*linkfunc) (); - -/* If nonzero, make symbolic links; otherwise, make hard links. */ -static int symbolic_link; - -/* If nonzero, ask the user before removing existing files. */ -static int interactive; - -/* If nonzero, remove existing files unconditionally. */ -static int remove_existing_files; - -/* If nonzero, list each file as it is moved. */ -static int verbose; - -/* If nonzero, allow the superuser to make hard links to directories. */ -static int hard_dir_link; - -/* If nonzero, and the specified destination is a symbolic link to a - directory, treat it just as if it were a directory. Otherwise, the - command `ln --force --no-dereference file symlink-to-dir' deletes - symlink-to-dir before creating the new link. */ -static int dereference_dest_dir_symlinks = 1; - -static struct option const long_options[] = -{ - {"backup", optional_argument, NULL, 'b'}, - {"directory", no_argument, NULL, 'F'}, - {"no-dereference", no_argument, NULL, 'n'}, - {"force", no_argument, NULL, 'f'}, - {"interactive", no_argument, NULL, 'i'}, - {"suffix", required_argument, NULL, 'S'}, - {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, - {"symbolic", no_argument, NULL, 's'}, - {"verbose", no_argument, NULL, 'v'}, - {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -/* Make a link DEST to the (usually) existing file SOURCE. - Symbolic links to nonexistent files are allowed. - If DEST is a directory, put the link to SOURCE in that directory. - Return 1 if there is an error, otherwise 0. */ - -static int -do_link (const char *source, const char *dest) -{ - struct stat source_stats; - struct stat dest_stats; - char *dest_backup = NULL; - int lstat_status; - int backup_succeeded = 0; - - /* Use stat here instead of lstat. - On SVR4, link does not follow symlinks, so this check disallows - making hard links to symlinks that point to directories. Big deal. - On other systems, link follows symlinks, so this check is right. */ - if (!symbolic_link) - { - if (STAT_LIKE_LINK (source, &source_stats) != 0) - { - error (0, errno, _("accessing %s"), quote (source)); - return 1; - } - - if (S_ISLNK (source_stats.st_mode)) - { - error (0, 0, _("%s: warning: making a hard link to a symbolic link\ - is not portable"), - quote (source)); - } - - if (!hard_dir_link && S_ISDIR (source_stats.st_mode)) - { - error (0, 0, _("%s: hard link not allowed for directory"), - quote (source)); - return 1; - } - } - - lstat_status = lstat (dest, &dest_stats); - if (lstat_status != 0 && errno != ENOENT) - { - error (0, errno, _("accessing %s"), quote (dest)); - return 1; - } - - /* If the destination is a directory or (it is a symlink to a directory - and the user has not specified --no-dereference), then form the - actual destination name by appending base_name (source) to the - specified destination directory. */ - if ((lstat_status == 0 - && S_ISDIR (dest_stats.st_mode)) -#ifdef S_ISLNK - || (dereference_dest_dir_symlinks - && (lstat_status == 0 - && S_ISLNK (dest_stats.st_mode) - && isdir (dest))) -#endif - ) - { - /* Target is a directory; build the full filename. */ - char *new_dest; - PATH_BASENAME_CONCAT (new_dest, dest, source); - dest = new_dest; - - /* Get stats for new DEST. */ - lstat_status = lstat (dest, &dest_stats); - if (lstat_status != 0 && errno != ENOENT) - { - error (0, errno, _("accessing %s"), quote (dest)); - return 1; - } - } - - /* If --force (-f) has been specified without --backup, then before - making a link ln must remove the destination file if it exists. - (with --backup, it just renames any existing destination file) - But if the source and destination are the same, don't remove - anything and fail right here. */ - if (remove_existing_files - && lstat_status == 0 - /* Allow `ln -sf --backup k k' to succeed in creating the - self-referential symlink, but don't allow the hard-linking - equivalent: `ln -f k k' (with or without --backup) to get - beyond this point, because the error message you'd get is - misleading. */ - && (backup_type == none || !symlink) - && (!symbolic_link || stat (source, &source_stats) == 0) - && source_stats.st_dev == dest_stats.st_dev - && source_stats.st_ino == dest_stats.st_ino - /* The following detects whether removing DEST will also remove - SOURCE. If the file has only one link then both are surely - the same link. Otherwise check whether they point to the same - name in the same directory. */ - && (source_stats.st_nlink == 1 || same_name (source, dest))) - { - error (0, 0, _("%s and %s are the same file"), - quote_n (0, source), quote_n (1, dest)); - return 1; - } - - if (lstat_status == 0 || lstat (dest, &dest_stats) == 0) - { - if (S_ISDIR (dest_stats.st_mode)) - { - error (0, 0, _("%s: cannot overwrite directory"), quote (dest)); - return 1; - } - if (interactive) - { - fprintf (stderr, _("%s: replace %s? "), program_name, quote (dest)); - if (!yesno ()) - return 0; - } - else if (!remove_existing_files && backup_type == none) - { - error (0, 0, _("%s: File exists"), quote (dest)); - return 1; - } - - if (backup_type != none) - { - char *tmp_backup = find_backup_file_name (dest, backup_type); - if (tmp_backup == NULL) - xalloc_die (); - dest_backup = (char *) alloca (strlen (tmp_backup) + 1); - strcpy (dest_backup, tmp_backup); - free (tmp_backup); - if (rename (dest, dest_backup)) - { - if (errno != ENOENT) - { - error (0, errno, _("cannot backup %s"), quote (dest)); - return 1; - } - else - dest_backup = NULL; - } - else - { - backup_succeeded = 1; - } - } - - /* Try to unlink DEST even if we may have renamed it. In some unusual - cases (when DEST and DEST_BACKUP are hard-links that refer to the - same file), rename succeeds and DEST remains. If we didn't remove - DEST in that case, the subsequent LINKFUNC call would fail. */ - if (unlink (dest) && errno != ENOENT) - { - error (0, errno, _("cannot remove %s"), quote (dest)); - return 1; - } - } - else if (errno != ENOENT) - { - error (0, errno, _("accessing %s"), quote (dest)); - return 1; - } - - if (verbose) - { - printf ((symbolic_link - ? _("create symbolic link %s to %s") - : _("create hard link %s to %s")), - quote_n (0, dest), quote_n (1, source)); - if (backup_succeeded) - printf (_(" (backup: %s)"), quote (dest_backup)); - putchar ('\n'); - } - - if ((*linkfunc) (source, dest) == 0) - { - return 0; - } - - error (0, errno, - (symbolic_link - ? _("creating symbolic link %s to %s") - : _("creating hard link %s to %s")), - quote_n (0, dest), quote_n (1, source)); - - if (dest_backup) - { - if (rename (dest_backup, dest)) - error (0, errno, _("cannot un-backup %s"), quote (dest)); - } - return 1; -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("\ -Usage: %s [OPTION]... TARGET [LINK_NAME]\n\ - or: %s [OPTION]... TARGET... DIRECTORY\n\ - or: %s [OPTION]... --target-directory=DIRECTORY TARGET...\n\ -"), - program_name, program_name, program_name); - printf (_("\ -Create a link to the specified TARGET with optional LINK_NAME.\n\ -If LINK_NAME is omitted, a link with the same basename as the TARGET is\n\ -created in the current directory. When using the second form with more\n\ -than one TARGET, the last argument must be a directory; create links\n\ -in DIRECTORY to each TARGET. Create hard links by default, symbolic\n\ -links with --symbolic. When creating hard links, each TARGET must exist.\n\ -\n\ - --backup[=CONTROL] make a backup of each existing destination file\n\ - -b like --backup but does not accept an argument\n\ - -d, -F, --directory hard link directories (super-user only)\n\ - -f, --force remove existing destination files\n\ - -n, --no-dereference treat destination that is a symlink to a\n\ - directory as if it were a normal file\n\ - -i, --interactive prompt whether to remove destinations\n\ - -s, --symbolic make symbolic links instead of hard links\n\ - -S, --suffix=SUFFIX override the usual backup suffix\n\ - --target-directory=DIRECTORY specify the DIRECTORY in which to create\n\ - the links\n\ - -v, --verbose print name of each file before linking\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -")); - printf (_("\ -The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ -The version control method may be selected via the --backup option or through\n\ -the VERSION_CONTROL environment variable. Here are the values:\n\ -\n\ - none, off never make backups (even if --backup is given)\n\ - numbered, t make numbered backups\n\ - existing, nil numbered if numbered backups exist, simple otherwise\n\ - simple, never always make simple backups\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - int c; - int errors; - int make_backups = 0; - char *backup_suffix_string; - char *version_control_string = NULL; - char *target_directory = NULL; - int target_directory_specified; - unsigned int n_files; - char **file; - int dest_is_dir; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); - - symbolic_link = remove_existing_files = interactive = verbose - = hard_dir_link = 0; - errors = 0; - - while ((c = getopt_long (argc, argv, "bdfinsvFS:V:", long_options, NULL)) - != -1) - { - switch (c) - { - case 0: /* Long-named option. */ - break; - - case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ - error (0, 0, - _("warning: --version-control (-V) is obsolete; support for\ - it\nwill be removed in some future release. Use --backup=%s instead." - ), optarg); - /* Fall through. */ - - case 'b': - make_backups = 1; - if (optarg) - version_control_string = optarg; - break; - case 'd': - case 'F': - hard_dir_link = 1; - break; - case 'f': - remove_existing_files = 1; - interactive = 0; - break; - case 'i': - remove_existing_files = 0; - interactive = 1; - break; - case 'n': - dereference_dest_dir_symlinks = 0; - break; - case 's': -#ifdef S_ISLNK - symbolic_link = 1; -#else - error (1, 0, _("symbolic links are not supported on this system")); -#endif - break; - case TARGET_DIRECTORY_OPTION: - target_directory = optarg; - break; - case 'v': - verbose = 1; - break; - case 'S': - make_backups = 1; - backup_suffix_string = optarg; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - break; - } - } - - n_files = argc - optind; - file = argv + optind; - - if (n_files == 0) - { - error (0, 0, _("missing file argument")); - usage (1); - } - - target_directory_specified = (target_directory != NULL); - if (!target_directory) - target_directory = file[n_files - 1]; - - /* If there's only one file argument, then pretend `.' was given - as the second argument. */ - if (n_files == 1) - { - static char *dummy[2]; - dummy[0] = file[0]; - dummy[1] = "."; - file = dummy; - n_files = 2; - dest_is_dir = 1; - } - else - { - dest_is_dir = isdir (target_directory); - } - - if (symbolic_link) - linkfunc = symlink; - else - linkfunc = link; - - if (target_directory_specified && !dest_is_dir) - { - error (0, 0, _("specified target directory, %s is not a directory"), - quote (target_directory)); - usage (1); - } - - if (backup_suffix_string) - simple_backup_suffix = xstrdup (backup_suffix_string); - - backup_type = (make_backups - ? xget_version (_("backup type"), version_control_string) - : none); - - if (target_directory_specified || n_files > 2) - { - unsigned int i; - unsigned int last_file_idx = (target_directory_specified - ? n_files - 1 - : n_files - 2); - - if (!target_directory_specified && !dest_is_dir) - error (1, 0, - _("when making multiple links, last argument must be a directory")); - for (i = 0; i <= last_file_idx; ++i) - errors += do_link (file[i], target_directory); - } - else - { - struct stat source_stats; - const char *source; - char *dest; - char *new_dest; - - source = file[0]; - dest = file[1]; - - /* When the destination is specified with a trailing slash and the - source exists but is not a directory, convert the user's command - `ln source dest/' to `ln source dest/basename(source)'. */ - - if (dest[strlen (dest) - 1] == '/' - && lstat (source, &source_stats) == 0 - && !S_ISDIR (source_stats.st_mode)) - { - PATH_BASENAME_CONCAT (new_dest, dest, source); - } - else - { - new_dest = dest; - } - - errors = do_link (source, new_dest); - } - - exit (errors != 0); -} diff --git a/src/apps/bin/gnu/ls-dir.c b/src/apps/bin/gnu/ls-dir.c deleted file mode 100644 index 85fe242ebf..0000000000 --- a/src/apps/bin/gnu/ls-dir.c +++ /dev/null @@ -1,2 +0,0 @@ -#include "ls.h" -int ls_mode = LS_MULTI_COL; diff --git a/src/apps/bin/gnu/ls-ls.c b/src/apps/bin/gnu/ls-ls.c deleted file mode 100644 index f33fbbc061..0000000000 --- a/src/apps/bin/gnu/ls-ls.c +++ /dev/null @@ -1,2 +0,0 @@ -#include "ls.h" -int ls_mode = LS_LS; diff --git a/src/apps/bin/gnu/ls-vdir.c b/src/apps/bin/gnu/ls-vdir.c deleted file mode 100644 index 36ebf913bc..0000000000 --- a/src/apps/bin/gnu/ls-vdir.c +++ /dev/null @@ -1,2 +0,0 @@ -#include "ls.h" -int ls_mode = LS_LONG_FORMAT; diff --git a/src/apps/bin/gnu/ls.c b/src/apps/bin/gnu/ls.c deleted file mode 100644 index efc5611bcb..0000000000 --- a/src/apps/bin/gnu/ls.c +++ /dev/null @@ -1,3338 +0,0 @@ -/* `dir', `vdir' and `ls' directory listing programs for GNU. - Copyright (C) 85, 88, 90, 91, 1995-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* If ls_mode is LS_MULTI_COL, - the multi-column format is the default regardless - of the type of output device. - This is for the `dir' program. - - If ls_mode is LS_LONG_FORMAT, - the long format is the default regardless of the - type of output device. - This is for the `vdir' program. - - If ls_mode is LS_LS, - the output format depends on whether the output - device is a terminal. - This is for the `ls' program. */ - -/* Written by Richard Stallman and David MacKenzie. */ - -/* Color support by Peter Anvin and Dennis - Flaherty based on original patches by - Greg Lee . */ - -#ifdef _AIX - #pragma alloca -#endif - -#include -#include - -#if HAVE_INTTYPES_H -# include -#endif - -#if HAVE_TERMIOS_H -# include -#endif - -#ifdef GWINSZ_IN_SYS_IOCTL -# include -#endif - -#ifdef WINSIZE_IN_PTEM -# include -# include -#endif - -#if HAVE_SYS_ACL_H -# include -#endif - -#include -#include -#include -#include -#include - -/* Get MB_CUR_MAX. */ -#if HAVE_STDLIB_H -# include -#endif - -/* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth(). */ -#if HAVE_WCHAR_H -# include -#endif - -/* Get iswprint(). */ -#if HAVE_WCTYPE_H -# include -#endif -#if !defined iswprint && !HAVE_ISWPRINT -# define iswprint(wc) 1 -#endif - -#ifndef HAVE_DECL_WCWIDTH -"this configure-time declaration test was not run" -#endif -#if !HAVE_DECL_WCWIDTH -int wcwidth (); -#endif - -/* If wcwidth() doesn't exist, assume all printable characters have - width 1. */ -#ifndef wcwidth -# if !HAVE_WCWIDTH -# define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1) -# endif -#endif - -#include "system.h" -#include - -#include "argmatch.h" -#include "error.h" -#include "human.h" -#include "filemode.h" -#include "ls.h" -#include "mbswidth.h" -#include "obstack.h" -#include "path-concat.h" -#include "quotearg.h" -#include "strverscmp.h" -#include "xstrtol.h" - -/* Use access control lists only under all the following conditions. - Some systems (OSF4, Irix5, Irix6) have the acl function, but not - sys/acl.h or don't define the GETACLCNT macro. */ -#if HAVE_SYS_ACL_H && HAVE_ACL && defined GETACLCNT -# define USE_ACL 1 -#endif - -#define PROGRAM_NAME (ls_mode == LS_LS ? "ls" \ - : (ls_mode == LS_MULTI_COL \ - ? "dir" : "vdir")) - -#define AUTHORS "Richard Stallman and David MacKenzie" - -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free - -/* Return an int indicating the result of comparing two integers. - Subtracting doesn't always work, due to overflow. */ -#define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b)) - -/* The field width for inode numbers. On some hosts inode numbers are - 64 bits, so columns won't line up exactly when a huge inode number - is encountered, but in practice 7 digits is usually enough. */ -#ifndef INODE_DIGITS -# define INODE_DIGITS 7 -#endif - -#ifdef S_ISLNK -# define HAVE_SYMLINKS 1 -#else -# define HAVE_SYMLINKS 0 -#endif - -/* If any of the S_* macros are undefined, define them here so each - use doesn't have to be guarded with e.g., #ifdef S_ISLNK. */ -#ifndef S_ISLNK -# define S_ISLNK(Mode) 0 -#endif - -#ifndef S_ISFIFO -# define S_ISFIFO(Mode) 0 -#endif - -#ifndef S_ISSOCK -# define S_ISSOCK(Mode) 0 -#endif - -#ifndef S_ISCHR -# define S_ISCHR(Mode) 0 -#endif - -#ifndef S_ISBLK -# define S_ISBLK(Mode) 0 -#endif - -#ifndef S_ISDOOR -# define S_ISDOOR(Mode) 0 -#endif - -/* Arrange to make lstat calls go through the wrapper function - on systems with an lstat function that does not dereference symlinks - that are specified with a trailing slash. */ -#if ! LSTAT_FOLLOWS_SLASHED_SYMLINK -int rpl_lstat PARAMS((const char *, struct stat *)); -# undef lstat -# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf) -#endif - -#if defined _DIRENT_HAVE_D_TYPE || defined DTTOIF -# define HAVE_STRUCT_DIRENT_D_TYPE 1 -# define DT_INIT(Val) = Val -#else -# define HAVE_STRUCT_DIRENT_D_TYPE 0 -# define DT_INIT(Val) /* empty */ -#endif - -#ifdef ST_MTIM_NSEC -# define TIMESPEC_NS(timespec) ((timespec).ST_MTIM_NSEC) -#else -# define TIMESPEC_NS(timespec) 0 -#endif - -enum filetype - { - unknown DT_INIT (DT_UNKNOWN), - fifo DT_INIT (DT_FIFO), - chardev DT_INIT (DT_CHR), - directory DT_INIT (DT_DIR), - blockdev DT_INIT (DT_BLK), - normal DT_INIT (DT_REG), - symbolic_link DT_INIT (DT_LNK), - sock DT_INIT (DT_SOCK), - arg_directory DT_INIT (2 * (DT_UNKNOWN | DT_FIFO | DT_CHR | DT_DIR | DT_BLK - | DT_REG | DT_LNK | DT_SOCK)) - }; - -struct fileinfo - { - /* The file name. */ - char *name; - - struct stat stat; - - /* For symbolic link, name of the file linked to, otherwise zero. */ - char *linkname; - - /* For symbolic link and long listing, st_mode of file linked to, otherwise - zero. */ - unsigned int linkmode; - - /* For symbolic link and color printing, 1 if linked-to file - exists, otherwise 0. */ - int linkok; - - enum filetype filetype; - -#if USE_ACL - /* For long listings, nonzero if the file has an access control list, - otherwise zero. */ - int have_acl; -#endif - }; - -#if USE_ACL -# define FILE_HAS_ACL(F) ((F)->have_acl) -#else -# define FILE_HAS_ACL(F) 0 -#endif - -#define LEN_STR_PAIR(s) sizeof (s) - 1, s - -/* Null is a valid character in a color indicator (think about Epson - printers, for example) so we have to use a length/buffer string - type. */ - -struct bin_str - { - int len; /* Number of bytes */ - const char *string; /* Pointer to the same */ - }; - -#ifndef STDC_HEADERS -time_t time (); -#endif - -char *getgroup (); -char *getuser (); - -static size_t quote_name PARAMS ((FILE *out, const char *name, - struct quoting_options const *options)); -static char *make_link_path PARAMS ((const char *path, const char *linkname)); -static int compare_atime PARAMS ((const struct fileinfo *file1, - const struct fileinfo *file2)); -static int rev_cmp_atime PARAMS ((const struct fileinfo *file2, - const struct fileinfo *file1)); -static int compare_ctime PARAMS ((const struct fileinfo *file1, - const struct fileinfo *file2)); -static int rev_cmp_ctime PARAMS ((const struct fileinfo *file2, - const struct fileinfo *file1)); -static int compare_mtime PARAMS ((const struct fileinfo *file1, - const struct fileinfo *file2)); -static int rev_cmp_mtime PARAMS ((const struct fileinfo *file2, - const struct fileinfo *file1)); -static int compare_size PARAMS ((const struct fileinfo *file1, - const struct fileinfo *file2)); -static int rev_cmp_size PARAMS ((const struct fileinfo *file2, - const struct fileinfo *file1)); -static int compare_name PARAMS ((const struct fileinfo *file1, - const struct fileinfo *file2)); -static int rev_cmp_name PARAMS ((const struct fileinfo *file2, - const struct fileinfo *file1)); -static int compare_extension PARAMS ((const struct fileinfo *file1, - const struct fileinfo *file2)); -static int rev_cmp_extension PARAMS ((const struct fileinfo *file2, - const struct fileinfo *file1)); -static int compare_version PARAMS ((const struct fileinfo *file1, - const struct fileinfo *file2)); -static int rev_cmp_version PARAMS ((const struct fileinfo *file2, - const struct fileinfo *file1)); -static int decode_switches PARAMS ((int argc, char **argv)); -static int file_interesting PARAMS ((const struct dirent *next)); -static uintmax_t gobble_file PARAMS ((const char *name, enum filetype type, - int explicit_arg, const char *dirname)); -static void print_color_indicator PARAMS ((const char *name, unsigned int mode, - int linkok)); -static void put_indicator PARAMS ((const struct bin_str *ind)); -static int length_of_file_name_and_frills PARAMS ((const struct fileinfo *f)); -static void add_ignore_pattern PARAMS ((const char *pattern)); -static void attach PARAMS ((char *dest, const char *dirname, const char *name)); -static void clear_files PARAMS ((void)); -static void extract_dirs_from_files PARAMS ((const char *dirname, - int recursive)); -static void get_link_name PARAMS ((const char *filename, struct fileinfo *f)); -static void indent PARAMS ((int from, int to)); -static void init_column_info PARAMS ((void)); -static void print_current_files PARAMS ((void)); -static void print_dir PARAMS ((const char *name, const char *realname)); -static void print_file_name_and_frills PARAMS ((const struct fileinfo *f)); -static void print_horizontal PARAMS ((void)); -static void print_long_format PARAMS ((const struct fileinfo *f)); -static void print_many_per_line PARAMS ((void)); -static void print_name_with_quoting PARAMS ((const char *p, unsigned int mode, - int linkok, - struct obstack *stack)); -static void prep_non_filename_text PARAMS ((void)); -static void print_type_indicator PARAMS ((unsigned int mode)); -static void print_with_commas PARAMS ((void)); -static void queue_directory PARAMS ((const char *name, const char *realname)); -static void sort_files PARAMS ((void)); -static void parse_ls_color PARAMS ((void)); -void usage PARAMS ((int status)); - -/* The name the program was run with, stripped of any leading path. */ -char *program_name; - -/* The table of files in the current directory: - - `files' points to a vector of `struct fileinfo', one per file. - `nfiles' is the number of elements space has been allocated for. - `files_index' is the number actually in use. */ - -/* Address of block containing the files that are described. */ -static struct fileinfo *files; /* FIXME: rename this to e.g. cwd_file */ - -/* Length of block that `files' points to, measured in files. */ -static int nfiles; /* FIXME: rename this to e.g. cwd_n_alloc */ - -/* Index of first unused in `files'. */ -static int files_index; /* FIXME: rename this to e.g. cwd_n_used */ - -/* When nonzero, in a color listing, color each symlink name according to the - type of file it points to. Otherwise, color them according to the `ln' - directive in LS_COLORS. Dangling (orphan) symlinks are treated specially, - regardless. This is set when `ln=target' appears in LS_COLORS. */ - -static int color_symlink_as_referent; - -/* mode of appropriate file for colorization */ -#define FILE_OR_LINK_MODE(File) \ - ((color_symlink_as_referent && (File)->linkok) \ - ? (File)->linkmode : (File)->stat.st_mode) - - -/* Record of one pending directory waiting to be listed. */ - -struct pending - { - char *name; - /* If the directory is actually the file pointed to by a symbolic link we - were told to list, `realname' will contain the name of the symbolic - link, otherwise zero. */ - char *realname; - struct pending *next; - }; - -static struct pending *pending_dirs; - -/* Current time in seconds and nanoseconds since 1970, updated as - needed when deciding whether a file is recent. */ - -static time_t current_time = TYPE_MINIMUM (time_t); -static int current_time_ns = -1; - -/* The number of digits to use for block sizes. - 4, or more if needed for bigger numbers. */ - -static int block_size_size; - -/* Option flags */ - -/* long_format for lots of info, one per line. - one_per_line for just names, one per line. - many_per_line for just names, many per line, sorted vertically. - horizontal for just names, many per line, sorted horizontally. - with_commas for just names, many per line, separated by commas. - - -l, -1, -C, -x and -m control this parameter. */ - -enum format - { - long_format, /* -l */ - one_per_line, /* -1 */ - many_per_line, /* -C */ - horizontal, /* -x */ - with_commas /* -m */ - }; - -static enum format format; - -/* Type of time to print or sort by. Controlled by -c and -u. */ - -enum time_type - { - time_mtime, /* default */ - time_ctime, /* -c */ - time_atime /* -u */ - }; - -static enum time_type time_type; - -/* print the full time, otherwise the standard unix heuristics. */ - -static int full_time; - -/* The file characteristic to sort by. Controlled by -t, -S, -U, -X, -v. */ - -enum sort_type - { - sort_none, /* -U */ - sort_name, /* default */ - sort_extension, /* -X */ - sort_time, /* -t */ - sort_size, /* -S */ - sort_version /* -v */ - }; - -static enum sort_type sort_type; - -/* Direction of sort. - 0 means highest first if numeric, - lowest first if alphabetic; - these are the defaults. - 1 means the opposite order in each case. -r */ - -static int sort_reverse; - -/* Nonzero means to NOT display group information. -G */ - -static int inhibit_group; - -/* Nonzero means print the user and group id's as numbers rather - than as names. -n */ - -static int numeric_ids; - -/* Nonzero means mention the size in blocks of each file. -s */ - -static int print_block_size; - -/* If positive, the units to use when printing sizes; - if negative, the human-readable base. */ -static int output_block_size; - -/* Precede each line of long output (per file) with a string like `m,n:' - where M is the number of characters after the `:' and before the - filename and N is the length of the filename. Using this format, - Emacs' dired mode starts up twice as fast, and can handle all - strange characters in file names. */ -static int dired; - -/* `none' means don't mention the type of files. - `classify' means mention file types and mark executables. - `file_type' means mention only file types. - - Controlled by -F, -p, and --indicator-style. */ - -enum indicator_style - { - none, /* --indicator-style=none */ - classify, /* -F, --indicator-style=classify */ - file_type /* -p, --indicator-style=file-type */ - }; - -static enum indicator_style indicator_style; - -/* Names of indicator styles. */ -static char const *const indicator_style_args[] = -{ - "none", "classify", "file-type", 0 -}; - -static enum indicator_style const indicator_style_types[]= -{ - none, classify, file_type -}; - -/* Nonzero means use colors to mark types. Also define the different - colors as well as the stuff for the LS_COLORS environment variable. - The LS_COLORS variable is now in a termcap-like format. */ - -static int print_with_color; - -enum color_type - { - color_never, /* 0: default or --color=never */ - color_always, /* 1: --color=always */ - color_if_tty /* 2: --color=tty */ - }; - -enum indicator_no - { - C_LEFT, C_RIGHT, C_END, C_NORM, C_FILE, C_DIR, C_LINK, C_FIFO, C_SOCK, - C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR - }; - -static const char *const indicator_name[]= - { - "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so", - "bd", "cd", "mi", "or", "ex", "do", NULL - }; - -struct color_ext_type - { - struct bin_str ext; /* The extension we're looking for */ - struct bin_str seq; /* The sequence to output when we do */ - struct color_ext_type *next; /* Next in list */ - }; - -static struct bin_str color_indicator[] = - { - { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */ - { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ - { 0, NULL }, /* ec: End color (replaces lc+no+rc) */ - { LEN_STR_PAIR ("0") }, /* no: Normal */ - { LEN_STR_PAIR ("0") }, /* fi: File: default */ - { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */ - { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */ - { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */ - { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */ - { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */ - { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */ - { 0, NULL }, /* mi: Missing file: undefined */ - { 0, NULL }, /* or: Orphanned symlink: undefined */ - { LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */ - { LEN_STR_PAIR ("01;35") } /* do: Door: bright magenta */ - }; - -/* FIXME: comment */ -static struct color_ext_type *color_ext_list = NULL; - -/* Buffer for color sequences */ -static char *color_buf; - -/* Nonzero means to check for orphaned symbolic link, for displaying - colors. */ - -static int check_symlink_color; - -/* Nonzero means mention the inode number of each file. -i */ - -static int print_inode; - -/* Nonzero means when a symbolic link is found, display info on - the file linked to. -L */ - -static int trace_links; - -/* Nonzero means when a directory is found, display info on its - contents. -R */ - -static int trace_dirs; - -/* Nonzero means when an argument is a directory name, display info - on it itself. -d */ - -static int immediate_dirs; - -/* Nonzero means don't omit files whose names start with `.'. -A */ - -static int all_files; - -/* Nonzero means don't omit files `.' and `..' - This flag implies `all_files'. -a */ - -static int really_all_files; - -/* A linked list of shell-style globbing patterns. If a non-argument - file name matches any of these patterns, it is omitted. - Controlled by -I. Multiple -I options accumulate. - The -B option adds `*~' and `.*~' to this list. */ - -struct ignore_pattern - { - const char *pattern; - struct ignore_pattern *next; - }; - -static struct ignore_pattern *ignore_patterns; - -/* Nonzero means output nongraphic chars in file names as `?'. - (-q, --hide-control-chars) - qmark_funny_chars and the quoting style (-Q, --quoting-style=WORD) are - independent. The algorithm is: first, obey the quoting style to get a - string representing the file name; then, if qmark_funny_chars is set, - replace all nonprintable chars in that string with `?'. It's necessary - to replace nonprintable chars even in quoted strings, because we don't - want to mess up the terminal if control chars get sent to it, and some - quoting methods pass through control chars as-is. */ -static int qmark_funny_chars; - -/* Quoting options for file and dir name output. */ - -static struct quoting_options *filename_quoting_options; -static struct quoting_options *dirname_quoting_options; - -/* The number of chars per hardware tab stop. Setting this to zero - inhibits the use of TAB characters for separating columns. -T */ -static int tabsize; - -/* Nonzero means we are listing the working directory because no - non-option arguments were given. */ - -static int dir_defaulted; - -/* Nonzero means print each directory name before listing it. */ - -static int print_dir_name; - -/* The line length to use for breaking lines in many-per-line format. - Can be set with -w. */ - -static int line_length; - -/* If nonzero, the file listing format requires that stat be called on - each file. */ - -static int format_needs_stat; - -/* Similar to `format_needs_stat', but set if only the file type is - needed. */ - -static int format_needs_type; - -/* strftime formats for non-recent and recent files, respectively, in - -l output. */ - -static char const *long_time_format[2]; - -/* The exit status to use if we don't get any fatal errors. */ - -static int exit_status; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - BLOCK_SIZE_OPTION = CHAR_MAX + 1, - COLOR_OPTION, - FORMAT_OPTION, - FULL_TIME_OPTION, - INDICATOR_STYLE_OPTION, - QUOTING_STYLE_OPTION, - SHOW_CONTROL_CHARS_OPTION, - SI_OPTION, - SORT_OPTION, - TIME_OPTION -}; - -static struct option const long_options[] = -{ - {"all", no_argument, 0, 'a'}, - {"escape", no_argument, 0, 'b'}, - {"directory", no_argument, 0, 'd'}, - {"dired", no_argument, 0, 'D'}, - {"full-time", no_argument, 0, FULL_TIME_OPTION}, - {"human-readable", no_argument, 0, 'h'}, - {"inode", no_argument, 0, 'i'}, - {"kilobytes", no_argument, 0, 'k'}, - {"numeric-uid-gid", no_argument, 0, 'n'}, - {"no-group", no_argument, 0, 'G'}, - {"hide-control-chars", no_argument, 0, 'q'}, - {"reverse", no_argument, 0, 'r'}, - {"size", no_argument, 0, 's'}, - {"width", required_argument, 0, 'w'}, - {"almost-all", no_argument, 0, 'A'}, - {"ignore-backups", no_argument, 0, 'B'}, - {"classify", no_argument, 0, 'F'}, - {"file-type", no_argument, 0, 'p'}, - {"si", no_argument, 0, SI_OPTION}, - {"ignore", required_argument, 0, 'I'}, - {"indicator-style", required_argument, 0, INDICATOR_STYLE_OPTION}, - {"dereference", no_argument, 0, 'L'}, - {"literal", no_argument, 0, 'N'}, - {"quote-name", no_argument, 0, 'Q'}, - {"quoting-style", required_argument, 0, QUOTING_STYLE_OPTION}, - {"recursive", no_argument, 0, 'R'}, - {"format", required_argument, 0, FORMAT_OPTION}, - {"show-control-chars", no_argument, 0, SHOW_CONTROL_CHARS_OPTION}, - {"sort", required_argument, 0, SORT_OPTION}, - {"tabsize", required_argument, 0, 'T'}, - {"time", required_argument, 0, TIME_OPTION}, - {"color", optional_argument, 0, COLOR_OPTION}, - {"block-size", required_argument, 0, BLOCK_SIZE_OPTION}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -static char const *const format_args[] = -{ - "verbose", "long", "commas", "horizontal", "across", - "vertical", "single-column", 0 -}; - -static enum format const format_types[] = -{ - long_format, long_format, with_commas, horizontal, horizontal, - many_per_line, one_per_line -}; - -static char const *const sort_args[] = -{ - "none", "time", "size", "extension", "version", 0 -}; - -static enum sort_type const sort_types[] = -{ - sort_none, sort_time, sort_size, sort_extension, sort_version -}; - -static char const *const time_args[] = -{ - "atime", "access", "use", "ctime", "status", 0 -}; - -static enum time_type const time_types[] = -{ - time_atime, time_atime, time_atime, time_ctime, time_ctime -}; - -static char const *const color_args[] = -{ - /* force and none are for compatibility with another color-ls version */ - "always", "yes", "force", - "never", "no", "none", - "auto", "tty", "if-tty", 0 -}; - -static enum color_type const color_types[] = -{ - color_always, color_always, color_always, - color_never, color_never, color_never, - color_if_tty, color_if_tty, color_if_tty -}; - -/* Information about filling a column. */ -struct column_info -{ - int valid_len; - int line_len; - int *col_arr; -}; - -/* Array with information about column filledness. */ -static struct column_info *column_info; - -/* Maximum number of columns ever possible for this display. */ -static int max_idx; - -/* The minimum width of a colum is 3: 1 character for the name and 2 - for the separating white space. */ -#define MIN_COLUMN_WIDTH 3 - - -/* This zero-based index is used solely with the --dired option. - When that option is in effect, this counter is incremented for each - character of output generated by this program so that the beginning - and ending indices (in that output) of every file name can be recorded - and later output themselves. */ -static size_t dired_pos; - -#define DIRED_PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0) - -/* Write S to STREAM and increment DIRED_POS by S_LEN. */ -#define DIRED_FPUTS(s, stream, s_len) \ - do {fputs ((s), (stream)); dired_pos += s_len;} while (0) - -/* Like DIRED_FPUTS, but for use when S is a literal string. */ -#define DIRED_FPUTS_LITERAL(s, stream) \ - do {fputs ((s), (stream)); dired_pos += sizeof((s)) - 1;} while (0) - -#define DIRED_INDENT() \ - do \ - { \ - /* FIXME: remove the `&& format == long_format' clause. */ \ - if (dired && format == long_format) \ - DIRED_FPUTS_LITERAL (" ", stdout); \ - } \ - while (0) - -/* With --dired, store pairs of beginning and ending indices of filenames. */ -static struct obstack dired_obstack; - -/* With --dired, store pairs of beginning and ending indices of any - directory names that appear as headers (just before `total' line) - for lists of directory entries. Such directory names are seen when - listing hierarchies using -R and when a directory is listed with at - least one other command line argument. */ -static struct obstack subdired_obstack; - -/* Save the current index on the specified obstack, OBS. */ -#define PUSH_CURRENT_DIRED_POS(obs) \ - do \ - { \ - /* FIXME: remove the `&& format == long_format' clause. */ \ - if (dired && format == long_format) \ - obstack_grow ((obs), &dired_pos, sizeof (dired_pos)); \ - } \ - while (0) - - -/* Write to standard output PREFIX, followed by the quoting style and - a space-separated list of the integers stored in OS all on one line. */ - -static void -dired_dump_obstack (const char *prefix, struct obstack *os) -{ - int n_pos; - - n_pos = obstack_object_size (os) / sizeof (dired_pos); - if (n_pos > 0) - { - int i; - size_t *pos; - - pos = (size_t *) obstack_finish (os); - fputs (prefix, stdout); - for (i = 0; i < n_pos; i++) - printf (" %d", (int) pos[i]); - fputs ("\n", stdout); - } -} - -int -main (int argc, char **argv) -{ - register int i; - register struct pending *thispend; - unsigned int n_files; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - -#define N_ENTRIES(Array) (sizeof Array / sizeof *(Array)) - assert (N_ENTRIES (color_indicator) + 1 == N_ENTRIES (indicator_name)); - - exit_status = 0; - dir_defaulted = 1; - print_dir_name = 1; - pending_dirs = 0; - - i = decode_switches (argc, argv); - - if (print_with_color) - { - parse_ls_color (); - prep_non_filename_text (); - /* Avoid following symbolic links when possible. */ - if (color_indicator[C_ORPHAN].string != NULL - || (color_indicator[C_MISSING].string != NULL - && format == long_format)) - check_symlink_color = 1; - } - - format_needs_stat = sort_type == sort_time || sort_type == sort_size - || format == long_format - || trace_links || trace_dirs || print_block_size || print_inode; - format_needs_type = (format_needs_stat == 0 - && (print_with_color || indicator_style != none)); - - if (dired && format == long_format) - { - obstack_init (&dired_obstack); - obstack_init (&subdired_obstack); - } - - nfiles = 100; - files = (struct fileinfo *) xmalloc (sizeof (struct fileinfo) * nfiles); - files_index = 0; - - clear_files (); - - n_files = argc - i; - if (0 < n_files) - dir_defaulted = 0; - - for (; i < argc; i++) - { - gobble_file (argv[i], unknown, 1, ""); - } - - if (dir_defaulted) - { - if (immediate_dirs) - gobble_file (".", directory, 1, ""); - else - queue_directory (".", 0); - } - - if (files_index) - { - sort_files (); - if (!immediate_dirs) - extract_dirs_from_files ("", 0); - /* `files_index' might be zero now. */ - } - if (files_index) - { - print_current_files (); - if (pending_dirs) - DIRED_PUTCHAR ('\n'); - } - else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0) - print_dir_name = 0; - - while (pending_dirs) - { - thispend = pending_dirs; - pending_dirs = pending_dirs->next; - print_dir (thispend->name, thispend->realname); - free (thispend->name); - if (thispend->realname) - free (thispend->realname); - free (thispend); - print_dir_name = 1; - } - - if (dired && format == long_format) - { - /* No need to free these since we're about to exit. */ - dired_dump_obstack ("//DIRED//", &dired_obstack); - dired_dump_obstack ("//SUBDIRED//", &subdired_obstack); - printf ("//DIRED-OPTIONS// --quoting-style=%s\n", - ARGMATCH_TO_ARGUMENT (filename_quoting_options, - quoting_style_args, quoting_style_vals)); - } - - /* Restore default color before exiting */ - if (print_with_color) - { - put_indicator (&color_indicator[C_LEFT]); - put_indicator (&color_indicator[C_RIGHT]); - } - - exit (exit_status); -} - -/* Set all the option flags according to the switches specified. - Return the index of the first non-option argument. */ - -static int -decode_switches (int argc, char **argv) -{ - register char const *p; - int c; - int i; - long int tmp_long; - - /* Record whether there is an option specifying sort type. */ - int sort_type_specified = 0; - - qmark_funny_chars = 0; - - /* initialize all switches to default settings */ - - switch (ls_mode) - { - case LS_MULTI_COL: - /* This is for the `dir' program. */ - format = many_per_line; - set_quoting_style (NULL, escape_quoting_style); - break; - - case LS_LONG_FORMAT: - /* This is for the `vdir' program. */ - format = long_format; - set_quoting_style (NULL, escape_quoting_style); - break; - - case LS_LS: - /* This is for the `ls' program. */ - if (isatty (STDOUT_FILENO)) - { - format = many_per_line; - /* See description of qmark_funny_chars, above. */ - qmark_funny_chars = 1; - } - else - { - format = one_per_line; - qmark_funny_chars = 0; - } - break; - - default: - abort (); - } - - time_type = time_mtime; - full_time = 0; - sort_type = sort_name; - sort_reverse = 0; - numeric_ids = 0; - print_block_size = 0; - indicator_style = none; - print_inode = 0; - trace_links = 0; - trace_dirs = 0; - immediate_dirs = 0; - all_files = 0; - really_all_files = 0; - ignore_patterns = 0; - - /* FIXME: Shouldn't we complain on wrong values? */ - if ((p = getenv ("QUOTING_STYLE")) - && 0 <= (i = ARGCASEMATCH (p, quoting_style_args, quoting_style_vals))) - set_quoting_style (NULL, quoting_style_vals[i]); - - human_block_size (getenv ("LS_BLOCK_SIZE"), 0, &output_block_size); - - line_length = 80; - if ((p = getenv ("COLUMNS")) && *p) - { - if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK - && 0 < tmp_long && tmp_long <= INT_MAX) - { - line_length = (int) tmp_long; - } - else - { - error (0, 0, - _("ignoring invalid width in environment variable COLUMNS: %s"), - quotearg (p)); - } - } - -#ifdef TIOCGWINSZ - { - struct winsize ws; - - if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) - line_length = ws.ws_col; - } -#endif - - /* Using the TABSIZE environment variable is not POSIX-approved. - Ignore it when POSIXLY_CORRECT is set. */ - tabsize = 8; - if (!getenv ("POSIXLY_CORRECT") && (p = getenv ("TABSIZE"))) - { - if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK - && 0 <= tmp_long && tmp_long <= INT_MAX) - { - tabsize = (int) tmp_long; - } - else - { - error (0, 0, - _("ignoring invalid tab size in environment variable TABSIZE: %s"), - quotearg (p)); - } - } - - while ((c = getopt_long (argc, argv, - "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1", - long_options, NULL)) != -1) - { - switch (c) - { - case 0: - break; - - case 'a': - all_files = 1; - really_all_files = 1; - break; - - case 'b': - set_quoting_style (NULL, escape_quoting_style); - break; - - case 'c': - time_type = time_ctime; - break; - - case 'd': - immediate_dirs = 1; - break; - - case 'f': - /* Same as enabling -a -U and disabling -l -s. */ - all_files = 1; - really_all_files = 1; - sort_type = sort_none; - sort_type_specified = 1; - /* disable -l */ - if (format == long_format) - format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line); - print_block_size = 0; /* disable -s */ - print_with_color = 0; /* disable --color */ - break; - - case 'g': - /* No effect. For BSD compatibility. */ - break; - - case 'h': - output_block_size = -1024; - break; - - case 'H': - error (0, 0, - _("\ -Warning: the meaning of `-H' will change in the future to conform to POSIX.\n\ -Use `--si' for the old meaning.")); - /* Fall through. */ - case SI_OPTION: - output_block_size = -1000; - break; - - case 'i': - print_inode = 1; - break; - - case 'k': - output_block_size = 1024; - break; - - case 'l': - format = long_format; - break; - - case 'm': - format = with_commas; - break; - - case 'n': - numeric_ids = 1; - break; - - case 'o': /* Just like -l, but don't display group info. */ - format = long_format; - inhibit_group = 1; - break; - - case 'p': - indicator_style = file_type; - break; - - case 'q': - qmark_funny_chars = 1; - break; - - case 'r': - sort_reverse = 1; - break; - - case 's': - print_block_size = 1; - break; - - case 't': - sort_type = sort_time; - sort_type_specified = 1; - break; - - case 'u': - time_type = time_atime; - break; - - case 'v': - sort_type = sort_version; - sort_type_specified = 1; - break; - - case 'w': - if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK - || tmp_long <= 0 || tmp_long > INT_MAX) - error (EXIT_FAILURE, 0, _("invalid line width: %s"), - quotearg (optarg)); - line_length = (int) tmp_long; - break; - - case 'x': - format = horizontal; - break; - - case 'A': - really_all_files = 0; - all_files = 1; - break; - - case 'B': - add_ignore_pattern ("*~"); - add_ignore_pattern (".*~"); - break; - - case 'C': - format = many_per_line; - break; - - case 'D': - dired = 1; - break; - - case 'F': - indicator_style = classify; - break; - - case 'G': /* inhibit display of group info */ - inhibit_group = 1; - break; - - case 'I': - add_ignore_pattern (optarg); - break; - - case 'L': - trace_links = 1; - break; - - case 'N': - set_quoting_style (NULL, literal_quoting_style); - break; - - case 'Q': - set_quoting_style (NULL, c_quoting_style); - break; - - case 'R': - trace_dirs = 1; - break; - - case 'S': - sort_type = sort_size; - sort_type_specified = 1; - break; - - case 'T': - if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK - || tmp_long < 0 || tmp_long > INT_MAX) - error (EXIT_FAILURE, 0, _("invalid tab size: %s"), - quotearg (optarg)); - tabsize = (int) tmp_long; - break; - - case 'U': - sort_type = sort_none; - sort_type_specified = 1; - break; - - case 'X': - sort_type = sort_extension; - sort_type_specified = 1; - break; - - case '1': - /* -1 has no effect after -l. */ - if (format != long_format) - format = one_per_line; - break; - - case SORT_OPTION: - sort_type = XARGMATCH ("--sort", optarg, sort_args, sort_types); - sort_type_specified = 1; - break; - - case TIME_OPTION: - time_type = XARGMATCH ("--time", optarg, time_args, time_types); - break; - - case FORMAT_OPTION: - format = XARGMATCH ("--format", optarg, format_args, format_types); - break; - - case FULL_TIME_OPTION: - format = long_format; - full_time = 1; - break; - - case COLOR_OPTION: - if (optarg) - i = XARGMATCH ("--color", optarg, color_args, color_types); - else - /* Using --color with no argument is equivalent to using - --color=always. */ - i = color_always; - - print_with_color = (i == color_always - || (i == color_if_tty - && isatty (STDOUT_FILENO))); - - if (print_with_color) - { - /* Don't use TAB characters in output. Some terminal - emulators can't handle the combination of tabs and - color codes on the same line. */ - tabsize = 0; - } - break; - - case INDICATOR_STYLE_OPTION: - indicator_style = XARGMATCH ("--indicator-style", optarg, - indicator_style_args, - indicator_style_types); - break; - - case QUOTING_STYLE_OPTION: - set_quoting_style (NULL, - XARGMATCH ("--quoting-style", optarg, - quoting_style_args, - quoting_style_vals)); - break; - - case SHOW_CONTROL_CHARS_OPTION: - qmark_funny_chars = 0; - break; - - case BLOCK_SIZE_OPTION: - human_block_size (optarg, 1, &output_block_size); - break; - - case_GETOPT_HELP_CHAR; - - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - - default: - usage (EXIT_FAILURE); - } - } - - filename_quoting_options = clone_quoting_options (NULL); - if (get_quoting_style (filename_quoting_options) == escape_quoting_style) - set_char_quoting (filename_quoting_options, ' ', 1); - if (indicator_style != none) - for (p = "*=@|" + (int) indicator_style - 1; *p; p++) - set_char_quoting (filename_quoting_options, *p, 1); - - dirname_quoting_options = clone_quoting_options (NULL); - set_char_quoting (dirname_quoting_options, ':', 1); - - /* If -c or -u is specified and not -l (or any other option that implies -l), - and no sort-type was specified, then sort by the ctime (-c) or atime (-u). - The behavior of ls when using either -c or -u but with neither -l nor -t - appears to be unspecified by POSIX. So, with GNU ls, `-u' alone means - sort by atime (this is the one that's not specified by the POSIX spec), - -lu means show atime and sort by name, -lut means show atime and sort - by atime. */ - - if ((time_type == time_ctime || time_type == time_atime) - && !sort_type_specified && format != long_format) - { - sort_type = sort_time; - } - - if (format == long_format) - { - if (full_time) - long_time_format[0] = long_time_format[1] = - dcgettext (NULL, "%a %b %d %H:%M:%S %Y", LC_TIME); - else - { - long_time_format[0] = dcgettext (NULL, "%b %e %Y", LC_TIME); - long_time_format[1] = dcgettext (NULL, "%b %e %H:%M", LC_TIME); - } - } - - return optind; -} - -/* Parse a string as part of the LS_COLORS variable; this may involve - decoding all kinds of escape characters. If equals_end is set an - unescaped equal sign ends the string, otherwise only a : or \0 - does. Returns the number of characters output, or -1 on failure. - - The resulting string is *not* null-terminated, but may contain - embedded nulls. - - Note that both dest and src are char **; on return they point to - the first free byte after the array and the character that ended - the input string, respectively. */ - -static int -get_funky_string (char **dest, const char **src, int equals_end) -{ - int num; /* For numerical codes */ - int count; /* Something to count with */ - enum { - ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR - } state; - const char *p; - char *q; - - p = *src; /* We don't want to double-indirect */ - q = *dest; /* the whole darn time. */ - - count = 0; /* No characters counted in yet. */ - num = 0; - - state = ST_GND; /* Start in ground state. */ - while (state < ST_END) - { - switch (state) - { - case ST_GND: /* Ground state (no escapes) */ - switch (*p) - { - case ':': - case '\0': - state = ST_END; /* End of string */ - break; - case '\\': - state = ST_BACKSLASH; /* Backslash scape sequence */ - ++p; - break; - case '^': - state = ST_CARET; /* Caret escape */ - ++p; - break; - case '=': - if (equals_end) - { - state = ST_END; /* End */ - break; - } - /* else fall through */ - default: - *(q++) = *(p++); - ++count; - break; - } - break; - - case ST_BACKSLASH: /* Backslash escaped character */ - switch (*p) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - state = ST_OCTAL; /* Octal sequence */ - num = *p - '0'; - break; - case 'x': - case 'X': - state = ST_HEX; /* Hex sequence */ - num = 0; - break; - case 'a': /* Bell */ - num = 7; /* Not all C compilers know what \a means */ - break; - case 'b': /* Backspace */ - num = '\b'; - break; - case 'e': /* Escape */ - num = 27; - break; - case 'f': /* Form feed */ - num = '\f'; - break; - case 'n': /* Newline */ - num = '\n'; - break; - case 'r': /* Carriage return */ - num = '\r'; - break; - case 't': /* Tab */ - num = '\t'; - break; - case 'v': /* Vtab */ - num = '\v'; - break; - case '?': /* Delete */ - num = 127; - break; - case '_': /* Space */ - num = ' '; - break; - case '\0': /* End of string */ - state = ST_ERROR; /* Error! */ - break; - default: /* Escaped character like \ ^ : = */ - num = *p; - break; - } - if (state == ST_BACKSLASH) - { - *(q++) = num; - ++count; - state = ST_GND; - } - ++p; - break; - - case ST_OCTAL: /* Octal sequence */ - if (*p < '0' || *p > '7') - { - *(q++) = num; - ++count; - state = ST_GND; - } - else - num = (num << 3) + (*(p++) - '0'); - break; - - case ST_HEX: /* Hex sequence */ - switch (*p) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - num = (num << 4) + (*(p++) - '0'); - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - num = (num << 4) + (*(p++) - 'a') + 10; - break; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - num = (num << 4) + (*(p++) - 'A') + 10; - break; - default: - *(q++) = num; - ++count; - state = ST_GND; - break; - } - break; - - case ST_CARET: /* Caret escape */ - state = ST_GND; /* Should be the next state... */ - if (*p >= '@' && *p <= '~') - { - *(q++) = *(p++) & 037; - ++count; - } - else if (*p == '?') - { - *(q++) = 127; - ++count; - } - else - state = ST_ERROR; - break; - - default: - abort (); - } - } - - *dest = q; - *src = p; - - return state == ST_ERROR ? -1 : count; -} - -static void -parse_ls_color (void) -{ - const char *p; /* Pointer to character being parsed */ - char *buf; /* color_buf buffer pointer */ - int state; /* State of parser */ - int ind_no; /* Indicator number */ - char label[3]; /* Indicator label */ - struct color_ext_type *ext; /* Extension we are working on */ - - if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0') - return; - - ext = NULL; - strcpy (label, "??"); - - /* This is an overly conservative estimate, but any possible - LS_COLORS string will *not* generate a color_buf longer than - itself, so it is a safe way of allocating a buffer in - advance. */ - buf = color_buf = xstrdup (p); - - state = 1; - while (state > 0) - { - switch (state) - { - case 1: /* First label character */ - switch (*p) - { - case ':': - ++p; - break; - - case '*': - /* Allocate new extension block and add to head of - linked list (this way a later definition will - override an earlier one, which can be useful for - having terminal-specific defs override global). */ - - ext = (struct color_ext_type *) - xmalloc (sizeof (struct color_ext_type)); - ext->next = color_ext_list; - color_ext_list = ext; - - ++p; - ext->ext.string = buf; - - state = (ext->ext.len = - get_funky_string (&buf, &p, 1)) < 0 ? -1 : 4; - break; - - case '\0': - state = 0; /* Done! */ - break; - - default: /* Assume it is file type label */ - label[0] = *(p++); - state = 2; - break; - } - break; - - case 2: /* Second label character */ - if (*p) - { - label[1] = *(p++); - state = 3; - } - else - state = -1; /* Error */ - break; - - case 3: /* Equal sign after indicator label */ - state = -1; /* Assume failure... */ - if (*(p++) == '=')/* It *should* be... */ - { - for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) - { - if (STREQ (label, indicator_name[ind_no])) - { - color_indicator[ind_no].string = buf; - state = ((color_indicator[ind_no].len = - get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1); - break; - } - } - if (state == -1) - error (0, 0, _("unrecognized prefix: %s"), quotearg (label)); - } - break; - - case 4: /* Equal sign after *.ext */ - if (*(p++) == '=') - { - ext->seq.string = buf; - state = (ext->seq.len = - get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1; - } - else - state = -1; - break; - } - } - - if (state < 0) - { - struct color_ext_type *e; - struct color_ext_type *e2; - - error (0, 0, - _("unparsable value for LS_COLORS environment variable")); - free (color_buf); - for (e = color_ext_list; e != NULL; /* empty */) - { - e2 = e; - e = e->next; - free (e2); - } - print_with_color = 0; - } - - if (color_indicator[C_LINK].len == 6 - && !strncmp (color_indicator[C_LINK].string, "target", 6)) - color_symlink_as_referent = 1; -} - -/* Request that the directory named `name' have its contents listed later. - If `realname' is nonzero, it will be used instead of `name' when the - directory name is printed. This allows symbolic links to directories - to be treated as regular directories but still be listed under their - real names. */ - -static void -queue_directory (const char *name, const char *realname) -{ - struct pending *new; - - new = (struct pending *) xmalloc (sizeof (struct pending)); - new->next = pending_dirs; - pending_dirs = new; - new->name = xstrdup (name); - if (realname) - new->realname = xstrdup (realname); - else - new->realname = 0; -} - -/* Read directory `name', and list the files in it. - If `realname' is nonzero, print its name instead of `name'; - this is used for symbolic links to directories. */ - -static void -print_dir (const char *name, const char *realname) -{ - register DIR *reading; - register struct dirent *next; - register uintmax_t total_blocks = 0; - - errno = 0; - reading = opendir (name); - if (!reading) - { - error (0, errno, "%s", quotearg_colon (name)); - exit_status = 1; - return; - } - - /* Read the directory entries, and insert the subfiles into the `files' - table. */ - - clear_files (); - - while ((next = readdir (reading)) != NULL) - if (file_interesting (next)) - { - enum filetype type = unknown; - -#if HAVE_STRUCT_DIRENT_D_TYPE - if (next->d_type == DT_DIR || next->d_type == DT_CHR - || next->d_type == DT_BLK || next->d_type == DT_SOCK - || next->d_type == DT_FIFO) - type = next->d_type; -#endif - total_blocks += gobble_file (next->d_name, type, 0, name); - } - - if (CLOSEDIR (reading)) - { - error (0, errno, "%s", quotearg_colon (name)); - exit_status = 1; - /* Don't return; print whatever we got. */ - } - - /* Sort the directory contents. */ - sort_files (); - - /* If any member files are subdirectories, perhaps they should have their - contents listed rather than being mentioned here as files. */ - - if (trace_dirs) - extract_dirs_from_files (name, 1); - - if (trace_dirs || print_dir_name) - { - DIRED_INDENT (); - PUSH_CURRENT_DIRED_POS (&subdired_obstack); - dired_pos += quote_name (stdout, realname ? realname : name, - dirname_quoting_options); - PUSH_CURRENT_DIRED_POS (&subdired_obstack); - DIRED_FPUTS_LITERAL (":\n", stdout); - } - - if (format == long_format || print_block_size) - { - const char *p; - char buf[LONGEST_HUMAN_READABLE + 1]; - - DIRED_INDENT (); - p = _("total"); - DIRED_FPUTS (p, stdout, strlen (p)); - DIRED_PUTCHAR (' '); - p = human_readable_inexact (total_blocks, buf, ST_NBLOCKSIZE, - output_block_size, human_ceiling); - DIRED_FPUTS (p, stdout, strlen (p)); - DIRED_PUTCHAR ('\n'); - } - - if (files_index) - print_current_files (); - - if (pending_dirs) - DIRED_PUTCHAR ('\n'); -} - -/* Add `pattern' to the list of patterns for which files that match are - not listed. */ - -static void -add_ignore_pattern (const char *pattern) -{ - register struct ignore_pattern *ignore; - - ignore = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern)); - ignore->pattern = pattern; - /* Add it to the head of the linked list. */ - ignore->next = ignore_patterns; - ignore_patterns = ignore; -} - -/* Return nonzero if the file in `next' should be listed. */ - -static int -file_interesting (const struct dirent *next) -{ - register struct ignore_pattern *ignore; - - for (ignore = ignore_patterns; ignore; ignore = ignore->next) - if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0) - return 0; - - if (really_all_files - || next->d_name[0] != '.' - || (all_files - && next->d_name[1] != '\0' - && (next->d_name[1] != '.' || next->d_name[2] != '\0'))) - return 1; - - return 0; -} - -/* Enter and remove entries in the table `files'. */ - -/* Empty the table of files. */ - -static void -clear_files (void) -{ - register int i; - - for (i = 0; i < files_index; i++) - { - free (files[i].name); - if (files[i].linkname) - free (files[i].linkname); - } - - files_index = 0; - block_size_size = 4; -} - -/* Add a file to the current table of files. - Verify that the file exists, and print an error message if it does not. - Return the number of blocks that the file occupies. */ - -static uintmax_t -gobble_file (const char *name, enum filetype type, int explicit_arg, - const char *dirname) -{ - register uintmax_t blocks; - register char *path; - - if (files_index == nfiles) - { - nfiles *= 2; - files = (struct fileinfo *) xrealloc ((char *) files, - sizeof (*files) * nfiles); - } - - files[files_index].linkname = 0; - files[files_index].linkmode = 0; - files[files_index].linkok = 0; - - /* FIXME: this use of ls: `mkdir a; touch a/{b,c,d}; ls -R a' - shouldn't require that ls stat b, c, and d -- at least - not on systems with usable d_type. The problem is that - format_needs_stat is set, because of the -R. */ - if (explicit_arg || format_needs_stat - || (format_needs_type && type == unknown)) - { - /* `path' is the absolute pathname of this file. */ - int val; - - if (name[0] == '/' || dirname[0] == 0) - path = (char *) name; - else - { - path = (char *) alloca (strlen (name) + strlen (dirname) + 2); - attach (path, dirname, name); - } - - val = (trace_links - ? stat (path, &files[files_index].stat) - : lstat (path, &files[files_index].stat)); - - if (val < 0) - { - error (0, errno, "%s", quotearg_colon (path)); - exit_status = 1; - return 0; - } - -#if USE_ACL - if (format == long_format) - files[files_index].have_acl = - (! S_ISLNK (files[files_index].stat.st_mode) - && 4 < acl (path, GETACLCNT, 0, NULL)); -#endif - - if (S_ISLNK (files[files_index].stat.st_mode) - && (explicit_arg || format == long_format || check_symlink_color)) - { - char *linkpath; - struct stat linkstats; - - get_link_name (path, &files[files_index]); - linkpath = make_link_path (path, files[files_index].linkname); - - /* Avoid following symbolic links when possible, ie, when - they won't be traced and when no indicator is needed. */ - if (linkpath - && ((explicit_arg && format != long_format) - || indicator_style != none - || check_symlink_color) - && stat (linkpath, &linkstats) == 0) - { - files[files_index].linkok = 1; - - /* Symbolic links to directories that are mentioned on the - command line are automatically traced if not being - listed as files. */ - if (explicit_arg && format != long_format - && S_ISDIR (linkstats.st_mode)) - { - /* Substitute the linked-to directory's name, but - save the real name in `linkname' for printing. */ - if (!immediate_dirs) - { - const char *tempname = name; - name = linkpath; - linkpath = files[files_index].linkname; - files[files_index].linkname = (char *) tempname; - } - files[files_index].stat = linkstats; - } - else - { - /* Get the linked-to file's mode for the filetype indicator - in long listings. */ - files[files_index].linkmode = linkstats.st_mode; - files[files_index].linkok = 1; - } - } - if (linkpath) - free (linkpath); - } - - if (S_ISLNK (files[files_index].stat.st_mode)) - files[files_index].filetype = symbolic_link; - else if (S_ISDIR (files[files_index].stat.st_mode)) - { - if (explicit_arg && !immediate_dirs) - files[files_index].filetype = arg_directory; - else - files[files_index].filetype = directory; - } - else - files[files_index].filetype = normal; - - blocks = ST_NBLOCKS (files[files_index].stat); - { - char buf[LONGEST_HUMAN_READABLE + 1]; - int len = strlen (human_readable_inexact (blocks, buf, ST_NBLOCKSIZE, - output_block_size, - human_ceiling)); - if (block_size_size < len) - block_size_size = len < 7 ? len : 7; - } - } - else - { - files[files_index].filetype = type; -#if HAVE_STRUCT_DIRENT_D_TYPE - files[files_index].stat.st_mode = DTTOIF (type); -#endif - blocks = 0; - } - - files[files_index].name = xstrdup (name); - files_index++; - - return blocks; -} - -#if HAVE_SYMLINKS - -/* Put the name of the file that `filename' is a symbolic link to - into the `linkname' field of `f'. */ - -static void -get_link_name (const char *filename, struct fileinfo *f) -{ - char *linkbuf; - register int linksize; - - linkbuf = (char *) alloca (PATH_MAX + 2); - /* Some automounters give incorrect st_size for mount points. - I can't think of a good workaround for it, though. */ - linksize = readlink (filename, linkbuf, PATH_MAX + 1); - if (linksize < 0) - { - error (0, errno, "%s", quotearg_colon (filename)); - exit_status = 1; - } - else - { - linkbuf[linksize] = '\0'; - f->linkname = xstrdup (linkbuf); - } -} - -/* If `linkname' is a relative path and `path' contains one or more - leading directories, return `linkname' with those directories - prepended; otherwise, return a copy of `linkname'. - If `linkname' is zero, return zero. */ - -static char * -make_link_path (const char *path, const char *linkname) -{ - char *linkbuf; - int bufsiz; - - if (linkname == 0) - return 0; - - if (*linkname == '/') - return xstrdup (linkname); - - /* The link is to a relative path. Prepend any leading path - in `path' to the link name. */ - linkbuf = strrchr (path, '/'); - if (linkbuf == 0) - return xstrdup (linkname); - - bufsiz = linkbuf - path + 1; - linkbuf = xmalloc (bufsiz + strlen (linkname) + 1); - strncpy (linkbuf, path, bufsiz); - strcpy (linkbuf + bufsiz, linkname); - return linkbuf; -} -#endif - -/* Return nonzero if base_name (NAME) ends in `.' or `..' - This is so we don't try to recurse on `././././. ...' */ - -static int -basename_is_dot_or_dotdot (const char *name) -{ - char *base = base_name (name); - return DOT_OR_DOTDOT (base); -} - -/* Remove any entries from `files' that are for directories, - and queue them to be listed as directories instead. - `dirname' is the prefix to prepend to each dirname - to make it correct relative to ls's working dir. - `recursive' is nonzero if we should not treat `.' and `..' as dirs. - This is desirable when processing directories recursively. */ - -static void -extract_dirs_from_files (const char *dirname, int recursive) -{ - register int i, j; - - /* Queue the directories last one first, because queueing reverses the - order. */ - for (i = files_index - 1; i >= 0; i--) - if ((files[i].filetype == directory || files[i].filetype == arg_directory) - && (!recursive || !basename_is_dot_or_dotdot (files[i].name))) - { - if (files[i].name[0] == '/' || dirname[0] == 0) - { - queue_directory (files[i].name, files[i].linkname); - } - else - { - char *path = path_concat (dirname, files[i].name, NULL); - queue_directory (path, files[i].linkname); - free (path); - } - if (files[i].filetype == arg_directory) - free (files[i].name); - } - - /* Now delete the directories from the table, compacting all the remaining - entries. */ - - for (i = 0, j = 0; i < files_index; i++) - if (files[i].filetype != arg_directory) - files[j++] = files[i]; - files_index = j; -} - -/* Sort the files now in the table. */ - -static void -sort_files (void) -{ - int (*func) (); - - switch (sort_type) - { - case sort_none: - return; - case sort_time: - switch (time_type) - { - case time_ctime: - func = sort_reverse ? rev_cmp_ctime : compare_ctime; - break; - case time_mtime: - func = sort_reverse ? rev_cmp_mtime : compare_mtime; - break; - case time_atime: - func = sort_reverse ? rev_cmp_atime : compare_atime; - break; - default: - abort (); - } - break; - case sort_name: - func = sort_reverse ? rev_cmp_name : compare_name; - break; - case sort_extension: - func = sort_reverse ? rev_cmp_extension : compare_extension; - break; - case sort_size: - func = sort_reverse ? rev_cmp_size : compare_size; - break; - case sort_version: - func = sort_reverse ? rev_cmp_version : compare_version; - break; - default: - abort (); - } - - qsort (files, files_index, sizeof (struct fileinfo), func); -} - -/* Comparison routines for sorting the files. */ - -static int -compare_ctime (const struct fileinfo *file1, const struct fileinfo *file2) -{ - int diff = CTIME_CMP (file2->stat, file1->stat); - if (diff == 0) - diff = strcoll (file1->name, file2->name); - return diff; -} - -static int -rev_cmp_ctime (const struct fileinfo *file2, const struct fileinfo *file1) -{ - int diff = CTIME_CMP (file2->stat, file1->stat); - if (diff == 0) - diff = strcoll (file1->name, file2->name); - return diff; -} - -static int -compare_mtime (const struct fileinfo *file1, const struct fileinfo *file2) -{ - int diff = MTIME_CMP (file2->stat, file1->stat); - if (diff == 0) - diff = strcoll (file1->name, file2->name); - return diff; -} - -static int -rev_cmp_mtime (const struct fileinfo *file2, const struct fileinfo *file1) -{ - int diff = MTIME_CMP (file2->stat, file1->stat); - if (diff == 0) - diff = strcoll (file1->name, file2->name); - return diff; -} - -static int -compare_atime (const struct fileinfo *file1, const struct fileinfo *file2) -{ - int diff = ATIME_CMP (file2->stat, file1->stat); - if (diff == 0) - diff = strcoll (file1->name, file2->name); - return diff; -} - -static int -rev_cmp_atime (const struct fileinfo *file2, const struct fileinfo *file1) -{ - int diff = ATIME_CMP (file2->stat, file1->stat); - if (diff == 0) - diff = strcoll (file1->name, file2->name); - return diff; -} - -static int -compare_size (const struct fileinfo *file1, const struct fileinfo *file2) -{ - int diff = longdiff (file2->stat.st_size, file1->stat.st_size); - if (diff == 0) - diff = strcoll (file1->name, file2->name); - return diff; -} - -static int -rev_cmp_size (const struct fileinfo *file2, const struct fileinfo *file1) -{ - int diff = longdiff (file2->stat.st_size, file1->stat.st_size); - if (diff == 0) - diff = strcoll (file1->name, file2->name); - return diff; -} - -static int -compare_version (const struct fileinfo *file1, const struct fileinfo *file2) -{ - return strverscmp (file1->name, file2->name); -} - -static int -rev_cmp_version (const struct fileinfo *file2, const struct fileinfo *file1) -{ - return strverscmp (file1->name, file2->name); -} - -static int -compare_name (const struct fileinfo *file1, const struct fileinfo *file2) -{ - return strcoll (file1->name, file2->name); -} - -static int -rev_cmp_name (const struct fileinfo *file2, const struct fileinfo *file1) -{ - return strcoll (file1->name, file2->name); -} - -/* Compare file extensions. Files with no extension are `smallest'. - If extensions are the same, compare by filenames instead. */ - -static int -compare_extension (const struct fileinfo *file1, const struct fileinfo *file2) -{ - register char *base1, *base2; - register int cmp; - - base1 = strrchr (file1->name, '.'); - base2 = strrchr (file2->name, '.'); - if (base1 == 0 && base2 == 0) - return strcoll (file1->name, file2->name); - if (base1 == 0) - return -1; - if (base2 == 0) - return 1; - cmp = strcoll (base1, base2); - if (cmp == 0) - return strcoll (file1->name, file2->name); - return cmp; -} - -static int -rev_cmp_extension (const struct fileinfo *file2, const struct fileinfo *file1) -{ - register char *base1, *base2; - register int cmp; - - base1 = strrchr (file1->name, '.'); - base2 = strrchr (file2->name, '.'); - if (base1 == 0 && base2 == 0) - return strcoll (file1->name, file2->name); - if (base1 == 0) - return -1; - if (base2 == 0) - return 1; - cmp = strcoll (base1, base2); - if (cmp == 0) - return strcoll (file1->name, file2->name); - return cmp; -} - -/* List all the files now in the table. */ - -static void -print_current_files (void) -{ - register int i; - - switch (format) - { - case one_per_line: - for (i = 0; i < files_index; i++) - { - print_file_name_and_frills (files + i); - putchar ('\n'); - } - break; - - case many_per_line: - init_column_info (); - print_many_per_line (); - break; - - case horizontal: - init_column_info (); - print_horizontal (); - break; - - case with_commas: - print_with_commas (); - break; - - case long_format: - for (i = 0; i < files_index; i++) - { - print_long_format (files + i); - DIRED_PUTCHAR ('\n'); - } - break; - } -} - -/* Return the expected number of columns in a long-format time stamp, - or zero if it cannot be calculated. */ - -static int -long_time_expected_width (void) -{ - static int width = -1; - - if (width < 0) - { - time_t epoch = 0; - struct tm const *tm = localtime (&epoch); - char const *fmt = long_time_format[0]; - char initbuf[100]; - char *buf = initbuf; - size_t bufsize = sizeof initbuf; - size_t len; - - for (;;) - { - *buf = '\1'; - len = strftime (buf, bufsize, fmt, tm); - if (len || ! *buf) - break; - buf = alloca (bufsize *= 2); - } - - width = mbsnwidth (buf, len, 0); - if (width < 0) - width = 0; - } - - return width; -} - -/* Get the current time. */ - -static void -get_current_time (void) -{ -#if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME - { - struct timespec timespec; - if (clock_gettime (CLOCK_REALTIME, ×pec) == 0) - { - current_time = timespec.tv_sec; - current_time_ns = timespec.tv_nsec; - return; - } - } -#endif - - /* The clock does not have nanosecond resolution, so get the maximum - possible value for the current time that is consistent with the - reported clock. That way, files are not considered to be in the - future merely because their time stamps have higher resolution - than the clock resolution. */ - -#if HAVE_GETTIMEOFDAY - { - struct timeval timeval; - if (gettimeofday (&timeval, NULL) == 0) - { - current_time = timeval.tv_sec; - current_time_ns = timeval.tv_usec * 1000 + 999; - return; - } - } -#endif - - current_time = time (NULL); - current_time_ns = 999999999; -} - -static void -print_long_format (const struct fileinfo *f) -{ - char modebuf[12]; - - /* 7 fields that may require LONGEST_HUMAN_READABLE bytes, - 1 10-byte mode string, - 1 24-byte time string (may be longer in some locales -- see below) - or LONGEST_HUMAN_READABLE integer, - 9 spaces, one following each of these fields, and - 1 trailing NUL byte. */ - char init_bigbuf[7 * LONGEST_HUMAN_READABLE + 10 - + (LONGEST_HUMAN_READABLE < 24 ? 24 : LONGEST_HUMAN_READABLE) - + 9 + 1]; - char *buf = init_bigbuf; - size_t bufsize = sizeof (init_bigbuf); - size_t s; - char *p; - time_t when; - int when_ns IF_LINT (= 0); - struct tm *when_local; - char *user_name; - -#if HAVE_ST_DM_MODE - /* Cray DMF: look at the file's migrated, not real, status */ - mode_string (f->stat.st_dm_mode, modebuf); -#else - mode_string (f->stat.st_mode, modebuf); -#endif - - modebuf[10] = (FILE_HAS_ACL (f) ? '+' : ' '); - modebuf[11] = '\0'; - - switch (time_type) - { - case time_ctime: - when = f->stat.st_ctime; - when_ns = TIMESPEC_NS (f->stat.st_ctim); - break; - case time_mtime: - when = f->stat.st_mtime; - when_ns = TIMESPEC_NS (f->stat.st_mtim); - break; - case time_atime: - when = f->stat.st_atime; - when_ns = TIMESPEC_NS (f->stat.st_atim); - break; - } - - p = buf; - - if (print_inode) - { - char hbuf[LONGEST_HUMAN_READABLE + 1]; - sprintf (p, "%*s ", INODE_DIGITS, - human_readable ((uintmax_t) f->stat.st_ino, hbuf, 1, 1)); - p += strlen (p); - } - - if (print_block_size) - { - char hbuf[LONGEST_HUMAN_READABLE + 1]; - sprintf (p, "%*s ", block_size_size, - human_readable_inexact ((uintmax_t) ST_NBLOCKS (f->stat), hbuf, - ST_NBLOCKSIZE, output_block_size, - human_ceiling)); - p += strlen (p); - } - - /* The last byte of the mode string is the POSIX - "optional alternate access method flag". */ - sprintf (p, "%s %3u ", modebuf, (unsigned int) f->stat.st_nlink); - p += strlen (p); - - user_name = (numeric_ids ? NULL : getuser (f->stat.st_uid)); - if (user_name) - sprintf (p, "%-8.8s ", user_name); - else - sprintf (p, "%-8u ", (unsigned int) f->stat.st_uid); - p += strlen (p); - - if (!inhibit_group) - { - char *group_name = (numeric_ids ? NULL : getgroup (f->stat.st_gid)); - if (group_name) - sprintf (p, "%-8.8s ", group_name); - else - sprintf (p, "%-8u ", (unsigned int) f->stat.st_gid); - p += strlen (p); - } - - if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)) - sprintf (p, "%3u, %3u ", (unsigned) major (f->stat.st_rdev), - (unsigned) minor (f->stat.st_rdev)); - else - { - char hbuf[LONGEST_HUMAN_READABLE + 1]; - sprintf (p, "%8s ", - human_readable ((uintmax_t) f->stat.st_size, hbuf, 1, - output_block_size < 0 ? output_block_size : 1)); - } - - p += strlen (p); - - if ((when_local = localtime (&when))) - { - time_t six_months_ago; - int recent; - char const *fmt; - - /* If the file appears to be in the future, update the current - time, in case the file happens to have been modified since - the last time we checked the clock. */ - if (current_time < when - || (current_time == when && current_time_ns < when_ns)) - get_current_time (); - - /* Consider a time to be recent if it is within the past six - months. A Gregorian year has 365.2425 * 24 * 60 * 60 == - 31556952 seconds on the average. Write this value as an - integer constant to avoid floating point hassles. */ - six_months_ago = current_time - 31556952 / 2; - recent = (six_months_ago <= when - && (when < current_time - || (when == current_time && when_ns <= current_time_ns))); - fmt = long_time_format[recent]; - - for (;;) - { - char *newbuf; - *p = '\1'; - s = strftime (p, buf + bufsize - p - 1, fmt, when_local); - if (s || ! *p) - break; - newbuf = alloca (bufsize *= 2); - memcpy (newbuf, buf, p - buf); - p = newbuf + (p - buf); - buf = newbuf; - } - - p += s; - *p++ = ' '; - - /* NUL-terminate the string -- fputs (via DIRED_FPUTS) requires it. */ - *p = '\0'; - } - else - { - /* The time cannot be represented as a local time; - print it as a huge integer number of seconds. */ - char hbuf[LONGEST_HUMAN_READABLE + 1]; - int width = long_time_expected_width (); - - if (when < 0) - { - const char *num = human_readable (- (uintmax_t) when, hbuf, 1, 1); - int sign_width = width - strlen (num); - sprintf (p, "%*s%s ", sign_width < 0 ? 0 : sign_width, "-", num); - } - else - sprintf (p, "%*s ", width, - human_readable ((uintmax_t) when, hbuf, 1, 1)); - - p += strlen (p); - } - - DIRED_INDENT (); - DIRED_FPUTS (buf, stdout, p - buf); - print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, - &dired_obstack); - - if (f->filetype == symbolic_link) - { - if (f->linkname) - { - DIRED_FPUTS_LITERAL (" -> ", stdout); - print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1, - NULL); - if (indicator_style != none) - print_type_indicator (f->linkmode); - } - } - else if (indicator_style != none) - print_type_indicator (f->stat.st_mode); -} - -/* Output to OUT a quoted representation of the file name NAME, - using OPTIONS to control quoting. Produce no output if OUT is NULL. - Return the number of screen columns occupied by NAME's quoted - representation. */ - -static size_t -quote_name (FILE *out, const char *name, struct quoting_options const *options) -{ - char smallbuf[BUFSIZ]; - size_t len = quotearg_buffer (smallbuf, sizeof smallbuf, name, -1, options); - char *buf; - int displayed_width; - - if (len < sizeof smallbuf) - buf = smallbuf; - else - { - buf = (char *) alloca (len + 1); - quotearg_buffer (buf, len + 1, name, -1, options); - } - - if (qmark_funny_chars) - { -#if HAVE_MBRTOWC - if (MB_CUR_MAX > 1) - { - const char *p = buf; - char *plimit = buf + len; - char *q = buf; - displayed_width = 0; - - while (p < plimit) - switch (*p) - { - case ' ': case '!': case '"': case '#': case '%': - case '&': case '\'': case '(': case ')': case '*': - case '+': case ',': case '-': case '.': case '/': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case ':': case ';': case '<': case '=': case '>': - case '?': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case '[': case '\\': case ']': case '^': case '_': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': - case 'z': case '{': case '|': case '}': case '~': - /* These characters are printable ASCII characters. */ - *q++ = *p++; - displayed_width += 1; - break; - default: - /* If we have a multibyte sequence, copy it until we - reach its end, replacing each non-printable multibyte - character with a single question mark. */ - { - mbstate_t mbstate; - memset (&mbstate, 0, sizeof mbstate); - do - { - wchar_t wc; - size_t bytes; - int w; - - bytes = mbrtowc (&wc, p, plimit - p, &mbstate); - - if (bytes == (size_t) -1) - { - /* An invalid multibyte sequence was - encountered. Skip one input byte, and - put a question mark. */ - p++; - *q++ = '?'; - displayed_width += 1; - break; - } - - if (bytes == (size_t) -2) - { - /* An incomplete multibyte character - at the end. Replace it entirely with - a question mark. */ - p = plimit; - *q++ = '?'; - displayed_width += 1; - break; - } - - if (bytes == 0) - /* A null wide character was encountered. */ - bytes = 1; - - w = wcwidth (wc); - if (w >= 0) - { - /* A printable multibyte character. - Keep it. */ - for (; bytes > 0; --bytes) - *q++ = *p++; - displayed_width += w; - } - else - { - /* An unprintable multibyte character. - Replace it entirely with a question - mark. */ - p += bytes; - *q++ = '?'; - displayed_width += 1; - } - } - while (! mbsinit (&mbstate)); - } - break; - } - - /* The buffer may have shrunk. */ - len = q - buf; - } - else -#endif - { - char *p = buf; - char *plimit = buf + len; - - while (p < plimit) - { - if (! ISPRINT ((unsigned char) *p)) - *p = '?'; - p++; - } - displayed_width = len; - } - } - else - { - /* Assume unprintable characters have a displayed_width of 1. */ -#if HAVE_MBRTOWC - if (MB_CUR_MAX > 1) - displayed_width = mbsnwidth (buf, len, - (MBSW_ACCEPT_INVALID - | MBSW_ACCEPT_UNPRINTABLE)); - else -#endif - displayed_width = len; - } - - if (out != NULL) - fwrite (buf, 1, len, out); - return displayed_width; -} - -static void -print_name_with_quoting (const char *p, unsigned int mode, int linkok, - struct obstack *stack) -{ - if (print_with_color) - print_color_indicator (p, mode, linkok); - - if (stack) - PUSH_CURRENT_DIRED_POS (stack); - - dired_pos += quote_name (stdout, p, filename_quoting_options); - - if (stack) - PUSH_CURRENT_DIRED_POS (stack); - - if (print_with_color) - prep_non_filename_text (); -} - -static void -prep_non_filename_text (void) -{ - if (color_indicator[C_END].string != NULL) - put_indicator (&color_indicator[C_END]); - else - { - put_indicator (&color_indicator[C_LEFT]); - put_indicator (&color_indicator[C_NORM]); - put_indicator (&color_indicator[C_RIGHT]); - } -} - -/* Print the file name of `f' with appropriate quoting. - Also print file size, inode number, and filetype indicator character, - as requested by switches. */ - -static void -print_file_name_and_frills (const struct fileinfo *f) -{ - char buf[LONGEST_HUMAN_READABLE + 1]; - - if (print_inode) - printf ("%*s ", INODE_DIGITS, - human_readable ((uintmax_t) f->stat.st_ino, buf, 1, 1)); - - if (print_block_size) - printf ("%*s ", block_size_size, - human_readable_inexact ((uintmax_t) ST_NBLOCKS (f->stat), buf, - ST_NBLOCKSIZE, output_block_size, - human_ceiling)); - - print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, NULL); - - if (indicator_style != none) - print_type_indicator (f->stat.st_mode); -} - -static void -print_type_indicator (unsigned int mode) -{ - int c; - - if (S_ISREG (mode)) - { - if (indicator_style == classify && (mode & S_IXUGO)) - c ='*'; - else - c = 0; - } - else - { - if (S_ISDIR (mode)) - c = '/'; - else if (S_ISLNK (mode)) - c = '@'; - else if (S_ISFIFO (mode)) - c = '|'; - else if (S_ISSOCK (mode)) - c = '='; - else if (S_ISDOOR (mode)) - c = '>'; - else - c = 0; - } - - if (c) - DIRED_PUTCHAR (c); -} - -static void -print_color_indicator (const char *name, unsigned int mode, int linkok) -{ - int type = C_FILE; - struct color_ext_type *ext; /* Color extension */ - size_t len; /* Length of name */ - - /* Is this a nonexistent file? If so, linkok == -1. */ - - if (linkok == -1 && color_indicator[C_MISSING].string != NULL) - { - ext = NULL; - type = C_MISSING; - } - else - { - if (S_ISDIR (mode)) - type = C_DIR; - else if (S_ISLNK (mode)) - type = ((!linkok && color_indicator[C_ORPHAN].string) - ? C_ORPHAN : C_LINK); - else if (S_ISFIFO (mode)) - type = C_FIFO; - else if (S_ISSOCK (mode)) - type = C_SOCK; - else if (S_ISBLK (mode)) - type = C_BLK; - else if (S_ISCHR (mode)) - type = C_CHR; - else if (S_ISDOOR (mode)) - type = C_DOOR; - - if (type == C_FILE && (mode & S_IXUGO) != 0) - type = C_EXEC; - - /* Check the file's suffix only if still classified as C_FILE. */ - ext = NULL; - if (type == C_FILE) - { - /* Test if NAME has a recognized suffix. */ - - len = strlen (name); - name += len; /* Pointer to final \0. */ - for (ext = color_ext_list; ext != NULL; ext = ext->next) - { - if ((size_t) ext->ext.len <= len - && strncmp (name - ext->ext.len, ext->ext.string, - ext->ext.len) == 0) - break; - } - } - } - - put_indicator (&color_indicator[C_LEFT]); - put_indicator (ext ? &(ext->seq) : &color_indicator[type]); - put_indicator (&color_indicator[C_RIGHT]); -} - -/* Output a color indicator (which may contain nulls). */ -static void -put_indicator (const struct bin_str *ind) -{ - register int i; - register const char *p; - - p = ind->string; - - for (i = ind->len; i > 0; --i) - putchar (*(p++)); -} - -static int -length_of_file_name_and_frills (const struct fileinfo *f) -{ - register int len = 0; - - if (print_inode) - len += INODE_DIGITS + 1; - - if (print_block_size) - len += 1 + block_size_size; - - len += quote_name (NULL, f->name, filename_quoting_options); - - if (indicator_style != none) - { - unsigned filetype = f->stat.st_mode; - - if (S_ISREG (filetype)) - { - if (indicator_style == classify - && (f->stat.st_mode & S_IXUGO)) - len += 1; - } - else if (S_ISDIR (filetype) - || S_ISLNK (filetype) - || S_ISFIFO (filetype) - || S_ISSOCK (filetype) - || S_ISDOOR (filetype) - ) - len += 1; - } - - return len; -} - -static void -print_many_per_line (void) -{ - struct column_info *line_fmt; - int filesno; /* Index into files. */ - int row; /* Current row. */ - int max_name_length; /* Length of longest file name + frills. */ - int name_length; /* Length of each file name + frills. */ - int pos; /* Current character column. */ - int cols; /* Number of files across. */ - int rows; /* Maximum number of files down. */ - int max_cols; - - /* Normally the maximum number of columns is determined by the - screen width. But if few files are available this might limit it - as well. */ - max_cols = max_idx > files_index ? files_index : max_idx; - - /* Compute the maximum number of possible columns. */ - for (filesno = 0; filesno < files_index; ++filesno) - { - int i; - - name_length = length_of_file_name_and_frills (files + filesno); - - for (i = 0; i < max_cols; ++i) - { - if (column_info[i].valid_len) - { - int idx = filesno / ((files_index + i) / (i + 1)); - int real_length = name_length + (idx == i ? 0 : 2); - - if (real_length > column_info[i].col_arr[idx]) - { - column_info[i].line_len += (real_length - - column_info[i].col_arr[idx]); - column_info[i].col_arr[idx] = real_length; - column_info[i].valid_len = column_info[i].line_len < line_length; - } - } - } - } - - /* Find maximum allowed columns. */ - for (cols = max_cols; cols > 1; --cols) - { - if (column_info[cols - 1].valid_len) - break; - } - - line_fmt = &column_info[cols - 1]; - - /* Calculate the number of rows that will be in each column except possibly - for a short column on the right. */ - rows = files_index / cols + (files_index % cols != 0); - - for (row = 0; row < rows; row++) - { - int col = 0; - filesno = row; - pos = 0; - /* Print the next row. */ - while (1) - { - print_file_name_and_frills (files + filesno); - name_length = length_of_file_name_and_frills (files + filesno); - max_name_length = line_fmt->col_arr[col++]; - - filesno += rows; - if (filesno >= files_index) - break; - - indent (pos + name_length, pos + max_name_length); - pos += max_name_length; - } - putchar ('\n'); - } -} - -static void -print_horizontal (void) -{ - struct column_info *line_fmt; - int filesno; - int max_name_length; - int name_length; - int cols; - int pos; - int max_cols; - - /* Normally the maximum number of columns is determined by the - screen width. But if few files are available this might limit it - as well. */ - max_cols = max_idx > files_index ? files_index : max_idx; - - /* Compute the maximum file name length. */ - max_name_length = 0; - for (filesno = 0; filesno < files_index; ++filesno) - { - int i; - - name_length = length_of_file_name_and_frills (files + filesno); - - for (i = 0; i < max_cols; ++i) - { - if (column_info[i].valid_len) - { - int idx = filesno % (i + 1); - int real_length = name_length + (idx == i ? 0 : 2); - - if (real_length > column_info[i].col_arr[idx]) - { - column_info[i].line_len += (real_length - - column_info[i].col_arr[idx]); - column_info[i].col_arr[idx] = real_length; - column_info[i].valid_len = column_info[i].line_len < line_length; - } - } - } - } - - /* Find maximum allowed columns. */ - for (cols = max_cols; cols > 1; --cols) - { - if (column_info[cols - 1].valid_len) - break; - } - - line_fmt = &column_info[cols - 1]; - - pos = 0; - - /* Print first entry. */ - print_file_name_and_frills (files); - name_length = length_of_file_name_and_frills (files); - max_name_length = line_fmt->col_arr[0]; - - /* Now the rest. */ - for (filesno = 1; filesno < files_index; ++filesno) - { - int col = filesno % cols; - - if (col == 0) - { - putchar ('\n'); - pos = 0; - } - else - { - indent (pos + name_length, pos + max_name_length); - pos += max_name_length; - } - - print_file_name_and_frills (files + filesno); - - name_length = length_of_file_name_and_frills (files + filesno); - max_name_length = line_fmt->col_arr[col]; - } - putchar ('\n'); -} - -static void -print_with_commas (void) -{ - int filesno; - int pos, old_pos; - - pos = 0; - - for (filesno = 0; filesno < files_index; filesno++) - { - old_pos = pos; - - pos += length_of_file_name_and_frills (files + filesno); - if (filesno + 1 < files_index) - pos += 2; /* For the comma and space */ - - if (old_pos != 0 && pos >= line_length) - { - putchar ('\n'); - pos -= old_pos; - } - - print_file_name_and_frills (files + filesno); - if (filesno + 1 < files_index) - { - putchar (','); - putchar (' '); - } - } - putchar ('\n'); -} - -/* Assuming cursor is at position FROM, indent up to position TO. - Use a TAB character instead of two or more spaces whenever possible. */ - -static void -indent (int from, int to) -{ - while (from < to) - { - if (tabsize > 0 && to / tabsize > (from + 1) / tabsize) - { - putchar ('\t'); - from += tabsize - from % tabsize; - } - else - { - putchar (' '); - from++; - } - } -} - -/* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */ -/* FIXME: maybe remove this function someday. See about using a - non-malloc'ing version of path_concat. */ - -static void -attach (char *dest, const char *dirname, const char *name) -{ - const char *dirnamep = dirname; - - /* Copy dirname if it is not ".". */ - if (dirname[0] != '.' || dirname[1] != 0) - { - while (*dirnamep) - *dest++ = *dirnamep++; - /* Add '/' if `dirname' doesn't already end with it. */ - if (dirnamep > dirname && dirnamep[-1] != '/') - *dest++ = '/'; - } - while (*name) - *dest++ = *name++; - *dest = 0; -} - -static void -init_column_info (void) -{ - int i; - int allocate = 0; - - max_idx = line_length / MIN_COLUMN_WIDTH; - if (max_idx == 0) - max_idx = 1; - - if (column_info == NULL) - { - column_info = (struct column_info *) xmalloc (max_idx - * sizeof (struct column_info)); - allocate = 1; - } - - for (i = 0; i < max_idx; ++i) - { - int j; - - column_info[i].valid_len = 1; - column_info[i].line_len = (i + 1) * MIN_COLUMN_WIDTH; - - if (allocate) - column_info[i].col_arr = (int *) xmalloc ((i + 1) * sizeof (int)); - - for (j = 0; j <= i; ++j) - column_info[i].col_arr[j] = MIN_COLUMN_WIDTH; - } -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); - printf (_("\ -List information about the FILEs (the current directory by default).\n\ -Sort entries alphabetically if none of -cftuSUX nor --sort.\n\ -\n\ - -a, --all do not hide entries starting with .\n\ - -A, --almost-all do not list implied . and ..\n\ - -b, --escape print octal escapes for nongraphic characters\n\ - --block-size=SIZE use SIZE-byte blocks\n\ - -B, --ignore-backups do not list implied entries ending with ~\n\ - -c with -lt: sort by, and show, ctime (time of last\n\ - modification of file status information)\n\ - with -l: show ctime and sort by name\n\ - otherwise: sort by ctime\n\ - -C list entries by columns\n\ - --color[=WHEN] control whether color is used to distinguish file\n\ - types. WHEN may be `never', `always', or `auto'\n\ - -d, --directory list directory entries instead of contents\n\ - -D, --dired generate output designed for Emacs' dired mode\n\ - -f do not sort, enable -aU, disable -lst\n\ - -F, --classify append indicator (one of */=@|) to entries\n\ - --format=WORD across -x, commas -m, horizontal -x, long -l,\n\ - single-column -1, verbose -l, vertical -C\n\ - --full-time list both full date and full time\n")); - - printf (_("\ - -g (ignored)\n\ - -G, --no-group inhibit display of group information\n\ - -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\ - --si likewise, but use powers of 1000 not 1024\n\ - -H same as `--si' for now; soon to change\n\ - to conform to POSIX\n\ - --indicator-style=WORD append indicator with style WORD to entry names:\n\ - none (default), classify (-F), file-type (-p)\n\ - -i, --inode print index number of each file\n\ - -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\n\ - -k, --kilobytes like --block-size=1024\n\ - -l use a long listing format\n\ - -L, --dereference list entries pointed to by symbolic links\n\ - -m fill width with a comma separated list of entries\n\ - -n, --numeric-uid-gid list numeric UIDs and GIDs instead of names\n\ - -N, --literal print raw entry names (don't treat e.g. control\n\ - characters specially)\n\ - -o use long listing format without group info\n\ - -p, --file-type append indicator (one of /=@|) to entries\n\ - -q, --hide-control-chars print ? instead of non graphic characters\n\ - --show-control-chars show non graphic characters as-is (default\n\ - unless program is `ls' and output is a terminal)\n\ - -Q, --quote-name enclose entry names in double quotes\n\ - --quoting-style=WORD use quoting style WORD for entry names:\n\ - literal, locale, shell, shell-always, c, escape\n\ - -r, --reverse reverse order while sorting\n\ - -R, --recursive list subdirectories recursively\n\ - -s, --size print size of each file, in blocks\n")); - - printf (_("\ - -S sort by file size\n\ - --sort=WORD extension -X, none -U, size -S, time -t,\n\ - version -v\n\ - status -c, time -t, atime -u, access -u, use -u\n\ - --time=WORD show time as WORD instead of modification time:\n\ - atime, access, use, ctime or status; use\n\ - specified time as sort key if --sort=time\n\ - -t sort by modification time\n\ - -T, --tabsize=COLS assume tab stops at each COLS instead of 8\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 sort by version\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\ - -1 list one file per line\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -By default, color is not used to distinguish types of files. That is\n\ -equivalent to using --color=none. Using the --color option without the\n\ -optional WHEN argument is equivalent to using --color=always. With\n\ ---color=auto, color codes are output only if standard output is connected\n\ -to a terminal (tty).\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} diff --git a/src/apps/bin/gnu/ls.h b/src/apps/bin/gnu/ls.h deleted file mode 100644 index 028271f574..0000000000 --- a/src/apps/bin/gnu/ls.h +++ /dev/null @@ -1,10 +0,0 @@ -/* This is for the `ls' program. */ -#define LS_LS 1 - -/* This is for the `dir' program. */ -#define LS_MULTI_COL 2 - -/* This is for the `vdir' program. */ -#define LS_LONG_FORMAT 3 - -extern int ls_mode; diff --git a/src/apps/bin/gnu/mkdir.c b/src/apps/bin/gnu/mkdir.c deleted file mode 100644 index 419bda75d9..0000000000 --- a/src/apps/bin/gnu/mkdir.c +++ /dev/null @@ -1,205 +0,0 @@ -/* mkdir -- make directories - Copyright (C) 90, 1995-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* David MacKenzie */ - -#include -#include -#include -#include - -#include "system.h" -#include "dirname.h" -#include "error.h" -#include "makepath.h" -#include "modechange.h" -#include "quote.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "mkdir" - -#define AUTHORS "David MacKenzie" - -void strip_trailing_slashes (); - -/* The name this program was run with. */ -char *program_name; - -/* If nonzero, ensure that all parents of the specified directory exist. */ -static int create_parents; - -static struct option const longopts[] = -{ - {"mode", required_argument, NULL, 'm'}, - {"parents", no_argument, NULL, 'p'}, - {"verbose", no_argument, NULL, 'v'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION] DIRECTORY...\n"), program_name); - printf (_("\ -Create the DIRECTORY(ies), if they do not already exist.\n\ -\n\ - -m, --mode=MODE set permission mode (as in chmod), not rwxrwxrwx - umask\n\ - -p, --parents no error if existing, make parent directories as needed\n\ - -v, --verbose print a message for each created directory\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - mode_t newmode; - mode_t parent_mode; - const char *specified_mode = NULL; - const char *verbose_fmt_string = NULL; - int errors = 0; - int optc; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - create_parents = 0; - - while ((optc = getopt_long (argc, argv, "pm:v", longopts, NULL)) != -1) - { - switch (optc) - { - case 0: /* Long option. */ - break; - case 'p': - create_parents = 1; - break; - case 'm': - specified_mode = optarg; - break; - case 'v': /* --verbose */ - verbose_fmt_string = _("created directory %s"); - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - if (optind == argc) - { - error (0, 0, _("too few arguments")); - usage (1); - } - - newmode = S_IRWXUGO; - { - mode_t umask_value = umask (0); - umask (umask_value); /* Restore the old value. */ - parent_mode = (newmode & (~ umask_value)) | S_IWUSR | S_IXUSR; - } - - if (specified_mode) - { - struct mode_change *change = mode_compile (specified_mode, 0); - newmode &= ~ umask (0); - if (change == MODE_INVALID) - error (1, 0, _("invalid mode %s"), quote (specified_mode)); - else if (change == MODE_MEMORY_EXHAUSTED) - xalloc_die (); - newmode = mode_adjust (newmode, change); - } - - for (; optind < argc; ++optind) - { - int fail = 0; - - /* Remove any trailing slashes. Not removing them would lead to calling - `mkdir ("dir/", mode)' for e.g., the commands `mkdir dir/' and - `mkdir -p dir/', and such a call fails on NetBSD systems when `dir' - doesn't already exist. */ - strip_trailing_slashes (argv[optind]); - - if (create_parents) - { - char *parents = dir_name (argv[optind]); - fail = make_path (parents, parent_mode, parent_mode, - -1, -1, 1, verbose_fmt_string); - free (parents); - } - - if (fail == 0) - { - const char *dir = argv[optind]; - int dir_created; - fail = make_dir (dir, dir, newmode, &dir_created); - if (fail) - { - /* make_dir already gave a diagnostic. */ - } - else if (!create_parents && !dir_created) - { - /* make_dir `succeeds' when DIR already exists. - In that case, mkdir must fail, unless --parents (-p) - was specified. */ - error (0, EEXIST, _("cannot create directory %s"), - quote (dir)); - fail = 1; - } - else if (verbose_fmt_string) - error (0, 0, verbose_fmt_string, quote (dir)); - - /* mkdir(2) is required to honor only the file permission bits. - In particular, it needn't do anything about `special' bits, - so if any were set in newmode, apply them with chmod. - This extra step is necessary in some cases when the containing - directory has a default ACL. */ - - /* Set the permissions only if this directory has just - been created. */ - - if (fail == 0 && specified_mode && dir_created) - { - fail = chmod (dir, newmode); - if (fail) - error (0, errno, _("cannot set permissions of directory %s"), - quote (dir)); - } - } - - if (fail) - errors = 1; - } - - exit (errors); -} diff --git a/src/apps/bin/gnu/mkfifo.c b/src/apps/bin/gnu/mkfifo.c deleted file mode 100644 index b5ce392aa1..0000000000 --- a/src/apps/bin/gnu/mkfifo.c +++ /dev/null @@ -1,147 +0,0 @@ -/* mkfifo -- make fifo's (named pipes) - Copyright (C) 90, 91, 1995-2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* David MacKenzie */ - -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "modechange.h" -#include "quote.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "mkfifo" - -#define AUTHORS "David MacKenzie" - -/* The name this program was run with. */ -char *program_name; - -static struct option const longopts[] = -{ - {"mode", required_argument, NULL, 'm'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -#ifdef S_ISFIFO -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION] NAME...\n"), program_name); - printf (_("\ -Create named pipes (FIFOs) with the given NAMEs.\n\ -\n\ - -m, --mode=MODE set permission mode (as in chmod), not a=rw - umask\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} -#endif - -int -main (int argc, char **argv) -{ - mode_t newmode; - struct mode_change *change; - const char *specified_mode; - int errors = 0; - int optc; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - specified_mode = NULL; - -#ifndef S_ISFIFO - error (4, 0, _("fifo files not supported")); -#else - while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) - { - switch (optc) - { - case 0: - break; - case 'm': - specified_mode = optarg; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - if (optind == argc) - { - error (0, 0, _("too few arguments")); - usage (1); - } - - newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (specified_mode) - { - newmode &= ~ umask (0); - change = mode_compile (specified_mode, 0); - if (change == MODE_INVALID) - error (1, 0, _("invalid mode")); - else if (change == MODE_MEMORY_EXHAUSTED) - xalloc_die (); - newmode = mode_adjust (newmode, change); - } - - for (; optind < argc; ++optind) - { - int fail = mkfifo (argv[optind], newmode); - if (fail) - error (0, errno, _("cannot create fifo `%s'"), quote (argv[optind])); - - /* If the containing directory happens to have a default ACL, chmod - ensures the file mode permission bits are still set as desired. */ - - if (fail == 0 && specified_mode) - { - fail = chmod (argv[optind], newmode); - if (fail) - error (0, errno, _("cannot set permissions of fifo `%s'"), - quote (argv[optind])); - } - - if (fail) - errors = 1; - } - - exit (errors); -#endif -} diff --git a/src/apps/bin/gnu/mknod.c b/src/apps/bin/gnu/mknod.c deleted file mode 100644 index fac49c9dab..0000000000 --- a/src/apps/bin/gnu/mknod.c +++ /dev/null @@ -1,238 +0,0 @@ -/* mknod -- make special files - Copyright (C) 90, 91, 1995-2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Usage: mknod [-m mode] [--mode=mode] path {bcu} major minor - make a block or character device node - mknod [-m mode] [--mode=mode] path p - make a FIFO (named pipe) - - Options: - -m, --mode=mode Set the mode of created nodes to MODE, which is - symbolic as in chmod and uses the umask as a point of - departure. - - David MacKenzie */ - -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "modechange.h" -#include "quote.h" -#include "xstrtol.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "mknod" - -#define AUTHORS "David MacKenzie" - -/* The name this program was run with. */ -char *program_name; - -static struct option const longopts[] = -{ - {"mode", required_argument, NULL, 'm'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"), program_name); - printf (_("\ -Create the special file NAME of the given TYPE.\n\ -\n\ - -m, --mode=MODE set permission mode (as in chmod), not a=rw - umask\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -MAJOR MINOR are forbidden for TYPE p, mandatory otherwise. TYPE may be:\n\ -\n\ - b create a block (buffered) special file\n\ - c, u create a character (unbuffered) special file\n\ - p create a FIFO\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - mode_t newmode; - struct mode_change *change; - const char *specified_mode; - int optc; - int i_major, i_minor; - long int tmp_major, tmp_minor; - char *s; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - specified_mode = NULL; - - while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) - { - switch (optc) - { - case 0: - break; - case 'm': - specified_mode = optarg; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (specified_mode) - { - newmode &= ~ umask (0); - change = mode_compile (specified_mode, 0); - if (change == MODE_INVALID) - error (1, 0, _("invalid mode")); - else if (change == MODE_MEMORY_EXHAUSTED) - xalloc_die (); - newmode = mode_adjust (newmode, change); - } - - if (argc - optind != 2 && argc - optind != 4) - { - const char *msg; - if (argc - optind < 2) - msg = _("too few arguments"); - else if (argc - optind > 4) - msg = _("too many arguments"); - else - msg = _("wrong number of arguments"); - error (0, 0, msg); - usage (1); - } - - /* Only check the first character, to allow mnemonic usage like - `mknod /dev/rst0 character 18 0'. */ - - switch (argv[optind + 1][0]) - { - case 'b': /* `block' or `buffered' */ -#ifndef S_IFBLK - error (4, 0, _("block special files not supported")); -#else - if (argc - optind != 4) - { - error (0, 0, _("\ -when creating block special files, major and minor device\n\ -numbers must be specified")); - usage (1); - } - - s = argv[optind + 2]; - if (xstrtol (s, NULL, 0, &tmp_major, NULL) != LONGINT_OK) - error (1, 0, _("invalid major device number %s"), quote (s)); - - s = argv[optind + 3]; - if (xstrtol (s, NULL, 0, &tmp_minor, NULL) != LONGINT_OK) - error (1, 0, _("invalid minor device number %s"), quote (s)); - - i_major = (int) tmp_major; - i_minor = (int) tmp_minor; - - if (mknod (argv[optind], newmode | S_IFBLK, makedev (i_major, i_minor))) - error (1, errno, "%s", quote (argv[optind])); -#endif - break; - - case 'c': /* `character' */ - case 'u': /* `unbuffered' */ -#ifndef S_IFCHR - error (4, 0, _("character special files not supported")); -#else - if (argc - optind != 4) - { - error (0, 0, _("\ -when creating character special files, major and minor device\n\ -numbers must be specified")); - usage (1); - } - - s = argv[optind + 2]; - if (xstrtol (s, NULL, 0, &tmp_major, NULL) != LONGINT_OK) - error (1, 0, _("invalid major device number %s"), quote (s)); - - s = argv[optind + 3]; - if (xstrtol (s, NULL, 0, &tmp_minor, NULL) != LONGINT_OK) - error (1, 0, _("invalid minor device number %s"), quote (s)); - - i_major = (int) tmp_major; - i_minor = (int) tmp_minor; - - if (mknod (argv[optind], newmode | S_IFCHR, makedev (i_major, i_minor))) - error (1, errno, "%s", quote (argv[optind])); -#endif - break; - - case 'p': /* `pipe' */ -#ifndef S_ISFIFO - error (4, 0, _("fifo files not supported")); -#else - if (argc - optind != 2) - { - error (0, 0, _("\ -major and minor device numbers may not be specified for fifo files")); - usage (1); - } - if (mkfifo (argv[optind], newmode)) - error (1, errno, "%s", quote (argv[optind])); -#endif - break; - - default: - usage (1); - } - - /* Perform an explicit chmod to ensure the file mode permission bits - are set as specified. This extra step is necessary in some cases - when the containing directory has a default ACL. */ - - if (specified_mode) - { - if (chmod (argv[optind], newmode)) - error (0, errno, _("cannot set permissions of `%s'"), - quote (argv[optind])); - } - - exit (0); -} diff --git a/src/apps/bin/gnu/mv.c b/src/apps/bin/gnu/mv.c deleted file mode 100644 index a429558710..0000000000 --- a/src/apps/bin/gnu/mv.c +++ /dev/null @@ -1,495 +0,0 @@ -/* mv -- move or rename files - Copyright (C) 86, 89, 90, 91, 1995-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by Mike Parker, David MacKenzie, and Jim Meyering */ - -#ifdef _AIX - #pragma alloca -#endif - -#include -#include -#include -#include -#include - -#include "system.h" -#include "backupfile.h" -#include "copy.h" -#include "cp-hash.h" -#include "error.h" -#include "path-concat.h" -#include "quote.h" -#include "remove.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "mv" - -#define AUTHORS "Mike Parker, David MacKenzie, and Jim Meyering" - -/* Initial number of entries in each hash table entry's table of inodes. */ -#define INITIAL_HASH_MODULE 100 - -/* Initial number of entries in the inode hash table. */ -#define INITIAL_ENTRY_TAB_SIZE 70 - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - TARGET_DIRECTORY_OPTION = CHAR_MAX + 1, - STRIP_TRAILING_SLASHES_OPTION -}; - -int euidaccess (); -int full_write (); -int isdir (); -int lstat (); -int yesno (); - -/* The name this program was run with. */ -char *program_name; - -/* Remove any trailing slashes from each SOURCE argument. */ -static int remove_trailing_slashes; - -static struct option const long_options[] = -{ - {"backup", optional_argument, NULL, 'b'}, - {"force", no_argument, NULL, 'f'}, - {"interactive", no_argument, NULL, 'i'}, - {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, - {"suffix", required_argument, NULL, 'S'}, - {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, - {"update", no_argument, NULL, 'u'}, - {"verbose", no_argument, NULL, 'v'}, - {"version-control", required_argument, NULL, 'V'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -static void -rm_option_init (struct rm_options *x) -{ - x->unlink_dirs = 0; - - x->ignore_missing_files = 0; - - x->recursive = 1; - - /* Should we prompt for removal, too? No. Prompting for the `move' - part is enough. It implies removal. */ - x->interactive = 0; - x->stdin_tty = 0; - - x->verbose = 0; -} - -static void -cp_option_init (struct cp_options *x) -{ - x->copy_as_regular = 0; /* FIXME: maybe make this an option */ - x->dereference = DEREF_NEVER; - x->unlink_dest_before_opening = 0; - x->unlink_dest_after_failed_open = 0; - x->failed_unlink_is_fatal = 1; - x->hard_link = 0; - x->interactive = 0; - x->move_mode = 1; - x->myeuid = geteuid (); - x->one_file_system = 0; - x->preserve_owner_and_group = 1; - x->preserve_chmod_bits = 1; - x->preserve_timestamps = 1; - x->require_preserve = 0; /* FIXME: maybe make this an option */ - x->recursive = 1; - x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */ - x->symbolic_link = 0; - x->set_mode = 0; - x->mode = 0; - - /* Find out the current file creation mask, to knock the right bits - when using chmod. The creation mask is set to be liberal, so - that created directories can be written, even if it would not - have been allowed with the mask this process was started with. */ - x->umask_kill = ~ umask (0); - - x->update = 0; - x->verbose = 0; - x->xstat = lstat; -} - -/* If PATH is an existing directory, return nonzero, else 0. */ - -static int -is_real_dir (const char *path) -{ - struct stat stats; - - return lstat (path, &stats) == 0 && S_ISDIR (stats.st_mode); -} - -static int -strip_trailing_slashes_2 (char *path) -{ - char *end_p = path + strlen (path) - 1; - char *slash = end_p; - - while (slash > path && *slash == '/') - *slash-- = '\0'; - - return slash < end_p; -} - -/* Move SOURCE onto DEST. Handles cross-filesystem moves. - If SOURCE is a directory, DEST must not exist. - Return 0 if successful, non-zero if an error occurred. */ - -static int -do_move (const char *source, const char *dest, const struct cp_options *x) -{ - static int first = 1; - int copy_into_self; - int rename_succeeded; - int fail; - - if (first) - { - first = 0; - - /* Allocate space for remembering copied and created files. */ - hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE); - } - - fail = copy (source, dest, 0, x, ©_into_self, &rename_succeeded); - - if (!fail) - { - const char *dir_to_remove; - if (copy_into_self) - { - /* In general, when copy returns with copy_into_self set, SOURCE is - the same as, or a parent of DEST. In this case we know it's a - parent. It doesn't make sense to move a directory into itself, and - besides in some situations doing so would give highly nonintuitive - results. Run this `mkdir b; touch a c; mv * b' in an empty - directory. Here's the result of running echo `find b -print`: - b b/a b/b b/b/a b/c. Notice that only file `a' was copied - into b/b. Handle this by giving a diagnostic, removing the - copied-into-self directory, DEST (`b/b' in the example), - and failing. */ - - dir_to_remove = NULL; - fail = 1; - } - else if (rename_succeeded) - { - /* No need to remove anything. SOURCE was successfully - renamed to DEST. */ - dir_to_remove = NULL; - } - else - { - /* This may mean SOURCE and DEST referred to different devices. - It may also conceivably mean that even though they referred - to the same device, rename wasn't implemented for that device. - - E.g., (from Joel N. Weber), - [...] there might someday be cases where you can't rename - but you can copy where the device name is the same, especially - on Hurd. Consider an ftpfs with a primitive ftp server that - supports uploading, downloading and deleting, but not renaming. - - Also, note that comparing device numbers is not a reliable - check for `can-rename'. Some systems can be set up so that - files from many different physical devices all have the same - st_dev field. This is a feature of some NFS mounting - configurations. - - We reach this point if SOURCE has been successfully copied - to DEST. Now we have to remove SOURCE. - - This function used to resort to copying only when rename - failed and set errno to EXDEV. */ - - dir_to_remove = source; - } - - if (dir_to_remove != NULL) - { - struct rm_options rm_options; - struct File_spec fs; - enum RM_status status; - - rm_option_init (&rm_options); - rm_options.verbose = x->verbose; - - remove_init (); - - fspec_init_file (&fs, dir_to_remove); - - /* Remove any trailing slashes. This is necessary if we - took the else branch of movefile. */ - strip_trailing_slashes_2 (fs.filename); - - status = rm (&fs, 1, &rm_options); - assert (VALID_STATUS (status)); - if (status == RM_ERROR) - fail = 1; - - remove_fini (); - - if (fail) - error (0, errno, _("cannot remove %s"), quote (dir_to_remove)); - } - } - - return fail; -} - -/* Move file SOURCE onto DEST. Handles the case when DEST is a directory. - DEST_IS_DIR must be nonzero when DEST is a directory or a symlink to a - directory and zero otherwise. - Return 0 if successful, non-zero if an error occurred. */ - -static int -movefile (char *source, char *dest, int dest_is_dir, - const struct cp_options *x) -{ - int dest_had_trailing_slash = strip_trailing_slashes_2 (dest); - int fail; - - /* This code was introduced to handle the ambiguity in the semantics - of mv that is induced by the varying semantics of the rename function. - Some systems (e.g., Linux) have a rename function that honors a - trailing slash, while others (like Solaris 5,6,7) have a rename - function that ignores a trailing slash. I believe the Linux - rename semantics are POSIX and susv2 compliant. */ - - if (remove_trailing_slashes) - strip_trailing_slashes_2 (source); - - /* In addition to when DEST is a directory, if DEST has a trailing - slash and neither SOURCE nor DEST is a directory, presume the target - is DEST/`basename source`. This converts `mv x y/' to `mv x y/x'. - This change means that the command `mv any file/' will now fail - rather than performing the move. The case when SOURCE is a - directory and DEST is not is properly diagnosed by do_move. */ - - if (dest_is_dir || (dest_had_trailing_slash && !is_real_dir (source))) - { - /* DEST is a directory; build full target filename. */ - char *src_basename; - char *new_dest; - - /* Remove trailing slashes before taking base_name. - Otherwise, base_name ("a/") returns "". */ - strip_trailing_slashes_2 (source); - - src_basename = base_name (source); - new_dest = path_concat (dest, src_basename, NULL); - if (new_dest == NULL) - xalloc_die (); - fail = do_move (source, new_dest, x); - - /* Do not free new_dest. It may have been squirreled away by - the remember_copied function. */ - } - else - { - fail = do_move (source, dest, x); - } - - return fail; -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("\ -Usage: %s [OPTION]... SOURCE DEST\n\ - or: %s [OPTION]... SOURCE... DIRECTORY\n\ - or: %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\ -"), - program_name, program_name, program_name); - printf (_("\ -Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\ -\n\ - --backup[=CONTROL] make a backup of each existing destination file\n\ - -b like --backup but does not accept an argument\n\ - -f, --force never prompt before overwriting\n\ - -i, --interactive prompt before overwrite\n\ - --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\ - argument\n\ - -S, --suffix=SUFFIX override the usual backup suffix\n\ - --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\ - -u, --update move only older or brand new non-directories\n\ - -v, --verbose explain what is being done\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -")); - printf (_("\ -The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ -The version control method may be selected via the --backup option or through\n\ -the VERSION_CONTROL environment variable. Here are the values:\n\ -\n\ - none, off never make backups (even if --backup is given)\n\ - numbered, t make numbered backups\n\ - existing, nil numbered if numbered backups exist, simple otherwise\n\ - simple, never always make simple backups\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - int c; - int errors; - int make_backups = 0; - int dest_is_dir; - char *backup_suffix_string; - char *version_control_string = NULL; - struct cp_options x; - char *target_directory = NULL; - int target_directory_specified; - unsigned int n_files; - char **file; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - cp_option_init (&x); - - /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless - we'll actually use backup_suffix_string. */ - backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); - - errors = 0; - - while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, NULL)) != -1) - { - switch (c) - { - case 0: - break; - - case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ - error (0, 0, - _("warning: --version-control (-V) is obsolete; support for\ - it\nwill be removed in some future release. Use --backup=%s instead." - ), optarg); - /* Fall through. */ - - case 'b': - make_backups = 1; - if (optarg) - version_control_string = optarg; - break; - case 'f': - x.interactive = 0; - break; - case 'i': - x.interactive = 1; - break; - case STRIP_TRAILING_SLASHES_OPTION: - remove_trailing_slashes = 1; - break; - case TARGET_DIRECTORY_OPTION: - target_directory = optarg; - break; - case 'u': - x.update = 1; - break; - case 'v': - x.verbose = 1; - break; - case 'S': - make_backups = 1; - backup_suffix_string = optarg; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - n_files = argc - optind; - file = argv + optind; - - target_directory_specified = (target_directory != NULL); - if (target_directory == NULL && n_files != 0) - target_directory = file[n_files - 1]; - - dest_is_dir = (n_files > 0 && isdir (target_directory)); - - if (n_files == 0 || (n_files == 1 && !target_directory_specified)) - { - error (0, 0, _("missing file argument")); - usage (1); - } - - if (target_directory_specified) - { - if (!dest_is_dir) - { - error (0, 0, _("specified target, %s is not a directory"), - quote (target_directory)); - usage (1); - } - } - else if (n_files > 2 && !dest_is_dir) - { - error (0, 0, - _("when moving multiple files, last argument must be a directory")); - usage (1); - } - - if (backup_suffix_string) - simple_backup_suffix = xstrdup (backup_suffix_string); - - x.backup_type = (make_backups - ? xget_version (_("backup type"), - version_control_string) - : none); - - /* Move each arg but the last into the target_directory. */ - { - unsigned int last_file_idx = (target_directory_specified - ? n_files - 1 - : n_files - 2); - unsigned int i; - for (i = 0; i <= last_file_idx; ++i) - errors |= movefile (file[i], target_directory, dest_is_dir, &x); - } - - exit (errors); -} diff --git a/src/apps/bin/gnu/remove.c b/src/apps/bin/gnu/remove.c deleted file mode 100644 index 0536893e7f..0000000000 --- a/src/apps/bin/gnu/remove.c +++ /dev/null @@ -1,946 +0,0 @@ -/* remove.c -- core functions for removing files and directories - Copyright (C) 88, 90, 91, 1994-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Extracted from rm.c and librarified by Jim Meyering. */ - -#ifdef _AIX - #pragma alloca -#endif - -#include -#include -#include -#include - -#if HAVE_STDBOOL_H -# include -#else -typedef enum {false = 0, true = 1} bool; -#endif - -#include "save-cwd.h" -#include "system.h" -#include "error.h" -#include "obstack.h" -#include "hash.h" -#include "quote.h" -#include "remove.h" - -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free - -#ifndef PARAMS -# if defined (__GNUC__) || __STDC__ -# define PARAMS(args) args -# else -# define PARAMS(args) () -# endif -#endif - -/* On systems with an lstat function that accepts the empty string, - arrange to make lstat calls go through the wrapper function. */ -#if HAVE_LSTAT_EMPTY_STRING_BUG -int rpl_lstat PARAMS((const char *, struct stat *)); -# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf) -#endif - -#ifdef D_INO_IN_DIRENT -# define D_INO(dp) ((dp)->d_ino) -# define ENABLE_CYCLE_CHECK -#else -/* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */ -# define D_INO(dp) 1 -#endif - -#if !defined S_ISLNK -# define S_ISLNK(Mode) 0 -#endif - -/* Initial capacity of per-directory hash table of entries that have - been processed but not been deleted. */ -#define HT_INITIAL_CAPACITY 13 - -/* Initial capacity of the active directory hash table. This table will - be resized only for hierarchies more than about 45 levels deep. */ -#define ACTIVE_DIR_INITIAL_CAPACITY 53 - -int euidaccess (); -int yesno (); - -extern char *program_name; - -/* state initialized by remove_init, freed by remove_fini */ - -/* An entry in the active_dir_map. */ -struct active_dir_ent -{ - ino_t st_ino; - dev_t st_dev; - unsigned int depth; -}; - -/* The name of the directory (starting with and relative to a command - line argument) being processed. When a subdirectory is entered, a new - component is appended (pushed). When RM chdir's out of a directory, - the top component is removed (popped). This is used to form a full - file name when necessary. */ -static struct obstack dir_stack; - -/* Stack of lengths of directory names (including trailing slash) - appended to dir_stack. We have to have a separate stack of lengths - (rather than just popping back to previous slash) because the first - element pushed onto the dir stack may contain slashes. */ -static struct obstack len_stack; - -/* Set of `active' directories from the current command-line argument - to the level in the hierarchy at which files are being removed. - A directory is added to the active set when RM begins removing it - (or its entries), and it is removed from the set just after RM has - finished processing it. - - This is actually a map (not a set), implemented with a hash table. - For each active directory, it maps the directory's inode number to the - depth of that directory relative to the root of the tree being deleted. - A directory specified on the command line has depth zero. - This construct is used to detect directory cycles so that RM can warn - about them rather than iterating endlessly. */ -#ifdef ENABLE_CYCLE_CHECK -static struct hash_table *active_dir_map; -#endif - -static inline unsigned int -current_depth (void) -{ - return obstack_object_size (&len_stack) / sizeof (size_t); -} - -static void -print_nth_dir (FILE *stream, unsigned int depth) -{ - size_t *length = (size_t *) obstack_base (&len_stack); - char *dir_name = (char *) obstack_base (&dir_stack); - unsigned int sum = 0; - unsigned int i; - - assert (depth < current_depth ()); - - for (i = 0; i <= depth; i++) - { - sum += length[i]; - } - - fwrite (dir_name, 1, sum - 1, stream); -} - -static inline struct active_dir_ent * -make_active_dir_ent (ino_t inum, dev_t device, unsigned int depth) -{ - struct active_dir_ent *ent; - ent = (struct active_dir_ent *) xmalloc (sizeof *ent); - ent->st_ino = inum; - ent->st_dev = device; - ent->depth = depth; - return ent; -} - -static unsigned int -hash_active_dir_ent (void const *x, unsigned int table_size) -{ - struct active_dir_ent const *ade = x; - - /* Ignoring the device number here should be fine. */ - return ade->st_ino % table_size; -} - -static bool -hash_compare_active_dir_ents (void const *x, void const *y) -{ - struct active_dir_ent const *a = x; - struct active_dir_ent const *b = y; - return SAME_INODE (*a, *b) ? true : false; -} - -/* A hash function for null-terminated char* strings using - the method described in Aho, Sethi, & Ullman, p 436. */ - -static unsigned int -hash_pjw (const void *x, unsigned int tablesize) -{ - const char *s = x; - unsigned int h = 0; - unsigned int g; - - while (*s != 0) - { - h = (h << 4) + *s++; - if ((g = h & (unsigned int) 0xf0000000) != 0) - h = (h ^ (g >> 24)) ^ g; - } - - return (h % tablesize); -} - -static bool -hash_compare_strings (void const *x, void const *y) -{ - return STREQ (x, y) ? true : false; -} - -static inline void -push_dir (const char *dir_name) -{ - size_t len; - - len = strlen (dir_name); - - /* Append the string onto the stack. */ - obstack_grow (&dir_stack, dir_name, len); - - /* Append a trailing slash. */ - obstack_1grow (&dir_stack, '/'); - - /* Add one for the slash. */ - ++len; - - /* Push the length (including slash) onto its stack. */ - obstack_grow (&len_stack, &len, sizeof (len)); -} - -static inline void -pop_dir (void) -{ - int n_lengths = obstack_object_size (&len_stack) / sizeof (size_t); - size_t *length = (size_t *) obstack_base (&len_stack); - size_t top_len; - - assert (n_lengths > 0); - top_len = length[n_lengths - 1]; - assert (top_len >= 2); - - /* Pop off the specified length of pathname. */ - assert (obstack_object_size (&dir_stack) >= top_len); - obstack_blank (&dir_stack, -top_len); - - /* Pop the length stack, too. */ - assert (obstack_object_size (&len_stack) >= sizeof (size_t)); - obstack_blank (&len_stack, (int) -(sizeof (size_t))); -} - -/* Copy the SRC_LEN bytes of data beginning at SRC into the DST_LEN-byte - buffer, DST, so that the last source byte is at the end of the destination - buffer. If SRC_LEN is longer than DST_LEN, then set *TRUNCATED to non-zero. - Set *RESULT to point to the beginning of (the portion of) the source data - in DST. Return the number of bytes remaining in the destination buffer. */ - -static size_t -right_justify (char *dst, size_t dst_len, const char *src, size_t src_len, - char **result, int *truncated) -{ - const char *sp; - char *dp; - - if (src_len <= dst_len) - { - sp = src; - dp = dst + (dst_len - src_len); - *truncated = 0; - } - else - { - sp = src + (src_len - dst_len); - dp = dst; - src_len = dst_len; - *truncated = 1; - } - - *result = memcpy (dp, sp, src_len); - return dst_len - src_len; -} - -/* Using the global directory name obstack, create the full path to FILENAME. - Return it in sometimes-realloc'd space that should not be freed by the - caller. Realloc as necessary. If realloc fails, use a static buffer - and put as long a suffix in that buffer as possible. */ - -static char * -full_filename (const char *filename) -{ - static char *buf = NULL; - static size_t n_allocated = 0; - - int dir_len = obstack_object_size (&dir_stack); - char *dir_name = (char *) obstack_base (&dir_stack); - size_t n_bytes_needed; - size_t filename_len; - - filename_len = strlen (filename); - n_bytes_needed = dir_len + filename_len + 1; - - if (n_bytes_needed > n_allocated) - { - /* This code requires that realloc accept NULL as the first arg. - This function must not use xrealloc. Otherwise, an out-of-memory - error involving a file name to be expanded here wouldn't ever - be issued. Use realloc and fall back on using a static buffer - if memory allocation fails. */ - buf = realloc (buf, n_bytes_needed); - n_allocated = n_bytes_needed; - - if (buf == NULL) - { -#define SBUF_SIZE 512 -#define ELLIPSES_PREFIX "[...]" - static char static_buf[SBUF_SIZE]; - int truncated; - size_t len; - char *p; - - len = right_justify (static_buf, SBUF_SIZE, filename, - filename_len + 1, &p, &truncated); - right_justify (static_buf, len, dir_name, dir_len, &p, &truncated); - if (truncated) - { - memcpy (static_buf, ELLIPSES_PREFIX, - sizeof (ELLIPSES_PREFIX) - 1); - } - return p; - } - } - - /* Copy directory part, including trailing slash, and then - append the filename part, including a trailing zero byte. */ - memcpy (mempcpy (buf, dir_name, dir_len), filename, filename_len + 1); - - assert (strlen (buf) + 1 == n_bytes_needed); - - return buf; -} - -static inline void -fspec_init_common (struct File_spec *fs) -{ - fs->have_full_mode = 0; - fs->have_filetype_mode = 0; - fs->have_device = 0; -} - -void -fspec_init_file (struct File_spec *fs, const char *filename) -{ - fs->filename = (char *) filename; - fspec_init_common (fs); -} - -static inline void -fspec_init_dp (struct File_spec *fs, struct dirent *dp) -{ - fs->filename = dp->d_name; - fspec_init_common (fs); - fs->st_ino = D_INO (dp); - -#if D_TYPE_IN_DIRENT && defined DT_UNKNOWN && defined DTTOIF - if (dp->d_type != DT_UNKNOWN) - { - fs->have_filetype_mode = 1; - fs->mode = DTTOIF (dp->d_type); - } -#endif -} - -static inline int -fspec_get_full_mode (struct File_spec *fs) -{ - struct stat stat_buf; - - if (fs->have_full_mode) - return 0; - - if (lstat (fs->filename, &stat_buf)) - return 1; - - fs->have_full_mode = 1; - fs->have_filetype_mode = 1; - fs->mode = stat_buf.st_mode; - fs->st_ino = stat_buf.st_ino; - fs->have_device = 1; - fs->st_dev = stat_buf.st_dev; - - return 0; -} - -static inline int -fspec_get_device_number (struct File_spec *fs) -{ - struct stat stat_buf; - - if (fs->have_device) - return 0; - - if (lstat (fs->filename, &stat_buf)) - return 1; - - fs->have_full_mode = 1; - fs->have_filetype_mode = 1; - fs->mode = stat_buf.st_mode; - fs->st_ino = stat_buf.st_ino; - fs->have_device = 1; - fs->st_dev = stat_buf.st_dev; - - return 0; -} - -static inline int -fspec_get_filetype_mode (struct File_spec *fs, mode_t *filetype_mode) -{ - int fail; - - fail = fs->have_filetype_mode ? 0 : fspec_get_full_mode (fs); - if (!fail) - *filetype_mode = fs->mode; - - return fail; -} - -static inline mode_t -fspec_filetype_mode (const struct File_spec *fs) -{ - assert (fs->have_filetype_mode); - return fs->mode; -} - -static int -same_file (const char *file_1, const char *file_2) -{ - struct stat sb1, sb2; - return (lstat (file_1, &sb1) == 0 - && lstat (file_2, &sb2) == 0 - && SAME_INODE (sb1, sb2)); -} - - -/* Recursively remove all of the entries in the current directory. - Return an indication of the success of the operation. */ - -static enum RM_status -remove_cwd_entries (const struct rm_options *x) -{ - /* NOTE: this is static. */ - static DIR *dirp = NULL; - - /* NULL or a malloc'd and initialized hash table of entries in the - current directory that have been processed but not removed -- - due either to an error or to an interactive `no' response. */ - struct hash_table *ht = NULL; - - /* FIXME: describe */ - static struct obstack entry_name_pool; - static int first_call = 1; - - enum RM_status status = RM_OK; - - if (first_call) - { - first_call = 0; - obstack_init (&entry_name_pool); - } - - if (dirp) - { - if (CLOSEDIR (dirp)) - { - /* FIXME-someday: but this is actually the previously opened dir. */ - error (0, errno, "%s", quote (full_filename ("."))); - status = RM_ERROR; - } - dirp = NULL; - } - - do - { - /* FIXME: why do this? */ - errno = 0; - - dirp = opendir ("."); - if (dirp == NULL) - { - if (errno != ENOENT || !x->ignore_missing_files) - { - error (0, errno, _("cannot open directory %s"), - quote (full_filename ("."))); - status = RM_ERROR; - } - break; - } - - while (1) - { - char *entry_name; - struct File_spec fs; - enum RM_status tmp_status; - struct dirent *dp; - -/* FILE should be skipped if it is `.' or `..', or if it is in - the table, HT, of entries we've already processed. */ -#define SKIPPABLE(Ht, File) \ - (DOT_OR_DOTDOT(File) || (Ht && hash_lookup (Ht, File))) - - /* FIXME: use readdir_r directly into an obstack to avoid - the obstack_copy0 below -- - Suggestion from Uli. Be careful -- there are different - prototypes on e.g. Solaris. - - Do something like this: - #define NAME_MAX_FOR(Parent_dir) pathconf ((Parent_dir), - _PC_NAME_MAX); - dp = obstack_alloc (sizeof (struct dirent) - + NAME_MAX_FOR (".") + 1); - fail = xreaddir (dirp, dp); - where xreaddir is ... - - But what about systems like the hurd where NAME_MAX is supposed - to be effectively unlimited. We don't want to have to allocate - a huge buffer to accommodate maximum possible entry name. */ - - dp = readdir (dirp); - -#if ! HAVE_WORKING_READDIR - if (dp == NULL) - { - /* Since we have probably modified the directory since it - was opened, readdir returning NULL does not necessarily - mean we have read the last entry. Rewind it and check - again. This happens on SunOS4.1.4 with 254 or more files - in a directory. */ - rewinddir (dirp); - while ((dp = readdir (dirp)) && SKIPPABLE (ht, dp->d_name)) - { - /* empty */ - } - } -#endif - - if (dp == NULL) - break; - - if (SKIPPABLE (ht, dp->d_name)) - continue; - - fspec_init_dp (&fs, dp); - - /* Save a copy of the name of this entry, in case we have - to add it to the set of unremoved entries below. */ - entry_name = obstack_copy0 (&entry_name_pool, - dp->d_name, NLENGTH (dp)); - - /* CAUTION: after this call to rm, DP may not be valid -- - it may have been freed due to a close in a recursive call - (through rm and remove_dir) to this function. */ - tmp_status = rm (&fs, 0, x); - - /* Update status. */ - if (tmp_status > status) - status = tmp_status; - assert (VALID_STATUS (status)); - - /* If this entry was not removed (due either to an error or to - an interactive `no' response), record it in the hash table so - we don't consider it again if we reopen this directory later. */ - if (status != RM_OK) - { - if (ht == NULL) - { - ht = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_pjw, - hash_compare_strings, NULL); - if (ht == NULL) - xalloc_die (); - } - if (! hash_insert (ht, entry_name)) - xalloc_die (); - } - else - { - /* This entry was not saved in the hash table. Free it. */ - obstack_free (&entry_name_pool, entry_name); - } - - if (dirp == NULL) - break; - } - } - while (dirp == NULL); - - if (dirp) - { - if (CLOSEDIR (dirp)) - { - error (0, errno, _("closing directory %s"), - quote (full_filename ("."))); - status = RM_ERROR; - } - dirp = NULL; - } - - if (ht) - { - hash_free (ht); - } - - if (obstack_object_size (&entry_name_pool) > 0) - obstack_free (&entry_name_pool, obstack_base (&entry_name_pool)); - - return status; -} - -/* Query the user if appropriate, and if ok try to remove the - file or directory specified by FS. Return RM_OK if it is removed, - and RM_ERROR or RM_USER_DECLINED if not. */ - -static enum RM_status -remove_file (struct File_spec *fs, const struct rm_options *x) -{ - int asked = 0; - char *pathname = fs->filename; - - if (!x->ignore_missing_files && (x->interactive || x->stdin_tty) - && euidaccess (pathname, W_OK)) - { - if (!S_ISLNK (fspec_filetype_mode (fs))) - { - fprintf (stderr, - (S_ISDIR (fspec_filetype_mode (fs)) - ? _("%s: remove write-protected directory %s? ") - : _("%s: remove write-protected file %s? ")), - program_name, quote (full_filename (pathname))); - if (!yesno ()) - return RM_USER_DECLINED; - - asked = 1; - } - } - - if (!asked && x->interactive) - { - /* FIXME: use a variant of error (instead of fprintf) that doesn't - append a newline. Then we won't have to declare program_name in - this file. */ - fprintf (stderr, - (S_ISDIR (fspec_filetype_mode (fs)) - ? _("%s: remove directory %s? ") - : _("%s: remove %s? ")), - program_name, quote (full_filename (pathname))); - if (!yesno ()) - return RM_USER_DECLINED; - } - - if (x->verbose) - printf (_("removing %s\n"), quote (full_filename (pathname))); - - if (unlink (pathname) && (errno != ENOENT || !x->ignore_missing_files)) - { - error (0, errno, _("cannot unlink %s"), quote (full_filename (pathname))); - return RM_ERROR; - } - return RM_OK; -} - -/* If not in recursive mode, print an error message and return RM_ERROR. - Otherwise, query the user if appropriate, then try to recursively - remove the directory specified by FS. Return RM_OK if it is removed, - and RM_ERROR or RM_USER_DECLINED if not. - FIXME: describe need_save_cwd parameter. */ - -static enum RM_status -remove_dir (struct File_spec *fs, int need_save_cwd, const struct rm_options *x) -{ - enum RM_status status; - struct saved_cwd cwd; - char *dir_name = fs->filename; - const char *fmt = NULL; - - if (!x->recursive) - { - error (0, 0, _("%s is a directory"), quote (full_filename (dir_name))); - return RM_ERROR; - } - - if (!x->ignore_missing_files && (x->interactive || x->stdin_tty) - && euidaccess (dir_name, W_OK)) - { - fmt = _("%s: directory %s is write protected; descend into it anyway? "); - } - else if (x->interactive) - { - fmt = _("%s: descend into directory %s? "); - } - - if (fmt) - { - fprintf (stderr, fmt, program_name, quote (full_filename (dir_name))); - if (!yesno ()) - return RM_USER_DECLINED; - } - - if (x->verbose) - printf (_("removing all entries of directory %s\n"), - quote (full_filename (dir_name))); - - /* Save cwd if needed. */ - if (need_save_cwd && save_cwd (&cwd)) - return RM_ERROR; - - /* Make target directory the current one. */ - if (chdir (dir_name) < 0) - { - error (0, errno, _("cannot change to directory %s"), - quote (full_filename (dir_name))); - if (need_save_cwd) - free_cwd (&cwd); - return RM_ERROR; - } - - /* Verify that the device and inode numbers of `.' are the same as - the ones we recorded for dir_name before we cd'd into it. This - detects the scenario in which an attacker tries to make Bob's rm - command remove some other directory belonging to Bob. The method - would be to replace an existing lstat'd but-not-yet-removed directory - with a symlink to the target directory. */ - { - struct stat sb; - if (lstat (".", &sb)) - error (EXIT_FAILURE, errno, - _("cannot lstat `.' in %s"), quote (full_filename (dir_name))); - - assert (fs->have_device); - if (!SAME_INODE (sb, *fs)) - { - error (EXIT_FAILURE, 0, - _("ERROR: the directory %s initially had device/inode\n\ -numbers %lu/%lu, but now (after a chdir into it), the numbers for `.'\n\ -are %lu/%lu. That means that while rm was running, the directory\n\ -was replaced with either another directory or a link to another directory."), - quote (full_filename (dir_name)), - (unsigned long)(fs->st_dev), - (unsigned long)(fs->st_ino), - (unsigned long)(sb.st_dev), - (unsigned long)(sb.st_ino)); - } - } - - push_dir (dir_name); - - /* Save a copy of dir_name. Otherwise, remove_cwd_entries may clobber - it because it is just a pointer to the dir entry's d_name field, and - remove_cwd_entries may close the directory. */ - ASSIGN_STRDUPA (dir_name, dir_name); - - status = remove_cwd_entries (x); - - pop_dir (); - - /* Restore cwd. */ - if (need_save_cwd) - { - if (restore_cwd (&cwd, NULL, NULL)) - { - free_cwd (&cwd); - return RM_ERROR; - } - free_cwd (&cwd); - } - else if (chdir ("..") < 0) - { - error (0, errno, _("cannot change back to directory %s via `..'"), - quote (full_filename (dir_name))); - return RM_ERROR; - } - - if (x->interactive) - { - fprintf (stderr, _("%s: remove directory %s%s? "), - program_name, - quote (full_filename (dir_name)), - (status != RM_OK ? _(" (might be nonempty)") : "")); - if (!yesno ()) - { - return RM_USER_DECLINED; - } - } - - if (x->verbose) - printf (_("removing the directory itself: %s\n"), - quote (full_filename (dir_name))); - - if (rmdir (dir_name) && (errno != ENOENT || !x->ignore_missing_files)) - { - int saved_errno = errno; - -#ifndef EINVAL -# define EINVAL 0 -#endif - /* See if rmdir just failed because DIR_NAME is the current directory. - If so, give a better diagnostic than `rm: cannot remove directory - `...': Invalid argument' */ - if (errno == EINVAL && same_file (".", dir_name)) - { - error (0, 0, _("cannot remove current directory %s"), - quote (full_filename (dir_name))); - } - else - { - error (0, saved_errno, _("cannot remove directory %s"), - quote (full_filename (dir_name))); - } - return RM_ERROR; - } - - return status; -} - -/* Remove the file or directory specified by FS after checking appropriate - things. Return RM_OK if it is removed, and RM_ERROR or RM_USER_DECLINED - if not. If USER_SPECIFIED_NAME is non-zero, then the name part of FS may - be `.', `..', or may contain slashes. Otherwise, it must be a simple file - name (and hence must specify a file in the current directory). */ - -enum RM_status -rm (struct File_spec *fs, int user_specified_name, const struct rm_options *x) -{ - mode_t filetype_mode; - - if (user_specified_name) - { - /* CAUTION: this use of base_name works only because any - trailing slashes in fs->filename have already been removed. */ - char *base = base_name (fs->filename); - - if (DOT_OR_DOTDOT (base)) - { - error (0, 0, _("cannot remove `.' or `..'")); - return RM_ERROR; - } - } - - if (fspec_get_filetype_mode (fs, &filetype_mode)) - { - if (x->ignore_missing_files && errno == ENOENT) - return RM_OK; - - error (0, errno, _("cannot remove %s"), - quote (full_filename (fs->filename))); - return RM_ERROR; - } - -#ifdef ENABLE_CYCLE_CHECK - if (S_ISDIR (filetype_mode)) - { - struct active_dir_ent *old_ent; - struct active_dir_ent *new_ent; - - /* If there is already a directory in the map with the same device - and inode numbers, then there is a directory cycle. */ - - if (fspec_get_device_number (fs)) - { - error (0, errno, _("cannot stat %s"), - quote (full_filename (fs->filename))); - return RM_ERROR; - } - new_ent = make_active_dir_ent (fs->st_ino, fs->st_dev, current_depth ()); - old_ent = hash_lookup (active_dir_map, new_ent); - if (old_ent) - { - error (0, 0, _("\ -WARNING: Circular directory structure.\n\ -This almost certainly means that you have a corrupted file system.\n\ -NOTIFY YOUR SYSTEM MANAGER.\n\ -The following two directories have the same inode number:\n")); - print_nth_dir (stderr, old_ent->depth); - fprintf (stderr, "\n%s\n", quote (full_filename (fs->filename))); - fflush (stderr); - - if (x->interactive) - { - error (0, 0, _("continue? ")); - if (yesno ()) - return RM_ERROR; - } - exit (1); - } - - /* Put this directory in the active_dir_map. */ - if (! hash_insert (active_dir_map, new_ent)) - xalloc_die (); - } -#endif - - if (!S_ISDIR (filetype_mode) || x->unlink_dirs) - { - return remove_file (fs, x); - } - else - { - int need_save_cwd = user_specified_name; - enum RM_status status; - - if (need_save_cwd) - need_save_cwd = (strchr (fs->filename, '/') != NULL); - - status = remove_dir (fs, need_save_cwd, x); - -#ifdef ENABLE_CYCLE_CHECK - { - struct active_dir_ent tmp; - struct active_dir_ent *old_ent; - - /* Remove this directory from the active_dir_map. */ - tmp.st_ino = fs->st_ino; - assert (fs->have_device); - tmp.st_dev = fs->st_dev; - old_ent = hash_delete (active_dir_map, &tmp); - assert (old_ent != NULL); - free (old_ent); - } -#endif - - return status; - } -} - -void -remove_init (void) -{ - /* Initialize dir-stack obstacks. */ - obstack_init (&dir_stack); - obstack_init (&len_stack); - -#ifdef ENABLE_CYCLE_CHECK - active_dir_map = hash_initialize (ACTIVE_DIR_INITIAL_CAPACITY, NULL, - hash_active_dir_ent, - hash_compare_active_dir_ents, free); -#endif -} - -void -remove_fini (void) -{ -#ifdef ENABLE_CYCLE_CHECK - hash_free (active_dir_map); -#endif - - obstack_free (&dir_stack, NULL); - obstack_free (&len_stack, NULL); -} diff --git a/src/apps/bin/gnu/remove.h b/src/apps/bin/gnu/remove.h deleted file mode 100644 index deb5d628c3..0000000000 --- a/src/apps/bin/gnu/remove.h +++ /dev/null @@ -1,51 +0,0 @@ - -struct rm_options -{ - /* If nonzero, ignore nonexistent files. */ - int ignore_missing_files; - - /* If nonzero, query the user about whether to remove each file. */ - int interactive; - - /* If nonzero, recursively remove directories. */ - int recursive; - - /* If nonzero, stdin is a tty. */ - int stdin_tty; - - /* If nonzero, remove directories with unlink instead of rmdir, and don't - require a directory to be empty before trying to unlink it. - Only works for the super-user. */ - int unlink_dirs; - - /* If nonzero, display the name of each file removed. */ - int verbose; -}; - -enum RM_status -{ - /* These must be listed in order of increasing seriousness. */ - RM_OK = 1, - RM_USER_DECLINED, - RM_ERROR -}; - -#define VALID_STATUS(S) \ - ((S) == RM_OK || (S) == RM_USER_DECLINED || (S) == RM_ERROR) - -struct File_spec -{ - char *filename; - unsigned int have_filetype_mode:1; - unsigned int have_full_mode:1; - unsigned int have_device:1; - mode_t mode; - ino_t st_ino; - dev_t st_dev; -}; - -enum RM_status rm PARAMS ((struct File_spec *fs, int user_specified_name, - const struct rm_options *x)); -void fspec_init_file PARAMS ((struct File_spec *fs, const char *filename)); -void remove_init PARAMS ((void)); -void remove_fini PARAMS ((void)); diff --git a/src/apps/bin/gnu/rm.c b/src/apps/bin/gnu/rm.c deleted file mode 100644 index 0000c70b7b..0000000000 --- a/src/apps/bin/gnu/rm.c +++ /dev/null @@ -1,205 +0,0 @@ -/* `rm' file deletion utility for GNU. - Copyright (C) 88, 90, 91, 1994-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by Paul Rubin, David MacKenzie, and Richard Stallman. - Reworked to use chdir and hash tables by Jim Meyering. */ - -/* Implementation overview: - - In the `usual' case, RM saves no state for directories it is processing. - When a removal fails (either due to an error or to an interactive `no' - reply), the failure is noted (see description of `ht' in remove.c's - remove_cwd_entries function) so that when/if the containing directory - is reopened, RM doesn't try to remove the entry again. - - RM may delete arbitrarily deep hierarchies -- even ones in which file - names (from root to leaf) are longer than the system-imposed maximum. - It does this by using chdir to change to each directory in turn before - removing the entries in that directory. - - RM detects directory cycles by maintaining a table of the currently - active directories. See the description of active_dir_map in remove.c. - - RM is careful to avoid forming full file names whenever possible. - A full file name is formed only when it is about to be used -- e.g. - in a diagnostic or in an interactive-mode prompt. - - RM minimizes the number of lstat system calls it makes. On systems - that have valid d_type data in directory entries, RM makes only one - lstat call per command line argument -- regardless of the depth of - the hierarchy. */ - -#include -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "remove.h" -#include "save-cwd.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "rm" - -#define AUTHORS \ - "Paul Rubin, David MacKenzie, Richard Stallman, and Jim Meyering" - -void strip_trailing_slashes (); - -/* Name this program was run with. */ -char *program_name; - -static struct option const long_opts[] = -{ - {"directory", no_argument, NULL, 'd'}, - {"force", no_argument, NULL, 'f'}, - {"interactive", no_argument, NULL, 'i'}, - {"recursive", no_argument, NULL, 'r'}, - {"verbose", no_argument, NULL, 'v'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]... FILE...\n"), program_name); - printf (_("\ -Remove (unlink) the FILE(s).\n\ -\n\ - -d, --directory unlink directory, even if non-empty (super-user only)\n\ - -f, --force ignore nonexistent files, never prompt\n\ - -i, --interactive prompt before any removal\n\ - -r, -R, --recursive remove the contents of directories recursively\n\ - -v, --verbose explain what is being done\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -To remove a file whose name starts with a `-', for example `-foo',\n\ -use one of these commands:\n\ - %s -- -foo\n\ -\n\ - %s ./-foo\n\ -\n\ -Note that if you use rm to remove a file, it is usually possible to recover\n\ -the contents of that file. If you want more assurance that the contents are\n\ -truly unrecoverable, consider using shred.\n\ -"), - program_name, program_name); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -static void -rm_option_init (struct rm_options *x) -{ - x->unlink_dirs = 0; - x->ignore_missing_files = 0; - x->interactive = 0; - x->recursive = 0; - x->stdin_tty = isatty (STDIN_FILENO); - x->verbose = 0; -} - -int -main (int argc, char **argv) -{ - struct rm_options x; - int fail = 0; - int c; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - rm_option_init (&x); - - while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1) - { - switch (c) - { - case 0: /* Long option. */ - break; - case 'd': - x.unlink_dirs = 1; - break; - case 'f': - x.interactive = 0; - x.ignore_missing_files = 1; - break; - case 'i': - x.interactive = 1; - x.ignore_missing_files = 0; - break; - case 'r': - case 'R': - x.recursive = 1; - break; - case 'v': - x.verbose = 1; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - if (optind == argc) - { - if (x.ignore_missing_files) - exit (0); - else - { - error (0, 0, _("too few arguments")); - usage (1); - } - } - - remove_init (); - - for (; optind < argc; optind++) - { - struct File_spec fs; - enum RM_status status; - - /* Stripping slashes is harmless for rmdir; - if the arg is not a directory, it will fail with ENOTDIR. */ - strip_trailing_slashes (argv[optind]); - fspec_init_file (&fs, argv[optind]); - status = rm (&fs, 1, &x); - assert (VALID_STATUS (status)); - if (status == RM_ERROR) - fail = 1; - } - - remove_fini (); - - exit (fail); -} diff --git a/src/apps/bin/gnu/rmdir.c b/src/apps/bin/gnu/rmdir.c deleted file mode 100644 index 260205c3c2..0000000000 --- a/src/apps/bin/gnu/rmdir.c +++ /dev/null @@ -1,239 +0,0 @@ -/* rmdir -- remove directories - Copyright (C) 90, 91, 1995-2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Options: - -p, --parent Remove any parent dirs that are explicitly mentioned - in an argument, if they become empty after the - argument file is removed. - - David MacKenzie */ - -#include -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "quote.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "rmdir" - -#define AUTHORS "David MacKenzie" - -#ifndef EEXIST -# define EEXIST 0 -#endif - -#ifndef ENOTEMPTY -# define ENOTEMPTY 0 -#endif - -void strip_trailing_slashes (); - -/* The name this program was run with. */ -char *program_name; - -/* If nonzero, remove empty parent directories. */ -static int empty_paths; - -/* If nonzero, don't treat failure to remove a nonempty directory - as an error. */ -static int ignore_fail_on_non_empty; - -/* If nonzero, output a diagnostic for every directory processed. */ -static int verbose; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - IGNORE_FAIL_ON_NON_EMPTY_OPTION = CHAR_MAX + 1 -}; - -static struct option const longopts[] = -{ - /* Don't name this `--force' because it's not close enough in meaning - to e.g. rm's -f option. */ - {"ignore-fail-on-non-empty", no_argument, NULL, - IGNORE_FAIL_ON_NON_EMPTY_OPTION}, - - {"path", no_argument, NULL, 'p'}, - {"parents", no_argument, NULL, 'p'}, - {"verbose", no_argument, NULL, 'v'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -}; - -/* Return nonzero if ERROR_NUMBER is one of the values associated - with a failed rmdir due to non-empty target directory. */ - -static int -errno_rmdir_non_empty (int error_number) -{ - return (error_number == RMDIR_ERRNO_NOT_EMPTY); -} - -/* Remove any empty parent directories of PATH. - If PATH contains slash characters, at least one of them - (beginning with the rightmost) is replaced with a NUL byte. */ - -static int -remove_parents (char *path) -{ - char *slash; - int fail = 0; - - while (1) - { - slash = strrchr (path, '/'); - if (slash == NULL) - break; - /* Remove any characters after the slash, skipping any extra - slashes in a row. */ - while (slash > path && *slash == '/') - --slash; - slash[1] = 0; - - /* Give a diagnostic for each attempted removal if --verbose. */ - if (verbose) - error (0, 0, _("removing directory, %s"), path); - - fail = rmdir (path); - - if (fail) - { - /* Stop quietly if --ignore-fail-on-non-empty. */ - if (ignore_fail_on_non_empty - && errno_rmdir_non_empty (errno)) - { - fail = 0; - } - else - { - error (0, errno, "%s", quote (path)); - } - break; - } - } - return fail; -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name); - printf (_("\ -Remove the DIRECTORY(ies), if they are empty.\n\ -\n\ - --ignore-fail-on-non-empty\n\ - ignore each failure that is solely because a directory\n\ - is non-empty\n\ - -p, --parents remove DIRECTORY, then try to remove each directory\n\ - component of that path name. E.g., `rmdir -p a/b/c' is\n\ - similar to `rmdir a/b/c a/b a'.\n\ - -v, --verbose output a diagnostic for every directory processed\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - int errors = 0; - int optc; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - empty_paths = 0; - - while ((optc = getopt_long (argc, argv, "pv", longopts, NULL)) != -1) - { - switch (optc) - { - case 0: /* Long option. */ - break; - case 'p': - empty_paths = 1; - break; - case IGNORE_FAIL_ON_NON_EMPTY_OPTION: - ignore_fail_on_non_empty = 1; - break; - case 'v': - verbose = 1; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (1); - } - } - - if (optind == argc) - { - error (0, 0, _("too few arguments")); - usage (1); - } - - for (; optind < argc; ++optind) - { - int fail; - char *dir = argv[optind]; - - /* Stripping slashes is harmless for rmdir; - if the arg is not a directory, it will fail with ENOTDIR. */ - strip_trailing_slashes (dir); - - /* Give a diagnostic for each attempted removal if --verbose. */ - if (verbose) - error (0, 0, _("removing directory, %s"), dir); - - fail = rmdir (dir); - - if (fail) - { - if (ignore_fail_on_non_empty - && errno_rmdir_non_empty (errno)) - continue; - - error (0, errno, "%s", quote (dir)); - errors = 1; - } - else if (empty_paths) - { - errors += remove_parents (dir); - } - } - - exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); -} diff --git a/src/apps/bin/gnu/sync.c b/src/apps/bin/gnu/sync.c deleted file mode 100644 index 1afc5d9276..0000000000 --- a/src/apps/bin/gnu/sync.c +++ /dev/null @@ -1,74 +0,0 @@ -/* sync - update the super block - Copyright (C) 1994-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by Jim Meyering */ - -#include -#include -#include - -#include "system.h" -#include "error.h" -#include "long-options.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "sync" - -#define AUTHORS "Jim Meyering" - -/* The name this program was run with. */ -char *program_name; - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]\n"), program_name); - printf (_("\ -Force changed blocks to disk, update the super block.\n\ -\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, - AUTHORS, usage); - - if (argc != 1) - error (0, 0, _("ignoring all arguments")); - - sync (); - exit (0); -} diff --git a/src/apps/bin/gnu/sys2.h b/src/apps/bin/gnu/sys2.h deleted file mode 100644 index 48af648c30..0000000000 --- a/src/apps/bin/gnu/sys2.h +++ /dev/null @@ -1,606 +0,0 @@ -/* WARNING -- this file is temporary. It is shared between the - sh-utils, fileutils, and textutils packages. Once I find a little - more time, I'll merge the remaining things in system.h and everything - in this file will go back there. */ - -#if STAT_MACROS_BROKEN -# undef S_ISBLK -# undef S_ISCHR -# undef S_ISDIR -# undef S_ISDOOR -# undef S_ISFIFO -# undef S_ISLNK -# undef S_ISMPB -# undef S_ISMPC -# undef S_ISNWK -# undef S_ISREG -# undef S_ISSOCK -#endif /* STAT_MACROS_BROKEN. */ - -#ifndef S_IFMT -# define S_IFMT 0170000 -#endif -#if !defined(S_ISBLK) && defined(S_IFBLK) -# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#endif -#if !defined(S_ISCHR) && defined(S_IFCHR) -# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#endif -#if !defined(S_ISDIR) && defined(S_IFDIR) -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif -#if !defined(S_ISREG) && defined(S_IFREG) -# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif -#if !defined(S_ISFIFO) && defined(S_IFIFO) -# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#endif -#if !defined(S_ISLNK) && defined(S_IFLNK) -# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif -#if !defined(S_ISSOCK) && defined(S_IFSOCK) -# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) -#endif -#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ -# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) -# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) -#endif -#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ -# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) -#endif -#if !defined(S_ISDOOR) && defined(S_IFDOOR) /* Solaris 2.5 and up */ -# define S_ISDOOR(m) (((m) & S_IFMT) == S_IFDOOR) -#endif - -#if !S_ISUID -# define S_ISUID 04000 -#endif -#if !S_ISGID -# define S_ISGID 02000 -#endif - -/* S_ISVTX is a common extension to POSIX.1. */ -#ifndef S_ISVTX -# define S_ISVTX 01000 -#endif - -#if !S_IRUSR && S_IREAD -# define S_IRUSR S_IREAD -#endif -#if !S_IRUSR -# define S_IRUSR 00400 -#endif -#if !S_IRGRP -# define S_IRGRP (S_IRUSR >> 3) -#endif -#if !S_IROTH -# define S_IROTH (S_IRUSR >> 6) -#endif - -#if !S_IWUSR && S_IWRITE -# define S_IWUSR S_IWRITE -#endif -#if !S_IWUSR -# define S_IWUSR 00200 -#endif -#if !S_IWGRP -# define S_IWGRP (S_IWUSR >> 3) -#endif -#if !S_IWOTH -# define S_IWOTH (S_IWUSR >> 6) -#endif - -#if !S_IXUSR && S_IEXEC -# define S_IXUSR S_IEXEC -#endif -#if !S_IXUSR -# define S_IXUSR 00100 -#endif -#if !S_IXGRP -# define S_IXGRP (S_IXUSR >> 3) -#endif -#if !S_IXOTH -# define S_IXOTH (S_IXUSR >> 6) -#endif - -#if !S_IRWXU -# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) -#endif -#if !S_IRWXG -# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) -#endif -#if !S_IRWXO -# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) -#endif - -/* S_IXUGO is a common extension to POSIX.1. */ -#if !S_IXUGO -# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) -#endif - -#ifndef S_IRWXUGO -# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO) -#endif - -/* All the mode bits that can be affected by chmod. */ -#define CHMOD_MODE_BITS \ - (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) - -#ifdef ST_MTIM_NSEC -# define ST_TIME_CMP_NS(a, b, ns) ((a).ns < (b).ns ? -1 : (a).ns > (b).ns) -#else -# define ST_TIME_CMP_NS(a, b, ns) 0 -#endif -#define ST_TIME_CMP(a, b, s, ns) \ - ((a).s < (b).s ? -1 : (a).s > (b).s ? 1 : ST_TIME_CMP_NS(a, b, ns)) -#define ATIME_CMP(a, b) ST_TIME_CMP (a, b, st_atime, st_atim.ST_MTIM_NSEC) -#define CTIME_CMP(a, b) ST_TIME_CMP (a, b, st_ctime, st_ctim.ST_MTIM_NSEC) -#define MTIME_CMP(a, b) ST_TIME_CMP (a, b, st_mtime, st_mtim.ST_MTIM_NSEC) - -#ifndef RETSIGTYPE -# define RETSIGTYPE void -#endif - -#ifndef __GNUC__ -# if HAVE_ALLOCA_H -# include -# else -# ifdef _AIX - # pragma alloca -# else -# ifdef _WIN32 -# include -# include -# else -# ifndef alloca -char *alloca (); -# endif -# endif -# endif -# endif -#endif - -#ifdef __DJGPP__ - /* We need the declaration of setmode. */ -# include - /* We need the declaration of __djgpp_set_ctrl_c. */ -# include -#endif - -#if HAVE_STDINT_H -# include -#endif - -#if HAVE_INTTYPES_H -# include /* for the definition of UINTMAX_MAX */ -#endif - -#include - -/* Jim Meyering writes: - - "... Some ctype macros are valid only for character codes that - isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when - using /bin/cc or gcc but without giving an ansi option). So, all - ctype uses should be through macros like ISPRINT... If - STDC_HEADERS is defined, then autoconf has verified that the ctype - macros don't need to be guarded with references to isascii. ... - Defining isascii to 1 should let any compiler worth its salt - eliminate the && through constant folding." - - Bruno Haible adds: - - "... Furthermore, isupper(c) etc. have an undefined result if c is - outside the range -1 <= c <= 255. One is tempted to write isupper(c) - with c being of type `char', but this is wrong if c is an 8-bit - character >= 128 which gets sign-extended to a negative value. - The macro ISUPPER protects against this as well." */ - -#if STDC_HEADERS || (!defined (isascii) && !HAVE_ISASCII) -# define IN_CTYPE_DOMAIN(c) 1 -#else -# define IN_CTYPE_DOMAIN(c) isascii(c) -#endif - -#ifdef isblank -# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c)) -#else -# define ISBLANK(c) ((c) == ' ' || (c) == '\t') -#endif -#ifdef isgraph -# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c)) -#else -# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c)) -#endif - -/* This is defined in on at least Solaris2.6 systems. */ -#undef ISPRINT - -#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) -#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c)) -#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) -#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c)) -#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) -#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c)) -#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) -#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) -#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) -#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) - -#if STDC_HEADERS -# define TOLOWER(Ch) tolower (Ch) -# define TOUPPER(Ch) toupper (Ch) -#else -# define TOLOWER(Ch) (ISUPPER (Ch) ? tolower (Ch) : (Ch)) -# define TOUPPER(Ch) (ISLOWER (Ch) ? toupper (Ch) : (Ch)) -#endif - -/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: - - Its arg may be any int or unsigned int; it need not be an unsigned char. - - It's guaranteed to evaluate its argument exactly once. - - It's typically faster. - Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that - only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless - it's important to use the locale's definition of `digit' even when the - host does not conform to Posix. */ -#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) - -#ifndef PARAMS -# if PROTOTYPES -# define PARAMS(Args) Args -# else -# define PARAMS(Args) () -# endif -#endif - -/* Take care of NLS matters. */ - -#if HAVE_LOCALE_H -# include -#endif -#if !HAVE_SETLOCALE -# define setlocale(Category, Locale) /* empty */ -#endif - -#if ENABLE_NLS -# include -# if HAVE_GETTEXT && !HAVE_DCGETTEXT && !defined dcgettext -# define dcgettext(Domain, Text, Category) Text -# endif -# define _(Text) gettext (Text) -#else -# undef bindtextdomain -# define bindtextdomain(Domain, Directory) /* empty */ -# undef textdomain -# define textdomain(Domain) /* empty */ -# undef dcgettext -# define dcgettext(Domainname, Text, Category) Text -# define _(Text) Text -#endif -#define N_(Text) Text - -#define STREQ(a, b) (strcmp ((a), (b)) == 0) - -#if !HAVE_DECL_FREE -void free (); -#endif - -#if !HAVE_DECL_MALLOC -char *malloc (); -#endif - -#if !HAVE_DECL_MEMCHR -char *memchr (); -#endif - -#if !HAVE_DECL_REALLOC -char *realloc (); -#endif - -#if !HAVE_DECL_STPCPY -# ifndef stpcpy -char *stpcpy (); -# endif -#endif - -#if !HAVE_DECL_STRNDUP -char *strndup (); -#endif - -#if !HAVE_DECL_STRSTR -char *strstr (); -#endif - -#if !HAVE_DECL_GETENV -char *getenv (); -#endif - -#if !HAVE_DECL_LSEEK -off_t lseek (); -#endif - -/* This is needed on some AIX systems. */ -#if !HAVE_DECL_STRTOUL -unsigned long strtoul (); -#endif - -/* This is needed on some AIX systems. */ -#if !HAVE_DECL_STRTOULL && HAVE_UNSIGNED_LONG_LONG -unsigned long long strtoull (); -#endif - -#if !HAVE_DECL_GETLOGIN -char *getlogin (); -#endif - -#if !HAVE_DECL_TTYNAME -char *ttyname (); -#endif - -#if !HAVE_DECL_GETEUID -uid_t geteuid (); -#endif - -#if !HAVE_DECL_GETPWUID -struct passwd *getpwuid (); -#endif - -#if !HAVE_DECL_GETGRGID -struct group *getgrgid (); -#endif - -#if !HAVE_DECL_GETUID -uid_t getuid (); -#endif - -#include "xalloc.h" - -#if ! defined HAVE_MEMPCPY && ! defined mempcpy -/* Be CAREFUL that there are no side effects in N. */ -# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) -#endif - -/* These are wrappers for functions/macros from GNU libc. - The standard I/O functions are thread-safe. These *_unlocked ones - are more efficient but not thread-safe. That they're not thread-safe - is fine since all these applications are single threaded. */ - -#if HAVE_CLEARERR_UNLOCKED -# undef clearerr -# define clearerr(S) clearerr_unlocked (S) -#endif - -#if HAVE_FEOF_UNLOCKED -# undef feof -# define feof(S) feof_unlocked (S) -#endif - -#if HAVE_FERROR_UNLOCKED -# undef ferror -# define ferror(S) ferror_unlocked (S) -#endif - -#if HAVE_FFLUSH_UNLOCKED -# undef fflush -# define fflush(S) fflush_unlocked (S) -#endif - -#if HAVE_FPUTC_UNLOCKED -# undef fputc -# define fputc(C, S) fputc_unlocked (C, S) -#endif - -#if HAVE_FREAD_UNLOCKED -# undef fread -# define fread(P, Z, N, S) fread_unlocked (P, Z, N, S) -#endif - -#if HAVE_FWRITE_UNLOCKED -# undef fwrite -# define fwrite(P, Z, N, S) fwrite_unlocked (P, Z, N, S) -#endif - -#if HAVE_GETC_UNLOCKED -# undef getc -# define getc(S) getc_unlocked (S) -#endif - -#if HAVE_GETCHAR_UNLOCKED -# undef getchar -# define getchar(S) getchar_unlocked (S) -#endif - -#if HAVE_PUTC_UNLOCKED -# undef putc -# define putc(C, S) putc_unlocked (C, S) -#endif - -#if HAVE_PUTCHAR_UNLOCKED -# undef putchar -# define putchar(C) putchar_unlocked (C) -#endif - -#define SAME_INODE(Stat_buf_1, Stat_buf_2) \ - ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \ - && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev) - -#define DOT_OR_DOTDOT(Basename) \ - (Basename[0] == '.' && (Basename[1] == '\0' \ - || (Basename[1] == '.' && Basename[2] == '\0'))) - -#if SETVBUF_REVERSED -# define SETVBUF(Stream, Buffer, Type, Size) \ - setvbuf (Stream, Type, Buffer, Size) -#else -# define SETVBUF(Stream, Buffer, Type, Size) \ - setvbuf (Stream, Buffer, Type, Size) -#endif - -char *base_name PARAMS ((char const *)); - -/* Factor out some of the common --help and --version processing code. */ - -/* These enum values cannot possibly conflict with the option values - ordinarily used by commands, including CHAR_MAX + 1, etc. Avoid - CHAR_MIN - 1, as it may equal -1, the getopt end-of-options value. */ -enum -{ - GETOPT_HELP_CHAR = (CHAR_MIN - 2), - GETOPT_VERSION_CHAR = (CHAR_MIN - 3) -}; - -#define GETOPT_HELP_OPTION_DECL \ - "help", no_argument, 0, GETOPT_HELP_CHAR -#define GETOPT_VERSION_OPTION_DECL \ - "version", no_argument, 0, GETOPT_VERSION_CHAR - -#define case_GETOPT_HELP_CHAR \ - case GETOPT_HELP_CHAR: \ - usage (EXIT_SUCCESS); \ - break; - -#include "closeout.h" -#include "version-etc.h" - -#define case_GETOPT_VERSION_CHAR(Program_name, Authors) \ - case GETOPT_VERSION_CHAR: \ - version_etc (stdout, Program_name, PACKAGE, VERSION, Authors); \ - exit (EXIT_SUCCESS); \ - break; - -#ifndef MAX -# define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif - -#ifndef MIN -# define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -#ifndef CHAR_BIT -# define CHAR_BIT 8 -#endif - -/* The extra casts work around common compiler bugs. */ -#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) -/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. - It is necessary at least when t == time_t. */ -#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ - ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) -#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) - -/* Upper bound on the string length of an integer converted to string. - 302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit; - add 1 for integer division truncation; add 1 more for a minus sign. */ -#define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2) - -#ifndef CHAR_MIN -# define CHAR_MIN TYPE_MINIMUM (char) -#endif - -#ifndef CHAR_MAX -# define CHAR_MAX TYPE_MAXIMUM (char) -#endif - -#ifndef SCHAR_MIN -# define SCHAR_MIN (-1 - SCHAR_MAX) -#endif - -#ifndef SCHAR_MAX -# define SCHAR_MAX (CHAR_MAX == UCHAR_MAX ? CHAR_MAX / 2 : CHAR_MAX) -#endif - -#ifndef UCHAR_MAX -# define UCHAR_MAX TYPE_MAXIMUM (unsigned char) -#endif - -#ifndef SHRT_MIN -# define SHRT_MIN TYPE_MINIMUM (short int) -#endif - -#ifndef SHRT_MAX -# define SHRT_MAX TYPE_MAXIMUM (short int) -#endif - -#ifndef INT_MAX -# define INT_MAX TYPE_MAXIMUM (int) -#endif - -#ifndef UINT_MAX -# define UINT_MAX TYPE_MAXIMUM (unsigned int) -#endif - -#ifndef LONG_MAX -# define LONG_MAX TYPE_MAXIMUM (long) -#endif - -#ifndef ULONG_MAX -# define ULONG_MAX TYPE_MAXIMUM (unsigned long) -#endif - -#ifndef SIZE_MAX -# define SIZE_MAX TYPE_MAXIMUM (size_t) -#endif - -#ifndef UINTMAX_MAX -# define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t) -#endif - -#ifndef OFF_T_MIN -# define OFF_T_MIN TYPE_MINIMUM (off_t) -#endif - -#ifndef OFF_T_MAX -# define OFF_T_MAX TYPE_MAXIMUM (off_t) -#endif - -#ifndef UID_T_MAX -# define UID_T_MAX TYPE_MAXIMUM (uid_t) -#endif - -#ifndef GID_T_MAX -# define GID_T_MAX TYPE_MAXIMUM (gid_t) -#endif - -#ifndef PID_T_MAX -# define PID_T_MAX TYPE_MAXIMUM (pid_t) -#endif - -#ifndef CHAR_BIT -# define CHAR_BIT 8 -#endif - -/* Use this to suppress gcc's `...may be used before initialized' warnings. */ -#ifdef lint -# define IF_LINT(Code) Code -#else -# define IF_LINT(Code) /* empty */ -#endif - -#ifndef __attribute__ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ -# define __attribute__(x) -# endif -#endif - -#ifndef ATTRIBUTE_NORETURN -# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) -#endif - -#ifndef ATTRIBUTE_UNUSED -# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif - -#if defined strdupa -# define ASSIGN_STRDUPA(DEST, S) \ - do { DEST = strdupa(S); } while (0) -#else -# define ASSIGN_STRDUPA(DEST, S) \ - do \ - { \ - const char *s_ = (S); \ - size_t len_ = strlen (s_) + 1; \ - char *tmp_dest_ = (char *) alloca (len_); \ - DEST = memcpy (tmp_dest_, (s_), len_); \ - } \ - while (0) -#endif diff --git a/src/apps/bin/gnu/system.h b/src/apps/bin/gnu/system.h deleted file mode 100644 index 582fd7c514..0000000000 --- a/src/apps/bin/gnu/system.h +++ /dev/null @@ -1,278 +0,0 @@ -/* system-dependent definitions for fileutils, textutils, and sh-utils packages. - Copyright (C) 1989, 1991-2000 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Include sys/types.h before this file. */ - -#include - -#if !defined(HAVE_MKFIFO) -# define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0)) -#endif - -#if HAVE_SYS_PARAM_H -# include -#endif - -/* should be included before any preprocessor test - of _POSIX_VERSION. */ -#if HAVE_UNISTD_H -# include -#endif - -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -#endif - -#ifndef STDOUT_FILENO -# define STDOUT_FILENO 1 -#endif - -#ifndef STDERR_FILENO -# define STDERR_FILENO 2 -#endif - - -#if HAVE_LIMITS_H -/* limits.h must come before pathmax.h because limits.h on some systems - undefs PATH_MAX, whereas pathmax.h sets PATH_MAX. */ -# include -#endif - -#include "pathmax.h" - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -/* Since major is a function on SVR4, we can't use `ifndef major'. */ -#if MAJOR_IN_MKDEV -# include -# define HAVE_MAJOR -#endif -#if MAJOR_IN_SYSMACROS -# include -# define HAVE_MAJOR -#endif -#ifdef major /* Might be defined in sys/types.h. */ -# define HAVE_MAJOR -#endif - -#ifndef HAVE_MAJOR -# define major(dev) (((dev) >> 8) & 0xff) -# define minor(dev) ((dev) & 0xff) -# define makedev(maj, min) (((maj) << 8) | (min)) -#endif -#undef HAVE_MAJOR - -#if HAVE_UTIME_H -# include -#endif - -/* Some systems (even some that do have ) don't declare this - structure anywhere. */ -#ifndef HAVE_STRUCT_UTIMBUF -struct utimbuf -{ - long actime; - long modtime; -}; -#endif - -/* Don't use bcopy! Use memmove if source and destination may overlap, - memcpy otherwise. */ - -#if HAVE_STRING_H -# if !STDC_HEADERS && HAVE_MEMORY_H -# include -# endif -# include -#else -# include -#endif - -#include -#ifndef errno -extern int errno; -#endif - -#if HAVE_STDLIB_H -# define getopt system_getopt -# include -# undef getopt -#endif - -/* The following test is to work around the gross typo in - systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE - is defined to 0, not 1. */ -#if !EXIT_FAILURE -# undef EXIT_FAILURE -# define EXIT_FAILURE 1 -#endif - -#ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -#endif - -#if HAVE_FCNTL_H -# include -#else -# include -#endif - -#if !defined (SEEK_SET) -# define SEEK_SET 0 -# define SEEK_CUR 1 -# define SEEK_END 2 -#endif -#ifndef F_OK -# define F_OK 0 -# define X_OK 1 -# define W_OK 2 -# define R_OK 4 -#endif - -/* For systems that distinguish between text and binary I/O. - O_BINARY is usually declared in fcntl.h */ -#if !defined O_BINARY && defined _O_BINARY - /* For MSC-compatible compilers. */ -# define O_BINARY _O_BINARY -# define O_TEXT _O_TEXT -#endif - -#ifdef __BEOS__ - /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */ -# undef O_BINARY -# undef O_TEXT -#endif - -#if O_BINARY -# ifndef __DJGPP__ -# define setmode _setmode -# define fileno(_fp) _fileno (_fp) -# endif /* not DJGPP */ -# define SET_BINARY(_f) do {if (!isatty(_f)) setmode (_f, O_BINARY);} while (0) -# define SET_BINARY2(_f1, _f2) \ - do { \ - if (!isatty (_f1)) \ - { \ - setmode (_f1, O_BINARY); \ - if (!isatty (_f2)) \ - setmode (_f2, O_BINARY); \ - } \ - } while(0) -#else -# define SET_BINARY(f) (void)0 -# define SET_BINARY2(f1,f2) (void)0 -# define O_BINARY 0 -# define O_TEXT 0 -#endif /* O_BINARY */ - -#if HAVE_DIRENT_H -# include -# define NLENGTH(direct) (strlen((direct)->d_name)) -#else /* not HAVE_DIRENT_H */ -# define dirent direct -# define NLENGTH(direct) ((direct)->d_namlen) -# if HAVE_SYS_NDIR_H -# include -# endif /* HAVE_SYS_NDIR_H */ -# if HAVE_SYS_DIR_H -# include -# endif /* HAVE_SYS_DIR_H */ -# if HAVE_NDIR_H -# include -# endif /* HAVE_NDIR_H */ -#endif /* HAVE_DIRENT_H */ - -#if CLOSEDIR_VOID -/* Fake a return value. */ -# define CLOSEDIR(d) (closedir (d), 0) -#else -# define CLOSEDIR(d) closedir (d) -#endif - -/* Get or fake the disk device blocksize. - Usually defined by sys/param.h (if at all). */ -#if !defined DEV_BSIZE && defined BSIZE -# define DEV_BSIZE BSIZE -#endif -#if !defined DEV_BSIZE && defined BBSIZE /* SGI */ -# define DEV_BSIZE BBSIZE -#endif -#ifndef DEV_BSIZE -# define DEV_BSIZE 4096 -#endif - -/* Extract or fake data from a `struct stat'. - ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes. - ST_NBLOCKS: Number of blocks in the file, including indirect blocks. - ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */ -#ifndef HAVE_STRUCT_STAT_ST_BLOCKS -# define ST_BLKSIZE(statbuf) DEV_BSIZE -# if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */ -# define ST_NBLOCKS(statbuf) \ - (S_ISREG ((statbuf).st_mode) \ - || S_ISDIR ((statbuf).st_mode) \ - ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0) -# else /* !_POSIX_SOURCE && BSIZE */ -# define ST_NBLOCKS(statbuf) \ - (S_ISREG ((statbuf).st_mode) \ - || S_ISDIR ((statbuf).st_mode) \ - ? st_blocks ((statbuf).st_size) : 0) -# endif /* !_POSIX_SOURCE && BSIZE */ -#else /* HAVE_STRUCT_STAT_ST_BLOCKS */ -/* Some systems, like Sequents, return st_blksize of 0 on pipes. */ -# define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \ - ? (statbuf).st_blksize : DEV_BSIZE) -# if defined(hpux) || defined(__hpux__) || defined(__hpux) -/* HP-UX counts st_blocks in 1024-byte units. - This loses when mixing HP-UX and BSD filesystems with NFS. */ -# define ST_NBLOCKSIZE 1024 -# else /* !hpux */ -# if defined(_AIX) && defined(_I386) -/* AIX PS/2 counts st_blocks in 4K units. */ -# define ST_NBLOCKSIZE (4 * 1024) -# else /* not AIX PS/2 */ -# if defined(_CRAY) -# define ST_NBLOCKS(statbuf) \ - (S_ISREG ((statbuf).st_mode) \ - || S_ISDIR ((statbuf).st_mode) \ - ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0) -# endif /* _CRAY */ -# endif /* not AIX PS/2 */ -# endif /* !hpux */ -#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */ - -#ifndef ST_NBLOCKS -# define ST_NBLOCKS(statbuf) \ - (S_ISREG ((statbuf).st_mode) \ - || S_ISDIR ((statbuf).st_mode) \ - ? (statbuf).st_blocks : 0) -#endif - -#ifndef ST_NBLOCKSIZE -# define ST_NBLOCKSIZE 512 -#endif - -#include "sys2.h" diff --git a/src/apps/bin/gnu/touch.c b/src/apps/bin/gnu/touch.c deleted file mode 100644 index 35fa58f4d1..0000000000 --- a/src/apps/bin/gnu/touch.c +++ /dev/null @@ -1,366 +0,0 @@ -/* touch -- change modification and access times of files - Copyright (C) 87, 1989-1991, 1995-2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* Written by Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie, - and Randy Smith. */ - -#include -#include -#include -#include - -#include "system.h" -#include "argmatch.h" -#include "error.h" -#include "getdate.h" -#include "posixtm.h" -#include "quote.h" -#include "safe-read.h" - -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "touch" - -#define AUTHORS \ - "Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie, and Randy Smith" - -#ifndef STDC_HEADERS -time_t time (); -#endif - -/* Bitmasks for `change_times'. */ -#define CH_ATIME 1 -#define CH_MTIME 2 - -#if !defined O_NDELAY -# define O_NDELAY 0 -#endif - -#if !defined O_NONBLOCK -# define O_NONBLOCK O_NDELAY -#endif - -#if !defined O_NOCTTY -# define O_NOCTTY 0 -#endif - -/* The name by which this program was run. */ -char *program_name; - -/* Which timestamps to change. */ -static int change_times; - -/* (-c) If nonzero, don't create if not already there. */ -static int no_create; - -/* (-d) If nonzero, date supplied on command line in get_date formats. */ -static int flexible_date; - -/* (-r) If nonzero, use times from a reference file. */ -static int use_ref; - -/* (-t) If nonzero, date supplied on command line in POSIX format. */ -static int posix_date; - -/* If nonzero, the only thing we have to do is change both the - modification and access time to the current time, so we don't - have to own the file, just be able to read and write it. - On some systems, we can do this if we own the file, even though - we have neither read nor write access to it. */ -static int amtime_now; - -/* New time to use when setting time. */ -static time_t newtime; - -/* File to use for -r. */ -static char *ref_file; - -/* Info about the reference file. */ -static struct stat ref_stats; - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - TIME_OPTION = CHAR_MAX + 1 -}; - -static struct option const longopts[] = -{ - {"time", required_argument, 0, TIME_OPTION}, - {"no-create", no_argument, 0, 'c'}, - {"date", required_argument, 0, 'd'}, - {"file", required_argument, 0, 'r'}, /* FIXME: phase out --file */ - {"reference", required_argument, 0, 'r'}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {0, 0, 0, 0} -}; - -/* Valid arguments to the `--time' option. */ -static char const* const time_args[] = -{ - "atime", "access", "use", "mtime", "modify", 0 -}; - -/* The bits in `change_times' that those arguments set. */ -static int const time_masks[] = -{ - CH_ATIME, CH_ATIME, CH_ATIME, CH_MTIME, CH_MTIME -}; - -/* Update the time of file FILE according to the options given. - Return 0 if successful, 1 if an error occurs. */ - -static int -touch (const char *file) -{ - int status; - struct stat sbuf; - int fd = -1; - int open_errno = 0; - - if (! no_create) - { - /* Try to open FILE, creating it if necessary. */ - fd = open (file, O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (fd == -1) - open_errno = errno; - } - - if (! amtime_now) - { - /* We're setting only one of the time values. stat the target to get - the other one. If we have the file descriptor already, use fstat. - Otherwise, either we're in no-create mode (and hence didn't call open) - or FILE is inaccessible or a directory, so we have to use stat. */ - if (fd != -1 ? fstat (fd, &sbuf) : stat (file, &sbuf)) - { - if (open_errno) - error (0, open_errno, _("creating %s"), quote (file)); - else - error (0, errno, _("getting attributes of %s"), quote (file)); - close (fd); - return 1; - } - } - - if (fd != -1 && close (fd) < 0) - { - error (0, errno, _("creating %s"), quote (file)); - return 1; - } - - if (amtime_now) - { - /* Pass NULL to utime so it will not fail if we just have - write access to the file, but don't own it. */ - status = utime (file, NULL); - } - else - { - struct utimbuf utb; - - /* There's currently no interface to set file timestamps with - better than 1-second resolution, so discard any fractional - part of the source timestamp. */ - - if (use_ref) - { - utb.actime = ref_stats.st_atime; - utb.modtime = ref_stats.st_mtime; - } - else - utb.actime = utb.modtime = newtime; - - if (!(change_times & CH_ATIME)) - utb.actime = sbuf.st_atime; - - if (!(change_times & CH_MTIME)) - utb.modtime = sbuf.st_mtime; - - status = utime (file, &utb); - } - - if (status) - { - if (open_errno) - error (0, open_errno, _("creating %s"), quote (file)); - else - error (0, errno, _("setting times of %s"), quote (file)); - return 1; - } - - return 0; -} - -void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]... FILE...\n"), program_name); - printf (_(" or: %s [-acm] MMDDhhmm[YY] FILE... (obsolescent)\n"), - program_name); - printf (_("\ -Update the access and modification times of each FILE to the current time.\n\ -\n\ - -a change only the access time\n\ - -c, --no-create do not create any files\n\ - -d, --date=STRING parse STRING and use it instead of current time\n\ - -f (ignored)\n\ - -m change only the modification time\n\ - -r, --reference=FILE use this file's times instead of current time\n\ - -t STAMP use [[CC]YY]MMDDhhmm[.ss] instead of current time\n\ - --time=WORD set time given by WORD: access atime use (same as -a)\n\ - modify mtime (same as -m)\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -Note that the three time-date formats recognized for the -d and -t options\n\ -and for the obsolescent argument are all different.\n\ -")); - puts (_("\nReport bugs to .")); - } - exit (status); -} - -int -main (int argc, char **argv) -{ - int c; - int date_set = 0; - int err = 0; - - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - atexit (close_stdout); - - change_times = no_create = use_ref = posix_date = flexible_date = 0; - newtime = (time_t) -1; - - while ((c = getopt_long (argc, argv, "acd:fmr:t:", longopts, NULL)) != -1) - { - switch (c) - { - case 0: - break; - - case 'a': - change_times |= CH_ATIME; - break; - - case 'c': - no_create++; - break; - - case 'd': - flexible_date++; - newtime = get_date (optarg, NULL); - if (newtime == (time_t) -1) - error (1, 0, _("invalid date format %s"), quote (optarg)); - date_set++; - break; - - case 'f': - break; - - case 'm': - change_times |= CH_MTIME; - break; - - case 'r': - use_ref++; - ref_file = optarg; - break; - - case 't': - posix_date++; - newtime = posixtime (optarg, - PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS); - if (newtime == (time_t) -1) - error (1, 0, _("invalid date format %s"), quote (optarg)); - date_set++; - break; - - case TIME_OPTION: /* --time */ - change_times |= XARGMATCH ("--time", optarg, - time_args, time_masks); - break; - - case_GETOPT_HELP_CHAR; - - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - - default: - usage (1); - } - } - - if (change_times == 0) - change_times = CH_ATIME | CH_MTIME; - - if ((use_ref && (posix_date || flexible_date)) - || (posix_date && flexible_date)) - { - error (0, 0, _("cannot specify times from more than one source")); - usage (1); - } - - if (use_ref) - { - if (stat (ref_file, &ref_stats)) - error (1, errno, _("getting attributes of %s"), quote (ref_file)); - date_set++; - } - - /* The obsolescent `MMDDhhmm[YY]' form is valid IFF there are - two or more non-option arguments. */ - if (!date_set && 2 <= argc - optind && !STREQ (argv[optind - 1], "--")) - { - newtime = posixtime (argv[optind], PDS_TRAILING_YEAR); - if (newtime != (time_t) -1) - { - optind++; - date_set++; - } - } - if (!date_set) - { - if ((change_times & (CH_ATIME | CH_MTIME)) == (CH_ATIME | CH_MTIME)) - amtime_now = 1; - else - time (&newtime); - } - - if (optind == argc) - { - error (0, 0, _("file arguments missing")); - usage (1); - } - - for (; optind < argc; ++optind) - err += touch (argv[optind]); - - exit (err != 0); -} diff --git a/src/apps/bin/pwd/Jamfile b/src/apps/bin/pwd/Jamfile deleted file mode 100644 index 6879eaad5c..0000000000 --- a/src/apps/bin/pwd/Jamfile +++ /dev/null @@ -1,3 +0,0 @@ -SubDir OBOS_TOP src kernel apps pwd ; - -KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/apps/bin/pwd/pwd.c b/src/apps/bin/pwd/pwd.c deleted file mode 100644 index 5c703209d9..0000000000 --- a/src/apps/bin/pwd/pwd.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -static char *getcwd_logical(void); -int usage(void); -int version(void); - -int -main(int argc, char *argv[]) -{ - int physical = false; - int argOption; - char *pcTemp; - int indexptr = 0; - char * const * optargv = argv; - - struct option help_opt = { "help", no_argument, 0, 1 } ; - struct option version_opt = { "version", no_argument, 0, 2 } ; - - struct option options[] = { - help_opt, version_opt, 0 - }; - - while ((argOption = getopt_long(argc, optargv, "LP", options, &indexptr)) != -1) { - - switch (argOption) { - case 'L': // Logical - physical = false; - break; - case 'P': // Physical - physical = true; - break; - default: - switch (options[indexptr].val) { - case 1: // help - usage(); - exit(0); - case 2: // version - version(); - exit(0); - default: - break; - } - break; - } - } - argc -= optind; - - if (argc != 0) { - usage(); - } - else { - /* - * If the logical option was specified, and we can not find the logical currrent directory - * then behave as if -P (physical) was specified. - */ - if ((!physical && (pcTemp = getcwd_logical()) != NULL) || (pcTemp = getcwd(NULL, 0)) != NULL) - printf("%s\n", pcTemp); - else - exit(0); - } - return B_NO_ERROR; -} - - -int -usage(void) -{ - (void)fprintf(stderr, -"pwd OBOS (C)2003 MIT License. (http://www.openbeos.net/) - -Usage: pwd [OPTION]... -Print the current working directory path - - --help display this help and exit - --version display version information and exit - -L treat path as a Logical device - -P treat path as a Physical device (default)\n" ); - return; -} - -int -version(void) -{ - (void)fprintf(stderr, "pwd OBOS (C)2003 MIT License. (http://www.openbeos.net/)\n"); - return; -} - -static char * -getcwd_logical(void) -{ - struct stat logical, physical; - char *pwd; - - /* - * Check that $PWD is an absolute logical pathname referring to the current working directory. - */ - if ((pwd = getenv("PWD")) != NULL && *pwd == '/') { - if (stat(pwd, &logical) == -1 || stat(".", &physical) == -1) - return (NULL); - if (logical.st_dev == physical.st_dev && logical.st_ino == physical.st_ino) - return (pwd); - } - - errno = ENOENT; - return (NULL); -} -