| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /* $OpenBSD: stat.c,v 1.21 2015/10/10 20:35:01 deraadt 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.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 \  | 
    ||
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 " \  | 
    ||
52  | 
    "%k %b %f %N"  | 
    ||
53  | 
    #define LS_FORMAT "%Sp %l %Su %Sg %Z %Sm %N%SY"  | 
    ||
54  | 
    #define LSF_FORMAT "%Sp %l %Su %Sg %Z %Sm %N%T%SY"  | 
    ||
55  | 
    #define SHELL_FORMAT \  | 
    ||
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 \  | 
    ||
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"  | 
    ||
70  | 
    |||
71  | 
    #define FLAG_POUND 0x01  | 
    ||
72  | 
    #define FLAG_SPACE 0x02  | 
    ||
73  | 
    #define FLAG_PLUS 0x04  | 
    ||
74  | 
    #define FLAG_ZERO 0x08  | 
    ||
75  | 
    #define FLAG_MINUS 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'  | 
    ||
84  | 
    #define SIMPLE_TAB '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'  | 
    ||
92  | 
    #define FMT_MINUS '-'  | 
    ||
93  | 
    |||
94  | 
    #define FMT_DECIMAL 'D'  | 
    ||
95  | 
    #define FMT_OCTAL 'O'  | 
    ||
96  | 
    #define FMT_UNSIGNED 'U'  | 
    ||
97  | 
    #define FMT_HEX 'X'  | 
    ||
98  | 
    #define FMT_FLOAT 'F'  | 
    ||
99  | 
    #define FMT_STRING 'S'  | 
    ||
100  | 
    |||
101  | 
    #define FMTF_DECIMAL 0x01  | 
    ||
102  | 
    #define FMTF_OCTAL 0x02  | 
    ||
103  | 
    #define FMTF_UNSIGNED 0x04  | 
    ||
104  | 
    #define FMTF_HEX 0x08  | 
    ||
105  | 
    #define FMTF_FLOAT 0x10  | 
    ||
106  | 
    #define FMTF_STRING 0x20  | 
    ||
107  | 
    |||
108  | 
    #define HIGH_PIECE 'H'  | 
    ||
109  | 
    #define MIDDLE_PIECE 'M'  | 
    ||
110  | 
    #define LOW_PIECE 'L'  | 
    ||
111  | 
    |||
112  | 
    #define SHOW_st_dev 'd'  | 
    ||
113  | 
    #define SHOW_st_ino 'i'  | 
    ||
114  | 
    #define SHOW_st_mode 'p'  | 
    ||
115  | 
    #define SHOW_st_nlink 'l'  | 
    ||
116  | 
    #define SHOW_st_uid 'u'  | 
    ||
117  | 
    #define SHOW_st_gid 'g'  | 
    ||
118  | 
    #define SHOW_st_rdev 'r'  | 
    ||
119  | 
    #define SHOW_st_atime 'a'  | 
    ||
120  | 
    #define SHOW_st_mtime 'm'  | 
    ||
121  | 
    #define SHOW_st_ctime 'c'  | 
    ||
122  | 
    #define SHOW_st_btime 'B'  | 
    ||
123  | 
    #define SHOW_st_size 'z'  | 
    ||
124  | 
    #define SHOW_st_blocks 'b'  | 
    ||
125  | 
    #define SHOW_st_blksize 'k'  | 
    ||
126  | 
    #define SHOW_st_flags 'f'  | 
    ||
127  | 
    #define SHOW_st_gen 'v'  | 
    ||
128  | 
    #define SHOW_symlink 'Y'  | 
    ||
129  | 
    #define SHOW_filetype 'T'  | 
    ||
130  | 
    #define SHOW_filename 'N'  | 
    ||
131  | 
    #define SHOW_sizerdev '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) \  | 
    ||
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  | 
    4180  | 
    struct stat st;  | 
    |
157  | 
    int ch, rc, errs;  | 
    ||
158  | 
    int lsF, fmtchar, usestat, fn, nonl, quiet;  | 
    ||
159  | 
    char *statfmt, *options, *synopsis;  | 
    ||
160  | 
    |||
161  | 
    ✗✓ | 2090  | 
    	if (pledge("stdio rpath getpw flock cpath wpath", NULL) == -1) | 
    
162  | 
    err(1, "pledge");  | 
    ||
163  | 
    |||
164  | 
    lsF = 0;  | 
    ||
165  | 
    fmtchar = '\0';  | 
    ||
166  | 
    usestat = 0;  | 
    ||
167  | 
    nonl = 0;  | 
    ||
168  | 
    quiet = 0;  | 
    ||
169  | 
    statfmt = NULL;  | 
    ||
170  | 
    2090  | 
    timefmt = NULL;  | 
    |
171  | 
    |||
172  | 
    options = "f:FlLnqrst:x";  | 
    ||
173  | 
    synopsis = "[-FLnq] [-f format | -l | -r | -s | -x] "  | 
    ||
174  | 
    "[-t timefmt] [file ...]";  | 
    ||
175  | 
    |||
176  | 
    ✓✓ | 8408  | 
    while ((ch = getopt(argc, argv, options)) != -1)  | 
    
177  | 
    ✗✓✗✗ ✓✗✗✗ ✓✗✗  | 
    4204  | 
    		switch (ch) { | 
    
178  | 
    case 'F':  | 
    ||
179  | 
    lsF = 1;  | 
    ||
180  | 
    break;  | 
    ||
181  | 
    case 'L':  | 
    ||
182  | 
    usestat = 1;  | 
    ||
183  | 
    24  | 
    break;  | 
    |
184  | 
    case 'n':  | 
    ||
185  | 
    nonl = 1;  | 
    ||
186  | 
    break;  | 
    ||
187  | 
    case 'q':  | 
    ||
188  | 
    quiet = 1;  | 
    ||
189  | 
    break;  | 
    ||
190  | 
    case 'f':  | 
    ||
191  | 
    2090  | 
    statfmt = optarg;  | 
    |
192  | 
    /* FALLTHROUGH */  | 
    ||
