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