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