stat.c revision 1.35 1 1.35 joerg /* $NetBSD: stat.c,v 1.35 2011/09/06 18:31:22 joerg Exp $ */
2 1.1 atatat
3 1.1 atatat /*
4 1.1 atatat * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 1.1 atatat * All rights reserved.
6 1.1 atatat *
7 1.1 atatat * This code is derived from software contributed to The NetBSD Foundation
8 1.1 atatat * by Andrew Brown.
9 1.1 atatat *
10 1.1 atatat * Redistribution and use in source and binary forms, with or without
11 1.1 atatat * modification, are permitted provided that the following conditions
12 1.1 atatat * are met:
13 1.1 atatat * 1. Redistributions of source code must retain the above copyright
14 1.1 atatat * notice, this list of conditions and the following disclaimer.
15 1.1 atatat * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 atatat * notice, this list of conditions and the following disclaimer in the
17 1.1 atatat * documentation and/or other materials provided with the distribution.
18 1.1 atatat *
19 1.1 atatat * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 atatat * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 atatat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 atatat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 atatat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 atatat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 atatat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 atatat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 atatat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 atatat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 atatat * POSSIBILITY OF SUCH DAMAGE.
30 1.1 atatat */
31 1.1 atatat
32 1.15 lukem #if HAVE_NBTOOL_CONFIG_H
33 1.15 lukem #include "nbtool_config.h"
34 1.15 lukem #endif
35 1.15 lukem
36 1.1 atatat #include <sys/cdefs.h>
37 1.15 lukem #if !defined(lint)
38 1.35 joerg __RCSID("$NetBSD: stat.c,v 1.35 2011/09/06 18:31:22 joerg Exp $");
39 1.11 lukem #endif
40 1.11 lukem
41 1.15 lukem #if ! HAVE_NBTOOL_CONFIG_H
42 1.11 lukem #define HAVE_STRUCT_STAT_ST_FLAGS 1
43 1.13 atatat #define HAVE_STRUCT_STAT_ST_GEN 1
44 1.13 atatat #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
45 1.21 jmc #define HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC 1
46 1.13 atatat #define HAVE_STRUCT_STAT_ST_MTIMENSEC 1
47 1.13 atatat #define HAVE_DEVNAME 1
48 1.15 lukem #endif /* HAVE_NBTOOL_CONFIG_H */
49 1.1 atatat
50 1.10 atatat #include <sys/types.h>
51 1.1 atatat #include <sys/stat.h>
52 1.6 atatat
53 1.6 atatat #include <ctype.h>
54 1.7 atatat #include <err.h>
55 1.18 atatat #include <errno.h>
56 1.6 atatat #include <grp.h>
57 1.8 atatat #include <limits.h>
58 1.6 atatat #include <pwd.h>
59 1.6 atatat #include <stdio.h>
60 1.7 atatat #include <stdlib.h>
61 1.1 atatat #include <string.h>
62 1.6 atatat #include <time.h>
63 1.6 atatat #include <unistd.h>
64 1.1 atatat
65 1.13 atatat #if HAVE_STRUCT_STAT_ST_FLAGS
66 1.13 atatat #define DEF_F "%#Xf "
67 1.13 atatat #define RAW_F "%f "
68 1.13 atatat #define SHELL_F " st_flags=%f"
69 1.13 atatat #else /* HAVE_STRUCT_STAT_ST_FLAGS */
70 1.13 atatat #define DEF_F
71 1.13 atatat #define RAW_F
72 1.13 atatat #define SHELL_F
73 1.13 atatat #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
74 1.13 atatat
75 1.13 atatat #if HAVE_STRUCT_STAT_ST_BIRTHTIME
76 1.13 atatat #define DEF_B "\"%SB\" "
77 1.13 atatat #define RAW_B "%B "
78 1.13 atatat #define SHELL_B "st_birthtime=%B "
79 1.13 atatat #else /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
80 1.13 atatat #define DEF_B
81 1.13 atatat #define RAW_B
82 1.13 atatat #define SHELL_B
83 1.13 atatat #endif /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
84 1.13 atatat
85 1.13 atatat #if HAVE_STRUCT_STAT_ST_ATIM
86 1.13 atatat #define st_atimespec st_atim
87 1.13 atatat #define st_ctimespec st_ctim
88 1.13 atatat #define st_mtimespec st_mtim
89 1.13 atatat #endif /* HAVE_STRUCT_STAT_ST_ATIM */
90 1.13 atatat
91 1.1 atatat #define DEF_FORMAT \
92 1.13 atatat "%d %i %Sp %l %Su %Sg %r %z \"%Sa\" \"%Sm\" \"%Sc\" " DEF_B \
93 1.13 atatat "%k %b " DEF_F "%N"
94 1.13 atatat #define RAW_FORMAT "%d %i %#p %l %u %g %r %z %a %m %c " RAW_B \
95 1.13 atatat "%k %b " RAW_F "%N"
96 1.1 atatat #define LS_FORMAT "%Sp %l %Su %Sg %Z %Sm %N%SY"
97 1.1 atatat #define LSF_FORMAT "%Sp %l %Su %Sg %Z %Sm %N%T%SY"
98 1.1 atatat #define SHELL_FORMAT \
99 1.1 atatat "st_dev=%d st_ino=%i st_mode=%#p st_nlink=%l " \
100 1.1 atatat "st_uid=%u st_gid=%g st_rdev=%r st_size=%z " \
101 1.13 atatat "st_atime=%a st_mtime=%m st_ctime=%c " SHELL_B \
102 1.13 atatat "st_blksize=%k st_blocks=%b" SHELL_F
103 1.1 atatat #define LINUX_FORMAT \
104 1.1 atatat " File: \"%N\"%n" \
105 1.1 atatat " Size: %-11z FileType: %HT%n" \
106 1.1 atatat " Mode: (%04OLp/%.10Sp) Uid: (%5u/%8Su) Gid: (%5g/%8Sg)%n" \
107 1.1 atatat "Device: %Hd,%Ld Inode: %i Links: %l%n" \
108 1.1 atatat "Access: %Sa%n" \
109 1.1 atatat "Modify: %Sm%n" \
110 1.1 atatat "Change: %Sc"
111 1.1 atatat
112 1.1 atatat #define TIME_FORMAT "%b %e %T %Y"
113 1.1 atatat
114 1.2 atatat #define FLAG_POUND 0x01
115 1.2 atatat #define FLAG_SPACE 0x02
116 1.2 atatat #define FLAG_PLUS 0x04
117 1.2 atatat #define FLAG_ZERO 0x08
118 1.2 atatat #define FLAG_MINUS 0x10
119 1.1 atatat
120 1.1 atatat /*
121 1.2 atatat * These format characters must all be unique, except the magic one.
122 1.1 atatat */
123 1.2 atatat #define FMT_MAGIC '%'
124 1.2 atatat #define FMT_DOT '.'
125 1.2 atatat
126 1.1 atatat #define SIMPLE_NEWLINE 'n'
127 1.1 atatat #define SIMPLE_TAB 't'
128 1.1 atatat #define SIMPLE_PERCENT '%'
129 1.2 atatat #define SIMPLE_NUMBER '@'
130 1.2 atatat
131 1.2 atatat #define FMT_POUND '#'
132 1.2 atatat #define FMT_SPACE ' '
133 1.2 atatat #define FMT_PLUS '+'
134 1.2 atatat #define FMT_ZERO '0'
135 1.2 atatat #define FMT_MINUS '-'
136 1.1 atatat
137 1.1 atatat #define FMT_DECIMAL 'D'
138 1.1 atatat #define FMT_OCTAL 'O'
139 1.1 atatat #define FMT_UNSIGNED 'U'
140 1.1 atatat #define FMT_HEX 'X'
141 1.1 atatat #define FMT_FLOAT 'F'
142 1.1 atatat #define FMT_STRING 'S'
143 1.1 atatat
144 1.5 atatat #define FMTF_DECIMAL 0x01
145 1.5 atatat #define FMTF_OCTAL 0x02
146 1.5 atatat #define FMTF_UNSIGNED 0x04
147 1.5 atatat #define FMTF_HEX 0x08
148 1.5 atatat #define FMTF_FLOAT 0x10
149 1.5 atatat #define FMTF_STRING 0x20
150 1.5 atatat
151 1.1 atatat #define HIGH_PIECE 'H'
152 1.1 atatat #define MIDDLE_PIECE 'M'
153 1.1 atatat #define LOW_PIECE 'L'
154 1.1 atatat
155 1.24 elad #define SHOW_realpath 'R'
156 1.1 atatat #define SHOW_st_dev 'd'
157 1.1 atatat #define SHOW_st_ino 'i'
158 1.1 atatat #define SHOW_st_mode 'p'
159 1.1 atatat #define SHOW_st_nlink 'l'
160 1.1 atatat #define SHOW_st_uid 'u'
161 1.1 atatat #define SHOW_st_gid 'g'
162 1.1 atatat #define SHOW_st_rdev 'r'
163 1.1 atatat #define SHOW_st_atime 'a'
164 1.1 atatat #define SHOW_st_mtime 'm'
165 1.1 atatat #define SHOW_st_ctime 'c'
166 1.10 atatat #define SHOW_st_btime 'B'
167 1.1 atatat #define SHOW_st_size 'z'
168 1.1 atatat #define SHOW_st_blocks 'b'
169 1.1 atatat #define SHOW_st_blksize 'k'
170 1.1 atatat #define SHOW_st_flags 'f'
171 1.1 atatat #define SHOW_st_gen 'v'
172 1.1 atatat #define SHOW_symlink 'Y'
173 1.1 atatat #define SHOW_filetype 'T'
174 1.1 atatat #define SHOW_filename 'N'
175 1.1 atatat #define SHOW_sizerdev 'Z'
176 1.1 atatat
177 1.35 joerg static void usage(const char *) __dead;
178 1.35 joerg static void output(const struct stat *, const char *,
179 1.34 christos const char *, int, int, int);
180 1.35 joerg static int format1(const struct stat *, /* stat info */
181 1.1 atatat const char *, /* the file name */
182 1.1 atatat const char *, int, /* the format string itself */
183 1.1 atatat char *, size_t, /* a place to put the output */
184 1.1 atatat int, int, int, int, /* the parsed format */
185 1.34 christos int, int, int);
186 1.1 atatat
187 1.35 joerg static const char *timefmt;
188 1.35 joerg static int linkfail;
189 1.1 atatat
190 1.4 atatat #define addchar(s, c, nl) \
191 1.1 atatat do { \
192 1.4 atatat (void)fputc((c), (s)); \
193 1.4 atatat (*nl) = ((c) == '\n'); \
194 1.1 atatat } while (0/*CONSTCOND*/)
195 1.1 atatat
196 1.1 atatat int
197 1.1 atatat main(int argc, char *argv[])
198 1.1 atatat {
199 1.1 atatat struct stat st;
200 1.4 atatat int ch, rc, errs, am_readlink;
201 1.4 atatat int lsF, fmtchar, usestat, fn, nonl, quiet;
202 1.28 lukem const char *statfmt, *options, *synopsis;
203 1.1 atatat
204 1.4 atatat am_readlink = 0;
205 1.1 atatat lsF = 0;
206 1.1 atatat fmtchar = '\0';
207 1.1 atatat usestat = 0;
208 1.1 atatat nonl = 0;
209 1.4 atatat quiet = 0;
210 1.4 atatat linkfail = 0;
211 1.1 atatat statfmt = NULL;
212 1.1 atatat timefmt = NULL;
213 1.1 atatat
214 1.34 christos setprogname(argv[0]);
215 1.34 christos
216 1.4 atatat if (strcmp(getprogname(), "readlink") == 0) {
217 1.4 atatat am_readlink = 1;
218 1.34 christos options = "fnqsv";
219 1.34 christos synopsis = "[-fnqsv] [file ...]";
220 1.4 atatat statfmt = "%Y";
221 1.4 atatat fmtchar = 'f';
222 1.4 atatat quiet = 1;
223 1.4 atatat } else {
224 1.4 atatat options = "f:FlLnqrst:x";
225 1.4 atatat synopsis = "[-FlLnqrsx] [-f format] [-t timefmt] [file ...]";
226 1.4 atatat }
227 1.4 atatat
228 1.4 atatat while ((ch = getopt(argc, argv, options)) != -1)
229 1.1 atatat switch (ch) {
230 1.1 atatat case 'F':
231 1.1 atatat lsF = 1;
232 1.1 atatat break;
233 1.1 atatat case 'L':
234 1.1 atatat usestat = 1;
235 1.1 atatat break;
236 1.1 atatat case 'n':
237 1.1 atatat nonl = 1;
238 1.1 atatat break;
239 1.4 atatat case 'q':
240 1.4 atatat quiet = 1;
241 1.4 atatat break;
242 1.1 atatat case 'f':
243 1.24 elad if (am_readlink) {
244 1.24 elad statfmt = "%R";
245 1.24 elad break;
246 1.24 elad }
247 1.1 atatat statfmt = optarg;
248 1.1 atatat /* FALLTHROUGH */
249 1.1 atatat case 'l':
250 1.1 atatat case 'r':
251 1.1 atatat case 's':
252 1.34 christos if (am_readlink) {
253 1.34 christos quiet = 1;
254 1.34 christos break;
255 1.34 christos }
256 1.34 christos /*FALLTHROUGH*/
257 1.1 atatat case 'x':
258 1.1 atatat if (fmtchar != 0)
259 1.1 atatat errx(1, "can't use format '%c' with '%c'",
260 1.1 atatat fmtchar, ch);
261 1.1 atatat fmtchar = ch;
262 1.1 atatat break;
263 1.1 atatat case 't':
264 1.1 atatat timefmt = optarg;
265 1.1 atatat break;
266 1.34 christos case 'v':
267 1.34 christos quiet = 0;
268 1.34 christos break;
269 1.1 atatat default:
270 1.4 atatat usage(synopsis);
271 1.1 atatat }
272 1.1 atatat
273 1.1 atatat argc -= optind;
274 1.1 atatat argv += optind;
275 1.2 atatat fn = 1;
276 1.1 atatat
277 1.1 atatat if (fmtchar == '\0') {
278 1.1 atatat if (lsF)
279 1.1 atatat fmtchar = 'l';
280 1.1 atatat else {
281 1.1 atatat fmtchar = 'f';
282 1.1 atatat statfmt = DEF_FORMAT;
283 1.1 atatat }
284 1.1 atatat }
285 1.1 atatat
286 1.1 atatat if (lsF && fmtchar != 'l')
287 1.1 atatat errx(1, "can't use format '%c' with -F", fmtchar);
288 1.1 atatat
289 1.1 atatat switch (fmtchar) {
290 1.1 atatat case 'f':
291 1.1 atatat /* statfmt already set */
292 1.1 atatat break;
293 1.1 atatat case 'l':
294 1.1 atatat statfmt = lsF ? LSF_FORMAT : LS_FORMAT;
295 1.1 atatat break;
296 1.1 atatat case 'r':
297 1.1 atatat statfmt = RAW_FORMAT;
298 1.1 atatat break;
299 1.1 atatat case 's':
300 1.1 atatat statfmt = SHELL_FORMAT;
301 1.1 atatat break;
302 1.1 atatat case 'x':
303 1.1 atatat statfmt = LINUX_FORMAT;
304 1.1 atatat if (timefmt == NULL)
305 1.1 atatat timefmt = "%c";
306 1.1 atatat break;
307 1.1 atatat default:
308 1.4 atatat usage(synopsis);
309 1.1 atatat /*NOTREACHED*/
310 1.1 atatat }
311 1.1 atatat
312 1.1 atatat if (timefmt == NULL)
313 1.1 atatat timefmt = TIME_FORMAT;
314 1.1 atatat
315 1.1 atatat errs = 0;
316 1.1 atatat do {
317 1.1 atatat if (argc == 0)
318 1.1 atatat rc = fstat(STDIN_FILENO, &st);
319 1.18 atatat else if (usestat) {
320 1.18 atatat /*
321 1.18 atatat * Try stat() and if it fails, fall back to
322 1.18 atatat * lstat() just in case we're examining a
323 1.18 atatat * broken symlink.
324 1.18 atatat */
325 1.18 atatat if ((rc = stat(argv[0], &st)) == -1 &&
326 1.18 atatat errno == ENOENT &&
327 1.18 atatat (rc = lstat(argv[0], &st)) == -1)
328 1.18 atatat errno = ENOENT;
329 1.18 atatat }
330 1.1 atatat else
331 1.1 atatat rc = lstat(argv[0], &st);
332 1.1 atatat
333 1.1 atatat if (rc == -1) {
334 1.1 atatat errs = 1;
335 1.4 atatat linkfail = 1;
336 1.4 atatat if (!quiet)
337 1.20 atatat warn("%s: %s",
338 1.20 atatat argc == 0 ? "(stdin)" : argv[0],
339 1.20 atatat usestat ? "stat" : "lstat");
340 1.1 atatat }
341 1.1 atatat else
342 1.34 christos output(&st, argv[0], statfmt, fn, nonl, quiet);
343 1.1 atatat
344 1.1 atatat argv++;
345 1.1 atatat argc--;
346 1.2 atatat fn++;
347 1.1 atatat } while (argc > 0);
348 1.1 atatat
349 1.4 atatat return (am_readlink ? linkfail : errs);
350 1.1 atatat }
351 1.1 atatat
352 1.35 joerg static void
353 1.4 atatat usage(const char *synopsis)
354 1.1 atatat {
355 1.1 atatat
356 1.4 atatat (void)fprintf(stderr, "usage: %s %s\n", getprogname(), synopsis);
357 1.1 atatat exit(1);
358 1.1 atatat }
359 1.1 atatat
360 1.1 atatat /*
361 1.1 atatat * Parses a format string.
362 1.1 atatat */
363 1.35 joerg static void
364 1.1 atatat output(const struct stat *st, const char *file,
365 1.34 christos const char *statfmt, int fn, int nonl, int quiet)
366 1.1 atatat {
367 1.1 atatat int flags, size, prec, ofmt, hilo, what;
368 1.22 atatat char buf[PATH_MAX + 4 + 1];
369 1.1 atatat const char *subfmt;
370 1.1 atatat int nl, t, i;
371 1.1 atatat
372 1.4 atatat nl = 1;
373 1.1 atatat while (*statfmt != '\0') {
374 1.1 atatat
375 1.1 atatat /*
376 1.1 atatat * Non-format characters go straight out.
377 1.1 atatat */
378 1.2 atatat if (*statfmt != FMT_MAGIC) {
379 1.4 atatat addchar(stdout, *statfmt, &nl);
380 1.1 atatat statfmt++;
381 1.1 atatat continue;
382 1.1 atatat }
383 1.1 atatat
384 1.1 atatat /*
385 1.1 atatat * The current format "substring" starts here,
386 1.2 atatat * and then we skip the magic.
387 1.1 atatat */
388 1.1 atatat subfmt = statfmt;
389 1.1 atatat statfmt++;
390 1.1 atatat
391 1.1 atatat /*
392 1.1 atatat * Some simple one-character "formats".
393 1.1 atatat */
394 1.1 atatat switch (*statfmt) {
395 1.1 atatat case SIMPLE_NEWLINE:
396 1.4 atatat addchar(stdout, '\n', &nl);
397 1.1 atatat statfmt++;
398 1.1 atatat continue;
399 1.1 atatat case SIMPLE_TAB:
400 1.4 atatat addchar(stdout, '\t', &nl);
401 1.1 atatat statfmt++;
402 1.1 atatat continue;
403 1.1 atatat case SIMPLE_PERCENT:
404 1.4 atatat addchar(stdout, '%', &nl);
405 1.1 atatat statfmt++;
406 1.1 atatat continue;
407 1.2 atatat case SIMPLE_NUMBER: {
408 1.2 atatat char num[12], *p;
409 1.2 atatat
410 1.2 atatat snprintf(num, sizeof(num), "%d", fn);
411 1.2 atatat for (p = &num[0]; *p; p++)
412 1.4 atatat addchar(stdout, *p, &nl);
413 1.2 atatat statfmt++;
414 1.2 atatat continue;
415 1.2 atatat }
416 1.1 atatat }
417 1.1 atatat
418 1.1 atatat /*
419 1.1 atatat * This must be an actual format string. Format strings are
420 1.1 atatat * similar to printf(3) formats up to a point, and are of
421 1.1 atatat * the form:
422 1.1 atatat *
423 1.1 atatat * % required start of format
424 1.1 atatat * [-# +0] opt. format characters
425 1.1 atatat * size opt. field width
426 1.1 atatat * . opt. decimal separator, followed by
427 1.1 atatat * prec opt. precision
428 1.1 atatat * fmt opt. output specifier (string, numeric, etc.)
429 1.1 atatat * sub opt. sub field specifier (high, middle, low)
430 1.1 atatat * datum required field specifier (size, mode, etc)
431 1.1 atatat *
432 1.1 atatat * Only the % and the datum selector are required. All data
433 1.1 atatat * have reasonable default output forms. The "sub" specifier
434 1.1 atatat * only applies to certain data (mode, dev, rdev, filetype).
435 1.1 atatat * The symlink output defaults to STRING, yet will only emit
436 1.1 atatat * the leading " -> " if STRING is explicitly specified. The
437 1.1 atatat * sizerdev datum will generate rdev output for character or
438 1.1 atatat * block devices, and size output for all others.
439 1.1 atatat */
440 1.1 atatat flags = 0;
441 1.1 atatat do {
442 1.2 atatat if (*statfmt == FMT_POUND)
443 1.2 atatat flags |= FLAG_POUND;
444 1.2 atatat else if (*statfmt == FMT_SPACE)
445 1.2 atatat flags |= FLAG_SPACE;
446 1.2 atatat else if (*statfmt == FMT_PLUS)
447 1.2 atatat flags |= FLAG_PLUS;
448 1.2 atatat else if (*statfmt == FMT_ZERO)
449 1.2 atatat flags |= FLAG_ZERO;
450 1.2 atatat else if (*statfmt == FMT_MINUS)
451 1.2 atatat flags |= FLAG_MINUS;
452 1.1 atatat else
453 1.1 atatat break;
454 1.1 atatat statfmt++;
455 1.1 atatat } while (1/*CONSTCOND*/);
456 1.1 atatat
457 1.1 atatat size = -1;
458 1.1 atatat if (isdigit((unsigned)*statfmt)) {
459 1.1 atatat size = 0;
460 1.1 atatat while (isdigit((unsigned)*statfmt)) {
461 1.1 atatat size = (size * 10) + (*statfmt - '0');
462 1.1 atatat statfmt++;
463 1.1 atatat if (size < 0)
464 1.1 atatat goto badfmt;
465 1.1 atatat }
466 1.1 atatat }
467 1.1 atatat
468 1.1 atatat prec = -1;
469 1.2 atatat if (*statfmt == FMT_DOT) {
470 1.1 atatat statfmt++;
471 1.1 atatat
472 1.1 atatat prec = 0;
473 1.1 atatat while (isdigit((unsigned)*statfmt)) {
474 1.1 atatat prec = (prec * 10) + (*statfmt - '0');
475 1.1 atatat statfmt++;
476 1.1 atatat if (prec < 0)
477 1.1 atatat goto badfmt;
478 1.1 atatat }
479 1.1 atatat }
480 1.1 atatat
481 1.5 atatat #define fmtcase(x, y) case (y): (x) = (y); statfmt++; break
482 1.5 atatat #define fmtcasef(x, y, z) case (y): (x) = (z); statfmt++; break
483 1.1 atatat switch (*statfmt) {
484 1.5 atatat fmtcasef(ofmt, FMT_DECIMAL, FMTF_DECIMAL);
485 1.5 atatat fmtcasef(ofmt, FMT_OCTAL, FMTF_OCTAL);
486 1.5 atatat fmtcasef(ofmt, FMT_UNSIGNED, FMTF_UNSIGNED);
487 1.5 atatat fmtcasef(ofmt, FMT_HEX, FMTF_HEX);
488 1.5 atatat fmtcasef(ofmt, FMT_FLOAT, FMTF_FLOAT);
489 1.5 atatat fmtcasef(ofmt, FMT_STRING, FMTF_STRING);
490 1.1 atatat default:
491 1.1 atatat ofmt = 0;
492 1.1 atatat break;
493 1.1 atatat }
494 1.1 atatat
495 1.1 atatat switch (*statfmt) {
496 1.1 atatat fmtcase(hilo, HIGH_PIECE);
497 1.1 atatat fmtcase(hilo, MIDDLE_PIECE);
498 1.1 atatat fmtcase(hilo, LOW_PIECE);
499 1.1 atatat default:
500 1.1 atatat hilo = 0;
501 1.1 atatat break;
502 1.1 atatat }
503 1.1 atatat
504 1.1 atatat switch (*statfmt) {
505 1.24 elad fmtcase(what, SHOW_realpath);
506 1.1 atatat fmtcase(what, SHOW_st_dev);
507 1.1 atatat fmtcase(what, SHOW_st_ino);
508 1.1 atatat fmtcase(what, SHOW_st_mode);
509 1.1 atatat fmtcase(what, SHOW_st_nlink);
510 1.1 atatat fmtcase(what, SHOW_st_uid);
511 1.1 atatat fmtcase(what, SHOW_st_gid);
512 1.1 atatat fmtcase(what, SHOW_st_rdev);
513 1.1 atatat fmtcase(what, SHOW_st_atime);
514 1.1 atatat fmtcase(what, SHOW_st_mtime);
515 1.1 atatat fmtcase(what, SHOW_st_ctime);
516 1.10 atatat fmtcase(what, SHOW_st_btime);
517 1.1 atatat fmtcase(what, SHOW_st_size);
518 1.1 atatat fmtcase(what, SHOW_st_blocks);
519 1.1 atatat fmtcase(what, SHOW_st_blksize);
520 1.1 atatat fmtcase(what, SHOW_st_flags);
521 1.1 atatat fmtcase(what, SHOW_st_gen);
522 1.1 atatat fmtcase(what, SHOW_symlink);
523 1.1 atatat fmtcase(what, SHOW_filetype);
524 1.1 atatat fmtcase(what, SHOW_filename);
525 1.1 atatat fmtcase(what, SHOW_sizerdev);
526 1.1 atatat default:
527 1.1 atatat goto badfmt;
528 1.1 atatat }
529 1.5 atatat #undef fmtcasef
530 1.1 atatat #undef fmtcase
531 1.1 atatat
532 1.1 atatat t = format1(st,
533 1.1 atatat file,
534 1.1 atatat subfmt, statfmt - subfmt,
535 1.4 atatat buf, sizeof(buf),
536 1.34 christos flags, size, prec, ofmt, hilo, what, quiet);
537 1.1 atatat
538 1.28 lukem for (i = 0; i < t && i < (int)(sizeof(buf) - 1); i++)
539 1.4 atatat addchar(stdout, buf[i], &nl);
540 1.1 atatat
541 1.1 atatat continue;
542 1.1 atatat
543 1.1 atatat badfmt:
544 1.1 atatat errx(1, "%.*s: bad format",
545 1.1 atatat (int)(statfmt - subfmt + 1), subfmt);
546 1.1 atatat }
547 1.1 atatat
548 1.1 atatat if (!nl && !nonl)
549 1.4 atatat (void)fputc('\n', stdout);
550 1.4 atatat (void)fflush(stdout);
551 1.1 atatat }
552 1.1 atatat
553 1.1 atatat /*
554 1.1 atatat * Arranges output according to a single parsed format substring.
555 1.1 atatat */
556 1.35 joerg static int
557 1.1 atatat format1(const struct stat *st,
558 1.1 atatat const char *file,
559 1.1 atatat const char *fmt, int flen,
560 1.1 atatat char *buf, size_t blen,
561 1.1 atatat int flags, int size, int prec, int ofmt,
562 1.34 christos int hilo, int what, int quiet)
563 1.1 atatat {
564 1.1 atatat u_int64_t data;
565 1.28 lukem char *stmp, lfmt[24], tmp[20];
566 1.28 lukem const char *sdata;
567 1.7 atatat char smode[12], sid[12], path[PATH_MAX + 4];
568 1.1 atatat struct passwd *pw;
569 1.1 atatat struct group *gr;
570 1.1 atatat struct tm *tm;
571 1.14 chs time_t secs;
572 1.14 chs long nsecs;
573 1.23 atatat int l, small, formats, gottime, shift;
574 1.1 atatat
575 1.1 atatat formats = 0;
576 1.1 atatat small = 0;
577 1.14 chs gottime = 0;
578 1.14 chs secs = 0;
579 1.14 chs nsecs = 0;
580 1.23 atatat shift = 0;
581 1.1 atatat
582 1.1 atatat /*
583 1.1 atatat * First, pick out the data and tweak it based on hilo or
584 1.1 atatat * specified output format (symlink output only).
585 1.1 atatat */
586 1.1 atatat switch (what) {
587 1.1 atatat case SHOW_st_dev:
588 1.1 atatat case SHOW_st_rdev:
589 1.1 atatat small = (sizeof(st->st_dev) == 4);
590 1.1 atatat data = (what == SHOW_st_dev) ? st->st_dev : st->st_rdev;
591 1.13 atatat #if HAVE_DEVNAME
592 1.1 atatat sdata = (what == SHOW_st_dev) ?
593 1.1 atatat devname(st->st_dev, S_IFBLK) :
594 1.1 atatat devname(st->st_rdev,
595 1.1 atatat S_ISCHR(st->st_mode) ? S_IFCHR :
596 1.1 atatat S_ISBLK(st->st_mode) ? S_IFBLK :
597 1.1 atatat 0U);
598 1.3 atatat if (sdata == NULL)
599 1.3 atatat sdata = "???";
600 1.13 atatat #endif /* HAVE_DEVNAME */
601 1.1 atatat if (hilo == HIGH_PIECE) {
602 1.1 atatat data = major(data);
603 1.1 atatat hilo = 0;
604 1.1 atatat }
605 1.1 atatat else if (hilo == LOW_PIECE) {
606 1.1 atatat data = minor((unsigned)data);
607 1.1 atatat hilo = 0;
608 1.1 atatat }
609 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
610 1.13 atatat #if HAVE_DEVNAME
611 1.5 atatat FMTF_STRING;
612 1.13 atatat #else /* HAVE_DEVNAME */
613 1.13 atatat 0;
614 1.13 atatat #endif /* HAVE_DEVNAME */
615 1.1 atatat if (ofmt == 0)
616 1.5 atatat ofmt = FMTF_UNSIGNED;
617 1.1 atatat break;
618 1.1 atatat case SHOW_st_ino:
619 1.1 atatat small = (sizeof(st->st_ino) == 4);
620 1.1 atatat data = st->st_ino;
621 1.1 atatat sdata = NULL;
622 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
623 1.1 atatat if (ofmt == 0)
624 1.5 atatat ofmt = FMTF_UNSIGNED;
625 1.1 atatat break;
626 1.1 atatat case SHOW_st_mode:
627 1.1 atatat small = (sizeof(st->st_mode) == 4);
628 1.1 atatat data = st->st_mode;
629 1.1 atatat strmode(st->st_mode, smode);
630 1.28 lukem stmp = smode;
631 1.28 lukem l = strlen(stmp);
632 1.28 lukem if (stmp[l - 1] == ' ')
633 1.28 lukem stmp[--l] = '\0';
634 1.1 atatat if (hilo == HIGH_PIECE) {
635 1.1 atatat data >>= 12;
636 1.28 lukem stmp += 1;
637 1.28 lukem stmp[3] = '\0';
638 1.1 atatat hilo = 0;
639 1.1 atatat }
640 1.1 atatat else if (hilo == MIDDLE_PIECE) {
641 1.2 atatat data = (data >> 9) & 07;
642 1.28 lukem stmp += 4;
643 1.28 lukem stmp[3] = '\0';
644 1.1 atatat hilo = 0;
645 1.1 atatat }
646 1.1 atatat else if (hilo == LOW_PIECE) {
647 1.2 atatat data &= 0777;
648 1.28 lukem stmp += 7;
649 1.28 lukem stmp[3] = '\0';
650 1.1 atatat hilo = 0;
651 1.1 atatat }
652 1.28 lukem sdata = stmp;
653 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
654 1.5 atatat FMTF_STRING;
655 1.1 atatat if (ofmt == 0)
656 1.5 atatat ofmt = FMTF_OCTAL;
657 1.1 atatat break;
658 1.1 atatat case SHOW_st_nlink:
659 1.1 atatat small = (sizeof(st->st_dev) == 4);
660 1.1 atatat data = st->st_nlink;
661 1.1 atatat sdata = NULL;
662 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
663 1.1 atatat if (ofmt == 0)
664 1.5 atatat ofmt = FMTF_UNSIGNED;
665 1.1 atatat break;
666 1.1 atatat case SHOW_st_uid:
667 1.1 atatat small = (sizeof(st->st_uid) == 4);
668 1.1 atatat data = st->st_uid;
669 1.1 atatat if ((pw = getpwuid(st->st_uid)) != NULL)
670 1.1 atatat sdata = pw->pw_name;
671 1.1 atatat else {
672 1.1 atatat snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_uid);
673 1.1 atatat sdata = sid;
674 1.1 atatat }
675 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
676 1.5 atatat FMTF_STRING;
677 1.1 atatat if (ofmt == 0)
678 1.5 atatat ofmt = FMTF_UNSIGNED;
679 1.1 atatat break;
680 1.1 atatat case SHOW_st_gid:
681 1.1 atatat small = (sizeof(st->st_gid) == 4);
682 1.1 atatat data = st->st_gid;
683 1.1 atatat if ((gr = getgrgid(st->st_gid)) != NULL)
684 1.1 atatat sdata = gr->gr_name;
685 1.1 atatat else {
686 1.1 atatat snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_gid);
687 1.1 atatat sdata = sid;
688 1.1 atatat }
689 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
690 1.5 atatat FMTF_STRING;
691 1.1 atatat if (ofmt == 0)
692 1.5 atatat ofmt = FMTF_UNSIGNED;
693 1.1 atatat break;
694 1.1 atatat case SHOW_st_atime:
695 1.14 chs gottime = 1;
696 1.14 chs secs = st->st_atime;
697 1.16 lukem #if HAVE_STRUCT_STAT_ST_MTIMENSEC
698 1.14 chs nsecs = st->st_atimensec;
699 1.14 chs #endif
700 1.1 atatat /* FALLTHROUGH */
701 1.1 atatat case SHOW_st_mtime:
702 1.14 chs if (!gottime) {
703 1.17 atatat gottime = 1;
704 1.14 chs secs = st->st_mtime;
705 1.16 lukem #if HAVE_STRUCT_STAT_ST_MTIMENSEC
706 1.14 chs nsecs = st->st_mtimensec;
707 1.14 chs #endif
708 1.14 chs }
709 1.1 atatat /* FALLTHROUGH */
710 1.1 atatat case SHOW_st_ctime:
711 1.14 chs if (!gottime) {
712 1.17 atatat gottime = 1;
713 1.14 chs secs = st->st_ctime;
714 1.16 lukem #if HAVE_STRUCT_STAT_ST_MTIMENSEC
715 1.14 chs nsecs = st->st_ctimensec;
716 1.14 chs #endif
717 1.14 chs }
718 1.10 atatat /* FALLTHROUGH */
719 1.13 atatat #if HAVE_STRUCT_STAT_ST_BIRTHTIME
720 1.10 atatat case SHOW_st_btime:
721 1.14 chs if (!gottime) {
722 1.17 atatat gottime = 1;
723 1.19 jmc secs = st->st_birthtime;
724 1.21 jmc #if HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
725 1.19 jmc nsecs = st->st_birthtimensec;
726 1.21 jmc #endif /* HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC */
727 1.14 chs }
728 1.13 atatat #endif /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
729 1.14 chs small = (sizeof(secs) == 4);
730 1.14 chs data = secs;
731 1.14 chs tm = localtime(&secs);
732 1.33 njoly if (tm == NULL) {
733 1.33 njoly secs = 0;
734 1.33 njoly tm = localtime(&secs);
735 1.33 njoly }
736 1.1 atatat (void)strftime(path, sizeof(path), timefmt, tm);
737 1.1 atatat sdata = path;
738 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
739 1.5 atatat FMTF_FLOAT | FMTF_STRING;
740 1.1 atatat if (ofmt == 0)
741 1.5 atatat ofmt = FMTF_DECIMAL;
742 1.1 atatat break;
743 1.1 atatat case SHOW_st_size:
744 1.1 atatat small = (sizeof(st->st_size) == 4);
745 1.1 atatat data = st->st_size;
746 1.1 atatat sdata = NULL;
747 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
748 1.1 atatat if (ofmt == 0)
749 1.5 atatat ofmt = FMTF_UNSIGNED;
750 1.23 atatat switch (hilo) {
751 1.23 atatat case HIGH_PIECE:
752 1.23 atatat shift = 30; /* gigabytes */
753 1.23 atatat hilo = 0;
754 1.23 atatat break;
755 1.23 atatat case MIDDLE_PIECE:
756 1.23 atatat shift = 20; /* megabytes */
757 1.23 atatat hilo = 0;
758 1.23 atatat break;
759 1.23 atatat case LOW_PIECE:
760 1.23 atatat shift = 10; /* kilobytes */
761 1.23 atatat hilo = 0;
762 1.23 atatat break;
763 1.23 atatat }
764 1.1 atatat break;
765 1.1 atatat case SHOW_st_blocks:
766 1.1 atatat small = (sizeof(st->st_blocks) == 4);
767 1.1 atatat data = st->st_blocks;
768 1.1 atatat sdata = NULL;
769 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
770 1.1 atatat if (ofmt == 0)
771 1.5 atatat ofmt = FMTF_UNSIGNED;
772 1.1 atatat break;
773 1.1 atatat case SHOW_st_blksize:
774 1.1 atatat small = (sizeof(st->st_blksize) == 4);
775 1.1 atatat data = st->st_blksize;
776 1.1 atatat sdata = NULL;
777 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
778 1.1 atatat if (ofmt == 0)
779 1.5 atatat ofmt = FMTF_UNSIGNED;
780 1.1 atatat break;
781 1.11 lukem #if HAVE_STRUCT_STAT_ST_FLAGS
782 1.1 atatat case SHOW_st_flags:
783 1.1 atatat small = (sizeof(st->st_flags) == 4);
784 1.1 atatat data = st->st_flags;
785 1.1 atatat sdata = NULL;
786 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
787 1.1 atatat if (ofmt == 0)
788 1.5 atatat ofmt = FMTF_UNSIGNED;
789 1.1 atatat break;
790 1.13 atatat #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
791 1.13 atatat #if HAVE_STRUCT_STAT_ST_GEN
792 1.1 atatat case SHOW_st_gen:
793 1.1 atatat small = (sizeof(st->st_gen) == 4);
794 1.1 atatat data = st->st_gen;
795 1.1 atatat sdata = NULL;
796 1.5 atatat formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
797 1.1 atatat if (ofmt == 0)
798 1.5 atatat ofmt = FMTF_UNSIGNED;
799 1.1 atatat break;
800 1.13 atatat #endif /* HAVE_STRUCT_STAT_ST_GEN */
801 1.24 elad case SHOW_realpath:
802 1.24 elad small = 0;
803 1.24 elad data = 0;
804 1.25 mlelstv if (file == NULL) {
805 1.31 dholland (void)strlcpy(path, "(stdin)", sizeof(path));
806 1.25 mlelstv sdata = path;
807 1.25 mlelstv } else {
808 1.25 mlelstv snprintf(path, sizeof(path), " -> ");
809 1.25 mlelstv if (realpath(file, path + 4) == NULL) {
810 1.34 christos if (!quiet)
811 1.34 christos warn("realpath `%s'", file);
812 1.25 mlelstv linkfail = 1;
813 1.25 mlelstv l = 0;
814 1.25 mlelstv path[0] = '\0';
815 1.25 mlelstv }
816 1.27 atatat sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
817 1.24 elad }
818 1.24 elad
819 1.24 elad formats = FMTF_STRING;
820 1.24 elad if (ofmt == 0)
821 1.24 elad ofmt = FMTF_STRING;
822 1.24 elad break;
823 1.1 atatat case SHOW_symlink:
824 1.1 atatat small = 0;
825 1.1 atatat data = 0;
826 1.1 atatat if (S_ISLNK(st->st_mode)) {
827 1.1 atatat snprintf(path, sizeof(path), " -> ");
828 1.9 provos l = readlink(file, path + 4, sizeof(path) - 4 - 1);
829 1.1 atatat if (l == -1) {
830 1.34 christos if (!quiet)
831 1.34 christos warn("readlink `%s'", file);
832 1.4 atatat linkfail = 1;
833 1.1 atatat l = 0;
834 1.1 atatat path[0] = '\0';
835 1.1 atatat }
836 1.1 atatat path[l + 4] = '\0';
837 1.5 atatat sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
838 1.1 atatat }
839 1.4 atatat else {
840 1.4 atatat linkfail = 1;
841 1.1 atatat sdata = "";
842 1.4 atatat }
843 1.5 atatat formats = FMTF_STRING;
844 1.1 atatat if (ofmt == 0)
845 1.5 atatat ofmt = FMTF_STRING;
846 1.1 atatat break;
847 1.1 atatat case SHOW_filetype:
848 1.1 atatat small = 0;
849 1.1 atatat data = 0;
850 1.28 lukem sdata = "";
851 1.1 atatat if (hilo == 0 || hilo == LOW_PIECE) {
852 1.1 atatat switch (st->st_mode & S_IFMT) {
853 1.28 lukem case S_IFIFO: sdata = "|"; break;
854 1.28 lukem case S_IFDIR: sdata = "/"; break;
855 1.1 atatat case S_IFREG:
856 1.1 atatat if (st->st_mode &
857 1.1 atatat (S_IXUSR | S_IXGRP | S_IXOTH))
858 1.28 lukem sdata = "*";
859 1.1 atatat break;
860 1.28 lukem case S_IFLNK: sdata = "@"; break;
861 1.19 jmc #ifdef S_IFSOCK
862 1.28 lukem case S_IFSOCK: sdata = "="; break;
863 1.19 jmc #endif
864 1.13 atatat #ifdef S_IFWHT
865 1.28 lukem case S_IFWHT: sdata = "%"; break;
866 1.13 atatat #endif /* S_IFWHT */
867 1.13 atatat #ifdef S_IFDOOR
868 1.28 lukem case S_IFDOOR: sdata = ">"; break;
869 1.13 atatat #endif /* S_IFDOOR */
870 1.1 atatat }
871 1.1 atatat hilo = 0;
872 1.1 atatat }
873 1.1 atatat else if (hilo == HIGH_PIECE) {
874 1.1 atatat switch (st->st_mode & S_IFMT) {
875 1.1 atatat case S_IFIFO: sdata = "Fifo File"; break;
876 1.1 atatat case S_IFCHR: sdata = "Character Device"; break;
877 1.1 atatat case S_IFDIR: sdata = "Directory"; break;
878 1.1 atatat case S_IFBLK: sdata = "Block Device"; break;
879 1.1 atatat case S_IFREG: sdata = "Regular File"; break;
880 1.1 atatat case S_IFLNK: sdata = "Symbolic Link"; break;
881 1.19 jmc #ifdef S_IFSOCK
882 1.1 atatat case S_IFSOCK: sdata = "Socket"; break;
883 1.19 jmc #endif
884 1.13 atatat #ifdef S_IFWHT
885 1.1 atatat case S_IFWHT: sdata = "Whiteout File"; break;
886 1.13 atatat #endif /* S_IFWHT */
887 1.13 atatat #ifdef S_IFDOOR
888 1.13 atatat case S_IFDOOR: sdata = "Door"; break;
889 1.13 atatat #endif /* S_IFDOOR */
890 1.1 atatat default: sdata = "???"; break;
891 1.1 atatat }
892 1.1 atatat hilo = 0;
893 1.1 atatat }
894 1.5 atatat formats = FMTF_STRING;
895 1.1 atatat if (ofmt == 0)
896 1.5 atatat ofmt = FMTF_STRING;
897 1.1 atatat break;
898 1.1 atatat case SHOW_filename:
899 1.1 atatat small = 0;
900 1.1 atatat data = 0;
901 1.20 atatat if (file == NULL) {
902 1.31 dholland (void)strlcpy(path, "(stdin)", sizeof(path));
903 1.20 atatat if (hilo == HIGH_PIECE || hilo == LOW_PIECE)
904 1.20 atatat hilo = 0;
905 1.20 atatat }
906 1.20 atatat else if (hilo == 0)
907 1.31 dholland (void)strlcpy(path, file, sizeof(path));
908 1.20 atatat else {
909 1.20 atatat char *s;
910 1.31 dholland (void)strlcpy(path, file, sizeof(path));
911 1.20 atatat s = strrchr(path, '/');
912 1.20 atatat if (s != NULL) {
913 1.20 atatat /* trim off trailing /'s */
914 1.20 atatat while (s != path &&
915 1.20 atatat s[0] == '/' && s[1] == '\0')
916 1.20 atatat *s-- = '\0';
917 1.20 atatat s = strrchr(path, '/');
918 1.20 atatat }
919 1.20 atatat if (hilo == HIGH_PIECE) {
920 1.20 atatat if (s == NULL)
921 1.31 dholland (void)strlcpy(path, ".", sizeof(path));
922 1.20 atatat else {
923 1.20 atatat while (s != path && s[0] == '/')
924 1.20 atatat *s-- = '\0';
925 1.20 atatat }
926 1.20 atatat hilo = 0;
927 1.20 atatat }
928 1.20 atatat else if (hilo == LOW_PIECE) {
929 1.20 atatat if (s != NULL && s[1] != '\0')
930 1.31 dholland (void)strlcpy(path, s + 1,
931 1.20 atatat sizeof(path));
932 1.20 atatat hilo = 0;
933 1.20 atatat }
934 1.20 atatat }
935 1.1 atatat sdata = path;
936 1.5 atatat formats = FMTF_STRING;
937 1.1 atatat if (ofmt == 0)
938 1.5 atatat ofmt = FMTF_STRING;
939 1.1 atatat break;
940 1.1 atatat case SHOW_sizerdev:
941 1.1 atatat if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
942 1.1 atatat char majdev[20], mindev[20];
943 1.1 atatat int l1, l2;
944 1.1 atatat
945 1.1 atatat l1 = format1(st,
946 1.1 atatat file,
947 1.1 atatat fmt, flen,
948 1.1 atatat majdev, sizeof(majdev),
949 1.1 atatat flags, size, prec,
950 1.34 christos ofmt, HIGH_PIECE, SHOW_st_rdev, quiet);
951 1.1 atatat l2 = format1(st,
952 1.1 atatat file,
953 1.1 atatat fmt, flen,
954 1.1 atatat mindev, sizeof(mindev),
955 1.1 atatat flags, size, prec,
956 1.34 christos ofmt, LOW_PIECE, SHOW_st_rdev, quiet);
957 1.1 atatat return (snprintf(buf, blen, "%.*s,%.*s",
958 1.1 atatat l1, majdev, l2, mindev));
959 1.1 atatat }
960 1.1 atatat else {
961 1.1 atatat return (format1(st,
962 1.1 atatat file,
963 1.1 atatat fmt, flen,
964 1.1 atatat buf, blen,
965 1.1 atatat flags, size, prec,
966 1.34 christos ofmt, 0, SHOW_st_size, quiet));
967 1.1 atatat }
968 1.1 atatat /*NOTREACHED*/
969 1.1 atatat default:
970 1.1 atatat errx(1, "%.*s: bad format", (int)flen, fmt);
971 1.1 atatat }
972 1.1 atatat
973 1.1 atatat /*
974 1.1 atatat * If a subdatum was specified but not supported, or an output
975 1.1 atatat * format was selected that is not supported, that's an error.
976 1.1 atatat */
977 1.1 atatat if (hilo != 0 || (ofmt & formats) == 0)
978 1.1 atatat errx(1, "%.*s: bad format", (int)flen, fmt);
979 1.1 atatat
980 1.1 atatat /*
981 1.1 atatat * Assemble the format string for passing to printf(3).
982 1.1 atatat */
983 1.1 atatat lfmt[0] = '\0';
984 1.1 atatat (void)strcat(lfmt, "%");
985 1.2 atatat if (flags & FLAG_POUND)
986 1.1 atatat (void)strcat(lfmt, "#");
987 1.2 atatat if (flags & FLAG_SPACE)
988 1.1 atatat (void)strcat(lfmt, " ");
989 1.2 atatat if (flags & FLAG_PLUS)
990 1.1 atatat (void)strcat(lfmt, "+");
991 1.2 atatat if (flags & FLAG_MINUS)
992 1.1 atatat (void)strcat(lfmt, "-");
993 1.2 atatat if (flags & FLAG_ZERO)
994 1.1 atatat (void)strcat(lfmt, "0");
995 1.1 atatat
996 1.1 atatat /*
997 1.1 atatat * Only the timespecs support the FLOAT output format, and that
998 1.1 atatat * requires work that differs from the other formats.
999 1.1 atatat */
1000 1.5 atatat if (ofmt == FMTF_FLOAT) {
1001 1.1 atatat /*
1002 1.1 atatat * Nothing after the decimal point, so just print seconds.
1003 1.1 atatat */
1004 1.1 atatat if (prec == 0) {
1005 1.1 atatat if (size != -1) {
1006 1.1 atatat (void)snprintf(tmp, sizeof(tmp), "%d", size);
1007 1.1 atatat (void)strcat(lfmt, tmp);
1008 1.1 atatat }
1009 1.29 dholland (void)strcat(lfmt, "lld");
1010 1.29 dholland return (snprintf(buf, blen, lfmt,
1011 1.29 dholland (long long)secs));
1012 1.1 atatat }
1013 1.1 atatat
1014 1.1 atatat /*
1015 1.1 atatat * Unspecified precision gets all the precision we have:
1016 1.1 atatat * 9 digits.
1017 1.1 atatat */
1018 1.1 atatat if (prec == -1)
1019 1.1 atatat prec = 9;
1020 1.1 atatat
1021 1.1 atatat /*
1022 1.1 atatat * Adjust the size for the decimal point and the digits
1023 1.1 atatat * that will follow.
1024 1.1 atatat */
1025 1.1 atatat size -= prec + 1;
1026 1.1 atatat
1027 1.1 atatat /*
1028 1.1 atatat * Any leftover size that's legitimate will be used.
1029 1.1 atatat */
1030 1.1 atatat if (size > 0) {
1031 1.1 atatat (void)snprintf(tmp, sizeof(tmp), "%d", size);
1032 1.1 atatat (void)strcat(lfmt, tmp);
1033 1.1 atatat }
1034 1.30 dholland /* Seconds: time_t cast to long long. */
1035 1.29 dholland (void)strcat(lfmt, "lld");
1036 1.1 atatat
1037 1.1 atatat /*
1038 1.1 atatat * The stuff after the decimal point always needs zero
1039 1.1 atatat * filling.
1040 1.1 atatat */
1041 1.1 atatat (void)strcat(lfmt, ".%0");
1042 1.1 atatat
1043 1.1 atatat /*
1044 1.1 atatat * We can "print" at most nine digits of precision. The
1045 1.1 atatat * rest we will pad on at the end.
1046 1.30 dholland *
1047 1.30 dholland * Nanoseconds: long.
1048 1.1 atatat */
1049 1.29 dholland (void)snprintf(tmp, sizeof(tmp), "%dld", prec > 9 ? 9 : prec);
1050 1.1 atatat (void)strcat(lfmt, tmp);
1051 1.1 atatat
1052 1.1 atatat /*
1053 1.1 atatat * For precision of less that nine digits, trim off the
1054 1.1 atatat * less significant figures.
1055 1.1 atatat */
1056 1.1 atatat for (; prec < 9; prec++)
1057 1.14 chs nsecs /= 10;
1058 1.1 atatat
1059 1.1 atatat /*
1060 1.1 atatat * Use the format, and then tack on any zeroes that
1061 1.1 atatat * might be required to make up the requested precision.
1062 1.1 atatat */
1063 1.29 dholland l = snprintf(buf, blen, lfmt, (long long)secs, nsecs);
1064 1.28 lukem for (; prec > 9 && l < (int)blen; prec--, l++)
1065 1.1 atatat (void)strcat(buf, "0");
1066 1.1 atatat return (l);
1067 1.1 atatat }
1068 1.1 atatat
1069 1.1 atatat /*
1070 1.1 atatat * Add on size and precision, if specified, to the format.
1071 1.1 atatat */
1072 1.1 atatat if (size != -1) {
1073 1.1 atatat (void)snprintf(tmp, sizeof(tmp), "%d", size);
1074 1.1 atatat (void)strcat(lfmt, tmp);
1075 1.1 atatat }
1076 1.1 atatat if (prec != -1) {
1077 1.1 atatat (void)snprintf(tmp, sizeof(tmp), ".%d", prec);
1078 1.1 atatat (void)strcat(lfmt, tmp);
1079 1.1 atatat }
1080 1.1 atatat
1081 1.1 atatat /*
1082 1.1 atatat * String output uses the temporary sdata.
1083 1.1 atatat */
1084 1.5 atatat if (ofmt == FMTF_STRING) {
1085 1.1 atatat if (sdata == NULL)
1086 1.1 atatat errx(1, "%.*s: bad format", (int)flen, fmt);
1087 1.1 atatat (void)strcat(lfmt, "s");
1088 1.1 atatat return (snprintf(buf, blen, lfmt, sdata));
1089 1.1 atatat }
1090 1.1 atatat
1091 1.1 atatat /*
1092 1.1 atatat * Ensure that sign extension does not cause bad looking output
1093 1.1 atatat * for some forms.
1094 1.1 atatat */
1095 1.5 atatat if (small && ofmt != FMTF_DECIMAL)
1096 1.1 atatat data = (u_int32_t)data;
1097 1.1 atatat
1098 1.1 atatat /*
1099 1.1 atatat * The four "numeric" output forms.
1100 1.1 atatat */
1101 1.1 atatat (void)strcat(lfmt, "ll");
1102 1.1 atatat switch (ofmt) {
1103 1.5 atatat case FMTF_DECIMAL: (void)strcat(lfmt, "d"); break;
1104 1.23 atatat case FMTF_OCTAL: (void)strcat(lfmt, "o"); break;
1105 1.5 atatat case FMTF_UNSIGNED: (void)strcat(lfmt, "u"); break;
1106 1.5 atatat case FMTF_HEX: (void)strcat(lfmt, "x"); break;
1107 1.1 atatat }
1108 1.1 atatat
1109 1.23 atatat /*
1110 1.23 atatat * shift and round to nearest for kilobytes, megabytes,
1111 1.23 atatat * gigabytes.
1112 1.23 atatat */
1113 1.23 atatat if (shift > 0) {
1114 1.23 atatat data >>= (shift - 1);
1115 1.23 atatat data++;
1116 1.23 atatat data >>= 1;
1117 1.23 atatat }
1118 1.23 atatat
1119 1.1 atatat return (snprintf(buf, blen, lfmt, data));
1120 1.1 atatat }
1121