193  | 
    case 'l':  | 
    ||
194  | 
    case 'r':  | 
    ||
195  | 
    case 's':  | 
    ||
196  | 
    case 'x':  | 
    ||
197  | 
    ✗✓ | 2090  | 
    if (fmtchar != 0)  | 
    
198  | 
    errx(1, "can't use format '%c' with '%c'",  | 
    ||
199  | 
    fmtchar, ch);  | 
    ||
200  | 
    fmtchar = ch;  | 
    ||
201  | 
    2090  | 
    break;  | 
    |
202  | 
    case 't':  | 
    ||
203  | 
    timefmt = optarg;  | 
    ||
204  | 
    break;  | 
    ||
205  | 
    default:  | 
    ||
206  | 
    usage(synopsis);  | 
    ||
207  | 
    }  | 
    ||
208  | 
    |||
209  | 
    2090  | 
    argc -= optind;  | 
    |
210  | 
    2090  | 
    argv += optind;  | 
    |
211  | 
    fn = 1;  | 
    ||
212  | 
    |||
213  | 
    ✗✓ | 2090  | 
    	if (fmtchar == '\0') { | 
    
214  | 
    if (lsF)  | 
    ||
215  | 
    fmtchar = 'l';  | 
    ||
216  | 
    		else { | 
    ||
217  | 
    fmtchar = 'f';  | 
    ||
218  | 
    statfmt = DEF_FORMAT;  | 
    ||
219  | 
    }  | 
    ||
220  | 
    }  | 
    ||
221  | 
    |||
222  | 
    ✗✓ | 2090  | 
    if (lsF && fmtchar != 'l')  | 
    
223  | 
    errx(1, "can't use format '%c' with -F", fmtchar);  | 
    ||
224  | 
    |||
225  | 
    ✗✗✗✗ ✗✓  | 
    2090  | 
    	switch (fmtchar) { | 
    
226  | 
    case 'f':  | 
    ||
227  | 
    /* statfmt already set */  | 
    ||
228  | 
    break;  | 
    ||
229  | 
    case 'l':  | 
    ||
230  | 
    statfmt = lsF ? LSF_FORMAT : LS_FORMAT;  | 
    ||
231  | 
    break;  | 
    ||
232  | 
    case 'r':  | 
    ||
233  | 
    statfmt = RAW_FORMAT;  | 
    ||
234  | 
    break;  | 
    ||
235  | 
    case 's':  | 
    ||
236  | 
    statfmt = SHELL_FORMAT;  | 
    ||
237  | 
    break;  | 
    ||
238  | 
    case 'x':  | 
    ||
239  | 
    statfmt = LINUX_FORMAT;  | 
    ||
240  | 
    if (timefmt == NULL)  | 
    ||
241  | 
    timefmt = "%c";  | 
    ||
242  | 
    break;  | 
    ||
243  | 
    default:  | 
    ||
244  | 
    usage(synopsis);  | 
    ||
245  | 
    /*NOTREACHED*/  | 
    ||
246  | 
    }  | 
    ||
247  | 
    |||
248  | 
    ✓✗ | 2090  | 
    if (timefmt == NULL)  | 
    
249  | 
    2090  | 
    timefmt = TIME_FORMAT;  | 
    |
250  | 
    |||
251  | 
    errs = 0;  | 
    ||
252  | 
    2090  | 
    	do { | 
    |
253  | 
    ✗✓ | 2090  | 
    if (argc == 0)  | 
    
254  | 
    rc = fstat(STDIN_FILENO, &st);  | 
    ||
255  | 
    ✓✓ | 2090  | 
    		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  | 
    ✗✓✗✗ | 
    24  | 
    if ((rc = stat(argv[0], &st)) == -1 &&  | 
    
262  | 
    errno == ENOENT &&  | 
    ||
263  | 
    (rc = lstat(argv[0], &st)) == -1)  | 
    ||
264  | 
    errno = ENOENT;  | 
    ||
265  | 
    } else  | 
    ||
266  | 
    2066  | 
    rc = lstat(argv[0], &st);  | 
    |
267  | 
    |||
268  | 
    ✗✓ | 2090  | 
    		if (rc == -1) { | 
    
269  | 
    errs = 1;  | 
    ||
270  | 
    if (!quiet)  | 
    ||
271  | 
    				warn("%s", | 
    ||
272  | 
    argc == 0 ? "(stdin)" : argv[0]);  | 
    ||
273  | 
    } else  | 
    ||
274  | 
    2090  | 
    output(&st, argv[0], statfmt, fn, nonl);  | 
    |
275  | 
    |||
276  | 
    2090  | 
    argv++;  | 
    |
277  | 
    2090  | 
    argc--;  | 
    |
278  | 
    2090  | 
    fn++;  | 
    |
279  | 
    ✗✓ | 2090  | 
    } while (argc > 0);  | 
    
280  | 
    |||
281  | 
    2090  | 
    return (errs);  | 
    |
282  | 
    2090  | 
    }  | 
    |
283  | 
    |||
284  | 
    void  | 
    ||
285  | 
    usage(const char *synopsis)  | 
    ||
