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