summaryrefslogtreecommitdiffstats
path: root/usr.bin/stat
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/stat')
-rw-r--r--usr.bin/stat/Makefile1
-rw-r--r--usr.bin/stat/stat.1104
-rw-r--r--usr.bin/stat/stat.c118
3 files changed, 160 insertions, 63 deletions
diff --git a/usr.bin/stat/Makefile b/usr.bin/stat/Makefile
index 808c41e..1a54979 100644
--- a/usr.bin/stat/Makefile
+++ b/usr.bin/stat/Makefile
@@ -1,7 +1,6 @@
# $FreeBSD$
PROG= stat
-WARNS?= 2
LINKS= ${BINDIR}/stat ${BINDIR}/readlink
MLINKS= stat.1 readlink.1
diff --git a/usr.bin/stat/stat.1 b/usr.bin/stat/stat.1
index 8bbdda4..92a8515 100644
--- a/usr.bin/stat/stat.1
+++ b/usr.bin/stat/stat.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: stat.1,v 1.11 2003/05/08 13:07:10 wiz Exp $
+.\" $NetBSD: stat.1,v 1.28 2010/04/05 21:25:01 joerg Exp $
.\"
.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 24, 2010
+.Dd December 5, 2010
.Dt STAT 1
.Os
.Sh NAME
@@ -43,15 +43,15 @@
.Op Fl t Ar timefmt
.Op Ar
.Nm readlink
-.Op Fl n
+.Op Fl fn
.Op Ar
.Sh DESCRIPTION
The
.Nm
utility displays information about the file pointed to by
.Ar file .
-Read, write or execute permissions of the named file are not required, but
-all directories listed in the path name leading to the file must be
+Read, write, or execute permissions of the named file are not required, but
+all directories listed in the pathname leading to the file must be
searchable.
If no argument is given,
.Nm
@@ -60,13 +60,42 @@ displays information about the file descriptor for standard input.
When invoked as
.Nm readlink ,
only the target of the symbolic link is printed.
-If the given argument is not a symbolic link,
+If the given argument is not a symbolic link and the
+.Fl f
+option is not specified,
.Nm readlink
will print nothing and exit with an error.
+If the
+.Fl f
+option is specified, the output is canonicalized by following every symlink
+in every component of the given path recursively.
+.Nm readlink
+will resolve both absolute and relative paths, and return the absolute pathname
+corresponding to
+.Ar file .
+In this case, the argument does not need to be a symbolic link.
.Pp
The information displayed is obtained by calling
.Xr lstat 2
with the given argument and evaluating the returned structure.
+The default format displays the
+.Fa st_dev ,
+.Fa st_ino ,
+.Fa st_mode ,
+.Fa st_nlink ,
+.Fa st_uid ,
+.Fa st_gid ,
+.Fa st_rdev ,
+.Fa st_size ,
+.Fa st_atime ,
+.Fa st_mtime ,
+.Fa st_ctime ,
+.Fa st_birthtime ,
+.Fa st_blksize ,
+.Fa st_blocks ,
+and
+.Fa st_flags
+fields, in that order.
.Pp
The options are as follows:
.Bl -tag -width indent
@@ -107,6 +136,14 @@ will refer to the target of
if file is a symbolic link, and not to
.Ar file
itself.
+If the link is broken or the target does not exist,
+fall back on
+.Xr lstat 2
+and report information about the link.
+.It Fl l
+Display output in
+.Ic ls Fl lT
+format.
.It Fl n
Do not force a newline to appear at the end of each piece of output.
.It Fl q
@@ -136,7 +173,8 @@ display the raw, numerical value (for example, times in seconds since the
epoch, etc.).
.It Fl s
Display information in
-.Dq "shell output" ,
+.Dq shell output
+format,
suitable for initializing variables.
.It Fl x
Display information in a more verbose way as known from some
@@ -334,49 +372,62 @@ A required field specifier, being one of the following:
.It Cm d
Device upon which
.Ar file
-resides.
+resides
+.Pq Fa st_dev .
.It Cm i
.Ar file Ns 's
-inode number.
+inode number
+.Pq Fa st_ino .
.It Cm p
-File type and permissions.
+File type and permissions
+.Pq Fa st_mode .
.It Cm l
Number of hard links to
-.Ar file .
+.Ar file
+.Pq Fa st_nlink .
.It Cm u , g
User ID and group ID of
.Ar file Ns 's
-owner.
+owner
+.Pq Fa st_uid , st_gid .
.It Cm r
-Device number for character and block device special files.
+Device number for character and block device special files
+.Pq Fa st_rdev .
.It Cm a , m , c , B
The time
.Ar file
-was last accessed or modified, of when the inode was last changed, or
-the birth time of the inode.
+was last accessed or modified, or when the inode was last changed, or
+the birth time of the inode
+.Pq Fa st_atime , st_mtime , st_ctime , st_birthtime .
.It Cm z
The size of
.Ar file
-in bytes.
+in bytes
+.Pq Fa st_size .
.It Cm b
Number of blocks allocated for
-.Ar file .
+.Ar file
+.Pq Fa st_blocks .
.It Cm k
-Optimal file system I/O operation block size.
+Optimal file system I/O operation block size
+.Pq Fa st_blksize .
.It Cm f
User defined flags for
.Ar file .
.It Cm v
-Inode generation number.
+Inode generation number
+.Pq Fa st_gen .
.El
.Pp
-The following four field specifiers are not drawn directly from the
+The following five field specifiers are not drawn directly from the
data in
.Vt "struct stat" ,
but are:
.Bl -tag -width indent
.It Cm N
The name of the file.
+.It Cm R
+The absolute pathname corresponding to the file.
.It Cm T
The file type, either as in
.Nm ls Fl F
@@ -406,12 +457,12 @@ as an output form, with the
exception of
.Cm p
which defaults to
-.Cm O ,
+.Cm O ;
.Cm a , m ,
and
.Cm c
which default to
-.Cm D ,
+.Cm D ;
and
.Cm Y , T ,
and
@@ -421,8 +472,15 @@ which default to
.Sh EXIT STATUS
.Ex -std stat readlink
.Sh EXAMPLES
+If no options are specified, the default format is
+"%d %i %Sp %l %Su %Sg %r %z \e"%Sa\e" \e"%Sm\e" \e"%Sc\e" \e"%SB\e" %k %b %#Xf %N".
+.Bd -literal -offset indent
+\*[Gt] stat /tmp/bar
+0 78852 -rw-r--r-- 1 root wheel 0 0 "Jul 8 10:26:03 2004" "Jul 8 10:26:03 2004" "Jul 8 10:28:13 2004" "Jan 1 09:00:00 1970" 16384 0 0 /tmp/bar
+.Ed
+.Pp
Given a symbolic link
-.Pa foo
+.Dq foo
that points from
.Pa /tmp/foo
to
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