286  | 
    { | 
    ||
287  | 
    |||
288  | 
    (void)fprintf(stderr, "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  | 
    4180  | 
    char buf[PATH_MAX + 4 + 1];  | 
    |
301  | 
    const char *subfmt;  | 
    ||
302  | 
    int nl, t, i;  | 
    ||
303  | 
    |||
304  | 
    nl = 1;  | 
    ||
305  | 
    ✓✓ | 6414  | 
    	while (*statfmt != '\0') { | 
    
306  | 
    |||
307  | 
    /*  | 
    ||
308  | 
    * Non-format characters go straight out.  | 
    ||
309  | 
    */  | 
    ||
310  | 
    ✓✓ | 2234  | 
    		if (*statfmt != FMT_MAGIC) { | 
    
311  | 
    72  | 
    addchar(stdout, *statfmt, &nl);  | 
    |
312  | 
    72  | 
    statfmt++;  | 
    |
313  | 
    72  | 
    continue;  | 
    |
314  | 
    }  | 
    ||
315  | 
    |||
316  | 
    /*  | 
    ||
317  | 
    * The current format "substring" starts here,  | 
    ||
318  | 
    * and then we skip the magic.  | 
    ||
319  | 
    */  | 
    ||
320  | 
    subfmt = statfmt;  | 
    ||
321  | 
    2162  | 
    statfmt++;  | 
    |
322  | 
    |||
323  | 
    /*  | 
    ||
324  | 
    * Some simple one-character "formats".  | 
    ||
325  | 
    */  | 
    ||
326  | 
    ✗✗✗✗ ✓  | 
    2162  | 
    		switch (*statfmt) { | 
    
327  | 
    case SIMPLE_NEWLINE:  | 
    ||
328  | 
    addchar(stdout, '\n', &nl);  | 
    ||
329  | 
    statfmt++;  | 
    ||
330  | 
    continue;  | 
    ||
331  | 
    case SIMPLE_TAB:  | 
    ||
332  | 
    addchar(stdout, '\t', &nl);  | 
    ||
333  | 
    statfmt++;  | 
    ||
334  | 
    continue;  | 
    ||
335  | 
    case SIMPLE_PERCENT:  | 
    ||
336  | 
    addchar(stdout, '%', &nl);  | 
    ||
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);  | 
    ||
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  | 
    2162  | 
    		do { | 
    |
374  | 
    ✗✓ | 2162  | 
    if (*statfmt == FMT_POUND)  | 
    
375  | 
    flags |= FLAG_POUND;  | 
    ||
376  | 
    ✗✓ | 2162  | 
    else if (*statfmt == FMT_SPACE)  | 
    
377  | 
    flags |= FLAG_SPACE;  | 
    ||
378  | 
    ✗✓ | 2162  | 
    else if (*statfmt == FMT_PLUS)  | 
    
379  | 
    flags |= FLAG_PLUS;  | 
    ||
380  | 
    ✗✓ | 2162  | 
    else if (*statfmt == FMT_ZERO)  | 
    
381  | 
    flags |= FLAG_ZERO;  | 
    ||
382  | 
    ✗✓ | 2162  | 
    else if (*statfmt == FMT_MINUS)  | 
    
383  | 
    flags |= FLAG_MINUS;  | 
    ||
384  | 
    else  | 
    ||
385  | 
    break;  | 
    ||
386  | 
    statfmt++;  | 
    ||
387  | 
    } while (1/*CONSTCOND*/);  | 
    ||
388  | 
    |||
389  | 
    size = -1;  | 
    ||
390  | 
    ✗✓ | 2162  | 
    		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  | 
    ✗✓ | 2162  | 
    		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  | 
    ✗✗✗✗ ✗✓✓  | 
    2162  | 
    		switch (*statfmt) { | 
    
416  | 
    fmtcasef(ofmt, FMT_DECIMAL, FMTF_DECIMAL);  | 
    ||
417  | 
    fmtcasef(ofmt, FMT_OCTAL, FMTF_OCTAL);  | 
    ||
418  | 
    fmtcasef(ofmt, FMT_UNSIGNED, FMTF_UNSIGNED);  | 
    ||
419  | 
    fmtcasef(ofmt, FMT_HEX, FMTF_HEX);  | 
    ||
420  | 
    fmtcasef(ofmt, FMT_FLOAT, FMTF_FLOAT);  | 
    ||
421  | 
    520  | 
    fmtcasef(ofmt, FMT_STRING, FMTF_STRING);  | 
    |
422  | 
    default:  | 
    ||
423  | 
    ofmt = 0;  | 
    ||
424  | 
    1642  | 
    break;  | 
    |
425  | 
    }  | 
    ||
426  | 
    |||
427  | 
    ✗✗✗✓ | 
    2162  | 
    		switch (*statfmt) { | 
    
428  | 
    fmtcase(hilo, HIGH_PIECE);  | 
    ||
429  | 
    fmtcase(hilo, MIDDLE_PIECE);  | 
    ||
430  | 
    fmtcase(hilo, LOW_PIECE);  | 
    ||
431  | 
    default:  | 
    ||
432  | 
    hilo = 0;  | 
    ||
433  | 
    2162  | 
    break;  | 
    |
434  | 
    }  | 
    ||
435  | 
    |||
436  | 
    ✓✓✓✗ ✓✓✗✗ ✗✗✗✗ ✗✗✓✗ ✗✗✗✗ ✗  | 
    2162  | 
    		switch (*statfmt) { | 
    
437  | 
    72  | 
    fmtcase(what, SHOW_st_dev);  | 
    |
438  | 
    72  | 
    fmtcase(what, SHOW_st_ino);  | 
    |
439  | 
    1295  | 
    fmtcase(what, SHOW_st_mode);  | 
    |
440  | 
    fmtcase(what, SHOW_st_nlink);  | 
    ||
441  | 
    268  | 
    fmtcase(what, SHOW_st_uid);  | 
    |
442  | 
    268  | 
    fmtcase(what, SHOW_st_gid);  | 
    |
443  | 
    fmtcase(what, SHOW_st_rdev);  | 
    ||
444  | 
    fmtcase(what, SHOW_st_atime);  | 
    ||
445  | 
    fmtcase(what, SHOW_st_mtime);  | 
    ||
446  | 
    fmtcase(what, SHOW_st_ctime);  | 
    ||
447  | 
    fmtcase(what, SHOW_st_btime);  | 
    ||
448  | 
    fmtcase(what, SHOW_st_size);  | 
    ||
449  | 
    fmtcase(what, SHOW_st_blocks);  | 
    ||
450  | 
    fmtcase(what, SHOW_st_blksize);  | 
    ||
451  | 
    187  | 
    fmtcase(what, SHOW_st_flags);  | 
    |
452  | 
    fmtcase(what, SHOW_st_gen);  | 
    ||
453  | 
    fmtcase(what, SHOW_symlink);  | 
    ||
454  | 
    fmtcase(what, SHOW_filetype);  | 
    ||
455  | 
    fmtcase(what, SHOW_filename);  | 
    ||
456  | 
    fmtcase(what, SHOW_sizerdev);  | 
    ||
457  | 
    default:  | 
    ||
458  | 
    goto badfmt;  | 
    ||
459  | 
    }  | 
    ||
460  | 
    #undef fmtcasef  | 
    ||
461  | 
    #undef fmtcase  | 
    ||
462  | 
    |||
463  | 
    2162  | 
    t = format1(st, file, subfmt, statfmt - subfmt, buf,  | 
    |
464  | 
    sizeof(buf), flags, size, prec, ofmt, hilo, what);  | 
    ||
465  | 
    |||
466  | 
    ✓✓ | 26664  | 
    for (i = 0; i < t && i < sizeof(buf) - 1; i++)  | 
    
467  | 
    11170  | 
    addchar(stdout, buf[i], &nl);  | 
    |
468  | 
    |||
469  | 
    2162  | 
    continue;  | 
    |
470  | 
    |||
471  | 
    badfmt:  | 
    ||
472  | 
    errx(1, "%.*s: bad format",  | 
    ||
473  | 
    (int)(statfmt - subfmt + 1), subfmt);  | 
    ||
474  | 
    }  | 
    ||
475  | 
    |||
476  | 
    ✓✗ | 2090  | 
    if (!nl && !nonl)  | 
    
477  | 
    2090  | 
    		(void)fputc('\n', stdout); | 
    |
478  | 
    2090  | 
    (void)fflush(stdout);  | 
    |
479  | 
    2090  | 
    }  | 
    |
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  | 
    4324  | 
    char *sdata, lfmt[24], tmp[20];  | 
    |
494  | 
    2162  | 
    char smode[12], sid[12], path[PATH_MAX + 4];  | 
    |
495  | 
    struct passwd *pw;  | 
    ||
496  | 
    struct group *gr;  | 
    ||
497  | 
    struct tm *tm;  | 
    ||
498  | 
    2162  | 
    time_t secs;  | 
    |
499  | 
    long nsecs;  | 
    ||
500  | 
    int l, small, formats, gottime, n;  | 
    ||
501  | 
    |||
502  | 
    formats = 0;  | 
    ||
503  | 
    small = 0;  | 
    ||
504  | 
    gottime = 0;  | 
    ||
505  | 
    2162  | 
    secs = 0;  | 
    |
506  | 
    nsecs = 0;  | 
    ||
507  | 
    |||
508  | 
    /*  | 
    ||
509  | 
    * First, pick out the data and tweak it based on hilo or  | 
    ||
510  | 
    * specified output format (symlink output only).  | 
    ||
511  | 
    */  | 
    ||
512  | 
    ✗✓✓✓ ✗✓✓✗ ✗✗✗✗ ✗✗✓✗ ✗✗✗✗ ✗  | 
    2162  | 
    	switch (what) { | 
    
513  | 
    case SHOW_st_dev:  | 
    ||
514  | 
    case SHOW_st_rdev:  | 
    ||
515  | 
    small = (sizeof(st->st_dev) == 4);  | 
    ||
516  | 
    72  | 
    data = (what == SHOW_st_dev) ? st->st_dev : st->st_rdev;  | 
    |
517  | 
    ✓✗ | 216  | 
    sdata = (what == SHOW_st_dev) ?  | 
    
518  | 
    72  | 
    devname(st->st_dev, S_IFBLK) :  | 
    |
519  | 
    devname(st->st_rdev,  | 
    ||
520  | 
    S_ISCHR(st->st_mode) ? S_IFCHR :  | 
    ||
521  | 
    S_ISBLK(st->st_mode) ? S_IFBLK :  | 
    ||
522  | 
    0U);  | 
    ||
523  | 
    72  | 
    if (sdata == NULL)  | 
    |
524  | 
    sdata = "???";  | 
    ||
525  | 
    ✗✓ | 72  | 
    		if (hilo == HIGH_PIECE) { | 
    
526  | 
    data = major(data);  | 
    ||
527  | 
    hilo = 0;  | 
    ||
528  | 
    ✗✓ | 72  | 
    		} else if (hilo == LOW_PIECE) { | 
    
529  | 
    data = minor((unsigned)data);  | 
    ||
530  | 
    hilo = 0;  | 
    ||
531  | 
    }  | 
    ||
532  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |  | 
    ||
533  | 
    FMTF_STRING;  | 
    ||
534  | 
    ✓✗ | 72  | 
    if (ofmt == 0)  | 
    
535  | 
    72  | 
    ofmt = FMTF_UNSIGNED;  | 
    |
536  | 
    break;  | 
    ||
537  | 
    case SHOW_st_ino:  | 
    ||
538  | 
    small = (sizeof(st->st_ino) == 4);  | 
    ||
539  | 
    72  | 
    data = st->st_ino;  | 
    |
540  | 
    sdata = NULL;  | 
    ||
541  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;  | 
    ||
542  | 
    ✓✗ | 72  | 
    if (ofmt == 0)  | 
    
543  | 
    72  | 
    ofmt = FMTF_UNSIGNED;  | 
    |
544  | 
    break;  | 
    ||
545  | 
    case SHOW_st_mode:  | 
    ||
546  | 
    small = (sizeof(st->st_mode) == 4);  | 
    ||
547  | 
    1295  | 
    data = st->st_mode;  | 
    |
548  | 
    1295  | 
    strmode(st->st_mode, smode);  | 
    |
549  | 
    sdata = smode;  | 
    ||
550  | 
    1295  | 
    l = strlen(sdata);  | 
    |
551  | 
    ✓✗ | 1295  | 
    if (sdata[l - 1] == ' ')  | 
    
552  | 
    1295  | 
    sdata[--l] = '\0';  | 
    |
553  | 
    ✗✓ | 1295  | 
    		if (hilo == HIGH_PIECE) { | 
    
554  | 
    data >>= 12;  | 
    ||
555  | 
    sdata += 1;  | 
    ||
556  | 
    sdata[3] = '\0';  | 
    ||
557  | 
    hilo = 0;  | 
    ||
558  | 
    ✗✓ | 1295  | 
    		} else if (hilo == MIDDLE_PIECE) { | 
    
559  | 
    data = (data >> 9) & 07;  | 
    ||
560  | 
    sdata += 4;  | 
    ||
561  | 
    sdata[3] = '\0';  | 
    ||
562  | 
    hilo = 0;  | 
    ||
563  | 
    ✗✓ | 1295  | 
    		} else if (hilo == LOW_PIECE) { | 
    
564  | 
    data &= 0777;  | 
    ||
565  | 
    sdata += 7;  | 
    ||
566  | 
    sdata[3] = '\0';  | 
    ||
567  | 
    hilo = 0;  | 
    ||
568  | 
    }  | 
    ||
569  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |  | 
    ||
570  | 
    FMTF_STRING;  | 
    ||
571  | 
    ✓✗ | 1295  | 
    if (ofmt == 0)  | 
    
572  | 
    1295  | 
    ofmt = FMTF_OCTAL;  | 
    |
573  | 
    break;  | 
    ||
574  | 
    case SHOW_st_nlink:  | 
    ||
575  | 
    small = (sizeof(st->st_dev) == 4);  | 
    ||
576  | 
    data = st->st_nlink;  | 
    ||
577  | 
    sdata = NULL;  | 
    ||
578  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;  | 
    ||
579  | 
    if (ofmt == 0)  | 
    ||
580  | 
    ofmt = FMTF_UNSIGNED;  | 
    ||
581  | 
    break;  | 
    ||
582  | 
    case SHOW_st_uid:  | 
    ||
583  | 
    small = (sizeof(st->st_uid) == 4);  | 
    ||
584  | 
    268  | 
    data = st->st_uid;  | 
    |
585  | 
    ✓✗ | 268  | 
    if ((pw = getpwuid(st->st_uid)) != NULL)  | 
    
586  | 
    268  | 
    sdata = pw->pw_name;  | 
    |
587  | 
    		else { | 
    ||
588  | 
    snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_uid);  | 
    ||
589  | 
    sdata = sid;  | 
    ||
590  | 
    }  | 
    ||
591  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |  | 
    ||
592  | 
    FMTF_STRING;  | 
    ||
593  | 
    ✓✓ | 268  | 
    if (ofmt == 0)  | 
    
594  | 
    8  | 
    ofmt = FMTF_UNSIGNED;  | 
    |
595  | 
    break;  | 
    ||
596  | 
    case SHOW_st_gid:  | 
    ||
597  | 
    small = (sizeof(st->st_gid) == 4);  | 
    ||
598  | 
    268  | 
    data = st->st_gid;  | 
    |
599  | 
    ✓✗ | 268  | 
    if ((gr = getgrgid(st->st_gid)) != NULL)  | 
    
600  | 
    268  | 
    sdata = gr->gr_name;  | 
    |
601  | 
    		else { | 
    ||
602  | 
    snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_gid);  | 
    ||
603  | 
    sdata = sid;  | 
    ||
604  | 
    }  | 
    ||
