summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/stat.c272
1 files changed, 155 insertions, 117 deletions
diff --git a/src/stat.c b/src/stat.c
index 777266ea3..83291f5ec 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -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_len, char m, char const *filename,
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_len, char m,
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_len, char m,
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 *filename,
{
/* 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 *filename,
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 *filename,
/* 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;