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