#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc_impl.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/hexdump.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <locale.h>
#include <langinfo.h>
#include <string.h>
#include <limits.h>
#include <project.h>
#include <zone.h>
#define USAGE \
"usage: ipcs [-AabciJmopqstZ] [-D mtype] [-z zone]\n"
static char chdr[] = "T ID KEY MODE OWNER GROUP";
static char chdr2[] = " CREATOR CGROUP";
static char chdr3[] = " PROJECT";
static char opts[] = "AabciJmopqstD:z:Z";
static long mtype;
static zoneid_t zoneid;
static int bflg,
cflg,
Dflg,
iflg,
Jflg,
mflg,
oflg,
pflg,
qflg,
sflg,
tflg,
zflg,
Zflg,
err;
static void hp(char, char *, struct ipc_perm64 *, int);
static void jp(struct ipc_perm64 *);
static void tp(ipc_time_t);
static void dumpmsgq(int);
static void dumpmsg(long, char *, size_t);
static zoneid_t getzone(char *);
static void printzone(zoneid_t);
int
main(int argc, char *argv[])
{
static int *ids;
static uint_t nids;
int o;
int id;
int i;
uint_t n;
time_t now;
char tbuf[BUFSIZ];
char *dfmt;
char *endptr;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
(void) memset(tbuf, 0, sizeof (tbuf));
dfmt = nl_langinfo(_DATE_FMT);
zoneid = getzoneid();
while ((o = getopt(argc, argv, opts)) != EOF) {
switch (o) {
case 'A':
bflg = cflg = iflg = oflg = pflg = tflg = Jflg = 1;
break;
case 'a':
bflg = cflg = oflg = pflg = tflg = 1;
break;
case 'b':
bflg = 1;
break;
case 'c':
cflg = 1;
break;
case 'D':
mtype = strtol(optarg, &endptr, 0);
if (endptr == optarg || *endptr != '\0') {
(void) fprintf(stderr,
gettext("ipcs: invalid message type: %s\n"),
optarg);
err++;
break;
}
Dflg = 1;
break;
case 'i':
iflg = 1;
break;
case 'J':
Jflg = 1;
break;
case 'm':
mflg = 1;
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 'z':
zflg = 1;
zoneid = getzone(optarg);
break;
case 'Z':
Zflg = 1;
break;
case '?':
err++;
break;
}
}
if (err || (optind < argc)) {
(void) fprintf(stderr, gettext(USAGE));
exit(1);
}
if ((mflg + qflg + sflg) == 0)
mflg = qflg = sflg = 1;
now = time(NULL);
(void) strftime(tbuf, sizeof (tbuf), dfmt, localtime(&now));
(void) printf(gettext("IPC status from <running system> as of %s\n"),
tbuf);
if (qflg) {
struct msqid_ds64 qds;
for (;;) {
if (msgids(ids, nids, &n) != 0) {
perror("msgids");
exit(1);
}
if (n <= nids)
break;
ids = realloc(ids, (nids = n) * sizeof (int));
}
(void) printf("%s%s%s%s%s%s%s%s\n", chdr,
cflg ? chdr2 : "",
oflg ? " CBYTES QNUM" : "",
bflg ? " QBYTES" : "",
pflg ? " LSPID LRPID" : "",
tflg ? " STIME RTIME CTIME " : "",
Jflg ? chdr3 : "",
Zflg ? " ZONE" : "");
(void) printf(gettext("Message Queues:\n"));
for (i = 0; i < n; i++) {
id = ids[i];
if (msgctl64(id, IPC_STAT64, &qds) < 0)
continue;
if ((zflg || !Zflg) &&
qds.msgx_perm.ipcx_zoneid != zoneid)
continue;
hp('q', "SRrw-rw-rw-", &qds.msgx_perm, id);
if (oflg)
(void) printf(" %6llu %5llu",
qds.msgx_cbytes, qds.msgx_qnum);
if (bflg)
(void) printf(" %6llu", qds.msgx_qbytes);
if (pflg)
(void) printf(" %5d %5d",
(int)qds.msgx_lspid, (int)qds.msgx_lrpid);
if (tflg) {
tp(qds.msgx_stime);
tp(qds.msgx_rtime);
tp(qds.msgx_ctime);
}
if (Jflg)
jp(&qds.msgx_perm);
if (Zflg)
printzone(qds.msgx_perm.ipcx_zoneid);
(void) printf("\n");
if (Dflg)
dumpmsgq(id);
}
}
if (mflg) {
struct shmid_ds64 mds;
for (;;) {
if (shmids(ids, nids, &n) != 0) {
perror("shmids");
exit(1);
}
if (n <= nids)
break;
ids = realloc(ids, (nids = n) * sizeof (int));
}
if (!qflg || oflg || bflg || pflg || tflg || iflg)
(void) printf("%s%s%s%s%s%s%s%s%s\n", chdr,
cflg ? chdr2 : "",
oflg ? " NATTCH" : "",
bflg ? " SEGSZ" : "",
pflg ? " CPID LPID" : "",
tflg ? " ATIME DTIME CTIME " : "",
iflg ? " ISMATTCH" : "",
Jflg ? chdr3 : "",
Zflg ? " ZONE" : "");
(void) printf(gettext("Shared Memory:\n"));
for (i = 0; i < n; i++) {
id = ids[i];
if (shmctl64(id, IPC_STAT64, &mds) < 0)
continue;
if ((zflg || !Zflg) &&
mds.shmx_perm.ipcx_zoneid != zoneid)
continue;
hp('m', "--rw-rw-rw-", &mds.shmx_perm, id);
if (oflg)
(void) printf(" %6llu", mds.shmx_nattch);
if (bflg)
(void) printf(" %10llu", mds.shmx_segsz);
if (pflg)
(void) printf(" %5d %5d",
(int)mds.shmx_cpid, (int)mds.shmx_lpid);
if (tflg) {
tp(mds.shmx_atime);
tp(mds.shmx_dtime);
tp(mds.shmx_ctime);
}
if (iflg)
(void) printf(" %8llu", mds.shmx_cnattch);
if (Jflg)
jp(&mds.shmx_perm);
if (Zflg)
printzone(mds.shmx_perm.ipcx_zoneid);
(void) printf("\n");
}
}
if (sflg) {
struct semid_ds64 sds;
union semun {
int val;
struct semid_ds64 *buf;
ushort_t *array;
} semarg;
semarg.buf = &sds;
for (;;) {
if (semids(ids, nids, &n) != 0) {
perror("semids");
exit(1);
}
if (n <= nids)
break;
ids = realloc(ids, (nids = n) * sizeof (int));
}
if (bflg || tflg || (!qflg && !mflg))
(void) printf("%s%s%s%s%s%s\n", chdr,
cflg ? chdr2 : "",
bflg ? " NSEMS" : "",
tflg ? " OTIME CTIME " : "",
Jflg ? chdr3 : "",
Zflg ? " ZONE" : "");
(void) printf(gettext("Semaphores:\n"));
for (i = 0; i < n; i++) {
id = ids[i];
if (semctl64(id, 0, IPC_STAT64, semarg) < 0)
continue;
if ((zflg || !Zflg) &&
sds.semx_perm.ipcx_zoneid != zoneid)
continue;
hp('s', "--ra-ra-ra-", &sds.semx_perm, id);
if (bflg)
(void) printf(" %5u", sds.semx_nsems);
if (tflg) {
tp(sds.semx_otime);
tp(sds.semx_ctime);
}
if (Jflg)
jp(&sds.semx_perm);
if (Zflg)
printzone(sds.semx_perm.ipcx_zoneid);
(void) printf("\n");
}
}
return (0);
}
static void
hp(char type, char *modesp, struct ipc_perm64 *permp, int slot)
{
int i;
struct group *g;
struct passwd *u;
char keyfield[16];
(void) snprintf(keyfield, sizeof (keyfield), " 0x%x", permp->ipcx_key);
(void) printf("%c %10d %-13s", type, slot, keyfield);
for (i = 02000; i; modesp++, i >>= 1)
(void) printf("%c", (permp->ipcx_mode & i) ? *modesp : '-');
if ((u = getpwuid(permp->ipcx_uid)) == NULL)
(void) printf("%9d", (int)permp->ipcx_uid);
else
(void) printf("%9.8s", u->pw_name);
if ((g = getgrgid(permp->ipcx_gid)) == NULL)
(void) printf("%9d", (int)permp->ipcx_gid);
else
(void) printf("%9.8s", g->gr_name);
if (cflg) {
if ((u = getpwuid(permp->ipcx_cuid)) == NULL)
(void) printf("%9d", (int)permp->ipcx_cuid);
else
(void) printf("%9.8s", u->pw_name);
if ((g = getgrgid(permp->ipcx_cgid)) == NULL)
(void) printf("%9d", (int)permp->ipcx_cgid);
else
(void) printf("%9.8s", g->gr_name);
}
}
static void
jp(struct ipc_perm64 *permp)
{
struct project proj;
char buf[PROJECT_BUFSZ];
if ((getprojbyid(permp->ipcx_projid, &proj, buf,
PROJECT_BUFSZ)) == NULL)
(void) printf("%16ld", permp->ipcx_projid);
else
(void) printf("%16.15s", proj.pj_name);
}
void
tp(ipc_time_t gmt64)
{
struct tm *t;
time_t gmt = (time_t)gmt64;
if (gmt && gmt64 <= UINT_MAX) {
t = localtime(&gmt);
(void) printf(" %2d:%2.2d:%2.2d",
t->tm_hour, t->tm_min, t->tm_sec);
} else {
(void) printf("%9s", gettext(" no-entry"));
}
}
#define SZROUND(x) (((x) + sizeof (size_t) - 1) & ~(sizeof (size_t) - 1))
void
dumpmsgq(int msqid)
{
static struct msgsnap_head *buf = NULL;
static size_t bufsize;
struct msgsnap_mhead *mhead;
size_t i;
if (buf == NULL)
buf = malloc(bufsize = sizeof (struct msgsnap_head));
for (;;) {
if (msgsnap(msqid, buf, bufsize, mtype) != 0) {
return;
}
if (bufsize >= buf->msgsnap_size) {
break;
}
buf = realloc(buf, bufsize = buf->msgsnap_size);
}
mhead = (struct msgsnap_mhead *)(buf + 1);
for (i = 0; i < buf->msgsnap_nmsg; i++) {
size_t mlen = mhead->msgsnap_mlen;
dumpmsg(mhead->msgsnap_mtype, (char *)(mhead + 1), mlen);
mhead = (struct msgsnap_mhead *)
((caddr_t)(mhead + 1) + SZROUND(mlen));
}
}
void
dumpmsg(long type, char *msg, size_t msgsize)
{
const uint8_t *data = (const uint8_t *)msg;
hexdump_t h;
(void) printf(gettext(" message type %ld, size %lu\n"),
type, (ulong_t)msgsize);
hexdump_init(&h);
hexdump_set_indent(&h, 4);
(void) hexdump_fileh(&h, data, msgsize, HDF_DEFAULT, stdout);
hexdump_fini(&h);
}
static zoneid_t
getzone(char *arg)
{
zoneid_t zoneid;
if (zone_get_id(arg, &zoneid) != 0) {
(void) fprintf(stderr,
gettext("ipcs: unknown zone: %s\n"), arg);
exit(1);
}
return (zoneid);
}
static void
printzone(zoneid_t id)
{
char zone_name[ZONENAME_MAX];
if (getzonenamebyid(id, zone_name, sizeof (zone_name)) < 0)
(void) printf("%9d", (int)id);
else
(void) printf("%9.8s", zone_name);
}