xref: /openbsd-src/usr.bin/ipcs/ipcs.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: ipcs.c,v 1.15 2001/08/13 15:10:21 millert Exp $	*/
2 /*	$NetBSD: ipcs.c,v 1.10.6.1 1996/06/07 01:53:47 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/proc.h>
35 #define _KERNEL
36 #include <sys/ipc.h>
37 #include <sys/sem.h>
38 #include <sys/shm.h>
39 #include <sys/msg.h>
40 #undef _KERNEL
41 
42 #include <err.h>
43 #include <fcntl.h>
44 #include <kvm.h>
45 #include <pwd.h>
46 #include <grp.h>
47 #include <limits.h>
48 #include <nlist.h>
49 #include <paths.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 
55 void	usage __P((void));
56 
57 extern	char *__progname;		/* from crt0.o */
58 
59 static struct nlist symbols[] = {
60 	{"_sema"},
61 #define X_SEMA		0
62 	{"_seminfo"},
63 #define X_SEMINFO	1
64 	{"_semu"},
65 #define X_SEMU		2
66 	{"_msginfo"},
67 #define X_MSGINFO	3
68 	{"_msqids"},
69 #define X_MSQIDS	4
70 	{"_shminfo"},
71 #define X_SHMINFO	5
72 	{"_shmsegs"},
73 #define X_SHMSEGS	6
74 	{NULL}
75 };
76 
77 static kvm_t *kd;
78 
79 char   *
80 fmt_perm(mode)
81 	u_short mode;
82 {
83 	static char buffer[100];
84 
85 	buffer[0] = '-';
86 	buffer[1] = '-';
87 	buffer[2] = ((mode & 0400) ? 'r' : '-');
88 	buffer[3] = ((mode & 0200) ? 'w' : '-');
89 	buffer[4] = ((mode & 0100) ? 'a' : '-');
90 	buffer[5] = ((mode & 0040) ? 'r' : '-');
91 	buffer[6] = ((mode & 0020) ? 'w' : '-');
92 	buffer[7] = ((mode & 0010) ? 'a' : '-');
93 	buffer[8] = ((mode & 0004) ? 'r' : '-');
94 	buffer[9] = ((mode & 0002) ? 'w' : '-');
95 	buffer[10] = ((mode & 0001) ? 'a' : '-');
96 	buffer[11] = '\0';
97 	return (&buffer[0]);
98 }
99 
100 void
101 cvt_time(t, buf)
102 	time_t  t;
103 	char   *buf;
104 {
105 	struct tm *tm;
106 
107 	if (t == 0) {
108 		strcpy(buf, "no-entry");
109 	} else {
110 		tm = localtime(&t);
111 		sprintf(buf, "%2d:%02d:%02d",
112 			tm->tm_hour, tm->tm_min, tm->tm_sec);
113 	}
114 }
115 #define	SHMINFO		1
116 #define	SHMTOTAL	2
117 #define	MSGINFO		4
118 #define	MSGTOTAL	8
119 #define	SEMINFO		16
120 #define	SEMTOTAL	32
121 
122 #define BIGGEST		1
123 #define CREATOR		2
124 #define OUTSTANDING	4
125 #define PID		8
126 #define TIME		16
127 
128 int
129 main(argc, argv)
130 	int     argc;
131 	char   *argv[];
132 {
133 	struct  semid_ds *sema;
134 	struct  seminfo seminfo;
135 	int     semu;
136 	struct  msginfo msginfo;
137 	struct  msqid_ds *msqids;
138 	struct  shminfo shminfo;
139 	struct  shmid_ds *shmsegs;
140 	int     display = SHMINFO | MSGINFO | SEMINFO;
141 	int     option = 0;
142 	char   *core = NULL, *namelist = NULL;
143 	int     i;
144 
145 	while ((i = getopt(argc, argv, "MmQqSsabC:cN:optT")) != -1)
146 		switch (i) {
147 		case 'M':
148 			display = SHMTOTAL;
149 			break;
150 		case 'm':
151 			display = SHMINFO;
152 			break;
153 		case 'Q':
154 			display = MSGTOTAL;
155 			break;
156 		case 'q':
157 			display = MSGINFO;
158 			break;
159 		case 'S':
160 			display = SEMTOTAL;
161 			break;
162 		case 's':
163 			display = SEMINFO;
164 			break;
165 		case 'T':
166 			display = SHMTOTAL | MSGTOTAL | SEMTOTAL;
167 			break;
168 		case 'a':
169 			option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME;
170 			break;
171 		case 'b':
172 			option |= BIGGEST;
173 			break;
174 		case 'C':
175 			core = optarg;
176 			break;
177 		case 'c':
178 			option |= CREATOR;
179 			break;
180 		case 'N':
181 			namelist = optarg;
182 			break;
183 		case 'o':
184 			option |= OUTSTANDING;
185 			break;
186 		case 'p':
187 			option |= PID;
188 			break;
189 		case 't':
190 			option |= TIME;
191 			break;
192 		default:
193 			usage();
194 		}
195 	/*
196 	 * Discard setgid privileges if not the running kernel so that bad
197 	 * guys can't print interesting stuff from kernel memory.
198 	 */
199 	if (namelist != NULL || core != NULL) {
200 		setegid(getgid());
201 		setgid(getgid());
202 	}
203 	if ((kd = kvm_open(namelist, core, NULL, O_RDONLY, "ipcs")) == NULL)
204 		exit(1);
205 
206 	setegid(getgid());
207 	setgid(getgid());
208 
209 	switch (kvm_nlist(kd, symbols)) {
210 	case 0:
211 		break;
212 	case -1:
213 		errx(1, "unable to read kernel symbol table.");
214 	default:
215 #ifdef notdef		/* they'll be told more civilly later */
216 		warnx("nlist failed");
217 		for (i = 0; symbols[i].n_name != NULL; i++)
218 			if (symbols[i].n_value == 0)
219 				warnx("symbol %s not found",
220 				    symbols[i].n_name);
221 		break;
222 #endif
223 	}
224 
225 	if ((display & (MSGINFO | MSGTOTAL)) &&
226 	    (kvm_read(kd, symbols[X_MSGINFO].n_value,
227 	     &msginfo, sizeof(msginfo)) == sizeof(msginfo))) {
228 
229 		if (display & MSGTOTAL) {
230 			printf("msginfo:\n");
231 			printf("\tmsgmax: %6d\t(max characters in a message)\n",
232 			    msginfo.msgmax);
233 			printf("\tmsgmni: %6d\t(# of message queues)\n",
234 			    msginfo.msgmni);
235 			printf("\tmsgmnb: %6d\t(max characters in a message queue)\n",
236 			    msginfo.msgmnb);
237 			printf("\tmsgtql: %6d\t(max # of messages in system)\n",
238 			    msginfo.msgtql);
239 			printf("\tmsgssz: %6d\t(size of a message segment)\n",
240 			    msginfo.msgssz);
241 			printf("\tmsgseg: %6d\t(# of message segments in system)\n\n",
242 			    msginfo.msgseg);
243 		}
244 		if (display & MSGINFO) {
245 			struct msqid_ds *xmsqids;
246 
247 			if (kvm_read(kd, symbols[X_MSQIDS].n_value,
248 			    &msqids, sizeof(msqids)) != sizeof(msqids))
249 				errx(1, "kvm_read (%s): %s",
250 				    symbols[X_MSQIDS].n_name, kvm_geterr(kd));
251 
252 			xmsqids = malloc(sizeof(struct msqid_ds) *
253 			    msginfo.msgmni);
254 
255 			if (kvm_read(kd, (u_long)msqids, xmsqids,
256 			    sizeof(struct msqid_ds) * msginfo.msgmni) !=
257 			    sizeof(struct msqid_ds) * msginfo.msgmni)
258 				errx(1, "kvm_read (msqids): %s",
259 				    kvm_geterr(kd));
260 
261 			printf("Message Queues:\n");
262 			printf("T     ID     KEY        MODE       OWNER    GROUP");
263 			if (option & CREATOR)
264 				printf("  CREATOR   CGROUP");
265 			if (option & OUTSTANDING)
266 				printf(" CBYTES  QNUM");
267 			if (option & BIGGEST)
268 				printf(" QBYTES");
269 			if (option & PID)
270 				printf(" LSPID LRPID");
271 			if (option & TIME)
272 				printf("   STIME    RTIME    CTIME");
273 			printf("\n");
274 			for (i = 0; i < msginfo.msgmni; i += 1) {
275 				if (xmsqids[i].msg_qbytes != 0) {
276 					char    stime_buf[100], rtime_buf[100],
277 					        ctime_buf[100];
278 					struct msqid_ds *msqptr = &xmsqids[i];
279 
280 					cvt_time(msqptr->msg_stime, stime_buf);
281 					cvt_time(msqptr->msg_rtime, rtime_buf);
282 					cvt_time(msqptr->msg_ctime, ctime_buf);
283 
284 					printf("q %6d %10ld %s %8s %8s",
285 					    IXSEQ_TO_IPCID(i, msqptr->msg_perm),
286 					    msqptr->msg_perm.key,
287 					    fmt_perm(msqptr->msg_perm.mode),
288 					    user_from_uid(msqptr->msg_perm.uid, 0),
289 					    group_from_gid(msqptr->msg_perm.gid, 0));
290 
291 					if (option & CREATOR)
292 						printf(" %8s %8s",
293 						    user_from_uid(msqptr->msg_perm.cuid, 0),
294 						    group_from_gid(msqptr->msg_perm.cgid, 0));
295 
296 					if (option & OUTSTANDING)
297 						printf(" %6lu %6lu",
298 						    msqptr->msg_cbytes,
299 						    msqptr->msg_qnum);
300 
301 					if (option & BIGGEST)
302 						printf(" %6lu",
303 						    msqptr->msg_qbytes);
304 
305 					if (option & PID)
306 						printf(" %6d %6d",
307 						    msqptr->msg_lspid,
308 						    msqptr->msg_lrpid);
309 
310 					if (option & TIME)
311 						printf(" %s %s %s",
312 						    stime_buf,
313 						    rtime_buf,
314 						    ctime_buf);
315 
316 					printf("\n");
317 				}
318 			}
319 			printf("\n");
320 		}
321 	} else
322 		if (display & (MSGINFO | MSGTOTAL)) {
323 			fprintf(stderr,
324 			    "SVID messages facility not configured in the system\n");
325 		}
326 	if ((display & (SHMINFO | SHMTOTAL)) &&
327 	    (kvm_read(kd, symbols[X_SHMINFO].n_value, &shminfo,
328 	     sizeof(shminfo)) == sizeof(shminfo))) {
329 
330 		if (display & SHMTOTAL) {
331 			printf("shminfo:\n");
332 			printf("\tshmmax: %7d\t(max shared memory segment size)\n",
333 			    shminfo.shmmax);
334 			printf("\tshmmin: %7d\t(min shared memory segment size)\n",
335 			    shminfo.shmmin);
336 			printf("\tshmmni: %7d\t(max number of shared memory identifiers)\n",
337 			    shminfo.shmmni);
338 			printf("\tshmseg: %7d\t(max shared memory segments per process)\n",
339 			    shminfo.shmseg);
340 			printf("\tshmall: %7d\t(max amount of shared memory in pages)\n\n",
341 			    shminfo.shmall);
342 		}
343 		if (display & SHMINFO) {
344 			struct shmid_ds *xshmids;
345 
346 			if (kvm_read(kd, symbols[X_SHMSEGS].n_value, &shmsegs,
347 			    sizeof(shmsegs)) != sizeof(shmsegs))
348 				errx(1, "kvm_read (%s): %s",
349 				    symbols[X_SHMSEGS].n_name, kvm_geterr(kd));
350 
351 			xshmids = malloc(sizeof(struct shmid_ds) *
352 			    shminfo.shmmni);
353 
354 			if (kvm_read(kd, (u_long)shmsegs, xshmids,
355 			    sizeof(struct shmid_ds) * shminfo.shmmni) !=
356 			    sizeof(struct shmid_ds) * shminfo.shmmni)
357 				errx(1, "kvm_read (shmsegs): %s",
358 				    kvm_geterr(kd));
359 
360 			printf("Shared Memory:\n");
361 			printf("T     ID     KEY        MODE       OWNER    GROUP");
362 			if (option & CREATOR)
363 				printf("  CREATOR   CGROUP");
364 			if (option & OUTSTANDING)
365 				printf(" NATTCH");
366 			if (option & BIGGEST)
367 				printf("  SEGSZ");
368 			if (option & PID)
369 				printf("  CPID  LPID");
370 			if (option & TIME)
371 				printf("   ATIME    DTIME    CTIME");
372 			printf("\n");
373 			for (i = 0; i < shminfo.shmmni; i += 1) {
374 				if (xshmids[i].shm_perm.mode & 0x0800) {
375 					char    atime_buf[100], dtime_buf[100],
376 					        ctime_buf[100];
377 					struct shmid_ds *shmptr = &xshmids[i];
378 
379 					cvt_time(shmptr->shm_atime, atime_buf);
380 					cvt_time(shmptr->shm_dtime, dtime_buf);
381 					cvt_time(shmptr->shm_ctime, ctime_buf);
382 
383 					printf("m %6d %10ld %s %8s %8s",
384 					    IXSEQ_TO_IPCID(i, shmptr->shm_perm),
385 					    shmptr->shm_perm.key,
386 					    fmt_perm(shmptr->shm_perm.mode),
387 					    user_from_uid(shmptr->shm_perm.uid, 0),
388 					    group_from_gid(shmptr->shm_perm.gid, 0));
389 
390 					if (option & CREATOR)
391 						printf(" %8s %8s",
392 						    user_from_uid(shmptr->shm_perm.cuid, 0),
393 						    group_from_gid(shmptr->shm_perm.cgid, 0));
394 
395 					if (option & OUTSTANDING)
396 						printf(" %6d",
397 						    shmptr->shm_nattch);
398 
399 					if (option & BIGGEST)
400 						printf(" %6d",
401 						    shmptr->shm_segsz);
402 
403 					if (option & PID)
404 						printf(" %6d %6d",
405 						    shmptr->shm_cpid,
406 						    shmptr->shm_lpid);
407 
408 					if (option & TIME)
409 						printf(" %s %s %s",
410 						    atime_buf,
411 						    dtime_buf,
412 						    ctime_buf);
413 
414 					printf("\n");
415 				}
416 			}
417 			printf("\n");
418 		}
419 	} else
420 		if (display & (SHMINFO | SHMTOTAL)) {
421 			fprintf(stderr,
422 			    "SVID shared memory facility not configured in the system\n");
423 		}
424 	if ((display & (SEMINFO | SEMTOTAL)) &&
425 	    (kvm_read(kd, symbols[X_SEMINFO].n_value, &seminfo,
426 	     sizeof(seminfo)) == sizeof(seminfo))) {
427 		struct semid_ds *xsema;
428 
429 		if (display & SEMTOTAL) {
430 			printf("seminfo:\n");
431 			printf("\tsemmni: %6d\t(# of semaphore identifiers)\n",
432 			    seminfo.semmni);
433 			printf("\tsemmns: %6d\t(# of semaphores in system)\n",
434 			    seminfo.semmns);
435 			printf("\tsemmnu: %6d\t(# of undo structures in system)\n",
436 			    seminfo.semmnu);
437 			printf("\tsemmsl: %6d\t(max # of semaphores per id)\n",
438 			    seminfo.semmsl);
439 			printf("\tsemopm: %6d\t(max # of operations per semop call)\n",
440 			    seminfo.semopm);
441 			printf("\tsemume: %6d\t(max # of undo entries per process)\n",
442 			    seminfo.semume);
443 			printf("\tsemusz: %6d\t(size in bytes of undo structure)\n",
444 			    seminfo.semusz);
445 			printf("\tsemvmx: %6d\t(semaphore maximum value)\n",
446 			    seminfo.semvmx);
447 			printf("\tsemaem: %6d\t(adjust on exit max value)\n\n",
448 			    seminfo.semaem);
449 		}
450 		if (display & SEMINFO) {
451 			if (kvm_read(kd, symbols[X_SEMA].n_value, &sema,
452 			    sizeof(sema)) != sizeof(sema))
453 				errx(1, "kvm_read (%s): %s",
454 				    symbols[X_SEMA].n_name, kvm_geterr(kd));
455 
456 			xsema = malloc(sizeof(struct semid_ds) *
457 			    seminfo.semmni);
458 
459 			if (kvm_read(kd, (u_long)sema, xsema,
460 			    sizeof(struct semid_ds) * seminfo.semmni) !=
461 			    sizeof(struct semid_ds) * seminfo.semmni)
462 				errx(1, "kvm_read (sema): %s",
463 				    kvm_geterr(kd));
464 
465 			printf("Semaphores:\n");
466 			printf("T     ID     KEY        MODE       OWNER    GROUP");
467 			if (option & CREATOR)
468 				printf("  CREATOR   CGROUP");
469 			if (option & BIGGEST)
470 				printf(" NSEMS");
471 			if (option & TIME)
472 				printf("   OTIME    CTIME");
473 			printf("\n");
474 			for (i = 0; i < seminfo.semmni; i += 1) {
475 				if ((xsema[i].sem_perm.mode & SEM_ALLOC) != 0) {
476 					char    ctime_buf[100], otime_buf[100];
477 					struct semid_ds *semaptr = &xsema[i];
478 
479 					cvt_time(semaptr->sem_otime, otime_buf);
480 					cvt_time(semaptr->sem_ctime, ctime_buf);
481 
482 					printf("s %6d %10ld %s %8s %8s",
483 					    IXSEQ_TO_IPCID(i, semaptr->sem_perm),
484 					    semaptr->sem_perm.key,
485 					    fmt_perm(semaptr->sem_perm.mode),
486 					    user_from_uid(semaptr->sem_perm.uid, 0),
487 					    group_from_gid(semaptr->sem_perm.gid, 0));
488 
489 					if (option & CREATOR)
490 						printf(" %8s %8s",
491 						    user_from_uid(semaptr->sem_perm.cuid, 0),
492 						    group_from_gid(semaptr->sem_perm.cgid, 0));
493 
494 					if (option & BIGGEST)
495 						printf(" %6d",
496 						    semaptr->sem_nsems);
497 
498 					if (option & TIME)
499 						printf(" %s %s",
500 						    otime_buf,
501 						    ctime_buf);
502 
503 					printf("\n");
504 				}
505 			}
506 
507 			printf("\n");
508 		}
509 	} else
510 		if (display & (SEMINFO | SEMTOTAL)) {
511 			fprintf(stderr, "SVID semaphores facility not configured in the system\n");
512 		}
513 	kvm_close(kd);
514 
515 	exit(0);
516 }
517 
518 void
519 usage()
520 {
521 
522 	fprintf(stderr,
523 	    "usage: %s [-abcmopqst] [-C corefile] [-N namelist]\n",
524 	    __progname);
525 	exit(1);
526 }
527