Bash-4.3 distribution sources and documentation
[platform/upstream/bash.git] / examples / loadables / finfo.c
1 /*
2  * finfo - print file info
3  *
4  * Chet Ramey
5  * chet@po.cwru.edu
6  */
7
8 /*
9    Copyright (C) 1999-2009 Free Software Foundation, Inc.
10
11    This file is part of GNU Bash.
12    Bash is free software: you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation, either version 3 of the License, or
15    (at your option) any later version.
16
17    Bash is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29
30 #include <sys/types.h>
31 #include "posixstat.h"
32 #include <stdio.h>
33 #include <pwd.h>
34 #include <grp.h>
35 #include <errno.h>
36 #include "posixtime.h"
37
38 #include "bashansi.h"
39 #include "shell.h"
40 #include "builtins.h"
41 #include "common.h"
42
43 #ifndef errno
44 extern int      errno;
45 #endif
46
47 extern char     **make_builtin_argv ();
48
49 static int      printst();
50 static int      printsome();
51 static int      printfinfo();
52 static int      finfo_main();
53
54 extern int      sh_optind;
55 extern char     *sh_optarg;
56 extern char     *this_command_name;
57
58 static char     *prog;
59 static int      pmask;
60
61 #define OPT_UID         0x00001
62 #define OPT_GID         0x00002
63 #define OPT_DEV         0x00004
64 #define OPT_INO         0x00008
65 #define OPT_PERM        0x00010
66 #define OPT_LNKNAM      0x00020
67 #define OPT_FID         0x00040
68 #define OPT_NLINK       0x00080
69 #define OPT_RDEV        0x00100
70 #define OPT_SIZE        0x00200
71 #define OPT_ATIME       0x00400
72 #define OPT_MTIME       0x00800
73 #define OPT_CTIME       0x01000
74 #define OPT_BLKSIZE     0x02000
75 #define OPT_BLKS        0x04000
76 #define OPT_FTYPE       0x08000
77 #define OPT_PMASK       0x10000
78 #define OPT_OPERM       0x20000
79
80 #define OPT_ASCII       0x1000000
81
82 #define OPTIONS         "acdgiflmnopsuACGMP:U"
83
84 static int
85 octal(s)
86 char    *s;
87 {
88         int     r;
89
90         r = *s - '0';
91         while (*++s >= '0' && *s <= '7')
92                 r = (r * 8) + (*s - '0');
93         return r;
94 }
95
96 static int
97 finfo_main(argc, argv)
98 int     argc;
99 char    **argv;
100 {
101         register int    i;
102         int     mode, flags, opt;
103
104         sh_optind = 0;  /* XXX */
105         prog = base_pathname(argv[0]);
106         if (argc == 1) {
107                 builtin_usage();
108                 return(1);
109         }
110         flags = 0;
111         while ((opt = sh_getopt(argc, argv, OPTIONS)) != EOF) {
112                 switch(opt) {
113                 case 'a': flags |= OPT_ATIME; break;
114                 case 'A': flags |= OPT_ATIME|OPT_ASCII; break;
115                 case 'c': flags |= OPT_CTIME; break;
116                 case 'C': flags |= OPT_CTIME|OPT_ASCII; break;
117                 case 'd': flags |= OPT_DEV; break;
118                 case 'i': flags |= OPT_INO; break;
119                 case 'f': flags |= OPT_FID; break;
120                 case 'g': flags |= OPT_GID; break;
121                 case 'G': flags |= OPT_GID|OPT_ASCII; break;
122                 case 'l': flags |= OPT_LNKNAM; break;
123                 case 'm': flags |= OPT_MTIME; break;
124                 case 'M': flags |= OPT_MTIME|OPT_ASCII; break;
125                 case 'n': flags |= OPT_NLINK; break;
126                 case 'o': flags |= OPT_OPERM; break;
127                 case 'p': flags |= OPT_PERM; break;
128                 case 'P': flags |= OPT_PMASK; pmask = octal(sh_optarg); break;
129                 case 's': flags |= OPT_SIZE; break;
130                 case 'u': flags |= OPT_UID; break;
131                 case 'U': flags |= OPT_UID|OPT_ASCII; break;
132                 default: builtin_usage (); return(1);
133                 }
134         }
135
136         argc -= sh_optind;
137         argv += sh_optind;
138
139         if (argc == 0) {
140                 builtin_usage();
141                 return(1);
142         }
143
144         for (i = 0; i < argc; i++)
145                 opt = flags ? printsome (argv[i], flags) : printfinfo(argv[i]);
146
147         return(opt);
148 }
149
150 static struct stat *
151 getstat(f)
152 char    *f;
153 {
154         static struct stat st;
155         int     fd, r;
156         intmax_t lfd;
157
158         if (strncmp(f, "/dev/fd/", 8) == 0) {
159                 if ((legal_number(f + 8, &lfd) == 0) || (int)lfd != lfd) {
160                         builtin_error("%s: invalid fd", f + 8);
161                         return ((struct stat *)0);
162                 }
163                 fd = lfd;
164                 r = fstat(fd, &st);
165         } else
166 #ifdef HAVE_LSTAT
167                 r = lstat(f, &st);
168 #else
169                 r = stat(f, &st);
170 #endif
171         if (r < 0) {
172                 builtin_error("%s: cannot stat: %s", f, strerror(errno));
173                 return ((struct stat *)0);
174         }
175         return (&st);
176 }
177
178 static int
179 printfinfo(f)
180 char    *f;
181 {
182         struct stat *st;
183
184         st = getstat(f);
185         return (st ? printst(st) : 1);
186 }
187
188 static int
189 getperm(m)
190 int     m;
191 {
192         return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID));
193 }
194
195 static int
196 perms(m)
197 int     m;
198 {
199         char ubits[4], gbits[4], obits[4];      /* u=rwx,g=rwx,o=rwx */
200         int i;
201
202         i = 0;
203         if (m & S_IRUSR)
204                 ubits[i++] = 'r';
205         if (m & S_IWUSR)
206                 ubits[i++] = 'w';
207         if (m & S_IXUSR)
208                 ubits[i++] = 'x';
209         ubits[i] = '\0';
210
211         i = 0;
212         if (m & S_IRGRP)
213                 gbits[i++] = 'r';
214         if (m & S_IWGRP)
215                 gbits[i++] = 'w';
216         if (m & S_IXGRP)
217                 gbits[i++] = 'x';
218         gbits[i] = '\0';
219
220         i = 0;
221         if (m & S_IROTH)
222                 obits[i++] = 'r';
223         if (m & S_IWOTH)
224                 obits[i++] = 'w';
225         if (m & S_IXOTH)
226                 obits[i++] = 'x';
227         obits[i] = '\0';
228
229         if (m & S_ISUID)
230                 ubits[2] = (m & S_IXUSR) ? 's' : 'S';
231         if (m & S_ISGID)
232                 gbits[2] = (m & S_IXGRP) ? 's' : 'S';
233         if (m & S_ISVTX)
234                 obits[2] = (m & S_IXOTH) ? 't' : 'T';
235
236         printf ("u=%s,g=%s,o=%s", ubits, gbits, obits);
237 }
238
239 static int
240 printmode(mode)
241 int     mode;
242 {
243         if (S_ISBLK(mode))
244                 printf("S_IFBLK ");
245         if (S_ISCHR(mode))
246                 printf("S_IFCHR ");
247         if (S_ISDIR(mode))
248                 printf("S_IFDIR ");
249         if (S_ISREG(mode))
250                 printf("S_IFREG ");
251         if (S_ISFIFO(mode))
252                 printf("S_IFIFO ");
253         if (S_ISLNK(mode))
254                 printf("S_IFLNK ");
255         if (S_ISSOCK(mode))
256                 printf("S_IFSOCK ");
257 #ifdef S_ISWHT
258         if (S_ISWHT(mode))
259                 printf("S_ISWHT ");
260 #endif
261         perms(getperm(mode));
262         printf("\n");
263 }
264
265 static int      
266 printst(st)
267 struct stat *st;
268 {
269         struct passwd   *pw;
270         struct group    *gr;
271         char    *owner;
272         int     ma, mi, d;
273
274         ma = major (st->st_rdev);
275         mi = minor (st->st_rdev);
276 #if defined (makedev)
277         d = makedev (ma, mi);
278 #else
279         d = st->st_rdev & 0xFF;
280 #endif
281         printf("Device (major/minor): %d (%d/%d)\n", d, ma, mi);
282
283         printf("Inode: %d\n", (int) st->st_ino);
284         printf("Mode: (%o) ", (int) st->st_mode);
285         printmode((int) st->st_mode);
286         printf("Link count: %d\n", (int) st->st_nlink);
287         pw = getpwuid(st->st_uid);
288         owner = pw ? pw->pw_name : "unknown";
289         printf("Uid of owner: %d (%s)\n", (int) st->st_uid, owner);
290         gr = getgrgid(st->st_gid);
291         owner = gr ? gr->gr_name : "unknown";
292         printf("Gid of owner: %d (%s)\n", (int) st->st_gid, owner);
293         printf("Device type: %d\n", (int) st->st_rdev);
294         printf("File size: %ld\n", (long) st->st_size);
295         printf("File last access time: %s", ctime (&st->st_atime));
296         printf("File last modify time: %s", ctime (&st->st_mtime));
297         printf("File last status change time: %s", ctime (&st->st_ctime));
298         fflush(stdout);
299         return(0);
300 }
301
302 static int
303 printsome(f, flags)
304 char    *f;
305 int     flags;
306 {
307         struct stat *st;
308         struct passwd *pw;
309         struct group *gr;
310         int     p;
311         char    *b;
312
313         st = getstat(f);
314         if (st == NULL)
315                 return (1);
316
317         /* Print requested info */
318         if (flags & OPT_ATIME) {
319                 if (flags & OPT_ASCII)
320                         printf("%s", ctime(&st->st_atime));
321                 else
322                         printf("%ld\n", st->st_atime);
323         } else if (flags & OPT_MTIME) {
324                 if (flags & OPT_ASCII)
325                         printf("%s", ctime(&st->st_mtime));
326                 else
327                         printf("%ld\n", st->st_mtime);
328         } else if (flags & OPT_CTIME) {
329                 if (flags & OPT_ASCII)
330                         printf("%s", ctime(&st->st_ctime));
331                 else
332                         printf("%ld\n", st->st_ctime);
333         } else if (flags & OPT_DEV)
334                 printf("%d\n", st->st_dev);
335         else if (flags & OPT_INO)
336                 printf("%d\n", st->st_ino);
337         else if (flags & OPT_FID)
338                 printf("%d:%ld\n", st->st_dev, st->st_ino);
339         else if (flags & OPT_NLINK)
340                 printf("%d\n", st->st_nlink);
341         else if (flags & OPT_LNKNAM) {
342 #ifdef S_ISLNK
343                 b = xmalloc(4096);
344                 p = readlink(f, b, 4096);
345                 if (p >= 0 && p < 4096)
346                         b[p] = '\0';
347                 else {
348                         p = errno;
349                         strcpy(b, prog);
350                         strcat(b, ": ");
351                         strcat(b, strerror(p));
352                 }
353                 printf("%s\n", b);
354                 free(b);
355 #else
356                 printf("%s\n", f);
357 #endif
358         } else if (flags & OPT_PERM) {
359                 perms(st->st_mode);
360                 printf("\n");
361         } else if (flags & OPT_OPERM)
362                 printf("%o\n", getperm(st->st_mode));
363         else if (flags & OPT_PMASK)
364                 printf("%o\n", getperm(st->st_mode) & pmask);
365         else if (flags & OPT_UID) {
366                 pw = getpwuid(st->st_uid);
367                 if (flags & OPT_ASCII)
368                         printf("%s\n", pw ? pw->pw_name : "unknown");
369                 else
370                         printf("%d\n", st->st_uid);
371         } else if (flags & OPT_GID) {
372                 gr = getgrgid(st->st_gid);
373                 if (flags & OPT_ASCII)
374                         printf("%s\n", gr ? gr->gr_name : "unknown");
375                 else
376                         printf("%d\n", st->st_gid);
377         } else if (flags & OPT_SIZE)
378                 printf("%ld\n", (long) st->st_size);
379
380         return (0);
381 }
382
383 #ifndef NOBUILTIN
384 int
385 finfo_builtin(list)
386      WORD_LIST *list;
387 {
388   int c, r;
389   char **v;
390   WORD_LIST *l;
391
392   v = make_builtin_argv (list, &c);
393   r = finfo_main (c, v);
394   free (v);
395
396   return r;
397 }
398
399 static char *finfo_doc[] = {
400   "Display information about file attributes.",
401   "",
402   "Display information about each FILE.  Only single operators should",
403   "be supplied.  If no options are supplied, a summary of the info",
404   "available about each FILE is printed.  If FILE is of the form",
405   "/dev/fd/XX, file descriptor XX is described.  Operators, if supplied,",
406   "have the following meanings:",
407   "",
408   "     -a      last file access time",
409   "     -A      last file access time in ctime format",
410   "     -c      last file status change time",
411   "     -C      last file status change time in ctime format",
412   "     -m      last file modification time",
413   "     -M      last file modification time in ctime format",
414   "     -d      device",
415   "     -i      inode",
416   "     -f      composite file identifier (device:inode)",
417   "     -g      gid of owner",
418   "     -G      group name of owner",
419   "     -l      name of file pointed to by symlink",
420   "     -n      link count",
421   "     -o      permissions in octal",
422   "     -p      permissions in ascii",
423   "     -P mask permissions ANDed with MASK (like with umask)",
424   "     -s      file size in bytes",
425   "     -u      uid of owner",
426   "     -U      user name of owner",
427   (char *)0
428 };
429
430 struct builtin finfo_struct = {
431         "finfo",
432         finfo_builtin,
433         BUILTIN_ENABLED,
434         finfo_doc,
435         "finfo [-acdgiflmnopsuACGMPU] file [file...]",
436         0
437 };
438 #endif
439
440 #ifdef NOBUILTIN
441 #if defined (PREFER_STDARG)
442 #  include <stdarg.h>
443 #else
444 #  if defined (PREFER_VARARGS)
445 #    include <varargs.h>
446 #  endif
447 #endif
448
449 char *this_command_name;
450
451 main(argc, argv)
452 int     argc;
453 char    **argv;
454 {
455         this_command_name = argv[0];
456         exit(finfo_main(argc, argv));
457 }
458
459 void
460 builtin_usage()
461 {
462         fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, OPTIONS);
463 }
464
465 #ifndef HAVE_STRERROR
466 char *
467 strerror(e)
468 int     e;
469 {
470         static char     ebuf[40];
471         extern int      sys_nerr;
472         extern char     *sys_errlist[];
473
474         if (e < 0 || e > sys_nerr) {
475                 sprintf(ebuf,"Unknown error code %d", e);
476                 return (&ebuf[0]);
477         }
478         return (sys_errlist[e]);
479 }
480 #endif
481
482 char *
483 xmalloc(s)
484 size_t  s;
485 {
486         char    *ret;
487         extern char *malloc();
488
489         ret = malloc(s);
490         if (ret)
491                 return (ret);
492         fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s);
493         exit(1);
494 }
495
496 char *
497 base_pathname(p)
498 char    *p;
499 {
500         char    *t;
501
502         if (t = strrchr(p, '/'))
503                 return(++t);
504         return(p);
505 }
506
507 int
508 legal_number (string, result)
509      char *string;
510      long *result;
511 {
512   int sign;
513   long value;
514
515   sign = 1;
516   value = 0;
517
518   if (result)
519     *result = 0;
520
521   /* Skip leading whitespace characters. */
522   while (whitespace (*string))
523     string++;
524
525   if (!*string)
526     return (0);
527
528   /* We allow leading `-' or `+'. */
529   if (*string == '-' || *string == '+')
530     {
531       if (!digit (string[1]))
532         return (0);
533
534       if (*string == '-')
535         sign = -1;
536
537       string++;
538     }
539
540   while (digit (*string))
541     {
542       if (result)
543         value = (value * 10) + digit_value (*string);
544       string++;
545     }
546
547   /* Skip trailing whitespace, if any. */
548   while (whitespace (*string))
549     string++;
550
551   /* Error if not at end of string. */
552   if (*string)
553     return (0);
554
555   if (result)
556     *result = value * sign;
557
558   return (1);
559 }
560
561 int sh_optind;
562 char *sh_optarg;
563 int sh_opterr;
564
565 extern int optind;
566 extern char *optarg;
567
568 int
569 sh_getopt(c, v, o)
570 int     c;
571 char    **v, *o;
572 {
573         int     r;
574
575         r = getopt(c, v, o);
576         sh_optind = optind;
577         sh_optarg = optarg;
578         return r;
579 }
580
581 #if defined (USE_VARARGS)
582 void
583 #if defined (PREFER_STDARG)
584 builtin_error (const char *format, ...)
585 #else
586 builtin_error (format, va_alist)
587      const char *format;
588      va_dcl
589 #endif
590 {
591   va_list args;
592
593   if (this_command_name && *this_command_name)
594     fprintf (stderr, "%s: ", this_command_name);
595
596 #if defined (PREFER_STDARG)
597   va_start (args, format);
598 #else
599   va_start (args);
600 #endif
601
602   vfprintf (stderr, format, args);
603   va_end (args);
604   fprintf (stderr, "\n");
605 }
606 #else
607 void
608 builtin_error (format, arg1, arg2, arg3, arg4, arg5)
609      char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
610 {
611   if (this_command_name && *this_command_name)
612     fprintf (stderr, "%s: ", this_command_name);
613
614   fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
615   fprintf (stderr, "\n");
616   fflush (stderr);
617 }
618 #endif /* !USE_VARARGS */
619
620 #endif