(src_to_dest_lookup): New function.
[coreutils.git] / src / stat.c
blob527ccf2fe764cfdcab73c354fa5be0495976914d
1 /* stat.c -- display file or filesystem status
2 Copyright (C) 2001, 2002, 2003, 2004 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 #include <pwd.h>
25 #include <grp.h>
26 #if HAVE_SYS_STATVFS_H && HAVE_STRUCT_STATVFS_F_BASETYPE
27 # include <sys/statvfs.h>
28 #elif HAVE_SYS_VFS_H
29 # include <sys/vfs.h>
30 #elif HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
31 /* NOTE: freebsd5.0 needs sys/param.h and sys/mount.h for statfs.
32 It does have statvfs.h, but shouldn't use it, since it doesn't
33 HAVE_STRUCT_STATVFS_F_BASETYPE. So find a clean way to fix it. */
34 /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
35 # include <sys/param.h>
36 # include <sys/mount.h>
37 # if HAVE_NETINET_IN_H && HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H
38 /* Ultrix 4.4 needs these for the declaration of struct statfs. */
39 # include <netinet/in.h>
40 # include <nfs/nfs_clnt.h>
41 # include <nfs/vfs.h>
42 # endif
43 #endif
45 #include "system.h"
47 #include "error.h"
48 #include "filemode.h"
49 #include "file-type.h"
50 #include "fs.h"
51 #include "getopt.h"
52 #include "inttostr.h"
53 #include "quote.h"
54 #include "quotearg.h"
55 #include "strftime.h"
56 #include "xreadlink.h"
58 #define NAMEMAX_FORMAT PRIuMAX
60 #if HAVE_STRUCT_STATVFS_F_BASETYPE
61 # define STRUCT_STATVFS struct statvfs
62 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS
63 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
64 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
65 # endif
66 #else
67 # define STRUCT_STATVFS struct statfs
68 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS
69 # if HAVE_STRUCT_STATFS_F_NAMELEN
70 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
71 # endif
72 #endif
74 #ifndef SB_F_NAMEMAX
75 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
76 # define SB_F_NAMEMAX(S) "*"
77 # undef NAMEMAX_FORMAT
78 # define NAMEMAX_FORMAT "s"
79 #endif
81 #if HAVE_STRUCT_STATVFS_F_BASETYPE
82 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
83 #else
84 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
85 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
86 # endif
87 #endif
89 #define PROGRAM_NAME "stat"
91 #define AUTHORS "Michael Meskes"
93 static struct option const long_options[] = {
94 {"link", no_argument, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */
95 {"dereference", no_argument, 0, 'L'},
96 {"format", required_argument, 0, 'c'},
97 {"filesystem", no_argument, 0, 'f'},
98 {"terse", no_argument, 0, 't'},
99 {GETOPT_HELP_OPTION_DECL},
100 {GETOPT_VERSION_OPTION_DECL},
101 {NULL, 0, NULL, 0}
104 /* Nonzero means we should exit with EXIT_FAILURE upon completion. */
105 static int G_fail;
107 char *program_name;
109 /* Return the type of the specified file system.
110 Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
111 Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
112 Still others have neither and have to get by with f_type (Linux). */
113 static char *
114 human_fstype (STRUCT_STATVFS const *statfsbuf)
116 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
117 /* Cast away the `const' attribute. */
118 return (char *) statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
119 #else
120 char const *type;
121 switch (statfsbuf->f_type)
123 # if defined __linux__
125 /* IMPORTANT NOTE: Each of the following `case S_MAGIC_...:'
126 statements must be followed by a hexadecimal constant in
127 a comment. The S_MAGIC_... name and constant are automatically
128 combined to produce the #define directives in fs.h. */
130 case S_MAGIC_AFFS: /* 0xADFF */
131 type = "affs";
132 break;
133 case S_MAGIC_DEVPTS: /* 0x1CD1 */
134 type = "devpts";
135 break;
136 case S_MAGIC_EXT: /* 0x137D */
137 type = "ext";
138 break;
139 case S_MAGIC_EXT2_OLD: /* 0xEF51 */
140 type = "ext2";
141 break;
142 case S_MAGIC_EXT2: /* 0xEF53 */
143 type = "ext2/ext3";
144 break;
145 case S_MAGIC_HPFS: /* 0xF995E849 */
146 type = "hpfs";
147 break;
148 case S_MAGIC_ISOFS: /* 0x9660 */
149 type = "isofs";
150 break;
151 case S_MAGIC_ISOFS_WIN: /* 0x4000 */
152 type = "isofs";
153 break;
154 case S_MAGIC_ISOFS_R_WIN: /* 0x4004 */
155 type = "isofs";
156 break;
157 case S_MAGIC_MINIX: /* 0x137F */
158 type = "minix";
159 break;
160 case S_MAGIC_MINIX_30: /* 0x138F */
161 type = "minix (30 char.)";
162 break;
163 case S_MAGIC_MINIX_V2: /* 0x2468 */
164 type = "minix v2";
165 break;
166 case S_MAGIC_MINIX_V2_30: /* 0x2478 */
167 type = "minix v2 (30 char.)";
168 break;
169 case S_MAGIC_MSDOS: /* 0x4d44 */
170 type = "msdos";
171 break;
172 case S_MAGIC_FAT: /* 0x4006 */
173 type = "fat";
174 break;
175 case S_MAGIC_NCP: /* 0x564c */
176 type = "novell";
177 break;
178 case S_MAGIC_NFS: /* 0x6969 */
179 type = "nfs";
180 break;
181 case S_MAGIC_PROC: /* 0x9fa0 */
182 type = "proc";
183 break;
184 case S_MAGIC_SMB: /* 0x517B */
185 type = "smb";
186 break;
187 case S_MAGIC_XENIX: /* 0x012FF7B4 */
188 type = "xenix";
189 break;
190 case S_MAGIC_SYSV4: /* 0x012FF7B5 */
191 type = "sysv4";
192 break;
193 case S_MAGIC_SYSV2: /* 0x012FF7B6 */
194 type = "sysv2";
195 break;
196 case S_MAGIC_COH: /* 0x012FF7B7 */
197 type = "coh";
198 break;
199 case S_MAGIC_UFS: /* 0x00011954 */
200 type = "ufs";
201 break;
202 case S_MAGIC_XIAFS: /* 0x012FD16D */
203 type = "xia";
204 break;
205 case S_MAGIC_NTFS: /* 0x5346544e */
206 type = "ntfs";
207 break;
208 case S_MAGIC_TMPFS: /* 0x1021994 */
209 type = "tmpfs";
210 break;
211 case S_MAGIC_REISERFS: /* 0x52654973 */
212 type = "reiserfs";
213 break;
214 case S_MAGIC_CRAMFS: /* 0x28cd3d45 */
215 type = "cramfs";
216 break;
217 case S_MAGIC_ROMFS: /* 0x7275 */
218 type = "romfs";
219 break;
220 # elif __GNU__
221 case FSTYPE_UFS:
222 type = "ufs";
223 break;
224 case FSTYPE_NFS:
225 type = "nfs";
226 break;
227 case FSTYPE_GFS:
228 type = "gfs";
229 break;
230 case FSTYPE_LFS:
231 type = "lfs";
232 break;
233 case FSTYPE_SYSV:
234 type = "sysv";
235 break;
236 case FSTYPE_FTP:
237 type = "ftp";
238 break;
239 case FSTYPE_TAR:
240 type = "tar";
241 break;
242 case FSTYPE_AR:
243 type = "ar";
244 break;
245 case FSTYPE_CPIO:
246 type = "cpio";
247 break;
248 case FSTYPE_MSLOSS:
249 type = "msloss";
250 break;
251 case FSTYPE_CPM:
252 type = "cpm";
253 break;
254 case FSTYPE_HFS:
255 type = "hfs";
256 break;
257 case FSTYPE_DTFS:
258 type = "dtfs";
259 break;
260 case FSTYPE_GRFS:
261 type = "grfs";
262 break;
263 case FSTYPE_TERM:
264 type = "term";
265 break;
266 case FSTYPE_DEV:
267 type = "dev";
268 break;
269 case FSTYPE_PROC:
270 type = "proc";
271 break;
272 case FSTYPE_IFSOCK:
273 type = "ifsock";
274 break;
275 case FSTYPE_AFS:
276 type = "afs";
277 break;
278 case FSTYPE_DFS:
279 type = "dfs";
280 break;
281 case FSTYPE_PROC9:
282 type = "proc9";
283 break;
284 case FSTYPE_SOCKET:
285 type = "socket";
286 break;
287 case FSTYPE_MISC:
288 type = "misc";
289 break;
290 case FSTYPE_EXT2FS:
291 type = "ext2/ext3";
292 break;
293 case FSTYPE_HTTP:
294 type = "http";
295 break;
296 case FSTYPE_MEMFS:
297 type = "memfs";
298 break;
299 case FSTYPE_ISO9660:
300 type = "iso9660";
301 break;
302 # endif
303 default:
304 type = NULL;
305 break;
308 if (type)
309 return (char *) type;
312 static char buf[sizeof "UNKNOWN (0x%lx)" - 3
313 + 2 * sizeof (statfsbuf->f_type)];
314 sprintf (buf, "UNKNOWN (0x%lx)", (unsigned long) statfsbuf->f_type);
315 return buf;
317 #endif
320 static char *
321 human_access (struct stat const *statbuf)
323 static char modebuf[11];
324 mode_string (statbuf->st_mode, modebuf);
325 modebuf[10] = 0;
326 return modebuf;
329 static char *
330 human_time (time_t t, int t_ns)
332 static char str[MAX (INT_BUFSIZE_BOUND (intmax_t),
333 (INT_STRLEN_BOUND (int) /* YYYY */
334 + 1 /* because YYYY might equal INT_MAX + 1900 */
335 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
336 struct tm const *tm = localtime (&t);
337 if (tm == NULL)
338 return (TYPE_SIGNED (time_t)
339 ? imaxtostr (t, str)
340 : umaxtostr (t, str));
341 nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, t_ns);
342 return str;
345 /* print statfs info */
346 static void
347 print_statfs (char *pformat, char m, char const *filename,
348 void const *data)
350 STRUCT_STATVFS const *statfsbuf = data;
352 switch (m)
354 case 'n':
355 strcat (pformat, "s");
356 printf (pformat, filename);
357 break;
359 case 'i':
360 #if HAVE_STRUCT_STATXFS_F_FSID___VAL
361 strcat (pformat, "x %-8x");
362 printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */
363 statfsbuf->f_fsid.__val[1]);
364 #else
365 strcat (pformat, "Lx");
366 printf (pformat, statfsbuf->f_fsid);
367 #endif
368 break;
370 case 'l':
371 strcat (pformat, NAMEMAX_FORMAT);
372 printf (pformat, SB_F_NAMEMAX (statfsbuf));
373 break;
374 case 't':
375 #if HAVE_STRUCT_STATXFS_F_TYPE
376 strcat (pformat, "lx");
377 printf (pformat, (long int) (statfsbuf->f_type)); /* no equiv. */
378 #else
379 fputc ('*', stdout);
380 #endif
381 break;
382 case 'T':
383 strcat (pformat, "s");
384 printf (pformat, human_fstype (statfsbuf));
385 break;
386 case 'b':
387 strcat (pformat, PRIdMAX);
388 printf (pformat, (intmax_t) (statfsbuf->f_blocks));
389 break;
390 case 'f':
391 strcat (pformat, PRIdMAX);
392 printf (pformat, (intmax_t) (statfsbuf->f_bfree));
393 break;
394 case 'a':
395 strcat (pformat, PRIdMAX);
396 printf (pformat, (intmax_t) (statfsbuf->f_bavail));
397 break;
398 case 's':
399 strcat (pformat, "ld");
400 printf (pformat, (long int) (statfsbuf->f_bsize));
401 break;
402 case 'c':
403 strcat (pformat, PRIdMAX);
404 printf (pformat, (intmax_t) (statfsbuf->f_files));
405 break;
406 case 'd':
407 strcat (pformat, PRIdMAX);
408 printf (pformat, (intmax_t) (statfsbuf->f_ffree));
409 break;
411 default:
412 strcat (pformat, "c");
413 printf (pformat, m);
414 break;
418 /* print stat info */
419 static void
420 print_stat (char *pformat, char m, char const *filename, void const *data)
422 struct stat *statbuf = (struct stat *) data;
423 struct passwd *pw_ent;
424 struct group *gw_ent;
426 switch (m)
428 case 'n':
429 strcat (pformat, "s");
430 printf (pformat, filename);
431 break;
432 case 'N':
433 strcat (pformat, "s");
434 if (S_ISLNK (statbuf->st_mode))
436 char *linkname = xreadlink (filename);
437 if (linkname == NULL)
439 error (0, errno, _("cannot read symbolic link %s"),
440 quote (filename));
441 return;
443 /*printf("\"%s\" -> \"%s\"", filename, linkname); */
444 printf (pformat, quote (filename));
445 printf (" -> ");
446 printf (pformat, quote (linkname));
448 else
450 printf (pformat, quote (filename));
452 break;
453 case 'd':
454 strcat (pformat, "d");
455 printf (pformat, (int) statbuf->st_dev);
456 break;
457 case 'D':
458 strcat (pformat, "x");
459 printf (pformat, (int) statbuf->st_dev);
460 break;
461 case 'i':
462 strcat (pformat, "d");
463 printf (pformat, (int) statbuf->st_ino);
464 break;
465 case 'a':
466 strcat (pformat, "o");
467 printf (pformat, statbuf->st_mode & 07777);
468 break;
469 case 'A':
470 strcat (pformat, "s");
471 printf (pformat, human_access (statbuf));
472 break;
473 case 'f':
474 strcat (pformat, "x");
475 printf (pformat, statbuf->st_mode);
476 break;
477 case 'F':
478 strcat (pformat, "s");
479 printf (pformat, file_type (statbuf));
480 break;
481 case 'h':
482 strcat (pformat, "d");
483 printf (pformat, (int) statbuf->st_nlink);
484 break;
485 case 'u':
486 strcat (pformat, "d");
487 printf (pformat, statbuf->st_uid);
488 break;
489 case 'U':
490 strcat (pformat, "s");
491 setpwent ();
492 pw_ent = getpwuid (statbuf->st_uid);
493 printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
494 break;
495 case 'g':
496 strcat (pformat, "d");
497 printf (pformat, statbuf->st_gid);
498 break;
499 case 'G':
500 strcat (pformat, "s");
501 setgrent ();
502 gw_ent = getgrgid (statbuf->st_gid);
503 printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
504 break;
505 case 't':
506 strcat (pformat, "x");
507 printf (pformat, major (statbuf->st_rdev));
508 break;
509 case 'T':
510 strcat (pformat, "x");
511 printf (pformat, minor (statbuf->st_rdev));
512 break;
513 case 's':
514 strcat (pformat, PRIuMAX);
515 printf (pformat, (uintmax_t) (statbuf->st_size));
516 break;
517 case 'B':
518 strcat (pformat, "u");
519 printf (pformat, (unsigned int) ST_NBLOCKSIZE);
520 break;
521 case 'b':
522 strcat (pformat, "u");
523 printf (pformat, (unsigned int) ST_NBLOCKS (*statbuf));
524 break;
525 case 'o':
526 strcat (pformat, "d");
527 printf (pformat, (int) statbuf->st_blksize);
528 break;
529 case 'x':
530 strcat (pformat, "s");
531 printf (pformat, human_time (statbuf->st_atime,
532 TIMESPEC_NS (statbuf->st_atim)));
533 break;
534 case 'X':
535 strcat (pformat, "d");
536 printf (pformat, (int) statbuf->st_atime);
537 break;
538 case 'y':
539 strcat (pformat, "s");
540 printf (pformat, human_time (statbuf->st_mtime,
541 TIMESPEC_NS (statbuf->st_mtim)));
542 break;
543 case 'Y':
544 strcat (pformat, "d");
545 printf (pformat, (int) statbuf->st_mtime);
546 break;
547 case 'z':
548 strcat (pformat, "s");
549 printf (pformat, human_time (statbuf->st_ctime,
550 TIMESPEC_NS (statbuf->st_ctim)));
551 break;
552 case 'Z':
553 strcat (pformat, "d");
554 printf (pformat, (int) statbuf->st_ctime);
555 break;
556 default:
557 strcat (pformat, "c");
558 printf (pformat, m);
559 break;
563 static void
564 print_it (char const *masterformat, char const *filename,
565 void (*print_func) (char *, char, char const *, void const *),
566 void const *data)
568 char *b;
570 /* create a working copy of the format string */
571 char *format = xstrdup (masterformat);
573 char *dest = xmalloc (strlen (format) + 1);
575 b = format;
576 while (b)
578 char *p = strchr (b, '%');
579 if (p != NULL)
581 size_t len;
582 *p++ = '\0';
583 fputs (b, stdout);
585 len = strspn (p, "#-+.I 0123456789");
586 dest[0] = '%';
587 memcpy (dest + 1, p, len);
588 dest[1 + len] = 0;
589 p += len;
591 b = p + 1;
592 switch (*p)
594 case '\0':
595 b = NULL;
596 /* fall through */
597 case '%':
598 putchar ('%');
599 break;
600 default:
601 print_func (dest, *p, filename, data);
602 break;
605 else
607 fputs (b, stdout);
608 b = NULL;
611 free (format);
612 free (dest);
613 fputc ('\n', stdout);
616 /* stat the filesystem and print what we find */
617 static void
618 do_statfs (char const *filename, int terse, char const *format)
620 STRUCT_STATVFS statfsbuf;
621 int i = statfs (filename, &statfsbuf);
623 if (i == -1)
625 error (0, errno, _("cannot read file system information for %s"),
626 quote (filename));
627 return;
630 if (format == NULL)
632 format = (terse
633 ? "%n %i %l %t %b %f %a %s %c %d"
634 : " File: \"%n\"\n"
635 " ID: %-8i Namelen: %-7l Type: %T\n"
636 "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
637 "Inodes: Total: %-10c Free: %-10d");
640 print_it (format, filename, print_statfs, &statfsbuf);
643 /* stat the file and print what we find */
644 static void
645 do_stat (char const *filename, int follow_links, int terse,
646 char const *format)
648 struct stat statbuf;
649 int i = ((follow_links == 1)
650 ? stat (filename, &statbuf)
651 : lstat (filename, &statbuf));
653 if (i == -1)
655 error (0, errno, _("cannot stat %s"), quote (filename));
656 return;
659 if (format == NULL)
661 if (terse != 0)
663 format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
665 else
667 /* tmp hack to match orignal output until conditional implemented */
668 i = statbuf.st_mode & S_IFMT;
669 if (i == S_IFCHR || i == S_IFBLK)
671 format =
672 " File: %N\n"
673 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
674 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
675 " Device type: %t,%T\n"
676 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
677 "Access: %x\n" "Modify: %y\n" "Change: %z";
679 else
681 format =
682 " File: %N\n"
683 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
684 "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
685 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
686 "Access: %x\n" "Modify: %y\n" "Change: %z";
690 print_it (format, filename, print_stat, &statbuf);
693 void
694 usage (int status)
696 if (status != EXIT_SUCCESS)
697 fprintf (stderr, _("Try `%s --help' for more information.\n"),
698 program_name);
699 else
701 printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
702 fputs (_("\
703 Display file or filesystem status.\n\
705 -f, --filesystem display filesystem status instead of file status\n\
706 -c --format=FORMAT use the specified FORMAT instead of the default\n\
707 -L, --dereference follow links\n\
708 -t, --terse print the information in terse form\n\
709 "), stdout);
710 fputs (HELP_OPTION_DESCRIPTION, stdout);
711 fputs (VERSION_OPTION_DESCRIPTION, stdout);
713 fputs (_("\n\
714 The valid format sequences for files (without --filesystem):\n\
716 %A Access rights in human readable form\n\
717 %a Access rights in octal\n\
718 %B The size in bytes of each block reported by `%b'\n\
719 %b Number of blocks allocated (see %B)\n\
720 "), stdout);
721 fputs (_("\
722 %D Device number in hex\n\
723 %d Device number in decimal\n\
724 %F File type\n\
725 %f Raw mode in hex\n\
726 %G Group name of owner\n\
727 %g Group ID of owner\n\
728 "), stdout);
729 fputs (_("\
730 %h Number of hard links\n\
731 %i Inode number\n\
732 %N Quoted File name with dereference if symbolic link\n\
733 %n File name\n\
734 %o IO block size\n\
735 %s Total size, in bytes\n\
736 %T Minor device type in hex\n\
737 %t Major device type in hex\n\
738 "), stdout);
739 fputs (_("\
740 %U User name of owner\n\
741 %u User ID of owner\n\
742 %X Time of last access as seconds since Epoch\n\
743 %x Time of last access\n\
744 %Y Time of last modification as seconds since Epoch\n\
745 %y Time of last modification\n\
746 %Z Time of last change as seconds since Epoch\n\
747 %z Time of last change\n\
749 "), stdout);
751 fputs (_("\
752 Valid format sequences for file systems:\n\
754 %a Free blocks available to non-superuser\n\
755 %b Total data blocks in file system\n\
756 %c Total file nodes in file system\n\
757 %d Free file nodes in file system\n\
758 %f Free blocks in file system\n\
759 "), stdout);
760 fputs (_("\
761 %i File System id in hex\n\
762 %l Maximum length of filenames\n\
763 %n File name\n\
764 %s Optimal transfer block size\n\
765 %T Type in human readable form\n\
766 %t Type in hex\n\
767 "), stdout);
768 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
770 exit (status);
774 main (int argc, char *argv[])
776 int c;
777 int i;
778 int follow_links = 0;
779 int fs = 0;
780 int terse = 0;
781 char *format = NULL;
783 initialize_main (&argc, &argv);
784 program_name = argv[0];
785 setlocale (LC_ALL, "");
786 bindtextdomain (PACKAGE, LOCALEDIR);
787 textdomain (PACKAGE);
789 atexit (close_stdout);
791 while ((c = getopt_long (argc, argv, "c:fLlt", long_options, NULL)) != -1)
793 switch (c)
795 case 'c':
796 format = optarg;
797 break;
799 case 'l': /* deprecated */
800 error (0, 0, _("Warning: `-l' is deprecated; use `-L' instead"));
801 /* fall through */
802 case 'L':
803 follow_links = 1;
804 break;
806 case 'f':
807 fs = 1;
808 break;
810 case 't':
811 terse = 1;
812 break;
814 case_GETOPT_HELP_CHAR;
816 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
818 default:
819 usage (EXIT_FAILURE);
823 if (argc == optind)
825 error (0, 0, _("too few arguments"));
826 usage (EXIT_FAILURE);
829 for (i = optind; i < argc; i++)
831 if (fs == 0)
832 do_stat (argv[i], follow_links, terse, format);
833 else
834 do_statfs (argv[i], terse, format);
837 exit (G_fail ? EXIT_FAILURE : EXIT_SUCCESS);