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.7 2004/11/02 19:38:49 liamfoy Exp $ 29 */ 30 31 #define _KERNEL_STRUCTURES 32 33 #include <err.h> 34 #include <fcntl.h> 35 #include <grp.h> 36 #include <kvm.h> 37 #include <nlist.h> 38 #include <paths.h> 39 #include <pwd.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <sys/types.h> 46 #include <sys/param.h> 47 #include <sys/time.h> 48 #include <sys/ipc.h> 49 #include <sys/sem.h> 50 #include <sys/shm.h> 51 #include <sys/msg.h> 52 53 struct semid_ds *sema; 54 struct seminfo seminfo; 55 struct msginfo msginfo; 56 struct msqid_ds *msqids; 57 struct shminfo shminfo; 58 struct shmid_ds *shmsegs; 59 60 static void usage(void); 61 static uid_t user2uid(const char *); 62 static gid_t grp2gid(const char *); 63 64 static struct nlist symbols[] = { 65 {"_sema"}, 66 #define X_SEMA 0 67 {"_seminfo"}, 68 #define X_SEMINFO 1 69 {"_semu"}, 70 #define X_SEMU 2 71 {"_msginfo"}, 72 #define X_MSGINFO 3 73 {"_msqids"}, 74 #define X_MSQIDS 4 75 {"_shminfo"}, 76 #define X_SHMINFO 5 77 {"_shmsegs"}, 78 #define X_SHMSEGS 6 79 {NULL} 80 }; 81 82 static kvm_t *kd; 83 84 char * 85 fmt_perm(u_short mode) 86 { 87 static char buffer[100]; 88 89 buffer[0] = '-'; 90 buffer[1] = '-'; 91 buffer[2] = ((mode & 0400) ? 'r' : '-'); 92 buffer[3] = ((mode & 0200) ? 'w' : '-'); 93 buffer[4] = ((mode & 0100) ? 'a' : '-'); 94 buffer[5] = ((mode & 0040) ? 'r' : '-'); 95 buffer[6] = ((mode & 0020) ? 'w' : '-'); 96 buffer[7] = ((mode & 0010) ? 'a' : '-'); 97 buffer[8] = ((mode & 0004) ? 'r' : '-'); 98 buffer[9] = ((mode & 0002) ? 'w' : '-'); 99 buffer[10] = ((mode & 0001) ? 'a' : '-'); 100 buffer[11] = '\0'; 101 return (&buffer[0]); 102 } 103 104 void 105 cvt_time(time_t t, char *buf) 106 { 107 struct tm *tm; 108 109 if (t == 0) { 110 strcpy(buf, "no-entry"); 111 } else { 112 tm = localtime(&t); 113 sprintf(buf, "%2d:%02d:%02d", 114 tm->tm_hour, tm->tm_min, tm->tm_sec); 115 } 116 } 117 #define SHMINFO 1 118 #define SHMTOTAL 2 119 #define MSGINFO 4 120 #define MSGTOTAL 8 121 #define SEMINFO 16 122 #define SEMTOTAL 32 123 124 #define BIGGEST 1 125 #define CREATOR 2 126 #define OUTSTANDING 4 127 #define PID 8 128 #define TIME 16 129 130 int 131 main(int argc, char **argv) 132 { 133 int display = SHMINFO | MSGINFO | SEMINFO; 134 int option = 0; 135 char *core, *namelist; 136 const char *user, *grp; 137 int i; 138 uid_t useruid; 139 gid_t grpgid; 140 141 core = namelist = NULL; 142 143 while ((i = getopt(argc, argv, "MmQqSsabC:cN:ou:g:ptT")) != -1) 144 switch (i) { 145 case 'M': 146 display = SHMTOTAL; 147 break; 148 case 'm': 149 display = SHMINFO; 150 break; 151 case 'Q': 152 display = MSGTOTAL; 153 break; 154 case 'q': 155 display = MSGINFO; 156 break; 157 case 'S': 158 display = SEMTOTAL; 159 break; 160 case 's': 161 display = SEMINFO; 162 break; 163 case 'T': 164 display = SHMTOTAL | MSGTOTAL | SEMTOTAL; 165 break; 166 case 'a': 167 option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME; 168 break; 169 case 'b': 170 option |= BIGGEST; 171 break; 172 case 'C': 173 core = optarg; 174 break; 175 case 'c': 176 option |= CREATOR; 177 break; 178 case 'N': 179 namelist = optarg; 180 break; 181 case 'o': 182 option |= OUTSTANDING; 183 break; 184 case 'p': 185 option |= PID; 186 break; 187 case 't': 188 option |= TIME; 189 break; 190 case 'u': 191 user = optarg; 192 grp = NULL; 193 useruid = user2uid(optarg); 194 break; 195 case 'g': 196 grp = optarg; 197 user = NULL; 198 grpgid = grp2gid(optarg); 199 break; 200 default: 201 usage(); 202 } 203 204 /* 205 * Discard setgid privileges if not the running kernel so that bad 206 * guys can't print interesting stuff from kernel memory. 207 */ 208 if (namelist != NULL || core != NULL) 209 setgid(getgid()); 210 211 if ((kd = kvm_open(namelist, core, NULL, O_RDONLY, "ipcs")) == NULL) 212 exit(1); 213 214 switch (kvm_nlist(kd, symbols)) { 215 case 0: 216 break; 217 case -1: 218 errx(1, "unable to read kernel symbol table"); 219 default: 220 #ifdef notdef /* they'll be told more civilly later */ 221 warnx("nlist failed"); 222 for (i = 0; symbols[i].n_name != NULL; i++) 223 if (symbols[i].n_value == 0) 224 warnx("symbol %s not found", 225 symbols[i].n_name); 226 #endif 227 break; 228 } 229 230 if ((display & (MSGINFO | MSGTOTAL)) && 231 kvm_read(kd, symbols[X_MSGINFO].n_value, &msginfo, sizeof(msginfo))== sizeof(msginfo)) { 232 233 if (display & MSGTOTAL) { 234 printf("msginfo:\n"); 235 printf("\tmsgmax: %6d\t(max characters in a message)\n", 236 msginfo.msgmax); 237 printf("\tmsgmni: %6d\t(# of message queues)\n", 238 msginfo.msgmni); 239 printf("\tmsgmnb: %6d\t(max characters in a message queue)\n", 240 msginfo.msgmnb); 241 printf("\tmsgtql: %6d\t(max # of messages in system)\n", 242 msginfo.msgtql); 243 printf("\tmsgssz: %6d\t(size of a message segment)\n", 244 msginfo.msgssz); 245 printf("\tmsgseg: %6d\t(# of message segments in system)\n\n", 246 msginfo.msgseg); 247 } 248 if (display & MSGINFO) { 249 struct msqid_ds *xmsqids; 250 251 kvm_read(kd, symbols[X_MSQIDS].n_value, &msqids, sizeof(msqids)); 252 xmsqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni); 253 kvm_read(kd, (u_long) msqids, xmsqids, sizeof(struct msqid_ds) * msginfo.msgmni); 254 255 printf("Message Queues:\n"); 256 printf("T ID KEY MODE OWNER GROUP"); 257 if (option & CREATOR) 258 printf(" CREATOR CGROUP"); 259 if (option & OUTSTANDING) 260 printf(" CBYTES QNUM"); 261 if (option & BIGGEST) 262 printf(" QBYTES"); 263 if (option & PID) 264 printf(" LSPID LRPID"); 265 if (option & TIME) 266 printf(" STIME RTIME CTIME"); 267 printf("\n"); 268 for (i = 0; i < msginfo.msgmni; i += 1) { 269 if (xmsqids[i].msg_qbytes != 0) { 270 char stime_buf[100], rtime_buf[100], 271 ctime_buf[100]; 272 struct msqid_ds *msqptr = &xmsqids[i]; 273 274 if (user && useruid != msqptr->msg_perm.uid) 275 continue; 276 if (grp && grpgid != msqptr->msg_perm.gid) 277 continue; 278 279 cvt_time(msqptr->msg_stime, stime_buf); 280 cvt_time(msqptr->msg_rtime, rtime_buf); 281 cvt_time(msqptr->msg_ctime, ctime_buf); 282 283 printf("q %6d %10d %s %8s %8s", 284 IXSEQ_TO_IPCID(i, msqptr->msg_perm), 285 msqptr->msg_perm.key, 286 fmt_perm(msqptr->msg_perm.mode), 287 user_from_uid(msqptr->msg_perm.uid, 0), 288 group_from_gid(msqptr->msg_perm.gid, 0)); 289 290 if (option & CREATOR) 291 printf(" %8s %8s", 292 user_from_uid(msqptr->msg_perm.cuid, 0), 293 group_from_gid(msqptr->msg_perm.cgid, 0)); 294 295 if (option & OUTSTANDING) 296 printf(" %6d %6d", 297 msqptr->msg_cbytes, 298 msqptr->msg_qnum); 299 300 if (option & BIGGEST) 301 printf(" %6d", 302 msqptr->msg_qbytes); 303 304 if (option & PID) 305 printf(" %6d %6d", 306 msqptr->msg_lspid, 307 msqptr->msg_lrpid); 308 309 if (option & TIME) 310 printf("%s %s %s", 311 stime_buf, 312 rtime_buf, 313 ctime_buf); 314 315 printf("\n"); 316 } 317 } 318 printf("\n"); 319 } 320 } else 321 if (display & (MSGINFO | MSGTOTAL)) { 322 fprintf(stderr, 323 "SVID messages facility not configured in the system\n"); 324 } 325 if ((display & (SHMINFO | SHMTOTAL)) && 326 kvm_read(kd, symbols[X_SHMINFO].n_value, &shminfo, sizeof(shminfo))) { 327 if (display & SHMTOTAL) { 328 printf("shminfo:\n"); 329 printf("\tshmmax: %7d\t(max shared memory segment size)\n", 330 shminfo.shmmax); 331 printf("\tshmmin: %7d\t(min shared memory segment size)\n", 332 shminfo.shmmin); 333 printf("\tshmmni: %7d\t(max number of shared memory identifiers)\n", 334 shminfo.shmmni); 335 printf("\tshmseg: %7d\t(max shared memory segments per process)\n", 336 shminfo.shmseg); 337 printf("\tshmall: %7d\t(max amount of shared memory in pages)\n\n", 338 shminfo.shmall); 339 } 340 if (display & SHMINFO) { 341 struct shmid_ds *xshmids; 342 343 kvm_read(kd, symbols[X_SHMSEGS].n_value, &shmsegs, sizeof(shmsegs)); 344 xshmids = malloc(sizeof(struct shmid_ds) * shminfo.shmmni); 345 kvm_read(kd, (u_long) shmsegs, xshmids, sizeof(struct shmid_ds) * 346 shminfo.shmmni); 347 348 printf("Shared Memory:\n"); 349 printf("T ID KEY MODE OWNER GROUP"); 350 if (option & CREATOR) 351 printf(" CREATOR CGROUP"); 352 if (option & OUTSTANDING) 353 printf(" NATTCH"); 354 if (option & BIGGEST) 355 printf(" SEGSZ"); 356 if (option & PID) 357 printf(" CPID LPID"); 358 if (option & TIME) 359 printf(" ATIME DTIME CTIME"); 360 printf("\n"); 361 for (i = 0; i < shminfo.shmmni; i += 1) { 362 if (xshmids[i].shm_perm.mode & 0x0800) { 363 char atime_buf[100], dtime_buf[100], 364 ctime_buf[100]; 365 struct shmid_ds *shmptr = &xshmids[i]; 366 367 if (user && useruid != shmptr->shm_perm.uid) 368 continue; 369 370 if (grp && grpgid != shmptr->shm_perm.gid) 371 continue; 372 373 cvt_time(shmptr->shm_atime, atime_buf); 374 cvt_time(shmptr->shm_dtime, dtime_buf); 375 cvt_time(shmptr->shm_ctime, ctime_buf); 376 377 printf("m %6d %10d %s %8s %8s", 378 IXSEQ_TO_IPCID(i, shmptr->shm_perm), 379 shmptr->shm_perm.key, 380 fmt_perm(shmptr->shm_perm.mode), 381 user_from_uid(shmptr->shm_perm.uid, 0), 382 group_from_gid(shmptr->shm_perm.gid, 0)); 383 384 if (option & CREATOR) 385 printf(" %8s %8s", 386 user_from_uid(shmptr->shm_perm.cuid, 0), 387 group_from_gid(shmptr->shm_perm.cgid, 0)); 388 389 if (option & OUTSTANDING) 390 printf(" %6d", 391 shmptr->shm_nattch); 392 393 if (option & BIGGEST) 394 printf(" %6d", 395 shmptr->shm_segsz); 396 397 if (option & PID) 398 printf(" %6d %6d", 399 shmptr->shm_cpid, 400 shmptr->shm_lpid); 401 402 if (option & TIME) 403 printf("%s %s %s", 404 atime_buf, 405 dtime_buf, 406 ctime_buf); 407 408 printf("\n"); 409 } 410 } 411 printf("\n"); 412 } 413 } else 414 if (display & (SHMINFO | SHMTOTAL)) { 415 fprintf(stderr, 416 "SVID shared memory facility not configured in the system\n"); 417 } 418 if ((display & (SEMINFO | SEMTOTAL)) && 419 kvm_read(kd, symbols[X_SEMINFO].n_value, &seminfo, sizeof(seminfo))) { 420 struct semid_ds *xsema; 421 422 if (display & SEMTOTAL) { 423 printf("seminfo:\n"); 424 printf("\tsemmap: %6d\t(# of entries in semaphore map)\n", 425 seminfo.semmap); 426 printf("\tsemmni: %6d\t(# of semaphore identifiers)\n", 427 seminfo.semmni); 428 printf("\tsemmns: %6d\t(# of semaphores in system)\n", 429 seminfo.semmns); 430 printf("\tsemmnu: %6d\t(# of undo structures in system)\n", 431 seminfo.semmnu); 432 printf("\tsemmsl: %6d\t(max # of semaphores per id)\n", 433 seminfo.semmsl); 434 printf("\tsemopm: %6d\t(max # of operations per semop call)\n", 435 seminfo.semopm); 436 printf("\tsemume: %6d\t(max # of undo entries per process)\n", 437 seminfo.semume); 438 printf("\tsemusz: %6d\t(size in bytes of undo structure)\n", 439 seminfo.semusz); 440 printf("\tsemvmx: %6d\t(semaphore maximum value)\n", 441 seminfo.semvmx); 442 printf("\tsemaem: %6d\t(adjust on exit max value)\n\n", 443 seminfo.semaem); 444 } 445 if (display & SEMINFO) { 446 kvm_read(kd, symbols[X_SEMA].n_value, &sema, sizeof(sema)); 447 xsema = malloc(sizeof(struct semid_ds) * seminfo.semmni); 448 kvm_read(kd, (u_long) sema, xsema, sizeof(struct semid_ds) * seminfo.semmni); 449 450 printf("Semaphores:\n"); 451 printf("T ID KEY MODE OWNER GROUP"); 452 if (option & CREATOR) 453 printf(" CREATOR CGROUP"); 454 if (option & BIGGEST) 455 printf(" NSEMS"); 456 if (option & TIME) 457 printf(" OTIME CTIME"); 458 printf("\n"); 459 for (i = 0; i < seminfo.semmni; i += 1) { 460 if ((xsema[i].sem_perm.mode & SEM_ALLOC) != 0) { 461 char ctime_buf[100], otime_buf[100]; 462 struct semid_ds *semaptr = &xsema[i]; 463 464 if (user && useruid != semaptr->sem_perm.uid) 465 continue; 466 467 if (grp && grpgid != semaptr->sem_perm.gid) 468 continue; 469 470 cvt_time(semaptr->sem_otime, otime_buf); 471 cvt_time(semaptr->sem_ctime, ctime_buf); 472 473 printf("s %6d %10d %s %8s %8s", 474 IXSEQ_TO_IPCID(i, semaptr->sem_perm), 475 semaptr->sem_perm.key, 476 fmt_perm(semaptr->sem_perm.mode), 477 user_from_uid(semaptr->sem_perm.uid, 0), 478 group_from_gid(semaptr->sem_perm.gid, 0)); 479 480 if (option & CREATOR) 481 printf(" %8s %8s", 482 user_from_uid(semaptr->sem_perm.cuid, 0), 483 group_from_gid(semaptr->sem_perm.cgid, 0)); 484 485 if (option & BIGGEST) 486 printf(" %6d", 487 semaptr->sem_nsems); 488 489 if (option & TIME) 490 printf("%s %s", 491 otime_buf, 492 ctime_buf); 493 494 printf("\n"); 495 } 496 } 497 498 printf("\n"); 499 } 500 } else 501 if (display & (SEMINFO | SEMTOTAL)) { 502 fprintf(stderr, "SVID semaphores facility not configured in the system\n"); 503 } 504 kvm_close(kd); 505 506 exit(0); 507 } 508 509 static uid_t 510 user2uid(const char *username) 511 { 512 struct passwd *pwd; 513 uid_t uid; 514 char *r; 515 516 uid = strtoul(username, &r, 0); 517 if (!*r && r != username) 518 return (uid); 519 if ((pwd = getpwnam(username)) == NULL) 520 errx(1, "No such user"); 521 endpwent(); 522 return (pwd->pw_uid); 523 } 524 525 static gid_t 526 grp2gid(const char *groupname) 527 { 528 struct group *grp; 529 gid_t gid; 530 char *r; 531 532 gid = strtol(groupname, &r, 0); 533 if (!*r && r != groupname) 534 return (gid); 535 if ((grp = getgrnam(groupname)) == NULL) 536 errx(1, "No such group"); 537 endgrent(); 538 return (grp->gr_gid); 539 } 540 541 static void 542 usage(void) 543 { 544 545 fprintf(stderr, 546 "usage: ipcs [-abcmopqstMQST] [-C corefile] [-N namelist] [-u user] [-g group]\n"); 547 exit(1); 548 } 549