1191005Sdelphij/*-
2204977Simp * Copyright 1997 Sean Eric Fagan
331899Ssef *
431899Ssef * Redistribution and use in source and binary forms, with or without
531899Ssef * modification, are permitted provided that the following conditions
631899Ssef * are met:
731899Ssef * 1. Redistributions of source code must retain the above copyright
831899Ssef *    notice, this list of conditions and the following disclaimer.
931899Ssef * 2. Redistributions in binary form must reproduce the above copyright
1031899Ssef *    notice, this list of conditions and the following disclaimer in the
1131899Ssef *    documentation and/or other materials provided with the distribution.
1231899Ssef * 3. All advertising materials mentioning features or use of this software
1331899Ssef *    must display the following acknowledgement:
1431899Ssef *	This product includes software developed by Sean Eric Fagan
1531899Ssef * 4. Neither the name of the author may be used to endorse or promote
1631899Ssef *    products derived from this software without specific prior written
1731899Ssef *    permission.
1831899Ssef *
1931899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2031899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2131899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2231899Ssef * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2331899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2431899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2531899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2631899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2731899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2831899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2931899Ssef * SUCH DAMAGE.
3031899Ssef */
3131899Ssef
32119852Scharnier#include <sys/cdefs.h>
33119852Scharnier__FBSDID("$FreeBSD: releng/11.0/usr.bin/truss/main.c 295930 2016-02-23 19:56:29Z jhb $");
3432275Scharnier
3531899Ssef/*
36222103Sbcr * The main module for truss.  Surprisingly simple, but, then, the other
3731567Ssef * files handle the bulk of the work.  And, of course, the kernel has to
3831567Ssef * do a lot of the work :).
3931567Ssef */
4031567Ssef
41288424Sjhb#include <sys/ptrace.h>
4285301Sdes
4332275Scharnier#include <err.h>
4432275Scharnier#include <signal.h>
4531567Ssef#include <stdio.h>
4631567Ssef#include <stdlib.h>
47294849Sjhb#include <sysdecode.h>
48101423Smdodd#include <time.h>
4931579Speter#include <unistd.h>
5031567Ssef
51101282Smdodd#include "truss.h"
5287703Smarkm#include "extern.h"
53192025Sdds#include "syscall.h"
5431567Ssef
55144177Salfredstatic void
5632275Scharnierusage(void)
5732275Scharnier{
58144177Salfred	fprintf(stderr, "%s\n%s\n",
59192025Sdds	    "usage: truss [-cfaedDS] [-o file] [-s strsize] -p pid",
60192025Sdds	    "       truss [-cfaedDS] [-o file] [-s strsize] command [args]");
61144177Salfred	exit(1);
6231567Ssef}
6331567Ssef
64132306Salfredchar *
65132306Salfredstrsig(int sig)
66132306Salfred{
67286913Sjhb	static char tmp[64];
68132306Salfred
69132306Salfred	if (sig > 0 && sig < NSIG) {
70286913Sjhb		snprintf(tmp, sizeof(tmp), "SIG%s", sys_signame[sig]);
71286913Sjhb		return (tmp);
72132306Salfred	}
73286913Sjhb	return (NULL);
74132306Salfred}
75132306Salfred
7632275Scharnierint
77144177Salfredmain(int ac, char **av)
78144177Salfred{
79240393Szont	struct sigaction sa;
80240005Szont	struct trussinfo *trussinfo;
81144178Salfred	char *fname;
82240005Szont	char **command;
83288424Sjhb	pid_t pid;
84288424Sjhb	int c;
8531567Ssef
86144178Salfred	fname = NULL;
87144178Salfred
88144177Salfred	/* Initialize the trussinfo struct */
89192153Sdelphij	trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
90144177Salfred	if (trussinfo == NULL)
91192153Sdelphij		errx(1, "calloc() failed");
92192153Sdelphij
93288424Sjhb	pid = 0;
94144177Salfred	trussinfo->outfile = stderr;
95153963Sbrian	trussinfo->strsize = 32;
96168569Sdelphij	trussinfo->curthread = NULL;
97288424Sjhb	LIST_INIT(&trussinfo->proclist);
98288832Sbdrewery	init_syscalls();
99295930Sjhb	while ((c = getopt(ac, av, "p:o:facedDs:SH")) != -1) {
100144177Salfred		switch (c) {
101144177Salfred		case 'p':	/* specified pid */
102288424Sjhb			pid = atoi(optarg);
103171055Sdelphij			/* make sure i don't trace me */
104288424Sjhb			if (pid == getpid()) {
105288424Sjhb				errx(2, "attempt to grab self.");
106171055Sdelphij			}
107144177Salfred			break;
108144177Salfred		case 'f': /* Follow fork()'s */
109144177Salfred			trussinfo->flags |= FOLLOWFORKS;
110144177Salfred			break;
111144177Salfred		case 'a': /* Print execve() argument strings. */
112144177Salfred			trussinfo->flags |= EXECVEARGS;
113144177Salfred			break;
114192025Sdds		case 'c': /* Count number of system calls and time. */
115289080Sbdrewery			trussinfo->flags |= (COUNTONLY | NOSIGS);
116192025Sdds			break;
117144177Salfred		case 'e': /* Print execve() environment strings. */
118144177Salfred			trussinfo->flags |= EXECVEENVS;
119144177Salfred			break;
120144177Salfred		case 'd': /* Absolute timestamps */
121144177Salfred			trussinfo->flags |= ABSOLUTETIMESTAMPS;
122144177Salfred			break;
123144177Salfred		case 'D': /* Relative timestamps */
124144177Salfred			trussinfo->flags |= RELATIVETIMESTAMPS;
125144177Salfred			break;
126144177Salfred		case 'o':	/* Specified output file */
127144177Salfred			fname = optarg;
128144177Salfred			break;
129153963Sbrian		case 's':	/* Specified string size */
130153963Sbrian			trussinfo->strsize = atoi(optarg);
131153963Sbrian			break;
132240005Szont		case 'S':	/* Don't trace signals */
133144177Salfred			trussinfo->flags |= NOSIGS;
134144177Salfred			break;
135295930Sjhb		case 'H':
136295930Sjhb			trussinfo->flags |= DISPLAYTIDS;
137295930Sjhb			break;
138144177Salfred		default:
139144177Salfred			usage();
140144177Salfred		}
141144177Salfred	}
14231567Ssef
143144177Salfred	ac -= optind; av += optind;
144288424Sjhb	if ((pid == 0 && ac == 0) ||
145288424Sjhb	    (pid != 0 && ac != 0))
146144177Salfred		usage();
14731567Ssef
148144177Salfred	if (fname != NULL) { /* Use output file */
149215235Sjh		/*
150245957Smjg		 * Set close-on-exec ('e'), so that the output file is not
151245957Smjg		 * shared with the traced process.
152215235Sjh		 */
153245957Smjg		if ((trussinfo->outfile = fopen(fname, "we")) == NULL)
154245957Smjg			err(1, "cannot open %s", fname);
155144177Salfred	}
15632275Scharnier
157144177Salfred	/*
158144177Salfred	 * If truss starts the process itself, it will ignore some signals --
159144177Salfred	 * they should be passed off to the process, which may or may not
160144177Salfred	 * exit.  If, however, we are examining an already-running process,
161144177Salfred	 * then we restore the event mask on these same signals.
162144177Salfred	 */
163288424Sjhb	if (pid == 0) {
164288424Sjhb		/* Start a command ourselves */
165144177Salfred		command = av;
166288424Sjhb		setup_and_wait(trussinfo, command);
167144177Salfred		signal(SIGINT, SIG_IGN);
168144177Salfred		signal(SIGTERM, SIG_IGN);
169144177Salfred		signal(SIGQUIT, SIG_IGN);
170144177Salfred	} else {
171240393Szont		sa.sa_handler = restore_proc;
172240393Szont		sa.sa_flags = 0;
173240393Szont		sigemptyset(&sa.sa_mask);
174240393Szont		sigaction(SIGINT, &sa, NULL);
175240393Szont		sigaction(SIGQUIT, &sa, NULL);
176240393Szont		sigaction(SIGTERM, &sa, NULL);
177288424Sjhb		start_tracing(trussinfo, pid);
178144177Salfred	}
17931567Ssef
180144177Salfred	/*
181144177Salfred	 * At this point, if we started the process, it is stopped waiting to
182144177Salfred	 * be woken up, either in exit() or in execve().
183144177Salfred	 */
184288424Sjhb	if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) {
185288424Sjhb		/*
186288424Sjhb		 * If we are not able to handle this ABI, detach from the
187288424Sjhb		 * process and exit.  If we just created a new process to
188288424Sjhb		 * run a command, kill the new process rather than letting
189288424Sjhb		 * it run untraced.
190288424Sjhb		 */
191288424Sjhb		if (pid == 0)
192288424Sjhb			kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL);
193288424Sjhb		ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL,
194288424Sjhb		    0);
195288424Sjhb		return (1);
196288424Sjhb	}
197288424Sjhb	ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1,
198288424Sjhb	    0);
19931567Ssef
200144177Salfred	/*
201144177Salfred	 * At this point, it's a simple loop, waiting for the process to
202144177Salfred	 * stop, finding out why, printing out why, and then continuing it.
203144177Salfred	 * All of the grunt work is done in the support routines.
204144177Salfred	 */
205144177Salfred	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
206101285Smdodd
207288424Sjhb	eventloop(trussinfo);
20831567Ssef
209240005Szont	if (trussinfo->flags & COUNTONLY)
210240005Szont		print_summary(trussinfo);
211192025Sdds
212192025Sdds	fflush(trussinfo->outfile);
213192025Sdds
214144177Salfred	return (0);
21531567Ssef}
216