
/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */


#ifndef lint
 static char rcsid[] = "$Header: ipcs.c 2.1 88/03/24 $";
#endif lint

/*
 * $Log:	ipcs.c,v $
 */

/*
**	ipcs - IPC status
**	Examine and print certain things about message queues, semaphores,
**		and shared memory.
*/

#define KERNEL	1
#include	"sys/types.h"
#include	"sys/ipc.h"
#include	"nlist.h"
#include	"fcntl.h"
#include	"time.h"
#include	"grp.h"
#include	"pwd.h"
#include	"stdio.h"
#include	"sys/msg.h"
#include	"sys/sem.h"

#define	TIME	0
#define	MSG	1
#define	SEM	2
#define	MSGINFO	3
#define	SEMINFO	4

/*
 * define this here, so it doesn't clash with system V time.h
 */
struct timeval {
	long	tv_sec;		/* seconds */
	long	tv_usec;	/* and microseconds */
};

struct nlist nl[] = {		/* name list entries for IPC facilities */
	{"_time"},
	{"_msgque"},
	{"_sema"},
	{"_msginfo"},
	{"_seminfo"},
	{NULL}
};
char	chdr[] = "T     ID     KEY        MODE       OWNER    GROUP",
				/* common header format */
	chdr2[] = "  CREATOR   CGROUP",
				/* c option header format */
	*name = "/dynix",	/* name list file */
	*mem = "/dev/kmem",	/* memory file */
	opts[] = "abcmopqstC:N:";/* allowable options for getopt */
extern char	*optarg;	/* arg pointer for getopt */
int		bflg,		/* biggest size:
					segsz on m; qbytes on q; nsems on s */
		cflg,		/* creator's login and group names */
		mflg,		/* shared memory status */
		oflg,		/* outstanding data:
					nattch on m; cbytes, qnum on q */
		pflg,		/* process id's: lrpid, lspid on q;
					cpid, lpid on m */
		qflg,		/* message queue status */
		sflg,		/* semaphore status */
		tflg,		/* times: atime, ctime, dtime on m;
					ctime, rtime, stime on q;
					ctime, otime on s */
		err;		/* option error count */
extern int	optind;		/* option index for getopt */

extern char		*ctime();
extern struct group	*getgrgid();
extern struct passwd	*getpwuid();
extern long		lseek();

main(argc, argv)
int	argc;	/* arg count */
char	**argv;	/* arg vector */
{
	register int	i,	/* loop control */
			md,	/* memory file file descriptor */
			o;	/* option flag */
	struct timeval	Btime;	/* BSD 4.2 time structure */
	time_t		time;	/* date in memory file */
	struct msqid_ds	qds;	/* message queue data structure */
	struct msginfo msginfo;	/* message information structure */
	struct semid_ds	sds;	/* semaphore data structure */
	struct seminfo seminfo;	/* semaphore information structure */

	/* Go through the options and set flags. */
	while((o = getopt(argc, argv, opts)) != EOF)
		switch(o) {
		case 'a':
			bflg = cflg = oflg = pflg = tflg = 1;
			break;
		case 'b':
			bflg = 1;
			break;
		case 'c':
			cflg = 1;
			break;
		case 'C':
			mem = optarg;
			break;
		case 'm':
			printf("This command does not support Shared Memory.\n");
			mflg = 1;
			break;
		case 'N':
			name = optarg;
			break;
		case 'o':
			oflg = 1;
			break;
		case 'p':
			pflg = 1;
			break;
		case 'q':
			qflg = 1;
			break;
		case 's':
			sflg = 1;
			break;
		case 't':
			tflg = 1;
			break;
		case '?':
			err++;
			break;
		}
	if(err || (optind < argc)) {
		fprintf(stderr,
			"usage:  ipcs [-abcmopqst] [-C corefile] [-N namelist]\n");
		exit(1);
	}
	if((mflg + qflg + sflg) == 0)
		mflg = qflg = sflg = 1;

	/* Check out namelist and memory files. */
	nlist(name, nl);
	if(!nl[TIME].n_value) {
		fprintf(stderr, "ipcs:  no namelist\n");
		exit(1);
	}
	if((md = open(mem, O_RDONLY)) < 0) {
		fprintf(stderr, "ipcs:  no memory file\n");
		exit(1);
	}
	lseeke(md, (long)nl[TIME].n_value, 0);
	reade(md, &Btime, sizeof(Btime));
	time = Btime.tv_sec;
	printf("Time is %x\n", time);
	printf("IPC status from %s as of %s", mem, ctime(&time));

	/* Print Message Queue status report. */
	if(qflg) {
		if(nl[MSG].n_value) {
			i = 0;
			lseeke(md, (long)nl[MSGINFO].n_value, 0);
			reade(md, &msginfo, sizeof(msginfo));
			lseeke(md, (long)nl[MSG].n_value, 0);
			printf("%s%s%s%s%s%s\nMessage Queues:\n", chdr,
				cflg ? chdr2 : "",
				oflg ? " CBYTES  QNUM" : "",
				bflg ? " QBYTES" : "",
				pflg ? " LSPID LRPID" : "",
				tflg ? "   STIME    RTIME    CTIME " : "");
		} else {
			i = msginfo.msgmni;
			printf("Message Queue facility not in system.\n");
		}
		while(i < msginfo.msgmni) {
			reade(md, &qds, sizeof(qds));
			if(!(qds.msg_perm.mode & IPC_ALLOC)) {
				i++;
				continue;
			}
			hp('q', "SRrw-rw-rw-", &qds.msg_perm, i++, msginfo.msgmni);
			if(oflg)
				printf("%7u%6u", qds.msg_cbytes, qds.msg_qnum);
			if(bflg)
				printf("%7u", qds.msg_qbytes);
			if(pflg)
				printf("%6u%6u", qds.msg_lspid, qds.msg_lrpid);
			if(tflg) {
				tp(qds.msg_stime);
				tp(qds.msg_rtime);
				tp(qds.msg_ctime);
			}
			printf("\n");
		}
	}

	/* Print Semaphore facility status. */
	if(sflg) {
		if(nl[SEM].n_value) {
			i = 0;
			lseeke(md, (long)nl[SEMINFO].n_value, 0);
			reade(md, &seminfo, sizeof(seminfo));
			lseeke(md, (long)nl[SEM].n_value, 0);
			if(bflg || tflg || (!qflg || !nl[MSG].n_value))
				printf("%s%s%s%s\n", chdr,
					cflg ? chdr2 : "",
					bflg ? " NSEMS" : "",
					tflg ? "   OTIME    CTIME " : "");
			printf("Semaphores:\n");
		} else {
			i = seminfo.semmni;
			printf("Semaphore facility not in system.\n");
		}
		while(i < seminfo.semmni) {
			reade(md, &sds, sizeof(sds));
			if(!(sds.sem_perm.mode & IPC_ALLOC)) {
				i++;
				continue;
			}
			hp('s', "--ra-ra-ra-", &sds.sem_perm, i++, seminfo.semmni);
			if(bflg)
				printf("%6u", sds.sem_nsems);
			if(tflg) {
				tp(sds.sem_otime);
				tp(sds.sem_ctime);
			}
			printf("\n");
		}
	}
	exit(0);
}