605  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |  | 
    ||
606  | 
    FMTF_STRING;  | 
    ||
607  | 
    ✓✓ | 268  | 
    if (ofmt == 0)  | 
    
608  | 
    8  | 
    ofmt = FMTF_UNSIGNED;  | 
    |
609  | 
    break;  | 
    ||
610  | 
    case SHOW_st_atime:  | 
    ||
611  | 
    gottime = 1;  | 
    ||
612  | 
    secs = st->st_atime;  | 
    ||
613  | 
    nsecs = st->st_atimensec;  | 
    ||
614  | 
    /* FALLTHROUGH */  | 
    ||
615  | 
    case SHOW_st_mtime:  | 
    ||
616  | 
    		if (!gottime) { | 
    ||
617  | 
    gottime = 1;  | 
    ||
618  | 
    secs = st->st_mtime;  | 
    ||
619  | 
    nsecs = st->st_mtimensec;  | 
    ||
620  | 
    }  | 
    ||
621  | 
    /* FALLTHROUGH */  | 
    ||
622  | 
    case SHOW_st_ctime:  | 
    ||
623  | 
    		if (!gottime) { | 
    ||
624  | 
    gottime = 1;  | 
    ||
625  | 
    secs = st->st_ctime;  | 
    ||
626  | 
    nsecs = st->st_ctimensec;  | 
    ||
627  | 
    }  | 
    ||
