diff options
Diffstat (limited to 'usr.bin/stat/stat.c')
-rw-r--r-- | usr.bin/stat/stat.c | 118 |
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); } |