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