File: | src/usr.bin/stat/stat.c |
Warning: | line 636, column 3 Value stored to 'small' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: stat.c,v 1.23 2018/09/18 15:14:06 tb Exp $ */ |
2 | /* $NetBSD: stat.c,v 1.19 2004/06/20 22:20:16 jmc Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 2002 The NetBSD Foundation, Inc. |
6 | * All rights reserved. |
7 | * |
8 | * This code is derived from software contributed to The NetBSD Foundation |
9 | * by Andrew Brown. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | #include <sys/types.h> |
34 | #include <sys/stat.h> |
35 | |
36 | #include <ctype.h> |
37 | #include <err.h> |
38 | #include <errno(*__errno()).h> |
39 | #include <grp.h> |
40 | #include <limits.h> |
41 | #include <pwd.h> |
42 | #include <stdio.h> |
43 | #include <stdlib.h> |
44 | #include <string.h> |
45 | #include <time.h> |
46 | #include <unistd.h> |
47 | |
48 | #define DEF_FORMAT"%d %i %Sp %l %Su %Sg %r %z \"%Sa\" \"%Sm\" \"%Sc\" " "%k %b %#Xf %N" \ |
49 | "%d %i %Sp %l %Su %Sg %r %z \"%Sa\" \"%Sm\" \"%Sc\" " \ |
50 | "%k %b %#Xf %N" |
51 | #define RAW_FORMAT"%d %i %#p %l %u %g %r %z %a %m %c " "%k %b %f %N" "%d %i %#p %l %u %g %r %z %a %m %c " \ |
52 | "%k %b %f %N" |
53 | #define LS_FORMAT"%Sp %l %Su %Sg %Z %Sm %N%SY" "%Sp %l %Su %Sg %Z %Sm %N%SY" |
54 | #define LSF_FORMAT"%Sp %l %Su %Sg %Z %Sm %N%T%SY" "%Sp %l %Su %Sg %Z %Sm %N%T%SY" |
55 | #define SHELL_FORMAT"st_dev=%d st_ino=%i st_mode=%#p st_nlink=%l " "st_uid=%u st_gid=%g st_rdev=%r st_size=%z " "st_atime=%a st_mtime=%m st_ctime=%c " "st_blksize=%k st_blocks=%b st_flags=%f" \ |
56 | "st_dev=%d st_ino=%i st_mode=%#p st_nlink=%l " \ |
57 | "st_uid=%u st_gid=%g st_rdev=%r st_size=%z " \ |
58 | "st_atime=%a st_mtime=%m st_ctime=%c " \ |
59 | "st_blksize=%k st_blocks=%b st_flags=%f" |
60 | #define LINUX_FORMAT" File: \"%N\"%n" " Size: %-11z FileType: %HT%n" " Mode: (%01Mp%03OLp/%.10Sp) Uid: (%5u/%8Su) Gid: (%5g/%8Sg)%n" "Device: %Hd,%Ld Inode: %i Links: %l%n" "Access: %Sa%n" "Modify: %Sm%n" "Change: %Sc" \ |
61 | " File: \"%N\"%n" \ |
62 | " Size: %-11z FileType: %HT%n" \ |
63 | " Mode: (%01Mp%03OLp/%.10Sp) Uid: (%5u/%8Su) Gid: (%5g/%8Sg)%n" \ |
64 | "Device: %Hd,%Ld Inode: %i Links: %l%n" \ |
65 | "Access: %Sa%n" \ |
66 | "Modify: %Sm%n" \ |
67 | "Change: %Sc" |
68 | |
69 | #define TIME_FORMAT"%b %e %T %Y" "%b %e %T %Y" |
70 | |
71 | #define FLAG_POUND0x01 0x01 |
72 | #define FLAG_SPACE0x02 0x02 |
73 | #define FLAG_PLUS0x04 0x04 |
74 | #define FLAG_ZERO0x08 0x08 |
75 | #define FLAG_MINUS0x10 0x10 |
76 | |
77 | /* |
78 | * These format characters must all be unique, except the magic one. |
79 | */ |
80 | #define FMT_MAGIC'%' '%' |
81 | #define FMT_DOT'.' '.' |
82 | |
83 | #define SIMPLE_NEWLINE'n' 'n' |
84 | #define SIMPLE_TAB't' 't' |
85 | #define SIMPLE_PERCENT'%' '%' |
86 | #define SIMPLE_NUMBER'@' '@' |
87 | |
88 | #define FMT_POUND'#' '#' |
89 | #define FMT_SPACE' ' ' ' |
90 | #define FMT_PLUS'+' '+' |
91 | #define FMT_ZERO'0' '0' |
92 | #define FMT_MINUS'-' '-' |
93 | |
94 | #define FMT_DECIMAL'D' 'D' |
95 | #define FMT_OCTAL'O' 'O' |
96 | #define FMT_UNSIGNED'U' 'U' |
97 | #define FMT_HEX'X' 'X' |
98 | #define FMT_FLOAT'F' 'F' |
99 | #define FMT_STRING'S' 'S' |
100 | |
101 | #define FMTF_DECIMAL0x01 0x01 |
102 | #define FMTF_OCTAL0x02 0x02 |
103 | #define FMTF_UNSIGNED0x04 0x04 |
104 | #define FMTF_HEX0x08 0x08 |
105 | #define FMTF_FLOAT0x10 0x10 |
106 | #define FMTF_STRING0x20 0x20 |
107 | |
108 | #define HIGH_PIECE'H' 'H' |
109 | #define MIDDLE_PIECE'M' 'M' |
110 | #define LOW_PIECE'L' 'L' |
111 | |
112 | #define SHOW_st_dev'd' 'd' |
113 | #define SHOW_st_ino'i' 'i' |
114 | #define SHOW_st_mode'p' 'p' |
115 | #define SHOW_st_nlink'l' 'l' |
116 | #define SHOW_st_uid'u' 'u' |
117 | #define SHOW_st_gid'g' 'g' |
118 | #define SHOW_st_rdev'r' 'r' |
119 | #define SHOW_st_atime'a' 'a' |
120 | #define SHOW_st_mtime'm' 'm' |
121 | #define SHOW_st_ctime'c' 'c' |
122 | #define SHOW_st_btime'B' 'B' |
123 | #define SHOW_st_size'z' 'z' |
124 | #define SHOW_st_blocks'b' 'b' |
125 | #define SHOW_st_blksize'k' 'k' |
126 | #define SHOW_st_flags'f' 'f' |
127 | #define SHOW_st_gen'v' 'v' |
128 | #define SHOW_symlink'Y' 'Y' |
129 | #define SHOW_filetype'T' 'T' |
130 | #define SHOW_filename'N' 'N' |
131 | #define SHOW_sizerdev'Z' 'Z' |
132 | |
133 | void usage(const char *); |
134 | void output(const struct stat *, const char *, |
135 | const char *, int, int); |
136 | int format1(const struct stat *, /* stat info */ |
137 | const char *, /* the file name */ |
138 | const char *, int, /* the format string itself */ |
139 | char *, size_t, /* a place to put the output */ |
140 | int, int, int, int, /* the parsed format */ |
141 | int, int); |
142 | |
143 | char *timefmt; |
144 | |
145 | #define addchar(s, c, nl)do { (void)fputc((c), (s)); (*nl) = ((c) == '\n'); } while (0 ) \ |
146 | do { \ |
147 | (void)fputc((c), (s)); \ |
148 | (*nl) = ((c) == '\n'); \ |
149 | } while (0/*CONSTCOND*/) |
150 | |
151 | extern char *__progname; |
152 | |
153 | int |
154 | main(int argc, char *argv[]) |
155 | { |
156 | struct stat st; |
157 | int ch, rc, errs; |
158 | int lsF, fmtchar, usestat, fn, nonl, quiet; |
159 | char *statfmt, *options, *synopsis; |
160 | |
161 | if (pledge("stdio rpath getpw", NULL((void *)0)) == -1) |
162 | err(1, "pledge"); |
163 | |
164 | lsF = 0; |
165 | fmtchar = '\0'; |
166 | usestat = 0; |
167 | nonl = 0; |
168 | quiet = 0; |
169 | statfmt = NULL((void *)0); |
170 | timefmt = NULL((void *)0); |
171 | |
172 | options = "f:FlLnqrst:x"; |
173 | synopsis = "[-FLnq] [-f format | -l | -r | -s | -x] " |
174 | "[-t timefmt] [file ...]"; |
175 | |
176 | while ((ch = getopt(argc, argv, options)) != -1) |
177 | switch (ch) { |
178 | case 'F': |
179 | lsF = 1; |
180 | break; |
181 | case 'L': |
182 | usestat = 1; |
183 | break; |
184 | case 'n': |
185 | nonl = 1; |
186 | break; |
187 | case 'q': |
188 | quiet = 1; |
189 | break; |
190 | case 'f': |
191 | statfmt = optarg; |
192 | /* FALLTHROUGH */ |
193 | case 'l': |
194 | case 'r': |
195 | case 's': |
196 | case 'x': |
197 | if (fmtchar != 0) |
198 | errx(1, "can't use format '%c' with '%c'", |
199 | fmtchar, ch); |
200 | fmtchar = ch; |
201 | break; |
202 | case 't': |
203 | timefmt = optarg; |
204 | break; |
205 | default: |
206 | usage(synopsis); |
207 | } |
208 | |
209 | argc -= optind; |
210 | argv += optind; |
211 | fn = 1; |
212 | |
213 | if (fmtchar == '\0') { |
214 | if (lsF) |
215 | fmtchar = 'l'; |
216 | else { |
217 | fmtchar = 'f'; |
218 | statfmt = DEF_FORMAT"%d %i %Sp %l %Su %Sg %r %z \"%Sa\" \"%Sm\" \"%Sc\" " "%k %b %#Xf %N"; |
219 | } |
220 | } |
221 | |
222 | if (lsF && fmtchar != 'l') |
223 | errx(1, "can't use format '%c' with -F", fmtchar); |
224 | |
225 | switch (fmtchar) { |
226 | case 'f': |
227 | /* statfmt already set */ |
228 | break; |
229 | case 'l': |
230 | statfmt = lsF ? LSF_FORMAT"%Sp %l %Su %Sg %Z %Sm %N%T%SY" : LS_FORMAT"%Sp %l %Su %Sg %Z %Sm %N%SY"; |
231 | break; |
232 | case 'r': |
233 | statfmt = RAW_FORMAT"%d %i %#p %l %u %g %r %z %a %m %c " "%k %b %f %N"; |
234 | break; |
235 | case 's': |
236 | statfmt = SHELL_FORMAT"st_dev=%d st_ino=%i st_mode=%#p st_nlink=%l " "st_uid=%u st_gid=%g st_rdev=%r st_size=%z " "st_atime=%a st_mtime=%m st_ctime=%c " "st_blksize=%k st_blocks=%b st_flags=%f"; |
237 | break; |
238 | case 'x': |
239 | statfmt = LINUX_FORMAT" File: \"%N\"%n" " Size: %-11z FileType: %HT%n" " Mode: (%01Mp%03OLp/%.10Sp) Uid: (%5u/%8Su) Gid: (%5g/%8Sg)%n" "Device: %Hd,%Ld Inode: %i Links: %l%n" "Access: %Sa%n" "Modify: %Sm%n" "Change: %Sc"; |
240 | if (timefmt == NULL((void *)0)) |
241 | timefmt = "%c"; |
242 | break; |
243 | default: |
244 | usage(synopsis); |
245 | /*NOTREACHED*/ |
246 | } |
247 | |
248 | if (timefmt == NULL((void *)0)) |
249 | timefmt = TIME_FORMAT"%b %e %T %Y"; |
250 | |
251 | errs = 0; |
252 | do { |
253 | if (argc == 0) |
254 | rc = fstat(STDIN_FILENO0, &st); |
255 | else if (usestat) { |
256 | /* |
257 | * Try stat() and if it fails, fall back to |
258 | * lstat() just in case we're examining a |
259 | * broken symlink. |
260 | */ |
261 | if ((rc = stat(argv[0], &st)) == -1 && |
262 | errno(*__errno()) == ENOENT2 && |
263 | (rc = lstat(argv[0], &st)) == -1) |
264 | errno(*__errno()) = ENOENT2; |
265 | } else |
266 | rc = lstat(argv[0], &st); |
267 | |
268 | if (rc == -1) { |
269 | errs = 1; |
270 | if (!quiet) |
271 | warn("%s", |
272 | argc == 0 ? "(stdin)" : argv[0]); |
273 | } else |
274 | output(&st, argv[0], statfmt, fn, nonl); |
275 | |
276 | argv++; |
277 | argc--; |
278 | fn++; |
279 | } while (argc > 0); |
280 | |
281 | return (errs); |
282 | } |
283 | |
284 | void |
285 | usage(const char *synopsis) |
286 | { |
287 | |
288 | (void)fprintf(stderr(&__sF[2]), "usage: %s %s\n", __progname, synopsis); |
289 | exit(1); |
290 | } |
291 | |
292 | /* |
293 | * Parses a format string. |
294 | */ |
295 | void |
296 | output(const struct stat *st, const char *file, |
297 | const char *statfmt, int fn, int nonl) |
298 | { |
299 | int flags, size, prec, ofmt, hilo, what; |
300 | char buf[PATH_MAX1024 + 4 + 1]; |
301 | const char *subfmt; |
302 | int nl, t, i; |
303 | |
304 | nl = 1; |
305 | while (*statfmt != '\0') { |
306 | |
307 | /* |
308 | * Non-format characters go straight out. |
309 | */ |
310 | if (*statfmt != FMT_MAGIC'%') { |
311 | addchar(stdout, *statfmt, &nl)do { (void)fputc((*statfmt), ((&__sF[1]))); (*&nl) = ( (*statfmt) == '\n'); } while (0 ); |
312 | statfmt++; |
313 | continue; |
314 | } |
315 | |
316 | /* |
317 | * The current format "substring" starts here, |
318 | * and then we skip the magic. |
319 | */ |
320 | subfmt = statfmt; |
321 | statfmt++; |
322 | |
323 | /* |
324 | * Some simple one-character "formats". |
325 | */ |
326 | switch (*statfmt) { |
327 | case SIMPLE_NEWLINE'n': |
328 | addchar(stdout, '\n', &nl)do { (void)fputc(('\n'), ((&__sF[1]))); (*&nl) = (('\n' ) == '\n'); } while (0 ); |
329 | statfmt++; |
330 | continue; |
331 | case SIMPLE_TAB't': |
332 | addchar(stdout, '\t', &nl)do { (void)fputc(('\t'), ((&__sF[1]))); (*&nl) = (('\t' ) == '\n'); } while (0 ); |
333 | statfmt++; |
334 | continue; |
335 | case SIMPLE_PERCENT'%': |
336 | addchar(stdout, '%', &nl)do { (void)fputc(('%'), ((&__sF[1]))); (*&nl) = (('%' ) == '\n'); } while (0 ); |
337 | statfmt++; |
338 | continue; |
339 | case SIMPLE_NUMBER'@': { |
340 | char num[12], *p; |
341 | |
342 | snprintf(num, sizeof(num), "%d", fn); |
343 | for (p = &num[0]; *p; p++) |
344 | addchar(stdout, *p, &nl)do { (void)fputc((*p), ((&__sF[1]))); (*&nl) = ((*p) == '\n'); } while (0 ); |
345 | statfmt++; |
346 | continue; |
347 | } |
348 | } |
349 | |
350 | /* |
351 | * This must be an actual format string. Format strings are |
352 | * similar to printf(3) formats up to a point, and are of |
353 | * the form: |
354 | * |
355 | * % required start of format |
356 | * [-# +0] opt. format characters |
357 | * size opt. field width |
358 | * . opt. decimal separator, followed by |
359 | * prec opt. precision |
360 | * fmt opt. output specifier (string, numeric, etc.) |
361 | * sub opt. sub field specifier (high, middle, low) |
362 | * datum required field specifier (size, mode, etc) |
363 | * |
364 | * Only the % and the datum selector are required. All data |
365 | * have reasonable default output forms. The "sub" specifier |
366 | * only applies to certain data (mode, dev, rdev, filetype). |
367 | * The symlink output defaults to STRING, yet will only emit |
368 | * the leading " -> " if STRING is explicitly specified. The |
369 | * sizerdev datum will generate rdev output for character or |
370 | * block devices, and size output for all others. |
371 | */ |
372 | flags = 0; |
373 | do { |
374 | if (*statfmt == FMT_POUND'#') |
375 | flags |= FLAG_POUND0x01; |
376 | else if (*statfmt == FMT_SPACE' ') |
377 | flags |= FLAG_SPACE0x02; |
378 | else if (*statfmt == FMT_PLUS'+') |
379 | flags |= FLAG_PLUS0x04; |
380 | else if (*statfmt == FMT_ZERO'0') |
381 | flags |= FLAG_ZERO0x08; |
382 | else if (*statfmt == FMT_MINUS'-') |
383 | flags |= FLAG_MINUS0x10; |
384 | else |
385 | break; |
386 | statfmt++; |
387 | } while (1/*CONSTCOND*/); |
388 | |
389 | size = -1; |
390 | if (isdigit((unsigned char)*statfmt)) { |
391 | size = 0; |
392 | while (isdigit((unsigned char)*statfmt)) { |
393 | size = (size * 10) + (*statfmt - '0'); |
394 | statfmt++; |
395 | if (size < 0) |
396 | goto badfmt; |
397 | } |
398 | } |
399 | |
400 | prec = -1; |
401 | if (*statfmt == FMT_DOT'.') { |
402 | statfmt++; |
403 | |
404 | prec = 0; |
405 | while (isdigit((unsigned char)*statfmt)) { |
406 | prec = (prec * 10) + (*statfmt - '0'); |
407 | statfmt++; |
408 | if (prec < 0) |
409 | goto badfmt; |
410 | } |
411 | } |
412 | |
413 | #define fmtcase(x, y) case (y): (x) = (y); statfmt++; break |
414 | #define fmtcasef(x, y, z) case (y): (x) = (z); statfmt++; break |
415 | switch (*statfmt) { |
416 | fmtcasef(ofmt, FMT_DECIMAL'D', FMTF_DECIMAL0x01); |
417 | fmtcasef(ofmt, FMT_OCTAL'O', FMTF_OCTAL0x02); |
418 | fmtcasef(ofmt, FMT_UNSIGNED'U', FMTF_UNSIGNED0x04); |
419 | fmtcasef(ofmt, FMT_HEX'X', FMTF_HEX0x08); |
420 | fmtcasef(ofmt, FMT_FLOAT'F', FMTF_FLOAT0x10); |
421 | fmtcasef(ofmt, FMT_STRING'S', FMTF_STRING0x20); |
422 | default: |
423 | ofmt = 0; |
424 | break; |
425 | } |
426 | |
427 | switch (*statfmt) { |
428 | fmtcase(hilo, HIGH_PIECE'H'); |
429 | fmtcase(hilo, MIDDLE_PIECE'M'); |
430 | fmtcase(hilo, LOW_PIECE'L'); |
431 | default: |
432 | hilo = 0; |
433 | break; |
434 | } |
435 | |
436 | switch (*statfmt) { |
437 | fmtcase(what, SHOW_st_dev'd'); |
438 | fmtcase(what, SHOW_st_ino'i'); |
439 | fmtcase(what, SHOW_st_mode'p'); |
440 | fmtcase(what, SHOW_st_nlink'l'); |
441 | fmtcase(what, SHOW_st_uid'u'); |
442 | fmtcase(what, SHOW_st_gid'g'); |
443 | fmtcase(what, SHOW_st_rdev'r'); |
444 | fmtcase(what, SHOW_st_atime'a'); |
445 | fmtcase(what, SHOW_st_mtime'm'); |
446 | fmtcase(what, SHOW_st_ctime'c'); |
447 | fmtcase(what, SHOW_st_btime'B'); |
448 | fmtcase(what, SHOW_st_size'z'); |
449 | fmtcase(what, SHOW_st_blocks'b'); |
450 | fmtcase(what, SHOW_st_blksize'k'); |
451 | fmtcase(what, SHOW_st_flags'f'); |
452 | fmtcase(what, SHOW_st_gen'v'); |
453 | fmtcase(what, SHOW_symlink'Y'); |
454 | fmtcase(what, SHOW_filetype'T'); |
455 | fmtcase(what, SHOW_filename'N'); |
456 | fmtcase(what, SHOW_sizerdev'Z'); |
457 | default: |
458 | goto badfmt; |
459 | } |
460 | #undef fmtcasef |
461 | #undef fmtcase |
462 | |
463 | t = format1(st, file, subfmt, statfmt - subfmt, buf, |
464 | sizeof(buf), flags, size, prec, ofmt, hilo, what); |
465 | |
466 | for (i = 0; i < t && i < sizeof(buf) - 1; i++) |
467 | addchar(stdout, buf[i], &nl)do { (void)fputc((buf[i]), ((&__sF[1]))); (*&nl) = (( buf[i]) == '\n'); } while (0 ); |
468 | |
469 | continue; |
470 | |
471 | badfmt: |
472 | errx(1, "%.*s: bad format", |
473 | (int)(statfmt - subfmt + 1), subfmt); |
474 | } |
475 | |
476 | if (!nl && !nonl) |
477 | (void)fputc('\n', stdout(&__sF[1])); |
478 | (void)fflush(stdout(&__sF[1])); |
479 | } |
480 | |
481 | /* |
482 | * Arranges output according to a single parsed format substring. |
483 | */ |
484 | int |
485 | format1(const struct stat *st, |
486 | const char *file, |
487 | const char *fmt, int flen, |
488 | char *buf, size_t blen, |
489 | int flags, int size, int prec, int ofmt, |
490 | int hilo, int what) |
491 | { |
492 | u_int64_t data; |
493 | char lfmt[24], tmp[20]; |
494 | char smode[12], sid[12], path[PATH_MAX1024 + 4]; |
495 | const char *sdata; |
496 | struct tm *tm; |
497 | time_t secs; |
498 | long nsecs; |
499 | int l, small, formats, gottime, n; |
500 | |
501 | formats = 0; |
502 | small = 0; |
503 | gottime = 0; |
504 | secs = 0; |
505 | nsecs = 0; |
506 | |
507 | /* |
508 | * First, pick out the data and tweak it based on hilo or |
509 | * specified output format (symlink output only). |
510 | */ |
511 | switch (what) { |
512 | case SHOW_st_dev'd': |
513 | case SHOW_st_rdev'r': |
514 | small = (sizeof(st->st_dev) == 4); |
515 | data = (what == SHOW_st_dev'd') ? st->st_dev : st->st_rdev; |
516 | sdata = (what == SHOW_st_dev'd') ? |
517 | devname(st->st_dev, S_IFBLK0060000) : |
518 | devname(st->st_rdev, |
519 | S_ISCHR(st->st_mode)((st->st_mode & 0170000) == 0020000) ? S_IFCHR0020000 : |
520 | S_ISBLK(st->st_mode)((st->st_mode & 0170000) == 0060000) ? S_IFBLK0060000 : |
521 | 0U); |
522 | if (sdata == NULL((void *)0)) |
523 | sdata = "???"; |
524 | if (hilo == HIGH_PIECE'H') { |
525 | data = major(data)(((unsigned)(data) >> 8) & 0xff); |
526 | hilo = 0; |
527 | } else if (hilo == LOW_PIECE'L') { |
528 | data = minor((unsigned)data)((unsigned)(((unsigned)data) & 0xff) | ((((unsigned)data) & 0xffff0000) >> 8)); |
529 | hilo = 0; |
530 | } |
531 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08 | |
532 | FMTF_STRING0x20; |
533 | if (ofmt == 0) |
534 | ofmt = FMTF_UNSIGNED0x04; |
535 | break; |
536 | case SHOW_st_ino'i': |
537 | small = (sizeof(st->st_ino) == 4); |
538 | data = st->st_ino; |
539 | sdata = NULL((void *)0); |
540 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; |
541 | if (ofmt == 0) |
542 | ofmt = FMTF_UNSIGNED0x04; |
543 | break; |
544 | case SHOW_st_mode'p': |
545 | small = (sizeof(st->st_mode) == 4); |
546 | data = st->st_mode; |
547 | strmode(st->st_mode, smode); |
548 | l = strlen(smode); |
549 | if (smode[l - 1] == ' ') |
550 | smode[--l] = '\0'; |
551 | switch (hilo) { |
552 | case HIGH_PIECE'H': |
553 | data >>= 12; |
554 | smode[4] = '\0'; |
555 | sdata = smode + 1; |
556 | break; |
557 | case MIDDLE_PIECE'M': |
558 | data = (data >> 9) & 07; |
559 | smode[7] = '\0'; |
560 | sdata = smode + 4; |
561 | break; |
562 | case LOW_PIECE'L': |
563 | data &= 0777; |
564 | smode[10] = '\0'; |
565 | sdata = smode + 7; |
566 | break; |
567 | default: |
568 | sdata = smode; |
569 | break; |
570 | } |
571 | hilo = 0; |
572 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08 | |
573 | FMTF_STRING0x20; |
574 | if (ofmt == 0) |
575 | ofmt = FMTF_OCTAL0x02; |
576 | break; |
577 | case SHOW_st_nlink'l': |
578 | small = (sizeof(st->st_dev) == 4); |
579 | data = st->st_nlink; |
580 | sdata = NULL((void *)0); |
581 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; |
582 | if (ofmt == 0) |
583 | ofmt = FMTF_UNSIGNED0x04; |
584 | break; |
585 | case SHOW_st_uid'u': |
586 | small = (sizeof(st->st_uid) == 4); |
587 | data = st->st_uid; |
588 | sdata = user_from_uid(st->st_uid, 1); |
589 | if (sdata == NULL((void *)0)) { |
590 | snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_uid); |
591 | sdata = sid; |
592 | } |
593 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08 | |
594 | FMTF_STRING0x20; |
595 | if (ofmt == 0) |
596 | ofmt = FMTF_UNSIGNED0x04; |
597 | break; |
598 | case SHOW_st_gid'g': |
599 | small = (sizeof(st->st_gid) == 4); |
600 | data = st->st_gid; |
601 | sdata = group_from_gid(st->st_gid, 1); |
602 | if (sdata == NULL((void *)0)) { |
603 | snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_gid); |
604 | sdata = sid; |
605 | } |
606 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08 | |
607 | FMTF_STRING0x20; |
608 | if (ofmt == 0) |
609 | ofmt = FMTF_UNSIGNED0x04; |
610 | break; |
611 | case SHOW_st_atime'a': |
612 | gottime = 1; |
613 | secs = st->st_atimest_atim.tv_sec; |
614 | nsecs = st->st_atimensecst_atim.tv_nsec; |
615 | /* FALLTHROUGH */ |
616 | case SHOW_st_mtime'm': |
617 | if (!gottime) { |
618 | gottime = 1; |
619 | secs = st->st_mtimest_mtim.tv_sec; |
620 | nsecs = st->st_mtimensecst_mtim.tv_nsec; |
621 | } |
622 | /* FALLTHROUGH */ |
623 | case SHOW_st_ctime'c': |
624 | if (!gottime) { |
625 | gottime = 1; |
626 | secs = st->st_ctimest_ctim.tv_sec; |
627 | nsecs = st->st_ctimensecst_ctim.tv_nsec; |
628 | } |
629 | /* FALLTHROUGH */ |
630 | case SHOW_st_btime'B': |
631 | if (!gottime) { |
632 | gottime = 1; |
633 | secs = st->__st_birthtimespec__st_birthtim.tv_sec; |
634 | nsecs = st->__st_birthtimespec__st_birthtim.tv_nsec; |
635 | } |
636 | small = (sizeof(secs) == 4); |
Value stored to 'small' is never read | |
637 | data = secs; |
638 | small = 1; |
639 | tm = localtime(&secs); |
640 | (void)strftime(path, sizeof(path), timefmt, tm); |
641 | sdata = path; |
642 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08 | |
643 | FMTF_FLOAT0x10 | FMTF_STRING0x20; |
644 | if (ofmt == 0) |
645 | ofmt = FMTF_DECIMAL0x01; |
646 | break; |
647 | case SHOW_st_size'z': |
648 | small = (sizeof(st->st_size) == 4); |
649 | data = st->st_size; |
650 | sdata = NULL((void *)0); |
651 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; |
652 | if (ofmt == 0) |
653 | ofmt = FMTF_UNSIGNED0x04; |
654 | break; |
655 | case SHOW_st_blocks'b': |
656 | small = (sizeof(st->st_blocks) == 4); |
657 | data = st->st_blocks; |
658 | sdata = NULL((void *)0); |
659 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; |
660 | if (ofmt == 0) |
661 | ofmt = FMTF_UNSIGNED0x04; |
662 | break; |
663 | case SHOW_st_blksize'k': |
664 | small = (sizeof(st->st_blksize) == 4); |
665 | data = st->st_blksize; |
666 | sdata = NULL((void *)0); |
667 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; |
668 | if (ofmt == 0) |
669 | ofmt = FMTF_UNSIGNED0x04; |
670 | break; |
671 | case SHOW_st_flags'f': |
672 | small = (sizeof(st->st_flags) == 4); |
673 | data = st->st_flags; |
674 | sdata = NULL((void *)0); |
675 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; |
676 | if (ofmt == 0) |
677 | ofmt = FMTF_UNSIGNED0x04; |
678 | break; |
679 | case SHOW_st_gen'v': |
680 | small = (sizeof(st->st_gen) == 4); |
681 | data = st->st_gen; |
682 | sdata = NULL((void *)0); |
683 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; |
684 | if (ofmt == 0) |
685 | ofmt = FMTF_UNSIGNED0x04; |
686 | break; |
687 | case SHOW_symlink'Y': |
688 | small = 0; |
689 | data = 0; |
690 | if (S_ISLNK(st->st_mode)((st->st_mode & 0170000) == 0120000)) { |
691 | snprintf(path, sizeof(path), " -> "); |
692 | l = readlink(file, path + 4, sizeof(path) - 4 - 1); |
693 | if (l == -1) { |
694 | l = 0; |
695 | path[0] = '\0'; |
696 | } |
697 | path[l + 4] = '\0'; |
698 | sdata = path + (ofmt == FMTF_STRING0x20 ? 0 : 4); |
699 | } else |
700 | sdata = ""; |
701 | |
702 | formats = FMTF_STRING0x20; |
703 | if (ofmt == 0) |
704 | ofmt = FMTF_STRING0x20; |
705 | break; |
706 | case SHOW_filetype'T': |
707 | small = 0; |
708 | data = 0; |
709 | sdata = smode; |
710 | smode[0] = '\0'; |
711 | if (hilo == 0 || hilo == LOW_PIECE'L') { |
712 | switch (st->st_mode & S_IFMT0170000) { |
713 | case S_IFIFO0010000: |
714 | (void)strlcat(smode, "|", sizeof(smode)); |
715 | break; |
716 | case S_IFDIR0040000: |
717 | (void)strlcat(smode, "/", sizeof(smode)); |
718 | break; |
719 | case S_IFREG0100000: |
720 | if (st->st_mode & (S_IXUSR0000100 | S_IXGRP0000010 | S_IXOTH0000001)) |
721 | (void)strlcat(smode, "*", |
722 | sizeof(smode)); |
723 | break; |
724 | case S_IFLNK0120000: |
725 | (void)strlcat(smode, "@", sizeof(smode)); |
726 | break; |
727 | case S_IFSOCK0140000: |
728 | (void)strlcat(smode, "=", sizeof(smode)); |
729 | break; |
730 | } |
731 | hilo = 0; |
732 | } else if (hilo == HIGH_PIECE'H') { |
733 | switch (st->st_mode & S_IFMT0170000) { |
734 | case S_IFIFO0010000: sdata = "Fifo File"; break; |
735 | case S_IFCHR0020000: sdata = "Character Device"; break; |
736 | case S_IFDIR0040000: sdata = "Directory"; break; |
737 | case S_IFBLK0060000: sdata = "Block Device"; break; |
738 | case S_IFREG0100000: sdata = "Regular File"; break; |
739 | case S_IFLNK0120000: sdata = "Symbolic Link"; break; |
740 | case S_IFSOCK0140000: sdata = "Socket"; break; |
741 | default: sdata = "???"; break; |
742 | } |
743 | hilo = 0; |
744 | } |
745 | formats = FMTF_STRING0x20; |
746 | if (ofmt == 0) |
747 | ofmt = FMTF_STRING0x20; |
748 | break; |
749 | case SHOW_filename'N': |
750 | small = 0; |
751 | data = 0; |
752 | if (file == NULL((void *)0)) |
753 | (void)strlcpy(path, "(stdin)", sizeof(path)); |
754 | else |
755 | (void)strlcpy(path, file, sizeof(path)); |
756 | sdata = path; |
757 | formats = FMTF_STRING0x20; |
758 | if (ofmt == 0) |
759 | ofmt = FMTF_STRING0x20; |
760 | break; |
761 | case SHOW_sizerdev'Z': |
762 | if (S_ISCHR(st->st_mode)((st->st_mode & 0170000) == 0020000) || S_ISBLK(st->st_mode)((st->st_mode & 0170000) == 0060000)) { |
763 | char majdev[20], mindev[20]; |
764 | int l1, l2; |
765 | |
766 | l1 = format1(st, file, fmt, flen, |
767 | majdev, sizeof(majdev), flags, size, prec, |
768 | ofmt, HIGH_PIECE'H', SHOW_st_rdev'r'); |
769 | l2 = format1(st, file, fmt, flen, |
770 | mindev, sizeof(mindev), flags, size, prec, |
771 | ofmt, LOW_PIECE'L', SHOW_st_rdev'r'); |
772 | n = snprintf(buf, blen, "%.*s,%.*s", |
773 | l1, majdev, l2, mindev); |
774 | return (n >= blen ? blen : n); |
775 | } else { |
776 | return (format1(st, file, fmt, flen, buf, blen, |
777 | flags, size, prec, ofmt, 0, SHOW_st_size'z')); |
778 | } |
779 | /*NOTREACHED*/ |
780 | default: |
781 | errx(1, "%.*s: bad format", (int)flen, fmt); |
782 | } |
783 | |
784 | /* |
785 | * If a subdatum was specified but not supported, or an output |
786 | * format was selected that is not supported, that's an error. |
787 | */ |
788 | if (hilo != 0 || (ofmt & formats) == 0) |
789 | errx(1, "%.*s: bad format", (int)flen, fmt); |
790 | |
791 | /* |
792 | * Assemble the format string for passing to printf(3). |
793 | */ |
794 | lfmt[0] = '\0'; |
795 | (void)strlcat(lfmt, "%", sizeof(lfmt)); |
796 | if (flags & FLAG_POUND0x01) |
797 | (void)strlcat(lfmt, "#", sizeof(lfmt)); |
798 | if (flags & FLAG_SPACE0x02) |
799 | (void)strlcat(lfmt, " ", sizeof(lfmt)); |
800 | if (flags & FLAG_PLUS0x04) |
801 | (void)strlcat(lfmt, "+", sizeof(lfmt)); |
802 | if (flags & FLAG_MINUS0x10) |
803 | (void)strlcat(lfmt, "-", sizeof(lfmt)); |
804 | if (flags & FLAG_ZERO0x08) |
805 | (void)strlcat(lfmt, "0", sizeof(lfmt)); |
806 | |
807 | /* |
808 | * Only the timespecs support the FLOAT output format, and that |
809 | * requires work that differs from the other formats. |
810 | */ |
811 | if (ofmt == FMTF_FLOAT0x10) { |
812 | /* |
813 | * Nothing after the decimal point, so just print seconds. |
814 | */ |
815 | if (prec == 0) { |
816 | if (size != -1) { |
817 | (void)snprintf(tmp, sizeof(tmp), "%d", size); |
818 | (void)strlcat(lfmt, tmp, sizeof(lfmt)); |
819 | } |
820 | (void)strlcat(lfmt, "d", sizeof(lfmt)); |
821 | n = snprintf(buf, blen, lfmt, secs); |
822 | return (n >= blen ? blen : n); |
823 | } |
824 | |
825 | /* |
826 | * Unspecified precision gets all the precision we have: |
827 | * 9 digits. |
828 | */ |
829 | if (prec == -1) |
830 | prec = 9; |
831 | |
832 | /* |
833 | * Adjust the size for the decimal point and the digits |
834 | * that will follow. |
835 | */ |
836 | size -= prec + 1; |
837 | |
838 | /* |
839 | * Any leftover size that's legitimate will be used. |
840 | */ |
841 | if (size > 0) { |
842 | (void)snprintf(tmp, sizeof(tmp), "%d", size); |
843 | (void)strlcat(lfmt, tmp, sizeof(lfmt)); |
844 | } |
845 | (void)strlcat(lfmt, "d", sizeof(lfmt)); |
846 | |
847 | /* |
848 | * The stuff after the decimal point always needs zero |
849 | * filling. |
850 | */ |
851 | (void)strlcat(lfmt, ".%0", sizeof(lfmt)); |
852 | |
853 | /* |
854 | * We can "print" at most nine digits of precision. The |
855 | * rest we will pad on at the end. |
856 | */ |
857 | (void)snprintf(tmp, sizeof(tmp), "%dd", prec > 9 ? 9 : prec); |
858 | (void)strlcat(lfmt, tmp, sizeof(lfmt)); |
859 | |
860 | /* |
861 | * For precision of less that nine digits, trim off the |
862 | * less significant figures. |
863 | */ |
864 | for (; prec < 9; prec++) |
865 | nsecs /= 10; |
866 | |
867 | /* |
868 | * Use the format, and then tack on any zeroes that |
869 | * might be required to make up the requested precision. |
870 | */ |
871 | l = snprintf(buf, blen, lfmt, secs, nsecs); |
872 | if (l >= blen) |
873 | return (l); |
874 | for (; prec > 9 && l < blen; prec--, l++) |
875 | (void)strlcat(buf, "0", blen); |
876 | return (l); |
877 | } |
878 | |
879 | /* |
880 | * Add on size and precision, if specified, to the format. |
881 | */ |
882 | if (size != -1) { |
883 | (void)snprintf(tmp, sizeof(tmp), "%d", size); |
884 | (void)strlcat(lfmt, tmp, sizeof(lfmt)); |
885 | } |
886 | if (prec != -1) { |
887 | (void)snprintf(tmp, sizeof(tmp), ".%d", prec); |
888 | (void)strlcat(lfmt, tmp, sizeof(lfmt)); |
889 | } |
890 | |
891 | /* |
892 | * String output uses the temporary sdata. |
893 | */ |
894 | if (ofmt == FMTF_STRING0x20) { |
895 | if (sdata == NULL((void *)0)) |
896 | errx(1, "%.*s: bad format", (int)flen, fmt); |
897 | (void)strlcat(lfmt, "s", sizeof(lfmt)); |
898 | n = snprintf(buf, blen, lfmt, sdata); |
899 | return (n >= blen ? blen : n); |
900 | } |
901 | |
902 | /* |
903 | * Ensure that sign extension does not cause bad looking output |
904 | * for some forms. |
905 | */ |
906 | if (small && ofmt != FMTF_DECIMAL0x01) |
907 | data = (u_int32_t)data; |
908 | |
909 | /* |
910 | * The four "numeric" output forms. |
911 | */ |
912 | (void)strlcat(lfmt, "ll", sizeof(lfmt)); |
913 | switch (ofmt) { |
914 | case FMTF_DECIMAL0x01: (void)strlcat(lfmt, "d", sizeof(lfmt)); break; |
915 | case FMTF_OCTAL0x02: (void)strlcat(lfmt, "o", sizeof(lfmt)); break; |
916 | case FMTF_UNSIGNED0x04: (void)strlcat(lfmt, "u", sizeof(lfmt)); break; |
917 | case FMTF_HEX0x08: (void)strlcat(lfmt, "x", sizeof(lfmt)); break; |
918 | } |
919 | |
920 | n = snprintf(buf, blen, lfmt, data); |
921 | return (n >= blen ? blen : n); |
922 | } |