xref: /freebsd/usr.bin/ipcs/ipcs.c (revision de2fa7b8af9fcb685150e9efd6831ee0d126f00d)
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 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/proc.h>
35 #include <sys/sysctl.h>
36 #define _KERNEL
37 #include <sys/ipc.h>
38 #include <sys/sem.h>
39 #include <sys/shm.h>
40 #include <sys/msg.h>
41 #undef _KERNEL
42 
43 #include <assert.h>
44 #include <err.h>
45 #include <fcntl.h>
46 #include <grp.h>
47 #include <kvm.h>
48 #include <limits.h>
49 #include <nlist.h>
50 #include <paths.h>
51 #include <pwd.h>
52 #include <stddef.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 
58 /* SysCtlGatherStruct structure. */
59 struct scgs_vector {
60 	const char *sysctl;
61 	off_t offset;
62 	size_t size;
63 };
64 
65 int	use_sysctl = 1;
66 struct semid_kernel	*sema;
67 struct seminfo		seminfo;
68 struct msginfo		msginfo;
69 struct msqid_kernel	*msqids;
70 struct shminfo		shminfo;
71 struct shmid_kernel	*shmsegs;
72 
73 char   *fmt_perm(u_short);
74 void	cvt_time(time_t, char *);
75 void	sysctlgatherstruct(void *addr, size_t size, struct scgs_vector *vec);
76 void	kget(int idx, void *addr, size_t size);
77 void	usage(void);
78 uid_t	user2uid(char *username);
79 void	print_kmsqtotal(struct msginfo msginfo);
80 void	print_kmsqheader(int option);
81 void	print_kmsqptr(int i, int option, struct msqid_kernel *kmsqptr);
82 void	print_kshmtotal(struct shminfo shminfo);
83 void	print_kshmheader(int option);
84 void	print_kshmptr(int i, int option, struct shmid_kernel *kshmptr);
85 void	print_ksemtotal(struct seminfo seminfo);
86 void	print_ksemheader(int option);
87 void	print_ksemptr(int i, int option, struct semid_kernel *ksemaptr);
88 
89 static struct nlist symbols[] = {
90 	{"sema"},
91 #define X_SEMA		0
92 	{"seminfo"},
93 #define X_SEMINFO	1
94 	{"msginfo"},
95 #define X_MSGINFO	2
96 	{"msqids"},
97 #define X_MSQIDS	3
98 	{"shminfo"},
99 #define X_SHMINFO	4
100 	{"shmsegs"},
101 #define X_SHMSEGS	5
102 	{NULL}
103 };
104 
105 #define	SHMINFO_XVEC	X(shmmax, sizeof(u_long))			\
106 			X(shmmin, sizeof(u_long))			\
107 			X(shmmni, sizeof(u_long))			\
108 			X(shmseg, sizeof(u_long))			\
109 			X(shmall, sizeof(u_long))
110 
111 #define	SEMINFO_XVEC	X(semmap, sizeof(int))				\
112 			X(semmni, sizeof(int))				\
113 			X(semmns, sizeof(int))				\
114 			X(semmnu, sizeof(int))				\
115 			X(semmsl, sizeof(int))				\
116 			X(semopm, sizeof(int))				\
117 			X(semume, sizeof(int))				\
118 			X(semusz, sizeof(int))				\
119 			X(semvmx, sizeof(int))				\
120 			X(semaem, sizeof(int))
121 
122 #define	MSGINFO_XVEC	X(msgmax, sizeof(int))				\
123 			X(msgmni, sizeof(int))				\
124 			X(msgmnb, sizeof(int))				\
125 			X(msgtql, sizeof(int))				\
126 			X(msgssz, sizeof(int))				\
127 			X(msgseg, sizeof(int))
128 
129 #define	X(a, b)	{ "kern.ipc." #a, offsetof(TYPEC, a), (b) },
130 #define	TYPEC	struct shminfo
131 struct scgs_vector shminfo_scgsv[] = { SHMINFO_XVEC { NULL } };
132 #undef	TYPEC
133 #define	TYPEC	struct seminfo
134 struct scgs_vector seminfo_scgsv[] = { SEMINFO_XVEC { NULL } };
135 #undef	TYPEC
136 #define	TYPEC	struct msginfo
137 struct scgs_vector msginfo_scgsv[] = { MSGINFO_XVEC { NULL } };
138 #undef	TYPEC
139 #undef	X
140 
141 static kvm_t *kd;
142 
143 char   *
144 fmt_perm(u_short mode)
145 {
146 	static char buffer[100];
147 
148 	buffer[0] = '-';
149 	buffer[1] = '-';
150 	buffer[2] = ((mode & 0400) ? 'r' : '-');
151 	buffer[3] = ((mode & 0200) ? 'w' : '-');
152 	buffer[4] = ((mode & 0100) ? 'a' : '-');
153 	buffer[5] = ((mode & 0040) ? 'r' : '-');
154 	buffer[6] = ((mode & 0020) ? 'w' : '-');
155 	buffer[7] = ((mode & 0010) ? 'a' : '-');
156 	buffer[8] = ((mode & 0004) ? 'r' : '-');
157 	buffer[9] = ((mode & 0002) ? 'w' : '-');
158 	buffer[10] = ((mode & 0001) ? 'a' : '-');
159 	buffer[11] = '\0';
160 	return (&buffer[0]);
161 }
162 
163 void
164 cvt_time(time_t t, char *buf)
165 {
166 	struct tm *tm;
167 
168 	if (t == 0) {
169 		strcpy(buf, "no-entry");
170 	} else {
171 		tm = localtime(&t);
172 		sprintf(buf, "%2d:%02d:%02d",
173 			tm->tm_hour, tm->tm_min, tm->tm_sec);
174 	}
175 }
176 #define	SHMINFO		1
177 #define	SHMTOTAL	2
178 #define	MSGINFO		4
179 #define	MSGTOTAL	8
180 #define	SEMINFO		16
181 #define	SEMTOTAL	32
182 
183 #define BIGGEST		1
184 #define CREATOR		2
185 #define OUTSTANDING	4
186 #define PID		8
187 #define TIME		16
188 
189 int
190 main(int argc, char *argv[])
191 {
192 	int     display = SHMINFO | MSGINFO | SEMINFO;
193 	int     option = 0;
194 	char   *core = NULL, *user = NULL, *namelist = NULL;
195 	char	kvmoferr[_POSIX2_LINE_MAX];  /* Error buf for kvm_openfiles. */
196 	int     i;
197 	uid_t   uid = 0;
198 
199 	while ((i = getopt(argc, argv, "MmQqSsabC:cN:optTu:y")) != -1)
200 		switch (i) {
201 		case 'T':
202 			display = SHMTOTAL | MSGTOTAL | SEMTOTAL;
203 			break;
204 		case 'a':
205 			option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME;
206 			break;
207 		case 'b':
208 			option |= BIGGEST;
209 			break;
210 		case 'C':
211 			core = optarg;
212 			break;
213 		case 'c':
214 			option |= CREATOR;
215 			break;
216 		case 'M':
217 			display = SHMTOTAL;
218 			break;
219 		case 'm':
220 			display = SHMINFO;
221 			break;
222 		case 'N':
223 			namelist = optarg;
224 			break;
225 		case 'o':
226 			option |= OUTSTANDING;
227 			break;
228 		case 'p':
229 			option |= PID;
230 			break;
231 		case 'Q':
232 			display = MSGTOTAL;
233 			break;
234 		case 'q':
235 			display = MSGINFO;
236 			break;
237 		case 'S':
238 			display = SEMTOTAL;
239 			break;
240 		case 's':
241 			display = SEMINFO;
242 			break;
243 		case 't':
244 			option |= TIME;
245 			break;
246 		case 'u':
247 			user = optarg;
248 			uid = user2uid(user);
249 			break;
250 		case 'y':
251 			use_sysctl = 0;
252 			break;
253 		default:
254 			usage();
255 		}
256 
257 	/*
258 	 * If paths to the exec file or core file were specified, we
259 	 * aren't operating on the running kernel, so we can't use
260 	 * sysctl.
261 	 */
262 	if (namelist != NULL || core != NULL)
263 		use_sysctl = 0;
264 
265 	if (!use_sysctl) {
266 		kd = kvm_openfiles(namelist, core, NULL, O_RDONLY, kvmoferr);
267 		if (kd == NULL)
268 			errx(1, "kvm_openfiles: %s", kvmoferr);
269 		switch (kvm_nlist(kd, symbols)) {
270 		case 0:
271 			break;
272 		case -1:
273 			errx(1, "unable to read kernel symbol table");
274 		default:
275 			break;
276 		}
277 	}
278 
279 	kget(X_MSGINFO, &msginfo, sizeof(msginfo));
280 	if ((display & (MSGINFO | MSGTOTAL))) {
281 		if (display & MSGTOTAL)
282 			print_kmsqtotal(msginfo);
283 
284 		if (display & MSGINFO) {
285 			struct msqid_kernel *kxmsqids;
286 			size_t kxmsqids_len;
287 
288 			kxmsqids_len =
289 			    sizeof(struct msqid_kernel) * msginfo.msgmni;
290 			kxmsqids = malloc(kxmsqids_len);
291 			kget(X_MSQIDS, kxmsqids, kxmsqids_len);
292 
293 			print_kmsqheader(option);
294 
295 			for (i = 0; i < msginfo.msgmni; i += 1) {
296 				if (kxmsqids[i].u.msg_qbytes != 0) {
297 					if (user &&
298 					    uid != kxmsqids[i].u.msg_perm.uid)
299 						continue;
300 
301 					print_kmsqptr(i, option, &kxmsqids[i]);
302 				}
303 
304 			}
305 
306 			printf("\n");
307 		}
308 	} else
309 		if (display & (MSGINFO | MSGTOTAL)) {
310 			fprintf(stderr,
311 			    "SVID messages facility "
312 			    "not configured in the system\n");
313 		}
314 
315 	kget(X_SHMINFO, &shminfo, sizeof(shminfo));
316 	if ((display & (SHMINFO | SHMTOTAL))) {
317 
318 		if (display & SHMTOTAL)
319 			print_kshmtotal(shminfo);
320 
321 		if (display & SHMINFO) {
322 			struct shmid_kernel *kxshmids;
323 			size_t kxshmids_len;
324 
325 			kxshmids_len =
326 			    sizeof(struct shmid_kernel) * shminfo.shmmni;
327 			kxshmids = malloc(kxshmids_len);
328 			kget(X_SHMSEGS, kxshmids, kxshmids_len);
329 
330 			print_kshmheader(option);
331 
332 			for (i = 0; i < shminfo.shmmni; i += 1) {
333 				if (kxshmids[i].u.shm_perm.mode & 0x0800) {
334 					if (user &&
335 					    uid != kxshmids[i].u.shm_perm.uid)
336 						continue;
337 
338 					print_kshmptr(i, option, &kxshmids[i]);
339 				}
340 			}
341 			printf("\n");
342 		}
343 	} else
344 		if (display & (SHMINFO | SHMTOTAL)) {
345 			fprintf(stderr,
346 			    "SVID shared memory facility "
347 			    "not configured in the system\n");
348 		}
349 
350 	kget(X_SEMINFO, &seminfo, sizeof(seminfo));
351 	if ((display & (SEMINFO | SEMTOTAL))) {
352 		struct semid_kernel *kxsema;
353 		size_t kxsema_len;
354 
355 		if (display & SEMTOTAL)
356 			print_ksemtotal(seminfo);
357 
358 		if (display & SEMINFO) {
359 			kxsema_len =
360 			    sizeof(struct semid_kernel) * seminfo.semmni;
361 			kxsema = malloc(kxsema_len);
362 			kget(X_SEMA, kxsema, kxsema_len);
363 
364 			print_ksemheader(option);
365 
366 			for (i = 0; i < seminfo.semmni; i += 1) {
367 				if ((kxsema[i].u.sem_perm.mode & SEM_ALLOC) != 0) {
368 					if (user &&
369 					    uid != kxsema[i].u.sem_perm.uid)
370 						continue;
371 
372 					print_ksemptr(i, option, &kxsema[i]);
373 
374 				}
375 			}
376 
377 			printf("\n");
378 		}
379 	} else
380 		if (display & (SEMINFO | SEMTOTAL)) {
381 			fprintf(stderr,
382 			    "SVID semaphores facility "
383 			    "not configured in the system\n");
384 		}
385 
386 	if (!use_sysctl)
387 		kvm_close(kd);
388 
389 	exit(0);
390 }
391 
392 void
393 print_kmsqtotal(struct msginfo msginfo)
394 {
395 
396 	printf("msginfo:\n");
397 	printf("\tmsgmax: %12d\t(max characters in a message)\n",
398 	    msginfo.msgmax);
399 	printf("\tmsgmni: %12d\t(# of message queues)\n",
400 	    msginfo.msgmni);
401 	printf("\tmsgmnb: %12d\t(max characters in a message queue)\n",
402 	    msginfo.msgmnb);
403 	printf("\tmsgtql: %12d\t(max # of messages in system)\n",
404 	    msginfo.msgtql);
405 	printf("\tmsgssz: %12d\t(size of a message segment)\n",
406 	    msginfo.msgssz);
407 	printf("\tmsgseg: %12d\t(# of message segments in system)\n\n",
408 	    msginfo.msgseg);
409 }
410 
411 void print_kmsqheader(int option) {
412 
413 	printf("Message Queues:\n");
414 	printf("T %12s %12s %-11s %-8s %-8s",
415 	    "ID", "KEY", "MODE", "OWNER", "GROUP");
416 	if (option & CREATOR)
417 		printf(" %-8s %-8s", "CREATOR", "CGROUP");
418 	if (option & OUTSTANDING)
419 		printf(" %20s %20s", "CBYTES", "QNUM");
420 	if (option & BIGGEST)
421 		printf(" %20s", "QBYTES");
422 	if (option & PID)
423 		printf(" %12s %12s", "LSPID", "LRPID");
424 	if (option & TIME)
425 		printf(" %-8s %-8s %-8s", "STIME", "RTIME", "CTIME");
426 	printf("\n");
427 }
428 
429 void
430 print_kmsqptr(int i, int option, struct msqid_kernel *kmsqptr)
431 {
432 	char    stime_buf[100], rtime_buf[100], ctime_buf[100];
433 
434 	cvt_time(kmsqptr->u.msg_stime, stime_buf);
435 	cvt_time(kmsqptr->u.msg_rtime, rtime_buf);
436 	cvt_time(kmsqptr->u.msg_ctime, ctime_buf);
437 
438 	printf("q %12d %12d %s %8s %8s",
439 	    IXSEQ_TO_IPCID(i, kmsqptr->u.msg_perm),
440 	    (int)kmsqptr->u.msg_perm.key,
441 	    fmt_perm(kmsqptr->u.msg_perm.mode),
442 	    user_from_uid(kmsqptr->u.msg_perm.uid, 0),
443 	    group_from_gid(kmsqptr->u.msg_perm.gid, 0));
444 
445 	if (option & CREATOR)
446 		printf(" %8s %8s",
447 		    user_from_uid(kmsqptr->u.msg_perm.cuid, 0),
448 		    group_from_gid(kmsqptr->u.msg_perm.cgid, 0));
449 
450 	if (option & OUTSTANDING)
451 		printf(" %12lu %12lu",
452 		    kmsqptr->u.msg_cbytes,
453 		    kmsqptr->u.msg_qnum);
454 
455 	if (option & BIGGEST)
456 		printf(" %20lu", kmsqptr->u.msg_qbytes);
457 
458 	if (option & PID)
459 		printf(" %12d %12d",
460 		    kmsqptr->u.msg_lspid,
461 		    kmsqptr->u.msg_lrpid);
462 
463 	if (option & TIME)
464 		printf(" %s %s %s",
465 		    stime_buf,
466 		    rtime_buf,
467 		    ctime_buf);
468 
469 	printf("\n");
470 }
471 
472 void
473 print_kshmtotal(struct shminfo shminfo)
474 {
475 
476 	printf("shminfo:\n");
477 	printf("\tshmmax: %12d\t(max shared memory segment size)\n",
478 	    shminfo.shmmax);
479 	printf("\tshmmin: %12d\t(min shared memory segment size)\n",
480 	    shminfo.shmmin);
481 	printf("\tshmmni: %12d\t(max number of shared memory identifiers)\n",
482 	    shminfo.shmmni);
483 	printf("\tshmseg: %12d\t(max shared memory segments per process)\n",
484 	    shminfo.shmseg);
485 	printf("\tshmall: %12d\t(max amount of shared memory in pages)\n\n",
486 	    shminfo.shmall);
487 }
488 
489 void
490 print_kshmheader(int option)
491 {
492 
493 	printf("Shared Memory:\n");
494 	printf("T %12s %12s %-11s %-8s %-8s",
495 	    "ID", "KEY", "MODE", "OWNER", "GROUP");
496 	if (option & CREATOR)
497 		printf(" %-8s %-8s", "CREATOR", "CGROUP");
498 	if (option & OUTSTANDING)
499 		printf(" %12s", "NATTCH");
500 	if (option & BIGGEST)
501 		printf(" %12s", "SEGSZ");
502 	if (option & PID)
503 		printf(" %12s %12s", "CPID", "LPID");
504 	if (option & TIME)
505 		printf(" %-8s %-8s %-8s", "ATIME", "DTIME", "CTIME");
506 	printf("\n");
507 }
508 
509 void
510 print_kshmptr(int i, int option, struct shmid_kernel *kshmptr)
511 {
512 	char    atime_buf[100], dtime_buf[100], ctime_buf[100];
513 
514 	cvt_time(kshmptr->u.shm_atime, atime_buf);
515 	cvt_time(kshmptr->u.shm_dtime, dtime_buf);
516 	cvt_time(kshmptr->u.shm_ctime, ctime_buf);
517 
518 	printf("m %12d %12d %s %8s %8s",
519 	    IXSEQ_TO_IPCID(i, kshmptr->u.shm_perm),
520 	    (int)kshmptr->u.shm_perm.key,
521 	    fmt_perm(kshmptr->u.shm_perm.mode),
522 	    user_from_uid(kshmptr->u.shm_perm.uid, 0),
523 	    group_from_gid(kshmptr->u.shm_perm.gid, 0));
524 
525 	if (option & CREATOR)
526 		printf(" %8s %8s",
527 		    user_from_uid(kshmptr->u.shm_perm.cuid, 0),
528 		    group_from_gid(kshmptr->u.shm_perm.cgid, 0));
529 
530 	if (option & OUTSTANDING)
531 		printf(" %12d",
532 		    kshmptr->u.shm_nattch);
533 
534 	if (option & BIGGEST)
535 		printf(" %12d",
536 		    kshmptr->u.shm_segsz);
537 
538 	if (option & PID)
539 		printf(" %12d %12d",
540 		    kshmptr->u.shm_cpid,
541 		    kshmptr->u.shm_lpid);
542 
543 	if (option & TIME)
544 		printf(" %s %s %s",
545 		    atime_buf,
546 		    dtime_buf,
547 		    ctime_buf);
548 
549 	printf("\n");
550 }
551 
552 void
553 print_ksemtotal(struct seminfo seminfo)
554 {
555 
556 	printf("seminfo:\n");
557 	printf("\tsemmap: %12d\t(# of entries in semaphore map)\n",
558 	    seminfo.semmap);
559 	printf("\tsemmni: %12d\t(# of semaphore identifiers)\n",
560 	    seminfo.semmni);
561 	printf("\tsemmns: %12d\t(# of semaphores in system)\n",
562 	    seminfo.semmns);
563 	printf("\tsemmnu: %12d\t(# of undo structures in system)\n",
564 	    seminfo.semmnu);
565 	printf("\tsemmsl: %12d\t(max # of semaphores per id)\n",
566 	    seminfo.semmsl);
567 	printf("\tsemopm: %12d\t(max # of operations per semop call)\n",
568 	    seminfo.semopm);
569 	printf("\tsemume: %12d\t(max # of undo entries per process)\n",
570 	    seminfo.semume);
571 	printf("\tsemusz: %12d\t(size in bytes of undo structure)\n",
572 	    seminfo.semusz);
573 	printf("\tsemvmx: %12d\t(semaphore maximum value)\n",
574 	    seminfo.semvmx);
575 	printf("\tsemaem: %12d\t(adjust on exit max value)\n\n",
576 	    seminfo.semaem);
577 }
578 
579 void
580 print_ksemheader(int option) {
581 
582 	printf("Semaphores:\n");
583 	printf("T %12s %12s %-11s %-8s %-8s",
584 	    "ID", "KEY", "MODE", "OWNER", "GROUP");
585 	if (option & CREATOR)
586 		printf(" %-8s %-8s", "CREATOR", "CGROUP");
587 	if (option & BIGGEST)
588 		printf(" %12s", "NSEMS");
589 	if (option & TIME)
590 		printf(" %-8s %-8s", "OTIME", "CTIME");
591 	printf("\n");
592 }
593 
594 void
595 print_ksemptr(int i, int option, struct semid_kernel *ksemaptr)
596 {
597 	char    ctime_buf[100], otime_buf[100];
598 
599 	cvt_time(ksemaptr->u.sem_otime, otime_buf);
600 	cvt_time(ksemaptr->u.sem_ctime, ctime_buf);
601 
602 	printf("s %12d %12d %s %8s %8s",
603 	    IXSEQ_TO_IPCID(i, ksemaptr->u.sem_perm),
604 	    (int)ksemaptr->u.sem_perm.key,
605 	    fmt_perm(ksemaptr->u.sem_perm.mode),
606 	    user_from_uid(ksemaptr->u.sem_perm.uid, 0),
607 	    group_from_gid(ksemaptr->u.sem_perm.gid, 0));
608 
609 	if (option & CREATOR)
610 		printf(" %8s %8s",
611 		    user_from_uid(ksemaptr->u.sem_perm.cuid, 0),
612 		    group_from_gid(ksemaptr->u.sem_perm.cgid, 0));
613 
614 	if (option & BIGGEST)
615 		printf(" %12d",
616 		    ksemaptr->u.sem_nsems);
617 
618 	if (option & TIME)
619 		printf(" %s %s",
620 		    otime_buf,
621 		    ctime_buf);
622 
623 	printf("\n");
624 }
625 
626 void
627 sysctlgatherstruct(void *addr, size_t size, struct scgs_vector *vecarr)
628 {
629 	struct scgs_vector *xp;
630 	size_t tsiz;
631 	int rv;
632 
633 	for (xp = vecarr; xp->sysctl != NULL; xp++) {
634 		assert(xp->offset <= size);
635 		tsiz = xp->size;
636 		rv = sysctlbyname(xp->sysctl, (char *)addr + xp->offset,
637 		    &tsiz, NULL, 0);
638 		if (rv == -1)
639 			err(1, "sysctlbyname: %s", xp->sysctl);
640 		if (tsiz != xp->size)
641 			errx(1, "%s size mismatch (expected %d, got %d)",
642 			    xp->sysctl, xp->size, tsiz);
643 	}
644 }
645 
646 void
647 kget(int idx, void *addr, size_t size)
648 {
649 	char *symn;			/* symbol name */
650 	size_t tsiz;
651 	int rv;
652 	unsigned long kaddr;
653 	const char *sym2sysctl[] = {	/* symbol to sysctl name table */
654 		"kern.ipc.sema",
655 		"kern.ipc.seminfo",
656 		"kern.ipc.msginfo",
657 		"kern.ipc.msqids",
658 		"kern.ipc.shminfo",
659 		"kern.ipc.shmsegs" };
660 
661 	assert((unsigned)idx <= sizeof(sym2sysctl) / sizeof(*sym2sysctl));
662 	if (!use_sysctl) {
663 		symn = symbols[idx].n_name;
664 		if (*symn == '_')
665 			symn++;
666 		if (symbols[idx].n_type == 0 || symbols[idx].n_value == 0)
667 			errx(1, "symbol %s undefined", symn);
668 		/*
669 		 * For some symbols, the value we retrieve is
670 		 * actually a pointer; since we want the actual value,
671 		 * we have to manually dereference it.
672 		 */
673 		switch (idx) {
674 		case X_MSQIDS:
675 			tsiz = sizeof(msqids);
676 			rv = kvm_read(kd, symbols[idx].n_value,
677 			    &msqids, tsiz);
678 			kaddr = (u_long)msqids;
679 			break;
680 		case X_SHMSEGS:
681 			tsiz = sizeof(shmsegs);
682 			rv = kvm_read(kd, symbols[idx].n_value,
683 			    &shmsegs, tsiz);
684 			kaddr = (u_long)shmsegs;
685 			break;
686 		case X_SEMA:
687 			tsiz = sizeof(sema);
688 			rv = kvm_read(kd, symbols[idx].n_value,
689 			    &sema, tsiz);
690 			kaddr = (u_long)sema;
691 			break;
692 		default:
693 			rv = tsiz = 0;
694 			kaddr = symbols[idx].n_value;
695 			break;
696 		}
697 		if ((unsigned)rv != tsiz)
698 			errx(1, "%s: %s", symn, kvm_geterr(kd));
699 		if ((unsigned)kvm_read(kd, kaddr, addr, size) != size)
700 			errx(1, "%s: %s", symn, kvm_geterr(kd));
701 	} else {
702 		switch (idx) {
703 		case X_SHMINFO:
704 			sysctlgatherstruct(addr, size, shminfo_scgsv);
705 			break;
706 		case X_SEMINFO:
707 			sysctlgatherstruct(addr, size, seminfo_scgsv);
708 			break;
709 		case X_MSGINFO:
710 			sysctlgatherstruct(addr, size, msginfo_scgsv);
711 			break;
712 		default:
713 			tsiz = size;
714 			rv = sysctlbyname(sym2sysctl[idx], addr, &tsiz,
715 			    NULL, 0);
716 			if (rv == -1)
717 				err(1, "sysctlbyname: %s", sym2sysctl[idx]);
718 			if (tsiz != size)
719 				errx(1, "%s size mismatch "
720 				    "(expected %d, got %d)",
721 				    sym2sysctl[idx], size, tsiz);
722 			break;
723 		}
724 	}
725 }
726 
727 uid_t
728 user2uid(char *username)
729 {
730 	struct passwd *pwd;
731 	uid_t uid;
732 	char *r;
733 
734 	uid = strtoul(username, &r, 0);
735 	if (!*r && r != username)
736 		return (uid);
737 	if ((pwd = getpwnam(username)) == NULL)
738 		errx(1, "getpwnam failed: No such user");
739 	endpwent();
740 	return (pwd->pw_uid);
741 }
742 
743 void
744 usage(void)
745 {
746 
747 	fprintf(stderr,
748 	    "usage: "
749 	    "ipcs [-abcmopqstyMQST] [-C corefile] [-N namelist] [-u user]\n");
750 	exit(1);
751 }
752