28-Dec-85 04:10:43-MST,7958;000000000001
Return-Path: <[email protected]>
Received: from BRL-TGR.ARPA by SIMTEL20.ARPA with TCP; Sat 28 Dec 85 04:10:33-MST
Received: from usenet by TGR.BRL.ARPA id a020626; 28 Dec 85 5:43 EST
From: Wombat <[email protected]>
Newsgroups: net.sources
Subject: Updated version of stat.c
Message-ID: <680@pucc-j>
Date: 27 Dec 85 19:48:29 GMT
Keywords: stat, inode, ls
To:       [email protected]

This is a revision of an earlier posting; it incorporates several improvements
and bug fixes as noted in the opening comments.  Additional bug fixes and
changes *to the author*, please.

/*
*      Stat.c          Dump out inode info in nice form.   pur-ee!rsk
*                      Original version by someone at Purdue in the days of v6;
*                      this one by Rsk for modern times. (4.2, V)
*
*                      Bug fix for setuid bit misplacement, and modifications
*                      for System V by Bill Stoll, whuxlm!wws.
*
*                      Masscomp (and system V) mods by Stan Barber, neuro1!sob.
*
*                      Bug fix for setuid bit and flag mods, and for
*                      misplaced include of time.h, okstate!zap.
*                      Note: I left SINCE as a compile-time option; it
*                      probably shouldn't even be there. ---Rsk
*
*                      (void)'s added to make lint happy, pur-ee!rsk.
*
*                      Still doesn't run under 2.9; to be fixed soon.
*
*
*      Vanilla version is for system V.
*      Define BSD42 for 4.2bsd version.
*      Define SINCE for "elapsed time" since inode times.
*      Define MASSCOMP for those machines; this implies system V.
*/

#ifdef MASSCOMP
#undef BSD42
#endif MASSCOMP

#include        <stdio.h>
#include        <sys/time.h>
#include        <sys/types.h>
#include        <ctype.h>
#include        <sys/stat.h>
#include        <pwd.h>
#include        <grp.h>

#define FAIL    -1              /* Failure return code from call */
#define OKAY    0               /* Success return code from call */

struct  stat    Sbuf;           /* for return values from stat() call */
char    *ctime();               /* Time conversion      */
struct  passwd  *getpwuid();    /* User entry */
struct  passwd  *pwent;         /* User structure */
struct  group   *getgrgid();    /* Group entry */
struct  group   *grent;         /* Group structure */

char    Mode[10];       /* File protection mode */

#define LBUFSIZ 256     /* Length for symbolic link translation buffer */
char    Lbuf[LBUFSIZ];  /* Symbolic link translation buffer */

main(argc, argv)
int argc;
char *argv[];
{
       int i;

       i = 1;

       if(argc == 1) {
               (void) fprintf(stderr,"Usage: stat file1 [file2 ...]\n");
               exit(1);
       }

       do {

               (void) stat_it(argv[i]);

               if(  (argc > 1) && (i < (argc-1)) )
                       (void) printf("\n");
       }
       while(++i < argc);

       exit(0);
}