628  | 
    /* FALLTHROUGH */  | 
    ||
629  | 
    case SHOW_st_btime:  | 
    ||
630  | 
    		if (!gottime) { | 
    ||
631  | 
    gottime = 1;  | 
    ||
632  | 
    secs = st->__st_birthtimespec.tv_sec;  | 
    ||
633  | 
    nsecs = st->__st_birthtimespec.tv_nsec;  | 
    ||
634  | 
    }  | 
    ||
635  | 
    small = (sizeof(secs) == 4);  | 
    ||
636  | 
    data = secs;  | 
    ||
637  | 
    small = 1;  | 
    ||
638  | 
    tm = localtime(&secs);  | 
    ||
639  | 
    (void)strftime(path, sizeof(path), timefmt, tm);  | 
    ||
640  | 
    sdata = path;  | 
    ||
641  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |  | 
    ||
642  | 
    FMTF_FLOAT | FMTF_STRING;  | 
    ||
643  | 
    if (ofmt == 0)  | 
    ||
644  | 
    ofmt = FMTF_DECIMAL;  | 
    ||
645  | 
    break;  | 
    ||
646  | 
    case SHOW_st_size:  | 
    ||
647  | 
    small = (sizeof(st->st_size) == 4);  | 
    ||
648  | 
    data = st->st_size;  | 
    ||
