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