/* Copyright (c) 1984 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ /* #ident "@(#)ipc:/ipcs.c 1.9" */ #ident "$Revision: 1.25 $" /* ** ipcs - IPC status ** Examine and print certain things about message queues, semaphores, ** and shared memory. */ #include "sys/types.h" #include "sys/ipc.h" #include "sys/msg.h" #include "sys/sem.h" #include "sys/shm.h" #include #include "errno.h" #include "nlist.h" #include "fcntl.h" #include "time.h" #include "grp.h" #include "pwd.h" #include "getopt.h" #include "stdio.h" #include "stdlib.h" #include "sys/sysmp.h" #include "sys/sysget.h" #include "sys.s" extern int syscall(int, ...); #define MSG 0 #define MSGINFO 2 void hp(char, char *, struct ipc_perm *, int, int); void tp(time_t); static void lseeke(int, off_t, int); static void reade(int fildes, void *buf, size_t nbyte); void print_shmstat(void); void print_semstat(void); #if (_MIPS_SZLONG == 64) #define NLIST nlist64 #else #define NLIST nlist #endif /* if 64bit */ struct NLIST nl[] = { /* name list entries for IPC facilities */ {"msgque", 0, 0, 0}, {"msginfo", 0, 0, 0}, {NULL} }; char chdr[] = "T ID KEY MODE OWNER GROUP", /* common header format */ chdr2[] = " CREATOR CGROUP", /* c option header format */ *name = "/unix", /* name list file */ *mem = "/dev/kmem", /* memory file */ opts[] = "abcemopqstC: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 */ eflg, /* shared memory extentions */ 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 */ int Nflg; /* specified -N */ main( int argc, /* arg count */ char **argv) /* arg vector */ { register int i, /* loop control */ md, /* memory file file descriptor */ o; /* option flag */ time_t curtime;/* date in memory file */ struct msqid_ds *qds; /* message queue data structure */ struct msginfo msginfo; /* message information structure */ struct msqid_ds *qp; sgt_cookie_t ck; /* 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 'e': eflg = 1; break; case 'm': mflg = 1; break; case 'N': name = optarg; Nflg++; 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 [-abcemopqst] [-C corefile] [-N namelist]\n"); exit(1); } if((mflg + qflg + sflg) == 0) mflg = qflg = sflg = 1; /* Check out namelist and memory files. */ if (Nflg) { NLIST(name, nl); if(!nl[MSG].n_value) { fprintf(stderr, "ipcs: no namelist\n"); exit(1); } } if(Nflg && ((md = open(mem, O_RDONLY)) < 0)) { fprintf(stderr, "ipcs: no memory file\n"); exit(1); } if (Nflg && (qflg || sflg)) { /* msgque is a struct msqid_ds **, so we have * to step through the indirection. But only if * Nflg is set - otherwise sysmp returns the * correct value. */ lseeke(md, nl[MSG].n_value, 0); reade(md, &nl[MSG].n_value, sizeof(nl[MSG].n_value)); } curtime = time(NULL); printf("IPC status from %s as of %s", mem, ctime(&curtime)); /* Print Message Queue status report. */ if(qflg) { if (Nflg) { lseeke(md, (long)nl[MSGINFO].n_value, 0); reade(md, &msginfo, sizeof(msginfo)); lseeke(md, (long)nl[MSG].n_value, 0); } else { SGT_COOKIE_INIT(&ck); SGT_COOKIE_SET_KSYM(&ck, KSYM_MSGINFO); if (sysget(SGT_KSYM, (char *)&msginfo, sizeof(msginfo), SGT_READ, &ck) < 0) { perror("SGT_READ msginfo"); exit(1); } } 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 " : ""); qds = (struct msqid_ds *)calloc(msginfo.msgmni, sizeof(struct msqid_ds)); if (!qds) { fprintf(stderr, "no memory for message queue\n"); exit(1); } if (!Nflg) { SGT_COOKIE_INIT(&ck); if (sysget(SGT_MSGQUEUE, (char *)qds, msginfo.msgmni * sizeof(struct msqid_ds), SGT_READ, &ck) < 0) { perror("SGT_READ msgqueue"); exit(1); } } for (i = 0; i < msginfo.msgmni; i++) { if (Nflg) { lseeke(md, (long)nl[MSG].n_value + (i*sizeof(int *)), 0); reade(md, &qp, sizeof(qp)); if (qp == NULL) { continue; } lseeke(md, (off_t)qp, 0); reade(md, &qds[i], sizeof(struct msqid_ds)); } if(!(qds[i].msg_perm.mode & IPC_ALLOC)) { continue; } hp('q', "SRrw-rw-rw-", &qds[i].msg_perm, i, msginfo.msgmni); if(oflg) printf("%7u%6u", qds[i].msg_cbytes, qds[i].msg_qnum); if(bflg) printf("%7u", qds[i].msg_qbytes); if(pflg) printf("%6u%6u", qds[i].msg_lspid, qds[i].msg_lrpid); if(tflg) { tp(qds[i].msg_stime); tp(qds[i].msg_rtime); tp(qds[i].msg_ctime); } printf("\n"); } } /* Print Shared Memory status report. */ if (mflg) print_shmstat(); /* Print Semaphore facility status. */ if (sflg) print_semstat(); exit(0); /* NOTREACHED */ } extern int __semstatus(struct semstat *); void print_semstat(void) { struct semstat semstat; int rv; if (bflg || tflg || !qflg && !mflg) printf("%s%s%s%s\n", chdr, cflg ? chdr2 : "", bflg ? " NSEMS" : "", tflg ? " OTIME CTIME " : ""); printf("Semaphores:\n"); semstat.sm_id = 0; semstat.sm_location = -1LL; while (((rv = __semstatus(&semstat)) == 0) || (errno == EACCES)) { struct semid_ds *semds; if (!rv && (errno == EACCES)) continue; semds = &semstat.sm_semds; hp('s', "--ra-ra-ra-", &semds->sem_perm, semstat.sm_id, 0); if(bflg) printf("%6u", semds->sem_nsems); if(tflg) { tp(semds->sem_otime); tp(semds->sem_ctime); } printf("\n"); } } extern int __shmstatus(struct shmstat *); void print_shmstat(void) { struct shmstat shmstat; int rv; if (oflg || bflg || tflg || !qflg || eflg) printf("%s%s%s%s%s%s%s\n", chdr, cflg ? chdr2 : "", oflg ? " NATTCH " : "", bflg ? " SEGSZ " : "", pflg ? " CPID LPID" : "", tflg ? " ATIME DTIME CTIME " : "", eflg ? " EXTENSIONS" : ""); printf("Shared Memory:\n"); shmstat.sh_id = 0; shmstat.sh_location = -1LL; while (((rv = __shmstatus(&shmstat)) == 0) || (errno == EACCES)) { struct shmid_ds *shmds; shmds = &shmstat.sh_shmds; if (!rv && (errno == EACCES)) { if (shmds->shm_cpid == NOPID) continue; /* Special case: We created this segments, but we didn't give ourselves read access. MP_SHMSTAT fills in just the cpid/cgid/cuid fields. We'll overwrite the uid and gid fields with cuid/cgid just to make it more obvious who should do something about this situation. */ shmds->shm_perm.uid = shmds->shm_perm.cuid; shmds->shm_perm.gid = shmds->shm_perm.cgid; } hp('m', "DCrw-rw-rw-", &shmds->shm_perm, shmstat.sh_id, 0); if(oflg) printf("%7u ", shmds->shm_nattch); if(bflg) printf("%9ld ", shmds->shm_segsz); if(pflg) printf("%6u%6u", shmds->shm_cpid, shmds->shm_lpid); if(tflg) { tp(shmds->shm_atime); tp(shmds->shm_dtime); tp(shmds->shm_ctime); } if (eflg) { printf(" %c", shmds->shm_perm.mode & IPC_AUTORMID ? 'A' : ' '); } printf("\n"); } } /* ** lseeke - lseek with error exit */ static void lseeke( int fd, off_t offset, int whence) { #if _MIPS_SZPTR == 64 offset &= 0x7fffffffffffffff; #else offset &= 0x7fffffff; #endif if (lseek(fd, offset, whence) == -1) { perror("ipcs: seek error"); exit(1); } } /* ** reade - read with error exit */ static void reade( int fd, void *bufaddr, size_t size) { if (read(fd, bufaddr, size) != size) { perror("ipcs: read error"); exit(1); } } /* ** hp - common header print */ void hp( char type, /* facility type */ char *modesp,/* ptr to mode replacement characters */ struct ipc_perm *permp, /* ptr to permission structure */ int slot, /* facility slot number */ int 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%11d%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 */ void tp( 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"); }