xref: /titanic_50/usr/src/cmd/abi/apptracecmd/apptrace.c (revision f07a2a2ef3832ccd4e9e1584966c139773495d2d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22*f07a2a2eScraigm 
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <unistd.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/wait.h>
367c478bd9Sstevel@tonic-gate #include <apptrace.h>
377c478bd9Sstevel@tonic-gate #include <libintl.h>
387c478bd9Sstevel@tonic-gate #include <locale.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #ifdef TRUE
417c478bd9Sstevel@tonic-gate #undef TRUE
427c478bd9Sstevel@tonic-gate #endif
437c478bd9Sstevel@tonic-gate #ifdef FALSE
447c478bd9Sstevel@tonic-gate #undef FALSE
457c478bd9Sstevel@tonic-gate #endif
467c478bd9Sstevel@tonic-gate #define	TRUE  1
477c478bd9Sstevel@tonic-gate #define	FALSE 0
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /* Various list pointers */
507c478bd9Sstevel@tonic-gate static char *fromlist;
517c478bd9Sstevel@tonic-gate static char *fromexcl;
527c478bd9Sstevel@tonic-gate static char *tolist;
537c478bd9Sstevel@tonic-gate static char *toexcl;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate static char *iflist;
567c478bd9Sstevel@tonic-gate static char *ifexcl;
577c478bd9Sstevel@tonic-gate static char *viflist;
587c478bd9Sstevel@tonic-gate static char *vifexcl;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /* The supported options */
617c478bd9Sstevel@tonic-gate static char const *optlet = "F:fo:T:t:v:";
627c478bd9Sstevel@tonic-gate /* basename(argv[0]) */
637c478bd9Sstevel@tonic-gate static char const *command;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /* The environment variables that'll get picked up by apptrace.so.1 */
667c478bd9Sstevel@tonic-gate static char const *APPTRACE_BINDTO = "APPTRACE_BINDTO=";
677c478bd9Sstevel@tonic-gate static char const *APPTRACE_BINDTO_EXCLUDE = "APPTRACE_BINDTO_EXCLUDE=";
687c478bd9Sstevel@tonic-gate static char const *APPTRACE_BINDFROM = "APPTRACE_BINDFROM=";
697c478bd9Sstevel@tonic-gate static char const *APPTRACE_BINDFROM_EXCLUDE = "APPTRACE_BINDFROM_EXCLUDE=";
707c478bd9Sstevel@tonic-gate static char const *APPTRACE_OUTPUT = "APPTRACE_OUTPUT=";
717c478bd9Sstevel@tonic-gate static char const *APPTRACE_PID = "APPTRACE_PID=";
727c478bd9Sstevel@tonic-gate static char const *APPTRACE_INTERFACES = "APPTRACE_INTERFACES=";
737c478bd9Sstevel@tonic-gate static char const *APPTRACE_INTERFACES_EXCLUDE = "APPTRACE_INTERFACES_EXCLUDE=";
747c478bd9Sstevel@tonic-gate static char const *APPTRACE_VERBOSE = "APPTRACE_VERBOSE=";
757c478bd9Sstevel@tonic-gate static char const *APPTRACE_VERBOSE_EXCLUDE = "APPTRACE_VERBOSE_EXCLUDE=";
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /* Some default values for the above */
787c478bd9Sstevel@tonic-gate static char *LD_AUDIT = "LD_AUDIT=/usr/lib/abi/apptrace.so.1";
797c478bd9Sstevel@tonic-gate #if	defined(sparc) || defined(__sparcv9)
807c478bd9Sstevel@tonic-gate static char *LD_AUDIT_64 =
817c478bd9Sstevel@tonic-gate 	"LD_AUDIT_64=/usr/lib/abi/sparcv9/apptrace.so.1";
827c478bd9Sstevel@tonic-gate #elif	defined(i386) || defined(__amd64)
837c478bd9Sstevel@tonic-gate static char *LD_AUDIT_64 =
847c478bd9Sstevel@tonic-gate 	"LD_AUDIT_64=/usr/lib/abi/amd64/apptrace.so.1";
857c478bd9Sstevel@tonic-gate #else
867c478bd9Sstevel@tonic-gate #error Unsupported Platform
877c478bd9Sstevel@tonic-gate #endif
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static char const *one = "1";
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /* The local support functions */
927c478bd9Sstevel@tonic-gate static void usage(char const *);
937c478bd9Sstevel@tonic-gate static void stuffenv(char const *, char const *);
947c478bd9Sstevel@tonic-gate static char *buildlist(char **, char const *);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate int
977c478bd9Sstevel@tonic-gate main(int argc, char **argv)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	int	opt;
1007c478bd9Sstevel@tonic-gate 	int	fflag = FALSE;
1017c478bd9Sstevel@tonic-gate 	int	errflg = FALSE;
1027c478bd9Sstevel@tonic-gate 	char	*outfile = NULL;
1037c478bd9Sstevel@tonic-gate 	int	stat_loc;
1047c478bd9Sstevel@tonic-gate 	pid_t	wret, pid;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1077c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
1087c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
1097c478bd9Sstevel@tonic-gate #endif
1107c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/* Squirrel the basename of the command name away. */
1147c478bd9Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
1157c478bd9Sstevel@tonic-gate 		command++;
1167c478bd9Sstevel@tonic-gate 	else
1177c478bd9Sstevel@tonic-gate 		command = argv[0];
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, optlet)) != EOF) {
1207c478bd9Sstevel@tonic-gate 		switch (opt) {
1217c478bd9Sstevel@tonic-gate 		case 'F':
1227c478bd9Sstevel@tonic-gate 			if (*optarg == '!')
1237c478bd9Sstevel@tonic-gate 				(void) buildlist(&fromexcl, optarg + 1);
1247c478bd9Sstevel@tonic-gate 			else
1257c478bd9Sstevel@tonic-gate 				(void) buildlist(&fromlist, optarg);
1267c478bd9Sstevel@tonic-gate 			break;
1277c478bd9Sstevel@tonic-gate 		case 'f':
1287c478bd9Sstevel@tonic-gate 			fflag = TRUE;
1297c478bd9Sstevel@tonic-gate 			break;
1307c478bd9Sstevel@tonic-gate 		case 'o':
1317c478bd9Sstevel@tonic-gate 			outfile = optarg;
1327c478bd9Sstevel@tonic-gate 			break;
1337c478bd9Sstevel@tonic-gate 		case 'T':
1347c478bd9Sstevel@tonic-gate 			if (*optarg == '!')
1357c478bd9Sstevel@tonic-gate 				(void) buildlist(&toexcl, optarg + 1);
1367c478bd9Sstevel@tonic-gate 			else
1377c478bd9Sstevel@tonic-gate 				(void) buildlist(&tolist, optarg);
1387c478bd9Sstevel@tonic-gate 			break;
1397c478bd9Sstevel@tonic-gate 		case 't':
1407c478bd9Sstevel@tonic-gate 			if (*optarg == '!')
1417c478bd9Sstevel@tonic-gate 				(void) buildlist(&ifexcl, optarg + 1);
1427c478bd9Sstevel@tonic-gate 			else
1437c478bd9Sstevel@tonic-gate 				(void) buildlist(&iflist, optarg);
1447c478bd9Sstevel@tonic-gate 			break;
1457c478bd9Sstevel@tonic-gate 		case 'v':
1467c478bd9Sstevel@tonic-gate 			if (*optarg == '!')
1477c478bd9Sstevel@tonic-gate 				(void) buildlist(&vifexcl, optarg + 1);
1487c478bd9Sstevel@tonic-gate 			else
1497c478bd9Sstevel@tonic-gate 				(void) buildlist(&viflist, optarg);
1507c478bd9Sstevel@tonic-gate 			break;
1517c478bd9Sstevel@tonic-gate 		default:
1527c478bd9Sstevel@tonic-gate 			errflg = TRUE;
1537c478bd9Sstevel@tonic-gate 			break;
1547c478bd9Sstevel@tonic-gate 		}
1557c478bd9Sstevel@tonic-gate 	}
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	/*
1587c478bd9Sstevel@tonic-gate 	 * Whack the argument vector so that the remainder will be
1597c478bd9Sstevel@tonic-gate 	 * ready for passing to exec
1607c478bd9Sstevel@tonic-gate 	 */
1617c478bd9Sstevel@tonic-gate 	argc -= optind;
1627c478bd9Sstevel@tonic-gate 	argv += optind;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	/*
1657c478bd9Sstevel@tonic-gate 	 * If there was a problem with the options, or there was no command
1667c478bd9Sstevel@tonic-gate 	 * to be run, then give the usage message and bugout.
1677c478bd9Sstevel@tonic-gate 	 */
1687c478bd9Sstevel@tonic-gate 	if (errflg || argc <= 0) {
1697c478bd9Sstevel@tonic-gate 		usage(command);
1707c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	/*
1747c478bd9Sstevel@tonic-gate 	 * This is where the environment gets setup.
1757c478bd9Sstevel@tonic-gate 	 */
1767c478bd9Sstevel@tonic-gate 	if (fflag == TRUE)
1777c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_PID, one);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	if (fromexcl != NULL)
1807c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_BINDFROM_EXCLUDE, fromexcl);
1817c478bd9Sstevel@tonic-gate 	if (fromlist != NULL)
1827c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_BINDFROM, fromlist);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	if (tolist != NULL)
1857c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_BINDTO, tolist);
1867c478bd9Sstevel@tonic-gate 	if (toexcl != NULL)
1877c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_BINDTO_EXCLUDE, toexcl);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	if (iflist != NULL)
1907c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_INTERFACES, iflist);
1917c478bd9Sstevel@tonic-gate 	if (ifexcl != NULL)
1927c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_INTERFACES_EXCLUDE, ifexcl);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	if (viflist != NULL)
1957c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_VERBOSE, viflist);
1967c478bd9Sstevel@tonic-gate 	if (vifexcl != NULL)
1977c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_VERBOSE_EXCLUDE, vifexcl);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if (outfile != NULL)
2007c478bd9Sstevel@tonic-gate 		stuffenv(APPTRACE_OUTPUT, outfile);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/*
2037c478bd9Sstevel@tonic-gate 	 * It is the setting of the LD_AUDIT environment variable
2047c478bd9Sstevel@tonic-gate 	 * that tells ld.so.1 to enable link auditing when the child
2057c478bd9Sstevel@tonic-gate 	 * is exec()ed.
2067c478bd9Sstevel@tonic-gate 	 */
2077c478bd9Sstevel@tonic-gate 	(void) putenv(LD_AUDIT);
2087c478bd9Sstevel@tonic-gate 	(void) putenv(LD_AUDIT_64);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	/*
2117c478bd9Sstevel@tonic-gate 	 * The environment is now all setup.
2127c478bd9Sstevel@tonic-gate 	 * For those about to rock, we salute you!
2137c478bd9Sstevel@tonic-gate 	 */
2147c478bd9Sstevel@tonic-gate 	pid = fork();
2157c478bd9Sstevel@tonic-gate 	switch (pid) {
2167c478bd9Sstevel@tonic-gate 		/* Error */
2177c478bd9Sstevel@tonic-gate 	case -1:
2187c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: fork failed: %s\n"),
2197c478bd9Sstevel@tonic-gate 		    command, strerror(errno));
2207c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2217c478bd9Sstevel@tonic-gate 		break;
2227c478bd9Sstevel@tonic-gate 		/* Child */
2237c478bd9Sstevel@tonic-gate 	case 0:
2247c478bd9Sstevel@tonic-gate 		/*
2257c478bd9Sstevel@tonic-gate 		 * Usual failure is argv[0] does not exist or is
2267c478bd9Sstevel@tonic-gate 		 * not executable.
2277c478bd9Sstevel@tonic-gate 		 */
2287c478bd9Sstevel@tonic-gate 		if (execvp(argv[0], argv)) {
2297c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: %s: %s\n"),
2307c478bd9Sstevel@tonic-gate 			    command, argv[0], strerror(errno));
2317c478bd9Sstevel@tonic-gate 			_exit(EXIT_FAILURE);
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 		break;
2347c478bd9Sstevel@tonic-gate 		/* Parent */
2357c478bd9Sstevel@tonic-gate 	default:
2367c478bd9Sstevel@tonic-gate 		wret = waitpid(pid, &stat_loc, 0);
2377c478bd9Sstevel@tonic-gate 		if (wret == -1) {
2387c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2397c478bd9Sstevel@tonic-gate 			    gettext("%s: waitpid failed: %s\n"),
2407c478bd9Sstevel@tonic-gate 			    command, strerror(errno));
2417c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
2427c478bd9Sstevel@tonic-gate 		}
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 		if (wret != pid) {
2457c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2467c478bd9Sstevel@tonic-gate 			    gettext("%s: "
2477c478bd9Sstevel@tonic-gate 			    "waitpid returned %ld when child pid was %ld\n"),
2487c478bd9Sstevel@tonic-gate 			    command, wret, pid);
2497c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
2507c478bd9Sstevel@tonic-gate 		}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 		if (WIFSIGNALED(stat_loc)) {
2537c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("\n%s: %s: %s"),
2547c478bd9Sstevel@tonic-gate 			    command, argv[0], strsignal(WTERMSIG(stat_loc)));
2557c478bd9Sstevel@tonic-gate 			if (WCOREDUMP(stat_loc)) {
2567c478bd9Sstevel@tonic-gate 				(void) fputs(gettext("(Core dump)"), stderr);
2577c478bd9Sstevel@tonic-gate #ifdef DEBUG
2587c478bd9Sstevel@tonic-gate 				(void) fputs(gettext("\nRunning pstack:\n"),
2597c478bd9Sstevel@tonic-gate 				    stderr);
2607c478bd9Sstevel@tonic-gate 				(void) putenv("LD_AUDIT=");
2617c478bd9Sstevel@tonic-gate 				(void) putenv("LD_AUDIT_64=");
2627c478bd9Sstevel@tonic-gate 				(void) system("/usr/proc/bin/pstack core");
2637c478bd9Sstevel@tonic-gate #endif
2647c478bd9Sstevel@tonic-gate 			}
2657c478bd9Sstevel@tonic-gate 			(void) putc('\n', stderr);
2667c478bd9Sstevel@tonic-gate 		}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		/* Normal return from main() */
2697c478bd9Sstevel@tonic-gate 		return (WEXITSTATUS(stat_loc));
2707c478bd9Sstevel@tonic-gate 	}
271*f07a2a2eScraigm 	return (0);
2727c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate  * Take a string in the form "VAR=" and another in the
2777c478bd9Sstevel@tonic-gate  * form "value" and paste them together.
2787c478bd9Sstevel@tonic-gate  */
2797c478bd9Sstevel@tonic-gate static void
2807c478bd9Sstevel@tonic-gate stuffenv(char const *var, char const *val)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	int lenvar, lenval;
2837c478bd9Sstevel@tonic-gate 	char *stuff;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	lenvar = strlen(var);
2867c478bd9Sstevel@tonic-gate 	lenval = strlen(val);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	if ((stuff = malloc(lenvar + lenval + 1)) == NULL) {
2897c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: malloc failed\n"), command);
2907c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 	(void) sprintf(stuff, "%s%s", var, val);
2937c478bd9Sstevel@tonic-gate 	(void) putenv(stuff);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  * If *dst is empty, use strdup to duplicate src.
2987c478bd9Sstevel@tonic-gate  * Otherwise:  dst = dst + "," + src;
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate static char *
3017c478bd9Sstevel@tonic-gate buildlist(char **dst, char const *src)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	int len;
3047c478bd9Sstevel@tonic-gate 	char *p;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	/*
3077c478bd9Sstevel@tonic-gate 	 * If dst is still empty then dup,
3087c478bd9Sstevel@tonic-gate 	 * if dup succeeds set dst.
3097c478bd9Sstevel@tonic-gate 	 */
3107c478bd9Sstevel@tonic-gate 	if (*dst == NULL) {
3117c478bd9Sstevel@tonic-gate 		p = strdup(src);
3127c478bd9Sstevel@tonic-gate 		if (p == NULL)
3137c478bd9Sstevel@tonic-gate 			goto error;
3147c478bd9Sstevel@tonic-gate 		*dst = p;
3157c478bd9Sstevel@tonic-gate 		return (p);
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	len = strlen(*dst);
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/* +2 because of the comma we add below */
3217c478bd9Sstevel@tonic-gate 	if ((p = realloc(*dst, len + strlen(src) + 2)) == NULL)
3227c478bd9Sstevel@tonic-gate 		goto error;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	*dst = p;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	*(*dst + len) = ',';
3277c478bd9Sstevel@tonic-gate 	(void) strcpy((*dst + len + 1), src);
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	return (*dst);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate error:
3327c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: allocation failed: %s\n"),
3337c478bd9Sstevel@tonic-gate 	    command, strerror(errno));
3347c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
3357c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate static void
3397c478bd9Sstevel@tonic-gate usage(char const *prog)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Usage: %s [-f][-F [!]tracefromlist]"
3427c478bd9Sstevel@tonic-gate 	    "[-T [!]tracetolist][-o outputfile]\n"
3437c478bd9Sstevel@tonic-gate 	    "	[-t calls][-v calls] prog [prog arguments]\n"
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	    "	-F <bindfromlist>\n"
3467c478bd9Sstevel@tonic-gate 	    "		A comma separated list of libraries that are to be\n"
3477c478bd9Sstevel@tonic-gate 	    "		traced.  Only calls from these libraries will be\n"
3487c478bd9Sstevel@tonic-gate 	    "		traced.  The default is to trace calls from the\n"
3497c478bd9Sstevel@tonic-gate 	    "		main executable.\n"
3507c478bd9Sstevel@tonic-gate 	    "		If <bindfromlist> begins with a ! then it defines\n"
3517c478bd9Sstevel@tonic-gate 	    "		a list of libraries to exclude from the trace.\n"
3527c478bd9Sstevel@tonic-gate 	    "	-T <bindtolist>\n"
3537c478bd9Sstevel@tonic-gate 	    "		A comma separated list of libraries that are to be\n"
3547c478bd9Sstevel@tonic-gate 	    "		traced.  Only calls to these libraries will be\n"
3557c478bd9Sstevel@tonic-gate 	    "		traced.  The default is to trace all calls.\n"
3567c478bd9Sstevel@tonic-gate 	    "		If <bindtolist> begins with a ! then it defines\n"
3577c478bd9Sstevel@tonic-gate 	    "		a list of libraries to exclude from the trace.\n"
3587c478bd9Sstevel@tonic-gate 	    "	-o <outputfile>\n"
3597c478bd9Sstevel@tonic-gate 	    "		%s output will be directed to 'outputfile'.\n"
3607c478bd9Sstevel@tonic-gate 	    "		by default it is placed on stderr\n"
3617c478bd9Sstevel@tonic-gate 	    "	-f\n"
3627c478bd9Sstevel@tonic-gate 	    "		Follow all children created by fork() and also\n"
3637c478bd9Sstevel@tonic-gate 	    "		print apptrace output for the children.  This also\n"
3647c478bd9Sstevel@tonic-gate 	    "		causes a 'pid' to be added to each output line\n"
3657c478bd9Sstevel@tonic-gate 	    "	-t <tracelist>\n"
3667c478bd9Sstevel@tonic-gate 	    "		A comma separated list of interfaces to trace.\n"
3677c478bd9Sstevel@tonic-gate 	    "		A list preceded by ! is an exlusion list.\n"
3687c478bd9Sstevel@tonic-gate 	    "	-v <verboselist>\n"
3697c478bd9Sstevel@tonic-gate 	    "		A comman separated list of interfaces to trace\n"
3707c478bd9Sstevel@tonic-gate 	    "		verbosely.\n"
3717c478bd9Sstevel@tonic-gate 	    "		A list preceded by ! is an exclusion list.\n"
3727c478bd9Sstevel@tonic-gate 	    "		Interfaces matched in -v do not also need to be\n"
3737c478bd9Sstevel@tonic-gate 	    "		named by -t\n"
3747c478bd9Sstevel@tonic-gate 	    "	All lists may use shell style wild cards.\n"
3757c478bd9Sstevel@tonic-gate 	    "	Leading path components or suffixes are not required when\n"
3767c478bd9Sstevel@tonic-gate 	    "	listing libraries (ie. libc will match /usr/lib/libc.so.1).\n"),
3777c478bd9Sstevel@tonic-gate 	    prog, prog);
3787c478bd9Sstevel@tonic-gate }
379