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