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