home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume10
/
stat
/
stat.c
< prev
Wrap
C/C++ Source or Header
|
1990-02-26
|
15KB
|
649 lines
/*
* 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);
}
}