(add_tabstop): Give correct size when reallocating tab_list buffer.
[platform/upstream/coreutils.git] / src / chmod.c
index 511e3e2..bfb3b32 100644 (file)
@@ -1,5 +1,5 @@
 /* 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 ();
@@ -149,7 +141,7 @@ main (argc, argv)
          verbose = 1;
          break;
        default:
-         usage ();
+         usage (1);
        }
     }
 
@@ -160,13 +152,16 @@ main (argc, argv)
     }
 
   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);
@@ -176,24 +171,30 @@ main (argc, argv)
     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);
@@ -201,7 +202,17 @@ change_file_mode (file, changes)
     }
 #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);
@@ -273,7 +284,7 @@ change_dir_mode (dir, changes, statp)
          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);
@@ -302,12 +313,30 @@ describe_change (file, mode, changed)
 }
 
 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);
 }