bug-coreutils
[Top][All Lists]
Advanced

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

Re: coreutils-6.0 on BeOS (9)


From: Paul Eggert
Subject: Re: coreutils-6.0 on BeOS (9)
Date: Wed, 23 Aug 2006 16:48:07 -0700
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.4 (gnu/linux)

Bruno Haible <address@hidden> writes:

> The 'df' program needs a small adjustment so that the 'struct statvfs' of
> BeOS can be used. And the 'stat' program needs porting too; here the
> 'struct statvfs' cannot be used, because it does not have a f_type

Thanks.  While testing this on GNU/Linux I uncovered several other
problems.  At least one serious problem leading to undefined behavior
was masked by a cast (arggh!!!) so I removed a lot of casts while I
was at it.

There is still some undefined behavior in there, with bad formats, but
I ran out of time to fix this right now.  Probably printf-parse or the
code in printf.c should be applied.  I don't think there are any
buffer overruns on any real platforms, but still it should get fixed
eventually.

I installed the following combined patch.  I also installed the gnulib
patch you sent.

> I propose to create a 'struct gnu_statvfs' that contains the usual POSIX
> fields plus 'char f_fstypename[]', containing the filesystem name, and a few
> minor fields that src/stat.c uses, and to transform the lib/fsusage.c code
> into a gnu_statvfs function that could be used by both "df" and "stat".
> Does this seem worthwhile?

It would clean up the code, I think.  Perhaps Jim has an opinion?

> Can the SVR2 code (this is the only code in
> lib/fsusage.c that makes use of the 'disk' argument) be dropped in the 
> process?

I don't know why we need that old code any more, and it'd be fine with
me if it vanished.


2006-08-23  Paul Eggert  <address@hidden>

        * src/stat.c (HAVE_STRUCT_STATXFS_F_FSID___VAL): Define.  This
        macro was being used without being defined.
        (SB_F_NAMEMAX): Remove cast.
        (f_fsid) [BeOS]: Likewise.
        (OUT_NAMEMAX): Renamed from NAMEMAX_FORMAT, with a new meaning.
        All uses changed.
        (out_string, out_int, out_uint, out_uint_o, out_uint_x): New
        functions.
        (xstrcat): Remove.  All uses changed to use the above functions.
        (print_statfs, print_stat): 2nd arg is now the prefix len, not the
        buffer len.  All uses changed.  Output '?', not '*', for unknown
        data or errors.  Do not assume signed values can be interchanged
        with unsigned when printing.
        (print_statfs): For %i, print the fsid as a single int, not as a
        pair.
        (print_it): Quote invalid format better.

2006-08-23  Bruno Haible  <address@hidden>

        * src/stat.c (STRUCT_STATVFS, statfs, f_fsid, f_blocks, f_bfree) [BeOS]:
        (f_bavail, f_bsize, STATFS_FRSIZE, f_files, f_ffree) [BeOS]:
        (STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME) [BeOS]: Define.

--- src/stat.c  20 Aug 2006 15:17:28 -0000      1.97
+++ src/stat.c  23 Aug 2006 23:39:55 -0000
@@ -48,6 +48,8 @@
 #  include <nfs/nfs_clnt.h>
 #  include <nfs/vfs.h>
 # endif
+#elif HAVE_OS_H /* BeOS */
+# include <fs_info.h>
 #endif
 
 #include "system.h"
@@ -66,28 +68,63 @@
 
 #if USE_STATVFS
 # define STRUCT_STATVFS struct statvfs
+# define HAVE_STRUCT_STATXFS_F_FSID___VAL HAVE_STRUCT_STATVFS_F_FSID___VAL
 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
-#  define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
+#  define SB_F_NAMEMAX(S) ((S)->f_namemax)
 # endif
 # define STATFS statvfs
 # define STATFS_FRSIZE(S) ((S)->f_frsize)
 #else
-# define STRUCT_STATVFS struct statfs
 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
 # if HAVE_STRUCT_STATFS_F_NAMELEN
-#  define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
+#  define SB_F_NAMEMAX(S) ((S)->f_namelen)
 # endif
 # define STATFS statfs
