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