/* chmod -- change permission modes of files
- Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1990, 1991, 1995 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
David MacKenzie <djm@gnu.ai.mit.edu> */
-#ifdef HAVE_CONFIG_H
-#if defined (CONFIG_BROKETS)
-/* We use <config.h> instead of "config.h" so that a compilation
- using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
- (which it would do because it found this file in $srcdir). */
#include <config.h>
-#else
-#include "config.h"
-#endif
-#endif
-
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
+
#include "modechange.h"
#include "system.h"
#include "version.h"
+#include "safe-stat.h"
+#include "safe-lstat.h"
+#include "error.h"
-int lstat ();
-
+void mode_string ();
char *savedir ();
+void strip_trailing_slashes ();
char *xmalloc ();
char *xrealloc ();
-void error ();
-void mode_string ();
static int change_file_mode ();
static int change_dir_mode ();
verbose = 1;
break;
default:
- usage ();
+ usage (1);
}
}
}
if (show_help)
- usage ();
+ usage (0);
if (modeind == 0)
modeind = optind++;
if (optind >= argc)
- usage ();
+ {
+ error (0, 0, "too few arguments");
+ usage (1);
+ }
changes = mode_compile (argv[modeind],
MODE_MASK_EQUALS | MODE_MASK_PLUS | MODE_MASK_MINUS);
error (1, 0, "virtual memory exhausted");
for (; optind < argc; ++optind)
- errors |= change_file_mode (argv[optind], changes);
+ {
+ strip_trailing_slashes (argv[optind]);
+ errors |= change_file_mode (argv[optind], changes, 1);
+ }
exit (errors);
}
/* Change the mode of FILE according to the list of operations CHANGES.
- Return 0 if successful, 1 if errors occurred. */
+ If DEREF_SYMLINK is non-zero 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 (file, changes)
+change_file_mode (file, changes, deref_symlink)
char *file;
struct mode_change *changes;
+ int deref_symlink;
{
struct stat file_stats;
unsigned short newmode;
int errors = 0;
- if (lstat (file, &file_stats))
+ if (safe_lstat (file, &file_stats))
{
if (force_silent == 0)
error (0, errno, "%s", file);
}
#ifdef S_ISLNK
if (S_ISLNK (file_stats.st_mode))
- return 0;
+ {
+ if (! deref_symlink)
+ return 0;
+ else
+ if (safe_stat (file, &file_stats))
+ {
+ if (force_silent == 0)
+ error (0, errno, "%s", file);
+ return 1;
+ }
+ }
#endif
newmode = mode_adjust (file_stats.st_mode, changes);
path = xrealloc (path, pathlength);
}
strcpy (path + dirlength, namep);
- errors |= change_file_mode (path, changes);
+ errors |= change_file_mode (path, changes, 0);
}
free (path);
free (name_space);
}
static void
-usage ()
+usage (status)
+ int status;
{
- fprintf (stderr, "\
-Usage: %s [-Rcfv] [--recursive] [--changes] [--silent] [--quiet]\n\
- [--verbose] [--help] [--version] mode file...\n\
- mode is [ugoa...][[+-=][rwxXstugo...]...][,...] or octal number\n",
- program_name);
- exit (1);
+ 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\
+",
+ program_name, program_name);
+ printf ("\
+\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\
+ -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");
+ }
+ exit (status);
}