-# define STATFS_FRSIZE(S) 0
+# if HAVE_OS_H /* BeOS */
+/* BeOS has a statvfs function, but it does not return sensible values
+   for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
+   f_fstypename.  Use 'struct fs_info' instead.  */
+static int
+statfs (char const *filename, struct fs_info *buf)
+{
+  dev_t device = dev_for_path (filename);
+  if (device < 0)
+    {
+      errno = (device == B_ENTRY_NOT_FOUND ? ENOENT
+              : device == B_BAD_VALUE ? EINVAL
+              : device == B_NAME_TOO_LONG ? ENAMETOOLONG
+              : device == B_NO_MEMORY ? ENOMEM
+              : device == B_FILE_ERROR ? EIO
+              : 0);
+      return -1;
+    }
+  /* If successful, buf->dev will be == device.  */
+  return fs_stat_dev (device, buf);
+}
+#  define f_fsid dev
+#  define f_blocks total_blocks
+#  define f_bfree free_blocks
+#  define f_bavail free_blocks
+#  define f_bsize io_size
+#  define f_files total_nodes
+#  define f_ffree free_nodes
+#  define STRUCT_STATVFS struct fs_info
+#  define HAVE_STRUCT_STATXFS_F_FSID___VAL 0
+#  define STATFS_FRSIZE(S) ((S)->block_size)
+# else
+#  define STRUCT_STATVFS struct statfs
+#  define HAVE_STRUCT_STATXFS_F_FSID___VAL HAVE_STRUCT_STATFS_F_FSID___VAL
+#  define STATFS_FRSIZE(S) 0
+# endif
 #endif
 
 #ifdef SB_F_NAMEMAX
-# define NAMEMAX_FORMAT PRIuMAX
+# define OUT_NAMEMAX out_uint
 #else
 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen.  */
 # define SB_F_NAMEMAX(S) "*"
-# define NAMEMAX_FORMAT "s"
+# define OUT_NAMEMAX out_string
 #endif
 
 #if HAVE_STRUCT_STATVFS_F_BASETYPE
@@ -95,6 +132,8 @@
 #else
 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
 #  define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
+# elif HAVE_OS_H /* BeOS */
+#  define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
 # endif
 #endif
 
@@ -319,22 +358,40 @@ human_time (struct timespec t)
   return str;
 }
 
-/* Like strcat, but don't return anything and do check that
-   DEST_BUFSIZE is at least a long as strlen (DEST) + strlen (SRC) + 1.
-   The signature is deliberately different from that of strncat.  */
 static void
-xstrcat (char *dest, size_t dest_bufsize, char const *src)
+out_string (char *pformat, size_t prefix_len, char const *arg)
+{
+  strcpy (pformat + prefix_len, "s");
+  printf (pformat, arg);
+}
+static void
+out_int (char *pformat, size_t prefix_len, intmax_t arg)
+{
+  strcpy (pformat + prefix_len, PRIdMAX);
+  printf (pformat, arg);
+}
+static void
+out_uint (char *pformat, size_t prefix_len, uintmax_t arg)
+{
+  strcpy (pformat + prefix_len, PRIuMAX);
+  printf (pformat, arg);
+}
+static void
+out_uint_o (char *pformat, size_t prefix_len, uintmax_t arg)
+{
+  strcpy (pformat + prefix_len, PRIoMAX);
+  printf (pformat, arg);
+}
+static void
+out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
 {
-  size_t dest_len = strlen (dest);
-  size_t src_len = strlen (src);
-  if (dest_bufsize < dest_len + src_len + 1)
-    abort ();
-  memcpy (dest + dest_len, src, src_len + 1);
+  strcpy (pformat + prefix_len, PRIxMAX);
+  printf (pformat, arg);
 }
 
 /* print statfs info */
 static void
