bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

more ls changes: stat-failed


From: Jim Meyering
Subject: more ls changes: stat-failed
Date: Tue, 25 Jul 2006 18:45:58 +0200

I've checked in another batch of changes to ls.
This time, it's a cross between a feature addition and a bug fix.

Before this change, if you ran "ls DIR" and some file in DIR could
not be stat'ed (or lstat'ed), then that file would not be listed
in a long listing.  However, it *would* be listed in some short
listings (i.e., on a file system with d_type support) and with some
combinations of options (any that don't require stat information --
type info is ok).  You can even demonstrate the problem in a short
listing, if you try hard enough.

Now, for a stat-failed entry in a long listing,
ls prints "---------" for the permission bits and a "?" for each
requested field other than the name.

Here's an example (run on a Linux-2.6.15 system):

  $ ls -lL /proc/6/task/6
  ls: cannot access /proc/6/task/6/cwd: Permission denied
  ls: cannot access /proc/6/task/6/root: Permission denied
  ls: cannot access /proc/6/task/6/exe: Permission denied
  total 0
  dr-xr-xr-x 2 root root 0 Jul 25 18:39 attr
  -r-------- 1 root root 0 Jul 25 18:39 auxv
  -r--r--r-- 1 root root 0 Jul 25 18:39 cmdline
  -r--r--r-- 1 root root 0 Jul 25 18:39 cpuset
  ?--------- ? ?    ?    ?            ? cwd
  -r-------- 1 root root 0 Jul 25 18:39 environ
  ?--------- ? ?    ?    ?            ? exe
  dr-x------ 2 root root 0 Jul 25 18:39 fd
  -r--r--r-- 1 root root 0 Jul 25 18:39 maps
  -rw------- 1 root root 0 Jul 25 18:39 mem
  -r--r--r-- 1 root root 0 Jul 25 18:39 mounts
  -rw-r--r-- 1 root root 0 Jul 25 18:39 oom_adj
  -r--r--r-- 1 root root 0 Jul 25 18:39 oom_score
  ?--------- ? ?    ?    ?            ? root
  -rw------- 1 root root 0 Jul 25 18:39 seccomp
  -r--r--r-- 1 root root 0 Jul 25 18:39 smaps
  -r--r--r-- 1 root root 0 Jul 25 18:39 stat
  -r--r--r-- 1 root root 0 Jul 25 18:39 statm
  -r--r--r-- 1 root root 0 Jul 25 18:39 status
  -r--r--r-- 1 root root 0 Jul 25 18:39 wchan

This is not the sort of thing you run into every day, but with
SELinux, I hear that it happens more often.  See the tests for
examples of how to trigger the undesirable behavior.

Here are the ChangeLog entries.
I've included the net diff for src/ls.c below.
See CVS for the individual deltas:

2006-07-25  Jim Meyering  <address@hidden>

        * src/ls.c (gobble_file): When handling a stat-failed entry,
        print the entry name not the absolute_name -- to be consistent
        with the usual case.
        * tests/ls/stat-failed: Update accordingly.

        * src/ls.c: Add parens around the new uses of ?: ternary operator.

        * src/dircolors.hin: Mention that ORPHAN refers not just to dangling
        symlinks.

        Get --dired offsets right when handling stat-failed entries.
        * src/ls.c (print_long_format): Be careful to increment P by the
        appropriate amount, even when inode_number_width and nlink_width
        are zero.
        * tests/ls/stat-failed: Test for the above.

        * src/ls.c (gobble_file) [USE_ACL]: Don't use-uninitialized the
        have_acl member.  That would happen for a directory with both a
        non-stat'able entry and one with an ACL.

        * src/ls.c (gobble_file): Make it so failure to stat a
        non-command-line file provokes an exit status of 1, not 0.
        Say "cannot access" rather than "cannot stat".
        * tests/ls/stat-failed: New file/test, for the above.
        * tests/ls/Makefile.am (TESTS): Add stat-failed.
        * tests/ls-2/tests (no-a-isdir-b): Update to reflect addition
        of "cannot access " to diagnostic.

        * src/ls.c: Declare stat_failed to be "bool", not "int" everywhere.

        * src/ls.c [enum filetype] (command_line): Remove member.  Not needed.
        Replace all occurrences of "type == command_line" with the
        equivalent, "command_line_arg".

        * src/ls.c: Apply the stat-failed parts of Red Hat's
        coreutils-selinux.patch.  From Ulrich Drepper.
        This makes it so files not mentioned on the command line (e.g.,
        names read from a directory that *is* mentioned on the command
        line) for which stat fails are still listed.  With --color,
        such files are colored just like ORPHANs (aka dangling symlinks).

