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