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