649  | 
    sdata = NULL;  | 
    ||
650  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;  | 
    ||
651  | 
    if (ofmt == 0)  | 
    ||
652  | 
    ofmt = FMTF_UNSIGNED;  | 
    ||
653  | 
    break;  | 
    ||
654  | 
    case SHOW_st_blocks:  | 
    ||
655  | 
    small = (sizeof(st->st_blocks) == 4);  | 
    ||
656  | 
    data = st->st_blocks;  | 
    ||
657  | 
    sdata = NULL;  | 
    ||
658  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;  | 
    ||
659  | 
    if (ofmt == 0)  | 
    ||
660  | 
    ofmt = FMTF_UNSIGNED;  | 
    ||
661  | 
    break;  | 
    ||
662  | 
    case SHOW_st_blksize:  | 
    ||
663  | 
    small = (sizeof(st->st_blksize) == 4);  | 
    ||
664  | 
    data = st->st_blksize;  | 
    ||
665  | 
    sdata = NULL;  | 
    ||
666  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;  | 
    ||
667  | 
    if (ofmt == 0)  | 
    ||
668  | 
    ofmt = FMTF_UNSIGNED;  | 
    ||
669  | 
    break;  | 
    ||
670  | 
    case SHOW_st_flags:  | 
    ||
671  | 
    small = (sizeof(st->st_flags) == 4);  | 
    ||
672  | 
    187  | 
    data = st->st_flags;  | 
    |
673  | 
    sdata = NULL;  | 
    ||
674  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;  | 
    ||
675  | 
    ✓✗ | 187  | 
    if (ofmt == 0)  | 
    
676  | 
    187  | 
    ofmt = FMTF_UNSIGNED;  | 
    |
677  | 
    break;  | 
    ||
678  | 
    case SHOW_st_gen:  | 
    ||
679  | 
    small = (sizeof(st->st_gen) == 4);  | 
    ||
680  | 
    data = st->st_gen;  | 
    ||
681  | 
    sdata = NULL;  | 
    ||
682  | 
    formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;  | 
    ||
683  | 
    if (ofmt == 0)  | 
    ||
684  | 
    ofmt = FMTF_UNSIGNED;  | 
    ||
685  | 
    break;  | 
    ||
686  | 
    case SHOW_symlink:  | 
    ||
687  | 
    small = 0;  | 
    ||
688  | 
    data = 0;  | 
    ||
689  | 
    		if (S_ISLNK(st->st_mode)) { | 
    ||
690  | 
    snprintf(path, sizeof(path), " -> ");  | 
    ||
691  | 
    l = readlink(file, path + 4, sizeof(path) - 4 - 1);  | 
    ||
692  | 
    			if (l == -1) { | 
    ||
693  | 
    l = 0;  | 
    ||
694  | 
    path[0] = '\0';  | 
    ||
695  | 
    }  | 
    ||
696  | 
    path[l + 4] = '\0';  | 
    ||
697  | 
    sdata = path + (ofmt == FMTF_STRING ? 0 : 4);  | 
    ||
698  | 
    } else  | 
    ||
699  | 
    sdata = "";  | 
    ||
700  | 
    |||
701  | 
    formats = FMTF_STRING;  | 
    ||
702  | 
    if (ofmt == 0)  | 
    ||
703  | 
    ofmt = FMTF_STRING;  | 
    ||
704  | 
    break;  | 
    ||
705  | 
    case SHOW_filetype:  | 
    ||
706  | 
    small = 0;  | 
    ||
707  | 
    data = 0;  | 
    ||
708  | 
    sdata = smode;  | 
    ||
709  | 
    sdata[0] = '\0';  | 
    ||
710  | 
    		if (hilo == 0 || hilo == LOW_PIECE) { | 
    ||
711  | 
    			switch (st->st_mode & S_IFMT) { | 
    ||
712  | 
    case S_IFIFO:  | 
    ||
713  | 
    (void)strlcat(sdata, "|", sizeof(smode));  | 
    ||
714  | 
    break;  | 
    ||
715  | 
    case S_IFDIR:  | 
    ||
716  | 
    (void)strlcat(sdata, "/", sizeof(smode));  | 
    ||
717  | 
    break;  | 
    ||
718  | 
    case S_IFREG:  | 
    ||
719  | 
    if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))  | 
    ||
720  | 
    (void)strlcat(sdata, "*",  | 
    ||
721  | 
    sizeof(smode));  | 
    ||
722  | 
    break;  | 
    ||
723  | 
    case S_IFLNK:  | 
    ||
724  | 
    (void)strlcat(sdata, "@", sizeof(smode));  | 
    ||
725  | 
    break;  | 
    ||
726  | 
    case S_IFSOCK:  | 
    ||
727  | 
    (void)strlcat(sdata, "=", sizeof(smode));  | 
    ||
728  | 
    break;  | 
    ||
729  | 
    }  | 
    ||
730  | 
    hilo = 0;  | 
    ||
731  | 
    		} else if (hilo == HIGH_PIECE) { | 
    ||
732  | 
    			switch (st->st_mode & S_IFMT) { | 
    ||
733  | 
    case S_IFIFO: sdata = "Fifo File"; break;  | 
    ||
734  | 
    case S_IFCHR: sdata = "Character Device"; break;  | 
    ||
735  | 
    case S_IFDIR: sdata = "Directory"; break;  | 
    ||
736  | 
    case S_IFBLK: sdata = "Block Device"; break;  | 
    ||
737  | 
    case S_IFREG: sdata = "Regular File"; break;  | 
    ||
738  | 
    case S_IFLNK: sdata = "Symbolic Link"; break;  | 
    ||
739  | 
    case S_IFSOCK: sdata = "Socket"; break;  | 
    ||
740  | 
    default: sdata = "???"; break;  | 
    ||
741  | 
    }  | 
    ||
742  | 
    hilo = 0;  | 
    ||
743  | 
    }  | 
    ||
