xref: /dflybsd-src/usr.bin/stat/stat.c (revision e9445c5db101778182984b7687e323b8a5d8ad21)
19a63ce63SRobert Garrett /*
29a63ce63SRobert Garrett  * Copyright (c) 2002 The NetBSD Foundation, Inc.
39a63ce63SRobert Garrett  * All rights reserved.
49a63ce63SRobert Garrett  *
59a63ce63SRobert Garrett  * This code is derived from software contributed to The NetBSD Foundation
69a63ce63SRobert Garrett  * by Andrew Brown.
79a63ce63SRobert Garrett  *
89a63ce63SRobert Garrett  * Redistribution and use in source and binary forms, with or without
99a63ce63SRobert Garrett  * modification, are permitted provided that the following conditions
109a63ce63SRobert Garrett  * are met:
119a63ce63SRobert Garrett  * 1. Redistributions of source code must retain the above copyright
129a63ce63SRobert Garrett  *    notice, this list of conditions and the following disclaimer.
139a63ce63SRobert Garrett  * 2. Redistributions in binary form must reproduce the above copyright
149a63ce63SRobert Garrett  *    notice, this list of conditions and the following disclaimer in the
159a63ce63SRobert Garrett  *    documentation and/or other materials provided with the distribution.
169a63ce63SRobert Garrett  *
179a63ce63SRobert Garrett  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
189a63ce63SRobert Garrett  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
199a63ce63SRobert Garrett  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
209a63ce63SRobert Garrett  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
219a63ce63SRobert Garrett  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
229a63ce63SRobert Garrett  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
239a63ce63SRobert Garrett  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
249a63ce63SRobert Garrett  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
259a63ce63SRobert Garrett  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
269a63ce63SRobert Garrett  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
279a63ce63SRobert Garrett  * POSSIBILITY OF SUCH DAMAGE.
2841250c5dSMatthew Dillon  *
2946659ea9SSascha Wildner  * $NetBSD: stat.c,v 1.33 2011/01/15 22:54:10 njoly Exp $
3046659ea9SSascha Wildner  * $OpenBSD: stat.c,v 1.14 2009/06/24 09:44:25 sobrado Exp $
3146659ea9SSascha Wildner  * $FreeBSD: head/usr.bin/stat/stat.c 265893 2014-05-11 18:49:18Z thomas $
329a63ce63SRobert Garrett  */
339a63ce63SRobert Garrett 
3446659ea9SSascha Wildner #include <sys/param.h>
359a63ce63SRobert Garrett #include <sys/types.h>
369a63ce63SRobert Garrett #include <sys/stat.h>
3746659ea9SSascha Wildner #include <sys/mount.h>
389a63ce63SRobert Garrett 
399a63ce63SRobert Garrett #include <ctype.h>
409a63ce63SRobert Garrett #include <err.h>
4146659ea9SSascha Wildner #include <errno.h>
429a63ce63SRobert Garrett #include <grp.h>
439a63ce63SRobert Garrett #include <limits.h>
4446659ea9SSascha Wildner #include <paths.h>
459a63ce63SRobert Garrett #include <pwd.h>
469a63ce63SRobert Garrett #include <stdio.h>
479a63ce63SRobert Garrett #include <stdlib.h>
489a63ce63SRobert Garrett #include <string.h>
499a63ce63SRobert Garrett #include <time.h>
509a63ce63SRobert Garrett #include <unistd.h>
519a63ce63SRobert Garrett 
52*e9445c5dSzrj #ifdef BOOTSTRAPPING
53*e9445c5dSzrj #define HAVE_DEVNAME 0
54*e9445c5dSzrj #define HAVE_STRUCT_STAT_ST_FLAGS 0
55*e9445c5dSzrj #define HAVE_STRUCT_STAT_ST_GEN 0
56*e9445c5dSzrj #define HAVE_STRUCT_STAT_ST_BIRTHTIME 0
57*e9445c5dSzrj #define HAVE_STRUCT_STAT_ST_ATIM 1
58*e9445c5dSzrj #else
59*e9445c5dSzrj #define HAVE_DEVNAME 1
60*e9445c5dSzrj #define HAVE_STRUCT_STAT_ST_FLAGS 1
61*e9445c5dSzrj #define HAVE_STRUCT_STAT_ST_GEN 1
62*e9445c5dSzrj #define HAVE_STRUCT_STAT_ST_BIRTHTIME 0
63*e9445c5dSzrj #define HAVE_STRUCT_STAT_ST_ATIM 1
64*e9445c5dSzrj #endif
65*e9445c5dSzrj 
66d542b1f4SSimon Schubert #if HAVE_STRUCT_STAT_ST_FLAGS
67d542b1f4SSimon Schubert #define DEF_F "%#Xf "
68d542b1f4SSimon Schubert #define RAW_F "%f "
69d542b1f4SSimon Schubert #define SHELL_F " st_flags=%f"
70d542b1f4SSimon Schubert #else /* HAVE_STRUCT_STAT_ST_FLAGS */
71d542b1f4SSimon Schubert #define DEF_F
72d542b1f4SSimon Schubert #define RAW_F
73d542b1f4SSimon Schubert #define SHELL_F
74d542b1f4SSimon Schubert #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
75d542b1f4SSimon Schubert 
76d542b1f4SSimon Schubert #if HAVE_STRUCT_STAT_ST_BIRTHTIME
77d542b1f4SSimon Schubert #define DEF_B "\"%SB\" "
78d542b1f4SSimon Schubert #define RAW_B "%B "
79d542b1f4SSimon Schubert #define SHELL_B "st_birthtime=%B "
80d542b1f4SSimon Schubert #else /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
81d542b1f4SSimon Schubert #define DEF_B
82d542b1f4SSimon Schubert #define RAW_B
83d542b1f4SSimon Schubert #define SHELL_B
84d542b1f4SSimon Schubert #endif /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
85d542b1f4SSimon Schubert 
86d542b1f4SSimon Schubert #if HAVE_STRUCT_STAT_ST_ATIM
87d542b1f4SSimon Schubert #define st_atimespec st_atim
88d542b1f4SSimon Schubert #define st_ctimespec st_ctim
89d542b1f4SSimon Schubert #define st_mtimespec st_mtim
90d542b1f4SSimon Schubert #endif /* HAVE_STRUCT_STAT_ST_ATIM */
91d542b1f4SSimon Schubert 
929a63ce63SRobert Garrett #define DEF_FORMAT \
93d542b1f4SSimon Schubert 	"%d %i %Sp %l %Su %Sg %r %z \"%Sa\" \"%Sm\" \"%Sc\" " DEF_B \
94d542b1f4SSimon Schubert 	"%k %b " DEF_F "%N"
95d542b1f4SSimon Schubert #define RAW_FORMAT	"%d %i %#p %l %u %g %r %z %a %m %c " RAW_B \
96d542b1f4SSimon Schubert 	"%k %b " RAW_F "%N"
97d542b1f4SSimon Schubert #define LS_FORMAT	"%Sp %l %Su %Sg %Z %Sm %N%SY"
98d542b1f4SSimon Schubert #define LSF_FORMAT	"%Sp %l %Su %Sg %Z %Sm %N%T%SY"
999a63ce63SRobert Garrett #define SHELL_FORMAT \
1009a63ce63SRobert Garrett 	"st_dev=%d st_ino=%i st_mode=%#p st_nlink=%l " \
1019a63ce63SRobert Garrett 	"st_uid=%u st_gid=%g st_rdev=%r st_size=%z " \
102d542b1f4SSimon Schubert 	"st_atime=%a st_mtime=%m st_ctime=%c " SHELL_B \
103d542b1f4SSimon Schubert 	"st_blksize=%k st_blocks=%b" SHELL_F
1049a63ce63SRobert Garrett #define LINUX_FORMAT \
1059a63ce63SRobert Garrett 	"  File: \"%N\"%n" \
1069a63ce63SRobert Garrett 	"  Size: %-11z  FileType: %HT%n" \
10746659ea9SSascha Wildner 	"  Mode: (%OMp%03OLp/%.10Sp)         Uid: (%5u/%8Su)  Gid: (%5g/%8Sg)%n" \
1089a63ce63SRobert Garrett 	"Device: %Hd,%Ld   Inode: %i    Links: %l%n" \
109d542b1f4SSimon Schubert 	"Access: %Sa%n" \
110d542b1f4SSimon Schubert 	"Modify: %Sm%n" \
111d542b1f4SSimon Schubert 	"Change: %Sc"
1129a63ce63SRobert Garrett 
1139a63ce63SRobert Garrett #define TIME_FORMAT	"%b %e %T %Y"
1149a63ce63SRobert Garrett 
1159a63ce63SRobert Garrett #define FLAG_POUND	0x01
1169a63ce63SRobert Garrett #define FLAG_SPACE	0x02
1179a63ce63SRobert Garrett #define FLAG_PLUS	0x04
1189a63ce63SRobert Garrett #define FLAG_ZERO	0x08
1199a63ce63SRobert Garrett #define FLAG_MINUS	0x10
1209a63ce63SRobert Garrett 
1219a63ce63SRobert Garrett /*
1229a63ce63SRobert Garrett  * These format characters must all be unique, except the magic one.
1239a63ce63SRobert Garrett  */
1249a63ce63SRobert Garrett #define FMT_MAGIC	'%'
1259a63ce63SRobert Garrett #define FMT_DOT		'.'
1269a63ce63SRobert Garrett 
1279a63ce63SRobert Garrett #define SIMPLE_NEWLINE	'n'
1289a63ce63SRobert Garrett #define SIMPLE_TAB	't'
1299a63ce63SRobert Garrett #define SIMPLE_PERCENT	'%'
1309a63ce63SRobert Garrett #define SIMPLE_NUMBER	'@'
1319a63ce63SRobert Garrett 
1329a63ce63SRobert Garrett #define FMT_POUND	'#'
1339a63ce63SRobert Garrett #define FMT_SPACE	' '
1349a63ce63SRobert Garrett #define FMT_PLUS	'+'
1359a63ce63SRobert Garrett #define FMT_ZERO	'0'
1369a63ce63SRobert Garrett #define FMT_MINUS	'-'
1379a63ce63SRobert Garrett 
1389a63ce63SRobert Garrett #define FMT_DECIMAL 	'D'
1399a63ce63SRobert Garrett #define FMT_OCTAL 	'O'
1409a63ce63SRobert Garrett #define FMT_UNSIGNED 	'U'
1419a63ce63SRobert Garrett #define FMT_HEX 	'X'
1429a63ce63SRobert Garrett #define FMT_FLOAT 	'F'
1439a63ce63SRobert Garrett #define FMT_STRING 	'S'
1449a63ce63SRobert Garrett 
1459a63ce63SRobert Garrett #define FMTF_DECIMAL	0x01
1469a63ce63SRobert Garrett #define FMTF_OCTAL	0x02
1479a63ce63SRobert Garrett #define FMTF_UNSIGNED	0x04
1489a63ce63SRobert Garrett #define FMTF_HEX	0x08
1499a63ce63SRobert Garrett #define FMTF_FLOAT	0x10
1509a63ce63SRobert Garrett #define FMTF_STRING	0x20
1519a63ce63SRobert Garrett 
1529a63ce63SRobert Garrett #define HIGH_PIECE	'H'
1539a63ce63SRobert Garrett #define MIDDLE_PIECE	'M'
1549a63ce63SRobert Garrett #define LOW_PIECE	'L'
1559a63ce63SRobert Garrett 
15646659ea9SSascha Wildner #define	SHOW_realpath	'R'
1579a63ce63SRobert Garrett #define SHOW_st_dev	'd'
1589a63ce63SRobert Garrett #define SHOW_st_ino	'i'
1599a63ce63SRobert Garrett #define SHOW_st_mode	'p'
1609a63ce63SRobert Garrett #define SHOW_st_nlink	'l'
1619a63ce63SRobert Garrett #define SHOW_st_uid	'u'
1629a63ce63SRobert Garrett #define SHOW_st_gid	'g'
1639a63ce63SRobert Garrett #define SHOW_st_rdev	'r'
1649a63ce63SRobert Garrett #define SHOW_st_atime	'a'
1659a63ce63SRobert Garrett #define SHOW_st_mtime	'm'
1669a63ce63SRobert Garrett #define SHOW_st_ctime	'c'
167d542b1f4SSimon Schubert #define SHOW_st_btime	'B'
1689a63ce63SRobert Garrett #define SHOW_st_size	'z'
1699a63ce63SRobert Garrett #define SHOW_st_blocks	'b'
1709a63ce63SRobert Garrett #define SHOW_st_blksize	'k'
1719a63ce63SRobert Garrett #define SHOW_st_flags	'f'
1729a63ce63SRobert Garrett #define SHOW_st_gen	'v'
1739a63ce63SRobert Garrett #define SHOW_symlink	'Y'
1749a63ce63SRobert Garrett #define SHOW_filetype	'T'
1759a63ce63SRobert Garrett #define SHOW_filename	'N'
1769a63ce63SRobert Garrett #define SHOW_sizerdev	'Z'
1779a63ce63SRobert Garrett 
1786d08986dSSascha Wildner static void	usage(const char *) __dead2;
17933437a44SSascha Wildner static void	output(const struct stat *, const char *,
18046659ea9SSascha Wildner 		    const char *, int, int);
18133437a44SSascha Wildner static int	format1(const struct stat *,	/* stat info */
1829a63ce63SRobert Garrett 		    const char *,		/* the file name */
1839a63ce63SRobert Garrett 		    const char *, int,		/* the format string itself */
1849a63ce63SRobert Garrett 		    char *, size_t,		/* a place to put the output */
1859a63ce63SRobert Garrett 		    int, int, int, int,		/* the parsed format */
1869a63ce63SRobert Garrett 		    int, int);
187*e9445c5dSzrj #if HAVE_DEVNAME
18833437a44SSascha Wildner static int	hex2byte(const char [2]);
189*e9445c5dSzrj #endif
19046659ea9SSascha Wildner #if HAVE_STRUCT_STAT_ST_FLAGS
19133437a44SSascha Wildner static char	*xfflagstostr(unsigned long);
19246659ea9SSascha Wildner #endif
1939a63ce63SRobert Garrett 
19446659ea9SSascha Wildner static const char *timefmt;
19546659ea9SSascha Wildner static int linkfail;
1969a63ce63SRobert Garrett 
1979a63ce63SRobert Garrett #define addchar(s, c, nl) \
1989a63ce63SRobert Garrett 	do { \
19946659ea9SSascha Wildner 		fputc((c), (s)); \
2009a63ce63SRobert Garrett 		(*nl) = ((c) == '\n'); \
2019a63ce63SRobert Garrett 	} while (0/*CONSTCOND*/)
2029a63ce63SRobert Garrett 
2039a63ce63SRobert Garrett int
main(int argc,char * argv[])2049a63ce63SRobert Garrett main(int argc, char *argv[])
2059a63ce63SRobert Garrett {
2069a63ce63SRobert Garrett 	struct stat st;
2079a63ce63SRobert Garrett 	int ch, rc, errs, am_readlink;
20846659ea9SSascha Wildner 	int lsF, fmtchar, usestat, nfs_handle, fn, nonl, quiet;
20946659ea9SSascha Wildner 	const char *statfmt, *options, *synopsis;
210*e9445c5dSzrj #if HAVE_DEVNAME
21146659ea9SSascha Wildner 	char dname[sizeof _PATH_DEV + MNAMELEN] = _PATH_DEV;
21246659ea9SSascha Wildner 	fhandle_t fhnd;
213*e9445c5dSzrj #endif
21446659ea9SSascha Wildner 	const char *file;
2159a63ce63SRobert Garrett 
2169a63ce63SRobert Garrett 	am_readlink = 0;
2179a63ce63SRobert Garrett 	lsF = 0;
2189a63ce63SRobert Garrett 	fmtchar = '\0';
2199a63ce63SRobert Garrett 	usestat = 0;
22046659ea9SSascha Wildner 	nfs_handle = 0;
2219a63ce63SRobert Garrett 	nonl = 0;
2229a63ce63SRobert Garrett 	quiet = 0;
2239a63ce63SRobert Garrett 	linkfail = 0;
2249a63ce63SRobert Garrett 	statfmt = NULL;
2259a63ce63SRobert Garrett 	timefmt = NULL;
2269a63ce63SRobert Garrett 
2279a63ce63SRobert Garrett 	if (strcmp(getprogname(), "readlink") == 0) {
2289a63ce63SRobert Garrett 		am_readlink = 1;
22946659ea9SSascha Wildner 		options = "fn";
23046659ea9SSascha Wildner 		synopsis = "[-fn] [file ...]";
2319a63ce63SRobert Garrett 		statfmt = "%Y";
2329a63ce63SRobert Garrett 		fmtchar = 'f';
2339a63ce63SRobert Garrett 		quiet = 1;
2349a63ce63SRobert Garrett 	} else {
23546659ea9SSascha Wildner 		options = "f:FHlLnqrst:x";
23646659ea9SSascha Wildner 		synopsis = "[-FLnq] [-f format | -l | -r | -s | -x] "
23746659ea9SSascha Wildner 		    "[-t timefmt] [file|handle ...]";
2389a63ce63SRobert Garrett 	}
2399a63ce63SRobert Garrett 
2409a63ce63SRobert Garrett 	while ((ch = getopt(argc, argv, options)) != -1)
2419a63ce63SRobert Garrett 		switch (ch) {
2429a63ce63SRobert Garrett 		case 'F':
2439a63ce63SRobert Garrett 			lsF = 1;
2449a63ce63SRobert Garrett 			break;
24546659ea9SSascha Wildner                 case 'H':
24646659ea9SSascha Wildner 			nfs_handle = 1;
24746659ea9SSascha Wildner 			break;
2489a63ce63SRobert Garrett 		case 'L':
2499a63ce63SRobert Garrett 			usestat = 1;
2509a63ce63SRobert Garrett 			break;
2519a63ce63SRobert Garrett 		case 'n':
2529a63ce63SRobert Garrett 			nonl = 1;
2539a63ce63SRobert Garrett 			break;
2549a63ce63SRobert Garrett 		case 'q':
2559a63ce63SRobert Garrett 			quiet = 1;
2569a63ce63SRobert Garrett 			break;
2579a63ce63SRobert Garrett 		case 'f':
25846659ea9SSascha Wildner 			if (am_readlink) {
25946659ea9SSascha Wildner 				statfmt = "%R";
26046659ea9SSascha Wildner 				break;
26146659ea9SSascha Wildner 			}
2629a63ce63SRobert Garrett 			statfmt = optarg;
2639a63ce63SRobert Garrett 			/* FALLTHROUGH */
2649a63ce63SRobert Garrett 		case 'l':
2659a63ce63SRobert Garrett 		case 'r':
2669a63ce63SRobert Garrett 		case 's':
2679a63ce63SRobert Garrett 		case 'x':
2689a63ce63SRobert Garrett 			if (fmtchar != 0)
2699a63ce63SRobert Garrett 				errx(1, "can't use format '%c' with '%c'",
2709a63ce63SRobert Garrett 				    fmtchar, ch);
2719a63ce63SRobert Garrett 			fmtchar = ch;
2729a63ce63SRobert Garrett 			break;
2739a63ce63SRobert Garrett 		case 't':
2749a63ce63SRobert Garrett 			timefmt = optarg;
2759a63ce63SRobert Garrett 			break;
2769a63ce63SRobert Garrett 		default:
2779a63ce63SRobert Garrett 			usage(synopsis);
2789a63ce63SRobert Garrett 		}
2799a63ce63SRobert Garrett 
2809a63ce63SRobert Garrett 	argc -= optind;
2819a63ce63SRobert Garrett 	argv += optind;
2829a63ce63SRobert Garrett 	fn = 1;
2839a63ce63SRobert Garrett 
2849a63ce63SRobert Garrett 	if (fmtchar == '\0') {
2859a63ce63SRobert Garrett 		if (lsF)
2869a63ce63SRobert Garrett 			fmtchar = 'l';
2879a63ce63SRobert Garrett 		else {
2889a63ce63SRobert Garrett 			fmtchar = 'f';
2899a63ce63SRobert Garrett 			statfmt = DEF_FORMAT;
2909a63ce63SRobert Garrett 		}
2919a63ce63SRobert Garrett 	}
2929a63ce63SRobert Garrett 
2939a63ce63SRobert Garrett 	if (lsF && fmtchar != 'l')
2949a63ce63SRobert Garrett 		errx(1, "can't use format '%c' with -F", fmtchar);
2959a63ce63SRobert Garrett 
2969a63ce63SRobert Garrett 	switch (fmtchar) {
2979a63ce63SRobert Garrett 	case 'f':
2989a63ce63SRobert Garrett 		/* statfmt already set */
2999a63ce63SRobert Garrett 		break;
3009a63ce63SRobert Garrett 	case 'l':
3019a63ce63SRobert Garrett 		statfmt = lsF ? LSF_FORMAT : LS_FORMAT;
3029a63ce63SRobert Garrett 		break;
3039a63ce63SRobert Garrett 	case 'r':
3049a63ce63SRobert Garrett 		statfmt = RAW_FORMAT;
3059a63ce63SRobert Garrett 		break;
3069a63ce63SRobert Garrett 	case 's':
3079a63ce63SRobert Garrett 		statfmt = SHELL_FORMAT;
3089a63ce63SRobert Garrett 		break;
3099a63ce63SRobert Garrett 	case 'x':
3109a63ce63SRobert Garrett 		statfmt = LINUX_FORMAT;
3119a63ce63SRobert Garrett 		if (timefmt == NULL)
3129a63ce63SRobert Garrett 			timefmt = "%c";
3139a63ce63SRobert Garrett 		break;
3149a63ce63SRobert Garrett 	default:
3159a63ce63SRobert Garrett 		usage(synopsis);
3169a63ce63SRobert Garrett 		/*NOTREACHED*/
3179a63ce63SRobert Garrett 	}
3189a63ce63SRobert Garrett 
3199a63ce63SRobert Garrett 	if (timefmt == NULL)
3209a63ce63SRobert Garrett 		timefmt = TIME_FORMAT;
3219a63ce63SRobert Garrett 
3229a63ce63SRobert Garrett 	errs = 0;
3239a63ce63SRobert Garrett 	do {
32446659ea9SSascha Wildner 		if (argc == 0) {
325*e9445c5dSzrj #if HAVE_DEVNAME
32646659ea9SSascha Wildner 			if (fdevname_r(STDIN_FILENO, dname +
32746659ea9SSascha Wildner 			    sizeof _PATH_DEV - 1, MNAMELEN) == 0)
32846659ea9SSascha Wildner 				file = dname;
3299a63ce63SRobert Garrett 			else
330*e9445c5dSzrj #endif
33146659ea9SSascha Wildner 				file = "(stdin)";
33246659ea9SSascha Wildner 			rc = fstat(STDIN_FILENO, &st);
33346659ea9SSascha Wildner 		} else {
33446659ea9SSascha Wildner 			file = argv[0];
33546659ea9SSascha Wildner 			if (nfs_handle) {
336*e9445c5dSzrj #if HAVE_DEVNAME
337*e9445c5dSzrj 				int j;
338*e9445c5dSzrj 
33946659ea9SSascha Wildner 				rc = 0;
34046659ea9SSascha Wildner 				bzero(&fhnd, sizeof(fhnd));
34146659ea9SSascha Wildner 				j = MIN(2 * sizeof(fhnd), strlen(file));
34246659ea9SSascha Wildner 				if ((j & 1) != 0) {
34346659ea9SSascha Wildner 					rc = -1;
34446659ea9SSascha Wildner 				} else {
34546659ea9SSascha Wildner 					while (j) {
34646659ea9SSascha Wildner 						rc = hex2byte(&file[j - 2]);
34746659ea9SSascha Wildner 						if (rc == -1)
34846659ea9SSascha Wildner 							break;
34946659ea9SSascha Wildner 						((char*) &fhnd)[j / 2 - 1] = rc;
35046659ea9SSascha Wildner 						j -= 2;
35146659ea9SSascha Wildner 					}
35246659ea9SSascha Wildner 				}
35346659ea9SSascha Wildner 				if (rc == -1)
35446659ea9SSascha Wildner 					errno = EINVAL;
35546659ea9SSascha Wildner 				else
35646659ea9SSascha Wildner 					rc = fhstat(&fhnd, &st);
357*e9445c5dSzrj #else
358*e9445c5dSzrj 				err(1, "-H is disabled in btools");
359*e9445c5dSzrj #endif
36046659ea9SSascha Wildner 			} else if (usestat) {
36146659ea9SSascha Wildner 				/*
36246659ea9SSascha Wildner 				 * Try stat() and if it fails, fall back to
36346659ea9SSascha Wildner 				 * lstat() just in case we're examining a
36446659ea9SSascha Wildner 				 * broken symlink.
36546659ea9SSascha Wildner 				 */
36646659ea9SSascha Wildner 				if ((rc = stat(file, &st)) == -1 &&
36746659ea9SSascha Wildner 				    errno == ENOENT &&
36846659ea9SSascha Wildner 				    (rc = lstat(file, &st)) == -1)
36946659ea9SSascha Wildner 					errno = ENOENT;
37046659ea9SSascha Wildner 			}
37146659ea9SSascha Wildner 			else
37246659ea9SSascha Wildner 				rc = lstat(file, &st);
37346659ea9SSascha Wildner 		}
3749a63ce63SRobert Garrett 
3759a63ce63SRobert Garrett 		if (rc == -1) {
3769a63ce63SRobert Garrett 			errs = 1;
3779a63ce63SRobert Garrett 			linkfail = 1;
3789a63ce63SRobert Garrett 			if (!quiet)
37946659ea9SSascha Wildner 				warn("%s: stat", file);
3809a63ce63SRobert Garrett 		}
3819a63ce63SRobert Garrett 		else
38246659ea9SSascha Wildner 			output(&st, file, statfmt, fn, nonl);
3839a63ce63SRobert Garrett 
3849a63ce63SRobert Garrett 		argv++;
3859a63ce63SRobert Garrett 		argc--;
3869a63ce63SRobert Garrett 		fn++;
3879a63ce63SRobert Garrett 	} while (argc > 0);
3889a63ce63SRobert Garrett 
3899a63ce63SRobert Garrett 	return (am_readlink ? linkfail : errs);
3909a63ce63SRobert Garrett }
3919a63ce63SRobert Garrett 
39246659ea9SSascha Wildner #if HAVE_STRUCT_STAT_ST_FLAGS
39346659ea9SSascha Wildner /*
39446659ea9SSascha Wildner  * fflagstostr() wrapper that leaks only once
39546659ea9SSascha Wildner  */
39633437a44SSascha Wildner static char *
xfflagstostr(unsigned long fflags)39746659ea9SSascha Wildner xfflagstostr(unsigned long fflags)
39846659ea9SSascha Wildner {
39946659ea9SSascha Wildner 	static char *str = NULL;
40046659ea9SSascha Wildner 
40146659ea9SSascha Wildner 	if (str != NULL)
40246659ea9SSascha Wildner 		free(str);
40346659ea9SSascha Wildner 
40446659ea9SSascha Wildner 	str = fflagstostr(fflags);
40546659ea9SSascha Wildner 	if (str == NULL)
40646659ea9SSascha Wildner 		err(1, "fflagstostr");
40746659ea9SSascha Wildner 	return (str);
40846659ea9SSascha Wildner }
40946659ea9SSascha Wildner #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
41046659ea9SSascha Wildner 
41133437a44SSascha Wildner static void
usage(const char * synopsis)4129a63ce63SRobert Garrett usage(const char *synopsis)
4139a63ce63SRobert Garrett {
4149a63ce63SRobert Garrett 
41546659ea9SSascha Wildner 	fprintf(stderr, "usage: %s %s\n", getprogname(), synopsis);
4169a63ce63SRobert Garrett 	exit(1);
4179a63ce63SRobert Garrett }
4189a63ce63SRobert Garrett 
4199a63ce63SRobert Garrett /*
4209a63ce63SRobert Garrett  * Parses a format string.
4219a63ce63SRobert Garrett  */
42233437a44SSascha Wildner static void
output(const struct stat * st,const char * file,const char * statfmt,int fn,int nonl)4239a63ce63SRobert Garrett output(const struct stat *st, const char *file,
42446659ea9SSascha Wildner     const char *statfmt, int fn, int nonl)
4259a63ce63SRobert Garrett {
4269a63ce63SRobert Garrett 	int flags, size, prec, ofmt, hilo, what;
42746659ea9SSascha Wildner 	char buf[PATH_MAX + 4 + 1];
4289a63ce63SRobert Garrett 	const char *subfmt;
4299a63ce63SRobert Garrett 	int nl, t, i;
4309a63ce63SRobert Garrett 
4319a63ce63SRobert Garrett 	nl = 1;
4329a63ce63SRobert Garrett 	while (*statfmt != '\0') {
4339a63ce63SRobert Garrett 
4349a63ce63SRobert Garrett 		/*
4359a63ce63SRobert Garrett 		 * Non-format characters go straight out.
4369a63ce63SRobert Garrett 		 */
4379a63ce63SRobert Garrett 		if (*statfmt != FMT_MAGIC) {
4389a63ce63SRobert Garrett 			addchar(stdout, *statfmt, &nl);
4399a63ce63SRobert Garrett 			statfmt++;
4409a63ce63SRobert Garrett 			continue;
4419a63ce63SRobert Garrett 		}
4429a63ce63SRobert Garrett 
4439a63ce63SRobert Garrett 		/*
4449a63ce63SRobert Garrett 		 * The current format "substring" starts here,
4459a63ce63SRobert Garrett 		 * and then we skip the magic.
4469a63ce63SRobert Garrett 		 */
4479a63ce63SRobert Garrett 		subfmt = statfmt;
4489a63ce63SRobert Garrett 		statfmt++;
4499a63ce63SRobert Garrett 
4509a63ce63SRobert Garrett 		/*
4519a63ce63SRobert Garrett 		 * Some simple one-character "formats".
4529a63ce63SRobert Garrett 		 */
4539a63ce63SRobert Garrett 		switch (*statfmt) {
4549a63ce63SRobert Garrett 		case SIMPLE_NEWLINE:
4559a63ce63SRobert Garrett 			addchar(stdout, '\n', &nl);
4569a63ce63SRobert Garrett 			statfmt++;
4579a63ce63SRobert Garrett 			continue;
4589a63ce63SRobert Garrett 		case SIMPLE_TAB:
4599a63ce63SRobert Garrett 			addchar(stdout, '\t', &nl);
4609a63ce63SRobert Garrett 			statfmt++;
4619a63ce63SRobert Garrett 			continue;
4629a63ce63SRobert Garrett 		case SIMPLE_PERCENT:
4639a63ce63SRobert Garrett 			addchar(stdout, '%', &nl);
4649a63ce63SRobert Garrett 			statfmt++;
4659a63ce63SRobert Garrett 			continue;
4669a63ce63SRobert Garrett 		case SIMPLE_NUMBER: {
4679a63ce63SRobert Garrett 			char num[12], *p;
4689a63ce63SRobert Garrett 
4699a63ce63SRobert Garrett 			snprintf(num, sizeof(num), "%d", fn);
4709a63ce63SRobert Garrett 			for (p = &num[0]; *p; p++)
4719a63ce63SRobert Garrett 				addchar(stdout, *p, &nl);
4729a63ce63SRobert Garrett 			statfmt++;
4739a63ce63SRobert Garrett 			continue;
4749a63ce63SRobert Garrett 		}
4759a63ce63SRobert Garrett 		}
4769a63ce63SRobert Garrett 
4779a63ce63SRobert Garrett 		/*
4789a63ce63SRobert Garrett 		 * This must be an actual format string.  Format strings are
4799a63ce63SRobert Garrett 		 * similar to printf(3) formats up to a point, and are of
4809a63ce63SRobert Garrett 		 * the form:
4819a63ce63SRobert Garrett 		 *
4829a63ce63SRobert Garrett 		 *	%	required start of format
4839a63ce63SRobert Garrett 		 *	[-# +0]	opt. format characters
4849a63ce63SRobert Garrett 		 *	size	opt. field width
4859a63ce63SRobert Garrett 		 *	.	opt. decimal separator, followed by
4869a63ce63SRobert Garrett 		 *	prec	opt. precision
4879a63ce63SRobert Garrett 		 *	fmt	opt. output specifier (string, numeric, etc.)
4889a63ce63SRobert Garrett 		 *	sub	opt. sub field specifier (high, middle, low)
4899a63ce63SRobert Garrett 		 *	datum	required field specifier (size, mode, etc)
4909a63ce63SRobert Garrett 		 *
4919a63ce63SRobert Garrett 		 * Only the % and the datum selector are required.  All data
4929a63ce63SRobert Garrett 		 * have reasonable default output forms.  The "sub" specifier
4939a63ce63SRobert Garrett 		 * only applies to certain data (mode, dev, rdev, filetype).
4949a63ce63SRobert Garrett 		 * The symlink output defaults to STRING, yet will only emit
4959a63ce63SRobert Garrett 		 * the leading " -> " if STRING is explicitly specified.  The
4969a63ce63SRobert Garrett 		 * sizerdev datum will generate rdev output for character or
4979a63ce63SRobert Garrett 		 * block devices, and size output for all others.
4989a63ce63SRobert Garrett 		 */
4999a63ce63SRobert Garrett 		flags = 0;
5009a63ce63SRobert Garrett 		do {
5019a63ce63SRobert Garrett 			if      (*statfmt == FMT_POUND)
5029a63ce63SRobert Garrett 				flags |= FLAG_POUND;
5039a63ce63SRobert Garrett 			else if (*statfmt == FMT_SPACE)
5049a63ce63SRobert Garrett 				flags |= FLAG_SPACE;
5059a63ce63SRobert Garrett 			else if (*statfmt == FMT_PLUS)
5069a63ce63SRobert Garrett 				flags |= FLAG_PLUS;
5079a63ce63SRobert Garrett 			else if (*statfmt == FMT_ZERO)
5089a63ce63SRobert Garrett 				flags |= FLAG_ZERO;
5099a63ce63SRobert Garrett 			else if (*statfmt == FMT_MINUS)
5109a63ce63SRobert Garrett 				flags |= FLAG_MINUS;
5119a63ce63SRobert Garrett 			else
5129a63ce63SRobert Garrett 				break;
5139a63ce63SRobert Garrett 			statfmt++;
5149a63ce63SRobert Garrett 		} while (1/*CONSTCOND*/);
5159a63ce63SRobert Garrett 
5169a63ce63SRobert Garrett 		size = -1;
5179a63ce63SRobert Garrett 		if (isdigit((unsigned)*statfmt)) {
5189a63ce63SRobert Garrett 			size = 0;
5199a63ce63SRobert Garrett 			while (isdigit((unsigned)*statfmt)) {
5209a63ce63SRobert Garrett 				size = (size * 10) + (*statfmt - '0');
5219a63ce63SRobert Garrett 				statfmt++;
5229a63ce63SRobert Garrett 				if (size < 0)
5239a63ce63SRobert Garrett 					goto badfmt;
5249a63ce63SRobert Garrett 			}
5259a63ce63SRobert Garrett 		}
5269a63ce63SRobert Garrett 
5279a63ce63SRobert Garrett 		prec = -1;
5289a63ce63SRobert Garrett 		if (*statfmt == FMT_DOT) {
5299a63ce63SRobert Garrett 			statfmt++;
5309a63ce63SRobert Garrett 
5319a63ce63SRobert Garrett 			prec = 0;
5329a63ce63SRobert Garrett 			while (isdigit((unsigned)*statfmt)) {
5339a63ce63SRobert Garrett 				prec = (prec * 10) + (*statfmt - '0');
5349a63ce63SRobert Garrett 				statfmt++;
5359a63ce63SRobert Garrett 				if (prec < 0)
5369a63ce63SRobert Garrett 					goto badfmt;
5379a63ce63SRobert Garrett 			}
5389a63ce63SRobert Garrett 		}
5399a63ce63SRobert Garrett 
5409a63ce63SRobert Garrett #define fmtcase(x, y)		case (y): (x) = (y); statfmt++; break
5419a63ce63SRobert Garrett #define fmtcasef(x, y, z)	case (y): (x) = (z); statfmt++; break
5429a63ce63SRobert Garrett 		switch (*statfmt) {
5439a63ce63SRobert Garrett 			fmtcasef(ofmt, FMT_DECIMAL,	FMTF_DECIMAL);
5449a63ce63SRobert Garrett 			fmtcasef(ofmt, FMT_OCTAL,	FMTF_OCTAL);
5459a63ce63SRobert Garrett 			fmtcasef(ofmt, FMT_UNSIGNED,	FMTF_UNSIGNED);
5469a63ce63SRobert Garrett 			fmtcasef(ofmt, FMT_HEX,		FMTF_HEX);
5479a63ce63SRobert Garrett 			fmtcasef(ofmt, FMT_FLOAT,	FMTF_FLOAT);
5489a63ce63SRobert Garrett 			fmtcasef(ofmt, FMT_STRING,	FMTF_STRING);
5499a63ce63SRobert Garrett 		default:
5509a63ce63SRobert Garrett 			ofmt = 0;
5519a63ce63SRobert Garrett 			break;
5529a63ce63SRobert Garrett 		}
5539a63ce63SRobert Garrett 
5549a63ce63SRobert Garrett 		switch (*statfmt) {
5559a63ce63SRobert Garrett 			fmtcase(hilo, HIGH_PIECE);
5569a63ce63SRobert Garrett 			fmtcase(hilo, MIDDLE_PIECE);
5579a63ce63SRobert Garrett 			fmtcase(hilo, LOW_PIECE);
5589a63ce63SRobert Garrett 		default:
5599a63ce63SRobert Garrett 			hilo = 0;
5609a63ce63SRobert Garrett 			break;
5619a63ce63SRobert Garrett 		}
5629a63ce63SRobert Garrett 
5639a63ce63SRobert Garrett 		switch (*statfmt) {
56446659ea9SSascha Wildner 			fmtcase(what, SHOW_realpath);
5659a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_dev);
5669a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_ino);
5679a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_mode);
5689a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_nlink);
5699a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_uid);
5709a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_gid);
5719a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_rdev);
5729a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_atime);
5739a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_mtime);
5749a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_ctime);
575d542b1f4SSimon Schubert 			fmtcase(what, SHOW_st_btime);
5769a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_size);
5779a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_blocks);
5789a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_blksize);
5799a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_flags);
5809a63ce63SRobert Garrett 			fmtcase(what, SHOW_st_gen);
5819a63ce63SRobert Garrett 			fmtcase(what, SHOW_symlink);
5829a63ce63SRobert Garrett 			fmtcase(what, SHOW_filetype);
5839a63ce63SRobert Garrett 			fmtcase(what, SHOW_filename);
5849a63ce63SRobert Garrett 			fmtcase(what, SHOW_sizerdev);
5859a63ce63SRobert Garrett 		default:
5869a63ce63SRobert Garrett 			goto badfmt;
5879a63ce63SRobert Garrett 		}
5889a63ce63SRobert Garrett #undef fmtcasef
5899a63ce63SRobert Garrett #undef fmtcase
5909a63ce63SRobert Garrett 
5919a63ce63SRobert Garrett 		t = format1(st,
5929a63ce63SRobert Garrett 		     file,
5939a63ce63SRobert Garrett 		     subfmt, statfmt - subfmt,
5949a63ce63SRobert Garrett 		     buf, sizeof(buf),
5959a63ce63SRobert Garrett 		     flags, size, prec, ofmt, hilo, what);
5969a63ce63SRobert Garrett 
59746659ea9SSascha Wildner 		for (i = 0; i < t && i < (int)(sizeof(buf) - 1); i++)
5989a63ce63SRobert Garrett 			addchar(stdout, buf[i], &nl);
5999a63ce63SRobert Garrett 
6009a63ce63SRobert Garrett 		continue;
6019a63ce63SRobert Garrett 
6029a63ce63SRobert Garrett 	badfmt:
6039a63ce63SRobert Garrett 		errx(1, "%.*s: bad format",
6049a63ce63SRobert Garrett 		    (int)(statfmt - subfmt + 1), subfmt);
6059a63ce63SRobert Garrett 	}
6069a63ce63SRobert Garrett 
6079a63ce63SRobert Garrett 	if (!nl && !nonl)
60846659ea9SSascha Wildner 		fputc('\n', stdout);
60946659ea9SSascha Wildner 	fflush(stdout);
6109a63ce63SRobert Garrett }
6119a63ce63SRobert Garrett 
6129a63ce63SRobert Garrett /*
6139a63ce63SRobert Garrett  * Arranges output according to a single parsed format substring.
6149a63ce63SRobert Garrett  */
61533437a44SSascha Wildner 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)6169a63ce63SRobert Garrett format1(const struct stat *st,
6179a63ce63SRobert Garrett     const char *file,
6189a63ce63SRobert Garrett     const char *fmt, int flen,
6199a63ce63SRobert Garrett     char *buf, size_t blen,
6209a63ce63SRobert Garrett     int flags, int size, int prec, int ofmt,
6219a63ce63SRobert Garrett     int hilo, int what)
6229a63ce63SRobert Garrett {
6239a63ce63SRobert Garrett 	u_int64_t data;
62446659ea9SSascha Wildner 	char *stmp, lfmt[24], tmp[20];
62546659ea9SSascha Wildner 	const char *sdata;
6269a63ce63SRobert Garrett 	char smode[12], sid[12], path[PATH_MAX + 4];
6279a63ce63SRobert Garrett 	struct passwd *pw;
6289a63ce63SRobert Garrett 	struct group *gr;
6299a63ce63SRobert Garrett 	const struct timespec *tsp;
6309a63ce63SRobert Garrett 	struct timespec ts;
631d542b1f4SSimon Schubert 	struct tm *tm;
6329a63ce63SRobert Garrett 	int l, small, formats;
6339a63ce63SRobert Garrett 
6349a63ce63SRobert Garrett 	tsp = NULL;
6359a63ce63SRobert Garrett 	formats = 0;
6369a63ce63SRobert Garrett 	small = 0;
6379a63ce63SRobert Garrett 
6389a63ce63SRobert Garrett 	/*
6399a63ce63SRobert Garrett 	 * First, pick out the data and tweak it based on hilo or
6409a63ce63SRobert Garrett 	 * specified output format (symlink output only).
6419a63ce63SRobert Garrett 	 */
6429a63ce63SRobert Garrett 	switch (what) {
6439a63ce63SRobert Garrett 	case SHOW_st_dev:
6449a63ce63SRobert Garrett 	case SHOW_st_rdev:
6459a63ce63SRobert Garrett 		small = (sizeof(st->st_dev) == 4);
6469a63ce63SRobert Garrett 		data = (what == SHOW_st_dev) ? st->st_dev : st->st_rdev;
647d542b1f4SSimon Schubert #if HAVE_DEVNAME
6489a63ce63SRobert Garrett 		sdata = (what == SHOW_st_dev) ?
6499a63ce63SRobert Garrett 		    devname(st->st_dev, S_IFBLK) :
6509a63ce63SRobert Garrett 		    devname(st->st_rdev,
6519a63ce63SRobert Garrett 		    S_ISCHR(st->st_mode) ? S_IFCHR :
6529a63ce63SRobert Garrett 		    S_ISBLK(st->st_mode) ? S_IFBLK :
6539a63ce63SRobert Garrett 		    0U);
654*e9445c5dSzrj #else
655*e9445c5dSzrj 		sdata = NULL;
656*e9445c5dSzrj #endif /* HAVE_DEVNAME */
6579a63ce63SRobert Garrett 		if (sdata == NULL)
6589a63ce63SRobert Garrett 			sdata = "???";
6599a63ce63SRobert Garrett 		if (hilo == HIGH_PIECE) {
6609a63ce63SRobert Garrett 			data = major(data);
6619a63ce63SRobert Garrett 			hilo = 0;
6629a63ce63SRobert Garrett 		}
6639a63ce63SRobert Garrett 		else if (hilo == LOW_PIECE) {
6649a63ce63SRobert Garrett 			data = minor((unsigned)data);
6659a63ce63SRobert Garrett 			hilo = 0;
6669a63ce63SRobert Garrett 		}
6679a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
668d542b1f4SSimon Schubert #if HAVE_DEVNAME
6699a63ce63SRobert Garrett 		    FMTF_STRING;
670d542b1f4SSimon Schubert #else /* HAVE_DEVNAME */
671d542b1f4SSimon Schubert 		    0;
672d542b1f4SSimon Schubert #endif /* HAVE_DEVNAME */
6739a63ce63SRobert Garrett 		if (ofmt == 0)
6749a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
6759a63ce63SRobert Garrett 		break;
6769a63ce63SRobert Garrett 	case SHOW_st_ino:
6779a63ce63SRobert Garrett 		small = (sizeof(st->st_ino) == 4);
6789a63ce63SRobert Garrett 		data = st->st_ino;
6799a63ce63SRobert Garrett 		sdata = NULL;
6809a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
6819a63ce63SRobert Garrett 		if (ofmt == 0)
6829a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
6839a63ce63SRobert Garrett 		break;
6849a63ce63SRobert Garrett 	case SHOW_st_mode:
6859a63ce63SRobert Garrett 		small = (sizeof(st->st_mode) == 4);
6869a63ce63SRobert Garrett 		data = st->st_mode;
6879a63ce63SRobert Garrett 		strmode(st->st_mode, smode);
68846659ea9SSascha Wildner 		stmp = smode;
68946659ea9SSascha Wildner 		l = strlen(stmp);
69046659ea9SSascha Wildner 		if (stmp[l - 1] == ' ')
69146659ea9SSascha Wildner 			stmp[--l] = '\0';
6929a63ce63SRobert Garrett 		if (hilo == HIGH_PIECE) {
6939a63ce63SRobert Garrett 			data >>= 12;
69446659ea9SSascha Wildner 			stmp += 1;
69546659ea9SSascha Wildner 			stmp[3] = '\0';
6969a63ce63SRobert Garrett 			hilo = 0;
6979a63ce63SRobert Garrett 		}
6989a63ce63SRobert Garrett 		else if (hilo == MIDDLE_PIECE) {
6999a63ce63SRobert Garrett 			data = (data >> 9) & 07;
70046659ea9SSascha Wildner 			stmp += 4;
70146659ea9SSascha Wildner 			stmp[3] = '\0';
7029a63ce63SRobert Garrett 			hilo = 0;
7039a63ce63SRobert Garrett 		}
7049a63ce63SRobert Garrett 		else if (hilo == LOW_PIECE) {
7059a63ce63SRobert Garrett 			data &= 0777;
70646659ea9SSascha Wildner 			stmp += 7;
70746659ea9SSascha Wildner 			stmp[3] = '\0';
7089a63ce63SRobert Garrett 			hilo = 0;
7099a63ce63SRobert Garrett 		}
71046659ea9SSascha Wildner 		sdata = stmp;
7119a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
7129a63ce63SRobert Garrett 		    FMTF_STRING;
7139a63ce63SRobert Garrett 		if (ofmt == 0)
7149a63ce63SRobert Garrett 			ofmt = FMTF_OCTAL;
7159a63ce63SRobert Garrett 		break;
7169a63ce63SRobert Garrett 	case SHOW_st_nlink:
7179a63ce63SRobert Garrett 		small = (sizeof(st->st_dev) == 4);
7189a63ce63SRobert Garrett 		data = st->st_nlink;
7199a63ce63SRobert Garrett 		sdata = NULL;
7209a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
7219a63ce63SRobert Garrett 		if (ofmt == 0)
7229a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
7239a63ce63SRobert Garrett 		break;
7249a63ce63SRobert Garrett 	case SHOW_st_uid:
7259a63ce63SRobert Garrett 		small = (sizeof(st->st_uid) == 4);
7269a63ce63SRobert Garrett 		data = st->st_uid;
7279a63ce63SRobert Garrett 		if ((pw = getpwuid(st->st_uid)) != NULL)
7289a63ce63SRobert Garrett 			sdata = pw->pw_name;
7299a63ce63SRobert Garrett 		else {
7309a63ce63SRobert Garrett 			snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_uid);
7319a63ce63SRobert Garrett 			sdata = sid;
7329a63ce63SRobert Garrett 		}
7339a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
7349a63ce63SRobert Garrett 		    FMTF_STRING;
7359a63ce63SRobert Garrett 		if (ofmt == 0)
7369a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
7379a63ce63SRobert Garrett 		break;
7389a63ce63SRobert Garrett 	case SHOW_st_gid:
7399a63ce63SRobert Garrett 		small = (sizeof(st->st_gid) == 4);
7409a63ce63SRobert Garrett 		data = st->st_gid;
7419a63ce63SRobert Garrett 		if ((gr = getgrgid(st->st_gid)) != NULL)
7429a63ce63SRobert Garrett 			sdata = gr->gr_name;
7439a63ce63SRobert Garrett 		else {
7449a63ce63SRobert Garrett 			snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_gid);
7459a63ce63SRobert Garrett 			sdata = sid;
7469a63ce63SRobert Garrett 		}
7479a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
7489a63ce63SRobert Garrett 		    FMTF_STRING;
7499a63ce63SRobert Garrett 		if (ofmt == 0)
7509a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
7519a63ce63SRobert Garrett 		break;
7529a63ce63SRobert Garrett 	case SHOW_st_atime:
7539a63ce63SRobert Garrett 		tsp = &st->st_atimespec;
7549a63ce63SRobert Garrett 		/* FALLTHROUGH */
7559a63ce63SRobert Garrett 	case SHOW_st_mtime:
7569a63ce63SRobert Garrett 		if (tsp == NULL)
7579a63ce63SRobert Garrett 			tsp = &st->st_mtimespec;
7589a63ce63SRobert Garrett 		/* FALLTHROUGH */
7599a63ce63SRobert Garrett 	case SHOW_st_ctime:
7609a63ce63SRobert Garrett 		if (tsp == NULL)
7619a63ce63SRobert Garrett 			tsp = &st->st_ctimespec;
7629a63ce63SRobert Garrett 		/* FALLTHROUGH */
763d542b1f4SSimon Schubert #if HAVE_STRUCT_STAT_ST_BIRTHTIME
764d542b1f4SSimon Schubert 	case SHOW_st_btime:
765d542b1f4SSimon Schubert 		if (tsp == NULL)
766d542b1f4SSimon Schubert 			tsp = &st->st_birthtimespec;
767d542b1f4SSimon Schubert #endif /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
768d542b1f4SSimon Schubert 		ts = *tsp;		/* copy so we can muck with it */
769d542b1f4SSimon Schubert 		small = (sizeof(ts.tv_sec) == 4);
770d542b1f4SSimon Schubert 		data = ts.tv_sec;
771d542b1f4SSimon Schubert 		tm = localtime(&ts.tv_sec);
77246659ea9SSascha Wildner 		if (tm == NULL) {
77346659ea9SSascha Wildner 			ts.tv_sec = 0;
77446659ea9SSascha Wildner 			tm = localtime(&ts.tv_sec);
77546659ea9SSascha Wildner 		}
776d542b1f4SSimon Schubert 		strftime(path, sizeof(path), timefmt, tm);
777d542b1f4SSimon Schubert 		sdata = path;
778d542b1f4SSimon Schubert 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
779d542b1f4SSimon Schubert 		    FMTF_FLOAT | FMTF_STRING;
780d542b1f4SSimon Schubert 		if (ofmt == 0)
781d542b1f4SSimon Schubert 			ofmt = FMTF_DECIMAL;
782d542b1f4SSimon Schubert 		break;
7839a63ce63SRobert Garrett 	case SHOW_st_size:
7849a63ce63SRobert Garrett 		small = (sizeof(st->st_size) == 4);
7859a63ce63SRobert Garrett 		data = st->st_size;
7869a63ce63SRobert Garrett 		sdata = NULL;
7879a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
7889a63ce63SRobert Garrett 		if (ofmt == 0)
7899a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
7909a63ce63SRobert Garrett 		break;
7919a63ce63SRobert Garrett 	case SHOW_st_blocks:
7929a63ce63SRobert Garrett 		small = (sizeof(st->st_blocks) == 4);
7939a63ce63SRobert Garrett 		data = st->st_blocks;
7949a63ce63SRobert Garrett 		sdata = NULL;
7959a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
7969a63ce63SRobert Garrett 		if (ofmt == 0)
7979a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
7989a63ce63SRobert Garrett 		break;
7999a63ce63SRobert Garrett 	case SHOW_st_blksize:
8009a63ce63SRobert Garrett 		small = (sizeof(st->st_blksize) == 4);
8019a63ce63SRobert Garrett 		data = st->st_blksize;
8029a63ce63SRobert Garrett 		sdata = NULL;
8039a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
8049a63ce63SRobert Garrett 		if (ofmt == 0)
8059a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
8069a63ce63SRobert Garrett 		break;
807d542b1f4SSimon Schubert #if HAVE_STRUCT_STAT_ST_FLAGS
8089a63ce63SRobert Garrett 	case SHOW_st_flags:
8099a63ce63SRobert Garrett 		small = (sizeof(st->st_flags) == 4);
8109a63ce63SRobert Garrett 		data = st->st_flags;
81146659ea9SSascha Wildner 		sdata = xfflagstostr(st->st_flags);
81246659ea9SSascha Wildner 		if (*sdata == '\0')
81346659ea9SSascha Wildner 			sdata = "-";
81446659ea9SSascha Wildner 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
81546659ea9SSascha Wildner 		    FMTF_STRING;
8169a63ce63SRobert Garrett 		if (ofmt == 0)
8179a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
8189a63ce63SRobert Garrett 		break;
819d542b1f4SSimon Schubert #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
820d542b1f4SSimon Schubert #if HAVE_STRUCT_STAT_ST_GEN
8219a63ce63SRobert Garrett 	case SHOW_st_gen:
8229a63ce63SRobert Garrett 		small = (sizeof(st->st_gen) == 4);
8239a63ce63SRobert Garrett 		data = st->st_gen;
8249a63ce63SRobert Garrett 		sdata = NULL;
8259a63ce63SRobert Garrett 		formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
8269a63ce63SRobert Garrett 		if (ofmt == 0)
8279a63ce63SRobert Garrett 			ofmt = FMTF_UNSIGNED;
8289a63ce63SRobert Garrett 		break;
829d542b1f4SSimon Schubert #endif /* HAVE_STRUCT_STAT_ST_GEN */
83046659ea9SSascha Wildner 	case SHOW_realpath:
83146659ea9SSascha Wildner 		small = 0;
83246659ea9SSascha Wildner 		data = 0;
83346659ea9SSascha Wildner 		if (file == NULL) {
83446659ea9SSascha Wildner 			strlcpy(path, "(stdin)", sizeof(path));
83546659ea9SSascha Wildner 			sdata = path;
83646659ea9SSascha Wildner 		} else {
83746659ea9SSascha Wildner 			snprintf(path, sizeof(path), " -> ");
83846659ea9SSascha Wildner 			if (realpath(file, path + 4) == NULL) {
83946659ea9SSascha Wildner 				linkfail = 1;
84046659ea9SSascha Wildner 				l = 0;
84146659ea9SSascha Wildner 				path[0] = '\0';
84246659ea9SSascha Wildner 			}
84346659ea9SSascha Wildner 			sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
84446659ea9SSascha Wildner 		}
84546659ea9SSascha Wildner 
84646659ea9SSascha Wildner 		formats = FMTF_STRING;
84746659ea9SSascha Wildner 		if (ofmt == 0)
84846659ea9SSascha Wildner 			ofmt = FMTF_STRING;
84946659ea9SSascha Wildner 		break;
8509a63ce63SRobert Garrett 	case SHOW_symlink:
8519a63ce63SRobert Garrett 		small = 0;
8529a63ce63SRobert Garrett 		data = 0;
8539a63ce63SRobert Garrett 		if (S_ISLNK(st->st_mode)) {
8549a63ce63SRobert Garrett 			snprintf(path, sizeof(path), " -> ");
8559a63ce63SRobert Garrett 			l = readlink(file, path + 4, sizeof(path) - 4 - 1);
8569a63ce63SRobert Garrett 			if (l == -1) {
8579a63ce63SRobert Garrett 				linkfail = 1;
8589a63ce63SRobert Garrett 				l = 0;
8599a63ce63SRobert Garrett 				path[0] = '\0';
8609a63ce63SRobert Garrett 			}
8619a63ce63SRobert Garrett 			path[l + 4] = '\0';
8629a63ce63SRobert Garrett 			sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
8639a63ce63SRobert Garrett 		}
8649a63ce63SRobert Garrett 		else {
8659a63ce63SRobert Garrett 			linkfail = 1;
8669a63ce63SRobert Garrett 			sdata = "";
8679a63ce63SRobert Garrett 		}
8689a63ce63SRobert Garrett 		formats = FMTF_STRING;
8699a63ce63SRobert Garrett 		if (ofmt == 0)
8709a63ce63SRobert Garrett 			ofmt = FMTF_STRING;
8719a63ce63SRobert Garrett 		break;
8729a63ce63SRobert Garrett 	case SHOW_filetype:
8739a63ce63SRobert Garrett 		small = 0;
8749a63ce63SRobert Garrett 		data = 0;
87546659ea9SSascha Wildner 		sdata = "";
8769a63ce63SRobert Garrett 		if (hilo == 0 || hilo == LOW_PIECE) {
8779a63ce63SRobert Garrett 			switch (st->st_mode & S_IFMT) {
87846659ea9SSascha Wildner 			case S_IFIFO:	sdata = "|";	break;
87946659ea9SSascha Wildner 			case S_IFDIR:	sdata = "/";	break;
8809a63ce63SRobert Garrett 			case S_IFREG:
8819a63ce63SRobert Garrett 				if (st->st_mode &
8829a63ce63SRobert Garrett 				    (S_IXUSR | S_IXGRP | S_IXOTH))
88346659ea9SSascha Wildner 					sdata = "*";
8849a63ce63SRobert Garrett 				break;
88546659ea9SSascha Wildner 			case S_IFLNK:	sdata = "@";	break;
88646659ea9SSascha Wildner 			case S_IFSOCK:	sdata = "=";	break;
887d542b1f4SSimon Schubert #ifdef S_IFWHT
88846659ea9SSascha Wildner 			case S_IFWHT:	sdata = "%";	break;
889d542b1f4SSimon Schubert #endif /* S_IFWHT */
890d542b1f4SSimon Schubert #ifdef S_IFDOOR
89146659ea9SSascha Wildner 			case S_IFDOOR:	sdata = ">";	break;
892d542b1f4SSimon Schubert #endif /* S_IFDOOR */
8939a63ce63SRobert Garrett 			}
8949a63ce63SRobert Garrett 			hilo = 0;
8959a63ce63SRobert Garrett 		}
8969a63ce63SRobert Garrett 		else if (hilo == HIGH_PIECE) {
8979a63ce63SRobert Garrett 			switch (st->st_mode & S_IFMT) {
8989a63ce63SRobert Garrett 			case S_IFIFO:	sdata = "Fifo File";		break;
8999a63ce63SRobert Garrett 			case S_IFCHR:	sdata = "Character Device";	break;
9009a63ce63SRobert Garrett 			case S_IFDIR:	sdata = "Directory";		break;
9019a63ce63SRobert Garrett 			case S_IFBLK:	sdata = "Block Device";		break;
9029a63ce63SRobert Garrett 			case S_IFREG:	sdata = "Regular File";		break;
9039a63ce63SRobert Garrett 			case S_IFLNK:	sdata = "Symbolic Link";	break;
9049a63ce63SRobert Garrett 			case S_IFSOCK:	sdata = "Socket";		break;
905d542b1f4SSimon Schubert #ifdef S_IFWHT
9069a63ce63SRobert Garrett 			case S_IFWHT:	sdata = "Whiteout File";	break;
907d542b1f4SSimon Schubert #endif /* S_IFWHT */
908d542b1f4SSimon Schubert #ifdef S_IFDOOR
909d542b1f4SSimon Schubert 			case S_IFDOOR:	sdata = "Door";			break;
910d542b1f4SSimon Schubert #endif /* S_IFDOOR */
9119a63ce63SRobert Garrett 			default:	sdata = "???";			break;
9129a63ce63SRobert Garrett 			}
9139a63ce63SRobert Garrett 			hilo = 0;
9149a63ce63SRobert Garrett 		}
9159a63ce63SRobert Garrett 		formats = FMTF_STRING;
9169a63ce63SRobert Garrett 		if (ofmt == 0)
9179a63ce63SRobert Garrett 			ofmt = FMTF_STRING;
9189a63ce63SRobert Garrett 		break;
9199a63ce63SRobert Garrett 	case SHOW_filename:
9209a63ce63SRobert Garrett 		small = 0;
9219a63ce63SRobert Garrett 		data = 0;
92246659ea9SSascha Wildner 		strlcpy(path, file, sizeof(path));
9239a63ce63SRobert Garrett 		sdata = path;
9249a63ce63SRobert Garrett 		formats = FMTF_STRING;
9259a63ce63SRobert Garrett 		if (ofmt == 0)
9269a63ce63SRobert Garrett 			ofmt = FMTF_STRING;
9279a63ce63SRobert Garrett 		break;
9289a63ce63SRobert Garrett 	case SHOW_sizerdev:
9299a63ce63SRobert Garrett 		if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
9309a63ce63SRobert Garrett 			char majdev[20], mindev[20];
9319a63ce63SRobert Garrett 			int l1, l2;
9329a63ce63SRobert Garrett 
9339a63ce63SRobert Garrett 			l1 = format1(st,
9349a63ce63SRobert Garrett 			    file,
9359a63ce63SRobert Garrett 			    fmt, flen,
9369a63ce63SRobert Garrett 			    majdev, sizeof(majdev),
9379a63ce63SRobert Garrett 			    flags, size, prec,
9389a63ce63SRobert Garrett 			    ofmt, HIGH_PIECE, SHOW_st_rdev);
9399a63ce63SRobert Garrett 			l2 = format1(st,
9409a63ce63SRobert Garrett 			    file,
9419a63ce63SRobert Garrett 			    fmt, flen,
9429a63ce63SRobert Garrett 			    mindev, sizeof(mindev),
9439a63ce63SRobert Garrett 			    flags, size, prec,
9449a63ce63SRobert Garrett 			    ofmt, LOW_PIECE, SHOW_st_rdev);
9459a63ce63SRobert Garrett 			return (snprintf(buf, blen, "%.*s,%.*s",
9469a63ce63SRobert Garrett 			    l1, majdev, l2, mindev));
9479a63ce63SRobert Garrett 		}
9489a63ce63SRobert Garrett 		else {
9499a63ce63SRobert Garrett 			return (format1(st,
9509a63ce63SRobert Garrett 			    file,
9519a63ce63SRobert Garrett 			    fmt, flen,
9529a63ce63SRobert Garrett 			    buf, blen,
9539a63ce63SRobert Garrett 			    flags, size, prec,
9549a63ce63SRobert Garrett 			    ofmt, 0, SHOW_st_size));
9559a63ce63SRobert Garrett 		}
9569a63ce63SRobert Garrett 		/*NOTREACHED*/
9579a63ce63SRobert Garrett 	default:
9589a63ce63SRobert Garrett 		errx(1, "%.*s: bad format", (int)flen, fmt);
9599a63ce63SRobert Garrett 	}
9609a63ce63SRobert Garrett 
9619a63ce63SRobert Garrett 	/*
9629a63ce63SRobert Garrett 	 * If a subdatum was specified but not supported, or an output
9639a63ce63SRobert Garrett 	 * format was selected that is not supported, that's an error.
9649a63ce63SRobert Garrett 	 */
9659a63ce63SRobert Garrett 	if (hilo != 0 || (ofmt & formats) == 0)
9669a63ce63SRobert Garrett 		errx(1, "%.*s: bad format", (int)flen, fmt);
9679a63ce63SRobert Garrett 
9689a63ce63SRobert Garrett 	/*
9699a63ce63SRobert Garrett 	 * Assemble the format string for passing to printf(3).
9709a63ce63SRobert Garrett 	 */
9719a63ce63SRobert Garrett 	lfmt[0] = '\0';
97246659ea9SSascha Wildner 	strcat(lfmt, "%");
9739a63ce63SRobert Garrett 	if (flags & FLAG_POUND)
97446659ea9SSascha Wildner 		strcat(lfmt, "#");
9759a63ce63SRobert Garrett 	if (flags & FLAG_SPACE)
97646659ea9SSascha Wildner 		strcat(lfmt, " ");
9779a63ce63SRobert Garrett 	if (flags & FLAG_PLUS)
97846659ea9SSascha Wildner 		strcat(lfmt, "+");
9799a63ce63SRobert Garrett 	if (flags & FLAG_MINUS)
98046659ea9SSascha Wildner 		strcat(lfmt, "-");
9819a63ce63SRobert Garrett 	if (flags & FLAG_ZERO)
98246659ea9SSascha Wildner 		strcat(lfmt, "0");
9839a63ce63SRobert Garrett 
9849a63ce63SRobert Garrett 	/*
9859a63ce63SRobert Garrett 	 * Only the timespecs support the FLOAT output format, and that
9869a63ce63SRobert Garrett 	 * requires work that differs from the other formats.
9879a63ce63SRobert Garrett 	 */
9889a63ce63SRobert Garrett 	if (ofmt == FMTF_FLOAT) {
9899a63ce63SRobert Garrett 		/*
9909a63ce63SRobert Garrett 		 * Nothing after the decimal point, so just print seconds.
9919a63ce63SRobert Garrett 		 */
9929a63ce63SRobert Garrett 		if (prec == 0) {
9939a63ce63SRobert Garrett 			if (size != -1) {
99446659ea9SSascha Wildner 				snprintf(tmp, sizeof(tmp), "%d", size);
99546659ea9SSascha Wildner 				strcat(lfmt, tmp);
9969a63ce63SRobert Garrett 			}
99746659ea9SSascha Wildner 			strcat(lfmt, "lld");
99846659ea9SSascha Wildner 			return (snprintf(buf, blen, lfmt,
99946659ea9SSascha Wildner 			    (long long)ts.tv_sec));
10009a63ce63SRobert Garrett 		}
10019a63ce63SRobert Garrett 
10029a63ce63SRobert Garrett 		/*
10039a63ce63SRobert Garrett 		 * Unspecified precision gets all the precision we have:
10049a63ce63SRobert Garrett 		 * 9 digits.
10059a63ce63SRobert Garrett 		 */
10069a63ce63SRobert Garrett 		if (prec == -1)
10079a63ce63SRobert Garrett 			prec = 9;
10089a63ce63SRobert Garrett 
10099a63ce63SRobert Garrett 		/*
10109a63ce63SRobert Garrett 		 * Adjust the size for the decimal point and the digits
10119a63ce63SRobert Garrett 		 * that will follow.
10129a63ce63SRobert Garrett 		 */
10139a63ce63SRobert Garrett 		size -= prec + 1;
10149a63ce63SRobert Garrett 
10159a63ce63SRobert Garrett 		/*
10169a63ce63SRobert Garrett 		 * Any leftover size that's legitimate will be used.
10179a63ce63SRobert Garrett 		 */
10189a63ce63SRobert Garrett 		if (size > 0) {
101946659ea9SSascha Wildner 			snprintf(tmp, sizeof(tmp), "%d", size);
102046659ea9SSascha Wildner 			strcat(lfmt, tmp);
10219a63ce63SRobert Garrett 		}
102246659ea9SSascha Wildner 		/* Seconds: time_t cast to long long. */
102346659ea9SSascha Wildner 		strcat(lfmt, "lld");
10249a63ce63SRobert Garrett 
10259a63ce63SRobert Garrett 		/*
10269a63ce63SRobert Garrett 		 * The stuff after the decimal point always needs zero
10279a63ce63SRobert Garrett 		 * filling.
10289a63ce63SRobert Garrett 		 */
102946659ea9SSascha Wildner 		strcat(lfmt, ".%0");
10309a63ce63SRobert Garrett 
10319a63ce63SRobert Garrett 		/*
10329a63ce63SRobert Garrett 		 * We can "print" at most nine digits of precision.  The
10339a63ce63SRobert Garrett 		 * rest we will pad on at the end.
103446659ea9SSascha Wildner 		 *
103546659ea9SSascha Wildner 		 * Nanoseconds: long.
10369a63ce63SRobert Garrett 		 */
103746659ea9SSascha Wildner 		snprintf(tmp, sizeof(tmp), "%dld", prec > 9 ? 9 : prec);
103846659ea9SSascha Wildner 		strcat(lfmt, tmp);
10399a63ce63SRobert Garrett 
10409a63ce63SRobert Garrett 		/*
10419a63ce63SRobert Garrett 		 * For precision of less that nine digits, trim off the
10429a63ce63SRobert Garrett 		 * less significant figures.
10439a63ce63SRobert Garrett 		 */
10449a63ce63SRobert Garrett 		for (; prec < 9; prec++)
10459a63ce63SRobert Garrett 			ts.tv_nsec /= 10;
10469a63ce63SRobert Garrett 
10479a63ce63SRobert Garrett 		/*
10489a63ce63SRobert Garrett 		 * Use the format, and then tack on any zeroes that
10499a63ce63SRobert Garrett 		 * might be required to make up the requested precision.
10509a63ce63SRobert Garrett 		 */
105146659ea9SSascha Wildner 		l = snprintf(buf, blen, lfmt, (long long)ts.tv_sec, ts.tv_nsec);
105246659ea9SSascha Wildner 		for (; prec > 9 && l < (int)blen; prec--, l++)
105346659ea9SSascha Wildner 			strcat(buf, "0");
10549a63ce63SRobert Garrett 		return (l);
10559a63ce63SRobert Garrett 	}
10569a63ce63SRobert Garrett 
10579a63ce63SRobert Garrett 	/*
10589a63ce63SRobert Garrett 	 * Add on size and precision, if specified, to the format.
10599a63ce63SRobert Garrett 	 */
10609a63ce63SRobert Garrett 	if (size != -1) {
106146659ea9SSascha Wildner 		snprintf(tmp, sizeof(tmp), "%d", size);
106246659ea9SSascha Wildner 		strcat(lfmt, tmp);
10639a63ce63SRobert Garrett 	}
10649a63ce63SRobert Garrett 	if (prec != -1) {
106546659ea9SSascha Wildner 		snprintf(tmp, sizeof(tmp), ".%d", prec);
106646659ea9SSascha Wildner 		strcat(lfmt, tmp);
10679a63ce63SRobert Garrett 	}
10689a63ce63SRobert Garrett 
10699a63ce63SRobert Garrett 	/*
10709a63ce63SRobert Garrett 	 * String output uses the temporary sdata.
10719a63ce63SRobert Garrett 	 */
10729a63ce63SRobert Garrett 	if (ofmt == FMTF_STRING) {
10739a63ce63SRobert Garrett 		if (sdata == NULL)
10749a63ce63SRobert Garrett 			errx(1, "%.*s: bad format", (int)flen, fmt);
107546659ea9SSascha Wildner 		strcat(lfmt, "s");
10769a63ce63SRobert Garrett 		return (snprintf(buf, blen, lfmt, sdata));
10779a63ce63SRobert Garrett 	}
10789a63ce63SRobert Garrett 
10799a63ce63SRobert Garrett 	/*
10809a63ce63SRobert Garrett 	 * Ensure that sign extension does not cause bad looking output
10819a63ce63SRobert Garrett 	 * for some forms.
10829a63ce63SRobert Garrett 	 */
10839a63ce63SRobert Garrett 	if (small && ofmt != FMTF_DECIMAL)
10849a63ce63SRobert Garrett 		data = (u_int32_t)data;
10859a63ce63SRobert Garrett 
10869a63ce63SRobert Garrett 	/*
10879a63ce63SRobert Garrett 	 * The four "numeric" output forms.
10889a63ce63SRobert Garrett 	 */
108946659ea9SSascha Wildner 	strcat(lfmt, "ll");
10909a63ce63SRobert Garrett 	switch (ofmt) {
109146659ea9SSascha Wildner 	case FMTF_DECIMAL:	strcat(lfmt, "d");	break;
109246659ea9SSascha Wildner 	case FMTF_OCTAL:	strcat(lfmt, "o");	break;
109346659ea9SSascha Wildner 	case FMTF_UNSIGNED:	strcat(lfmt, "u");	break;
109446659ea9SSascha Wildner 	case FMTF_HEX:		strcat(lfmt, "x");	break;
10959a63ce63SRobert Garrett 	}
10969a63ce63SRobert Garrett 
10979a63ce63SRobert Garrett 	return (snprintf(buf, blen, lfmt, data));
10989a63ce63SRobert Garrett }
109946659ea9SSascha Wildner 
1100*e9445c5dSzrj #if HAVE_DEVNAME
110146659ea9SSascha Wildner #define hex2nibble(c) (c <= '9' ? c - '0' : toupper(c) - 'A' + 10)
110233437a44SSascha Wildner static int
hex2byte(const char c[2])110346659ea9SSascha Wildner hex2byte(const char c[2]) {
110446659ea9SSascha Wildner 	if (!(ishexnumber(c[0]) && ishexnumber(c[1])))
110546659ea9SSascha Wildner 		return -1;
110646659ea9SSascha Wildner 	return (hex2nibble(c[0]) << 4) + hex2nibble(c[1]);
110746659ea9SSascha Wildner }
1108*e9445c5dSzrj #endif
1109