#!mkcmd
# mkcmd for stat util
from '<sys/time.h>'
from '<sys/types.h>'
from '<sys/stat.h>'
from '<unistd.h>'
from '<errno.h>'
from '<pwd.h>'
from '<grp.h>'
from '<time.h>'

require "std_help.m" "std_version.m"

basename "stat" ""

%i
static char rcsid[] =
	"$Id: stat.m,v 2.11 2012/11/08 15:07:26 ksb Exp $";

#if defined(SYSV) || defined(MASSCOMP)
#include <sys/sysmacros.h>
#endif /* SYSV */

/* more evolved systems have a inode allocation time (birthtime)
 */
#if !defined(HAVE_BIRTHTIME)
#define HAVE_BIRTHTIME	(defined(FREEBSD) && (HOSTOS>=70000))
#endif
%%

%c
#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 */
void	exit();			/* Terminate the program */
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	acMode[16];	/* File protection mode "drwxrwxrwx\000" */

#if defined(S_IFLNK)
#define	LBUFSIZ	1024	/* Length for symbolic link translation buffer */
char	Lbuf[LBUFSIZ];	/* Symbolic link translation buffer */
#endif

#ifdef SINCE
void
tsince(time_sec)
time_t	time_sec;
{
	time_t	time_buf;
	time_t	d_since;	/* days elapsed since time */
	time_t	h_since;	/* hours elapsed since time */
	time_t	m_since;	/* minutes elapsed since time */
	time_t	s_since;	/* seconds elapsed since time */
	char	*backward;	/* "-" if future time, else "" */

	(void) time(&time_buf);

	if (time_sec > time_buf) {
		time_t	temp;

		temp = time_sec;
		time_sec = time_buf;
		time_buf = temp;
		backward = "-";
	} else {
		backward = "";
	}

	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%s)\n",
	  d_since,h_since,m_since,s_since,backward);

	return;
}
#endif /* SINCE */

/*
 * stat_it() - Actually stat and format results from file.		(rsk)
 *		exit -    OKAY if no problems encountered
 *			  FAIL if couldn't open or other nastiness
 *
 */