744  | 
    formats = FMTF_STRING;  | 
    ||
745  | 
    if (ofmt == 0)  | 
    ||
746  | 
    ofmt = FMTF_STRING;  | 
    ||
747  | 
    break;  | 
    ||
748  | 
    case SHOW_filename:  | 
    ||
749  | 
    small = 0;  | 
    ||
750  | 
    data = 0;  | 
    ||
751  | 
    if (file == NULL)  | 
    ||
752  | 
    (void)strlcpy(path, "(stdin)", sizeof(path));  | 
    ||
753  | 
    else  | 
    ||
754  | 
    (void)strlcpy(path, file, sizeof(path));  | 
    ||
755  | 
    sdata = path;  | 
    ||
756  | 
    formats = FMTF_STRING;  | 
    ||
757  | 
    if (ofmt == 0)  | 
    ||
758  | 
    ofmt = FMTF_STRING;  | 
    ||
759  | 
    break;  | 
    ||
760  | 
    case SHOW_sizerdev:  | 
    ||
761  | 
    		if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { | 
    ||
762  | 
    char majdev[20], mindev[20];  | 
    ||
763  | 
    int l1, l2;  | 
    ||
764  | 
    |||
765  | 
    l1 = format1(st, file, fmt, flen,  | 
    ||
766  | 
    majdev, sizeof(majdev), flags, size, prec,  | 
    ||
767  | 
    ofmt, HIGH_PIECE, SHOW_st_rdev);  | 
    ||
768  | 
    l2 = format1(st, file, fmt, flen,  | 
    ||
769  | 
    mindev, sizeof(mindev), flags, size, prec,  | 
    ||
770  | 
    ofmt, LOW_PIECE, SHOW_st_rdev);  | 
    ||
771  | 
    n = snprintf(buf, blen, "%.*s,%.*s",  | 
    ||
772  | 
    l1, majdev, l2, mindev);  | 
    ||
773  | 
    return (n >= blen ? blen : n);  | 
    ||
774  | 
    		} else { | 
    ||
775  | 
    return (format1(st, file, fmt, flen, buf, blen,  | 
    ||
776  | 
    flags, size, prec, ofmt, 0, SHOW_st_size));  | 
    ||
777  | 
    }  | 
    ||
778  | 
    /*NOTREACHED*/  | 
    ||
779  | 
    default:  | 
    ||
780  | 
    errx(1, "%.*s: bad format", (int)flen, fmt);  | 
    ||
781  | 
    }  | 
    ||
782  | 
    |||
783  | 
    /*  | 
    ||
784  | 
    * If a subdatum was specified but not supported, or an output  | 
    ||
785  | 
    * format was selected that is not supported, that's an error.  | 
    ||
786  | 
    */  | 
    ||
787  | 
    ✓✗✗✓ | 
    4324  | 
    if (hilo != 0 || (ofmt & formats) == 0)  | 
    
788  | 
    errx(1, "%.*s: bad format", (int)flen, fmt);  | 
    ||
789  | 
    |||
790  | 
    /*  | 
    ||
791  | 
    * Assemble the format string for passing to printf(3).  | 
    ||
792  | 
    */  | 
    ||
793  | 
    2162  | 
    lfmt[0] = '\0';  | 
    |
794  | 
    2162  | 
    (void)strlcat(lfmt, "%", sizeof(lfmt));  | 
    |
795  | 
    ✗✓ | 2162  | 
    if (flags & FLAG_POUND)  | 
    
796  | 
    (void)strlcat(lfmt, "#", sizeof(lfmt));  | 
    ||
797  | 
    ✗✓ | 2162  | 
    if (flags & FLAG_SPACE)  | 
    
798  | 
    (void)strlcat(lfmt, " ", sizeof(lfmt));  | 
    ||
799  | 
    ✗✓ | 2162  | 
    if (flags & FLAG_PLUS)  | 
    
800  | 
    (void)strlcat(lfmt, "+", sizeof(lfmt));  | 
    ||
801  | 
    ✗✓ | 2162  | 
    if (flags & FLAG_MINUS)  | 
    
802  | 
    (void)strlcat(lfmt, "-", sizeof(lfmt));  | 
    ||
803  | 
    ✗✓ | 2162  | 
    if (flags & FLAG_ZERO)  | 
    
804  | 
    (void)strlcat(lfmt, "0", sizeof(lfmt));  | 
    ||
805  | 
    |||
806  | 
    /*  | 
    ||
807  | 
    * Only the timespecs support the FLOAT output format, and that  | 
    ||
808  | 
    * requires work that differs from the other formats.  | 
    ||
809  | 
    */  | 
    ||
