xref: /illumos-gate/usr/src/cmd/truss/listopts.c (revision 88f8b78a88cbdc6d8c1af5c3e54bc49d25095c98)
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 2003 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 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.2	*/
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <memory.h>
39 #include <sys/types.h>
40 #include <signal.h>
41 #include <libproc.h>
42 #include "ramdata.h"
43 #include "systable.h"
44 #include "proto.h"
45 
46 /* XXX A bug in the <string.h> header file requires this */
47 extern char *strtok_r(char *s1, const char *s2, char **lasts);
48 
49 /*
50  * option procesing ---
51  * Routines for scanning syscall, signal, fault
52  * and file descriptor lists.
53  */
54 
55 /*
56  * Function prototypes for static routines in this module.
57  */
58 void	upcase(char *);
59 
60 const char white[] = " \t\n";	/* white space characters */
61 const char sepr[] = " ,\t\n";	/* list separator characters */
62 const char csepr[] = " :,\t\n";	/* same, with ':' added */
63 
64 /*
65  * Scan list of syscall names.
66  * Return 0 on success, != 0 on any failure.
67  */
68 int
69 syslist(char *str,			/* string of syscall names */
70 	sysset_t *setp,			/* syscall set */
71 	int *fp)			/* first-time flag */
72 {
73 	char *name;
74 	int exclude = FALSE;
75 	int rc = 0;
76 	char *lasts;
77 
78 	name = strtok_r(str, sepr, &lasts);
79 
80 	if (name != NULL && *name == '!') {	/* exclude from set */
81 		exclude = TRUE;
82 		if (*++name == '\0')
83 			name = strtok_r(NULL, sepr, &lasts);
84 	} else if (!*fp) {	/* first time, clear the set */
85 		premptyset(setp);
86 		*fp = TRUE;
87 	}
88 
89 	for (; name; name = strtok_r(NULL, sepr, &lasts)) {
90 		int sys;
91 		int sysx;
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 = 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 				sys = SYS_forkall;
215 				sysx = SYS_fork1;
216 				sys64 = SYS_vfork;
217 				goto def;
218 
219 			case SYS_exec:		/* set both if either */
220 			case SYS_execve:
221 				sysx = SYS_exec;
222 				sys = SYS_execve;
223 				goto def;
224 
225 			case SYS_poll:		/* set both if either */
226 			case SYS_pollsys:
227 				sysx = SYS_poll;
228 				sys = SYS_pollsys;
229 				goto def;
230 
231 			case SYS_sigprocmask:	/* set both if either */
232 			case SYS_lwp_sigmask:
233 				sysx = SYS_sigprocmask;
234 				sys = SYS_lwp_sigmask;
235 				goto def;
236 
237 			case SYS_wait:		/* set both if either */
238 			case SYS_waitsys:
239 				sysx = SYS_wait;
240 				sys = SYS_waitsys;
241 				goto def;
242 
243 			case SYS_lseek:		/* set both if either */
244 			case SYS_llseek:
245 				sysx = SYS_lseek;
246 				sys = SYS_llseek;
247 				goto def;
248 
249 			case SYS_lwp_mutex_lock: /* set both if either */
250 			case SYS_lwp_mutex_timedlock:
251 				sysx = SYS_lwp_mutex_lock;
252 				sys = SYS_lwp_mutex_timedlock;
253 				goto def;
254 
255 			case SYS_lwp_sema_wait: /* set both if either */
256 			case SYS_lwp_sema_timedwait:
257 				sysx = SYS_lwp_sema_wait;
258 				sys = SYS_lwp_sema_timedwait;
259 				goto def;
260 
261 			default:
262 			def:
263 				if (exclude) {
264 					prdelset(setp, sys);
265 					if (sysx)
266 						prdelset(setp, sysx);
267 					if (sys64)
268 						prdelset(setp, sys64);
269 				} else {
270 					praddset(setp, sys);
271 					if (sysx)
272 						praddset(setp, sysx);
273 					if (sys64)
274 						praddset(setp, sys64);
275 				}
276 				break;
277 			}
278 		} else if (strcmp(name, "all") == 0 ||
279 		    strcmp(name, "ALL") == 0) {
280 			if (exclude) {
281 				premptyset(setp);
282 			} else {
283 				prfillset(setp);
284 			}
285 		} else {
286 			(void) fprintf(stderr,
287 				"%s: unrecognized syscall: %s\n",
288 				command, name);
289 			rc = -1;
290 		}
291 	}
292 
293 	return (rc);
294 }
295 
296 /*
297  * List of signals to trace.
298  * Return 0 on success, != 0 on any failure.
299  */
300 int
301 siglist(private_t *pri,
302 	char *str,			/* string of signal names */
303 	sigset_t *setp,			/* signal set */
304 	int *fp)			/* first-time flag */
305 {
306 	char *name;
307 	int exclude = FALSE;
308 	int rc = 0;
309 	char *lasts;
310 
311 	upcase(str);
312 	name = strtok_r(str, sepr, &lasts);
313 
314 	if (name != NULL && *name == '!') {	/* exclude from set */
315 		exclude = TRUE;
316 		if (*++name == '\0')
317 			name = strtok_r(NULL, sepr, &lasts);
318 	} else if (!*fp) {	/* first time, clear the set */
319 		premptyset(setp);
320 		*fp = TRUE;
321 	}
322 
323 	for (; name; name = strtok_r(NULL, sepr, &lasts)) {
324 		int sig;
325 		char *next;
326 
327 		if (*name == '!') {	/* exclude remainder from set */
328 			exclude = TRUE;
329 			while (*++name == '!')
330 				/* empty */;
331 			if (*name == '\0')
332 				continue;
333 		}
334 
335 		sig = strtol(name, &next, 0);
336 		if (sig <= 0 || sig > PRMAXSIG || *next != '\0') {
337 			for (sig = 1; sig <= PRMAXSIG; sig++) {
338 				const char *sname = rawsigname(pri, sig);
339 				if (sname == NULL)
340 					continue;
341 				if (strcmp(sname, name) == 0 ||
342 				    strcmp(sname+3, name) == 0)
343 					break;
344 			}
345 			if (sig > PRMAXSIG)
346 				sig = 0;
347 		}
348 		if (sig > 0 && sig <= PRMAXSIG) {
349 			if (exclude) {
350 				prdelset(setp, sig);
351 			} else {
352 				praddset(setp, sig);
353 			}
354 		} else if (strcmp(name, "ALL") == 0) {
355 			if (exclude) {
356 				premptyset(setp);
357 			} else {
358 				prfillset(setp);
359 			}
360 		} else {
361 			(void) fprintf(stderr,
362 				"%s: unrecognized signal name/number: %s\n",
363 				command, name);
364 			rc = -1;
365 		}
366 	}
367 
368 	return (rc);
369 }
370 
371 /*
372  * List of faults to trace.
373  * return 0 on success, != 0 on any failure.
374  */
375 int
376 fltlist(char *str,			/* string of fault names */
377 	fltset_t *setp,			/* fault set */
378 	int *fp)			/* first-time flag */
379 {
380 	char *name;
381 	int exclude = FALSE;
382 	int rc = 0;
383 	char *lasts;
384 
385 	upcase(str);
386 	name = strtok_r(str, sepr, &lasts);
387 
388 	if (name != NULL && *name == '!') {	/* exclude from set */
389 		exclude = TRUE;
390 		if (*++name == '\0')
391 			name = strtok_r(NULL, sepr, &lasts);
392 	} else if (!*fp) {	/* first time, clear the set */
393 		premptyset(setp);
394 		*fp = TRUE;
395 	}
396 
397 	for (; name; name = strtok_r(NULL, sepr, &lasts)) {
398 		int flt;
399 		char *next;
400 
401 		if (*name == '!') {	/* exclude remainder from set */
402 			exclude = TRUE;
403 			while (*++name == '!')
404 				/* empty */;
405 			if (*name == '\0')
406 				continue;
407 		}
408 
409 		flt = strtol(name, &next, 0);
410 		if (flt <= 0 || flt > PRMAXFAULT || *next != '\0') {
411 			for (flt = 1; flt <= PRMAXFAULT; flt++) {
412 				char fname[32];
413 
414 				if (proc_fltname(flt, fname,
415 				    sizeof (fname)) == NULL)
416 					continue;
417 
418 				if (strcmp(fname, name) == 0 ||
419 				    strcmp(fname+3, name) == 0)
420 					break;
421 			}
422 			if (flt > PRMAXFAULT)
423 				flt = 0;
424 		}
425 		if (flt > 0 && flt <= PRMAXFAULT) {
426 			if (exclude) {
427 				prdelset(setp, flt);
428 			} else {
429 				praddset(setp, flt);
430 			}
431 		} else if (strcmp(name, "ALL") == 0) {
432 			if (exclude) {
433 				premptyset(setp);
434 			} else {
435 				prfillset(setp);
436 			}
437 		} else {
438 			(void) fprintf(stderr,
439 				"%s: unrecognized fault name/number: %s\n",
440 				command, name);
441 			rc = -1;
442 		}
443 	}
444 
445 	return (rc);
446 }
447 
448 /*
449  * Gather file descriptors to dump.
450  * Return 0 on success, != 0 on any failure.
451  */
452 int
453 fdlist(char *str,		/* string of filedescriptors */
454 	fileset_t *setp)	/* set of boolean flags */
455 {
456 	char *name;
457 	int exclude = FALSE;
458 	int rc = 0;
459 	char *lasts;
460 
461 	upcase(str);
462 	name = strtok_r(str, sepr, &lasts);
463 
464 	if (name != NULL && *name == '!') {	/* exclude from set */
465 		exclude = TRUE;
466 		if (*++name == '\0')
467 			name = strtok_r(NULL, sepr, &lasts);
468 	}
469 
470 	for (; name; name = strtok_r(NULL, sepr, &lasts)) {
471 		int fd;
472 		char *next;
473 
474 		if (*name == '!') {	/* exclude remainder from set */
475 			exclude = TRUE;
476 			while (*++name == '!')
477 				/* empty */;
478 			if (*name == '\0')
479 				continue;
480 		}
481 
482 		fd = strtol(name, &next, 0);
483 		if (fd >= 0 && fd < NOFILES_MAX && *next == '\0') {
484 			fd++;
485 			if (exclude) {
486 				prdelset(setp, fd);
487 			} else {
488 				praddset(setp, fd);
489 			}
490 		} else if (strcmp(name, "ALL") == 0) {
491 			if (exclude) {
492 				premptyset(setp);
493 			} else {
494 				prfillset(setp);
495 			}
496 		} else {
497 			(void) fprintf(stderr,
498 				"%s: filedescriptor not in range[0..%d]: %s\n",
499 				command, NOFILES_MAX-1, name);
500 			rc = -1;
501 		}
502 	}
503 
504 	return (rc);
505 }
506 
507 void
508 upcase(char *str)
509 {
510 	int c;
511 
512 	while ((c = *str) != '\0')
513 		*str++ = toupper(c);
514 }
515 
516 /*
517  * 'arg' points to a string like:
518  *	libc,libnsl,... : printf,read,write,...
519  * or
520  *	libc,libnsl,... :: printf,read,write,...
521  * with possible filename pattern-matching metacharacters.
522  *
523  * Assumption:  No library or function name can contain ',' or ':'.
524  */
525 int
526 liblist(char *arg, int hang)
527 {
528 	const char *star = "*";
529 	struct dynpat *Dyp;
530 	char *pat;
531 	char *fpat;
532 	char *lasts;
533 	uint_t maxpat;
534 
535 	/* append a new dynpat structure to the end of the Dynpat list */
536 	Dyp = my_malloc(sizeof (struct dynpat), NULL);
537 	Dyp->next = NULL;
538 	if (Lastpat == NULL)
539 		Dynpat = Lastpat = Dyp;
540 	else {
541 		Lastpat->next = Dyp;
542 		Lastpat = Dyp;
543 	}
544 	Dyp->flag = hang? BPT_HANG : 0;
545 	Dyp->exclude_lib = 0;
546 	Dyp->exclude = 0;
547 	Dyp->internal = 0;
548 	Dyp->Dp = NULL;
549 
550 	/*
551 	 * Find the beginning of the filename patterns
552 	 * and null-terminate the library name patterns.
553 	 */
554 	if ((fpat = strchr(arg, ':')) != NULL)
555 		*fpat++ = '\0';
556 
557 	/*
558 	 * Library name patterns.
559 	 */
560 	pat = strtok_r(arg, sepr, &lasts);
561 
562 	/* '!' introduces an exclusion list */
563 	if (pat != NULL && *pat == '!') {
564 		Dyp->exclude_lib = 1;
565 		pat += strspn(pat, "!");
566 		if (*pat == '\0')
567 			pat = strtok_r(NULL, sepr, &lasts);
568 		/* force exclusion of all functions as well */
569 		Dyp->exclude = 1;
570 		Dyp->internal = 1;
571 		fpat = NULL;
572 	}
573 
574 	if (pat == NULL) {
575 		/* empty list means all libraries */
576 		Dyp->libpat = my_malloc(sizeof (char *), NULL);
577 		Dyp->libpat[0] = star;
578 		Dyp->nlibpat = 1;
579 	} else {
580 		/*
581 		 * We are now at the library list.
582 		 * Generate the list and count the library name patterns.
583 		 */
584 		maxpat = 1;
585 		Dyp->libpat = my_malloc(maxpat * sizeof (char *), NULL);
586 		Dyp->nlibpat = 0;
587 		Dyp->libpat[Dyp->nlibpat++] = pat;
588 		while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) {
589 			if (Dyp->nlibpat == maxpat) {
590 				maxpat *= 2;
591 				Dyp->libpat = my_realloc(Dyp->libpat,
592 					maxpat * sizeof (char *), NULL);
593 			}
594 			Dyp->libpat[Dyp->nlibpat++] = pat;
595 		}
596 	}
597 
598 	/*
599 	 * Function name patterns.
600 	 */
601 	if (fpat == NULL)
602 		pat = NULL;
603 	else {
604 		/*
605 		 * We have already seen a ':'.  Look for another.
606 		 * Double ':' means trace internal calls.
607 		 */
608 		fpat += strspn(fpat, white);
609 		if (*fpat == ':') {
610 			Dyp->internal = 1;
611 			*fpat++ = '\0';
612 		}
613 		pat = strtok_r(fpat, csepr, &lasts);
614 	}
615 
616 	/* '!' introduces an exclusion list */
617 	if (pat != NULL && *pat == '!') {
618 		Dyp->exclude = 1;
619 		Dyp->internal = 1;
620 		pat += strspn(pat, "!");
621 		if (*pat == '\0')
622 			pat = strtok_r(NULL, sepr, &lasts);
623 	}
624 
625 	if (pat == NULL) {
626 		/* empty function list means exclude all functions */
627 		Dyp->sympat = my_malloc(sizeof (char *), NULL);
628 		Dyp->sympat[0] = star;
629 		Dyp->nsympat = 1;
630 	} else {
631 		/*
632 		 * We are now at the function list.
633 		 * Generate the list and count the symbol name patterns.
634 		 */
635 		maxpat = 1;
636 		Dyp->sympat = my_malloc(maxpat * sizeof (char *), NULL);
637 		Dyp->nsympat = 0;
638 		Dyp->sympat[Dyp->nsympat++] = pat;
639 		while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) {
640 			if (Dyp->nsympat == maxpat) {
641 				maxpat *= 2;
642 				Dyp->sympat = my_realloc(Dyp->sympat,
643 					maxpat * sizeof (char *), NULL);
644 			}
645 			Dyp->sympat[Dyp->nsympat++] = pat;
646 		}
647 	}
648 
649 	return (0);
650 }
651