-.\" $NetBSD: stat.1,v 1.28 2010/04/05 21:25:01 joerg Exp $
+.\" $NetBSD: stat.1,v 1.34 2011/09/22 20:23:55 apb Exp $
.\"
-.\" Copyright (c) 2002-2005 The NetBSD Foundation, Inc.
+.\" Copyright (c) 2002-2011 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd November 7, 2008
+.Dd September 22, 2011
.Dt STAT 1
.Os
.Sh NAME
.Op Fl t Ar timefmt
.Op Ar
.Nm readlink
-.Op Fl fn
+.Op Fl fnqsv
.Op Ar
.Sh DESCRIPTION
The
Display information in
.Dq shell output ,
suitable for initializing variables.
+When run as
+.Nm readlink ,
+suppress error messages.
.It Fl t Ar timefmt
Display timestamps using the specified format.
This format is
passed directly to
.Xr strftime 3 .
+.It Fl v
+Turn off quiet mode.
.It Fl x
Display information in a more verbose way as known from some Linux
distributions.
Any of the following optional flags:
.Bl -tag -width Ds
.It Cm #
-Selects an alternate output form for octal and hexadecimal output.
-Non-zero octal output will have a leading zero, and non-zero
-hexadecimal output will have
+Selects an alternate output form for string, octal and hexadecimal output.
+String output will be encoded in
+.Xr vis 3
+style.
+Non-zero octal output will have a leading zero.
+Non-zero hexadecimal output will have
.Dq 0x
prepended to it.
.It Cm +
The target of a symbolic link.
.It Cm Z
Expands to
-.Dq major,minor
+.Dq Ar major , Ns Ar minor
from the rdev field for character or block
special devices and gives size output for all others.
.El
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
+This example produces output very similar to that from
+.Ic find ... -ls
+(except that
+.Xr find 1
+displays the time in a different format, and
+.Xr find 1
+sometimes adds one or more spaces after the comma in
+.Dq Ar major , Ns Ar minor
+for device nodes):
+.Bd -literal -offset indent
+\*[Gt] stat -f "%7i %6b %-11Sp %3l %-17Su %-17Sg %9Z %Sm %N%SY" /tmp/bar
+ 78852 0 -rw-r--r-- 1 root wheel 0 Jul 8 10:26:03 2004 /tmp/bar
+
+\*[Gt] find /tmp/bar -ls -exit
+ 78852 0 -rw-r--r-- 1 root wheel 0 Jul 8 2004 /tmp/bar
+.Ed
+.Pp
+This example produces output very similar to that from
+.Ic ls -lTd
+(except that
+.Xr ls 1
+adjusts the column spacing differently when listing multiple files,
+and
+.Xr ls 1
+adds at least one space after the comma in
+.Dq Ar major , Ns Ar minor
+for device nodes):
+.Bd -literal -offset indent
+\*[Gt] stat -f "%-11Sp %l %Su %Sg %Z %Sm %N%SY" /tmp/bar
+-rw-r--r-- 1 root wheel 0 Jul 8 10:26:03 2004 /tmp/bar
+
+\*[Gt] ls -lTd /tmp/bar
+-rw-r--r-- 1 root wheel 0 Jul 8 10:26:03 2004 /tmp/bar
+.Ed
+.Pp
Given a symbolic link
.Dq foo
that points from
Apr 25 10:36:34 2002 /tmp/bar
Apr 24 16:47:35 2002 /tmp/foo
.Ed
+.Pp
+User names, group names, and file names that contain spaces
+or other special characters may be encoded in
+.Xr vis 3
+style, using the
+.Cm \&#
+modifier:
+.Bd -literal -offset indent
+\*[Gt] ln -s 'target with spaces' 'link with spaces'
+\*[Gt] stat -f "%#N%#SY" 'link with spaces'
+link\eswith\esspaces -\*[Gt] target\eswith\esspaces
+.Ed
.Sh SEE ALSO
.Xr basename 1 ,
.Xr dirname 1 ,
-/* $NetBSD: stat.c,v 1.33 2011/01/15 22:54:10 njoly Exp $ */
+/* $NetBSD: stat.c,v 1.36 2011/09/22 20:23:56 apb Exp $ */
/*
- * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * Copyright (c) 2002-2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
#include <sys/cdefs.h>
#if !defined(lint)
-__RCSID("$NetBSD: stat.c,v 1.33 2011/01/15 22:54:10 njoly Exp $");
+__RCSID("$NetBSD: stat.c,v 1.36 2011/09/22 20:23:56 apb Exp $");
#endif
#if ! HAVE_NBTOOL_CONFIG_H
#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1
#ifdef __minix
/* Not supported in Minix. */
-#define HAVE_DEVNAME 0
+#define HAVE_DEVNAME 0
#else /* __minix */
#define HAVE_DEVNAME 1
#endif /* __minx */
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <vis.h>
#if HAVE_STRUCT_STAT_ST_FLAGS
#define DEF_F "%#Xf "
#define SHOW_filename 'N'
#define SHOW_sizerdev 'Z'
-void usage(const char *);
-void output(const struct stat *, const char *,
- const char *, int, int);
-int format1(const struct stat *, /* stat info */
+static void usage(const char *) __dead;
+static void output(const struct stat *, const char *,
+ const char *, int, int, int);
+static int format1(const struct stat *, /* stat info */
const char *, /* the file name */
const char *, int, /* the format string itself */
char *, size_t, /* a place to put the output */
int, int, int, int, /* the parsed format */
- int, int);
+ int, int, int);
-const char *timefmt;
-int linkfail;
+static const char *timefmt;
+static int linkfail;
#define addchar(s, c, nl) \
do { \
statfmt = NULL;
timefmt = NULL;
+ setprogname(argv[0]);
+
if (strcmp(getprogname(), "readlink") == 0) {
am_readlink = 1;
- options = "fn";
- synopsis = "[-fn] [file ...]";
+ options = "fnqsv";
+ synopsis = "[-fnqsv] [file ...]";
statfmt = "%Y";
fmtchar = 'f';
quiet = 1;
case 'l':
case 'r':
case 's':
+ if (am_readlink) {
+ quiet = 1;
+ break;
+ }
+ /*FALLTHROUGH*/
case 'x':
if (fmtchar != 0)
errx(1, "can't use format '%c' with '%c'",
case 't':
timefmt = optarg;
break;
+ case 'v':
+ quiet = 0;
+ break;
default:
usage(synopsis);
}
usestat ? "stat" : "lstat");
}
else
- output(&st, argv[0], statfmt, fn, nonl);
+ output(&st, argv[0], statfmt, fn, nonl, quiet);
argv++;
argc--;
return (am_readlink ? linkfail : errs);
}
-void
+static void
usage(const char *synopsis)
{
/*
* Parses a format string.
*/
-void
+static void
output(const struct stat *st, const char *file,
- const char *statfmt, int fn, int nonl)
+ const char *statfmt, int fn, int nonl, int quiet)
{
int flags, size, prec, ofmt, hilo, what;
- char buf[PATH_MAX + 4 + 1];
+ /*
+ * buf size is enough for an item of length PATH_MAX,
+ * multiplied by 4 for vis encoding, plus 4 for symlink
+ * " -> " prefix, plus 1 for \0 terminator.
+ */
+ char buf[PATH_MAX * 4 + 4 + 1];
const char *subfmt;
int nl, t, i;
* the leading " -> " if STRING is explicitly specified. The
* sizerdev datum will generate rdev output for character or
* block devices, and size output for all others.
+ * For STRING output, the # format requests vis encoding.
*/
flags = 0;
do {
file,
subfmt, statfmt - subfmt,
buf, sizeof(buf),
- flags, size, prec, ofmt, hilo, what);
+ flags, size, prec, ofmt, hilo, what, quiet);
for (i = 0; i < t && i < (int)(sizeof(buf) - 1); i++)
addchar(stdout, buf[i], &nl);
/*
* Arranges output according to a single parsed format substring.
*/
-int
+static int
format1(const struct stat *st,
const char *file,
const char *fmt, int flen,
char *buf, size_t blen,
int flags, int size, int prec, int ofmt,
- int hilo, int what)
+ int hilo, int what, int quiet)
{
u_int64_t data;
char *stmp, lfmt[24], tmp[20];
const char *sdata;
- char smode[12], sid[12], path[PATH_MAX + 4];
+ char smode[12], sid[12], path[PATH_MAX + 4], visbuf[PATH_MAX * 4 + 4];
struct passwd *pw;
struct group *gr;
struct tm *tm;
time_t secs;
long nsecs;
- int l, small, formats, gottime, shift;
+ int l;
+ int formats; /* bitmap of allowed formats for this datum */
+ int small; /* true if datum is a small integer */
+ int gottime; /* true if secs and nsecs are valid */
+ int shift; /* powers of 2 to scale numbers before printing */
+ size_t prefixlen; /* length of constant prefix for string data */
formats = 0;
small = 0;
secs = 0;
nsecs = 0;
shift = 0;
+ prefixlen = 0;
/*
* First, pick out the data and tweak it based on hilo or
} else {
snprintf(path, sizeof(path), " -> ");
if (realpath(file, path + 4) == NULL) {
+ if (!quiet)
+ warn("realpath `%s'", file);
linkfail = 1;
l = 0;
path[0] = '\0';
}
sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
+ prefixlen = (ofmt == FMTF_STRING ? 4 : 0);
}
formats = FMTF_STRING;
snprintf(path, sizeof(path), " -> ");
l = readlink(file, path + 4, sizeof(path) - 4 - 1);
if (l == -1) {
+ if (!quiet)
+ warn("readlink `%s'", file);
linkfail = 1;
l = 0;
path[0] = '\0';
}
path[l + 4] = '\0';
sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
+ prefixlen = (ofmt == FMTF_STRING ? 4 : 0);
}
else {
linkfail = 1;
fmt, flen,
majdev, sizeof(majdev),
flags, size, prec,
- ofmt, HIGH_PIECE, SHOW_st_rdev);
+ ofmt, HIGH_PIECE, SHOW_st_rdev, quiet);
l2 = format1(st,
file,
fmt, flen,
mindev, sizeof(mindev),
flags, size, prec,
- ofmt, LOW_PIECE, SHOW_st_rdev);
+ ofmt, LOW_PIECE, SHOW_st_rdev, quiet);
return (snprintf(buf, blen, "%.*s,%.*s",
l1, majdev, l2, mindev));
}
fmt, flen,
buf, blen,
flags, size, prec,
- ofmt, 0, SHOW_st_size));
+ ofmt, 0, SHOW_st_size, quiet));
}
/*NOTREACHED*/
default:
if (hilo != 0 || (ofmt & formats) == 0)
errx(1, "%.*s: bad format", (int)flen, fmt);
+ /*
+ * FLAG_POUND with FMTF_STRING means use vis(3) encoding.
+ * First prefixlen chars are not encoded.
+ */
+ if ((flags & FLAG_POUND) != 0 && ofmt == FMTF_STRING) {
+ flags &= !FLAG_POUND;
+ strncpy(visbuf, sdata, prefixlen);
+ strnvis(visbuf + prefixlen, sizeof(visbuf) - prefixlen,
+ sdata + prefixlen, VIS_WHITE | VIS_OCTAL | VIS_CSTYLE);
+ sdata = visbuf;
+ }
+
/*
* Assemble the format string for passing to printf(3).
*/