/*-
 * Copyright (c)1997-2005 by Hartmut Brandt
 * 	All rights reserved.
 *
 * Author: Harti Brandt <harti@freebsd.org>
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Begemot: libbegemot/prstat.c,v 1.18 2005/06/01 08:01:45 brandt_h Exp $
 */
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include "begemot.h"

#ifdef TIMESPEC_HAS_TS
#define TV_SEC	ts_sec
#define TV_NSEC	ts_nsec
#else
#define TV_SEC	tv_sec
#define TV_NSEC	tv_nsec
#endif

#define CB(B,F) ((B & F) != 0)

/*
 * Print the contents of a stat buffer onto a file
 */
void
prstat(FILE *fp, const struct stat *sb)
{
#if defined(STAT_HAS_TIMESPEC) || defined(STAT_HAS_TIMEVAL)
	char tbuf[512];
	time_t clk;
#else
	char *tval;
#endif
#ifdef STAT_HAS_FLAGS
	int first;
#endif

	(void)fprintf(fp, "st_dev = (%lu,%lu)\n",
		(u_long)major(sb->st_dev),
		(u_long)minor(sb->st_dev));
	(void)fprintf(fp, "st_ino = %lu\n", (u_long)sb->st_ino);
	(void)fprintf(fp, "st_mode = ");
	switch (sb->st_mode & S_IFMT) {

	  case S_IFIFO:
		(void)putc('f', fp);
		break;

	  case S_IFCHR:
		(void)putc('c', fp);
		break;

	  case S_IFDIR:
		(void)putc('d', fp);
		break;

#ifdef IFNAM
	  case S_IFNAM:
		(void)putc('n', fp);
		break;
#endif

	  case S_IFBLK:
		(void)putc('b', fp);
		break;

	  case S_IFREG:
		(void)putc('-', fp);
		break;

	  case S_IFLNK:
		(void)putc('l', fp);
		break;

	  case S_IFSOCK:
		(void)putc('s', fp);
		break;

#ifdef IFDOOR
	  case S_IFDOOR:
		(void)putc('o', fp);
		break;
#endif

#ifdef IFWHT
	  case S_IFWHT:
		(void)putc('w', fp);
		break;
#endif

	  default:
		(void)fprintf(fp, "type=0x%lx", (u_long)((sb->st_mode & S_IFMT) >> 12));
		break;
	}
	(void)putc(' ', fp);

	if(sb->st_mode & S_ISUID)
		(void)fprintf(fp, "suid ");
	if(sb->st_mode & S_ISGID)
		(void)fprintf(fp, "sgid ");
	if(sb->st_mode & S_ISVTX)
		(void)fprintf(fp, "vtx ");

	(void)fprintf(fp, "%c%c%c%c%c%c%c%c%c",
		"-r"[CB(S_IRUSR, sb->st_mode)],
		"-w"[CB(S_IWUSR, sb->st_mode)],
		"-x"[CB(S_IXUSR, sb->st_mode)],
		"-r"[CB(S_IRGRP, sb->st_mode)],
		"-w"[CB(S_IWGRP, sb->st_mode)],
		"-x"[CB(S_IXGRP, sb->st_mode)],
		"-r"[CB(S_IROTH, sb->st_mode)],
		"-w"[CB(S_IWOTH, sb->st_mode)],
		"-x"[CB(S_IXOTH, sb->st_mode)]);
	(void)putc('\n', fp);
	(void)fprintf(fp, "st_nlink = %lu\n", (u_long)sb->st_nlink);
	(void)fprintf(fp, "st_uid = %ld\n", (long)sb->st_uid);
	(void)fprintf(fp, "st_gid = %ld\n", (long)sb->st_gid);
	(void)fprintf(fp, "st_rdev = (%lu,%lu)\n",
		(u_long)major(sb->st_rdev), 
		(u_long)minor(sb->st_rdev));
	(void)fprintf(fp, "st_size = %ld\n", (long)sb->st_size);

#ifdef STAT_HAS_TIMESPEC
	clk = sb->st_atimespec.TV_SEC;
	(void)strftime(tbuf, sizeof(tbuf), "%Y %T", gmtime(&clk));
	(void)sprintf(tbuf + strlen(tbuf), ".%09lu", sb->st_atimespec.TV_NSEC);
	(void)fprintf(fp, "st_atime = %s\n", tbuf);

	clk = sb->st_mtimespec.TV_SEC;
	(void)strftime(tbuf, sizeof(tbuf), "%Y %T", gmtime(&clk));
	(void)sprintf(tbuf + strlen(tbuf), ".%09lu", sb->st_mtimespec.TV_NSEC);
	(void)fprintf(fp, "st_mtime = %s\n", tbuf);

	clk = sb->st_ctimespec.TV_SEC;
	(void)strftime(tbuf, sizeof(tbuf), "%Y %T", gmtime(&clk));
	(void)sprintf(tbuf + strlen(tbuf), ".%09lu", sb->st_ctimespec.TV_NSEC);
	(void)fprintf(fp, "st_ctime = %s\n", tbuf);
#elif defined(STAT_HAS_TIMEVAL)
	clk = sb->st_atim.tv_sec;
	(void)strftime(tbuf, sizeof(tbuf), "%Y %T", gmtime(&clk));
	(void)sprintf(tbuf + strlen(tbuf), ".%06lu", sb->st_atim.tv_nsec);
	(void)fprintf(fp, "st_atime = %s\n", tbuf);

	clk = sb->st_mtim.tv_sec;
	(void)strftime(tbuf, sizeof(tbuf), "%Y %T", gmtime(&clk));
	(void)sprintf(tbuf + strlen(tbuf), ".%06lu", sb->st_mtim.tv_nsec);
	(void)fprintf(fp, "st_mtime = %s\n", tbuf);

	clk = sb->st_ctim.tv_sec;
	(void)strftime(tbuf, sizeof(tbuf), "%Y %T", gmtime(&clk));
	(void)sprintf(tbuf + strlen(tbuf), ".%06lu", sb->st_ctim.tv_nsec);
	(void)fprintf(fp, "st_ctime = %s\n", tbuf);
#else
	tval = asctime(gmtime(&sb->st_atime));
	(void)fprintf(fp, "st_atime = %s", tval);
	tval = asctime(gmtime(&sb->st_mtime));
	(void)fprintf(fp, "st_mtime = %s", tval);
	tval = asctime(gmtime(&sb->st_ctime));
	(void)fprintf(fp, "st_ctime = %s", tval);
#endif
	(void)fprintf(fp, "st_blksize = %ld\n", (long)sb->st_blksize);
	(void)fprintf(fp, "st_blocks = %"QUADFMT"d\n", (u_int64_t)sb->st_blocks);
#ifdef STAT_HAS_FSTYPE
	(void)fprintf(fp, "st_fstype = %.*s\n", (int)sizeof(sb->st_fstype), sb->st_fstype);
#endif
#ifdef STAT_HAS_FLAGS
	(void)fprintf(fp, "st_flags = %08lx<", (u_long)sb->st_flags);

#define PRFLAG(L,S)						\
	if (sb->st_flags & L) {					\
		if (!first)					\
			(void)fprintf(fp, ",");			\
		else						\
			first = 0;				\
		(void)fprintf(fp, #S);				\
	}
	first = 1;

#ifdef UF_NODUMP
	PRFLAG(UF_NODUMP, nodump);
#endif
#ifdef UF_IMMUTABLE
	PRFLAG(UF_IMMUTABLE, uimmutable);
#endif
#ifdef UF_APPEND
	PRFLAG(UF_APPEND, uappend)
#endif
#ifdef UF_OPAQUE
	PRFLAG(UF_OPAQUE, opaque)
#endif
#ifdef UF_NOUNLINK
	PRFLAG(UF_NOUNLINK, unounlink)
#endif
#ifdef SF_ARCHIVED
	PRFLAG(SF_ARCHIVED, archived)
#endif
#ifdef SF_IMMUTABLE
	PRFLAG(SF_IMMUTABLE, simmutable)
#endif
#ifdef SF_APPEND
	PRFLAG(SF_APPEND, sappend)
#endif
#ifdef SF_NOUNLINK
	PRFLAG(SF_NOUNLINK, snounlink)
#endif
#ifdef SF_SNAPSHOT
	PRFLAG(SF_SNAPSHOT, snapshot)
#endif
#undef PRFLAG
	(void)fprintf(fp, ">\n");
#endif


#ifdef STAT_HAS_GEN
	(void)fprintf(fp, "st_gen = %u\n", sb->st_gen);
#endif

#ifdef STAT_HAS_BIRTHTIMESPEC
	clk = sb->st_birthtimespec.TV_SEC;
	(void)strftime(tbuf, sizeof(tbuf), "%Y %T", gmtime(&clk));
	(void)sprintf(tbuf + strlen(tbuf), ".%09lu", sb->st_birthtimespec.TV_NSEC);
	(void)fprintf(fp, "st_birthtime = %s\n", tbuf);
#endif
}

#ifdef TEST
#include <string.h>
#include <errno.h>
int
main(int argc, char *argv[])
{
	struct stat statb;

	if (fstat(0, &statb))
		panic("cannot stat stdin: %s", strerror(errno));
	prstat(stdout, &statb);
	return (0);
}
#endif


syntax highlighted by Code2HTML, v. 0.9.1