xref: /illumos-gate/usr/src/cmd/truss/listopts.c (revision e77c795bcbe51aebd7579fe13cbf2a6d56eca47f)
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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <memory.h>
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <libproc.h>
38 #include "ramdata.h"
39 #include "systable.h"
40 #include "proto.h"
41 
42 /* XXX A bug in the <string.h> header file requires this */
43 extern char *strtok_r(char *s1, const char *s2, char **lasts);
44 
45 /*
46  * option procesing ---
47  * Routines for scanning syscall, signal, fault
48  * and file descriptor lists.
49  */
50 
51 /*
52  * Function prototypes for static routines in this module.
53  */
54 void	upcase(char *);
55 
56 const char white[] = " \t\n";	/* white space characters */
57 const char sepr[] = " ,\t\n";	/* list separator characters */
58 const char csepr[] = " :,\t\n";	/* same, with ':' added */
59 
60 /*
61  * Scan list of syscall names.
62  * Return 0 on success, != 0 on any failure.
63  */
64 int
65 syslist(char *str,			/* string of syscall names */
66 	sysset_t *setp,			/* syscall set */
67 	int *fp)			/* first-time flag */
68 {
69 	char *name;
70 	int exclude = FALSE;
71 	int rc = 0;
72 	char *lasts;
73 
74 	name = strtok_r(str, sepr, &lasts);
75 
76 	if (name != NULL && *name == '!') {	/* exclude from set */
77 		exclude = TRUE;
78 		if (*++name == '\0')
79 			name = strtok_r(NULL, sepr, &lasts);
80 	} else if (!*fp) {	/* first time, clear the set */
81 		premptyset(setp);
82 		*fp = TRUE;
83 	}
84 
85 	for (; name; name = strtok_r(NULL, sepr, &lasts)) {
86 		int sys;
87 		int sysx;
88 		int sysxx;
89 		int sys64;
90 		char *next;
91 
92 		if (*name == '!') {	/* exclude remainder from set */
93 			exclude = TRUE;
94 			while (*++name == '!')
95 				/* empty */;
96 			if (*name == '\0')
97 				continue;
98 		}
99 
100 		sys = strtol(name, &next, 0);
101 		sysx = sysxx = sys64 = 0;
102 		if (sys < 0 || sys > PRMAXSYS || *next != '\0')
103 			sys = 0;
104 		if (sys == 0) {
105 			const struct systable *stp = systable;
106 			for (; sys == 0 && stp->nargs >= 0; stp++)
107 				if (stp->name && strcmp(stp->name, name) == 0)
108 					sys = stp-systable;
109 		}
110 		if (sys == 0) {
111 			const struct sysalias *sap = sysalias;
112 			for (; sys == 0 && sap->name; sap++)
113 				if (strcmp(sap->name, name) == 0)
114 					sys = sap->number;
115 		}
116 		if (sys > 0 && sys <= PRMAXSYS) {
117 			switch (sys) {
118 			case SYS_fstatat:	/* set both if either */
119 			case SYS_fstatat64:
120 				sys = SYS_fstatat;
121 				sys64 = SYS_fstatat64;
122 				goto def;
123 
124 			case SYS_stat:		/* set all if either */
125 			case SYS_stat64:
126 				sys = SYS_stat;
127 				sys64 = SYS_stat64;
128 				sysx = SYS_fstatat;
129 				sysxx = SYS_fstatat64;
130 				goto def;
131 
132 			case SYS_lstat:		/* set all if either */
133 			case SYS_lstat64:
134 				sys = SYS_lstat;
135 				sys64 = SYS_lstat64;
136 				sysx = SYS_fstatat;
137 				sysxx = SYS_fstatat64;
138 				goto def;
139 
140 			case SYS_fstat:		/* set all if either */
141 			case SYS_fstat64:
142 				sys = SYS_fstat;
143 				sys64 = SYS_fstat64;
144 				sysx = SYS_fstatat;
145 				sysxx = SYS_fstatat64;
146 				goto def;
147 
148 			case SYS_getdents:	/* set both if either */
149 			case SYS_getdents64:
150 				sys = SYS_getdents;
151 				sys64 = SYS_getdents64;
152 				goto def;
153 
154 			case SYS_mmap:		/* set both if either */
155 			case SYS_mmap64:
156 				sys = SYS_mmap;
157 				sys64 = SYS_mmap64;
158 				goto def;
159 
160 			case SYS_statvfs:	/* set both if either */
161 			case SYS_statvfs64:
162 				sys = SYS_statvfs;
163 				sys64 = SYS_statvfs64;
164 				goto def;
165 
166 			case SYS_fstatvfs:	/* set both if either */
167 			case SYS_fstatvfs64:
168 				sys = SYS_fstatvfs;
169 				sys64 = SYS_fstatvfs64;
170 				goto def;
171 
172 			case SYS_setrlimit:	/* set both if either */
173 			case SYS_setrlimit64:
174 				sys = SYS_setrlimit;
175 				sys64 = SYS_setrlimit64;
176 				goto def;
177 
178 			case SYS_getrlimit:	/* set both if either */
179 			case SYS_getrlimit64:
180 				sys = SYS_getrlimit;
181 				sys64 = SYS_getrlimit64;
182 				goto def;
183 
184 			case SYS_pread:		/* set both if either */
185 			case SYS_pread64:
186 				sys = SYS_pread;
187 				sys64 = SYS_pread64;
188 				goto def;
189 
190 			case SYS_pwrite:	/* set both if either */
191 			case SYS_pwrite64:
192 				sys = SYS_pwrite;
193 				sys64 = SYS_pwrite64;
194 				goto def;
195 
196 			case SYS_openat:	/* set all if any */
197 			case SYS_openat64:
198 			case SYS_open:
199 			case SYS_open64:
200 				sys = SYS_openat;
201 				sys64 = SYS_openat64;
202 				sysx = SYS_open;
203 				sysxx = SYS_open64;
204 				goto def;
205 
206 			case SYS_forksys:	/* set both if either */
207 			case SYS_vfork:
208 				sysx = SYS_forksys;
209 				sys = SYS_vfork;
210 				goto def;
211 
212 			case SYS_sigprocmask:	/* set both if either */
213 			case SYS_lwp_sigmask:
214 				sysx = SYS_sigprocmask;
215 				sys = SYS_lwp_sigmask;
216 				goto def;
217 
218 			case SYS_lseek:		/* set both if either */
219 			case SYS_llseek:
220 				sysx = SYS_lseek;
221 				sys = SYS_llseek;
222 				goto def;
223 
224 			case SYS_rename:	/* set both */
225 				sysx = SYS_renameat;
226 				goto def;
227 
228 			case SYS_link:		/* set both */
229 				sysx = SYS_linkat;
230 				goto def;
231 
232 			case SYS_unlink:	/* set both */
233 			case SYS_rmdir:		/* set both */
234 				sysx = SYS_unlinkat;
235 				goto def;
236 
237 			case SYS_symlink:	/* set both */
238 				sysx = SYS_symlinkat;
239 				goto def;
240 
241 			case SYS_readlink:	/* set both */
242 				sysx = SYS_readlinkat;
243 				goto def;
244 
245 			case SYS_chmod:		/* set both */
246 			case SYS_fchmod:	/* set both */
247 				sysx = SYS_fchmodat;
248 				goto def;
249 
250 			case SYS_chown:		/* set both */
251 			case SYS_lchown:	/* set both */
252 			case SYS_fchown:	/* set both */
253 				sysx = SYS_fchownat;
254 				goto def;
255 
256 			case SYS_mkdir:		/* set both */
257 				sysx = SYS_mkdirat;
258 				goto def;
259 
260 			case SYS_mknod:		/* set both */
261 				sysx = SYS_mknodat;
262 				goto def;
263 
264 			case SYS_access:	/* set both */
265 				sysx = SYS_faccessat;
266 				goto def;
267 
268 			default:
269 			def:
270 				if (exclude) {
271 					prdelset(setp, sys);
272 					if (sysx)
273 						prdelset(setp, sysx);
274 					if (sysxx)
275 						prdelset(setp, sysxx);
276 					if (sys64)
277 						prdelset(setp, sys64);
278 				} else {
279 					praddset(setp, sys);
280 					if (sysx)
281 						praddset(setp, sysx);
282 					if (sysxx)
283 						praddset(setp, sysxx);
284 					if (sys64)
285 						praddset(setp, sys64);
286 				}
287 				break;
288 			}
289 		} else if (strcmp(name, "all") == 0 ||
290 		    strcmp(name, "ALL") == 0) {
291 			if (exclude) {
292 				premptyset(setp);
293 			} else {
294 				prfillset(setp);
295 			}
296 		} else {
297 			(void) fprintf(stderr,
298 			    "%s: unrecognized syscall: %s\n",
299 			    command, name);
300 			rc = -1;
301 		}
302 	}
303 
304 	return (rc);
305 }
306 
307 /*
308  * List of signals to trace.
309  * Return 0 on success, != 0 on any failure.
310  */
311 int
312 siglist(private_t *pri,
313 	char *str,			/* string of signal names */
314 	sigset_t *setp,			/* signal set */
315 	int *fp)			/* first-time flag */
316 {
317 	char *name;
318 	int exclude = FALSE;
319 	int rc = 0;
320 	char *lasts;
321 
322 	upcase(str);
323 	name = strtok_r(str, sepr, &lasts);
324 
325 	if (name != NULL && *name == '!') {	/* exclude from set */
326 		exclude = TRUE;
327 		if (*++name == '\0')
328 			name = strtok_r(NULL, sepr, &lasts);
329 	} else if (!*fp) {	/* first time, clear the set */
330 		premptyset(setp);
331 		*fp = TRUE;
332 	}
333 
334 	for (; name; name = strtok_r(NULL, sepr, &lasts)) {
335 		int sig;
336 		char *next;
337 
338 		if (*name == '!') {	/* exclude remainder from set */
339 			exclude = TRUE;
340 			while (*++name == '!')
341 				/* empty */;
342 			if (*name == '\0')
343 				continue;
344 		}
345 
346 		sig = strtol(name, &next, 0);
347 		if (sig <= 0 || sig > PRMAXSIG || *next != '\0') {
348 			for (sig = 1; sig <= PRMAXSIG; sig++) {
349 				const char *sname = rawsigname(pri, sig);
350 				if (sname == NULL)
351 					continue;
352 				if (strcmp(sname, name) == 0 ||
353 				    strcmp(sname+3, name) == 0)
354 					break;
355 			}
356 			if (sig > PRMAXSIG)
357 				sig = 0;
358 		}
359 		if (sig > 0 && sig <= PRMAXSIG) {
360 			if (exclude) {
361 				prdelset(setp, sig);
362 			} else {
363 				praddset(setp, sig);
364 			}
365 		} else if (strcmp(name, "ALL") == 0) {
366 			if (exclude) {
367 				premptyset(setp);
368 			} else {
369 				prfillset(setp);
370 			}
371 		} else {
372 			(void) fprintf(stderr,
373 			    "%s: unrecognized signal name/number: %s\n",
374 			    command, name);
375 			rc = -1;
376 		}
377 	}
378 
379 	return (rc);
380 }
381 
382 /*
383  * List of faults to trace.
384  * return 0 on success, != 0 on any failure.
385  */
386 int
387 fltlist(char *str,			/* string of fault names */
388 	fltset_t *setp,			/* fault set */
389 	int *fp)			/* first-time flag */
390 {
391 	char *name;
392 	int exclude = FALSE;
393 	int rc = 0;
394 	char *lasts;
395 
396 	upcase(str);
397 	name = strtok_r(str, sepr, &lasts);
398 
399 	if (name != NULL && *name == '!') {	/* exclude from set */
400 		exclude = TRUE;
401 		if (*++name == '\0')
402 			name = strtok_r(NULL, sepr, &lasts);
403 	} else if (!*fp) {	/* first time, clear the set */
404 		premptyset(setp);
405 		*fp = TRUE;
406 	}
407 
408 	for (; name; name = strtok_r(NULL, sepr, &lasts)) {
409 		int flt;
410 		char *next;
411 
412 		if (*name == '!') {	/* exclude remainder from set */
413 			exclude = TRUE;
414 			while (*++name == '!')
415 				/* empty */;
416 			if (*name == '\0')
417 				continue;
418 		}
419 
420 		flt = strtol(name, &next, 0);
421 		if (flt <= 0 || flt > PRMAXFAULT || *next != '\0') {
422 			for (flt = 1; flt <= PRMAXFAULT; flt++) {
423 				char fname[32];
424 
425 				if (proc_fltname(flt, fname,
426 				    sizeof (fname)) == NULL)
427 					continue;
428 
429 				if (strcmp(fname, name) == 0 ||
430 				    strcmp(fname+3, name) == 0)
431 					break;
432 			}
433 			if (flt > PRMAXFAULT)
434 				flt = 0;
435 		}
436 		if (flt > 0 && flt <= PRMAXFAULT) {
437 			if (exclude) {
438 				prdelset(setp, flt);
439 			} else {
440 				praddset(setp, flt);
441 			}
442 		} else if (strcmp(name, "ALL") == 0) {
443 			if (exclude) {
444 				premptyset(setp);
445 			} else {
446 				prfillset(setp);
447 			}
448 		} else {
449 			(void) fprintf(stderr,
450 			    "%s: unrecognized fault name/number: %s\n",
451 			    command, name);
452 			rc = -1;
453 		}
454 	}
455 
456 	return (rc);
457 }
458 
459 /*
460  * Gather file descriptors to dump.
461  * Return 0 on success, != 0 on any failure.
462  */
463 int
464 fdlist(char *str,		/* string of filedescriptors */
465 	fileset_t *setp)	/* set of boolean flags */
466 {
467 	char *name;
468 	int exclude = FALSE;
469 	int rc = 0;
470 	char *lasts;
471 
472 	upcase(str);
473 	name = strtok_r(str, sepr, &lasts);
474 
475 	if (name != NULL && *name == '!') {	/* exclude from set */
476 		exclude = TRUE;
477 		if (*++name == '\0')
478 			name = strtok_r(NULL, sepr, &lasts);
479 	}
480 
481 	for (; name; name = strtok_r(NULL, sepr, &lasts)) {
482 		int fd;
483 		char *next;
484 
485 		if (*name == '!') {	/* exclude remainder from set */
486 			exclude = TRUE;
487 			while (*++name == '!')
488 				/* empty */;
489 			if (*name == '\0')
490 				continue;
491 		}
492 
493 		fd = strtol(name, &next, 0);
494 		if (fd >= 0 && fd < NOFILES_MAX && *next == '\0') {
495 			fd++;
496 			if (exclude) {
497 				prdelset(setp, fd);
498 			} else {
499 				praddset(setp, fd);
500 			}
501 		} else if (strcmp(name, "ALL") == 0) {
502 			if (exclude) {
503 				premptyset(setp);
504 			} else {
505 				prfillset(setp);
506 			}
507 		} else {
508 			(void) fprintf(stderr,
509 			    "%s: filedescriptor not in range[0..%d]: %s\n",
510 			    command, NOFILES_MAX-1, name);
511 			rc = -1;
512 		}
513 	}
514 
515 	return (rc);
516 }
517 
518 void
519 upcase(char *str)
520 {
521 	int c;
522 
523 	while ((c = *str) != '\0')
524 		*str++ = toupper(c);
525 }
526 
527 /*
528  * 'arg' points to a string like:
529  *	libc,libnsl,... : printf,read,write,...
530  * or
531  *	libc,libnsl,... :: printf,read,write,...
532  * with possible filename pattern-matching metacharacters.
533  *
534  * Assumption:  No library or function name can contain ',' or ':'.
535  */
536 int
537 liblist(char *arg, int hang)
538 {
539 	const char *star = "*";
540 	struct dynpat *Dyp;
541 	char *pat;
542 	char *fpat;
543 	char *lasts;
544 	uint_t maxpat;
545 
546 	/* append a new dynpat structure to the end of the Dynpat list */
547 	Dyp = my_malloc(sizeof (struct dynpat), NULL);
548 	Dyp->next = NULL;
549 	if (Lastpat == NULL)
550 		Dynpat = Lastpat = Dyp;
551 	else {
552 		Lastpat->next = Dyp;
553 		Lastpat = Dyp;
554 	}
555 	Dyp->flag = hang? BPT_HANG : 0;
556 	Dyp->exclude_lib = 0;
557 	Dyp->exclude = 0;
558 	Dyp->internal = 0;
559 	Dyp->Dp = NULL;
560 
561 	/*
562 	 * Find the beginning of the filename patterns
563 	 * and null-terminate the library name patterns.
564 	 */
565 	if ((fpat = strchr(arg, ':')) != NULL)
566 		*fpat++ = '\0';
567 
568 	/*
569 	 * Library name patterns.
570 	 */
571 	pat = strtok_r(arg, sepr, &lasts);
572 
573 	/* '!' introduces an exclusion list */
574 	if (pat != NULL && *pat == '!') {
575 		Dyp->exclude_lib = 1;
576 		pat += strspn(pat, "!");
577 		if (*pat == '\0')
578 			pat = strtok_r(NULL, sepr, &lasts);
579 		/* force exclusion of all functions as well */
580 		Dyp->exclude = 1;
581 		Dyp->internal = 1;
582 		fpat = NULL;
583 	}
584 
585 	if (pat == NULL) {
586 		/* empty list means all libraries */
587 		Dyp->libpat = my_malloc(sizeof (char *), NULL);
588 		Dyp->libpat[0] = star;
589 		Dyp->nlibpat = 1;
590 	} else {
591 		/*
592 		 * We are now at the library list.
593 		 * Generate the list and count the library name patterns.
594 		 */
595 		maxpat = 1;
596 		Dyp->libpat = my_malloc(maxpat * sizeof (char *), NULL);
597 		Dyp->nlibpat = 0;
598 		Dyp->libpat[Dyp->nlibpat++] = pat;
599 		while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) {
600 			if (Dyp->nlibpat == maxpat) {
601 				maxpat *= 2;
602 				Dyp->libpat = my_realloc(Dyp->libpat,
603 				    maxpat * sizeof (char *), NULL);
604 			}
605 			Dyp->libpat[Dyp->nlibpat++] = pat;
606 		}
607 	}
608 
609 	/*
610 	 * Function name patterns.
611 	 */
612 	if (fpat == NULL)
613 		pat = NULL;
614 	else {
615 		/*
616 		 * We have already seen a ':'.  Look for another.
617 		 * Double ':' means trace internal calls.
618 		 */
619 		fpat += strspn(fpat, white);
620 		if (*fpat == ':') {
621 			Dyp->internal = 1;
622 			*fpat++ = '\0';
623 		}
624 		pat = strtok_r(fpat, csepr, &lasts);
625 	}
626 
627 	/* '!' introduces an exclusion list */
628 	if (pat != NULL && *pat == '!') {
629 		Dyp->exclude = 1;
630 		Dyp->internal = 1;
631 		pat += strspn(pat, "!");
632 		if (*pat == '\0')
633 			pat = strtok_r(NULL, sepr, &lasts);
634 	}
635 
636 	if (pat == NULL) {
637 		/* empty function list means exclude all functions */
638 		Dyp->sympat = my_malloc(sizeof (char *), NULL);
639 		Dyp->sympat[0] = star;
640 		Dyp->nsympat = 1;
641 	} else {
642 		/*
643 		 * We are now at the function list.
644 		 * Generate the list and count the symbol name patterns.
645 		 */
646 		maxpat = 1;
647 		Dyp->sympat = my_malloc(maxpat * sizeof (char *), NULL);
648 		Dyp->nsympat = 0;
649 		Dyp->sympat[Dyp->nsympat++] = pat;
650 		while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) {
651 			if (Dyp->nsympat == maxpat) {
652 				maxpat *= 2;
653 				Dyp->sympat = my_realloc(Dyp->sympat,
654 				    maxpat * sizeof (char *), NULL);
655 			}
656 			Dyp->sympat[Dyp->nsympat++] = pat;
657 		}
658 	}
659 
660 	return (0);
661 }
662