| File: | src/usr.bin/stat/stat.c | 
| Warning: | line 632, column 4 Value stored to 'gottime' is never read | 
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: stat.c,v 1.25 2023/08/06 19:36:13 guenther 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_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_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_ctim.tv_nsec; | 
| 628 | } | 
| 629 | /* FALLTHROUGH */ | 
| 630 | case SHOW_st_btime'B': | 
| 631 | if (!gottime) { | 
| 632 | gottime = 1; | 
| Value stored to 'gottime' is never read | |
| 633 | secs = st->__st_birthtime__st_birthtim.tv_sec; | 
| 634 | nsecs = st->__st_birthtim.tv_nsec; | 
| 635 | } | 
| 636 | small = (sizeof(secs) == 4); | 
| 637 | data = secs; | 
| 638 | tm = localtime(&secs); | 
| 639 | (void)strftime(path, sizeof(path), timefmt, tm); | 
| 640 | sdata = path; | 
| 641 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08 | | 
| 642 | FMTF_FLOAT0x10 | FMTF_STRING0x20; | 
| 643 | if (ofmt == 0) | 
| 644 | ofmt = FMTF_DECIMAL0x01; | 
| 645 | break; | 
| 646 | case SHOW_st_size'z': | 
| 647 | small = (sizeof(st->st_size) == 4); | 
| 648 | data = st->st_size; | 
| 649 | sdata = NULL((void *)0); | 
| 650 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; | 
| 651 | if (ofmt == 0) | 
| 652 | ofmt = FMTF_UNSIGNED0x04; | 
| 653 | break; | 
| 654 | case SHOW_st_blocks'b': | 
| 655 | small = (sizeof(st->st_blocks) == 4); | 
| 656 | data = st->st_blocks; | 
| 657 | sdata = NULL((void *)0); | 
| 658 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; | 
| 659 | if (ofmt == 0) | 
| 660 | ofmt = FMTF_UNSIGNED0x04; | 
| 661 | break; | 
| 662 | case SHOW_st_blksize'k': | 
| 663 | small = (sizeof(st->st_blksize) == 4); | 
| 664 | data = st->st_blksize; | 
| 665 | sdata = NULL((void *)0); | 
| 666 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; | 
| 667 | if (ofmt == 0) | 
| 668 | ofmt = FMTF_UNSIGNED0x04; | 
| 669 | break; | 
| 670 | case SHOW_st_flags'f': | 
| 671 | small = (sizeof(st->st_flags) == 4); | 
| 672 | data = st->st_flags; | 
| 673 | sdata = NULL((void *)0); | 
| 674 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; | 
| 675 | if (ofmt == 0) | 
| 676 | ofmt = FMTF_UNSIGNED0x04; | 
| 677 | break; | 
| 678 | case SHOW_st_gen'v': | 
| 679 | small = (sizeof(st->st_gen) == 4); | 
| 680 | data = st->st_gen; | 
| 681 | sdata = NULL((void *)0); | 
| 682 | formats = FMTF_DECIMAL0x01 | FMTF_OCTAL0x02 | FMTF_UNSIGNED0x04 | FMTF_HEX0x08; | 
| 683 | if (ofmt == 0) | 
| 684 | ofmt = FMTF_UNSIGNED0x04; | 
| 685 | break; | 
| 686 | case SHOW_symlink'Y': | 
| 687 | small = 0; | 
| 688 | data = 0; | 
| 689 | if (S_ISLNK(st->st_mode)((st->st_mode & 0170000) == 0120000)) { | 
| 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_STRING0x20 ? 0 : 4); | 
| 698 | } else | 
| 699 | sdata = ""; | 
| 700 | |
| 701 | formats = FMTF_STRING0x20; | 
| 702 | if (ofmt == 0) | 
| 703 | ofmt = FMTF_STRING0x20; | 
| 704 | break; | 
| 705 | case SHOW_filetype'T': | 
| 706 | small = 0; | 
| 707 | data = 0; | 
| 708 | sdata = smode; | 
| 709 | smode[0] = '\0'; | 
| 710 | if (hilo == 0 || hilo == LOW_PIECE'L') { | 
| 711 | switch (st->st_mode & S_IFMT0170000) { | 
| 712 | case S_IFIFO0010000: | 
| 713 | (void)strlcat(smode, "|", sizeof(smode)); | 
| 714 | break; | 
| 715 | case S_IFDIR0040000: | 
| 716 | (void)strlcat(smode, "/", sizeof(smode)); | 
| 717 | break; | 
| 718 | case S_IFREG0100000: | 
| 719 | if (st->st_mode & (S_IXUSR0000100 | S_IXGRP0000010 | S_IXOTH0000001)) | 
| 720 | (void)strlcat(smode, "*", | 
| 721 | sizeof(smode)); | 
| 722 | break; | 
| 723 | case S_IFLNK0120000: | 
| 724 | (void)strlcat(smode, "@", sizeof(smode)); | 
| 725 | break; | 
| 726 | case S_IFSOCK0140000: | 
| 727 | (void)strlcat(smode, "=", sizeof(smode)); | 
| 728 | break; | 
| 729 | } | 
| 730 | hilo = 0; | 
| 731 | } else if (hilo == HIGH_PIECE'H') { | 
| 732 | switch (st->st_mode & S_IFMT0170000) { | 
| 733 | case S_IFIFO0010000: sdata = "Fifo File"; break; | 
| 734 | case S_IFCHR0020000: sdata = "Character Device"; break; | 
| 735 | case S_IFDIR0040000: sdata = "Directory"; break; | 
| 736 | case S_IFBLK0060000: sdata = "Block Device"; break; | 
| 737 | case S_IFREG0100000: sdata = "Regular File"; break; | 
| 738 | case S_IFLNK0120000: sdata = "Symbolic Link"; break; | 
| 739 | case S_IFSOCK0140000: sdata = "Socket"; break; | 
| 740 | default: sdata = "???"; break; | 
| 741 | } | 
| 742 | hilo = 0; | 
| 743 | } | 
| 744 | formats = FMTF_STRING0x20; | 
| 745 | if (ofmt == 0) | 
| 746 | ofmt = FMTF_STRING0x20; | 
| 747 | break; | 
| 748 | case SHOW_filename'N': | 
| 749 | small = 0; | 
| 750 | data = 0; | 
| 751 | if (file == NULL((void *)0)) | 
| 752 | (void)strlcpy(path, "(stdin)", sizeof(path)); | 
| 753 | else | 
| 754 | (void)strlcpy(path, file, sizeof(path)); | 
| 755 | sdata = path; | 
| 756 | formats = FMTF_STRING0x20; | 
| 757 | if (ofmt == 0) | 
| 758 | ofmt = FMTF_STRING0x20; | 
| 759 | break; | 
| 760 | case SHOW_sizerdev'Z': | 
| 761 | if (S_ISCHR(st->st_mode)((st->st_mode & 0170000) == 0020000) || S_ISBLK(st->st_mode)((st->st_mode & 0170000) == 0060000)) { | 
| 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'H', SHOW_st_rdev'r'); | 
| 768 | l2 = format1(st, file, fmt, flen, | 
| 769 | mindev, sizeof(mindev), flags, size, prec, | 
| 770 | ofmt, LOW_PIECE'L', SHOW_st_rdev'r'); | 
| 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'z')); | 
| 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 | 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 | lfmt[0] = '\0'; | 
| 794 | (void)strlcat(lfmt, "%", sizeof(lfmt)); | 
| 795 | if (flags & FLAG_POUND0x01) | 
| 796 | (void)strlcat(lfmt, "#", sizeof(lfmt)); | 
| 797 | if (flags & FLAG_SPACE0x02) | 
| 798 | (void)strlcat(lfmt, " ", sizeof(lfmt)); | 
| 799 | if (flags & FLAG_PLUS0x04) | 
| 800 | (void)strlcat(lfmt, "+", sizeof(lfmt)); | 
| 801 | if (flags & FLAG_MINUS0x10) | 
| 802 | (void)strlcat(lfmt, "-", sizeof(lfmt)); | 
| 803 | if (flags & FLAG_ZERO0x08) | 
| 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 | if (ofmt == FMTF_FLOAT0x10) { | 
| 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, "lld", sizeof(lfmt)); | 
| 820 | n = snprintf(buf, blen, lfmt, (long long)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, "lld", 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), "%dld", 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, (long long)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 | if (size != -1) { | 
| 882 | (void)snprintf(tmp, sizeof(tmp), "%d", size); | 
| 883 | (void)strlcat(lfmt, tmp, sizeof(lfmt)); | 
| 884 | } | 
| 885 | 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 | if (ofmt == FMTF_STRING0x20) { | 
| 894 | if (sdata == NULL((void *)0)) | 
| 895 | errx(1, "%.*s: bad format", (int)flen, fmt); | 
| 896 | (void)strlcat(lfmt, "s", sizeof(lfmt)); | 
| 897 | n = snprintf(buf, blen, lfmt, sdata); | 
| 898 | 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 | if (small && ofmt != FMTF_DECIMAL0x01) | 
| 906 | data = (u_int32_t)data; | 
| 907 | |
| 908 | /* | 
| 909 | * The four "numeric" output forms. | 
| 910 | */ | 
| 911 | (void)strlcat(lfmt, "ll", sizeof(lfmt)); | 
| 912 | switch (ofmt) { | 
| 913 | case FMTF_DECIMAL0x01: (void)strlcat(lfmt, "d", sizeof(lfmt)); break; | 
| 914 | case FMTF_OCTAL0x02: (void)strlcat(lfmt, "o", sizeof(lfmt)); break; | 
| 915 | case FMTF_UNSIGNED0x04: (void)strlcat(lfmt, "u", sizeof(lfmt)); break; | 
| 916 | case FMTF_HEX0x08: (void)strlcat(lfmt, "x", sizeof(lfmt)); break; | 
| 917 | } | 
| 918 | |
| 919 | n = snprintf(buf, blen, lfmt, data); | 
| 920 | return (n >= blen ? blen : n); | 
| 921 | } |