-print_statfs (char *pformat, size_t buf_len, char m, char const *filename,
+print_statfs (char *pformat, size_t prefix_len, char m, char const *filename,
              void const *data)
 {
   STRUCT_STATVFS const *statfsbuf = data;
@@ -342,82 +399,75 @@ print_statfs (char *pformat, size_t buf_
   switch (m)
     {
     case 'n':
-      xstrcat (pformat, buf_len, "s");
-      printf (pformat, filename);
+      out_string (pformat, prefix_len, filename);
       break;
 
     case 'i':
+      {
 #if HAVE_STRUCT_STATXFS_F_FSID___VAL
-      xstrcat (pformat, buf_len, "x %-8x");
-      printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */
-             statfsbuf->f_fsid.__val[1]);
+       uintmax_t val0 = statfsbuf->f_fsid.__val[0];
+       uintmax_t val1 = statfsbuf->f_fsid.__val[1];
+       uintmax_t fsid =
+         (val1
+          + (sizeof statfsbuf->f_fsid.__val[1] < sizeof fsid
+             ? val0 << (CHAR_BIT * sizeof sizeof statfsbuf->f_fsid.__val[1])
+             : 0));
 #else
-      xstrcat (pformat, buf_len, "Lx");
-      printf (pformat, statfsbuf->f_fsid);
+       uintmax_t fsid = statfsbuf->f_fsid;
 #endif
+       out_uint_x (pformat, prefix_len, fsid);
+      }
       break;
 
     case 'l':
-      xstrcat (pformat, buf_len, NAMEMAX_FORMAT);
-      printf (pformat, SB_F_NAMEMAX (statfsbuf));
+      OUT_NAMEMAX (pformat, prefix_len, SB_F_NAMEMAX (statfsbuf));
       break;
     case 't':
 #if HAVE_STRUCT_STATXFS_F_TYPE
-      xstrcat (pformat, buf_len, "lx");
-      printf (pformat,
-             (unsigned long int) (statfsbuf->f_type));  /* no equiv. */
+      out_uint_x (pformat, prefix_len, statfsbuf->f_type);
 #else
-      fputc ('*', stdout);
+      fputc ('?', stdout);
 #endif
       break;
     case 'T':
-      xstrcat (pformat, buf_len, "s");
-      printf (pformat, human_fstype (statfsbuf));
+      out_string (pformat, prefix_len, human_fstype (statfsbuf));
       break;
     case 'b':
-      xstrcat (pformat, buf_len, PRIdMAX);
-      printf (pformat, (intmax_t) (statfsbuf->f_blocks));
+      out_int (pformat, prefix_len, statfsbuf->f_blocks);
       break;
     case 'f':
-      xstrcat (pformat, buf_len, PRIdMAX);
-      printf (pformat, (intmax_t) (statfsbuf->f_bfree));
+      out_int (pformat, prefix_len, statfsbuf->f_bfree);
       break;
     case 'a':
-      xstrcat (pformat, buf_len, PRIdMAX);
-      printf (pformat, (intmax_t) (statfsbuf->f_bavail));
+      out_int (pformat, prefix_len, statfsbuf->f_bavail);
       break;
     case 's':
-      xstrcat (pformat, buf_len, "lu");
-      printf (pformat, (unsigned long int) (statfsbuf->f_bsize));
+      out_uint (pformat, prefix_len, statfsbuf->f_bsize);
       break;
     case 'S':
       {
-       unsigned long int frsize = STATFS_FRSIZE (statfsbuf);
+       uintmax_t frsize = STATFS_FRSIZE (statfsbuf);
        if (! frsize)
          frsize = statfsbuf->f_bsize;
-       xstrcat (pformat, buf_len, "lu");
-       printf (pformat, frsize);
+       out_uint (pformat, prefix_len, frsize);
       }
       break;
     case 'c':
-      xstrcat (pformat, buf_len, PRIdMAX);
-      printf (pformat, (intmax_t) (statfsbuf->f_files));
+      out_int (pformat, prefix_len, statfsbuf->f_files);
       break;
     case 'd':
-      xstrcat (pformat, buf_len, PRIdMAX);
-      printf (pformat, (intmax_t) (statfsbuf->f_ffree));
+      out_int (pformat, prefix_len, statfsbuf->f_ffree);
       break;
 
     default:
-      xstrcat (pformat, buf_len, "c");
-      printf (pformat, m);
+      fputc ('?', stdout);
       break;
     }
 }
 
 /* print stat info */
 static void
-print_stat (char *pformat, size_t buf_len, char m,
+print_stat (char *pformat, size_t prefix_len, char m,
            char const *filename, void const *data)
 {
   struct stat *statbuf = (struct stat *) data;
@@ -427,11 +477,10 @@ print_stat (char *pformat, size_t buf_le
   switch (m)
     {
     case 'n':
-      xstrcat (pformat, buf_len, "s");
-      printf (pformat, filename);
+      out_string (pformat, prefix_len, filename);
       break;
     case 'N':
-      xstrcat (pformat, buf_len, "s");
+      out_string (pformat, prefix_len, quote (filename));
       if (S_ISLNK (statbuf->st_mode))
        {
          char *linkname = xreadlink (filename, statbuf->st_size);
@@ -441,120 +490,99 @@ print_stat (char *pformat, size_t buf_le
                     quote (filename));
              return;
            }
-         /*printf("\"%s\" -> \"%s\"", filename, linkname); */
-         printf (pformat, quote (filename));
          printf (" -> ");
-         printf (pformat, quote (linkname));
-       }
-      else
-       {
-         printf (pformat, quote (filename));
+         out_string (pformat, prefix_len, quote (linkname));
        }
       break;
     case 'd':
-      xstrcat (pformat, buf_len, PRIuMAX);
-      printf (pformat, (uintmax_t) statbuf->st_dev);
+      out_uint (pformat, prefix_len, statbuf->st_dev);
       break;
     case 'D':
-      xstrcat (pformat, buf_len, PRIxMAX);
-      printf (pformat, (uintmax_t) statbuf->st_dev);
+      out_uint_x (pformat, prefix_len, statbuf->st_dev);
       break;
     case 'i':
-      xstrcat (pformat, buf_len, PRIuMAX);
-      printf (pformat, (uintmax_t) statbuf->st_ino);
+      out_uint (pformat, prefix_len, statbuf->st_ino);
       break;
     case 'a':
-      xstrcat (pformat, buf_len, "lo");
-      printf (pformat,
-             (unsigned long int) (statbuf->st_mode & CHMOD_MODE_BITS));
+      out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS);
       break;
     case 'A':
-      xstrcat (pformat, buf_len, "s");
-      printf (pformat, human_access (statbuf));
+      out_string (pformat, prefix_len, human_access (statbuf));
       break;
     case 'f':
-      xstrcat (pformat, buf_len, "lx");
-      printf (pformat, (unsigned long int) statbuf->st_mode);
+      out_uint_x (pformat, prefix_len, statbuf->st_mode);
       break;
     case 'F':
-      xstrcat (pformat, buf_len, "s");
-      printf (pformat, file_type (statbuf));
+      out_string (pformat, prefix_len, file_type (statbuf));
       break;
     case 'h':
-      xstrcat (pformat, buf_len, "lu");
-      printf (pformat, (unsigned long int) statbuf->st_nlink);
+      out_uint (pformat, prefix_len, statbuf->st_nlink);
       break;
     case 'u':
-      xstrcat (pformat, buf_len, "lu");
-      printf (pformat, (unsigned long int) statbuf->st_uid);
+      out_uint (pformat, prefix_len, statbuf->st_uid);
       break;
     case 'U':
-      xstrcat (pformat, buf_len, "s");
       setpwent ();
       pw_ent = getpwuid (statbuf->st_uid);
-      printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
+      out_string (pformat, prefix_len,
+                 pw_ent ? pw_ent->pw_name : "UNKNOWN");
       break;
     case 'g':
-      xstrcat (pformat, buf_len, "lu");
-      printf (pformat, (unsigned long int) statbuf->st_gid);
+      out_uint (pformat, prefix_len, statbuf->st_gid);
       break;
     case 'G':
-      xstrcat (pformat, buf_len, "s");
       setgrent ();
       gw_ent = getgrgid (statbuf->st_gid);
-      printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
+      out_string (pformat, prefix_len,
+                 gw_ent ? gw_ent->gr_name : "UNKNOWN");
       break;
     case 't':
-      xstrcat (pformat, buf_len, "lx");
-      printf (pformat, (unsigned long int) major (statbuf->st_rdev));
+      out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
       break;
     case 'T':
-      xstrcat (pformat, buf_len, "lx");
-      printf (pformat, (unsigned long int) minor (statbuf->st_rdev));
+      out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev));
       break;
     case 's':
-      xstrcat (pformat, buf_len, PRIuMAX);
-      printf (pformat, (uintmax_t) (statbuf->st_size));
+      out_uint (pformat, prefix_len, statbuf->st_size);
       break;
     case 'B':
-      xstrcat (pformat, buf_len, "lu");
-      printf (pformat, (unsigned long int) ST_NBLOCKSIZE);
+      out_uint (pformat, prefix_len, ST_NBLOCKSIZE);
       break;
     case 'b':
-      xstrcat (pformat, buf_len, PRIuMAX);
-      printf (pformat, (uintmax_t) ST_NBLOCKS (*statbuf));
+      out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf));
       break;
     case 'o':
