Removed unused files

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11902 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2005-03-18 10:43:58 +00:00
parent a84a3aae19
commit 1929784f0c
36 changed files with 0 additions and 15458 deletions
-2
View File
@@ -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 ;
-84
View File
@@ -1,84 +0,0 @@
/*
basename(C) -- remove directory names from pathnames
OBOS Release 1.0 -- 1st January 2003
Additional Code by Sikosis ([email protected])
*/
#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);
}
-233
View File
@@ -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 <[email protected]>. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <grp.h>
#include <getopt.h>
#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 <[email protected]>."));
}
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);
}
-396
View File
@@ -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 <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#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 <[email protected]>."));
}
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);
}
-366
View File
@@ -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 <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#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;
}
-89
View File
@@ -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 */
-247
View File
@@ -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 <[email protected]>. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#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 <[email protected]>."));
}
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);
}
File diff suppressed because it is too large Load Diff
-161
View File
@@ -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
-235
View File
@@ -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 ([email protected]). */
#include <config.h>
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#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);
}
-8
View File
@@ -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));
-911
View File
@@ -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 <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <assert.h>
#include <getopt.h>
#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 <[email protected]>."));
}
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, &copy_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);
}
File diff suppressed because it is too large Load Diff
-952
View File
@@ -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 <[email protected]>.
--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 <config.h>
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include <assert.h>
#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 <[email protected]>."));
}
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);
}
-794
View File
@@ -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 <config.h>
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <assert.h>
#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 <[email protected]>."));
}
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);
}
-643
View File
@@ -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 <[email protected]> */
#ifdef _AIX
#pragma alloca
#endif
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#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 <sys/wait.h>
#endif
#if HAVE_VALUES_H
# include <values.h>
#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, &copy_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 <[email protected]>."));
}
exit (status);
}
-563
View File
@@ -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 <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#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 <[email protected]>."));
}
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);
}
-2
View File
@@ -1,2 +0,0 @@
#include "ls.h"
int ls_mode = LS_MULTI_COL;
-2
View File
@@ -1,2 +0,0 @@
#include "ls.h"
int ls_mode = LS_LS;
-2
View File
@@ -1,2 +0,0 @@
#include "ls.h"
int ls_mode = LS_LONG_FORMAT;
File diff suppressed because it is too large Load Diff
-10
View File
@@ -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;
-205
View File
@@ -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 <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#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 <[email protected]>."));
}
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);
}
-147
View File
@@ -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 <[email protected]> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#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 <[email protected]>."));
}
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
}
-238
View File
@@ -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 <djm@ai.mit.edu> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#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 <[email protected]>."));
}
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);
}
-495
View File
@@ -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 <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <assert.h>
#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, &copy_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 <[email protected]>."));
}
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);
}
-946
View File
@@ -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 <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <assert.h>
#if HAVE_STDBOOL_H
# include <stdbool.h>
#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);
}
-51
View File
@@ -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));
-205
View File
@@ -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 <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <assert.h>
#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 <[email protected]>."));
}
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);
}
-239
View File
@@ -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 <djm@ai.mit.edu> */
#include <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#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 <[email protected]>."));
}
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);
}
-74
View File
@@ -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 <config.h>
#include <stdio.h>
#include <sys/types.h>
#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 <[email protected]>."));
}
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);
}
-606
View File
@@ -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 <alloca.h>
# else
# ifdef _AIX
# pragma alloca
# else
# ifdef _WIN32
# include <malloc.h>
# include <io.h>
# else
# ifndef alloca
char *alloca ();
# endif
# endif
# endif
# endif
#endif
#ifdef __DJGPP__
/* We need the declaration of setmode. */
# include <io.h>
/* We need the declaration of __djgpp_set_ctrl_c. */
# include <sys/exceptn.h>
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h> /* for the definition of UINTMAX_MAX */
#endif
#include <ctype.h>
/* 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 <sys/euc.h> 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 <locale.h>
#endif
#if !HAVE_SETLOCALE
# define setlocale(Category, Locale) /* empty */
#endif
#if ENABLE_NLS
# include <libintl.h>
# 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
-278
View File
@@ -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 <sys/stat.h>
#if !defined(HAVE_MKFIFO)
# define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0))
#endif
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
/* <unistd.h> should be included before any preprocessor test
of _POSIX_VERSION. */
#if HAVE_UNISTD_H
# include <unistd.h>
#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 <limits.h>
#endif
#include "pathmax.h"
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
/* Since major is a function on SVR4, we can't use `ifndef major'. */
#if MAJOR_IN_MKDEV
# include <sys/mkdev.h>
# define HAVE_MAJOR
#endif
#if MAJOR_IN_SYSMACROS
# include <sys/sysmacros.h>
# 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 <utime.h>
#endif
/* Some systems (even some that do have <utime.h>) 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 <memory.h>
# endif
# include <string.h>
#else
# include <strings.h>
#endif
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#if HAVE_STDLIB_H
# define getopt system_getopt
# include <stdlib.h>
# 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 <fcntl.h>
#else
# include <sys/file.h>
#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 <dirent.h>
# 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 <sys/ndir.h>
# endif /* HAVE_SYS_NDIR_H */
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif /* HAVE_SYS_DIR_H */
# if HAVE_NDIR_H
# include <ndir.h>
# 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"
-366
View File
@@ -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 <config.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#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 <[email protected]>."));
}
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);
}
-3
View File
@@ -1,3 +0,0 @@
SubDir OBOS_TOP src kernel apps pwd ;
KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ;
-146
View File
@@ -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 <sys/stat.h>
#include <errno.h>
#include <getopt.h>
#include <ktypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
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);
}