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 */
43extern 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 */
54void	upcase(char *);
55
56const char white[] = " \t\n";	/* white space characters */
57const char sepr[] = " ,\t\n";	/* list separator characters */
58const 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 */
64int
65syslist(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 */
311int
312siglist(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 */
386int
387fltlist(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 */
463int
464fdlist(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
518void
519upcase(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 */
536int
537liblist(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