Index: src/ls.c
===================================================================
RCS file: /fetish/cu/src/ls.c,v
retrieving revision 1.422
retrieving revision 1.430
diff -u -p -r1.422 -r1.430
--- src/ls.c    21 Jul 2006 09:14:39 -0000      1.422
+++ src/ls.c    25 Jul 2006 16:35:59 -0000      1.430
@@ -172,6 +172,7 @@ struct fileinfo
     char *name;
 
     struct stat stat;
+    bool stat_failed;
 
     /* For symbolic link, name of the file linked to, otherwise zero.  */
     char *linkname;
@@ -226,7 +227,8 @@ static bool file_ignored (char const *na
 static uintmax_t gobble_file (char const *name, enum filetype type,
                              ino_t inode, bool command_line_arg,
                              char const *dirname);
-static void print_color_indicator (const char *name, mode_t mode, int linkok);
+static void print_color_indicator (const char *name, mode_t mode, int linkok,
+                                  bool stat_failed);
 static void put_indicator (const struct bin_str *ind);
 static void add_ignore_pattern (const char *pattern);
 static void attach (char *dest, const char *dirname, const char *name);
@@ -247,7 +249,7 @@ static int format_group_width (gid_t g);
 static void print_long_format (const struct fileinfo *f);
 static void print_many_per_line (void);
 static void print_name_with_quoting (const char *p, mode_t mode,
-                                    int linkok,
+                                    int linkok, bool stat_failed,
                                     struct obstack *stack);
 static void prep_non_filename_text (void);
 static void print_type_indicator (mode_t mode);
@@ -2546,7 +2548,7 @@ gobble_file (char const *name, enum file
              || (dereference == DEREF_ALWAYS
                  && (type == symbolic_link || type == unknown))))
       || (format_needs_type
-         && (type == unknown
+         && (type == unknown || command_line_arg
              /* --indicator-style=classify (aka -F)
                 requires that we stat each regular file
                 to see if it's executable.  */
@@ -2606,9 +2608,26 @@ gobble_file (char const *name, enum file
          break;
        }
 
-      if (err < 0)
+      f->stat_failed = (err < 0);
+      if (f->stat_failed)
        {
-         file_failure (command_line_arg, "%s", absolute_name);
+         /* Failure to stat a command line argument leads to
+            an exit status of 2.  For other files, stat failure
+            provokes an exit status of 1.  */
+         file_failure (command_line_arg,
+                       _("cannot access %s"), absolute_name);
+         if (command_line_arg)
+           return 0;
+
+         f->filetype = type;
+         memset (&f->stat, '\0', sizeof (f->stat));
+
+#if USE_ACL
+         f->have_acl = false;
+#endif
+         f->name = xstrdup (name);
+         files_index++;
+
          return 0;
        }
 
@@ -3271,17 +3290,19 @@ format_user_or_group (char const *name, 
    WIDTH.  */
 
 static void
-format_user (uid_t u, int width)
+format_user (uid_t u, int width, bool stat_failed)
 {
-  format_user_or_group (numeric_ids ? NULL : getuser (u), u, width);
+  format_user_or_group (stat_failed ? "?" :
+                       (numeric_ids ? NULL : getuser (u)), u, width);
 }
 
 /* Likewise, for groups.  */
 
 static void
-format_group (gid_t g, int width)
+format_group (gid_t g, int width, bool stat_failed)
 {
-  format_user_or_group (numeric_ids ? NULL : getgroup (g), g, width);
+  format_user_or_group (stat_failed ? "?" :
+                       (numeric_ids ? NULL : getgroup (g)), g, width);
 }
 
 /* Return the number of columns that format_user_or_group will print.  */
@@ -3373,16 +3394,20 @@ print_long_format (const struct fileinfo
     {
       char hbuf[INT_BUFSIZE_BOUND (uintmax_t)];
       sprintf (p, "%*s ", inode_number_width,
-              umaxtostr (f->stat.st_ino, hbuf));
-      p += inode_number_width + 1;
+              f->stat_failed ? "?" : umaxtostr (f->stat.st_ino, hbuf));
+      /* Increment by strlen (p) here, rather than by inode_number_width + 1.
+        The latter is wrong when inode_number_width is zero.  */
+      p += strlen (p);
     }
 
   if (print_block_size)
     {
       char hbuf[LONGEST_HUMAN_READABLE + 1];
       char const *blocks =
-       human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts,
-                       ST_NBLOCKSIZE, output_block_size);
+       (f->stat_failed
+        ? "?"
+        : human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts,
+                          ST_NBLOCKSIZE, output_block_size));
       int pad;
       for (pad = block_size_width - mbswidth (blocks, 0); 0 < pad; pad--)
        *p++ = ' ';
@@ -3396,9 +3421,12 @@ print_long_format (const struct fileinfo
   {
     char hbuf[INT_BUFSIZE_BOUND (uintmax_t)];
     sprintf (p, "%s %*s ", modebuf, nlink_width,
-            umaxtostr (f->stat.st_nlink, hbuf));
+            f->stat_failed ? "?" : umaxtostr (f->stat.st_nlink, hbuf));
   }
-  p += sizeof modebuf - 2 + any_has_acl + 1 + nlink_width + 1;
+  /* Increment by strlen (p) here, rather than by, e.g.,
+     sizeof modebuf - 2 + any_has_acl + 1 + nlink_width + 1.
+     The latter is wrong when nlink_width is zero.  */
+  p += strlen (p);
 
   DIRED_INDENT ();
 
@@ -3407,18 +3435,19 @@ print_long_format (const struct fileinfo
       DIRED_FPUTS (buf, stdout, p - buf);
 
       if (print_owner)
-       format_user (f->stat.st_uid, owner_width);
+       format_user (f->stat.st_uid, owner_width, f->stat_failed);
 
       if (print_group)
-       format_group (f->stat.st_gid, group_width);
+       format_group (f->stat.st_gid, group_width, f->stat_failed);
 
       if (print_author)
-       format_user (f->stat.st_author, author_width);
+       format_user (f->stat.st_author, author_width, f->stat_failed);
 
       p = buf;
     }
 
-  if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
+  if (!f->stat_failed
+      && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)))
     {
       char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
       char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
@@ -3436,8 +3465,10 @@ print_long_format (const struct fileinfo
     {
       char hbuf[LONGEST_HUMAN_READABLE + 1];
       char const *size =
-       human_readable (unsigned_file_size (f->stat.st_size),
-                       hbuf, human_output_opts, 1, file_output_block_size);
+       (f->stat_failed
+        ? "?"
+        : human_readable (unsigned_file_size (f->stat.st_size),
+                          hbuf, human_output_opts, 1, file_output_block_size));
       int pad;
       for (pad = file_size_width - mbswidth (size, 0); 0 < pad; pad--)
        *p++ = ' ';
@@ -3450,7 +3481,7 @@ print_long_format (const struct fileinfo
   s = 0;
   *p = '\1';
 
-  if (when_local)
+  if (!f->stat_failed && when_local)
     {
       time_t six_months_ago;
       bool recent;
@@ -3497,15 +3528,17 @@ print_long_format (const struct fileinfo
         print it as a huge integer number of seconds.  */
       char hbuf[INT_BUFSIZE_BOUND (intmax_t)];
       sprintf (p, "%*s ", long_time_expected_width (),
-              (TYPE_SIGNED (time_t)
-               ? imaxtostr (when, hbuf)
-               : umaxtostr (when, hbuf)));
+              (f->stat_failed
+               ? "?"
+               : (TYPE_SIGNED (time_t)
+                  ? imaxtostr (when, hbuf)
+                  : umaxtostr (when, hbuf))));
       p += strlen (p);
     }
 
   DIRED_FPUTS (buf, stdout, p - buf);
   print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
-                          &dired_obstack);
+                          f->stat_failed, &dired_obstack);
 
   if (f->filetype == symbolic_link)
     {
@@ -3513,7 +3546,7 @@ print_long_format (const struct fileinfo
        {
          DIRED_FPUTS_LITERAL (" -> ", stdout);
          print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1,
-                                  NULL);
+                                  f->stat_failed, NULL);
          if (indicator_style != none)
            print_type_indicator (f->linkmode);
        }
@@ -3695,10 +3728,10 @@ quote_name (FILE *out, const char *name,
 
 static void
 print_name_with_quoting (const char *p, mode_t mode, int linkok,
-                        struct obstack *stack)
+                        bool stat_failed, struct obstack *stack)
 {
   if (print_with_color)
-    print_color_indicator (p, mode, linkok);
+    print_color_indicator (p, mode, linkok, stat_failed);
 
   if (stack)
     PUSH_CURRENT_DIRED_POS (stack);
@@ -3746,7 +3779,8 @@ print_file_name_and_frills (const struct
            human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts,
                            ST_NBLOCKSIZE, output_block_size));
 
-  print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, NULL);
+  print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
+                          f->stat_failed, NULL);
 
   if (indicator_style != none)
     print_type_indicator (f->stat.st_mode);
@@ -3787,7 +3821,8 @@ print_type_indicator (mode_t mode)
 }
 
 static void
-print_color_indicator (const char *name, mode_t mode, int linkok)
+print_color_indicator (const char *name, mode_t mode, int linkok,
+                      bool stat_failed)
 {
   int type = C_FILE;
   struct color_ext_type *ext;  /* Color extension */
@@ -3826,6 +3861,8 @@ print_color_indicator (const char *name,
        type = C_CHR;
       else if (S_ISDOOR (mode))
        type = C_DOOR;
+      else if (stat_failed)
+       type = C_ORPHAN;
 
       if (type == C_FILE)
        {




reply via email to

[Prev in Thread] Current Thread [Next in Thread]