1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2015, Joyent, Inc. All rights reserved. 25 * Copyright 2019, Carlos Neira <cneirabustos@gmail.com> 26 * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. 27 * Copyright 2020 Oxide Computer Company 28 */ 29 30 #include <stdio.h> 31 #define __EXTENSIONS__ 32 #include <string.h> 33 #undef __EXTENSIONS__ 34 #include <signal.h> 35 #include <errno.h> 36 #include "libproc.h" 37 #include <sys/procfs_isa.h> 38 39 static const char * 40 rawfltname(int flt) 41 { 42 const char *name; 43 44 switch (flt) { 45 case FLTILL: name = "FLTILL"; break; 46 case FLTPRIV: name = "FLTPRIV"; break; 47 case FLTBPT: name = "FLTBPT"; break; 48 case FLTTRACE: name = "FLTTRACE"; break; 49 case FLTACCESS: name = "FLTACCESS"; break; 50 case FLTBOUNDS: name = "FLTBOUNDS"; break; 51 case FLTIOVF: name = "FLTIOVF"; break; 52 case FLTIZDIV: name = "FLTIZDIV"; break; 53 case FLTFPE: name = "FLTFPE"; break; 54 case FLTSTACK: name = "FLTSTACK"; break; 55 case FLTPAGE: name = "FLTPAGE"; break; 56 case FLTWATCH: name = "FLTWATCH"; break; 57 case FLTCPCOVF: name = "FLTCPCOVF"; break; 58 default: name = NULL; break; 59 } 60 61 return (name); 62 } 63 64 /* 65 * Return the name of a fault. 66 * Manufacture a name for unknown fault. 67 */ 68 char * 69 proc_fltname(int flt, char *buf, size_t bufsz) 70 { 71 const char *name = rawfltname(flt); 72 size_t len; 73 74 if (bufsz == 0) /* force a program failure */ 75 return (NULL); 76 77 if (name != NULL) { 78 len = strlen(name); 79 (void) strncpy(buf, name, bufsz); 80 } else { 81 len = snprintf(buf, bufsz, "FLT#%d", flt); 82 } 83 84 if (len >= bufsz) /* ensure null-termination */ 85 buf[bufsz-1] = '\0'; 86 87 return (buf); 88 } 89 90 /* 91 * Return the name of a signal. 92 * Manufacture a name for unknown signal. 93 */ 94 char * 95 proc_signame(int sig, char *buf, size_t bufsz) 96 { 97 char name[SIG2STR_MAX+4]; 98 size_t len; 99 100 if (bufsz == 0) /* force a program failure */ 101 return (NULL); 102 103 /* sig2str() omits the leading "SIG" */ 104 (void) strcpy(name, "SIG"); 105 106 if (sig2str(sig, name+3) == 0) { 107 len = strlen(name); 108 (void) strncpy(buf, name, bufsz); 109 } else { 110 len = snprintf(buf, bufsz, "SIG#%d", sig); 111 } 112 113 if (len >= bufsz) /* ensure null-termination */ 114 buf[bufsz-1] = '\0'; 115 116 return (buf); 117 } 118 119 static const char *const systable[] = { 120 NULL, /* 0 */ 121 "_exit", /* 1 */ 122 NULL, /* 2 */ 123 "read", /* 3 */ 124 "write", /* 4 */ 125 "open", /* 5 */ 126 "close", /* 6 */ 127 "linkat", /* 7 */ 128 NULL, /* 8 */ 129 "link", /* 9 */ 130 "unlink", /* 10 */ 131 "symlinkat", /* 11 */ 132 "chdir", /* 12 */ 133 "time", /* 13 */ 134 "mknod", /* 14 */ 135 "chmod", /* 15 */ 136 "chown", /* 16 */ 137 "brk", /* 17 */ 138 "stat", /* 18 */ 139 "lseek", /* 19 */ 140 "getpid", /* 20 */ 141 "mount", /* 21 */ 142 "readlinkat", /* 22 */ 143 "setuid", /* 23 */ 144 "getuid", /* 24 */ 145 "stime", /* 25 */ 146 "ptrace", /* 26 */ 147 "alarm", /* 27 */ 148 "fstat", /* 28 */ 149 "pause", /* 29 */ 150 NULL, /* 30 */ 151 "stty", /* 31 */ 152 "gtty", /* 32 */ 153 "access", /* 33 */ 154 "nice", /* 34 */ 155 "statfs", /* 35 */ 156 "sync", /* 36 */ 157 "kill", /* 37 */ 158 "fstatfs", /* 38 */ 159 "pgrpsys", /* 39 */ 160 "uucopystr", /* 40 */ 161 NULL, /* 41 */ 162 "pipe", /* 42 */ 163 "times", /* 43 */ 164 "profil", /* 44 */ 165 "faccessat", /* 45 */ 166 "setgid", /* 46 */ 167 "getgid", /* 47 */ 168 "mknodat", /* 48 */ 169 "msgsys", /* 49 */ 170 "sysi86", /* 50 */ 171 "acct", /* 51 */ 172 "shmsys", /* 52 */ 173 "semsys", /* 53 */ 174 "ioctl", /* 54 */ 175 "uadmin", /* 55 */ 176 "fchownat", /* 56 */ 177 "utssys", /* 57 */ 178 "fdsync", /* 58 */ 179 "execve", /* 59 */ 180 "umask", /* 60 */ 181 "chroot", /* 61 */ 182 "fcntl", /* 62 */ 183 "ulimit", /* 63 */ 184 "renameat", /* 64 */ 185 "unlinkat", /* 65 */ 186 "fstatat", /* 66 */ 187 "fstatat64", /* 67 */ 188 "openat", /* 68 */ 189 "openat64", /* 69 */ 190 "tasksys", /* 70 */ 191 "acctctl", /* 71 */ 192 "exacctsys", /* 72 */ 193 "getpagesizes", /* 73 */ 194 "rctlsys", /* 74 */ 195 "issetugid", /* 75 */ 196 "fsat", /* 76 */ 197 "lwp_park", /* 77 */ 198 "sendfilev", /* 78 */ 199 "rmdir", /* 79 */ 200 "mkdir", /* 80 */ 201 "getdents", /* 81 */ 202 "privsys", /* 82 */ 203 "ucredsys", /* 83 */ 204 "sysfs", /* 84 */ 205 "getmsg", /* 85 */ 206 "putmsg", /* 86 */ 207 NULL, /* 87 */ 208 "lstat", /* 88 */ 209 "symlink", /* 89 */ 210 "readlink", /* 90 */ 211 "setgroups", /* 91 */ 212 "getgroups", /* 92 */ 213 "fchmod", /* 93 */ 214 "fchown", /* 94 */ 215 "sigprocmask", /* 95 */ 216 "sigsuspend", /* 96 */ 217 "sigaltstack", /* 97 */ 218 "sigaction", /* 98 */ 219 "sigpending", /* 99 */ 220 "context", /* 100 */ 221 "fchmodat", /* 101 */ 222 "mkdirat", /* 102 */ 223 "statvfs", /* 103 */ 224 "fstatvfs", /* 104 */ 225 "getloadavg", /* 105 */ 226 "nfssys", /* 106 */ 227 "waitid", /* 107 */ 228 "sigsendsys", /* 108 */ 229 "hrtsys", /* 109 */ 230 "acancel", /* 110 */ 231 "async", /* 111 */ 232 "priocntlsys", /* 112 */ 233 "pathconf", /* 113 */ 234 "mincore", /* 114 */ 235 "mmap", /* 115 */ 236 "mprotect", /* 116 */ 237 "munmap", /* 117 */ 238 "fpathconf", /* 118 */ 239 "vfork", /* 119 */ 240 "fchdir", /* 120 */ 241 "readv", /* 121 */ 242 "writev", /* 122 */ 243 "preadv", /* 123 */ 244 "pwritev", /* 124 */ 245 "upanic", /* 125 */ 246 "getrandom", /* 126 */ 247 "mmapobj", /* 127 */ 248 "setrlimit", /* 128 */ 249 "getrlimit", /* 129 */ 250 "lchown", /* 130 */ 251 "memcntl", /* 131 */ 252 "getpmsg", /* 132 */ 253 "putpmsg", /* 133 */ 254 "rename", /* 134 */ 255 "uname", /* 135 */ 256 "setegid", /* 136 */ 257 "sysconfig", /* 137 */ 258 "adjtime", /* 138 */ 259 "systeminfo", /* 139 */ 260 "sharefs", /* 140 */ 261 "seteuid", /* 141 */ 262 "forksys", /* 142 */ 263 NULL, /* 143 */ 264 "sigtimedwait", /* 144 */ 265 "lwp_info", /* 145 */ 266 "yield", /* 146 */ 267 NULL, /* 147 */ 268 "lwp_sema_post", /* 148 */ 269 "lwp_sema_trywait", /* 149 */ 270 "lwp_detatch", /* 150 */ 271 "corectl", /* 151 */ 272 "modctl", /* 152 */ 273 "fchroot", /* 153 */ 274 NULL, /* 154 */ 275 "vhangup", /* 155 */ 276 "gettimeofday", /* 156 */ 277 "getitimer", /* 157 */ 278 "setitimer", /* 158 */ 279 "lwp_create", /* 159 */ 280 "lwp_exit", /* 160 */ 281 "lwp_suspend", /* 161 */ 282 "lwp_continue", /* 162 */ 283 "lwp_kill", /* 163 */ 284 "lwp_self", /* 164 */ 285 "lwp_sigmask", /* 165 */ 286 "lwp_private", /* 166 */ 287 "lwp_wait", /* 167 */ 288 "lwp_mutex_wakeup", /* 168 */ 289 NULL, /* 169 */ 290 "lwp_cond_wait", /* 170 */ 291 "lwp_cond_signal", /* 171 */ 292 "lwp_cond_broadcast", /* 172 */ 293 "pread", /* 173 */ 294 "pwrite", /* 174 */ 295 "llseek", /* 175 */ 296 "inst_sync", /* 176 */ 297 "brand", /* 177 */ 298 "kaio", /* 178 */ 299 "cpc", /* 179 */ 300 "lgrpsys", /* 180 */ 301 "rusagesys", /* 181 */ 302 "portfs", /* 182 */ 303 "pollsys", /* 183 */ 304 "labelsys", /* 184 */ 305 "acl", /* 185 */ 306 "auditsys", /* 186 */ 307 "processor_bind", /* 187 */ 308 "processor_info", /* 188 */ 309 "p_online", /* 189 */ 310 "sigqueue", /* 190 */ 311 "clock_gettime", /* 191 */ 312 "clock_settime", /* 192 */ 313 "clock_getres", /* 193 */ 314 "timer_create", /* 194 */ 315 "timer_delete", /* 195 */ 316 "timer_settime", /* 196 */ 317 "timer_gettime", /* 197 */ 318 "timer_getoverrun", /* 198 */ 319 "nanosleep", /* 199 */ 320 "facl", /* 200 */ 321 "door", /* 201 */ 322 "setreuid", /* 202 */ 323 "setregid", /* 203 */ 324 "install_utrap", /* 204 */ 325 "signotify", /* 205 */ 326 "schedctl", /* 206 */ 327 "pset", /* 207 */ 328 "sparc_utrap_install", /* 208 */ 329 "resolvepath", /* 209 */ 330 "lwp_mutex_timedlock", /* 210 */ 331 "lwp_sema_timedwait", /* 211 */ 332 "lwp_rwlock_sys", /* 212 */ 333 "getdents64", /* 213 */ 334 "mmap64", /* 214 */ 335 "stat64", /* 215 */ 336 "lstat64", /* 216 */ 337 "fstat64", /* 217 */ 338 "statvfs64", /* 218 */ 339 "fstatvfs64", /* 219 */ 340 "setrlimit64", /* 220 */ 341 "getrlimit64", /* 221 */ 342 "pread64", /* 222 */ 343 "pwrite64", /* 223 */ 344 NULL, /* 224 */ 345 "open64", /* 225 */ 346 "rpcmod", /* 226 */ 347 "zone", /* 227 */ 348 "autofssys", /* 228 */ 349 "getcwd", /* 229 */ 350 "so_socket", /* 230 */ 351 "so_socketpair", /* 231 */ 352 "bind", /* 232 */ 353 "listen", /* 233 */ 354 "accept", /* 234 */ 355 "connect", /* 235 */ 356 "shutdown", /* 236 */ 357 "recv", /* 237 */ 358 "recvfrom", /* 238 */ 359 "recvmsg", /* 239 */ 360 "send", /* 240 */ 361 "sendmsg", /* 241 */ 362 "sendto", /* 242 */ 363 "getpeername", /* 243 */ 364 "getsockname", /* 244 */ 365 "getsockopt", /* 245 */ 366 "setsockopt", /* 246 */ 367 "sockconfig", /* 247 */ 368 "ntp_gettime", /* 248 */ 369 "ntp_adjtime", /* 249 */ 370 "lwp_mutex_unlock", /* 250 */ 371 "lwp_mutex_trylock", /* 251 */ 372 "lwp_mutex_register", /* 252 */ 373 "cladm", /* 253 */ 374 "uucopy", /* 254 */ 375 "umount2" /* 255 */ 376 }; 377 378 /* SYSEND == max syscall number + 1 */ 379 #define SYSEND (sizeof (systable) / sizeof (systable[0])) 380 381 /* 382 * Return the name of a system call. 383 * Manufacture a name for unknown system call. 384 */ 385 char * 386 proc_sysname(int sys, char *buf, size_t bufsz) 387 { 388 const char *name; 389 size_t len; 390 391 if (bufsz == 0) /* force a program failure */ 392 return (NULL); 393 394 if (sys >= 0 && sys < SYSEND) 395 name = systable[sys]; 396 else 397 name = NULL; 398 399 if (name != NULL) { 400 len = strlen(name); 401 (void) strncpy(buf, name, bufsz); 402 } else { 403 len = snprintf(buf, bufsz, "SYS#%d", sys); 404 } 405 406 if (len >= bufsz) /* ensure null-termination */ 407 buf[bufsz-1] = '\0'; 408 409 return (buf); 410 } 411 412 /* 413 * Convert a string representation of a fault to the corresponding number. 414 */ 415 int 416 proc_str2flt(const char *str, int *fltnum) 417 { 418 char *next; 419 int i; 420 421 i = strtol(str, &next, 0); 422 if (i > 0 && i <= PRMAXFAULT && *next == '\0') { 423 *fltnum = i; 424 return (0); 425 } 426 427 for (i = 1; i <= PRMAXFAULT; i++) { 428 const char *s = rawfltname(i); 429 430 if (s && (strcasecmp(s, str) == 0 || 431 strcasecmp(s + 3, str) == 0)) { 432 *fltnum = i; 433 return (0); 434 } 435 } 436 437 return (-1); 438 } 439 440 /* 441 * Convert a string representation of a signal to the signal number. This 442 * functionality is already available in libc, but the interface doesn't 443 * optionally accept a "SIG" prefix. We strip that first, and then call libc. 444 */ 445 int 446 proc_str2sig(const char *str, int *signum) 447 { 448 if (strncasecmp(str, "SIG", 3) == 0) 449 str += 3; /* skip prefix */ 450 451 return (str2sig(str, signum)); 452 } 453 454 /* 455 * Convert a string representation of a system call to the corresponding number. 456 * We do this by performing a simple linear search of the table above. 457 */ 458 int 459 proc_str2sys(const char *str, int *sysnum) 460 { 461 char *next; 462 int i; 463 464 i = strtol(str, &next, 0); 465 if (i > 0 && i <= PRMAXSYS && *next == '\0') { 466 *sysnum = i; 467 return (0); 468 } 469 470 for (i = 1; i < SYSEND; i++) { 471 if (systable[i] != NULL && strcmp(systable[i], str) == 0) { 472 *sysnum = i; 473 return (0); 474 } 475 } 476 477 return (-1); 478 } 479 480 /* 481 * Convert a fltset_t to a string representation consisting of canonical 482 * machine fault names separated by the given delimeter string. If 483 * m is non-zero (TRUE), set members are printed. If m is zero (FALSE), set 484 * non-members are printed. If the specified buf is too small to hold the 485 * complete formatted set, NULL is returned; otherwise buf is returned. 486 */ 487 char * 488 proc_fltset2str(const fltset_t *set, const char *delim, int m, 489 char *buf, size_t len) 490 { 491 char name[FLT2STR_MAX], *p = buf; 492 size_t n; 493 int i; 494 495 if (buf == NULL || len < 1) { 496 errno = EINVAL; 497 return (NULL); 498 } 499 500 buf[0] = '\0'; /* Set first byte to \0 */ 501 502 for (i = 1; i <= PRMAXFAULT; i++) { 503 if ((prismember(set, i) != 0) ^ (m == 0)) { 504 (void) proc_fltname(i, name, sizeof (name)); 505 506 if (buf[0] != '\0') 507 n = snprintf(p, len, "%s%s", delim, name); 508 else 509 n = snprintf(p, len, "%s", name); 510 511 if (n != strlen(p)) { 512 errno = ENAMETOOLONG; /* Output was truncated */ 513 return (NULL); 514 } 515 len -= n; 516 p += n; 517 } 518 } 519 return (buf); 520 } 521 522 /* 523 * Convert a sigset_t to a string representation consisting of canonical signal 524 * names (without the SIG prefix). Parameters and return values analogous to 525 * proc_fltset2str(). 526 */ 527 char * 528 proc_sigset2str(const sigset_t *set, const char *delim, int m, 529 char *buf, size_t len) 530 { 531 char name[SIG2STR_MAX], *p = buf; 532 size_t n; 533 int i; 534 535 if (buf == NULL || len < 1) { 536 errno = EINVAL; 537 return (NULL); 538 } 539 540 m = (m != 0); /* Make sure m is 0 or 1 */ 541 buf[0] = '\0'; /* Set first byte to \0 */ 542 543 /* 544 * Unlike proc_fltset2str() and proc_sysset2str(), we don't loop 545 * until i <= NSIG here, because sigismember() rejects i == NSIG. 546 */ 547 for (i = 1; i < NSIG; i++) { 548 if (sigismember(set, i) == m) { 549 (void) sig2str(i, name); 550 551 if (buf[0] != '\0') 552 n = snprintf(p, len, "%s%s", delim, name); 553 else 554 n = snprintf(p, len, "%s", name); 555 556 if (n != strlen(p)) { 557 errno = ENAMETOOLONG; /* Output was truncated */ 558 return (NULL); 559 } 560 561 len -= n; 562 p += n; 563 } 564 } 565 566 return (buf); 567 } 568 569 /* 570 * Convert a sysset_t to a string representation consisting of canonical system 571 * call names. Parameters and return values analogous to proc_fltset2str(). 572 */ 573 char * 574 proc_sysset2str(const sysset_t *set, const char *delim, int m, 575 char *buf, size_t len) 576 { 577 char name[SYS2STR_MAX], *p = buf; 578 size_t n; 579 int i; 580 581 if (buf == NULL || len < 1) { 582 errno = EINVAL; 583 return (NULL); 584 } 585 586 buf[0] = '\0'; /* Set first byte to \0 */ 587 588 for (i = 1; i <= PRMAXSYS; i++) { 589 if ((prismember(set, i) != 0) ^ (m == 0)) { 590 (void) proc_sysname(i, name, sizeof (name)); 591 592 if (buf[0] != '\0') 593 n = snprintf(p, len, "%s%s", delim, name); 594 else 595 n = snprintf(p, len, "%s", name); 596 597 if (n != strlen(p)) { 598 errno = ENAMETOOLONG; /* Output was truncated */ 599 return (NULL); 600 } 601 len -= n; 602 p += n; 603 } 604 } 605 return (buf); 606 } 607 608 /* 609 * Convert a string representation of a fault set (names separated by 610 * one or more of the given delimeters) to a fltset_t. 611 * If m is non-zero (TRUE), members of the string representation are set. 612 * If m is zero (FALSE), non-members of the string representation are set. 613 * This function returns NULL for success. Otherwise it returns a pointer 614 * to the token of the string that couldn't be identified as a string 615 * representation of a fault. 616 */ 617 char * 618 proc_str2fltset(const char *s, const char *delim, int m, fltset_t *set) 619 { 620 char *p, *q, *t; 621 int flt; 622 623 if (m) { 624 premptyset(set); 625 } else { 626 prfillset(set); 627 } 628 629 t = strdupa(s); 630 631 for (p = strtok_r(t, delim, &q); p != NULL; 632 p = strtok_r(NULL, delim, &q)) { 633 if (proc_str2flt(p, &flt) == -1) { 634 errno = EINVAL; 635 return ((char *)s + (p - t)); 636 } 637 if (m) 638 praddset(set, flt); 639 else 640 prdelset(set, flt); 641 } 642 return (NULL); 643 } 644 645 /* 646 * Convert a string representation of a signal set (names with or without the 647 * SIG prefix separated by one or more of the given delimeters) to a sigset_t. 648 * Parameters and return values analogous to proc_str2fltset(). 649 */ 650 char * 651 proc_str2sigset(const char *s, const char *delim, int m, sigset_t *set) 652 { 653 char *p, *q, *t; 654 int sig; 655 656 if (m) { 657 premptyset(set); 658 } else { 659 prfillset(set); 660 } 661 662 t = strdupa(s); 663 664 for (p = strtok_r(t, delim, &q); p != NULL; 665 p = strtok_r(NULL, delim, &q)) { 666 if (proc_str2sig(p, &sig) == -1) { 667 errno = EINVAL; 668 return ((char *)s + (p - t)); 669 } 670 if (m) 671 praddset(set, sig); 672 else 673 prdelset(set, sig); 674 } 675 return (NULL); 676 } 677 678 /* 679 * Convert a string representation of a system call set (names separated by 680 * one or more of the given delimeters) to a sysset_t. Parameters and return 681 * values analogous to proc_str2fltset(). 682 */ 683 char * 684 proc_str2sysset(const char *s, const char *delim, int m, sysset_t *set) 685 { 686 char *p, *q, *t; 687 int sys; 688 689 if (m) { 690 premptyset(set); 691 } else { 692 prfillset(set); 693 } 694 695 t = strdupa(s); 696 697 for (p = strtok_r(t, delim, &q); p != NULL; 698 p = strtok_r(NULL, delim, &q)) { 699 if (proc_str2sys(p, &sys) == -1) { 700 errno = EINVAL; 701 return ((char *)s + (p - t)); 702 } 703 if (m) 704 praddset(set, sys); 705 else 706 prdelset(set, sys); 707 } 708 return (NULL); 709 } 710 711 /* 712 * Returns a string representation of a process data model. 713 * See <sys/procfs_isa.h> for possible values. 714 */ 715 char * 716 proc_dmodelname(int dmodel, char *buf, size_t bufsz) 717 { 718 static const char *const dmdls[] = { 719 "PR_MODEL_UNKNOWN", 720 "PR_MODEL_ILP32", 721 "PR_MODEL_LP64", 722 NULL 723 }; 724 size_t len; 725 726 if (bufsz == 0) 727 return (NULL); 728 729 if (dmodel > PR_MODEL_LP64 || dmodel < PR_MODEL_UNKNOWN) { 730 len = snprintf(buf, bufsz, "DMODEL#%d", dmodel); 731 } else { 732 len = strlen(dmdls[dmodel]); 733 (void) strncpy(buf, dmdls[dmodel], bufsz); 734 } 735 736 if (len >= bufsz) 737 buf[bufsz-1] = '\0'; 738 739 return (buf); 740 } 741