diff options
author | Mike Frysinger <vapier@gentoo.org> | 2005-04-23 06:26:38 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2005-04-23 06:26:38 +0000 |
commit | 9b5f71ec029776e21bda6c4c61e6b463fd3a2314 (patch) | |
tree | 962bf98157f322d70e5c0fdd7fce5ef6865bbd3d /coreutils/stat.c | |
parent | 84ab267e226407ee402eff10aaf8239ed684de77 (diff) | |
download | busybox-w32-9b5f71ec029776e21bda6c4c61e6b463fd3a2314.tar.gz busybox-w32-9b5f71ec029776e21bda6c4c61e6b463fd3a2314.tar.bz2 busybox-w32-9b5f71ec029776e21bda6c4c61e6b463fd3a2314.zip |
stat implementation based upon coreutils
Diffstat (limited to 'coreutils/stat.c')
-rw-r--r-- | coreutils/stat.c | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/coreutils/stat.c b/coreutils/stat.c new file mode 100644 index 000000000..e386d75a0 --- /dev/null +++ b/coreutils/stat.c | |||
@@ -0,0 +1,599 @@ | |||
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 | |||
27 | #include <stdio.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <pwd.h> | ||
30 | #include <grp.h> | ||
31 | #include <sys/vfs.h> | ||
32 | #include <time.h> | ||
33 | #include <getopt.h> | ||
34 | #include <sys/stat.h> | ||
35 | #include <string.h> | ||
36 | #include "busybox.h" | ||
37 | |||
38 | /* vars to control behavior */ | ||
39 | static int follow_links = 0; | ||
40 | static int terse = 0; | ||
41 | |||
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 | |||
65 | static char const *human_time(time_t t) | ||
66 | { | ||
67 | static char *str; | ||
68 | str = ctime(&t); | ||
69 | str[strlen(str)-1] = '\0'; | ||
70 | return str; | ||
71 | } | ||
72 | |||
73 | /* Return the type of the specified file system. | ||
74 | * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris) | ||
75 | * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2) | ||
76 | * Still others have neither and have to get by with f_type (Linux). | ||
77 | */ | ||
78 | static char const *human_fstype(long f_type) | ||
79 | { | ||
80 | #define S_MAGIC_AFFS 0xADFF | ||
81 | #define S_MAGIC_DEVPTS 0x1CD1 | ||
82 | #define S_MAGIC_EXT 0x137D | ||
83 | #define S_MAGIC_EXT2_OLD 0xEF51 | ||
84 | #define S_MAGIC_EXT2 0xEF53 | ||
85 | #define S_MAGIC_JFS 0x3153464a | ||
86 | #define S_MAGIC_XFS 0x58465342 | ||
87 | #define S_MAGIC_HPFS 0xF995E849 | ||
88 | #define S_MAGIC_ISOFS 0x9660 | ||
89 | #define S_MAGIC_ISOFS_WIN 0x4000 | ||
90 | #define S_MAGIC_ISOFS_R_WIN 0x4004 | ||
91 | #define S_MAGIC_MINIX 0x137F | ||
92 | #define S_MAGIC_MINIX_30 0x138F | ||
93 | #define S_MAGIC_MINIX_V2 0x2468 | ||
94 | #define S_MAGIC_MINIX_V2_30 0x2478 | ||
95 | #define S_MAGIC_MSDOS 0x4d44 | ||
96 | #define S_MAGIC_FAT 0x4006 | ||
97 | #define S_MAGIC_NCP 0x564c | ||
98 | #define S_MAGIC_NFS 0x6969 | ||
99 | #define S_MAGIC_PROC 0x9fa0 | ||
100 | #define S_MAGIC_SMB 0x517B | ||
101 | #define S_MAGIC_XENIX 0x012FF7B4 | ||
102 | #define S_MAGIC_SYSV4 0x012FF7B5 | ||
103 | #define S_MAGIC_SYSV2 0x012FF7B6 | ||
104 | #define S_MAGIC_COH 0x012FF7B7 | ||
105 | #define S_MAGIC_UFS 0x00011954 | ||
106 | #define S_MAGIC_XIAFS 0x012FD16D | ||
107 | #define S_MAGIC_NTFS 0x5346544e | ||
108 | #define S_MAGIC_TMPFS 0x1021994 | ||
109 | #define S_MAGIC_REISERFS 0x52654973 | ||
110 | #define S_MAGIC_CRAMFS 0x28cd3d45 | ||
111 | #define S_MAGIC_ROMFS 0x7275 | ||
112 | #define S_MAGIC_RAMFS 0x858458f6 | ||
113 | #define S_MAGIC_SQUASHFS 0x73717368 | ||
114 | #define S_MAGIC_SYSFS 0x62656572 | ||
115 | switch (f_type) { | ||
116 | case S_MAGIC_AFFS: return "affs"; | ||
117 | case S_MAGIC_DEVPTS: return "devpts"; | ||
118 | case S_MAGIC_EXT: return "ext"; | ||
119 | case S_MAGIC_EXT2_OLD: return "ext2"; | ||
120 | case S_MAGIC_EXT2: return "ext2/ext3"; | ||
121 | case S_MAGIC_JFS: return "jfs"; | ||
122 | case S_MAGIC_XFS: return "xfs"; | ||
123 | case S_MAGIC_HPFS: return "hpfs"; | ||
124 | case S_MAGIC_ISOFS: return "isofs"; | ||
125 | case S_MAGIC_ISOFS_WIN: return "isofs"; | ||
126 | case S_MAGIC_ISOFS_R_WIN: return "isofs"; | ||
127 | case S_MAGIC_MINIX: return "minix"; | ||
128 | case S_MAGIC_MINIX_30: return "minix (30 char.)"; | ||
129 | case S_MAGIC_MINIX_V2: return "minix v2"; | ||
130 | case S_MAGIC_MINIX_V2_30: return "minix v2 (30 char.)"; | ||
131 | case S_MAGIC_MSDOS: return "msdos"; | ||
132 | case S_MAGIC_FAT: return "fat"; | ||
133 | case S_MAGIC_NCP: return "novell"; | ||
134 | case S_MAGIC_NFS: return "nfs"; | ||
135 | case S_MAGIC_PROC: return "proc"; | ||
136 | case S_MAGIC_SMB: return "smb"; | ||
137 | case S_MAGIC_XENIX: return "xenix"; | ||
138 | case S_MAGIC_SYSV4: return "sysv4"; | ||
139 | case S_MAGIC_SYSV2: return "sysv2"; | ||
140 | case S_MAGIC_COH: return "coh"; | ||
141 | case S_MAGIC_UFS: return "ufs"; | ||
142 | case S_MAGIC_XIAFS: return "xia"; | ||
143 | case S_MAGIC_NTFS: return "ntfs"; | ||
144 | case S_MAGIC_TMPFS: return "tmpfs"; | ||
145 | case S_MAGIC_REISERFS: return "reiserfs"; | ||
146 | case S_MAGIC_CRAMFS: return "cramfs"; | ||
147 | case S_MAGIC_ROMFS: return "romfs"; | ||
148 | case S_MAGIC_RAMFS: return "ramfs"; | ||
149 | case S_MAGIC_SQUASHFS: return "squashfs"; | ||
150 | case S_MAGIC_SYSFS: return "sysfs"; | ||
151 | default: { | ||
152 | static char buf[sizeof("UNKNOWN (0x%lx)") - 3 | ||
153 | + (sizeof(f_type) * CHAR_BIT + 3) / 4]; | ||
154 | sprintf(buf, "UNKNOWN (0x%lx)", f_type); | ||
155 | return buf; | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
161 | /* print statfs info */ | ||
162 | static void print_statfs(char *pformat, size_t buf_len, char m, | ||
163 | char const *filename, void const *data) | ||
164 | { | ||
165 | struct statfs const *statfsbuf = data; | ||
166 | |||
167 | switch (m) { | ||
168 | case 'n': | ||
169 | strncat(pformat, "s", buf_len); | ||
170 | printf(pformat, filename); | ||
171 | break; | ||
172 | case 'i': | ||
173 | strncat(pformat, "Lx", buf_len); | ||
174 | printf(pformat, statfsbuf->f_fsid); | ||
175 | break; | ||
176 | case 'l': | ||
177 | strncat(pformat, "lu", buf_len); | ||
178 | printf(pformat, statfsbuf->f_namelen); | ||
179 | break; | ||
180 | case 't': | ||
181 | strncat(pformat, "lx", buf_len); | ||
182 | printf(pformat, (unsigned long int) (statfsbuf->f_type)); /* no equiv. */ | ||
183 | break; | ||
184 | case 'T': | ||
185 | strncat(pformat, "s", buf_len); | ||
186 | printf(pformat, human_fstype(statfsbuf->f_type)); | ||
187 | break; | ||
188 | case 'b': | ||
189 | strncat(pformat, "ld", buf_len); | ||
190 | printf(pformat, (intmax_t) (statfsbuf->f_blocks)); | ||
191 | break; | ||
192 | case 'f': | ||
193 | strncat(pformat, "ld", buf_len); | ||
194 | printf(pformat, (intmax_t) (statfsbuf->f_bfree)); | ||
195 | break; | ||
196 | case 'a': | ||
197 | strncat(pformat, "ld", buf_len); | ||
198 | printf(pformat, (intmax_t) (statfsbuf->f_bavail)); | ||
199 | break; | ||
200 | case 's': | ||
201 | strncat(pformat, "lu", buf_len); | ||
202 | printf(pformat, (unsigned long int) (statfsbuf->f_bsize)); | ||
203 | break; | ||
204 | case 'S': { | ||
205 | unsigned long int frsize = statfsbuf->f_frsize; | ||
206 | if (!frsize) | ||
207 | frsize = statfsbuf->f_bsize; | ||
208 | strncat(pformat, "lu", buf_len); | ||
209 | printf(pformat, frsize); | ||
210 | break; | ||
211 | } | ||
212 | case 'c': | ||
213 | strncat(pformat, "ld", buf_len); | ||
214 | printf(pformat, (intmax_t) (statfsbuf->f_files)); | ||
215 | break; | ||
216 | case 'd': | ||
217 | strncat(pformat, "ld", buf_len); | ||
218 | printf(pformat, (intmax_t) (statfsbuf->f_ffree)); | ||
219 | break; | ||
220 | default: | ||
221 | strncat(pformat, "c", buf_len); | ||
222 | printf(pformat, m); | ||
223 | break; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* print stat info */ | ||
228 | static void print_stat(char *pformat, size_t buf_len, char m, | ||
229 | char const *filename, void const *data) | ||
230 | { | ||
231 | #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) | ||
232 | struct stat *statbuf = (struct stat *) data; | ||
233 | struct passwd *pw_ent; | ||
234 | struct group *gw_ent; | ||
235 | |||
236 | switch (m) { | ||
237 | case 'n': | ||
238 | strncat(pformat, "s", buf_len); | ||
239 | printf(pformat, filename); | ||
240 | break; | ||
241 | case 'N': | ||
242 | strncat(pformat, "s", buf_len); | ||
243 | if (S_ISLNK(statbuf->st_mode)) { | ||
244 | char *linkname = xreadlink(filename); | ||
245 | if (linkname == NULL) { | ||
246 | bb_perror_msg("cannot read symbolic link '%s'", filename); | ||
247 | return; | ||
248 | } | ||
249 | /*printf("\"%s\" -> \"%s\"", filename, linkname); */ | ||
250 | printf(pformat, filename); | ||
251 | printf(" -> "); | ||
252 | printf(pformat, linkname); | ||
253 | } else { | ||
254 | printf(pformat, filename); | ||
255 | } | ||
256 | break; | ||
257 | case 'd': | ||
258 | strncat(pformat, "lu", buf_len); | ||
259 | printf(pformat, (uintmax_t) statbuf->st_dev); | ||
260 | break; | ||
261 | case 'D': | ||
262 | strncat(pformat, "lx", buf_len); | ||
263 | printf(pformat, (uintmax_t) statbuf->st_dev); | ||
264 | break; | ||
265 | case 'i': | ||
266 | strncat(pformat, "lu", buf_len); | ||
267 | printf(pformat, (uintmax_t) statbuf->st_ino); | ||
268 | break; | ||
269 | case 'a': | ||
270 | strncat(pformat, "lo", buf_len); | ||
271 | printf(pformat, (unsigned long int) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO))); | ||
272 | break; | ||
273 | case 'A': | ||
274 | strncat(pformat, "s", buf_len); | ||
275 | printf(pformat, bb_mode_string(statbuf->st_mode)); | ||
276 | break; | ||
277 | case 'f': | ||
278 | strncat(pformat, "lx", buf_len); | ||
279 | printf(pformat, (unsigned long int) statbuf->st_mode); | ||
280 | break; | ||
281 | case 'F': | ||
282 | strncat(pformat, "s", buf_len); | ||
283 | printf(pformat, file_type(statbuf)); | ||
284 | break; | ||
285 | case 'h': | ||
286 | strncat(pformat, "lu", buf_len); | ||
287 | printf(pformat, (unsigned long int) statbuf->st_nlink); | ||
288 | break; | ||
289 | case 'u': | ||
290 | strncat(pformat, "lu", buf_len); | ||
291 | printf(pformat, (unsigned long int) statbuf->st_uid); | ||
292 | break; | ||
293 | case 'U': | ||
294 | strncat(pformat, "s", buf_len); | ||
295 | setpwent(); | ||
296 | pw_ent = getpwuid(statbuf->st_uid); | ||
297 | printf(pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN"); | ||
298 | break; | ||
299 | case 'g': | ||
300 | strncat(pformat, "lu", buf_len); | ||
301 | printf(pformat, (unsigned long int) statbuf->st_gid); | ||
302 | break; | ||
303 | case 'G': | ||
304 | strncat(pformat, "s", buf_len); | ||
305 | setgrent(); | ||
306 | gw_ent = getgrgid(statbuf->st_gid); | ||
307 | printf(pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN"); | ||
308 | break; | ||
309 | case 't': | ||
310 | strncat(pformat, "lx", buf_len); | ||
311 | printf(pformat, (unsigned long int) major(statbuf->st_rdev)); | ||
312 | break; | ||
313 | case 'T': | ||
314 | strncat(pformat, "lx", buf_len); | ||
315 | printf(pformat, (unsigned long int) minor(statbuf->st_rdev)); | ||
316 | break; | ||
317 | case 's': | ||
318 | strncat(pformat, "lu", buf_len); | ||
319 | printf(pformat, (uintmax_t) (statbuf->st_size)); | ||
320 | break; | ||
321 | case 'B': | ||
322 | strncat(pformat, "lu", buf_len); | ||
323 | printf(pformat, (unsigned long int) 512); //ST_NBLOCKSIZE | ||
324 | break; | ||
325 | case 'b': | ||
326 | strncat(pformat, "lu", buf_len); | ||
327 | printf(pformat, (uintmax_t) statbuf->st_blocks); | ||
328 | break; | ||
329 | case 'o': | ||
330 | strncat(pformat, "lu", buf_len); | ||
331 | printf(pformat, (unsigned long int) statbuf->st_blksize); | ||
332 | break; | ||
333 | case 'x': | ||
334 | strncat(pformat, "s", buf_len); | ||
335 | printf(pformat, human_time(statbuf->st_atime)); | ||
336 | break; | ||
337 | case 'X': | ||
338 | strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len); | ||
339 | printf(pformat, (unsigned long int) statbuf->st_atime); | ||
340 | break; | ||
341 | case 'y': | ||
342 | strncat(pformat, "s", buf_len); | ||
343 | printf(pformat, human_time(statbuf->st_mtime)); | ||
344 | break; | ||
345 | case 'Y': | ||
346 | strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len); | ||
347 | printf(pformat, (unsigned long int) statbuf->st_mtime); | ||
348 | break; | ||
349 | case 'z': | ||
350 | strncat(pformat, "s", buf_len); | ||
351 | printf(pformat, human_time(statbuf->st_ctime)); | ||
352 | break; | ||
353 | case 'Z': | ||
354 | strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len); | ||
355 | printf(pformat, (unsigned long int) statbuf->st_ctime); | ||
356 | break; | ||
357 | default: | ||
358 | strncat(pformat, "c", buf_len); | ||
359 | printf(pformat, m); | ||
360 | break; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | static void print_it(char const *masterformat, char const *filename, | ||
365 | void (*print_func) (char *, size_t, char, char const *, void const *), | ||
366 | void const *data) | ||
367 | { | ||
368 | char *b; | ||
369 | |||
370 | /* create a working copy of the format string */ | ||
371 | char *format = bb_xstrdup(masterformat); | ||
372 | |||
373 | /* Add 2 to accommodate our conversion of the stat `%s' format string | ||
374 | * to the printf `%llu' one. */ | ||
375 | size_t n_alloc = strlen(format) + 2 + 1; | ||
376 | char *dest = xmalloc(n_alloc); | ||
377 | |||
378 | b = format; | ||
379 | while (b) { | ||
380 | char *p = strchr(b, '%'); | ||
381 | if (p != NULL) { | ||
382 | size_t len; | ||
383 | *p++ = '\0'; | ||
384 | fputs(b, stdout); | ||
385 | |||
386 | len = strspn(p, "#-+.I 0123456789"); | ||
387 | dest[0] = '%'; | ||
388 | memcpy(dest + 1, p, len); | ||
389 | dest[1 + len] = 0; | ||
390 | p += len; | ||
391 | |||
392 | b = p + 1; | ||
393 | switch (*p) { | ||
394 | case '\0': | ||
395 | b = NULL; | ||
396 | /* fall through */ | ||
397 | case '%': | ||
398 | putchar('%'); | ||
399 | break; | ||
400 | default: | ||
401 | print_func(dest, n_alloc, *p, filename, data); | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | } else { | ||
406 | fputs(b, stdout); | ||
407 | b = NULL; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | free(format); | ||
412 | free(dest); | ||
413 | } | ||
414 | #endif | ||
415 | |||
416 | /* Stat the file system and print what we find. */ | ||
417 | static int do_statfs(char const *filename, char const *format) | ||
418 | { | ||
419 | struct statfs statfsbuf; | ||
420 | |||
421 | if (statfs(filename, &statfsbuf) != 0) { | ||
422 | bb_perror_msg("cannot read file system information for '%s'", filename); | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
427 | if (format == NULL) | ||
428 | format = (terse | ||
429 | ? "%n %i %l %t %s %S %b %f %a %c %d\n" | ||
430 | : " File: \"%n\"\n" | ||
431 | " ID: %-8i Namelen: %-7l Type: %T\n" | ||
432 | "Block size: %-10s Fundamental block size: %S\n" | ||
433 | "Blocks: Total: %-10b Free: %-10f Available: %a\n" | ||
434 | "Inodes: Total: %-10c Free: %d\n"); | ||
435 | print_it(format, filename, print_statfs, &statfsbuf); | ||
436 | #else | ||
437 | |||
438 | format = (terse | ||
439 | ? "%s %Lx %lu " | ||
440 | : " File: \"%s\"\n" | ||
441 | " ID: %-8Lx Namelen: %-7lu "); | ||
442 | printf(format, | ||
443 | filename, | ||
444 | statfsbuf.f_fsid, | ||
445 | statfsbuf.f_namelen); | ||
446 | |||
447 | if (terse) | ||
448 | printf("%lx ", (unsigned long int) (statfsbuf.f_type)); | ||
449 | else | ||
450 | printf("Type: %s\n", human_fstype(statfsbuf.f_type)); | ||
451 | |||
452 | format = (terse | ||
453 | ? "%lu %lu %ld %ld %ld %ld %ld\n" | ||
454 | : "Block size: %-10lu Fundamental block size: %lu\n" | ||
455 | "Blocks: Total: %-10ld Free: %-10ld Available: %ld\n" | ||
456 | "Inodes: Total: %-10ld Free: %ld\n"); | ||
457 | printf(format, | ||
458 | (unsigned long int) (statfsbuf.f_bsize), | ||
459 | statfsbuf.f_frsize ? statfsbuf.f_frsize : statfsbuf.f_bsize, | ||
460 | (intmax_t) (statfsbuf.f_blocks), | ||
461 | (intmax_t) (statfsbuf.f_bfree), | ||
462 | (intmax_t) (statfsbuf.f_bavail), | ||
463 | (intmax_t) (statfsbuf.f_files), | ||
464 | (intmax_t) (statfsbuf.f_ffree)); | ||
465 | #endif | ||
466 | |||
467 | return 1; | ||
468 | } | ||
469 | |||
470 | /* stat the file and print what we find */ | ||
471 | static int do_stat(char const *filename, char const *format) | ||
472 | { | ||
473 | struct stat statbuf; | ||
474 | |||
475 | if ((follow_links ? stat : lstat) (filename, &statbuf) != 0) { | ||
476 | bb_perror_msg("cannot stat '%s'", filename); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
481 | if (format == NULL) { | ||
482 | if (terse) { | ||
483 | format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; | ||
484 | } else { | ||
485 | if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) { | ||
486 | format = | ||
487 | " File: \"%N\"\n" | ||
488 | " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" | ||
489 | "Device: %Dh/%dd\tInode: %-10i Links: %-5h" | ||
490 | " Device type: %t,%T\n" | ||
491 | "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" | ||
492 | "Access: %x\n" "Modify: %y\n" "Change: %z\n"; | ||
493 | } else { | ||
494 | format = | ||
495 | " File: \"%N\"\n" | ||
496 | " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" | ||
497 | "Device: %Dh/%dd\tInode: %-10i Links: %h\n" | ||
498 | "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" | ||
499 | "Access: %x\n" "Modify: %y\n" "Change: %z\n"; | ||
500 | } | ||
501 | } | ||
502 | } | ||
503 | print_it(format, filename, print_stat, &statbuf); | ||
504 | #else | ||
505 | if (terse) { | ||
506 | printf("%s %lu %lu %lx %lu %lu %lx %lu %lu %lx %lx %lu %lu %lu %lu\n", | ||
507 | filename, | ||
508 | (uintmax_t) (statbuf.st_size), | ||
509 | (uintmax_t) statbuf.st_blocks, | ||
510 | (unsigned long int) statbuf.st_mode, | ||
511 | (unsigned long int) statbuf.st_uid, | ||
512 | (unsigned long int) statbuf.st_gid, | ||
513 | (uintmax_t) statbuf.st_dev, | ||
514 | (uintmax_t) statbuf.st_ino, | ||
515 | (unsigned long int) statbuf.st_nlink, | ||
516 | (unsigned long int) major(statbuf.st_rdev), | ||
517 | (unsigned long int) minor(statbuf.st_rdev), | ||
518 | (unsigned long int) statbuf.st_atime, | ||
519 | (unsigned long int) statbuf.st_mtime, | ||
520 | (unsigned long int) statbuf.st_ctime, | ||
521 | (unsigned long int) statbuf.st_blksize | ||
522 | ); | ||
523 | } else { | ||
524 | char *linkname = NULL; | ||
525 | |||
526 | struct passwd *pw_ent; | ||
527 | struct group *gw_ent; | ||
528 | setgrent(); | ||
529 | gw_ent = getgrgid(statbuf.st_gid); | ||
530 | setpwent(); | ||
531 | pw_ent = getpwuid(statbuf.st_uid); | ||
532 | |||
533 | if (S_ISLNK(statbuf.st_mode)) | ||
534 | linkname = xreadlink(filename); | ||
535 | if (linkname) | ||
536 | printf(" File: \"%s\" -> \"%s\"\n", filename, linkname); | ||
537 | else | ||
538 | printf(" File: \"%s\"\n", filename); | ||
539 | |||
540 | printf(" Size: %-10lu\tBlocks: %-10lu IO Block: %-6lu %s\n" | ||
541 | "Device: %lxh/%lud\tInode: %-10lu Links: %-5lu", | ||
542 | (uintmax_t) (statbuf.st_size), | ||
543 | (uintmax_t) statbuf.st_blocks, | ||
544 | (unsigned long int) statbuf.st_blksize, | ||
545 | file_type(&statbuf), | ||
546 | (uintmax_t) statbuf.st_dev, | ||
547 | (uintmax_t) statbuf.st_dev, | ||
548 | (uintmax_t) statbuf.st_ino, | ||
549 | (unsigned long int) statbuf.st_nlink); | ||
550 | if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) | ||
551 | printf(" Device type: %lx,%lx\n", | ||
552 | (unsigned long int) major(statbuf.st_rdev), | ||
553 | (unsigned long int) minor(statbuf.st_rdev)); | ||
554 | else | ||
555 | putchar('\n'); | ||
556 | printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n" | ||
557 | "Access: %s\n" "Modify: %s\n" "Change: %s\n", | ||
558 | (unsigned long int) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)), | ||
559 | bb_mode_string(statbuf.st_mode), | ||
560 | (unsigned long int) statbuf.st_uid, | ||
561 | (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN", | ||
562 | (unsigned long int) statbuf.st_gid, | ||
563 | (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN", | ||
564 | human_time(statbuf.st_atime), | ||
565 | human_time(statbuf.st_mtime), | ||
566 | human_time(statbuf.st_ctime)); | ||
567 | } | ||
568 | #endif | ||
569 | return 1; | ||
570 | } | ||
571 | |||
572 | int stat_main(int argc, char **argv) | ||
573 | { | ||
574 | int i; | ||
575 | char *format = NULL; | ||
576 | int ok = 1; | ||
577 | long flags; | ||
578 | int (*statfunc)(char const *, char const *) = do_stat; | ||
579 | |||
580 | flags = bb_getopt_ulflags(argc, argv, "fLlt" | ||
581 | #ifdef CONFIG_FEATURE_STAT_FORMAT | ||
582 | "c:", &format | ||
583 | #endif | ||
584 | ); | ||
585 | |||
586 | if (flags & 1) /* -f */ | ||
587 | statfunc = do_statfs; | ||
588 | if (flags & 2 || flags & 4) /* -L, -l */ | ||
589 | follow_links = 1; | ||
590 | if (flags & 8) /* -t */ | ||
591 | terse = 1; | ||
592 | if (argc == optind) /* files */ | ||
593 | bb_show_usage(); | ||
594 | |||
595 | for (i = optind; i < argc; ++i) | ||
596 | ok &= statfunc(argv[i], format); | ||
597 | |||
598 | return (ok ? EXIT_SUCCESS : EXIT_FAILURE); | ||
599 | } | ||