summaryrefslogtreecommitdiffstats
path: root/usr.bin/stat/stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/stat/stat.c')
-rw-r--r--usr.bin/stat/stat.c118
1 files changed, 79 insertions, 39 deletions
diff --git a/usr.bin/stat/stat.c b/usr.bin/stat/stat.c
index 1ab10ea..950c76a 100644
--- a/usr.bin/stat/stat.c
+++ b/usr.bin/stat/stat.c
@@ -30,7 +30,7 @@
#include <sys/cdefs.h>
#if 0
#ifndef lint
-__RCSID("$NetBSD: stat.c,v 1.13 2003/07/25 03:21:17 atatat Exp $");
+__RCSID("$NetBSD: stat.c,v 1.30 2010/11/25 04:33:30 dholland Exp $");
#endif
#endif
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <err.h>
+#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <paths.h>
@@ -152,6 +153,7 @@ __FBSDID("$FreeBSD$");
#define MIDDLE_PIECE 'M'
#define LOW_PIECE 'L'
+#define SHOW_realpath 'R'
#define SHOW_st_dev 'd'
#define SHOW_st_ino 'i'
#define SHOW_st_mode 'p'
@@ -175,7 +177,7 @@ __FBSDID("$FreeBSD$");
void usage(const char *);
void output(const struct stat *, const char *,
- const char *, int, int, int);
+ const char *, int, int);
int format1(const struct stat *, /* stat info */
const char *, /* the file name */
const char *, int, /* the format string itself */
@@ -186,7 +188,7 @@ int format1(const struct stat *, /* stat info */
char *xfflagstostr(unsigned long);
#endif
-char *timefmt;
+const char *timefmt;
int linkfail;
#define addchar(s, c, nl) \
@@ -201,7 +203,7 @@ main(int argc, char *argv[])
struct stat st;
int ch, rc, errs, am_readlink;
int lsF, fmtchar, usestat, fn, nonl, quiet;
- char *statfmt, *options, *synopsis;
+ const char *statfmt, *options, *synopsis;
char dname[sizeof _PATH_DEV + SPECNAMELEN] = _PATH_DEV;
const char *file;
@@ -217,8 +219,8 @@ main(int argc, char *argv[])
if (strcmp(getprogname(), "readlink") == 0) {
am_readlink = 1;
- options = "n";
- synopsis = "[-n] [file ...]";
+ options = "fn";
+ synopsis = "[-fn] [file ...]";
statfmt = "%Y";
fmtchar = 'f';
quiet = 1;
@@ -242,6 +244,10 @@ main(int argc, char *argv[])
quiet = 1;
break;
case 'f':
+ if (am_readlink) {
+ statfmt = "%R";
+ break;
+ }
statfmt = optarg;
/* FALLTHROUGH */
case 'l':
@@ -313,8 +319,17 @@ main(int argc, char *argv[])
rc = fstat(STDIN_FILENO, &st);
} else {
file = argv[0];
- if (usestat)
- rc = stat(file, &st);
+ if (usestat) {
+ /*
+ * Try stat() and if it fails, fall back to
+ * lstat() just in case we're examining a
+ * broken symlink.
+ */
+ if ((rc = stat(file, &st)) == -1 &&
+ errno == ENOENT &&
+ (rc = lstat(file, &st)) == -1)
+ errno = ENOENT;
+ }
else
rc = lstat(file, &st);
}
@@ -326,7 +341,7 @@ main(int argc, char *argv[])
warn("%s: stat", file);
}
else
- output(&st, file, statfmt, fn, nonl, quiet);
+ output(&st, file, statfmt, fn, nonl);
argv++;
argc--;
@@ -368,10 +383,10 @@ usage(const char *synopsis)
*/
void
output(const struct stat *st, const char *file,
- const char *statfmt, int fn, int nonl, int quiet)
+ const char *statfmt, int fn, int nonl)
{
int flags, size, prec, ofmt, hilo, what;
- char buf[PATH_MAX];
+ char buf[PATH_MAX + 4 + 1];
const char *subfmt;
int nl, t, i;
@@ -508,6 +523,7 @@ output(const struct stat *st, const char *file,
}
switch (*statfmt) {
+ fmtcase(what, SHOW_realpath);
fmtcase(what, SHOW_st_dev);
fmtcase(what, SHOW_st_ino);
fmtcase(what, SHOW_st_mode);
@@ -540,7 +556,7 @@ output(const struct stat *st, const char *file,
buf, sizeof(buf),
flags, size, prec, ofmt, hilo, what);
- for (i = 0; i < t && i < sizeof(buf); i++)
+ for (i = 0; i < t && i < (int)(sizeof(buf) - 1); i++)
addchar(stdout, buf[i], &nl);
continue;
@@ -567,7 +583,8 @@ format1(const struct stat *st,
int hilo, int what)
{
u_int64_t data;
- char *sdata, lfmt[24], tmp[20];
+ char *stmp, lfmt[24], tmp[20];
+ const char *sdata;
char smode[12], sid[12], path[PATH_MAX + 4];
struct passwd *pw;
struct group *gr;
@@ -628,28 +645,29 @@ format1(const struct stat *st,
small = (sizeof(st->st_mode) == 4);
data = st->st_mode;
strmode(st->st_mode, smode);
- sdata = smode;
- l = strlen(sdata);
- if (sdata[l - 1] == ' ')
- sdata[--l] = '\0';
+ stmp = smode;
+ l = strlen(stmp);
+ if (stmp[l - 1] == ' ')
+ stmp[--l] = '\0';
if (hilo == HIGH_PIECE) {
data >>= 12;
- sdata += 1;
- sdata[3] = '\0';
+ stmp += 1;
+ stmp[3] = '\0';
hilo = 0;
}
else if (hilo == MIDDLE_PIECE) {
data = (data >> 9) & 07;
- sdata += 4;
- sdata[3] = '\0';
+ stmp += 4;
+ stmp[3] = '\0';
hilo = 0;
}
else if (hilo == LOW_PIECE) {
data &= 0777;
- sdata += 7;
- sdata[3] = '\0';
+ stmp += 7;
+ stmp[3] = '\0';
hilo = 0;
}
+ sdata = stmp;
formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
FMTF_STRING;
if (ofmt == 0)
@@ -710,7 +728,6 @@ format1(const struct stat *st,
ts = *tsp; /* copy so we can muck with it */
small = (sizeof(ts.tv_sec) == 4);
data = ts.tv_sec;
- small = 1;
tm = localtime(&ts.tv_sec);
(void)strftime(path, sizeof(path), timefmt, tm);
sdata = path;
@@ -766,6 +783,26 @@ format1(const struct stat *st,
ofmt = FMTF_UNSIGNED;
break;
#endif /* HAVE_STRUCT_STAT_ST_GEN */
+ case SHOW_realpath:
+ small = 0;
+ data = 0;
+ if (file == NULL) {
+ (void)strncpy(path, "(stdin)", sizeof(path));
+ sdata = path;
+ } else {
+ snprintf(path, sizeof(path), " -> ");
+ if (realpath(file, path + 4) == NULL) {
+ linkfail = 1;
+ l = 0;
+ path[0] = '\0';
+ }
+ sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
+ }
+
+ formats = FMTF_STRING;
+ if (ofmt == 0)
+ ofmt = FMTF_STRING;
+ break;
case SHOW_symlink:
small = 0;
data = 0;
@@ -791,24 +828,23 @@ format1(const struct stat *st,
case SHOW_filetype:
small = 0;
data = 0;
- sdata = smode;
- sdata[0] = '\0';
+ sdata = "";
if (hilo == 0 || hilo == LOW_PIECE) {
switch (st->st_mode & S_IFMT) {
- case S_IFIFO: (void)strcat(sdata, "|"); break;
- case S_IFDIR: (void)strcat(sdata, "/"); break;
+ case S_IFIFO: sdata = "|"; break;
+ case S_IFDIR: sdata = "/"; break;
case S_IFREG:
if (st->st_mode &
(S_IXUSR | S_IXGRP | S_IXOTH))
- (void)strcat(sdata, "*");
+ sdata = "*";
break;
- case S_IFLNK: (void)strcat(sdata, "@"); break;
- case S_IFSOCK: (void)strcat(sdata, "="); break;
+ case S_IFLNK: sdata = "@"; break;
+ case S_IFSOCK: sdata = "="; break;
#ifdef S_IFWHT
- case S_IFWHT: (void)strcat(sdata, "%"); break;
+ case S_IFWHT: sdata = "%"; break;
#endif /* S_IFWHT */
#ifdef S_IFDOOR
- case S_IFDOOR: (void)strcat(sdata, ">"); break;
+ case S_IFDOOR: sdata = ">"; break;
#endif /* S_IFDOOR */
}
hilo = 0;
@@ -914,8 +950,9 @@ format1(const struct stat *st,
(void)snprintf(tmp, sizeof(tmp), "%d", size);
(void)strcat(lfmt, tmp);
}
- (void)strcat(lfmt, "d");
- return (snprintf(buf, blen, lfmt, ts.tv_sec));
+ (void)strcat(lfmt, "lld");
+ return (snprintf(buf, blen, lfmt,
+ (long long)ts.tv_sec));
}
/*
@@ -938,7 +975,8 @@ format1(const struct stat *st,
(void)snprintf(tmp, sizeof(tmp), "%d", size);
(void)strcat(lfmt, tmp);
}
- (void)strcat(lfmt, "d");
+ /* Seconds: time_t cast to long long. */
+ (void)strcat(lfmt, "lld");
/*
* The stuff after the decimal point always needs zero
@@ -949,8 +987,10 @@ format1(const struct stat *st,
/*
* We can "print" at most nine digits of precision. The
* rest we will pad on at the end.
+ *
+ * Nanoseconds: long.
*/
- (void)snprintf(tmp, sizeof(tmp), "%dd", prec > 9 ? 9 : prec);
+ (void)snprintf(tmp, sizeof(tmp), "%dld", prec > 9 ? 9 : prec);
(void)strcat(lfmt, tmp);
/*
@@ -964,8 +1004,8 @@ format1(const struct stat *st,
* Use the format, and then tack on any zeroes that
* might be required to make up the requested precision.
*/
- l = snprintf(buf, blen, lfmt, ts.tv_sec, ts.tv_nsec);
- for (; prec > 9 && l < blen; prec--, l++)
+ l = snprintf(buf, blen, lfmt, (long long)ts.tv_sec, ts.tv_nsec);
+ for (; prec > 9 && l < (int)blen; prec--, l++)
(void)strcat(buf, "0");
return (l);
}
OpenPOWER on IntegriCloud