(G_fail): New global.
[coreutils.git] / src / stat.c
blob71b8bb7253fc69fa31ceda4d3a54605411a2513d
1 /* stat.c -- display file or filesystem status
2 Copyright (C) 2001, 2002, 2003 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 "system.h"
48 #include "closeout.h"
49 #include "error.h"
50 #include "filemode.h"
51 #include "file-type.h"
52 #include "fs.h"
53 #include "getopt.h"
54 #include "quote.h"
55 #include "quotearg.h"
56 #include "strftime.h"
57 #include "xreadlink.h"
59 #define NAMEMAX_FORMAT PRIuMAX
61 #if HAVE_STRUCT_STATVFS_F_BASETYPE
62 # define STRUCT_STATVFS struct statvfs
63 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS
64 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
65 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
66 # endif
67 #else
68 # define STRUCT_STATVFS struct statfs
69 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS
70 # if HAVE_STRUCT_STATFS_F_NAMELEN
71 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
72 # endif
73 #endif
75 #ifndef SB_F_NAMEMAX
76 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
77 # define SB_F_NAMEMAX(S) "*"
78 # undef NAMEMAX_FORMAT
79 # define NAMEMAX_FORMAT "s"
80 #endif
82 #define PROGRAM_NAME "stat"
84 #define AUTHORS "Michael Meskes"
86 static struct option const long_options[] = {
87 {"link", no_argument, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */
88 {"dereference", no_argument, 0, 'L'},
89 {"format", required_argument, 0, 'c'},
90 {"filesystem", no_argument, 0, 'f'},
91 {"terse", no_argument, 0, 't'},
92 {GETOPT_HELP_OPTION_DECL},
93 {GETOPT_VERSION_OPTION_DECL},
94 {NULL, 0, NULL, 0}
97 /* Nonzero means we should exit with EXIT_FAILURE upon completion. */
98 static int G_fail;
100 char *program_name;
102 /* Return the type of the specified file system.
103 Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
104 Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
105 Still others have neither and have to get by with f_type (Linux). */
106 static char *
107 human_fstype (STRUCT_STATVFS const *statfsbuf)
109 #if HAVE_STRUCT_STATVFS_F_BASETYPE
110 return statfsbuf->f_basetype;
111 #else
112 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
113 return statfsbuf->f_fstypename;
114 # else
115 char const *type;
117 switch (statfsbuf->f_type)
119 # if defined __linux__
120 case S_MAGIC_AFFS:
121 type = "affs";
122 break;
123 case S_MAGIC_EXT:
124 type = "ext";
125 break;
126 case S_MAGIC_EXT2_OLD:
127 type = "ext2";
128 break;
129 case S_MAGIC_EXT2:
130 type = "ext2/ext3";
131 break;
132 case S_MAGIC_HPFS:
133 type = "hpfs";
134 break;
135 case S_MAGIC_ISOFS:
136 type = "isofs";
137 break;
138 case S_MAGIC_ISOFS_WIN:
139 type = "isofs";
140 break;
141 case S_MAGIC_ISOFS_R_WIN:
142 type = "isofs";
143 break;
144 case S_MAGIC_MINIX:
145 type = "minix";
146 break;
147 case S_MAGIC_MINIX_30:
148 type = "minix (30 char.)";
149 break;
150 case S_MAGIC_MINIX_V2:
151 type = "minix v2";
152 break;
153 case S_MAGIC_MINIX_V2_30:
154 type = "minix v2 (30 char.)";
155 break;
156 case S_MAGIC_MSDOS:
157 type = "msdos";
158 break;
159 case S_MAGIC_FAT:
160 type = "fat";
161 break;
162 case S_MAGIC_NCP:
163 type = "novell";
164 break;
165 case S_MAGIC_NFS:
166 type = "nfs";
167 break;
168 case S_MAGIC_PROC:
169 type = "proc";
170 break;
171 case S_MAGIC_SMB:
172 type = "smb";
173 break;
174 case S_MAGIC_XENIX:
175 type = "xenix";
176 break;
177 case S_MAGIC_SYSV4:
178 type = "sysv4";
179 break;
180 case S_MAGIC_SYSV2:
181 type = "sysv2";
182 break;
183 case S_MAGIC_COH:
184 type = "coh";
185 break;
186 case S_MAGIC_UFS:
187 type = "ufs";
188 break;
189 case S_MAGIC_XIAFS:
190 type = "xia";
191 break;
192 case S_MAGIC_NTFS:
193 type = "ntfs";
194 break;
195 case S_MAGIC_TMPFS:
196 type = "tmpfs";
197 break;
198 case S_MAGIC_REISERFS:
199 type = "reiserfs";
200 break;
201 case S_MAGIC_CRAMFS:
202 type = "cramfs";
203 break;
204 case S_MAGIC_ROMFS:
205 type = "romfs";
206 break;
207 # elif __GNU__
208 case FSTYPE_UFS:
209 type = "ufs";
210 break;
211 case FSTYPE_NFS:
212 type = "nfs";
213 break;
214 case FSTYPE_GFS:
215 type = "gfs";
216 break;
217 case FSTYPE_LFS:
218 type = "lfs";
219 break;
220 case FSTYPE_SYSV:
221 type = "sysv";
222 break;
223 case FSTYPE_FTP:
224 type = "ftp";
225 break;
226 case FSTYPE_TAR:
227 type = "tar";
228 break;
229 case FSTYPE_AR:
230 type = "ar";
231 break;
232 case FSTYPE_CPIO:
233 type = "cpio";
234 break;
235 case FSTYPE_MSLOSS:
236 type = "msloss";
237 break;
238 case FSTYPE_CPM:
239 type = "cpm";
240 break;
241 case FSTYPE_HFS:
242 type = "hfs";
243 break;
244 case FSTYPE_DTFS:
245 type = "dtfs";
246 break;
247 case FSTYPE_GRFS:
248 type = "grfs";
249 break;
250 case FSTYPE_TERM:
251 type = "term";
252 break;
253 case FSTYPE_DEV:
254 type = "dev";
255 break;
256 case FSTYPE_PROC:
257 type = "proc";
258 break;
259 case FSTYPE_IFSOCK:
260 type = "ifsock";
261 break;
262 case FSTYPE_AFS:
263 type = "afs";
264 break;
265 case FSTYPE_DFS:
266 type = "dfs";
267 break;
268 case FSTYPE_PROC9:
269 type = "proc9";
270 break;
271 case FSTYPE_SOCKET:
272 type = "socket";
273 break;
274 case FSTYPE_MISC:
275 type = "misc";
276 break;
277 case FSTYPE_EXT2FS:
278 type = "ext2/ext3";
279 break;
280 case FSTYPE_HTTP:
281 type = "http";
282 break;
283 case FSTYPE_MEMFS:
284 type = "memfs";
285 break;
286 case FSTYPE_ISO9660:
287 type = "iso9660";
288 break;
289 # endif
290 default:
291 type = NULL;
292 break;
295 if (type)
296 return (char *) type;
299 static char buf[sizeof "UNKNOWN (0x%x)" - 2
300 + 2 * sizeof (statfsbuf->f_type)];
301 sprintf (buf, "UNKNOWN (0x%x)", statfsbuf->f_type);
302 return buf;
304 # endif
305 #endif
308 static char *
309 human_access (struct stat const *statbuf)
311 static char modebuf[11];
312 mode_string (statbuf->st_mode, modebuf);
313 modebuf[10] = 0;
314 return modebuf;
317 static char *
318 human_time (time_t const *t)
320 static char str[80];
321 struct tm *tm = localtime (t);
322 if (tm == NULL)
324 G_fail = 1;
325 return (char *) _("*** invalid date/time ***");
327 nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, 0);
328 return str;
331 /* print statfs info */
332 static void
333 print_statfs (char *pformat, char m, char const *filename,
334 void const *data)
336 STRUCT_STATVFS const *statfsbuf = data;
338 switch (m)
340 case 'n':
341 strcat (pformat, "s");
342 printf (pformat, filename);
343 break;
345 case 'i':
346 #if HAVE_STRUCT_STATXFS_F_FSID___VAL
347 strcat (pformat, "x %-8x");
348 printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */
349 statfsbuf->f_fsid.__val[1]);
350 #else
351 strcat (pformat, "Lx");
352 printf (pformat, statfsbuf->f_fsid);
353 #endif
354 break;
356 case 'l':
357 strcat (pformat, NAMEMAX_FORMAT);
358 printf (pformat, SB_F_NAMEMAX (statfsbuf));
359 break;
360 case 't':
361 #if HAVE_STRUCT_STATXFS_F_TYPE
362 strcat (pformat, "lx");
363 printf (pformat, (long int) (statfsbuf->f_type)); /* no equiv. */
364 #else
365 fputc ('*', stdout);
366 #endif
367 break;
368 case 'T':
369 strcat (pformat, "s");
370 printf (pformat, human_fstype (statfsbuf));
371 break;
372 case 'b':
373 strcat (pformat, PRIdMAX);
374 printf (pformat, (intmax_t) (statfsbuf->f_blocks));
375 break;
376 case 'f':
377 strcat (pformat, PRIdMAX);
378 printf (pformat, (intmax_t) (statfsbuf->f_bfree));
379 break;
380 case 'a':
381 strcat (pformat, PRIdMAX);
382 printf (pformat, (intmax_t) (statfsbuf->f_bavail));
383 break;
384 case 's':
385 strcat (pformat, "ld");
386 printf (pformat, (long int) (statfsbuf->f_bsize));
387 break;
388 case 'c':
389 strcat (pformat, PRIdMAX);
390 printf (pformat, (intmax_t) (statfsbuf->f_files));
391 break;
392 case 'd':
393 strcat (pformat, PRIdMAX);
394 printf (pformat, (intmax_t) (statfsbuf->f_ffree));
395 break;
397 default:
398 strcat (pformat, "c");
399 printf (pformat, m);
400 break;
404 /* print stat info */
405 static void
406 print_stat (char *pformat, char m, char const *filename, void const *data)
408 struct stat *statbuf = (struct stat *) data;
409 struct passwd *pw_ent;
410 struct group *gw_ent;
412 switch (m)
414 case 'n':
415 strcat (pformat, "s");
416 printf (pformat, filename);
417 break;
418 case 'N':
419 strcat (pformat, "s");
420 if (S_ISLNK (statbuf->st_mode))
422 char *linkname = xreadlink (filename);
423 if (linkname == NULL)
425 error (0, errno, _("cannot read symbolic link %s"),
426 quote (filename));
427 return;
429 /*printf("\"%s\" -> \"%s\"", filename, linkname); */
430 printf (pformat, quote (filename));
431 printf (" -> ");
432 printf (pformat, quote (linkname));
434 else
436 printf (pformat, quote (filename));
438 break;
439 case 'd':
440 strcat (pformat, "d");
441 printf (pformat, (int) statbuf->st_dev);
442 break;
443 case 'D':
444 strcat (pformat, "x");
445 printf (pformat, (int) statbuf->st_dev);
446 break;
447 case 'i':
448 strcat (pformat, "d");
449 printf (pformat, (int) statbuf->st_ino);
450 break;
451 case 'a':
452 strcat (pformat, "o");
453 printf (pformat, statbuf->st_mode & 07777);
454 break;
455 case 'A':
456 strcat (pformat, "s");
457 printf (pformat, human_access (statbuf));
458 break;
459 case 'f':
460 strcat (pformat, "x");
461 printf (pformat, statbuf->st_mode);
462 break;
463 case 'F':
464 strcat (pformat, "s");
465 printf (pformat, file_type (statbuf));
466 break;
467 case 'h':
468 strcat (pformat, "d");
469 printf (pformat, (int) statbuf->st_nlink);
470 break;
471 case 'u':
472 strcat (pformat, "d");
473 printf (pformat, statbuf->st_uid);
474 break;
475 case 'U':
476 strcat (pformat, "s");
477 setpwent ();
478 pw_ent = getpwuid (statbuf->st_uid);
479 printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
480 break;
481 case 'g':
482 strcat (pformat, "d");
483 printf (pformat, statbuf->st_gid);
484 break;
485 case 'G':
486 strcat (pformat, "s");
487 setgrent ();
488 gw_ent = getgrgid (statbuf->st_gid);
489 printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
490 break;
491 case 't':
492 strcat (pformat, "x");
493 printf (pformat, major (statbuf->st_rdev));
494 break;
495 case 'T':
496 strcat (pformat, "x");
497 printf (pformat, minor (statbuf->st_rdev));
498 break;
499 case 's':
500 strcat (pformat, PRIuMAX);
501 printf (pformat, (uintmax_t) (statbuf->st_size));
502 break;
503 case 'b':
504 strcat (pformat, "u");
505 printf (pformat, (unsigned int) ST_NBLOCKS (*statbuf));
506 break;
507 case 'o':
508 strcat (pformat, "d");
509 printf (pformat, (int) statbuf->st_blksize);
510 break;
511 case 'x':
512 strcat (pformat, "s");
513 printf (pformat, human_time (&(statbuf->st_atime)));
514 break;
515 case 'X':
516 strcat (pformat, "d");
517 printf (pformat, (int) statbuf->st_atime);
518 break;
519 case 'y':
520 strcat (pformat, "s");
521 printf (pformat, human_time (&(statbuf->st_mtime)));
522 break;
523 case 'Y':
524 strcat (pformat, "d");
525 printf (pformat, (int) statbuf->st_mtime);
526 break;
527 case 'z':
528 strcat (pformat, "s");
529 printf (pformat, human_time (&(statbuf->st_ctime)));
530 break;
531 case 'Z':
532 strcat (pformat, "d");
533 printf (pformat, (int) statbuf->st_ctime);
534 break;
535 default:
536 strcat (pformat, "c");
537 printf (pformat, m);
538 break;
542 static void
543 print_it (char const *masterformat, char const *filename,
544 void (*print_func) (char *, char, char const *, void const *),
545 void const *data)
547 char *b;
549 /* create a working copy of the format string */
550 char *format = xstrdup (masterformat);
552 char *dest = xmalloc (strlen (format) + 1);
555 b = format;
556 while (b)
558 char *p = strchr (b, '%');
559 if (p != NULL)
561 size_t len;
562 *p++ = '\0';
563 fputs (b, stdout);
565 len = strspn (p, "#-+.I 0123456789");
566 dest[0] = '%';
567 memcpy (dest + 1, p, len);
568 dest[1 + len] = 0;
569 p += len;
571 switch (*p)
573 case '\0':
574 case '%':
575 fputs ("%", stdout);
576 break;
577 default:
578 print_func (dest, *p, filename, data);
579 break;
581 b = p + 1;
583 else
585 fputs (b, stdout);
586 b = NULL;
589 free (format);
590 free (dest);
591 fputc ('\n', stdout);
594 /* stat the filesystem and print what we find */
595 static void
596 do_statfs (char const *filename, int terse, char const *format)
598 STRUCT_STATVFS statfsbuf;
599 int i = statfs (filename, &statfsbuf);
601 if (i == -1)
603 error (0, errno, _("cannot read file system information for %s"),
604 quote (filename));
605 return;
608 if (format == NULL)
610 format = (terse
611 ? "%n %i %l %t %b %f %a %s %c %d"
612 : " File: \"%n\"\n"
613 " ID: %-8i Namelen: %-7l Type: %T\n"
614 "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
615 "Inodes: Total: %-10c Free: %-10d");
618 print_it (format, filename, print_statfs, &statfsbuf);
621 /* stat the file and print what we find */
622 static void
623 do_stat (char const *filename, int follow_links, int terse,
624 char const *format)
626 struct stat statbuf;
627 int i = ((follow_links == 1)
628 ? stat (filename, &statbuf)
629 : lstat (filename, &statbuf));
631 if (i == -1)
633 error (0, errno, _("cannot stat %s"), quote (filename));
634 return;
637 if (format == NULL)
639 if (terse != 0)
641 format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
643 else
645 /* tmp hack to match orignal output until conditional implemented */
646 i = statbuf.st_mode & S_IFMT;
647 if (i == S_IFCHR || i == S_IFBLK)
649 format =
650 " File: %N\n"
651 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
652 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
653 " Device type: %t,%T\n"
654 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
655 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
657 else
659 format =
660 " File: %N\n"
661 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
662 "Device: %Dh/%dd\tInode: %-10i Links: %-5h\n"
663 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
664 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
668 print_it (format, filename, print_stat, &statbuf);
671 void
672 usage (int status)
674 if (status != 0)
675 fprintf (stderr, _("Try `%s --help' for more information.\n"),
676 program_name);
677 else
679 printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
680 fputs (_("\
681 Display file or filesystem status.\n\
683 -f, --filesystem display filesystem status instead of file status\n\
684 -c --format=FORMAT use the specified FORMAT instead of the default\n\
685 -L, --dereference follow links\n\
686 -t, --terse print the information in terse form\n\
687 "), stdout);
688 fputs (HELP_OPTION_DESCRIPTION, stdout);
689 fputs (VERSION_OPTION_DESCRIPTION, stdout);
691 fputs (_("\n\
692 The valid format sequences for files (without --filesystem):\n\
694 %A Access rights in human readable form\n\
695 %a Access rights in octal\n\
696 %b Number of blocks allocated\n\
697 "), stdout);
698 fputs (_("\
699 %D Device number in hex\n\
700 %d Device number in decimal\n\
701 %F File type\n\
702 %f raw mode in hex\n\
703 %G Group name of owner\n\
704 %g Group ID of owner\n\
705 "), stdout);
706 fputs (_("\
707 %h Number of hard links\n\
708 %i Inode number\n\
709 %N Quoted File name with dereference if symbolic link\n\
710 %n File name\n\
711 %o IO block size\n\
712 %s Total size, in bytes\n\
713 %T Minor device type in hex\n\
714 %t Major device type in hex\n\
715 "), stdout);
716 fputs (_("\
717 %U User name of owner\n\
718 %u User ID of owner\n\
719 %X Time of last access as seconds since Epoch\n\
720 %x Time of last access\n\
721 %Y Time of last modification as seconds since Epoch\n\
722 %y Time of last modification\n\
723 %Z Time of last change as seconds since Epoch\n\
724 %z Time of last change\n\
726 "), stdout);
728 fputs (_("\
729 Valid format sequences for file systems:\n\
731 %a Free blocks available to non-superuser\n\
732 %b Total data blocks in file system\n\
733 %c Total file nodes in file system\n\
734 %d Free file nodes in file system\n\
735 %f Free blocks in file system\n\
736 "), stdout);
737 fputs (_("\
738 %i File System id in hex\n\
739 %l Maximum length of filenames\n\
740 %n File name\n\
741 %s Optimal transfer block size\n\
742 %T Type in human readable form\n\
743 %t Type in hex\n\
744 "), stdout);
745 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
747 exit (status);
751 main (int argc, char *argv[])
753 int c;
754 int i;
755 int follow_links = 0;
756 int fs = 0;
757 int terse = 0;
758 char *format = NULL;
760 program_name = argv[0];
761 setlocale (LC_ALL, "");
762 bindtextdomain (PACKAGE, LOCALEDIR);
763 textdomain (PACKAGE);
765 atexit (close_stdout);
767 while ((c = getopt_long (argc, argv, "c:fLlt", long_options, NULL)) != -1)
769 switch (c)
771 case 'c':
772 format = optarg;
773 break;
774 case 'l': /* deprecated */
775 case 'L':
776 follow_links = 1;
777 break;
778 case 'f':
779 fs = 1;
780 break;
781 case 't':
782 terse = 1;
783 break;
785 case_GETOPT_HELP_CHAR;
787 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
789 default:
790 usage (EXIT_FAILURE);
794 if (argc == optind)
796 error (0, 0, _("too few arguments"));
797 usage (EXIT_FAILURE);
800 for (i = optind; i < argc; i++)
802 if (fs == 0)
803 do_stat (argv[i], follow_links, terse, format);
804 else
805 do_statfs (argv[i], terse, format);
808 exit (G_fail ? EXIT_FAILURE : EXIT_SUCCESS);