/*
**	lseeke - lseek with error exit
*/

lseeke(f, o, w)
int	f,	/* fd */
	w;	/* whence */
long	o;	/* offset */
{
	o &= 0x3fffffff;
	if(lseek(f, o, w) < 0) {
		perror("ipcs:  seek error");
		exit(1);
	}
}

/*
**	reade - read with error exit
*/

reade(f, b, s)
int	f,	/* fd */
	s;	/* size */
char	*b;	/* buffer address */
{
	if(read(f, b, s) != s) {
		perror("ipcs:  read error");
		exit(1);
	}
}

/*
**	hp - common header print
*/

hp(type, modesp, permp, slot, slots)
char				type,	/* facility type */
				*modesp;/* ptr to mode replacement characters */
register struct ipc_perm	*permp;	/* ptr to permission structure */
int				slot,	/* facility slot number */
				slots;	/* # of facility slots */
{
	register int		i,	/* loop control */
				j;	/* loop control */
	register struct group	*g;	/* ptr to group group entry */
	register struct passwd	*u;	/* ptr to user passwd entry */

	printf("%c%7d%s%#8.8x ", type, slot + slots * permp->seq,
		permp->key ? " " : " 0x", permp->key);
	for(i = 02000;i;modesp++, i >>= 1)
		printf("%c", (permp->mode & i) ? *modesp : '-');
	if((u = getpwuid(permp->uid)) == NULL)
		printf("%9d", permp->uid);
	else
		printf("%9.8s", u->pw_name);
	if((g = getgrgid(permp->gid)) == NULL)
		printf("%9d", permp->gid);
	else
		printf("%9.8s", g->gr_name);
	if(cflg) {
		if((u = getpwuid(permp->cuid)) == NULL)
			printf("%9d", permp->cuid);
		else
			printf("%9.8s", u->pw_name);
		if((g = getgrgid(permp->cgid)) == NULL)
			printf("%9d", permp->cgid);
		else
			printf("%9.8s", g->gr_name);
	}
}

/*
**	tp - time entry printer
*/

tp(time)
time_t	time;	/* time to be displayed */
{
	register struct tm	*t;	/* ptr to converted time */

	if(time) {
		t = localtime(&time);
		printf(" %2d:%2.2d:%2.2d", t->tm_hour, t->tm_min, t->tm_sec);
	} else
		printf(" no-entry");
}

/* <@(#)ipcs.c	1.6> */