static void
stat_it(filename)
char	*filename;
{
	static int fBeenHere = 0;
	auto char *pwn, *grn;
#ifdef SINCE
	auto time_t time_temp;
#endif /* SINCE */
#if defined(S_IFLNK)
	register int count;
#endif
#ifdef eta10
	register int cpid;
#endif /* eta10 */

	if (fBeenHere)
		putchar('\n');
	fBeenHere = 1;

#if defined(S_IFLNK)
	if (-1 == lstat(filename,&Sbuf)) {
		fprintf(stderr,"%s: lstat: %s: %s\n", progname, filename, strerror(errno));
		return;
	}
#else
	if (-1 == stat(filename, &Sbuf)) {
		fprintf(stderr,"%s: stat: %s: %s\n", progname, filename, strerror(errno));
		return;
	}
#endif

#if defined(S_IFLNK)
	if (S_IFLNK == (Sbuf.st_mode & S_IFMT)) {
		if (-1 == (count = readlink(filename,Lbuf,LBUFSIZ))) {
			fprintf(stderr,"%s: readlink: %s: %s\n", progname, filename, strerror(errno));
			return;
		}
		if (count < LBUFSIZ)
			Lbuf[count] = '\0';
		if (fOnePerLine)
			(void) printf("File: \"%s\" -> \"%s\"\n",filename,Lbuf);
		else
			(void) printf("  File: \"%s\" -> \"%s\"\n",filename,Lbuf);
	} else
#endif
	{
		if (fOnePerLine)
			(void) printf("File: \"%s\"\n", filename);
		else
			(void) printf("  File: \"%s\"\n", filename);

		if (fOnePerLine)
			(void) printf("Size: %-10ld\n", Sbuf.st_size);
		else
			(void) printf("  Size: %-10ld", Sbuf.st_size);

		if (fOnePerLine)
			(void) printf("Allocated Blocks: %-10ld\n", Sbuf.st_blocks);
		else
			(void) printf("   Allocated Blocks: %-10ld", Sbuf.st_blocks);
	}

	if (fOnePerLine)
		(void) printf("Filetype: ");
	else
		(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;
#if defined(S_IFLNK)
	case	S_IFLNK:
		(void) printf("Symbolic Link\n");
		break;
#endif
#if defined(S_IFSOCK)
	case	S_IFSOCK:
		(void) printf("Socket\n");
		break;
#endif
#if defined(S_IFIFO)
	case	S_IFIFO:
		(void) printf("Fifo File\n");
		break;
#endif
#if defined(S_IFCTG)
	case	S_IFCTG:
		(void) printf("Contiguous File\n");
		break;
#endif
	default:
		(void) printf("Unknown\n");
		break;
	}

	(void) strcpy(acMode,"----------");
	if (Sbuf.st_mode & S_ISVTX)		/* Sticky bit */
		acMode[9] = (Sbuf.st_mode & (S_IEXEC>>6)) ? 't' : 'T';
	else if (Sbuf.st_mode & (S_IEXEC>>6))	/* Other execute */
		acMode[9] = 'x';
	if (Sbuf.st_mode & (S_IWRITE>>6))	/* Other write */
		acMode[8] = 'w';
	if (Sbuf.st_mode & (S_IREAD>>6))		/* Other read */
		acMode[7] = 'r';

	/* Sun's the 'S' is a 'l' if no execute bits are set
	 * see thelocking description in ls(1) --ksb
	 */
	if (Sbuf.st_mode & S_ISGID)		/* Set group id */
		acMode[6] = 0 != (Sbuf.st_mode & 0010) ? 's' : 0 == (Sbuf.st_mode & 0111) ? 'l' : 'S';
	else if (Sbuf.st_mode & (S_IEXEC>>3))	/* Group execute */
		acMode[6] = 'x';
	if (Sbuf.st_mode & (S_IWRITE>>3))	/* Group write */
		acMode[5] = 'w';
	if (Sbuf.st_mode & (S_IREAD>>3))		/* Group read */
		acMode[4] = 'r';

	if (Sbuf.st_mode & S_ISUID)		/* Set user id */
		acMode[3] = 0 != (Sbuf.st_mode & 0100) ? 's' : 'S';
	else if (Sbuf.st_mode & S_IEXEC)		/* User execute */
		acMode[3] = 'x';
	if (Sbuf.st_mode & S_IWRITE)		/* User write */
		acMode[2] = 'w';
	if (Sbuf.st_mode & S_IREAD)		/* User read */
		acMode[1] = 'r';

	switch (Sbuf.st_mode & S_IFMT) {	/* node type */
	case	S_IFDIR:
		acMode[0] = 'd';
		break;
	case	S_IFCHR:
		acMode[0] = 'c';
		break;
	case	S_IFBLK:
		acMode[0] = 'b';
		break;
	case	S_IFREG:
		acMode[0] = '-';
		break;
#if defined(S_IFLNK)
	case	S_IFLNK:
		acMode[0] = 'l';
		break;
#endif
#if defined(S_IFSOCK)
	case	S_IFSOCK:
		acMode[0] = 's';
		break;
#endif
#if defined(S_IFIFO)
	case	S_IFIFO:
		acMode[0] = 'p';
		break;
#endif
#if defined(S_IFCTG)
	case	S_IFCTG:
		acMode[0] = 'C';
		break;
#endif
	default:
		acMode[0] = '?';
		break;
	}
	if (fOnePerLine)
		(void) printf("Mode: (%04o/%s)\n", Sbuf.st_mode&07777,acMode);
	else
		(void) printf("  Mode: (%04o/%s)", Sbuf.st_mode&07777,acMode);

	(void) setpwent();
	if ((struct passwd *)0 == (pwent = getpwuid(Sbuf.st_uid))) {
		pwn = "???";
	} else {
		pwn = pwent->pw_name;
	}
	if (fOnePerLine)
		(void) printf("Uid: (%d/%s)\n", Sbuf.st_uid, pwn);

	else
		(void) printf("         Uid: (%5d/%8s)", Sbuf.st_uid, pwn);

	(void) setgrent();
	if ((struct group *)0 == (grent = getgrgid(Sbuf.st_gid))) {
		grn = "???";
	} else {
		grn = grent->gr_name;
	}
	if (fOnePerLine)
		(void) printf("Gid: (%d/%s)\n", Sbuf.st_gid, grn);
	else
		(void) printf("  Gid: (%5d/%8s)\n", Sbuf.st_gid, grn);


	(void) printf("Device:");
#ifdef eta10
	cpid = devcpuid(Sbuf.st_dev);
	if (iscpid(cpid))
		(void) printf(" CPU%d          ", cpnum(cpid));
	else if (isiopid(cpid))
		(void) printf(" IOU%d IOP%d VME%d", iounum(cpid), iopnum(cpid), vmenum(cpid));
	else
		(void) printf(" CPID 0x%04x   ", cpid);
#endif /* eta10 */
#if !defined(major)
#define major(x)        (((unsigned)(x)>>16)&0xffff)
#endif

#if !defined(minor)
#define minor(x)        ((x)&0xffff)
#endif
	(void) printf(" %2d,%-2d", major(Sbuf.st_dev), minor(Sbuf.st_dev));
	if (fOnePerLine)
		(void) printf("\n");
	if (fOnePerLine)
		(void) printf("Inode: %-10ld\n", (long)Sbuf.st_ino);
	else
		(void) printf("  Inode: %-10ld", (long)Sbuf.st_ino);
	(void) printf("Links: %-5d", Sbuf.st_nlink);

	/* Only meaningful if file is device */

	if (S_IFCHR == (Sbuf.st_mode & S_IFMT) || S_IFBLK == (Sbuf.st_mode & S_IFMT)) {
#ifdef eta10
		(void) printf("\n  Type: ");
		cpid = devcpuid(Sbuf.st_rdev);
		if (iscpid(cpid))
			(void) printf("CPU%d          ", cpnum(cpid));
		else if (isiopid(cpid))
			(void) printf("IOU%d IOP%d VME%d",
			  iounum(cpid), iopnum(cpid), vmenum(cpid));
		else
			(void) printf("CPID 0x%04x   ", cpid);
#else /* not eta10 */
		if (fOnePerLine)
			(void) printf("\nDevice type:");
		else
			(void) printf("     Device type:");
#endif /* eta10 */
		(void) printf(" %2d,%-2d\n",
		  major(Sbuf.st_rdev), minor(Sbuf.st_rdev));
	} else {
		(void) printf("\n");
	}

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

#ifdef SINCE
#if HAVE_BIRTHTIME
	time_temp = Sbuf.st_birthtime;
	(void) printf("Birth: %.24s",ctime(&time_temp));
	tsince(time_temp);
#endif
	time_temp = Sbuf.st_atime;
	(void) printf("Access: %.24s",ctime(&time_temp));
	tsince(time_temp);
	time_temp = Sbuf.st_mtime;
	(void) printf("Modify: %.24s",ctime(&time_temp));
	tsince(time_temp);
	time_temp = Sbuf.st_ctime;
	(void) printf("Change: %.24s",ctime(&time_temp));
	tsince(time_temp);
#else /* SINCE */
#if HAVE_BIRTHTIME
	(void) printf("Birth: %s",ctime(&Sbuf.st_birthtime));
#endif
	(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 */
}
%%

boolean '1' {
	named "fOnePerLine"
	help "output one attribute per line (was -)"
}
every {
	named "stat_it"
	parameter "nodes"
	help "names to stat"
}
