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