-      xstrcat (pformat, buf_len, "lu");
-      printf (pformat, (unsigned long int) statbuf->st_blksize);
+      out_uint (pformat, prefix_len, statbuf->st_blksize);
       break;
     case 'x':
-      xstrcat (pformat, buf_len, "s");
-      printf (pformat, human_time (get_stat_atime (statbuf)));
+      out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf)));
       break;
     case 'X':
-      xstrcat (pformat, buf_len, TYPE_SIGNED (time_t) ? "ld" : "lu");
-      printf (pformat, (unsigned long int) statbuf->st_atime);
+      if (TYPE_SIGNED (time_t))
+       out_int (pformat, prefix_len, statbuf->st_atime);
+      else
+       out_uint (pformat, prefix_len, statbuf->st_atime);
       break;
     case 'y':
-      xstrcat (pformat, buf_len, "s");
-      printf (pformat, human_time (get_stat_mtime (statbuf)));
+      out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf)));
       break;
     case 'Y':
-      xstrcat (pformat, buf_len, TYPE_SIGNED (time_t) ? "ld" : "lu");
-      printf (pformat, (unsigned long int) statbuf->st_mtime);
+      if (TYPE_SIGNED (time_t))
+       out_int (pformat, prefix_len, statbuf->st_mtime);
+      else
+       out_uint (pformat, prefix_len, statbuf->st_mtime);
       break;
     case 'z':
