home *** CD-ROM | disk | FTP | other *** search
- /*
- * stat - List the status information of a list of files
- *
- * (C) Copyright 1989 Diomidis D. Spinellis. All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Diomidis D. Spinellis.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * $Header: stat.c,v 1.9 89/11/03 22:53:12 dds Rel $
- *
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <varargs.h>
- #include <pwd.h>
- #include <grp.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/param.h>
-
- #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
-
- #ifndef lint
- static char RCSid[] = "$Header: stat.c,v 1.9 89/11/03 22:53:12 dds Rel $";
- #endif
-
- int debug = 0;
- int lflag = 0; /* Follow links */
- int gflag = 0; /* Use GMT */
- int eflag = 0; /* Exit on error */
- char *progname; /* Base name of the program */
- /* Output format string */
- char *format = "%P%(3d)l %(-8s)U %(8ld)s %M %n%-%L";
- char *ttformat = "%h %(2d)d %T%(5d)Y"; /* Current time format */
- char *tcformat = "%h %(2d)d %T%(5d)Y"; /* Creation time format */
- char *taformat = "%h %(2d)d %T%(5d)Y"; /* Access time format */
- char *tmformat = "%h %(2d)d %T%(5d)Y"; /* Modification time format */
- char *typename[]; /* File type english names */
- char *modename[]; /* File mode english names */
- struct tm currtime; /* Current time structure */
- long currclock, halfyearago; /* ... in seconds */
-
- extern void error(), exit();
- extern struct tm *localtime(), *gmtime();
-
- static void parsenames();
-
- /*
- * main - parse arguments and handle options
- */
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int c;
- int errflg = 0;
- extern int optind;
- extern char *optarg;
- extern char *mkprogname();
- void process();
- struct timeval time;
- struct timezone zone;
-
- progname = mkprogname(argv[0]);
-
- while ((c = getopt(argc, argv, "dglf:t:a:m:c:q:y:")) != EOF)
- switch (c) {
- #ifndef NDEBUG
- case 'd': /* Debugging. */
- debug++;
- break;
- #endif
- case 'e':
- eflag++;
- break;
- case 'g':
- gflag++;
- break;
- case 'l':
- lflag++;
- break;
- case 'c': /* Format for current time specification */
- tcformat = optarg;
- break;
- case 'a': /* Format for current time specification */
- taformat = optarg;
- break;
- case 'm': /* Format for current time specification */
- tmformat = optarg;
- break;
- case 't': /* Format for current time specification */
- ttformat = optarg;
- break;
- case 'f': /* Format specification */
- format = optarg;
- break;
- case 'q': /* Names for english file mode descriptions */
- parsenames(optarg, modename, 24, "mode");
- break;
- case 'y': /* Names for file type descriptions */
- parsenames(optarg, typename, 7, "type");
- break;
- case '?':
- default:
- errflg++;
- break;
- }
- if (errflg || optind >= argc) {
- fprintf(stderr, "usage: %s [-f format] [-t date_format]file ...\n", progname);
- exit(2);
- }
-
- gettimeofday(&time, &zone);
- currclock = time.tv_sec;
- halfyearago = currclock - 365L * 24L * 60L * 60L / 2L;
- if (gflag)
- currtime = *gmtime(&time.tv_sec);
- else
- currtime = *localtime(&time.tv_sec);
- for (; optind < argc; optind++)
- process(argv[optind]);
- exit(0);
- }
-
- /*
- * List the mode of a file a la ls
- */
- #ifdef __GCC__
- inline
- #endif
- static void
- lsmode(mode)
- unsigned short mode;
- {
- if ((mode & S_IFMT) == S_IFDIR)
- putchar('d');
- else if ((mode & S_IFMT) == S_IFBLK)
- putchar('b');
- else if ((mode & S_IFMT) == S_IFCHR)
- putchar('c');
- #ifdef S_IFLNK
- else if ((mode & S_IFMT) == S_IFLNK)
- putchar('l');
- #endif
- #ifdef S_IFIFO
- else if ((mode & S_IFMT) == S_IFIFO)
- putchar('p');
- #endif
- #ifdef S_IFSOCK
- else if ((mode & S_IFMT) == S_IFSOCK)
- putchar('s');
- #endif
- else
- putchar('-');
- putchar((mode & (S_IREAD >> 0)) ? 'r' : '-');
- putchar((mode & (S_IWRITE >> 0)) ? 'w' : '-');
- if (mode & S_ISUID)
- putchar((mode & (S_IEXEC >> 0)) ? 's' : 'S');
- else
- putchar((mode & (S_IEXEC >> 0)) ? 'x' : '-');
- putchar((mode & (S_IREAD >> 3)) ? 'r' : '-');
- putchar((mode & (S_IWRITE >> 3)) ? 'w' : '-');
- if (mode & S_ISGID)
- putchar((mode & (S_IEXEC >> 3)) ? 's' : 'S');
- else
- putchar((mode & (S_IEXEC >> 3)) ? 'x' : '-');
- putchar((mode & (S_IREAD >> 6)) ? 'r' : '-');
- putchar((mode & (S_IWRITE >> 6)) ? 'w' : '-');
- if (mode & S_ISVTX)
- putchar((mode & (S_IEXEC >> 3)) ? 't' : 'T');
- else
- putchar((mode & (S_IEXEC >> 3)) ? 'x' : '-');
- }
-
- #define optform(x) (form[1]?form:(x))
- static char form[512] = "%";
-
- /*
- * Print time using the time format
- */
- static
- timef(clock, format)
- long clock;
- char *format;
- {
- struct tm *t;
- char c, *p, *fp;
- static char *weekday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
- static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
- if (gflag)
- t = gmtime(&clock);
- else
- t = localtime(&clock);
- for (p = format; *p; p++) {
- c = *p;
- if (c != '%')
- putchar(c);
- else {
- fp = form + 1;
- p++;
- if (*p == '(') {
- p++;
- while (*p && *p != ')')
- *fp++ = *p++;
- if (*p)
- p++;
- }
- *fp = 0;
- switch (*p) {
- case 'm':
- printf(optform("%d"), t->tm_mon + 1);
- break;
- case 'd':
- printf(optform("%d"), t->tm_mday);
- break;
- case 'y':
- printf(optform("%d"), t->tm_year+1900);
- break;
- case 'Y':
- if (clock < halfyearago)
- printf(optform("%d"), t->tm_year+1900);
- break;
- case 'H':
- printf(optform("%d"), t->tm_hour);
- break;
- case 'M':
- printf(optform("%d"), t->tm_min);
- break;
- case 'T':
- if (clock >= halfyearago)
- printf("%02d:%02d", t->tm_hour, t->tm_min);
- break;
- case 'S':
- printf(optform("%d"), t->tm_sec);
- break;
- case 'j':
- printf(optform("%d"), t->tm_yday);
- break;
- case 'w':
- printf(optform("%d"), t->tm_wday);
- break;
- case 'a':
- printf(optform("%s"), weekday[t->tm_wday]);
- break;
- case 'h':
- printf(optform("%s"), month[t->tm_mon]);
- break;
- #ifdef sun
- case 'z':
- printf(optform("%s"), t->tm_gmtoff);
- break;
- case 'Z':
- printf(optform("%s"), t->tm_zone);
- break;
- #endif
- case 'D':
- printf(optform("%s"), t->tm_isdst ? "DST" : "");
- break;
- case 't':
- printf("%02d%02d%02d%02d%02d", t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_year);
- break;
- default :
- putchar(*p);
- break;
- }
- }
- }
- }
-
- /*
- * process - process input file
- */
- static void
- process(inname)
- char *inname;
- {
- struct stat statbuf;
- struct group *grp, *getgrgid();
- struct passwd *pwd, *getpwuid();
- int uid = -10, gid = -10; /* Cached */
- char *pw_name, *gr_name;
- char *p, c, *fp, *ctime();
- int i, j;
- int Lprinted = 0;
-
- if (STREQ(inname, "-")) {
- if (fstat(0, &statbuf) < 0) {
- error("can't fstat `%s'", inname);
- return;
- }
- } else {
- if (lflag) {
- if (stat(inname, &statbuf) < 0) {
- error("can't stat `%s'", inname);
- return;
- }
- } else {
- if (lstat(inname, &statbuf) < 0) {
- error("can't lstat `%s'", inname);
- return;
- }
- }
- }
-
- for (p = format; *p; p++) {
- c = *p;
- if (c != '%')
- putchar(c);
- else {
- fp = form + 1;
- p++;
- if (*p == '(') {
- p++;
- while (*p && *p != ')')
- *fp++ = *p++;
- if (*p)
- p++;
- }
- *fp = 0;
- switch (*p) {
- case 'v':
- printf(optform("%d"), statbuf.st_dev);
- break;
- case 'i':
- printf(optform("%lu"), statbuf.st_ino);
- break;
- case 'p':
- printf(optform("%o"), statbuf.st_mode);
- break;
- case 'P':
- lsmode(statbuf.st_mode);
- break;
- case 'l':
- printf(optform("%d"), statbuf.st_nlink);
- break;
- case 'u':
- printf(optform("%d"), statbuf.st_uid);
- break;
- case 'g':
- printf(optform("%d"), statbuf.st_gid);
- break;
- case 'U':
- if (uid != statbuf.st_uid) {
- if (pwd = getpwuid(statbuf.st_uid))
- pw_name = pwd->pw_name;
- else
- pw_name = "[UNKOWN]";
- }
- printf(optform("%s"), pw_name);
- break;
- case 'G':
- if (gid != statbuf.st_gid) {
- if (grp = getgrgid(statbuf.st_gid))
- gr_name = grp->gr_name;
- else
- gr_name = "[UNKOWN]";
- }
- printf(optform("%s"), gr_name);
- break;
- case 'r':
- printf(optform("%d"), statbuf.st_rdev);
- break;
- case 's':
- printf(optform("%ld"), statbuf.st_size);
- break;
- case 'a':
- printf(optform("%ld"), statbuf.st_atime);
- break;
- case 'm':
- printf(optform("%ld"), statbuf.st_mtime);
- break;
- case 'c':
- printf(optform("%ld"), statbuf.st_ctime);
- break;
- case 't':
- printf(optform("%ld"), currclock);
- break;
- case 'A':
- timef(statbuf.st_atime, taformat);
- break;
- case 'M':
- timef(statbuf.st_mtime, tmformat);
- break;
- case 'C':
- timef(statbuf.st_ctime, tcformat);
- break;
- case 'T':
- timef(currclock, ttformat);
- break;
- #ifndef AIX
- case 'z':
- printf(optform("%ld"), statbuf.st_blksize);
- break;
- case 'b':
- printf(optform("%ld"), statbuf.st_blocks);
- break;
- #endif
- case 'n':
- printf(optform("%s"), inname);
- break;
- case 'f':
- #ifdef S_IFLNK
- if ((statbuf.st_mode & S_IFMT) == S_IFLNK && Lprinted)
- break;
- #endif
- if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
- putchar('/');
- #ifdef S_IFLNK
- else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
- putchar('@');
- #endif
- #ifdef S_IFSOCK
- else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
- putchar('=');
- #endif
- else if (statbuf.st_mode & (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)))
- putchar('*');
- else
- putchar(' ');
- break;
- case 'F':
- if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
- printf(optform("%s"), "S_IFDIR");
- else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
- printf(optform("%s"), "S_IFBLK");
- else if ((statbuf.st_mode & S_IFMT) == S_IFCHR)
- printf(optform("%s"), "S_IFCHR");
- #ifdef S_IFLNK
- else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
- printf(optform("%s"), "S_IFLNK");
- #endif
- #ifdef S_IFIFO
- else if ((statbuf.st_mode & S_IFMT) == S_IFIFO)
- printf(optform("%s"), "S_IFIFO");
- #endif
- #ifdef S_IFSOCK
- else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
- printf(optform("%s"), "S_IFSOCK");
- #endif
- else if ((statbuf.st_mode & S_IFMT) == S_IFREG)
- printf(optform("%s"), "S_IFREG");
- else
- printf(optform("%s"), "");
- break;
- case 'Y':
- if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
- printf(optform("%s"), typename[0]);
- else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
- printf(optform("%s"), typename[1]);
- else if ((statbuf.st_mode & S_IFMT) == S_IFCHR)
- printf(optform("%s"), typename[2]);
- #ifdef S_IFLNK
- else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
- printf(optform("%s"), typename[3]);
- #endif
- #ifdef S_IFIFO
- else if ((statbuf.st_mode & S_IFMT) == S_IFIFO)
- printf(optform("%s"), typename[4]);
- #endif
- #ifdef S_IFSOCK
- else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
- printf(optform("%s"), typename[5]);
- #endif
- else if ((statbuf.st_mode & S_IFMT) == S_IFREG)
- printf(optform("%s"), typename[6]);
- else
- printf(optform("%s"), "");
- break;
- case 'q':
- for (i = 0400; i; i >>= 1)
- if (statbuf.st_mode & i)
- printf(optform("%s"), "1");
- else
- printf(optform("%s"), "0");
- break;
- case 'Q':
- #ifdef S_IFLNK
- if ((statbuf.st_mode & S_IFMT) == S_IFLNK && ! lflag)
- break;
- #endif
- if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
- j = 12;
- else
- j = 0;
- for (i = 04000; i; i >>= 1, j++)
- if (statbuf.st_mode & i)
- printf(optform("%s"), modename[j]);
- break;
- #ifdef S_IFLNK
- case 'L':
- if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
- int len;
- char buf[MAXPATHLEN];
-
- if ((len = readlink(inname, buf, MAXPATHLEN)) == -1) {
- error("can't readlink `%s'", inname);
- break;
- }
- buf[len] = 0;
- printf(optform("%s"), buf);
- Lprinted = 1;
- } else
- printf(optform("%s"), "");
- break;
- case '-':
- if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
- fputs(" -> ", stdout);
- Lprinted = 1;
- }
- break;
- #endif
- default :
- putchar(c);
- break;
- }
- }
- }
- putchar('\n');
- }
-
- /*
- * error - report trouble
- */
- static void /* does not return */
- error(s1, s2)
- char *s1, *s2;
- {
- extern int sys_nerr, errno;
- extern char *sys_errlist[];
-
- fprintf(stderr, "%s: ", progname);
- fprintf(stderr, s1, s2);
- if( errno && errno <= sys_nerr )
- fprintf(stderr, " (%s)", sys_errlist[errno]);
- putc('\n', stderr);
- if (eflag)
- exit(1);
- }
-
- /*
- * mkprogname - convert string to a meaningful program name
- * May change the string
- */
- char *
- mkprogname(s)
- char *s;
- {
- char *p, *p2;
- char *unkown="[unkown]";
-
- if (!s || !*s)
- return unkown;
- p = s;
- if ((p2 = strrchr(s, '/')) > p) /* Check for path */
- p = p2+1;
- #ifdef MSDOS
- if ((p2 = strrchr(s, '\\')) > p) /* Check for backslash path */
- p = p2+1;
- if ((p2 = strrchr(s, ':')) > p) /* Check for drive spec */
- p = p2+1;
- if ((p2 = strrchr(s, '.')) > p) /* Check for extension */
- *p2=0;
- for (p2=p; *p2; p2++) /* Make it lowercase */
- if (isascii(*p2) && isupper(*p2))
- *p2 = tolower(*p2);
- #endif
- if (*p)
- return p;
- else
- return unkown;
- }
-
- char *modename[] = { /* File mode english names */
- "run with id of the owner ",
- "run with id of the group ",
- "stay in swap space on termination ",
- "owner can read ",
- "owner can change ",
- "owner can execute ",
- "group can read ",
- "group can change ",
- "group can execute ",
- "anyone can read ",
- "anyone can change ",
- "anyone can execute ",
- "",
- "files inherit group ",
- "only owners can delete files ",
- "owner can read ",
- "owner can change ",
- "owner can access ",
- "group can read ",
- "group can change ",
- "group can access ",
- "anyone can read ",
- "anyone can change ",
- "anyone can access ",
- };
-
- /* File type english names */
- char *typename[] = {
- "Directory",
- "Block special",
- "Character special",
- "Symbolic link",
- "Named pipe",
- "Socket",
- "Regular file",
- };
-
- /*
- * Convert a separator terminated list of strings starting with the
- * terminator to an array. The strings should be exactly number else
- * an error is printed.
- */
- static void
- parsenames(names, array, number, errname)
- char *names, *errname;
- char *array[];
- int number;
- {
- char term = *names;
- char *p, *p2;
- int count = 0;
-
- for (p = p2 = names + 1; *p ; p++)
- if (*p == term) {
- array[count++] = p2;
- *p++ = 0;
- p2 = p;
- if (count > number)
- break;
- }
- if (count != number) {
- fprintf(stderr, "%s: expected %d arguments to specify file %s, got %d\n", progname, number, errname, count);
- exit(1);
- }
- }
-