[net.sources] Updated version of stat.c

rsk@pucc-j (Wombat) (12/27/85)

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 rsk@purdue-asc.arpa rsk@asc.purdue.edu