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