/*
* stat_it() - Actually stat and format results from file.
*              exit -    OKAY if no problems encountered
*                        FAIL if couldn't open or other nastiness
*
*/
stat_it(filename)
char    *filename;
{
       int     count;

#ifdef BSD42
       if( lstat(filename,&Sbuf) == FAIL) {
               (void) fprintf(stderr,"Can't lstat %s\n",filename);
               return(FAIL);
       }
#else BSD42
       if( stat(filename,&Sbuf) == FAIL) {
               (void) fprintf(stderr,"Can't stat %s\n",filename);
               return(FAIL);
       }
#endif BSD42

#ifdef BSD42
       if( (Sbuf.st_mode & S_IFMT) == S_IFLNK) {
               if( (count=readlink(filename,Lbuf,LBUFSIZ)) == FAIL) {
                       (void) fprintf(stderr,"Can't readlink %s\n", filename);
                       return(FAIL);
               }
               if( count < LBUFSIZ)
                       Lbuf[count] = '\0';
               (void) printf("  File: \"%s\" -> \"%s\"\n",filename,Lbuf);
       }
       else
#endif BSD42
               (void) printf("  File: \"%s\"\n", filename);

       (void) printf("  Size: %-10d", Sbuf.st_size);
#ifdef BSD42
       (void) printf("   Allocated Blocks: %-10ld", Sbuf.st_blocks);
#endif BSD42

       (void) printf("   Filetype: ");
       switch( Sbuf.st_mode & S_IFMT) {
               case    S_IFDIR:        (void) printf("Directory\n");
                                       break;
               case    S_IFCHR:        (void) printf("Character Device\n");
                                       break;
               case    S_IFBLK:        (void) printf("Block Device\n");
                                       break;
               case    S_IFREG:        (void) printf("Regular File\n");
                                       break;
#ifdef BSD42
               case    S_IFLNK:        (void) printf("Symbolic Link\n");
                                       break;
               case    S_IFSOCK:       (void) printf("Socket\n");
                                       break;
#else BSD42
               case    S_IFIFO:        (void) printf("Fifo File\n");
                                       break;
#endif BSD42
#ifdef MASSCOMP
               case    S_IFCTG:        (void) printf("Contiguous File\n");
                                       break;
#endif MASSCOMP
               default         :       (void) printf("Unknown\n");
       }

       (void) strcpy(Mode,"----------");
       if(Sbuf.st_mode & (S_IEXEC>>6))         /* Other execute */
               Mode[9] = 'x';
       if(Sbuf.st_mode & (S_IWRITE>>6))        /* Other write */
               Mode[8] = 'w';
       if(Sbuf.st_mode & (S_IREAD>>6))         /* Other read */
               Mode[7] = 'r';
       if(Sbuf.st_mode & (S_IEXEC>>3))         /* Group execute */
               Mode[6] = 'x';
       if(Sbuf.st_mode & (S_IWRITE>>3))        /* Group write */
               Mode[5] = 'w';
       if(Sbuf.st_mode & (S_IREAD>>3))         /* Group read */
               Mode[4] = 'r';
       if(Sbuf.st_mode & S_IEXEC)              /* User execute */
               Mode[3] = 'x';
       if(Sbuf.st_mode & S_IWRITE)             /* User write */
               Mode[2] = 'w';
       if(Sbuf.st_mode & S_IREAD)              /* User read */
               Mode[1] = 'r';
       if(Sbuf.st_mode & S_ISVTX)              /* Sticky bit */
               Mode[9] = 't';
       if(Sbuf.st_mode & S_ISGID)              /* Set group id */
               Mode[6] = 's';
       if(Sbuf.st_mode & S_ISUID)              /* Set user id */
               Mode[3] = 's';
       switch( Sbuf.st_mode & S_IFMT) {
               case    S_IFDIR:        Mode[0] = 'd';
                                       break;
               case    S_IFCHR:        Mode[0] = 'c';
                                       break;
               case    S_IFBLK:        Mode[0] = 'b';
                                       break;
               case    S_IFREG:        Mode[0] = '-';
                                       break;
#ifdef BSD42
               case    S_IFLNK:        Mode[0] = 'l';
                                       break;
               case    S_IFSOCK:       Mode[0] = 's';
                                       break;
#else BSD42
               case    S_IFIFO:        Mode[0] = 'f';
                                       break;
#endif BSD42
#ifdef MASSCOMP
               case    S_IFCTG:        Mode[0] = 'C';
                                       break;
#endif MASSCOMP
               default         :       Mode[0] = '?';
       }
       (void) printf("  Mode: (%04o/%s)", Sbuf.st_mode&07777,Mode);


       (void) setpwent();
       if( (pwent = getpwuid(Sbuf.st_uid)) == NULL) {
               (void) fprintf(stderr,"getpwuid() failed\n");
               exit(1);
       }
       (void) printf("         Uid: (%5d/%8s)", Sbuf.st_uid, pwent->pw_name);

       (void) setgrent();
       if( (grent = getgrgid(Sbuf.st_gid)) == NULL) {
               (void) fprintf(stderr,"getgrgid() failed\n");
               exit(1);
       }
       (void) printf("  Gid: (%5d/%8s)\n", Sbuf.st_gid, grent->gr_name);


       (void) printf("Device: %-5d", Sbuf.st_dev);
       (void) printf("  Inode: %-10d", Sbuf.st_ino);
       (void) printf("Links: %-5d", Sbuf.st_nlink);

       /* Only meaningful if file is device */

       if(  ( (Sbuf.st_mode & S_IFMT) == S_IFCHR)
               || ( (Sbuf.st_mode & S_IFMT) == S_IFBLK) )
               (void) printf("     Device type: %d\n",Sbuf.st_rdev);
       else
               (void) printf("\n");

       /* The %.24s strips the newline from the ctime() string */

#ifdef SINCE
       (void) printf("Access: %.24s",ctime(&Sbuf.st_atime));
       (void) tsince(Sbuf.st_atime);
       (void) printf("Modify: %.24s",ctime(&Sbuf.st_mtime));
       (void) tsince(Sbuf.st_mtime);
       (void) printf("Change: %.24s",ctime(&Sbuf.st_ctime));
       (void) tsince(Sbuf.st_ctime);
#else SINCE
       (void) printf("Access: %s",ctime(&Sbuf.st_atime));
       (void) printf("Modify: %s",ctime(&Sbuf.st_mtime));
       (void) printf("Change: %s",ctime(&Sbuf.st_ctime));
#endif SINCE

/*
*       Should I put this in somewhere?  No.
*
*       printf("Optimal Blocksize: %ld\n", Sbuf.st_blksize);
*/

       return(OKAY);
}

#ifdef SINCE
tsince(time_sec)
long    time_sec;
{
       long    time_buf;
       long    d_since;        /* days elapsed since time */
       long    h_since;        /* hours elapsed since time */
       long    m_since;        /* minutes elapsed since time */
       long    s_since;        /* seconds elapsed since time */

       (void) time(&time_buf);

       if(time_sec > time_buf) {
               (void) fprintf(stderr,"Time going backwards\n");
               exit(1);
       }

       s_since = time_buf - time_sec;
       d_since = s_since / 86400l ;
       s_since -= d_since * 86400l ;
       h_since = s_since / 3600l ;
       s_since -= h_since * 3600l ;
       m_since = s_since / 60l ;
       s_since -= m_since * 60l ;

       (void) printf("(%05ld.%02ld:%02ld:%02ld)\n",d_since,h_since,m_since,s_since);

       return(OKAY);
}
#endif SINCE
--
Rich Kulawiec pur-ee!rsk purdue-!rsk [email protected] [email protected]