stat.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /*
  2. * stat -- display file or file system status
  3. *
  4. * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation.
  5. * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
  6. * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
  7. *
  8. * Written by Michael Meskes
  9. * Taken from coreutils and turned into a busybox applet by Mike Frysinger
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24. *
  25. */
  26. #include <stdio.h>
  27. #include <sys/types.h>
  28. #include <pwd.h>
  29. #include <grp.h>
  30. #include <sys/vfs.h>
  31. #include <time.h>
  32. #include <getopt.h> /* optind */
  33. #include <sys/stat.h>
  34. #include <sys/statfs.h>
  35. #include <sys/statvfs.h>
  36. #include <string.h>
  37. #include "busybox.h"
  38. /* vars to control behavior */
  39. #define OPT_TERSE 2
  40. #define OPT_DEREFERNCE 4
  41. static long flags;
  42. static char const *file_type(struct stat const *st)
  43. {
  44. /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107
  45. * for some of these formats.
  46. * To keep diagnostics grammatical in English, the
  47. * returned string must start with a consonant.
  48. */
  49. if (S_ISREG(st->st_mode)) return st->st_size == 0 ? "regular empty file" : "regular file";
  50. if (S_ISDIR(st->st_mode)) return "directory";
  51. if (S_ISBLK(st->st_mode)) return "block special file";
  52. if (S_ISCHR(st->st_mode)) return "character special file";
  53. if (S_ISFIFO(st->st_mode)) return "fifo";
  54. if (S_ISLNK(st->st_mode)) return "symbolic link";
  55. if (S_ISSOCK(st->st_mode)) return "socket";
  56. if (S_TYPEISMQ(st)) return "message queue";
  57. if (S_TYPEISSEM(st)) return "semaphore";
  58. if (S_TYPEISSHM(st)) return "shared memory object";
  59. #ifdef S_TYPEISTMO
  60. if (S_TYPEISTMO(st)) return "typed memory object";
  61. #endif
  62. return "weird file";
  63. }
  64. static char const *human_time(time_t t)
  65. {
  66. static char *str;
  67. str = ctime(&t);
  68. str[strlen(str)-1] = '\0';
  69. return str;
  70. }
  71. /* Return the type of the specified file system.
  72. * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
  73. * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
  74. * Still others have neither and have to get by with f_type (Linux).
  75. */
  76. static char const *human_fstype(long f_type)
  77. {
  78. int i;
  79. static const struct types {
  80. long type;
  81. const char *fs;
  82. } humantypes[] = {
  83. { 0xADFF, "affs" },
  84. { 0x1Cd1, "devpts" },
  85. { 0x137D, "ext" },
  86. { 0xEF51, "ext2" },
  87. { 0xEF53, "ext2/ext3" },
  88. { 0x3153464a, "jfs" },
  89. { 0x58465342, "xfs" },
  90. { 0xF995E849, "hpfs" },
  91. { 0x9660, "isofs" },
  92. { 0x4000, "isofs" },
  93. { 0x4004, "isofs" },
  94. { 0x137F, "minix" },
  95. { 0x138F, "minix (30 char.)" },
  96. { 0x2468, "minix v2" },
  97. { 0x2478, "minix v2 (30 char.)" },
  98. { 0x4d44, "msdos" },
  99. { 0x4006, "fat" },
  100. { 0x564c, "novell" },
  101. { 0x6969, "nfs" },
  102. { 0x9fa0, "proc" },
  103. { 0x517B, "smb" },
  104. { 0x012FF7B4, "xenix" },
  105. { 0x012FF7B5, "sysv4" },
  106. { 0x012FF7B6, "sysv2" },
  107. { 0x012FF7B7, "coh" },
  108. { 0x00011954, "ufs" },
  109. { 0x012FD16D, "xia" },
  110. { 0x5346544e, "ntfs" },
  111. { 0x1021994, "tmpfs" },
  112. { 0x52654973, "reiserfs" },
  113. { 0x28cd3d45, "cramfs" },
  114. { 0x7275, "romfs" },
  115. { 0x858458f6, "romfs" },
  116. { 0x73717368, "squashfs" },
  117. { 0x62656572, "sysfs" },
  118. { 0, "UNKNOWN" }
  119. };
  120. for (i=0; humantypes[i].type; ++i)
  121. if (humantypes[i].type == f_type)
  122. break;
  123. return humantypes[i].fs;
  124. }
  125. #ifdef CONFIG_FEATURE_STAT_FORMAT
  126. /* print statfs info */
  127. static void print_statfs(char *pformat, size_t buf_len, char m,
  128. char const *filename, void const *data)
  129. {
  130. struct statfs const *statfsbuf = data;
  131. switch (m) {
  132. case 'n':
  133. strncat(pformat, "s", buf_len);
  134. printf(pformat, filename);
  135. break;
  136. case 'i':
  137. strncat(pformat, "Lx", buf_len);
  138. printf(pformat, statfsbuf->f_fsid);
  139. break;
  140. case 'l':
  141. strncat(pformat, "lu", buf_len);
  142. printf(pformat, statfsbuf->f_namelen);
  143. break;
  144. case 't':
  145. strncat(pformat, "lx", buf_len);
  146. printf(pformat, (unsigned long int) (statfsbuf->f_type)); /* no equiv. */
  147. break;
  148. case 'T':
  149. strncat(pformat, "s", buf_len);
  150. printf(pformat, human_fstype(statfsbuf->f_type));
  151. break;
  152. case 'b':
  153. strncat(pformat, "ld", buf_len);
  154. printf(pformat, (intmax_t) (statfsbuf->f_blocks));
  155. break;
  156. case 'f':
  157. strncat(pformat, "ld", buf_len);
  158. printf(pformat, (intmax_t) (statfsbuf->f_bfree));
  159. break;
  160. case 'a':
  161. strncat(pformat, "ld", buf_len);
  162. printf(pformat, (intmax_t) (statfsbuf->f_bavail));
  163. break;
  164. case 'S':
  165. case 's':
  166. strncat(pformat, "lu", buf_len);
  167. printf(pformat, (unsigned long int) (statfsbuf->f_bsize));
  168. break;
  169. case 'c':
  170. strncat(pformat, "ld", buf_len);
  171. printf(pformat, (intmax_t) (statfsbuf->f_files));
  172. break;
  173. case 'd':
  174. strncat(pformat, "ld", buf_len);
  175. printf(pformat, (intmax_t) (statfsbuf->f_ffree));
  176. break;
  177. default:
  178. strncat(pformat, "c", buf_len);
  179. printf(pformat, m);
  180. break;
  181. }
  182. }
  183. /* print stat info */
  184. static void print_stat(char *pformat, size_t buf_len, char m,
  185. char const *filename, void const *data)
  186. {
  187. #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
  188. struct stat *statbuf = (struct stat *) data;
  189. struct passwd *pw_ent;
  190. struct group *gw_ent;
  191. switch (m) {
  192. case 'n':
  193. strncat(pformat, "s", buf_len);
  194. printf(pformat, filename);
  195. break;
  196. case 'N':
  197. strncat(pformat, "s", buf_len);
  198. if (S_ISLNK(statbuf->st_mode)) {
  199. char *linkname = xreadlink(filename);
  200. if (linkname == NULL) {
  201. bb_perror_msg("cannot read symbolic link '%s'", filename);
  202. return;
  203. }
  204. /*printf("\"%s\" -> \"%s\"", filename, linkname); */
  205. printf(pformat, filename);
  206. printf(" -> ");
  207. printf(pformat, linkname);
  208. } else {
  209. printf(pformat, filename);
  210. }
  211. break;
  212. case 'd':
  213. strncat(pformat, "lu", buf_len);
  214. printf(pformat, (uintmax_t) statbuf->st_dev);
  215. break;
  216. case 'D':
  217. strncat(pformat, "lx", buf_len);
  218. printf(pformat, (uintmax_t) statbuf->st_dev);
  219. break;
  220. case 'i':
  221. strncat(pformat, "lu", buf_len);
  222. printf(pformat, (uintmax_t) statbuf->st_ino);
  223. break;
  224. case 'a':
  225. strncat(pformat, "lo", buf_len);
  226. printf(pformat, (unsigned long int) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)));
  227. break;
  228. case 'A':
  229. strncat(pformat, "s", buf_len);
  230. printf(pformat, bb_mode_string(statbuf->st_mode));
  231. break;
  232. case 'f':
  233. strncat(pformat, "lx", buf_len);
  234. printf(pformat, (unsigned long int) statbuf->st_mode);
  235. break;
  236. case 'F':
  237. strncat(pformat, "s", buf_len);
  238. printf(pformat, file_type(statbuf));
  239. break;
  240. case 'h':
  241. strncat(pformat, "lu", buf_len);
  242. printf(pformat, (unsigned long int) statbuf->st_nlink);
  243. break;
  244. case 'u':
  245. strncat(pformat, "lu", buf_len);
  246. printf(pformat, (unsigned long int) statbuf->st_uid);
  247. break;
  248. case 'U':
  249. strncat(pformat, "s", buf_len);
  250. setpwent();
  251. pw_ent = getpwuid(statbuf->st_uid);
  252. printf(pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
  253. break;
  254. case 'g':
  255. strncat(pformat, "lu", buf_len);
  256. printf(pformat, (unsigned long int) statbuf->st_gid);
  257. break;
  258. case 'G':
  259. strncat(pformat, "s", buf_len);
  260. setgrent();
  261. gw_ent = getgrgid(statbuf->st_gid);
  262. printf(pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
  263. break;
  264. case 't':
  265. strncat(pformat, "lx", buf_len);
  266. printf(pformat, (unsigned long int) major(statbuf->st_rdev));
  267. break;
  268. case 'T':
  269. strncat(pformat, "lx", buf_len);
  270. printf(pformat, (unsigned long int) minor(statbuf->st_rdev));
  271. break;
  272. case 's':
  273. strncat(pformat, "lu", buf_len);
  274. printf(pformat, (uintmax_t) (statbuf->st_size));
  275. break;
  276. case 'B':
  277. strncat(pformat, "lu", buf_len);
  278. printf(pformat, (unsigned long int) 512); //ST_NBLOCKSIZE
  279. break;
  280. case 'b':
  281. strncat(pformat, "lu", buf_len);
  282. printf(pformat, (uintmax_t) statbuf->st_blocks);
  283. break;
  284. case 'o':
  285. strncat(pformat, "lu", buf_len);
  286. printf(pformat, (unsigned long int) statbuf->st_blksize);
  287. break;
  288. case 'x':
  289. strncat(pformat, "s", buf_len);
  290. printf(pformat, human_time(statbuf->st_atime));
  291. break;
  292. case 'X':
  293. strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);
  294. printf(pformat, (unsigned long int) statbuf->st_atime);
  295. break;
  296. case 'y':
  297. strncat(pformat, "s", buf_len);
  298. printf(pformat, human_time(statbuf->st_mtime));
  299. break;
  300. case 'Y':
  301. strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);
  302. printf(pformat, (unsigned long int) statbuf->st_mtime);
  303. break;
  304. case 'z':
  305. strncat(pformat, "s", buf_len);
  306. printf(pformat, human_time(statbuf->st_ctime));
  307. break;
  308. case 'Z':
  309. strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);
  310. printf(pformat, (unsigned long int) statbuf->st_ctime);
  311. break;
  312. default:
  313. strncat(pformat, "c", buf_len);
  314. printf(pformat, m);
  315. break;
  316. }
  317. }
  318. static void print_it(char const *masterformat, char const *filename,
  319. void (*print_func) (char *, size_t, char, char const *, void const *),
  320. void const *data)
  321. {
  322. char *b;
  323. /* create a working copy of the format string */
  324. char *format = bb_xstrdup(masterformat);
  325. /* Add 2 to accommodate our conversion of the stat `%s' format string
  326. * to the printf `%llu' one. */
  327. size_t n_alloc = strlen(format) + 2 + 1;
  328. char *dest = xmalloc(n_alloc);
  329. b = format;
  330. while (b) {
  331. char *p = strchr(b, '%');
  332. if (p != NULL) {
  333. size_t len;
  334. *p++ = '\0';
  335. fputs(b, stdout);
  336. len = strspn(p, "#-+.I 0123456789");
  337. dest[0] = '%';
  338. memcpy(dest + 1, p, len);
  339. dest[1 + len] = 0;
  340. p += len;
  341. b = p + 1;
  342. switch (*p) {
  343. case '\0':
  344. b = NULL;
  345. /* fall through */
  346. case '%':
  347. putchar('%');
  348. break;
  349. default:
  350. print_func(dest, n_alloc, *p, filename, data);
  351. break;
  352. }
  353. } else {
  354. fputs(b, stdout);
  355. b = NULL;
  356. }
  357. }
  358. free(format);
  359. free(dest);
  360. }
  361. #endif
  362. /* Stat the file system and print what we find. */
  363. static int do_statfs(char const *filename, char const *format)
  364. {
  365. struct statfs statfsbuf;
  366. if (statfs(filename, &statfsbuf) != 0) {
  367. bb_perror_msg("cannot read file system information for '%s'", filename);
  368. return 0;
  369. }
  370. #ifdef CONFIG_FEATURE_STAT_FORMAT
  371. if (format == NULL)
  372. format = (flags & OPT_TERSE
  373. ? "%n %i %l %t %s %b %f %a %c %d\n"
  374. : " File: \"%n\"\n"
  375. " ID: %-8i Namelen: %-7l Type: %T\n"
  376. "Block size: %-10s\n"
  377. "Blocks: Total: %-10b Free: %-10f Available: %a\n"
  378. "Inodes: Total: %-10c Free: %d\n");
  379. print_it(format, filename, print_statfs, &statfsbuf);
  380. #else
  381. format = (flags & OPT_TERSE
  382. ? "%s %Lx %lu "
  383. : " File: \"%s\"\n"
  384. " ID: %-8Lx Namelen: %-7lu ");
  385. printf(format,
  386. filename,
  387. statfsbuf.f_fsid,
  388. statfsbuf.f_namelen);
  389. if (flags & OPT_TERSE)
  390. printf("%lx ", (unsigned long int) (statfsbuf.f_type));
  391. else
  392. printf("Type: %s\n", human_fstype(statfsbuf.f_type));
  393. format = (flags & OPT_TERSE
  394. ? "%lu %ld %ld %ld %ld %ld\n"
  395. : "Block size: %-10lu\n"
  396. "Blocks: Total: %-10ld Free: %-10ld Available: %ld\n"
  397. "Inodes: Total: %-10ld Free: %ld\n");
  398. printf(format,
  399. (unsigned long int) (statfsbuf.f_bsize),
  400. (intmax_t) (statfsbuf.f_blocks),
  401. (intmax_t) (statfsbuf.f_bfree),
  402. (intmax_t) (statfsbuf.f_bavail),
  403. (intmax_t) (statfsbuf.f_files),
  404. (intmax_t) (statfsbuf.f_ffree));
  405. #endif
  406. return 1;
  407. }
  408. /* stat the file and print what we find */
  409. static int do_stat(char const *filename, char const *format)
  410. {
  411. struct stat statbuf;
  412. if ((flags & OPT_DEREFERNCE ? stat : lstat) (filename, &statbuf) != 0) {
  413. bb_perror_msg("cannot stat '%s'", filename);
  414. return 0;
  415. }
  416. #ifdef CONFIG_FEATURE_STAT_FORMAT
  417. if (format == NULL) {
  418. if (flags & OPT_TERSE) {
  419. format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n";
  420. } else {
  421. if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
  422. format =
  423. " File: \"%N\"\n"
  424. " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
  425. "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
  426. " Device type: %t,%T\n"
  427. "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
  428. "Access: %x\n" "Modify: %y\n" "Change: %z\n";
  429. } else {
  430. format =
  431. " File: \"%N\"\n"
  432. " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
  433. "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
  434. "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
  435. "Access: %x\n" "Modify: %y\n" "Change: %z\n";
  436. }
  437. }
  438. }
  439. print_it(format, filename, print_stat, &statbuf);
  440. #else
  441. if (flags & OPT_TERSE) {
  442. printf("%s %lu %lu %lx %lu %lu %lx %lu %lu %lx %lx %lu %lu %lu %lu\n",
  443. filename,
  444. (uintmax_t) (statbuf.st_size),
  445. (uintmax_t) statbuf.st_blocks,
  446. (unsigned long int) statbuf.st_mode,
  447. (unsigned long int) statbuf.st_uid,
  448. (unsigned long int) statbuf.st_gid,
  449. (uintmax_t) statbuf.st_dev,
  450. (uintmax_t) statbuf.st_ino,
  451. (unsigned long int) statbuf.st_nlink,
  452. (unsigned long int) major(statbuf.st_rdev),
  453. (unsigned long int) minor(statbuf.st_rdev),
  454. (unsigned long int) statbuf.st_atime,
  455. (unsigned long int) statbuf.st_mtime,
  456. (unsigned long int) statbuf.st_ctime,
  457. (unsigned long int) statbuf.st_blksize
  458. );
  459. } else {
  460. char *linkname = NULL;
  461. struct passwd *pw_ent;
  462. struct group *gw_ent;
  463. setgrent();
  464. gw_ent = getgrgid(statbuf.st_gid);
  465. setpwent();
  466. pw_ent = getpwuid(statbuf.st_uid);
  467. if (S_ISLNK(statbuf.st_mode))
  468. linkname = xreadlink(filename);
  469. if (linkname)
  470. printf(" File: \"%s\" -> \"%s\"\n", filename, linkname);
  471. else
  472. printf(" File: \"%s\"\n", filename);
  473. printf(" Size: %-10lu\tBlocks: %-10lu IO Block: %-6lu %s\n"
  474. "Device: %lxh/%lud\tInode: %-10lu Links: %-5lu",
  475. (uintmax_t) (statbuf.st_size),
  476. (uintmax_t) statbuf.st_blocks,
  477. (unsigned long int) statbuf.st_blksize,
  478. file_type(&statbuf),
  479. (uintmax_t) statbuf.st_dev,
  480. (uintmax_t) statbuf.st_dev,
  481. (uintmax_t) statbuf.st_ino,
  482. (unsigned long int) statbuf.st_nlink);
  483. if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode))
  484. printf(" Device type: %lx,%lx\n",
  485. (unsigned long int) major(statbuf.st_rdev),
  486. (unsigned long int) minor(statbuf.st_rdev));
  487. else
  488. putchar('\n');
  489. printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n"
  490. "Access: %s\n" "Modify: %s\n" "Change: %s\n",
  491. (unsigned long int) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)),
  492. bb_mode_string(statbuf.st_mode),
  493. (unsigned long int) statbuf.st_uid,
  494. (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN",
  495. (unsigned long int) statbuf.st_gid,
  496. (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN",
  497. human_time(statbuf.st_atime),
  498. human_time(statbuf.st_mtime),
  499. human_time(statbuf.st_ctime));
  500. }
  501. #endif
  502. return 1;
  503. }
  504. int stat_main(int argc, char **argv)
  505. {
  506. int i;
  507. char *format = NULL;
  508. int ok = 1;
  509. int (*statfunc)(char const *, char const *) = do_stat;
  510. flags = bb_getopt_ulflags(argc, argv, "ftL"
  511. #ifdef CONFIG_FEATURE_STAT_FORMAT
  512. "c:", &format
  513. #endif
  514. );
  515. if (flags & 1) /* -f */
  516. statfunc = do_statfs;
  517. if (argc == optind) /* files */
  518. bb_show_usage();
  519. for (i = optind; i < argc; ++i)
  520. ok &= statfunc(argv[i], format);
  521. return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
  522. }