-      xstrcat (pformat, buf_len, "s");
-      printf (pformat, human_time (get_stat_ctime (statbuf)));
+      out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf)));
       break;
     case 'Z':
-      xstrcat (pformat, buf_len, TYPE_SIGNED (time_t) ? "ld" : "lu");
-      printf (pformat, (unsigned long int) statbuf->st_ctime);
+      if (TYPE_SIGNED (time_t))
+       out_int (pformat, prefix_len, statbuf->st_ctime);
+      else
+       out_uint (pformat, prefix_len, statbuf->st_ctime);
       break;
     default:
-      xstrcat (pformat, buf_len, "c");
-      printf (pformat, m);
+      fputc ('?', stdout);
       break;
     }
 }
@@ -604,7 +632,14 @@ print_it (char const *format, char const
 {
   /* Add 2 to accommodate our conversion of the stat `%s' format string
      to the longer printf `%llu' one.  */
-  size_t n_alloc = strlen (format) + 2 + 1;
+  enum
+    {
+      MAX_ADDITIONAL_BYTES =
+       (MAX (sizeof PRIdMAX,
+             MAX (sizeof PRIoMAX, MAX (sizeof PRIuMAX, sizeof PRIxMAX)))
+        - 1)
+    };
+  size_t n_alloc = strlen (format) + MAX_ADDITIONAL_BYTES + 1;
   char *dest = xmalloc (n_alloc);
   char const *b;
   for (b = format; *b; b++)
@@ -614,9 +649,8 @@ print_it (char const *format, char const
        case '%':
          {
            size_t len = strspn (b + 1, "#-+.I 0123456789");
-           char const *fmt_char = b + 1 + len;
-           memcpy (dest, b, 1 + len);
-           dest[1 + len] = 0;
+           char const *fmt_char = b + len + 1;
+           memcpy (dest, b, len + 1);
 
            b = fmt_char;
            switch (*fmt_char)
@@ -626,12 +660,16 @@ print_it (char const *format, char const
                /* fall through */
              case '%':
                if (0 < len)
-                 error (EXIT_FAILURE, 0, _("%s%s: invalid directive"),
-                        quotearg_colon (dest), *fmt_char ? "%" : "");
+                 {
+                   dest[len + 1] = *fmt_char;
+                   dest[len + 2] = '\0';
+                   error (EXIT_FAILURE, 0, _("%s: invalid directive"),
+                          quotearg_colon (dest));
+                 }
                putchar ('%');
                break;
              default:
-               print_func (dest, n_alloc, *fmt_char, filename, data);
+               print_func (dest, len + 1, *fmt_char, filename, data);
                break;
              }
            break;




reply via email to

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