home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / stat / stat.c < prev   
C/C++ Source or Header  |  1990-02-26  |  15KB  |  649 lines

  1. /*
  2.  * stat - List the status information of a list of files
  3.  *
  4.  * (C) Copyright 1989 Diomidis D. Spinellis.  All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that the above copyright notice and this paragraph are
  8.  * duplicated in all such forms and that any documentation,
  9.  * advertising materials, and other materials related to such
  10.  * distribution and use acknowledge that the software was developed
  11.  * by Diomidis D. Spinellis.
  12.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  13.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  14.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  15.  *
  16.  * $Header: stat.c,v 1.9 89/11/03 22:53:12 dds Rel $
  17.  *
  18.  */
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <varargs.h>
  23. #include <pwd.h>
  24. #include <grp.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/time.h>
  28. #include <sys/param.h>
  29.  
  30. #define    STREQ(a, b)    (*(a) == *(b) && strcmp((a), (b)) == 0)
  31.  
  32. #ifndef lint
  33. static char RCSid[] = "$Header: stat.c,v 1.9 89/11/03 22:53:12 dds Rel $";
  34. #endif
  35.  
  36. int debug = 0;
  37. int lflag = 0;                    /* Follow links */
  38. int gflag = 0;                    /* Use GMT */
  39. int eflag = 0;                    /* Exit on error */
  40. char *progname;                    /* Base name of the program */
  41. /* Output format string */
  42. char *format = "%P%(3d)l %(-8s)U %(8ld)s %M %n%-%L";
  43. char *ttformat = "%h %(2d)d %T%(5d)Y";        /* Current time format */
  44. char *tcformat = "%h %(2d)d %T%(5d)Y";        /* Creation time format */
  45. char *taformat = "%h %(2d)d %T%(5d)Y";        /* Access time format */
  46. char *tmformat = "%h %(2d)d %T%(5d)Y";        /* Modification time format */
  47. char *typename[];                /* File type english names */
  48. char *modename[];                /* File mode english names */
  49. struct tm currtime;                /* Current time structure */
  50. long currclock, halfyearago;            /* ... in seconds */
  51.  
  52. extern void error(), exit();
  53. extern struct tm *localtime(), *gmtime();
  54.  
  55. static void parsenames();
  56.  
  57. /*
  58.  * main - parse arguments and handle options
  59.  */
  60. main(argc, argv)
  61.     int argc;
  62.     char *argv[];
  63. {
  64.     int c;
  65.     int errflg = 0;
  66.     extern int optind;
  67.     extern char *optarg;
  68.     extern char *mkprogname();
  69.     void process();
  70.     struct timeval time;
  71.     struct timezone zone;
  72.  
  73.     progname = mkprogname(argv[0]);
  74.  
  75.     while ((c = getopt(argc, argv, "dglf:t:a:m:c:q:y:")) != EOF)
  76.         switch (c) {
  77. #ifndef NDEBUG
  78.         case 'd':    /* Debugging. */
  79.             debug++;
  80.             break;
  81. #endif
  82.         case 'e':
  83.             eflag++;
  84.             break;
  85.         case 'g':
  86.             gflag++;
  87.             break;
  88.         case 'l':
  89.             lflag++;
  90.             break;
  91.         case 'c':    /* Format for current time specification */
  92.             tcformat = optarg;
  93.             break;
  94.         case 'a':    /* Format for current time specification */
  95.             taformat = optarg;
  96.             break;
  97.         case 'm':    /* Format for current time specification */
  98.             tmformat = optarg;
  99.             break;
  100.         case 't':    /* Format for current time specification */
  101.             ttformat = optarg;
  102.             break;
  103.         case 'f':    /* Format specification */
  104.             format = optarg;
  105.             break;
  106.         case 'q':    /* Names for english file mode descriptions */
  107.             parsenames(optarg, modename, 24, "mode");
  108.             break;
  109.         case 'y':    /* Names for file type descriptions */
  110.             parsenames(optarg, typename, 7, "type");
  111.             break;
  112.         case '?':
  113.         default:
  114.             errflg++;
  115.             break;
  116.         }
  117.     if (errflg || optind >= argc) {
  118.         fprintf(stderr, "usage: %s [-f format] [-t date_format]file ...\n", progname);
  119.         exit(2);
  120.     }
  121.  
  122.     gettimeofday(&time, &zone);
  123.     currclock = time.tv_sec;
  124.     halfyearago = currclock - 365L * 24L * 60L * 60L / 2L;
  125.     if (gflag)
  126.         currtime = *gmtime(&time.tv_sec);
  127.     else
  128.         currtime = *localtime(&time.tv_sec);
  129.     for (; optind < argc; optind++)
  130.         process(argv[optind]);
  131.     exit(0);
  132. }
  133.  
  134. /*
  135.  * List the mode of a file a la ls
  136.  */
  137. #ifdef __GCC__
  138. inline
  139. #endif
  140. static void
  141. lsmode(mode)
  142.     unsigned short mode;
  143. {
  144.     if ((mode & S_IFMT) == S_IFDIR)
  145.         putchar('d');
  146.     else if ((mode & S_IFMT) == S_IFBLK)
  147.         putchar('b');
  148.     else if ((mode & S_IFMT) == S_IFCHR)
  149.         putchar('c');
  150. #ifdef S_IFLNK
  151.     else if ((mode & S_IFMT) == S_IFLNK)
  152.         putchar('l');
  153. #endif
  154. #ifdef S_IFIFO
  155.     else if ((mode & S_IFMT) == S_IFIFO)
  156.         putchar('p');
  157. #endif
  158. #ifdef S_IFSOCK
  159.     else if ((mode & S_IFMT) == S_IFSOCK)
  160.         putchar('s');
  161. #endif
  162.     else
  163.         putchar('-');
  164.     putchar((mode & (S_IREAD >> 0)) ? 'r' : '-');
  165.     putchar((mode & (S_IWRITE >> 0)) ? 'w' : '-');
  166.     if (mode & S_ISUID)
  167.         putchar((mode & (S_IEXEC >> 0)) ? 's' : 'S');
  168.     else
  169.         putchar((mode & (S_IEXEC >> 0)) ? 'x' : '-');
  170.     putchar((mode & (S_IREAD >> 3)) ? 'r' : '-');
  171.     putchar((mode & (S_IWRITE >> 3)) ? 'w' : '-');
  172.     if (mode & S_ISGID)
  173.         putchar((mode & (S_IEXEC >> 3)) ? 's' : 'S');
  174.     else
  175.         putchar((mode & (S_IEXEC >> 3)) ? 'x' : '-');
  176.     putchar((mode & (S_IREAD >> 6)) ? 'r' : '-');
  177.     putchar((mode & (S_IWRITE >> 6)) ? 'w' : '-');
  178.     if (mode & S_ISVTX)
  179.         putchar((mode & (S_IEXEC >> 3)) ? 't' : 'T');
  180.     else
  181.         putchar((mode & (S_IEXEC >> 3)) ? 'x' : '-');
  182. }
  183.  
  184. #define optform(x) (form[1]?form:(x))
  185. static char form[512] = "%";
  186.  
  187. /*
  188.  * Print time using the time format
  189.  */
  190. static
  191. timef(clock, format)
  192.     long clock;
  193.     char *format;
  194. {
  195.     struct tm *t;
  196.     char c, *p, *fp;
  197.     static char *weekday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  198.     static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  199.  
  200.     if (gflag)
  201.         t = gmtime(&clock);
  202.     else
  203.         t = localtime(&clock);
  204.     for (p = format; *p; p++) {
  205.         c = *p;
  206.         if (c != '%')
  207.             putchar(c);
  208.         else {
  209.             fp = form + 1;
  210.             p++;
  211.             if (*p == '(') {
  212.                 p++;
  213.                 while (*p && *p != ')')
  214.                     *fp++ = *p++;
  215.                 if (*p)
  216.                     p++;
  217.             }
  218.             *fp = 0;
  219.             switch (*p) {
  220.             case 'm':
  221.                 printf(optform("%d"), t->tm_mon + 1);
  222.                 break;
  223.             case 'd':
  224.                 printf(optform("%d"), t->tm_mday);
  225.                 break;
  226.             case 'y':
  227.                 printf(optform("%d"), t->tm_year+1900);
  228.                 break;
  229.             case 'Y':
  230.                 if (clock < halfyearago)
  231.                     printf(optform("%d"), t->tm_year+1900);
  232.                 break;
  233.             case 'H':
  234.                 printf(optform("%d"), t->tm_hour);
  235.                 break;
  236.             case 'M':
  237.                 printf(optform("%d"), t->tm_min);
  238.                 break;
  239.             case 'T':
  240.                 if (clock >= halfyearago)
  241.                     printf("%02d:%02d", t->tm_hour, t->tm_min);
  242.                 break;
  243.             case 'S':
  244.                 printf(optform("%d"), t->tm_sec);
  245.                 break;
  246.             case 'j':
  247.                 printf(optform("%d"), t->tm_yday);
  248.                 break;
  249.             case 'w':
  250.                 printf(optform("%d"), t->tm_wday);
  251.                 break;
  252.             case 'a':
  253.                 printf(optform("%s"), weekday[t->tm_wday]);
  254.                 break;
  255.             case 'h':
  256.                 printf(optform("%s"), month[t->tm_mon]);
  257.                 break;
  258. #ifdef sun
  259.             case 'z':
  260.                 printf(optform("%s"), t->tm_gmtoff);
  261.                 break;
  262.             case 'Z':
  263.                 printf(optform("%s"), t->tm_zone);
  264.                 break;
  265. #endif
  266.             case 'D':
  267.                 printf(optform("%s"), t->tm_isdst ? "DST" : "");
  268.                 break;
  269.             case 't':
  270.                 printf("%02d%02d%02d%02d%02d", t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_year);
  271.                 break;
  272.             default :
  273.                 putchar(*p);
  274.                 break;
  275.             }
  276.         }
  277.     }
  278. }
  279.  
  280. /*
  281.  * process - process input file
  282.  */
  283. static void
  284. process(inname)
  285.     char *inname;
  286. {
  287.     struct stat statbuf;
  288.     struct group *grp, *getgrgid();
  289.     struct passwd *pwd, *getpwuid();
  290.     int uid = -10, gid = -10;            /* Cached */
  291.     char *pw_name, *gr_name;
  292.     char *p, c, *fp, *ctime();
  293.     int i, j;
  294.     int Lprinted = 0;
  295.  
  296.     if (STREQ(inname, "-")) {
  297.         if (fstat(0, &statbuf) < 0) {
  298.             error("can't fstat `%s'", inname);
  299.             return;
  300.         }
  301.     } else {
  302.         if (lflag) {
  303.             if (stat(inname, &statbuf) < 0) {
  304.                 error("can't stat `%s'", inname);
  305.                 return;
  306.             }
  307.         } else {
  308.             if (lstat(inname, &statbuf) < 0) {
  309.                 error("can't lstat `%s'", inname);
  310.                 return;
  311.             }
  312.         }
  313.     }
  314.  
  315.     for (p = format; *p; p++) {
  316.         c = *p;
  317.         if (c != '%')
  318.             putchar(c);
  319.         else {
  320.             fp = form + 1;
  321.             p++;
  322.             if (*p == '(') {
  323.                 p++;
  324.                 while (*p && *p != ')')
  325.                     *fp++ = *p++;
  326.                 if (*p)
  327.                     p++;
  328.             }
  329.             *fp = 0;
  330.             switch (*p) {
  331.             case 'v':
  332.                 printf(optform("%d"), statbuf.st_dev);
  333.                 break;
  334.             case 'i':
  335.                 printf(optform("%lu"), statbuf.st_ino);
  336.                 break;
  337.             case 'p':
  338.                 printf(optform("%o"), statbuf.st_mode);
  339.                 break;
  340.             case 'P':
  341.                 lsmode(statbuf.st_mode);
  342.                 break;
  343.             case 'l':
  344.                 printf(optform("%d"), statbuf.st_nlink);
  345.                 break;
  346.             case 'u':
  347.                 printf(optform("%d"), statbuf.st_uid);
  348.                 break;
  349.             case 'g':
  350.                 printf(optform("%d"), statbuf.st_gid);
  351.                 break;
  352.             case 'U':
  353.                 if (uid != statbuf.st_uid) {
  354.                     if (pwd = getpwuid(statbuf.st_uid))
  355.                         pw_name = pwd->pw_name;
  356.                     else
  357.                         pw_name = "[UNKOWN]";
  358.                 }
  359.                 printf(optform("%s"), pw_name);
  360.                 break;
  361.             case 'G':
  362.                 if (gid != statbuf.st_gid) {
  363.                     if (grp = getgrgid(statbuf.st_gid))
  364.                         gr_name = grp->gr_name;
  365.                     else
  366.                         gr_name = "[UNKOWN]";
  367.                 }
  368.                 printf(optform("%s"), gr_name);
  369.                 break;
  370.             case 'r':
  371.                 printf(optform("%d"), statbuf.st_rdev);
  372.                 break;
  373.             case 's':
  374.                 printf(optform("%ld"), statbuf.st_size);
  375.                 break;
  376.             case 'a':
  377.                 printf(optform("%ld"), statbuf.st_atime);
  378.                 break;
  379.             case 'm':
  380.                 printf(optform("%ld"), statbuf.st_mtime);
  381.                 break;
  382.             case 'c':
  383.                 printf(optform("%ld"), statbuf.st_ctime);
  384.                 break;
  385.             case 't':
  386.                 printf(optform("%ld"), currclock);
  387.                 break;
  388.             case 'A':
  389.                 timef(statbuf.st_atime, taformat);
  390.                 break;
  391.             case 'M':
  392.                 timef(statbuf.st_mtime, tmformat);
  393.                 break;
  394.             case 'C':
  395.                 timef(statbuf.st_ctime, tcformat);
  396.                 break;
  397.             case 'T':
  398.                 timef(currclock, ttformat);
  399.                 break;
  400. #ifndef AIX
  401.             case 'z':
  402.                 printf(optform("%ld"), statbuf.st_blksize);
  403.                 break;
  404.             case 'b':
  405.                 printf(optform("%ld"), statbuf.st_blocks);
  406.                 break;
  407. #endif
  408.             case 'n':
  409.                 printf(optform("%s"), inname);
  410.                 break;
  411.             case 'f':
  412. #ifdef S_IFLNK
  413.                 if ((statbuf.st_mode & S_IFMT) == S_IFLNK && Lprinted)
  414.                     break;
  415. #endif
  416.                 if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  417.                     putchar('/');
  418. #ifdef S_IFLNK
  419.                 else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
  420.                     putchar('@');
  421. #endif
  422. #ifdef S_IFSOCK
  423.                 else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
  424.                     putchar('=');
  425. #endif
  426.                 else if (statbuf.st_mode & (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)))
  427.                     putchar('*');
  428.                 else
  429.                     putchar(' ');
  430.                 break;
  431.             case 'F':
  432.                 if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  433.                     printf(optform("%s"), "S_IFDIR");
  434.                 else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
  435.                     printf(optform("%s"), "S_IFBLK");
  436.                 else if ((statbuf.st_mode & S_IFMT) == S_IFCHR)
  437.                     printf(optform("%s"), "S_IFCHR");
  438. #ifdef S_IFLNK
  439.                 else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
  440.                     printf(optform("%s"), "S_IFLNK");
  441. #endif
  442. #ifdef S_IFIFO
  443.                 else if ((statbuf.st_mode & S_IFMT) == S_IFIFO)
  444.                     printf(optform("%s"), "S_IFIFO");
  445. #endif
  446. #ifdef S_IFSOCK
  447.                 else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
  448.                     printf(optform("%s"), "S_IFSOCK");
  449. #endif
  450.                 else if ((statbuf.st_mode & S_IFMT) == S_IFREG)
  451.                     printf(optform("%s"), "S_IFREG");
  452.                 else
  453.                     printf(optform("%s"), "");
  454.                 break;
  455.             case 'Y':
  456.                 if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  457.                     printf(optform("%s"), typename[0]);
  458.                 else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
  459.                     printf(optform("%s"), typename[1]);
  460.                 else if ((statbuf.st_mode & S_IFMT) == S_IFCHR)
  461.                     printf(optform("%s"), typename[2]);
  462. #ifdef S_IFLNK
  463.                 else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
  464.                     printf(optform("%s"), typename[3]);
  465. #endif
  466. #ifdef S_IFIFO
  467.                 else if ((statbuf.st_mode & S_IFMT) == S_IFIFO)
  468.                     printf(optform("%s"), typename[4]);
  469. #endif
  470. #ifdef S_IFSOCK
  471.                 else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
  472.                     printf(optform("%s"), typename[5]);
  473. #endif
  474.                 else if ((statbuf.st_mode & S_IFMT) == S_IFREG)
  475.                     printf(optform("%s"), typename[6]);
  476.                 else
  477.                     printf(optform("%s"), "");
  478.                 break;
  479.             case 'q':
  480.                 for (i = 0400; i; i >>= 1)
  481.                     if (statbuf.st_mode & i)
  482.                         printf(optform("%s"), "1");
  483.                     else
  484.                         printf(optform("%s"), "0");
  485.                 break;
  486.             case 'Q':
  487. #ifdef S_IFLNK
  488.                 if ((statbuf.st_mode & S_IFMT) == S_IFLNK && ! lflag)
  489.                     break;
  490. #endif
  491.                 if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  492.                     j = 12;
  493.                 else
  494.                     j = 0;
  495.                 for (i = 04000; i; i >>= 1, j++)
  496.                     if (statbuf.st_mode & i)
  497.                         printf(optform("%s"), modename[j]);
  498.                 break;
  499. #ifdef S_IFLNK
  500.             case 'L':
  501.                 if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
  502.                     int len;
  503.                     char buf[MAXPATHLEN];
  504.  
  505.                     if ((len = readlink(inname, buf, MAXPATHLEN)) == -1) {
  506.                         error("can't readlink `%s'", inname);
  507.                         break;
  508.                     }
  509.                     buf[len] = 0;
  510.                     printf(optform("%s"), buf);
  511.                     Lprinted = 1;
  512.                 } else 
  513.                     printf(optform("%s"), "");
  514.                 break;
  515.             case '-':
  516.                 if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
  517.                     fputs(" -> ", stdout);
  518.                     Lprinted = 1;
  519.                 }
  520.                 break;
  521. #endif
  522.             default :
  523.                 putchar(c);
  524.                 break;
  525.             }
  526.         }
  527.     }
  528.     putchar('\n');
  529. }
  530.  
  531. /*
  532.  * error - report trouble
  533.  */
  534. static void                /* does not return */
  535. error(s1, s2)
  536.     char *s1, *s2;
  537. {
  538.     extern int sys_nerr, errno;
  539.     extern char *sys_errlist[];
  540.  
  541.     fprintf(stderr, "%s: ", progname);
  542.     fprintf(stderr, s1, s2);
  543.     if( errno && errno <= sys_nerr )
  544.         fprintf(stderr, " (%s)", sys_errlist[errno]);
  545.     putc('\n', stderr);
  546.     if (eflag)
  547.         exit(1);
  548. }
  549.  
  550. /*
  551.  * mkprogname - convert string to a meaningful program name
  552.  * May change the string
  553.  */
  554. char *
  555. mkprogname(s)
  556.     char *s;
  557. {
  558.     char *p, *p2;
  559.     char *unkown="[unkown]";
  560.  
  561.     if (!s || !*s)
  562.         return unkown;
  563.     p = s;
  564.     if ((p2 = strrchr(s, '/')) > p)        /* Check for path */
  565.         p = p2+1;
  566. #ifdef MSDOS
  567.     if ((p2 = strrchr(s, '\\')) > p)    /* Check for backslash path */
  568.         p = p2+1;
  569.     if ((p2 = strrchr(s, ':')) > p)        /* Check for drive spec */
  570.         p = p2+1;
  571.     if ((p2 = strrchr(s, '.')) > p)        /* Check for extension */
  572.         *p2=0;
  573.     for (p2=p; *p2; p2++)            /* Make it lowercase */
  574.         if (isascii(*p2) && isupper(*p2))
  575.             *p2 = tolower(*p2);
  576. #endif
  577.     if (*p)
  578.         return p;
  579.     else
  580.         return unkown;
  581. }
  582.  
  583. char *modename[] = {                /* File mode english names */
  584.     "run with id of the owner ",
  585.     "run with id of the group ",
  586.     "stay in swap space on termination ",
  587.     "owner can read ",
  588.     "owner can change ",
  589.     "owner can execute ",
  590.     "group can read ",
  591.     "group can change ",
  592.     "group can execute ",
  593.     "anyone can read ",
  594.     "anyone can change ",
  595.     "anyone can execute ",
  596.     "",
  597.     "files inherit group ",
  598.     "only owners can delete files ",
  599.     "owner can read ",
  600.     "owner can change ",
  601.     "owner can access ",
  602.     "group can read ",
  603.     "group can change ",
  604.     "group can access ",
  605.     "anyone can read ",
  606.     "anyone can change ",
  607.     "anyone can access ",
  608. };
  609.  
  610. /* File type english names */
  611. char *typename[] = {
  612.     "Directory",
  613.     "Block special",
  614.     "Character special",
  615.     "Symbolic link",
  616.     "Named pipe",
  617.     "Socket",
  618.     "Regular file",
  619. };
  620.  
  621. /*
  622.  * Convert a separator terminated list of strings starting with the
  623.  * terminator to an array.  The strings should be exactly number else
  624.  * an error is printed.
  625.  */
  626. static void
  627. parsenames(names, array, number, errname)
  628.     char *names, *errname;
  629.     char *array[];
  630.     int number;
  631. {
  632.     char term = *names;
  633.     char *p, *p2;
  634.     int count = 0;
  635.  
  636.     for (p = p2 = names + 1; *p ; p++)
  637.         if (*p == term) {
  638.             array[count++] = p2;
  639.             *p++ = 0;
  640.             p2 = p;
  641.             if (count > number)
  642.                 break;
  643.         }
  644.     if (count != number) {
  645.         fprintf(stderr, "%s: expected %d arguments to specify file %s, got %d\n", progname, number, errname, count);
  646.         exit(1);
  647.     }
  648. }
  649.