source: MondoRescue/branches/3.3/mindi-busybox/coreutils/stat.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 23.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * stat -- display file or file system status
4 *
5 * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation.
6 * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
7 * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
8 * Copyright (C) 2006 by Yoshinori Sato <ysato@users.sourceforge.jp>
9 *
10 * Written by Michael Meskes
11 * Taken from coreutils and turned into a busybox applet by Mike Frysinger
12 *
13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
14 */
15//config:config STAT
16//config: bool "stat"
17//config: default y
18//config: help
19//config: display file or filesystem status.
20//config:
21//config:config FEATURE_STAT_FORMAT
22//config: bool "Enable custom formats (-c)"
23//config: default y
24//config: depends on STAT
25//config: help
26//config: Without this, stat will not support the '-c format' option where
27//config: users can pass a custom format string for output. This adds about
28//config: 7k to a nonstatic build on amd64.
29//config:
30//config:config FEATURE_STAT_FILESYSTEM
31//config: bool "Enable display of filesystem status (-f)"
32//config: default y
33//config: depends on STAT
34//config: select PLATFORM_LINUX # statfs()
35//config: help
36//config: Without this, stat will not support the '-f' option to display
37//config: information about filesystem status.
38
39
40//usage:#define stat_trivial_usage
41//usage: "[OPTIONS] FILE..."
42//usage:#define stat_full_usage "\n\n"
43//usage: "Display file"
44//usage: IF_FEATURE_STAT_FILESYSTEM(" (default) or filesystem")
45//usage: " status\n"
46//usage: IF_FEATURE_STAT_FORMAT(
47//usage: "\n -c FMT Use the specified format"
48//usage: )
49//usage: IF_FEATURE_STAT_FILESYSTEM(
50//usage: "\n -f Display filesystem status"
51//usage: )
52//usage: "\n -L Follow links"
53//usage: "\n -t Terse display"
54//usage: IF_SELINUX(
55//usage: "\n -Z Print security context"
56//usage: )
57//usage: IF_FEATURE_STAT_FORMAT(
58//usage: "\n\nFMT sequences"IF_FEATURE_STAT_FILESYSTEM(" for files")":\n"
59//usage: " %a Access rights in octal\n"
60//usage: " %A Access rights in human readable form\n"
61//usage: " %b Number of blocks allocated (see %B)\n"
62//usage: " %B Size in bytes of each block reported by %b\n"
63//usage: " %d Device number in decimal\n"
64//usage: " %D Device number in hex\n"
65//usage: " %f Raw mode in hex\n"
66//usage: " %F File type\n"
67//usage: " %g Group ID\n"
68//usage: " %G Group name\n"
69//usage: " %h Number of hard links\n"
70//usage: " %i Inode number\n"
71//usage: " %n File name\n"
72//usage: " %N File name, with -> TARGET if symlink\n"
73//usage: " %o I/O block size\n"
74//usage: " %s Total size in bytes\n"
75//usage: " %t Major device type in hex\n"
76//usage: " %T Minor device type in hex\n"
77//usage: " %u User ID\n"
78//usage: " %U User name\n"
79//usage: " %x Time of last access\n"
80//usage: " %X Time of last access as seconds since Epoch\n"
81//usage: " %y Time of last modification\n"
82//usage: " %Y Time of last modification as seconds since Epoch\n"
83//usage: " %z Time of last change\n"
84//usage: " %Z Time of last change as seconds since Epoch\n"
85//usage: IF_FEATURE_STAT_FILESYSTEM(
86//usage: "\nFMT sequences for file systems:\n"
87//usage: " %a Free blocks available to non-superuser\n"
88//usage: " %b Total data blocks\n"
89//usage: " %c Total file nodes\n"
90//usage: " %d Free file nodes\n"
91//usage: " %f Free blocks\n"
92//usage: IF_SELINUX(
93//usage: " %C Security context in selinux\n"
94//usage: )
95//usage: " %i File System ID in hex\n"
96//usage: " %l Maximum length of filenames\n"
97//usage: " %n File name\n"
98//usage: " %s Block size (for faster transfer)\n"
99//usage: " %S Fundamental block size (for block counts)\n"
100//usage: " %t Type in hex\n"
101//usage: " %T Type in human readable form"
102//usage: )
103//usage: )
104
105#include "libbb.h"
106#include "common_bufsiz.h"
107
108enum {
109 OPT_TERSE = (1 << 0),
110 OPT_DEREFERENCE = (1 << 1),
111 OPT_FILESYS = (1 << 2) * ENABLE_FEATURE_STAT_FILESYSTEM,
112 OPT_SELINUX = (1 << (2+ENABLE_FEATURE_STAT_FILESYSTEM)) * ENABLE_SELINUX,
113};
114
115#if ENABLE_FEATURE_STAT_FORMAT
116typedef bool (*statfunc_ptr)(const char *, const char *);
117#else
118typedef bool (*statfunc_ptr)(const char *);
119#endif
120
121static const char *file_type(const struct stat *st)
122{
123 /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107
124 * for some of these formats.
125 * To keep diagnostics grammatical in English, the
126 * returned string must start with a consonant.
127 */
128 if (S_ISREG(st->st_mode)) return st->st_size == 0 ? "regular empty file" : "regular file";
129 if (S_ISDIR(st->st_mode)) return "directory";
130 if (S_ISBLK(st->st_mode)) return "block special file";
131 if (S_ISCHR(st->st_mode)) return "character special file";
132 if (S_ISFIFO(st->st_mode)) return "fifo";
133 if (S_ISLNK(st->st_mode)) return "symbolic link";
134 if (S_ISSOCK(st->st_mode)) return "socket";
135#ifdef S_TYPEISMQ
136 if (S_TYPEISMQ(st)) return "message queue";
137#endif
138#ifdef S_TYPEISSEM
139 if (S_TYPEISSEM(st)) return "semaphore";
140#endif
141#ifdef S_TYPEISSHM
142 if (S_TYPEISSHM(st)) return "shared memory object";
143#endif
144#ifdef S_TYPEISTMO
145 if (S_TYPEISTMO(st)) return "typed memory object";
146#endif
147 return "weird file";
148}
149
150static const char *human_time(time_t t)
151{
152 /* Old
153 static char *str;
154 str = ctime(&t);
155 str[strlen(str)-1] = '\0';
156 return str;
157 */
158 /* coreutils 6.3 compat: */
159
160 /*static char buf[sizeof("YYYY-MM-DD HH:MM:SS.000000000")] ALIGN1;*/
161#define buf bb_common_bufsiz1
162 setup_common_bufsiz();
163 strcpy(strftime_YYYYMMDDHHMMSS(buf, COMMON_BUFSIZE, &t), ".000000000");
164 return buf;
165#undef buf
166}
167
168#if ENABLE_FEATURE_STAT_FILESYSTEM
169/* Return the type of the specified file system.
170 * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
171 * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
172 * Still others have neither and have to get by with f_type (Linux).
173 */
174static const char *human_fstype(uint32_t f_type)
175{
176 static const struct types {
177 uint32_t type;
178 const char *const fs;
179 } humantypes[] = {
180 { 0xADFF, "affs" },
181 { 0x1Cd1, "devpts" },
182 { 0x137D, "ext" },
183 { 0xEF51, "ext2" },
184 { 0xEF53, "ext2/ext3" },
185 { 0x3153464a, "jfs" },
186 { 0x58465342, "xfs" },
187 { 0xF995E849, "hpfs" },
188 { 0x9660, "isofs" },
189 { 0x4000, "isofs" },
190 { 0x4004, "isofs" },
191 { 0x137F, "minix" },
192 { 0x138F, "minix (30 char.)" },
193 { 0x2468, "minix v2" },
194 { 0x2478, "minix v2 (30 char.)" },
195 { 0x4d44, "msdos" },
196 { 0x4006, "fat" },
197 { 0x564c, "novell" },
198 { 0x6969, "nfs" },
199 { 0x9fa0, "proc" },
200 { 0x517B, "smb" },
201 { 0x012FF7B4, "xenix" },
202 { 0x012FF7B5, "sysv4" },
203 { 0x012FF7B6, "sysv2" },
204 { 0x012FF7B7, "coh" },
205 { 0x00011954, "ufs" },
206 { 0x012FD16D, "xia" },
207 { 0x5346544e, "ntfs" },
208 { 0x1021994, "tmpfs" },
209 { 0x52654973, "reiserfs" },
210 { 0x28cd3d45, "cramfs" },
211 { 0x7275, "romfs" },
212 { 0x858458f6, "romfs" },
213 { 0x73717368, "squashfs" },
214 { 0x62656572, "sysfs" },
215 { 0, "UNKNOWN" }
216 };
217
218 int i;
219
220 for (i = 0; humantypes[i].type; ++i)
221 if (humantypes[i].type == f_type)
222 break;
223 return humantypes[i].fs;
224}
225
226/* "man statfs" says that statfsbuf->f_fsid is a mess */
227/* coreutils treats it as an array of ints, most significant first */
228static unsigned long long get_f_fsid(const struct statfs *statfsbuf)
229{
230 const unsigned *p = (const void*) &statfsbuf->f_fsid;
231 unsigned sz = sizeof(statfsbuf->f_fsid) / sizeof(unsigned);
232 unsigned long long r = 0;
233
234 do
235 r = (r << (sizeof(unsigned)*8)) | *p++;
236 while (--sz > 0);
237 return r;
238}
239#endif /* FEATURE_STAT_FILESYSTEM */
240
241#if ENABLE_FEATURE_STAT_FORMAT
242static void strcatc(char *str, char c)
243{
244 int len = strlen(str);
245 str[len++] = c;
246 str[len] = '\0';
247}
248
249static void printfs(char *pformat, const char *msg)
250{
251 strcatc(pformat, 's');
252 printf(pformat, msg);
253}
254
255#if ENABLE_FEATURE_STAT_FILESYSTEM
256/* print statfs info */
257static void FAST_FUNC print_statfs(char *pformat, const char m,
258 const char *const filename, const void *data
259 IF_SELINUX(, security_context_t scontext))
260{
261 const struct statfs *statfsbuf = data;
262 if (m == 'n') {
263 printfs(pformat, filename);
264 } else if (m == 'i') {
265 strcat(pformat, "llx");
266 printf(pformat, get_f_fsid(statfsbuf));
267 } else if (m == 'l') {
268 strcat(pformat, "lu");
269 printf(pformat, (unsigned long) statfsbuf->f_namelen);
270 } else if (m == 't') {
271 strcat(pformat, "lx");
272 printf(pformat, (unsigned long) statfsbuf->f_type); /* no equiv */
273 } else if (m == 'T') {
274 printfs(pformat, human_fstype(statfsbuf->f_type));
275 } else if (m == 'b') {
276 strcat(pformat, "llu");
277 printf(pformat, (unsigned long long) statfsbuf->f_blocks);
278 } else if (m == 'f') {
279 strcat(pformat, "llu");
280 printf(pformat, (unsigned long long) statfsbuf->f_bfree);
281 } else if (m == 'a') {
282 strcat(pformat, "llu");
283 printf(pformat, (unsigned long long) statfsbuf->f_bavail);
284 } else if (m == 's' || m == 'S') {
285 strcat(pformat, "lu");
286 printf(pformat, (unsigned long) statfsbuf->f_bsize);
287 } else if (m == 'c') {
288 strcat(pformat, "llu");
289 printf(pformat, (unsigned long long) statfsbuf->f_files);
290 } else if (m == 'd') {
291 strcat(pformat, "llu");
292 printf(pformat, (unsigned long long) statfsbuf->f_ffree);
293# if ENABLE_SELINUX
294 } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) {
295 printfs(pformat, scontext);
296# endif
297 } else {
298 strcatc(pformat, 'c');
299 printf(pformat, m);
300 }
301}
302#endif
303
304/* print stat info */
305static void FAST_FUNC print_stat(char *pformat, const char m,
306 const char *const filename, const void *data
307 IF_SELINUX(, security_context_t scontext))
308{
309#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
310 struct stat *statbuf = (struct stat *) data;
311 struct passwd *pw_ent;
312 struct group *gw_ent;
313
314 if (m == 'n') {
315 printfs(pformat, filename);
316 } else if (m == 'N') {
317 strcatc(pformat, 's');
318 if (S_ISLNK(statbuf->st_mode)) {
319 char *linkname = xmalloc_readlink_or_warn(filename);
320 if (linkname == NULL)
321 return;
322 printf("'%s' -> '%s'", filename, linkname);
323 free(linkname);
324 } else {
325 printf(pformat, filename);
326 }
327 } else if (m == 'd') {
328 strcat(pformat, "llu");
329 printf(pformat, (unsigned long long) statbuf->st_dev);
330 } else if (m == 'D') {
331 strcat(pformat, "llx");
332 printf(pformat, (unsigned long long) statbuf->st_dev);
333 } else if (m == 'i') {
334 strcat(pformat, "llu");
335 printf(pformat, (unsigned long long) statbuf->st_ino);
336 } else if (m == 'a') {
337 strcat(pformat, "lo");
338 printf(pformat, (unsigned long) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)));
339 } else if (m == 'A') {
340 printfs(pformat, bb_mode_string(statbuf->st_mode));
341 } else if (m == 'f') {
342 strcat(pformat, "lx");
343 printf(pformat, (unsigned long) statbuf->st_mode);
344 } else if (m == 'F') {
345 printfs(pformat, file_type(statbuf));
346 } else if (m == 'h') {
347 strcat(pformat, "lu");
348 printf(pformat, (unsigned long) statbuf->st_nlink);
349 } else if (m == 'u') {
350 strcat(pformat, "lu");
351 printf(pformat, (unsigned long) statbuf->st_uid);
352 } else if (m == 'U') {
353 pw_ent = getpwuid(statbuf->st_uid);
354 printfs(pformat, (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN");
355 } else if (m == 'g') {
356 strcat(pformat, "lu");
357 printf(pformat, (unsigned long) statbuf->st_gid);
358 } else if (m == 'G') {
359 gw_ent = getgrgid(statbuf->st_gid);
360 printfs(pformat, (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN");
361 } else if (m == 't') {
362 strcat(pformat, "lx");
363 printf(pformat, (unsigned long) major(statbuf->st_rdev));
364 } else if (m == 'T') {
365 strcat(pformat, "lx");
366 printf(pformat, (unsigned long) minor(statbuf->st_rdev));
367 } else if (m == 's') {
368 strcat(pformat, "llu");
369 printf(pformat, (unsigned long long) statbuf->st_size);
370 } else if (m == 'B') {
371 strcat(pformat, "lu");
372 printf(pformat, (unsigned long) 512); //ST_NBLOCKSIZE
373 } else if (m == 'b') {
374 strcat(pformat, "llu");
375 printf(pformat, (unsigned long long) statbuf->st_blocks);
376 } else if (m == 'o') {
377 strcat(pformat, "lu");
378 printf(pformat, (unsigned long) statbuf->st_blksize);
379 } else if (m == 'x') {
380 printfs(pformat, human_time(statbuf->st_atime));
381 } else if (m == 'X') {
382 strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
383 /* note: (unsigned long) would be wrong:
384 * imagine (unsigned long64)int32 */
385 printf(pformat, (long) statbuf->st_atime);
386 } else if (m == 'y') {
387 printfs(pformat, human_time(statbuf->st_mtime));
388 } else if (m == 'Y') {
389 strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
390 printf(pformat, (long) statbuf->st_mtime);
391 } else if (m == 'z') {
392 printfs(pformat, human_time(statbuf->st_ctime));
393 } else if (m == 'Z') {
394 strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
395 printf(pformat, (long) statbuf->st_ctime);
396# if ENABLE_SELINUX
397 } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) {
398 printfs(pformat, scontext);
399# endif
400 } else {
401 strcatc(pformat, 'c');
402 printf(pformat, m);
403 }
404}
405
406static void print_it(const char *masterformat,
407 const char *filename,
408 void FAST_FUNC (*print_func)(char*, char, const char*, const void* IF_SELINUX(, security_context_t scontext)),
409 const void *data
410 IF_SELINUX(, security_context_t scontext))
411{
412 /* Create a working copy of the format string */
413 char *format = xstrdup(masterformat);
414 /* Add 2 to accommodate our conversion of the stat '%s' format string
415 * to the printf '%llu' one. */
416 char *dest = xmalloc(strlen(format) + 2 + 1);
417 char *b;
418
419 b = format;
420 while (b) {
421 /* Each iteration finds next %spec,
422 * prints preceding string and handles found %spec
423 */
424 size_t len;
425 char *p = strchr(b, '%');
426 if (!p) {
427 /* coreutils 6.3 always prints newline at the end */
428 /*fputs(b, stdout);*/
429 puts(b);
430 break;
431 }
432
433 /* dest = "%<modifiers>" */
434 len = 1 + strspn(p + 1, "#-+.I 0123456789");
435 memcpy(dest, p, len);
436 dest[len] = '\0';
437
438 /* print preceding string */
439 *p = '\0';
440 fputs(b, stdout);
441
442 p += len;
443 b = p + 1;
444 switch (*p) {
445 case '\0':
446 b = NULL;
447 /* fall through */
448 case '%':
449 bb_putchar('%');
450 break;
451 default:
452 /* Completes "%<modifiers>" with specifier and printfs */
453 print_func(dest, *p, filename, data IF_SELINUX(,scontext));
454 break;
455 }
456 }
457
458 free(format);
459 free(dest);
460}
461#endif /* FEATURE_STAT_FORMAT */
462
463#if ENABLE_FEATURE_STAT_FILESYSTEM
464/* Stat the file system and print what we find. */
465#if !ENABLE_FEATURE_STAT_FORMAT
466#define do_statfs(filename, format) do_statfs(filename)
467#endif
468static bool do_statfs(const char *filename, const char *format)
469{
470 struct statfs statfsbuf;
471#if !ENABLE_FEATURE_STAT_FORMAT
472 const char *format;
473#endif
474#if ENABLE_SELINUX
475 security_context_t scontext = NULL;
476
477 if (option_mask32 & OPT_SELINUX) {
478 if ((option_mask32 & OPT_DEREFERENCE
479 ? lgetfilecon(filename, &scontext)
480 : getfilecon(filename, &scontext)
481 ) < 0
482 ) {
483 bb_simple_perror_msg(filename);
484 return 0;
485 }
486 }
487#endif
488 if (statfs(filename, &statfsbuf) != 0) {
489 bb_perror_msg("can't read file system information for '%s'", filename);
490 return 0;
491 }
492
493#if ENABLE_FEATURE_STAT_FORMAT
494 if (format == NULL) {
495# if !ENABLE_SELINUX
496 format = (option_mask32 & OPT_TERSE
497 ? "%n %i %l %t %s %b %f %a %c %d\n"
498 : " File: \"%n\"\n"
499 " ID: %-8i Namelen: %-7l Type: %T\n"
500 "Block size: %-10s\n"
501 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
502 "Inodes: Total: %-10c Free: %d");
503# else
504 format = (option_mask32 & OPT_TERSE
505 ? (option_mask32 & OPT_SELINUX ? "%n %i %l %t %s %b %f %a %c %d %C\n":
506 "%n %i %l %t %s %b %f %a %c %d\n")
507 : (option_mask32 & OPT_SELINUX ?
508 " File: \"%n\"\n"
509 " ID: %-8i Namelen: %-7l Type: %T\n"
510 "Block size: %-10s\n"
511 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
512 "Inodes: Total: %-10c Free: %d"
513 " S_context: %C\n":
514 " File: \"%n\"\n"
515 " ID: %-8i Namelen: %-7l Type: %T\n"
516 "Block size: %-10s\n"
517 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
518 "Inodes: Total: %-10c Free: %d\n")
519 );
520# endif /* SELINUX */
521 }
522 print_it(format, filename, print_statfs, &statfsbuf IF_SELINUX(, scontext));
523#else /* FEATURE_STAT_FORMAT */
524 format = (option_mask32 & OPT_TERSE
525 ? "%s %llx %lu "
526 : " File: \"%s\"\n"
527 " ID: %-8llx Namelen: %-7lu ");
528 printf(format,
529 filename,
530 get_f_fsid(&statfsbuf),
531 statfsbuf.f_namelen);
532
533 if (option_mask32 & OPT_TERSE)
534 printf("%lx ", (unsigned long) statfsbuf.f_type);
535 else
536 printf("Type: %s\n", human_fstype(statfsbuf.f_type));
537
538# if !ENABLE_SELINUX
539 format = (option_mask32 & OPT_TERSE
540 ? "%lu %llu %llu %llu %llu %llu\n"
541 : "Block size: %-10lu\n"
542 "Blocks: Total: %-10llu Free: %-10llu Available: %llu\n"
543 "Inodes: Total: %-10llu Free: %llu\n");
544 printf(format,
545 (unsigned long) statfsbuf.f_bsize,
546 (unsigned long long) statfsbuf.f_blocks,
547 (unsigned long long) statfsbuf.f_bfree,
548 (unsigned long long) statfsbuf.f_bavail,
549 (unsigned long long) statfsbuf.f_files,
550 (unsigned long long) statfsbuf.f_ffree);
551# else
552 format = (option_mask32 & OPT_TERSE
553 ? (option_mask32 & OPT_SELINUX ? "%lu %llu %llu %llu %llu %llu %C\n" : "%lu %llu %llu %llu %llu %llu\n")
554 : (option_mask32 & OPT_SELINUX
555 ? "Block size: %-10lu\n"
556 "Blocks: Total: %-10llu Free: %-10llu Available: %llu\n"
557 "Inodes: Total: %-10llu Free: %llu"
558 "S_context: %C\n"
559 : "Block size: %-10lu\n"
560 "Blocks: Total: %-10llu Free: %-10llu Available: %llu\n"
561 "Inodes: Total: %-10llu Free: %llu\n"
562 )
563 );
564 printf(format,
565 (unsigned long) statfsbuf.f_bsize,
566 (unsigned long long) statfsbuf.f_blocks,
567 (unsigned long long) statfsbuf.f_bfree,
568 (unsigned long long) statfsbuf.f_bavail,
569 (unsigned long long) statfsbuf.f_files,
570 (unsigned long long) statfsbuf.f_ffree,
571 scontext);
572
573 if (scontext)
574 freecon(scontext);
575# endif
576#endif /* FEATURE_STAT_FORMAT */
577 return 1;
578}
579#endif /* FEATURE_STAT_FILESYSTEM */
580
581/* stat the file and print what we find */
582#if !ENABLE_FEATURE_STAT_FORMAT
583#define do_stat(filename, format) do_stat(filename)
584#endif
585static bool do_stat(const char *filename, const char *format)
586{
587 struct stat statbuf;
588#if ENABLE_SELINUX
589 security_context_t scontext = NULL;
590
591 if (option_mask32 & OPT_SELINUX) {
592 if ((option_mask32 & OPT_DEREFERENCE
593 ? lgetfilecon(filename, &scontext)
594 : getfilecon(filename, &scontext)
595 ) < 0
596 ) {
597 bb_simple_perror_msg(filename);
598 return 0;
599 }
600 }
601#endif
602 if ((option_mask32 & OPT_DEREFERENCE ? stat : lstat) (filename, &statbuf) != 0) {
603 bb_perror_msg("can't stat '%s'", filename);
604 return 0;
605 }
606
607#if ENABLE_FEATURE_STAT_FORMAT
608 if (format == NULL) {
609# if !ENABLE_SELINUX
610 if (option_mask32 & OPT_TERSE) {
611 format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
612 } else {
613 if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
614 format =
615 " File: %N\n"
616 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
617 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
618 " Device type: %t,%T\n"
619 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
620 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
621 } else {
622 format =
623 " File: %N\n"
624 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
625 "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
626 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
627 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
628 }
629 }
630# else
631 if (option_mask32 & OPT_TERSE) {
632 format = (option_mask32 & OPT_SELINUX ?
633 "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %C\n"
634 :
635 "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"
636 );
637 } else {
638 if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
639 format = (option_mask32 & OPT_SELINUX ?
640 " File: %N\n"
641 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
642 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
643 " Device type: %t,%T\n"
644 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
645 " S_Context: %C\n"
646 "Access: %x\n" "Modify: %y\n" "Change: %z\n"
647 :
648 " File: %N\n"
649 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
650 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
651 " Device type: %t,%T\n"
652 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
653 "Access: %x\n" "Modify: %y\n" "Change: %z\n"
654 );
655 } else {
656 format = (option_mask32 & OPT_SELINUX ?
657 " File: %N\n"
658 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
659 "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
660 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
661 "S_Context: %C\n"
662 "Access: %x\n" "Modify: %y\n" "Change: %z\n"
663 :
664 " File: %N\n"
665 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
666 "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
667 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
668 "Access: %x\n" "Modify: %y\n" "Change: %z\n"
669 );
670 }
671 }
672# endif
673 }
674 print_it(format, filename, print_stat, &statbuf IF_SELINUX(, scontext));
675#else /* FEATURE_STAT_FORMAT */
676 if (option_mask32 & OPT_TERSE) {
677 printf("%s %llu %llu %lx %lu %lu %llx %llu %lu %lx %lx %lu %lu %lu %lu"
678 IF_NOT_SELINUX("\n"),
679 filename,
680 (unsigned long long) statbuf.st_size,
681 (unsigned long long) statbuf.st_blocks,
682 (unsigned long) statbuf.st_mode,
683 (unsigned long) statbuf.st_uid,
684 (unsigned long) statbuf.st_gid,
685 (unsigned long long) statbuf.st_dev,
686 (unsigned long long) statbuf.st_ino,
687 (unsigned long) statbuf.st_nlink,
688 (unsigned long) major(statbuf.st_rdev),
689 (unsigned long) minor(statbuf.st_rdev),
690 (unsigned long) statbuf.st_atime,
691 (unsigned long) statbuf.st_mtime,
692 (unsigned long) statbuf.st_ctime,
693 (unsigned long) statbuf.st_blksize
694 );
695# if ENABLE_SELINUX
696 if (option_mask32 & OPT_SELINUX)
697 printf(" %s\n", scontext);
698 else
699 bb_putchar('\n');
700# endif
701 } else {
702 char *linkname = NULL;
703 struct passwd *pw_ent;
704 struct group *gw_ent;
705
706 gw_ent = getgrgid(statbuf.st_gid);
707 pw_ent = getpwuid(statbuf.st_uid);
708
709 if (S_ISLNK(statbuf.st_mode))
710 linkname = xmalloc_readlink_or_warn(filename);
711 if (linkname) {
712 printf(" File: '%s' -> '%s'\n", filename, linkname);
713 free(linkname);
714 } else {
715 printf(" File: '%s'\n", filename);
716 }
717
718 printf(" Size: %-10llu\tBlocks: %-10llu IO Block: %-6lu %s\n"
719 "Device: %llxh/%llud\tInode: %-10llu Links: %-5lu",
720 (unsigned long long) statbuf.st_size,
721 (unsigned long long) statbuf.st_blocks,
722 (unsigned long) statbuf.st_blksize,
723 file_type(&statbuf),
724 (unsigned long long) statbuf.st_dev,
725 (unsigned long long) statbuf.st_dev,
726 (unsigned long long) statbuf.st_ino,
727 (unsigned long) statbuf.st_nlink);
728 if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode))
729 printf(" Device type: %lx,%lx\n",
730 (unsigned long) major(statbuf.st_rdev),
731 (unsigned long) minor(statbuf.st_rdev));
732 else
733 bb_putchar('\n');
734 printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n",
735 (unsigned long) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)),
736 bb_mode_string(statbuf.st_mode),
737 (unsigned long) statbuf.st_uid,
738 (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN",
739 (unsigned long) statbuf.st_gid,
740 (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN");
741# if ENABLE_SELINUX
742 if (option_mask32 & OPT_SELINUX)
743 printf(" S_Context: %s\n", scontext);
744# endif
745 printf("Access: %s\n", human_time(statbuf.st_atime));
746 printf("Modify: %s\n", human_time(statbuf.st_mtime));
747 printf("Change: %s\n", human_time(statbuf.st_ctime));
748 }
749#endif /* FEATURE_STAT_FORMAT */
750 return 1;
751}
752
753int stat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
754int stat_main(int argc UNUSED_PARAM, char **argv)
755{
756 IF_FEATURE_STAT_FORMAT(char *format = NULL;)
757 int i;
758 int ok;
759 unsigned opts;
760 statfunc_ptr statfunc = do_stat;
761
762 opt_complementary = "-1"; /* min one arg */
763 opts = getopt32(argv, "tL"
764 IF_FEATURE_STAT_FILESYSTEM("f")
765 IF_SELINUX("Z")
766 IF_FEATURE_STAT_FORMAT("c:", &format)
767 );
768#if ENABLE_FEATURE_STAT_FILESYSTEM
769 if (opts & OPT_FILESYS) /* -f */
770 statfunc = do_statfs;
771#endif
772#if ENABLE_SELINUX
773 if (opts & OPT_SELINUX) {
774 selinux_or_die();
775 }
776#endif
777 ok = 1;
778 argv += optind;
779 for (i = 0; argv[i]; ++i)
780 ok &= statfunc(argv[i] IF_FEATURE_STAT_FORMAT(, format));
781
782 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
783}
Note: See TracBrowser for help on using the repository browser.