Split some long lines.
[platform/upstream/coreutils.git] / src / stat.c
1 #include <config.h>
2
3 #include <stdio.h>
4 #include <sys/types.h>
5 #ifdef HAVE_SYS_SYSMACROS_H
6 # include <sys/sysmacros.h>
7 #endif
8 #include <pwd.h>
9 #include <grp.h>
10 #include <unistd.h>
11 #include <time.h>
12 #if HAVE_SYS_VFS_H
13 # include <sys/vfs.h>
14 #endif
15 #include <string.h>
16 #include <malloc.h>
17 #include <ctype.h>
18
19 #include "system.h"
20
21 #include "closeout.h"
22 #include "error.h"
23 #include "filemode.h"
24 #include "fs.h"
25 #include "getopt.h"
26 #include "quotearg.h"
27 #include "xreadlink.h"
28
29 #ifdef FLASK_LINUX
30 # include <selinux/fs_secure.h>
31 # include <linux/flask/security.h>
32 # include <selinux/flask_util.h>           /* for is_flask_enabled() */
33 # define SECURITY_ID_T security_id_t
34 #else
35 # define SECURITY_ID_T int
36 # define is_flask_enabled() 0
37 # define stat_secure(a,b,c) stat(a,b)
38 # define lstat_secure(a,b,c) lstat(a,b)
39 #endif
40
41 #define PROGRAM_NAME "stat"
42
43 #define AUTHORS "Michael Meskes"
44
45 static struct option const long_options[] = {
46   {"link", no_argument, 0, 'l'},
47   {"format", required_argument, 0, 'c'},
48   {"filesystem", no_argument, 0, 'f'},
49   {"secure", no_argument, 0, 's'},
50   {"terse", no_argument, 0, 't'},
51   {GETOPT_HELP_OPTION_DECL},
52   {GETOPT_VERSION_OPTION_DECL},
53   {NULL, 0, NULL, 0}
54 };
55
56 static char *program_name;
57
58 static void
59 print_human_type (mode_t mode)
60 {
61   char const *type;
62   switch (mode & S_IFMT)
63     {
64     case S_IFDIR:
65       type = "Directory";
66       break;
67     case S_IFCHR:
68       type = "Character Device";
69       break;
70     case S_IFBLK:
71       type = "Block Device";
72       break;
73     case S_IFREG:
74       type = "Regular File";
75       break;
76     case S_IFLNK:
77       type = "Symbolic Link";
78       break;
79     case S_IFSOCK:
80       type = "Socket";
81       break;
82     case S_IFIFO:
83       type = "Fifo File";
84       break;
85     default:
86       type = "Unknown";
87     }
88   fputs (type, stdout);
89 }
90
91 static void
92 print_human_fstype (struct statfs const *statfsbuf)
93 {
94   char const *type;
95
96   switch (statfsbuf->f_type)
97     {
98 #if defined (__linux__)
99     case S_MAGIC_AFFS:
100       type = "affs";
101       break;
102     case S_MAGIC_EXT:
103       type = "ext";
104       break;
105     case S_MAGIC_EXT2_OLD:
106       type = "ext2";
107       break;
108     case S_MAGIC_EXT2:
109       type = "ext2/ext3";
110       break;
111     case S_MAGIC_HPFS:
112       type = "hpfs";
113       break;
114     case S_MAGIC_ISOFS:
115       type = "isofs";
116       break;
117     case S_MAGIC_ISOFS_WIN:
118       type = "isofs";
119       break;
120     case S_MAGIC_ISOFS_R_WIN:
121       type = "isofs";
122       break;
123     case S_MAGIC_MINIX:
124       type = "minix";
125     case S_MAGIC_MINIX_30:
126       type = "minix (30 char.)";
127       break;
128     case S_MAGIC_MINIX_V2:
129       type = "minix v2";
130       break;
131     case S_MAGIC_MINIX_V2_30:
132       type = "minix v2 (30 char.)";
133       break;
134     case S_MAGIC_MSDOS:
135       type = "msdos";
136       break;
137     case S_MAGIC_FAT:
138       type = "fat";
139       break;
140     case S_MAGIC_NCP:
141       type = "novell";
142       break;
143     case S_MAGIC_NFS:
144       type = "nfs";
145       break;
146     case S_MAGIC_PROC:
147       type = "proc";
148       break;
149     case S_MAGIC_SMB:
150       type = "smb";
151       break;
152     case S_MAGIC_XENIX:
153       type = "xenix";
154       break;
155     case S_MAGIC_SYSV4:
156       type = "sysv4";
157       break;
158     case S_MAGIC_SYSV2:
159       type = "sysv2";
160       break;
161     case S_MAGIC_COH:
162       type = "coh";
163       break;
164     case S_MAGIC_UFS:
165       type = "ufs";
166       break;
167     case S_MAGIC_XIAFS:
168       type = "xia";
169       break;
170     case S_MAGIC_NTFS:
171       type = "ntfs";
172       break;
173     case S_MAGIC_TMPFS:
174       type = "tmpfs";
175       break;
176     case S_MAGIC_REISERFS:
177       type = "reiserfs";
178       break;
179     case S_MAGIC_CRAMFS:
180       type = "cramfs";
181       break;
182     case S_MAGIC_ROMFS:
183       type = "romfs";
184       break;
185 #elif __GNU__
186     case FSTYPE_UFS:
187       type = "ufs";
188       break;
189     case FSTYPE_NFS:
190       type = "nfs";
191       break;
192     case FSTYPE_GFS:
193       type = "gfs";
194       break;
195     case FSTYPE_LFS:
196       type = "lfs";
197       break;
198     case FSTYPE_SYSV:
199       type = "sysv";
200       break;
201     case FSTYPE_FTP:
202       type = "ftp";
203       break;
204     case FSTYPE_TAR:
205       type = "tar";
206       break;
207     case FSTYPE_AR:
208       type = "ar";
209       break;
210     case FSTYPE_CPIO:
211       type = "cpio";
212       break;
213     case FSTYPE_MSLOSS:
214       type = "msloss";
215       break;
216     case FSTYPE_CPM:
217       type = "cpm";
218       break;
219     case FSTYPE_HFS:
220       type = "hfs";
221       break;
222     case FSTYPE_DTFS:
223       type = "dtfs";
224       break;
225     case FSTYPE_GRFS:
226       type = "grfs";
227       break;
228     case FSTYPE_TERM:
229       type = "term";
230       break;
231     case FSTYPE_DEV:
232       type = "dev";
233       break;
234     case FSTYPE_PROC:
235       type = "proc";
236       break;
237     case FSTYPE_IFSOCK:
238       type = "ifsock";
239       break;
240     case FSTYPE_AFS:
241       type = "afs";
242       break;
243     case FSTYPE_DFS:
244       type = "dfs";
245       break;
246     case FSTYPE_PROC9:
247       type = "proc9";
248       break;
249     case FSTYPE_SOCKET:
250       type = "socket";
251       break;
252     case FSTYPE_MISC:
253       type = "misc";
254       break;
255     case FSTYPE_EXT2FS:
256       type = "ext2/ext3";
257       break;
258     case FSTYPE_HTTP:
259       type = "http";
260       break;
261     case FSTYPE_MEMFS:
262       type = "memfs";
263       break;
264     case FSTYPE_ISO9660:
265       type = "iso9660";
266       break;
267 #endif
268     default:
269       type = NULL;
270       break;
271     }
272
273   if (type)
274     fputs (type, stdout);
275   else
276     printf ("UNKNOWN (0x%x)\n", statfsbuf->f_type);
277 }
278
279 static void
280 print_human_access (struct stat const *statbuf)
281 {
282   char modebuf[11];
283   mode_string (statbuf->st_mode, modebuf);
284   modebuf[10] = 0;
285   fputs (modebuf, stdout);
286 }
287
288 static void
289 print_human_time (time_t const *t)
290 {
291   char str[40];
292
293   if (strftime (str, 40, "%c", localtime (t)) > 0) fputs (str, stdout);
294   else printf ("Cannot calculate human readable time, sorry");
295 }
296
297 /* print statfs info */
298 static void
299 print_statfs (char *pformat, char m, char const *filename,
300               void const *data, SECURITY_ID_T sid)
301 {
302     struct statfs const *statfsbuf = data;
303 #ifdef FLASK_LINUX
304     char sbuf[256];
305     int rv;
306     unsigned int sbuflen = sizeof(sbuf);
307 #endif
308
309     switch(m) {
310         case 'n':
311             strcat(pformat, "s");
312             printf(pformat, filename);
313             break;
314
315         case 'i':
316 #if !defined(__linux__) && defined (__GNU__)
317             strcat(pformat, "Lx");
318             printf(pformat, statfsbuf->f_fsid);
319 #else
320             strcat(pformat, "x %-8x");
321             printf(pformat, statfsbuf->f_fsid.__val[0],
322                    statfsbuf->f_fsid.__val[1]);
323 #endif
324             break;
325
326         case 'l':
327             strcat(pformat, "llu");
328             printf(pformat, (uintmax_t) (statfsbuf->f_namelen));
329             break;
330         case 't':
331             strcat(pformat, "lx");
332             printf(pformat, (long int) (statfsbuf->f_type));
333             break;
334         case 'T':
335 /*          print_human_fstype(statfsbuf, pformat);*/
336             print_human_fstype(statfsbuf);
337             break;
338         case 'b':
339             strcat(pformat, "lld");
340             printf(pformat, (intmax_t) (statfsbuf->f_blocks));
341             break;
342         case 'f':
343             strcat(pformat, "lld");
344             printf(pformat, (intmax_t) (statfsbuf->f_bfree));
345             break;
346         case 'a':
347             strcat(pformat, "lld");
348             printf(pformat, (intmax_t) (statfsbuf->f_bavail));
349             break;
350         case 's':
351             strcat(pformat, "ld");
352             printf(pformat, (long int) (statfsbuf->f_bsize));
353             break;
354         case 'c':
355             strcat(pformat, "lld");
356             printf(pformat, (intmax_t) (statfsbuf->f_files));
357             break;
358         case 'd':
359             strcat(pformat, "lld");
360             printf(pformat, (intmax_t) (statfsbuf->f_ffree));
361             break;
362 #ifdef FLASK_LINUX
363         case 'S':
364             strcat(pformat, "d");
365             printf(pformat, sid);
366             break;
367         case 'C':
368             rv = security_sid_to_context(sid, (security_context_t *) &sbuf,
369                                          &sbuflen);
370             if ( rv < 0 )
371                 sprintf(sbuf, "<error finding security context %d>", sid);
372             printf(sbuf);
373             break;
374 #endif
375         default:
376             strcat(pformat, "c");
377             printf(pformat, m);
378             break;
379     }
380 }
381
382 /* print stat info */
383 static void
384 print_stat (char *pformat, char m, char const *filename,
385             void const *data, SECURITY_ID_T sid)
386 {
387     char linkname[256];
388     int i;
389     struct stat *statbuf = (struct stat*)data;
390     struct passwd *pw_ent;
391     struct group *gw_ent;
392 #ifdef FLASK_LINUX
393     char sbuf[256];
394     int rv;
395     unsigned int sbuflen = sizeof(sbuf);
396 #endif
397
398     switch(m) {
399         case 'n':
400             strcat(pformat, "s");
401             printf(pformat, filename);
402             break;
403         case 'N':
404             strcat(pformat, "s");
405             if ((statbuf->st_mode & S_IFMT) == S_IFLNK) {
406                 if ((i = readlink(filename, linkname, 256)) == -1) {
407                     perror(filename);
408                     return;
409                 }
410                 linkname[(i >= 256) ? 255 : i] = '\0';
411                 /*printf("\"%s\" -> \"%s\"", filename, linkname);*/
412                 printf("\"");
413                 printf(pformat, filename);
414                 printf("\" -> \"");
415                 printf(pformat, linkname);
416                 printf("\"");
417             } else {
418                 printf("\"");
419                 printf(pformat, filename);
420                 printf("\"");
421             }
422             break;
423         case 'd':
424             strcat(pformat, "d");
425             printf(pformat, (int)statbuf->st_dev);
426             break;
427         case 'D':
428             strcat(pformat, "x");
429             printf(pformat, (int)statbuf->st_dev);
430             break;
431         case 'i':
432             strcat(pformat, "d");
433             printf(pformat, (int)statbuf->st_ino);
434             break;
435         case 'a':
436             strcat(pformat, "o");
437             printf(pformat, statbuf->st_mode & 07777);
438             break;
439         case 'A':
440             print_human_access(statbuf);
441             break;
442         case 'f':
443             strcat(pformat, "x");
444             printf(pformat, statbuf->st_mode);
445             break;
446         case 'F':
447             print_human_type(statbuf->st_mode);
448             break;
449         case 'h':
450             strcat(pformat, "d");
451             printf(pformat, (int)statbuf->st_nlink);
452             break;
453 #ifdef FLASK_LINUX
454         case 'S':
455             strcat(pformat, "d");
456             printf(pformat, sid);
457             break;
458         case 'C':
459             rv = security_sid_to_context(sid, (security_context_t *) &sbuf,
460                                          &sbuflen);
461             if ( rv < 0 )
462                 sprintf(sbuf, "<error finding security context %d>", sid);
463             printf(sbuf);
464             break;
465 #endif
466         case 'u':
467             strcat(pformat, "d");
468             printf(pformat, statbuf->st_uid);
469             break;
470         case 'U':
471             strcat(pformat, "s");
472             setpwent();
473             pw_ent = getpwuid(statbuf->st_uid);
474             printf(pformat,
475                 (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
476             break;
477         case 'g':
478             strcat(pformat, "d");
479             printf(pformat, statbuf->st_gid);
480             break;
481         case 'G':
482             strcat(pformat, "s");
483             setgrent();
484             gw_ent = getgrgid(statbuf->st_gid);
485             printf(pformat,
486                 (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
487             break;
488         case 't':
489             strcat(pformat, "x");
490             printf(pformat, major(statbuf->st_rdev));
491             break;
492         case 'T':
493             strcat(pformat, "x");
494             printf(pformat, minor(statbuf->st_rdev));
495             break;
496         case 's':
497 #ifdef __USE_FILE_OFFSET64
498             strcat(pformat, "llu");
499             printf(pformat, (unsigned long long)statbuf->st_size);
500 #else
501             strcat(pformat, "u");
502             printf(pformat, (unsigned int)statbuf->st_size);
503 #endif
504             break;
505         case 'b':
506             strcat(pformat, "u");
507             printf(pformat, (unsigned int)statbuf->st_blocks);
508             break;
509         case 'o':
510             strcat(pformat, "d");
511             printf(pformat, (int)statbuf->st_blksize);
512             break;
513         case 'x':
514             print_human_time(&(statbuf->st_atime));
515             break;
516         case 'X':
517             strcat(pformat, "d");
518             printf(pformat, (int)statbuf->st_atime);
519             break;
520         case 'y':
521             print_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             print_human_time(&(statbuf->st_ctime));
529             break;
530         case 'Z':
531             strcat(pformat, "d");
532             printf(pformat, (int)statbuf->st_ctime);
533             break;
534         default:
535             strcat(pformat, "c");
536             printf(pformat, m);
537             break;
538     }
539 }
540
541 static void
542 print_it (char const *masterformat, char const *filename,
543           void (*print_func) (char *, char, char const *,
544                               void const *, SECURITY_ID_T),
545           void const *data, SECURITY_ID_T sid)
546 {
547     char *m, *b, *format;
548     char pformat[65];
549
550     /* create a working copy of the format string */
551     format = strdup(masterformat);
552     if (!format) {
553         perror(filename);
554         return;
555     }
556
557     b = format;
558     while (b)
559     {
560         if ((m = strchr(b, (int)'%')) != NULL)
561         {
562             strcpy (pformat, "%");
563             *m++ = '\0';
564             fputs (b, stdout);
565
566             /* copy all format specifiers to our format string */
567             while (isdigit(*m) || strchr("#0-+. I", *m))
568             {
569                 char copy[2]="a";
570
571                 *copy = *m;
572                 /* make sure the format specifier is not too long */
573                 if (strlen (pformat) > 63)
574                         fprintf(stderr, "Warning: Format specifier too long, truncating: %s\n", pformat);
575                 else
576                         strcat (pformat, copy);
577                 m++;
578             }
579
580             switch(*m) {
581                 case '\0':
582                 case '%':
583                     fputs("%", stdout);
584                     break;
585                 default:
586                     print_func(pformat, *m, filename, data, sid);
587                     break;
588             }
589             b = m + 1;
590         }
591         else
592         {
593             fputs (b, stdout);
594             b = NULL;
595         }
596     }
597     free(format);
598     printf("\n");
599 }
600
601 /* stat the filesystem and print what we find */
602 static void
603 do_statfs (char const *filename, int terse, int secure, char const *format)
604 {
605   struct statfs statfsbuf;
606   SECURITY_ID_T sid = -1;
607   int i;
608
609 #ifdef FLASK_LINUX
610   if (secure)
611     i = statfs_secure(filename, &statfsbuf, &sid);
612   else
613 #endif
614     i = statfs(filename, &statfsbuf);
615   if (i == -1)
616     {
617       perror (filename);
618       return;
619     }
620
621   if (format == NULL)
622     {
623         if (terse != 0)
624           {
625                 if (secure)
626                         format = "%n %i %l %t %b %f %a %s %c %d %S %C";
627                 else
628                         format = "%n %i %l %t %b %f %a %s %c %d";
629           }
630         else
631           {
632                 if (secure)
633                     format = "  File: \"%n\"\n"
634                          "    ID: %-8i Namelen: %-7l Type: %T\n"
635                          "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
636                          "Inodes: Total: %-10c Free: %-10d\n"
637                          "   SID: %-14S  S_Context: %C\n";
638                 else
639                     format = "  File: \"%n\"\n"
640                          "    ID: %-8i Namelen: %-7l Type: %T\n"
641                          "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
642                          "Inodes: Total: %-10c Free: %-10d";
643           }
644     }
645
646     print_it (format, filename, print_statfs, &statfsbuf, sid);
647 }
648
649 /* stat the file and print what we find */
650 static void
651 do_stat (char const *filename, int follow_links, int terse, int secure, char const *format)
652 {
653   struct stat statbuf;
654   int i;
655   SECURITY_ID_T sid = -1;
656
657   if (secure)
658     i = ((follow_links == 1)
659          ? stat_secure(filename, &statbuf, &sid)
660          : lstat_secure(filename, &statbuf, &sid));
661   else
662     i = ((follow_links == 1)
663          ? stat(filename, &statbuf)
664          : lstat(filename, &statbuf));
665
666   if (i == -1)
667     {
668       perror (filename);
669       return;
670     }
671
672    if (format == NULL)
673     {
674        if (terse != 0)
675        {
676            if (secure)
677                   format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %S %C";
678            else
679                   format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
680        }
681        else
682        {
683            /* tmp hack to match orignal output until conditional implemented */
684           i = statbuf.st_mode & S_IFMT;
685           if (i == S_IFCHR || i == S_IFBLK) {
686                 if (secure)
687                         format =
688                            "  File: %N\n"
689                            "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
690                            "Device: %Dh/%dd\tInode: %-10i  Links: %-5h"
691                            " Device type: %t,%T\n"
692                            "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
693                            "   SID: %-14S  S_Context: %C\n"
694                            "Access: %x\n"
695                            "Modify: %y\n"
696                            "Change: %z\n";
697                 else
698                         format =
699                            "  File: %N\n"
700                            "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
701                            "Device: %Dh/%dd\tInode: %-10i  Links: %-5h"
702                            " Device type: %t,%T\n"
703                            "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
704                            "Access: %x\n"
705                            "Modify: %y\n"
706                            "Change: %z\n";
707            }
708            else
709            {
710                 if (secure)
711                        format =
712                            "  File: %N\n"
713                            "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
714                            "Device: %Dh/%dd\tInode: %-10i  Links: %-5h\n"
715                            "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
716                            "   SID: %-14S  S_Context: %C\n"
717                            "Access: %x\n"
718                            "Modify: %y\n"
719                            "Change: %z\n";
720                 else
721                       format =
722                            "  File: %N\n"
723                            "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
724                            "Device: %Dh/%dd\tInode: %-10i  Links: %-5h\n"
725                            "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
726                            "Access: %x\n"
727                            "Modify: %y\n"
728                            "Change: %z\n";
729           }
730        }
731     }
732     print_it(format, filename, print_stat, &statbuf, sid);
733 }
734
735 void
736 usage (int status)
737 {
738   if (status != 0)
739     fprintf (stderr, _("Try %s --help' for more information.\n"),
740              program_name);
741   else
742     {
743       printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
744       fputs (_("\
745 Display file or filesystem status.\n\
746 \n\
747   -f, --filesystem      display filesystem status instead of file status\n\
748   -c  --format=FORMAT   FIXME\n\
749   -l, --link            follow links\n\
750   -s, --secure          FIXME\n\
751   -t, --terse           print the information in terse form\n\
752 "), stdout);
753       fputs (HELP_OPTION_DESCRIPTION, stdout);
754       fputs (VERSION_OPTION_DESCRIPTION, stdout);
755
756       fputs (_("\n\
757 The valid format sequences for files (without --filesystem):\n\
758 \n\
759   %A - Access rights in human readable form\n\
760   %a - Access rights in octal\n\
761   %b - Number of blocks allocated\n\
762   %C - Security context in SE-Linux\n\
763 "), stdout);
764       fputs (_("\
765   %D - Device number in hex\n\
766   %d - Device number in decimal\n\
767   %F - File type\n\
768   %f - raw mode in hex\n\
769   %G - Group name of owner\n\
770   %g - Group ID of owner\n\
771 "), stdout);
772       fputs (_("\
773   %h - Number of hard links\n\
774   %i - Inode number\n\
775   %N - Quoted File name with dereference if symbolic link\n\
776   %n - File name\n\
777   %o - IO block size\n\
778   %S - Security ID in SE-Linux\n\
779   %s - Total size, in bytes\n\
780   %T - Minor device type in hex\n\
781   %t - Major device type in hex\n\
782 "), stdout);
783       fputs (_("\
784   %U - User name of owner\n\
785   %u - User ID of owner\n\
786   %X - Time of last access as seconds since Epoch\n\
787   %x - Time of last access\n\
788   %Y - Time of last modification as seconds since Epoch\n\
789   %y - Time of last modification\n\
790   %Z - Time of last change as seconds since Epoch\n\
791   %z - Time of last change\n\
792 \n\
793 "), stdout);
794
795       fputs (_("\
796 Valid format sequences for file systems:\n\
797 \n\
798   %a - Free blocks available to non-superuser\n\
799   %b - Total data blocks in file system\n\
800   %C - Security context in SE-Linux\n\
801   %c - Total file nodes in file system\n\
802   %d - Free file nodes in file system\n\
803   %f - Free blocks in file system\n\
804 "), stdout);
805       fputs (_("\
806   %i - File System id in hex\n\
807   %l - Maximum length of filenames\n\
808   %n - File name\n\
809   %S - Security ID in SE-Linux\n\
810   %s - Optimal transfer block size\n\
811   %T - Type in human readable form\n\
812   %t - Type in hex\n\
813 "), stdout);
814       puts (_("\nReport bugs to <bug-fileutils@gnu.org>."));
815     }
816   exit (status);
817 }
818
819 int
820 main (int argc, char *argv[])
821 {
822   int c;
823   int i;
824   int follow_links = 0;
825   int fs = 0;
826   int terse = 0;
827   int secure = 0;
828   char *format = NULL;
829
830   program_name = argv[0];
831   setlocale (LC_ALL, "");
832   bindtextdomain (PACKAGE, LOCALEDIR);
833   textdomain (PACKAGE);
834
835   atexit (close_stdout);
836
837   while ((c = getopt_long (argc, argv, "c:flst", long_options, NULL)) != -1)
838     {
839       switch (c)
840         {
841         case 'c':
842           format = optarg;
843           break;
844         case 'l':
845           follow_links = 1;
846           break;
847         case 'f':
848           fs = 1;
849           break;
850         case 's':
851           secure = 1;
852           break;
853         case 't':
854           terse = 1;
855           break;
856
857         case_GETOPT_HELP_CHAR;
858
859         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
860
861         default:
862           usage (EXIT_FAILURE);
863         }
864     }
865
866   if (argc == optind)
867     {
868       error (0, 0, _("too few arguments"));
869       usage (EXIT_FAILURE);
870     }
871
872   if (!is_flask_enabled ())
873     secure = 0;
874
875   for (i = optind; i < argc; i++)
876     {
877       if (fs == 0)
878         do_stat (argv[i], follow_links, terse, secure, format);
879       else
880         do_statfs (argv[i], terse, secure, format);
881     }
882
883   exit (EXIT_SUCCESS);
884 }