810  | 
    ✗✓ | 2162  | 
    	if (ofmt == FMTF_FLOAT) { | 
    
811  | 
    /*  | 
    ||
812  | 
    * Nothing after the decimal point, so just print seconds.  | 
    ||
813  | 
    */  | 
    ||
814  | 
    		if (prec == 0) { | 
    ||
815  | 
    			if (size != -1) { | 
    ||
816  | 
    (void)snprintf(tmp, sizeof(tmp), "%d", size);  | 
    ||
817  | 
    (void)strlcat(lfmt, tmp, sizeof(lfmt));  | 
    ||
818  | 
    }  | 
    ||
819  | 
    (void)strlcat(lfmt, "d", sizeof(lfmt));  | 
    ||
820  | 
    n = snprintf(buf, blen, lfmt, secs);  | 
    ||
821  | 
    return (n >= blen ? blen : n);  | 
    ||
822  | 
    }  | 
    ||
823  | 
    |||
824  | 
    /*  | 
    ||
825  | 
    * Unspecified precision gets all the precision we have:  | 
    ||
826  | 
    * 9 digits.  | 
    ||
827  | 
    */  | 
    ||
828  | 
    if (prec == -1)  | 
    ||
829  | 
    prec = 9;  | 
    ||
830  | 
    |||
831  | 
    /*  | 
    ||
832  | 
    * Adjust the size for the decimal point and the digits  | 
    ||
833  | 
    * that will follow.  | 
    ||
834  | 
    */  | 
    ||
835  | 
    size -= prec + 1;  | 
    ||
836  | 
    |||
837  | 
    /*  | 
    ||
838  | 
    * Any leftover size that's legitimate will be used.  | 
    ||
839  | 
    */  | 
    ||
840  | 
    		if (size > 0) { | 
    ||
841  | 
    (void)snprintf(tmp, sizeof(tmp), "%d", size);  | 
    ||
842  | 
    (void)strlcat(lfmt, tmp, sizeof(lfmt));  | 
    ||
843  | 
    }  | 
    ||
844  | 
    (void)strlcat(lfmt, "d", sizeof(lfmt));  | 
    ||
845  | 
    |||
846  | 
    /*  | 
    ||
847  | 
    * The stuff after the decimal point always needs zero  | 
    ||
848  | 
    * filling.  | 
    ||
849  | 
    */  | 
    ||
850  | 
    (void)strlcat(lfmt, ".%0", sizeof(lfmt));  | 
    ||
851  | 
    |||
852  | 
    /*  | 
    ||
853  | 
    * We can "print" at most nine digits of precision. The  | 
    ||
854  | 
    * rest we will pad on at the end.  | 
    ||
855  | 
    */  | 
    ||
856  | 
    (void)snprintf(tmp, sizeof(tmp), "%dd", prec > 9 ? 9 : prec);  | 
    ||
857  | 
    (void)strlcat(lfmt, tmp, sizeof(lfmt));  | 
    ||
858  | 
    |||
859  | 
    /*  | 
    ||
860  | 
    * For precision of less that nine digits, trim off the  | 
    ||
861  | 
    * less significant figures.  | 
    ||
862  | 
    */  | 
    ||
863  | 
    for (; prec < 9; prec++)  | 
    ||
864  | 
    nsecs /= 10;  | 
    ||
865  | 
    |||
866  | 
    /*  | 
    ||
867  | 
    * Use the format, and then tack on any zeroes that  | 
    ||
868  | 
    * might be required to make up the requested precision.  | 
    ||
869  | 
    */  | 
    ||
870  | 
    l = snprintf(buf, blen, lfmt, secs, nsecs);  | 
    ||
871  | 
    if (l >= blen)  | 
    ||
872  | 
    return (l);  | 
    ||
873  | 
    for (; prec > 9 && l < blen; prec--, l++)  | 
    ||
874  | 
    (void)strlcat(buf, "0", blen);  | 
    ||
875  | 
    return (l);  | 
    ||
876  | 
    }  | 
    ||
877  | 
    |||
878  | 
    /*  | 
    ||
879  | 
    * Add on size and precision, if specified, to the format.  | 
    ||
880  | 
    */  | 
    ||
881  | 
    ✗✓ | 2162  | 
    	if (size != -1) { | 
    
882  | 
    (void)snprintf(tmp, sizeof(tmp), "%d", size);  | 
    ||
883  | 
    (void)strlcat(lfmt, tmp, sizeof(lfmt));  | 
    ||
884  | 
    }  | 
    ||
885  | 
    ✗✓ | 2162  | 
    	if (prec != -1) { | 
    
886  | 
    (void)snprintf(tmp, sizeof(tmp), ".%d", prec);  | 
    ||
887  | 
    (void)strlcat(lfmt, tmp, sizeof(lfmt));  | 
    ||
888  | 
    }  | 
    ||
889  | 
    |||
890  | 
    /*  | 
    ||
891  | 
    * String output uses the temporary sdata.  | 
    ||
892  | 
    */  | 
    ||
893  | 
    ✓✓ | 2162  | 
    	if (ofmt == FMTF_STRING) { | 
    
894  | 
    ✗✓ | 520  | 
    if (sdata == NULL)  | 
    
895  | 
    errx(1, "%.*s: bad format", (int)flen, fmt);  | 
    ||
896  | 
    520  | 
    (void)strlcat(lfmt, "s", sizeof(lfmt));  | 
    |
897  | 
    520  | 
    n = snprintf(buf, blen, lfmt, sdata);  | 
    |
898  | 
    520  | 
    return (n >= blen ? blen : n);  | 
    |
899  | 
    }  | 
    ||
900  | 
    |||
901  | 
    /*  | 
    ||
902  | 
    * Ensure that sign extension does not cause bad looking output  | 
    ||
903  | 
    * for some forms.  | 
    ||
904  | 
    */  | 
    ||
905  | 
    ✓✓ | 1642  | 
    if (small && ofmt != FMTF_DECIMAL)  | 
    
906  | 
    1570  | 
    data = (u_int32_t)data;  | 
    |
907  | 
    |||
908  | 
    /*  | 
    ||
909  | 
    * The four "numeric" output forms.  | 
    ||
910  | 
    */  | 
    ||
911  | 
    3284  | 
    (void)strlcat(lfmt, "ll", sizeof(lfmt));  | 
    |
912  | 
    ✗✓✓✗ ✓  | 
    3284  | 
    	switch (ofmt) { | 
    
913  | 
    case FMTF_DECIMAL: (void)strlcat(lfmt, "d", sizeof(lfmt)); break;  | 
    ||
914  | 
    1295  | 
    case FMTF_OCTAL: (void)strlcat(lfmt, "o", sizeof(lfmt)); break;  | 
    |
915  | 
    347  | 
    case FMTF_UNSIGNED: (void)strlcat(lfmt, "u", sizeof(lfmt)); break;  | 
    |
916  | 
    case FMTF_HEX: (void)strlcat(lfmt, "x", sizeof(lfmt)); break;  | 
    ||
917  | 
    }  | 
    ||
918  | 
    |||
919  | 
    1642  | 
    n = snprintf(buf, blen, lfmt, data);  | 
    |
920  | 
    1642  | 
    return (n >= blen ? blen : n);  | 
    |
921  | 
    2162  | 
    }  | 
    
| Generated by: GCOVR (Version 3.3) |