*** empty log message ***
[coreutils.git] / src / stat.c
blobb4cc437a0a5f2f44c6b65064f1de18420bdcb735
1 /* stat.c -- display file or filesystem status
2 Copyright (C) 2001, 2002 Free Software Foundation.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 Written by Michael Meskes. */
20 #include <config.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #ifdef HAVE_SYS_SYSMACROS_H
25 # include <sys/sysmacros.h>
26 #endif
27 #include <pwd.h>
28 #include <grp.h>
29 #include <unistd.h>
30 #include <time.h>
31 #if HAVE_SYS_STATVFS_H
32 # include <sys/statvfs.h>
33 #endif
34 #if HAVE_SYS_VFS_H
35 # include <sys/vfs.h>
36 #endif
38 /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
39 #if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H
40 # if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
41 # include <sys/param.h>
42 # include <sys/mount.h>
43 # endif
44 #endif
46 #include <string.h>
47 #include <ctype.h>
49 #if HAVE_INTTYPES_H
50 # include <inttypes.h>
51 #endif
53 #if ! defined PRIdMAX
54 # if HAVE_LONG_LONG
55 # define PRIdMAX "lld"
56 # else
57 # define PRIdMAX "ld"
58 # endif
59 #endif
61 #if ! defined PRIuMAX
62 # if HAVE_LONG_LONG
63 # define PRIuMAX "llu"
64 # else
65 # define PRIuMAX "lu"
66 # endif
67 #endif
69 #include "system.h"
71 #include "closeout.h"
72 #include "error.h"
73 #include "filemode.h"
74 #include "fs.h"
75 #include "getopt.h"
76 #include "quote.h"
77 #include "quotearg.h"
78 #include "xreadlink.h"
80 #define NAMEMAX_FORMAT PRIuMAX
82 #if HAVE_STRUCT_STATVFS_F_BASETYPE
83 # define STRUCT_STATVFS struct statvfs
84 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS
85 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
86 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
87 # endif
88 #else
89 # define STRUCT_STATVFS struct statfs
90 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS
91 # if HAVE_STRUCT_STATFS_F_NAMELEN
92 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
93 # endif
94 #endif
96 #ifndef SB_F_NAMEMAX
97 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
98 # define SB_F_NAMEMAX(S) "*"
99 # undef NAMEMAX_FORMAT
100 # define NAMEMAX_FORMAT "s"
101 #endif
103 size_t nstrftime PARAMS ((char *, size_t, char const *,
104 struct tm const *, int, int));
106 #define PROGRAM_NAME "stat"
108 #define AUTHORS "Michael Meskes"
110 static struct option const long_options[] = {
111 {"link", no_argument, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */
112 {"dereference", no_argument, 0, 'L'},
113 {"format", required_argument, 0, 'c'},
114 {"filesystem", no_argument, 0, 'f'},
115 {"terse", no_argument, 0, 't'},
116 {GETOPT_HELP_OPTION_DECL},
117 {GETOPT_VERSION_OPTION_DECL},
118 {NULL, 0, NULL, 0}
121 char *program_name;
123 static void
124 print_human_type (mode_t mode)
126 char const *type;
127 switch (mode & S_IFMT)
129 case S_IFDIR:
130 type = "Directory";
131 break;
132 case S_IFCHR:
133 type = "Character Device";
134 break;
135 case S_IFBLK:
136 type = "Block Device";
137 break;
138 case S_IFREG:
139 type = "Regular File";
140 break;
141 case S_IFLNK:
142 type = "Symbolic Link";
143 break;
144 case S_IFSOCK:
145 type = "Socket";
146 break;
147 case S_IFIFO:
148 type = "Fifo File";
149 break;
150 default:
151 type = "Unknown";
153 fputs (type, stdout);
156 /* Return the type of the specified file system.
157 Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
158 Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
159 Still others have neither and have to get by with f_type (Linux). */
160 static char *
161 human_fstype (STRUCT_STATVFS const *statfsbuf)
163 #if HAVE_STRUCT_STATVFS_F_BASETYPE
164 return statfsbuf->f_basetype;
165 #else
166 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
167 return statfsbuf->f_fstypename;
168 # else
169 char const *type;
171 switch (statfsbuf->f_type)
173 # if defined __linux__
174 case S_MAGIC_AFFS:
175 type = "affs";
176 break;
177 case S_MAGIC_EXT:
178 type = "ext";
179 break;
180 case S_MAGIC_EXT2_OLD:
181 type = "ext2";
182 break;
183 case S_MAGIC_EXT2:
184 type = "ext2/ext3";
185 break;
186 case S_MAGIC_HPFS:
187 type = "hpfs";
188 break;
189 case S_MAGIC_ISOFS:
190 type = "isofs";
191 break;
192 case S_MAGIC_ISOFS_WIN:
193 type = "isofs";
194 break;
195 case S_MAGIC_ISOFS_R_WIN:
196 type = "isofs";
197 break;
198 case S_MAGIC_MINIX:
199 type = "minix";
200 break;
201 case S_MAGIC_MINIX_30:
202 type = "minix (30 char.)";
203 break;
204 case S_MAGIC_MINIX_V2:
205 type = "minix v2";
206 break;
207 case S_MAGIC_MINIX_V2_30:
208 type = "minix v2 (30 char.)";
209 break;
210 case S_MAGIC_MSDOS:
211 type = "msdos";
212 break;
213 case S_MAGIC_FAT:
214 type = "fat";
215 break;
216 case S_MAGIC_NCP:
217 type = "novell";
218 break;
219 case S_MAGIC_NFS:
220 type = "nfs";
221 break;
222 case S_MAGIC_PROC:
223 type = "proc";
224 break;
225 case S_MAGIC_SMB:
226 type = "smb";
227 break;
228 case S_MAGIC_XENIX:
229 type = "xenix";
230 break;
231 case S_MAGIC_SYSV4:
232 type = "sysv4";
233 break;
234 case S_MAGIC_SYSV2:
235 type = "sysv2";
236 break;
237 case S_MAGIC_COH:
238 type = "coh";
239 break;
240 case S_MAGIC_UFS:
241 type = "ufs";
242 break;
243 case S_MAGIC_XIAFS:
244 type = "xia";
245 break;
246 case S_MAGIC_NTFS:
247 type = "ntfs";
248 break;
249 case S_MAGIC_TMPFS:
250 type = "tmpfs";
251 break;
252 case S_MAGIC_REISERFS:
253 type = "reiserfs";
254 break;
255 case S_MAGIC_CRAMFS:
256 type = "cramfs";
257 break;
258 case S_MAGIC_ROMFS:
259 type = "romfs";
260 break;
261 # elif __GNU__
262 case FSTYPE_UFS:
263 type = "ufs";
264 break;
265 case FSTYPE_NFS:
266 type = "nfs";
267 break;
268 case FSTYPE_GFS:
269 type = "gfs";
270 break;
271 case FSTYPE_LFS:
272 type = "lfs";
273 break;
274 case FSTYPE_SYSV:
275 type = "sysv";
276 break;
277 case FSTYPE_FTP:
278 type = "ftp";
279 break;
280 case FSTYPE_TAR:
281 type = "tar";
282 break;
283 case FSTYPE_AR:
284 type = "ar";
285 break;
286 case FSTYPE_CPIO:
287 type = "cpio";
288 break;
289 case FSTYPE_MSLOSS:
290 type = "msloss";
291 break;
292 case FSTYPE_CPM:
293 type = "cpm";
294 break;
295 case FSTYPE_HFS:
296 type = "hfs";
297 break;
298 case FSTYPE_DTFS:
299 type = "dtfs";
300 break;
301 case FSTYPE_GRFS:
302 type = "grfs";
303 break;
304 case FSTYPE_TERM:
305 type = "term";
306 break;
307 case FSTYPE_DEV:
308 type = "dev";
309 break;
310 case FSTYPE_PROC:
311 type = "proc";
312 break;
313 case FSTYPE_IFSOCK:
314 type = "ifsock";
315 break;
316 case FSTYPE_AFS:
317 type = "afs";
318 break;
319 case FSTYPE_DFS:
320 type = "dfs";
321 break;
322 case FSTYPE_PROC9:
323 type = "proc9";
324 break;
325 case FSTYPE_SOCKET:
326 type = "socket";
327 break;
328 case FSTYPE_MISC:
329 type = "misc";
330 break;
331 case FSTYPE_EXT2FS:
332 type = "ext2/ext3";
333 break;
334 case FSTYPE_HTTP:
335 type = "http";
336 break;
337 case FSTYPE_MEMFS:
338 type = "memfs";
339 break;
340 case FSTYPE_ISO9660:
341 type = "iso9660";
342 break;
343 # endif
344 default:
345 type = NULL;
346 break;
349 if (type)
350 return (char *) type;
353 static char buf[sizeof "UNKNOWN (0x%x)" - 2
354 + 2 * sizeof (statfsbuf->f_type)];
355 sprintf (buf, "UNKNOWN (0x%x)", statfsbuf->f_type);
356 return buf;
358 # endif
359 #endif
362 static void
363 print_human_access (struct stat const *statbuf)
365 char modebuf[11];
366 mode_string (statbuf->st_mode, modebuf);
367 modebuf[10] = 0;
368 fputs (modebuf, stdout);
371 static void
372 print_human_time (time_t const *t)
374 char str[80];
376 #if 0 /* %c is too locale-dependent. */
377 if (strftime (str, 40, "%c", localtime (t)) > 0)
378 #else
379 if (nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z",
380 localtime (t), 0, 0) > 0)
381 #endif
382 fputs (str, stdout);
383 else
384 printf ("Cannot calculate human readable time, sorry");
387 /* print statfs info */
388 static void
389 print_statfs (char *pformat, char m, char const *filename,
390 void const *data)
392 STRUCT_STATVFS const *statfsbuf = data;
394 switch (m)
396 case 'n':
397 strcat (pformat, "s");
398 printf (pformat, filename);
399 break;
401 case 'i':
402 #if HAVE_STRUCT_STATXFS_F_FSID___VAL
403 strcat (pformat, "x %-8x");
404 printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */
405 statfsbuf->f_fsid.__val[1]);
406 #else
407 strcat (pformat, "Lx");
408 printf (pformat, statfsbuf->f_fsid);
409 #endif
410 break;
412 case 'l':
413 strcat (pformat, NAMEMAX_FORMAT);
414 printf (pformat, SB_F_NAMEMAX (statfsbuf));
415 break;
416 case 't':
417 #if HAVE_STRUCT_STATXFS_F_TYPE
418 strcat (pformat, "lx");
419 printf (pformat, (long int) (statfsbuf->f_type)); /* no equiv. */
420 #else
421 fputc ('*', stdout);
422 #endif
423 break;
424 case 'T':
425 strcat (pformat, "s");
426 printf (pformat, human_fstype (statfsbuf));
427 break;
428 case 'b':
429 strcat (pformat, PRIdMAX);
430 printf (pformat, (intmax_t) (statfsbuf->f_blocks));
431 break;
432 case 'f':
433 strcat (pformat, PRIdMAX);
434 printf (pformat, (intmax_t) (statfsbuf->f_bfree));
435 break;
436 case 'a':
437 strcat (pformat, PRIdMAX);
438 printf (pformat, (intmax_t) (statfsbuf->f_bavail));
439 break;
440 case 's':
441 strcat (pformat, "ld");
442 printf (pformat, (long int) (statfsbuf->f_bsize));
443 break;
444 case 'c':
445 strcat (pformat, PRIdMAX);
446 printf (pformat, (intmax_t) (statfsbuf->f_files));
447 break;
448 case 'd':
449 strcat (pformat, PRIdMAX);
450 printf (pformat, (intmax_t) (statfsbuf->f_ffree));
451 break;
453 default:
454 strcat (pformat, "c");
455 printf (pformat, m);
456 break;
460 /* print stat info */
461 static void
462 print_stat (char *pformat, char m, char const *filename, void const *data)
464 struct stat *statbuf = (struct stat *) data;
465 struct passwd *pw_ent;
466 struct group *gw_ent;
468 switch (m)
470 case 'n':
471 strcat (pformat, "s");
472 printf (pformat, filename);
473 break;
474 case 'N':
475 strcat (pformat, "s");
476 if ((statbuf->st_mode & S_IFMT) == S_IFLNK)
478 char *linkname = xreadlink (filename);
479 if (linkname == NULL)
481 error (0, errno, _("cannot read symbolic link %s"),
482 quote (filename));
483 return;
485 /*printf("\"%s\" -> \"%s\"", filename, linkname); */
486 printf (pformat, quote (filename));
487 printf (" -> ");
488 printf (pformat, quote (linkname));
490 else
492 printf (pformat, quote (filename));
494 break;
495 case 'd':
496 strcat (pformat, "d");
497 printf (pformat, (int) statbuf->st_dev);
498 break;
499 case 'D':
500 strcat (pformat, "x");
501 printf (pformat, (int) statbuf->st_dev);
502 break;
503 case 'i':
504 strcat (pformat, "d");
505 printf (pformat, (int) statbuf->st_ino);
506 break;
507 case 'a':
508 strcat (pformat, "o");
509 printf (pformat, statbuf->st_mode & 07777);
510 break;
511 case 'A':
512 print_human_access (statbuf);
513 break;
514 case 'f':
515 strcat (pformat, "x");
516 printf (pformat, statbuf->st_mode);
517 break;
518 case 'F':
519 print_human_type (statbuf->st_mode);
520 break;
521 case 'h':
522 strcat (pformat, "d");
523 printf (pformat, (int) statbuf->st_nlink);
524 break;
525 case 'u':
526 strcat (pformat, "d");
527 printf (pformat, statbuf->st_uid);
528 break;
529 case 'U':
530 strcat (pformat, "s");
531 setpwent ();
532 pw_ent = getpwuid (statbuf->st_uid);
533 printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
534 break;
535 case 'g':
536 strcat (pformat, "d");
537 printf (pformat, statbuf->st_gid);
538 break;
539 case 'G':
540 strcat (pformat, "s");
541 setgrent ();
542 gw_ent = getgrgid (statbuf->st_gid);
543 printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
544 break;
545 case 't':
546 strcat (pformat, "x");
547 printf (pformat, major (statbuf->st_rdev));
548 break;
549 case 'T':
550 strcat (pformat, "x");
551 printf (pformat, minor (statbuf->st_rdev));
552 break;
553 case 's':
554 strcat (pformat, PRIuMAX);
555 printf (pformat, (uintmax_t) (statbuf->st_size));
556 break;
557 case 'b':
558 strcat (pformat, "u");
559 printf (pformat, (unsigned int) statbuf->st_blocks);
560 break;
561 case 'o':
562 strcat (pformat, "d");
563 printf (pformat, (int) statbuf->st_blksize);
564 break;
565 case 'x':
566 print_human_time (&(statbuf->st_atime));
567 break;
568 case 'X':
569 strcat (pformat, "d");
570 printf (pformat, (int) statbuf->st_atime);
571 break;
572 case 'y':
573 print_human_time (&(statbuf->st_mtime));
574 break;
575 case 'Y':
576 strcat (pformat, "d");
577 printf (pformat, (int) statbuf->st_mtime);
578 break;
579 case 'z':
580 print_human_time (&(statbuf->st_ctime));
581 break;
582 case 'Z':
583 strcat (pformat, "d");
584 printf (pformat, (int) statbuf->st_ctime);
585 break;
586 default:
587 strcat (pformat, "c");
588 printf (pformat, m);
589 break;
593 static void
594 print_it (char const *masterformat, char const *filename,
595 void (*print_func) (char *, char, char const *, void const *),
596 void const *data)
598 char *b;
600 /* create a working copy of the format string */
601 char *format = xstrdup (masterformat);
603 char *dest = xmalloc (strlen (format) + 1);
606 b = format;
607 while (b)
609 char *p = strchr (b, '%');
610 if (p != NULL)
612 size_t len;
613 *p++ = '\0';
614 fputs (b, stdout);
616 len = strspn (p, "#-+.I 0123456789");
617 dest[0] = '%';
618 memcpy (dest + 1, p, len);
619 dest[1 + len] = 0;
620 p += len;
622 switch (*p)
624 case '\0':
625 case '%':
626 fputs ("%", stdout);
627 break;
628 default:
629 print_func (dest, *p, filename, data);
630 break;
632 b = p + 1;
634 else
636 fputs (b, stdout);
637 b = NULL;
640 free (format);
641 free (dest);
642 fputc ('\n', stdout);
645 /* stat the filesystem and print what we find */
646 static void
647 do_statfs (char const *filename, int terse, char const *format)
649 STRUCT_STATVFS statfsbuf;
650 int i = statfs (filename, &statfsbuf);
652 if (i == -1)
654 error (0, errno, _("cannot read file system information for %s"),
655 quote (filename));
656 return;
659 if (format == NULL)
661 format = (terse
662 ? "%n %i %l %t %b %f %a %s %c %d"
663 : " File: \"%n\"\n"
664 " ID: %-8i Namelen: %-7l Type: %T\n"
665 "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
666 "Inodes: Total: %-10c Free: %-10d");
669 print_it (format, filename, print_statfs, &statfsbuf);
672 /* stat the file and print what we find */
673 static void
674 do_stat (char const *filename, int follow_links, int terse,
675 char const *format)
677 struct stat statbuf;
678 int i = ((follow_links == 1)
679 ? stat (filename, &statbuf)
680 : lstat (filename, &statbuf));
682 if (i == -1)
684 error (0, errno, _("cannot stat %s"), quote (filename));
685 return;
688 if (format == NULL)
690 if (terse != 0)
692 format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
694 else
696 /* tmp hack to match orignal output until conditional implemented */
697 i = statbuf.st_mode & S_IFMT;
698 if (i == S_IFCHR || i == S_IFBLK)
700 format =
701 " File: %N\n"
702 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
703 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
704 " Device type: %t,%T\n"
705 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
706 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
708 else
710 format =
711 " File: %N\n"
712 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
713 "Device: %Dh/%dd\tInode: %-10i Links: %-5h\n"
714 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
715 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
719 print_it (format, filename, print_stat, &statbuf);
722 void
723 usage (int status)
725 if (status != 0)
726 fprintf (stderr, _("Try `%s --help' for more information.\n"),
727 program_name);
728 else
730 printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
731 fputs (_("\
732 Display file or filesystem status.\n\
734 -f, --filesystem display filesystem status instead of file status\n\
735 -c --format=FORMAT use the specified FORMAT instead of the default\n\
736 -L, --dereference follow links\n\
737 -t, --terse print the information in terse form\n\
738 "), stdout);
739 fputs (HELP_OPTION_DESCRIPTION, stdout);
740 fputs (VERSION_OPTION_DESCRIPTION, stdout);
742 fputs (_("\n\
743 The valid format sequences for files (without --filesystem):\n\
745 %A - Access rights in human readable form\n\
746 %a - Access rights in octal\n\
747 %b - Number of blocks allocated\n\
748 "), stdout);
749 fputs (_("\
750 %D - Device number in hex\n\
751 %d - Device number in decimal\n\
752 %F - File type\n\
753 %f - raw mode in hex\n\
754 %G - Group name of owner\n\
755 %g - Group ID of owner\n\
756 "), stdout);
757 fputs (_("\
758 %h - Number of hard links\n\
759 %i - Inode number\n\
760 %N - Quoted File name with dereference if symbolic link\n\
761 %n - File name\n\
762 %o - IO block size\n\
763 %s - Total size, in bytes\n\
764 %T - Minor device type in hex\n\
765 %t - Major device type in hex\n\
766 "), stdout);
767 fputs (_("\
768 %U - User name of owner\n\
769 %u - User ID of owner\n\
770 %X - Time of last access as seconds since Epoch\n\
771 %x - Time of last access\n\
772 %Y - Time of last modification as seconds since Epoch\n\
773 %y - Time of last modification\n\
774 %Z - Time of last change as seconds since Epoch\n\
775 %z - Time of last change\n\
777 "), stdout);
779 fputs (_("\
780 Valid format sequences for file systems:\n\
782 %a - Free blocks available to non-superuser\n\
783 %b - Total data blocks in file system\n\
784 %c - Total file nodes in file system\n\
785 %d - Free file nodes in file system\n\
786 %f - Free blocks in file system\n\
787 "), stdout);
788 fputs (_("\
789 %i - File System id in hex\n\
790 %l - Maximum length of filenames\n\
791 %n - File name\n\
792 %s - Optimal transfer block size\n\
793 %T - Type in human readable form\n\
794 %t - Type in hex\n\
795 "), stdout);
796 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
798 exit (status);
802 main (int argc, char *argv[])
804 int c;
805 int i;
806 int follow_links = 0;
807 int fs = 0;
808 int terse = 0;
809 char *format = NULL;
811 program_name = argv[0];
812 setlocale (LC_ALL, "");
813 bindtextdomain (PACKAGE, LOCALEDIR);
814 textdomain (PACKAGE);
816 atexit (close_stdout);
818 while ((c = getopt_long (argc, argv, "c:fLlt", long_options, NULL)) != -1)
820 switch (c)
822 case 'c':
823 format = optarg;
824 break;
825 case 'l': /* deprecated */
826 case 'L':
827 follow_links = 1;
828 break;
829 case 'f':
830 fs = 1;
831 break;
832 case 't':
833 terse = 1;
834 break;
836 case_GETOPT_HELP_CHAR;
838 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
840 default:
841 usage (EXIT_FAILURE);
845 if (argc == optind)
847 error (0, 0, _("too few arguments"));
848 usage (EXIT_FAILURE);
851 for (i = optind; i < argc; i++)
853 if (fs == 0)
854 do_stat (argv[i], follow_links, terse, format);
855 else
856 do_statfs (argv[i], terse, format);
859 exit (EXIT_SUCCESS);