main.c revision 31579
131567Ssef/* 231567Ssef * The main module for truss. Suprisingly simple, but, then, the other 331567Ssef * files handle the bulk of the work. And, of course, the kernel has to 431567Ssef * do a lot of the work :). 531567Ssef */ 631567Ssef/* 731579Speter * $Id: main.c,v 1.1 1997/12/06 05:23:03 sef Exp $ 831567Ssef */ 931567Ssef 1031567Ssef#include <stdio.h> 1131567Ssef#include <stdlib.h> 1231567Ssef#include <string.h> 1331567Ssef#include <errno.h> 1431567Ssef#include <err.h> 1531567Ssef#include <signal.h> 1631567Ssef#include <fcntl.h> 1731579Speter#include <unistd.h> 1831567Ssef#include <sys/ioctl.h> 1931567Ssef#include <sys/pioctl.h> 2031567Ssef 2131567Ssefextern int setup_and_wait(char **); 2231567Ssefextern int start_tracing(int, int); 2331567Ssefextern void i386_syscall_entry(int, int); 2431567Ssefextern void i386_syscall_exit(int, int); 2531567Ssefextern void i386_linux_syscall_entry(int, int); 2631567Ssefextern void i386_linux_syscall_exit(int, int); 2731567Ssef 2831567Ssef/* 2931567Ssef * These should really be parameterized -- I don't like having globals, 3031567Ssef * but this is the easiest way, right now, to deal with them. 3131567Ssef */ 3231567Ssef 3331567Ssefint pid = 0; 3431567Ssefint nosigs = 0; 3531567SsefFILE *outfile = stderr; 3631567Ssefchar *prog; 3731567Ssefint Procfd; 3831567Ssefchar progtype[50]; /* OS and type of executable */ 3931567Ssef 4031567Ssefstatic inline void 4131567Ssefusage(void) { 4231567Ssef fprintf(stderr, "usage: %s [-o <file>] [-S] { [-p <pid> ] | " 4331567Ssef "[ <command> <args>] }\n", prog); 4431567Ssef exit(1); 4531567Ssef} 4631567Ssef 4731567Ssefstruct ex_types { 4831567Ssef char *type; 4931567Ssef void (*enter_syscall)(int, int); 5031567Ssef void (*exit_syscall)(int, int); 5131567Ssef} ex_types[] = { 5231567Ssef { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit }, 5331567Ssef { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit }, 5431567Ssef { 0, 0, 0 }, 5531567Ssef}; 5631567Ssef 5731567Ssef/* 5831567Ssef * Set the execution type. This is called after every exec, and when 5931567Ssef * a process is first monitored. The procfs pseudo-file "etype" has 6031567Ssef * the execution module type -- see /proc/curproc/etype for an example. 6131567Ssef */ 6231567Ssef 6331567Ssefstatic struct ex_types * 6431567Ssefset_etype() { 6531567Ssef struct ex_types *funcs; 6631567Ssef char etype[24]; 6731567Ssef char progtype[32]; 6831567Ssef int fd; 6931567Ssef 7031567Ssef sprintf(etype, "/proc/%d/etype", pid); 7131567Ssef if ((fd = open(etype, O_RDONLY)) == -1) { 7231567Ssef strcpy(progtype, "FreeBSD a.out"); 7331567Ssef } else { 7431567Ssef int len = read(fd, progtype, sizeof(progtype)); 7531567Ssef progtype[len-1] = '\0'; 7631567Ssef close(etype); 7731567Ssef } 7831567Ssef 7931567Ssef for (funcs = ex_types; funcs->type; funcs++) 8031567Ssef if (!strcmp(funcs->type, progtype)) 8131567Ssef break; 8231567Ssef 8331567Ssef return funcs; 8431567Ssef} 8531567Ssef 8631567Ssefmain(int ac, char **av) { 8731567Ssef int mask; 8831567Ssef int c; 8931567Ssef int i; 9031567Ssef char **command; 9131567Ssef struct procfs_status pfs; 9231567Ssef char etype[25]; 9331567Ssef struct ex_types *funcs; 9431567Ssef int fd; 9531567Ssef int in_exec = 0; 9631567Ssef 9731567Ssef prog = av[0]; 9831567Ssef 9931567Ssef while ((c = getopt(ac, av, "p:o:S")) != EOF) { 10031567Ssef switch (c) { 10131567Ssef case 'p': /* specified pid */ 10231567Ssef pid = atoi(optarg); 10331567Ssef break; 10431567Ssef case 'o': /* Specified output file */ 10531567Ssef if ((outfile = fopen(optarg, "w")) == NULL) { 10631567Ssef fprintf (stderr, "%s: cannot open %s\n", av[0], optarg); 10731567Ssef exit(1); 10831567Ssef } 10931567Ssef break; 11031567Ssef case 'S': /* Don't trace signals */ 11131567Ssef nosigs = 1; 11231567Ssef break; 11331567Ssef default: 11431567Ssef usage(); 11531567Ssef } 11631567Ssef } 11731567Ssef 11831567Ssef ac -= optind; av += optind; 11931567Ssef if (ac && pid != 0) 12031567Ssef usage(); 12131567Ssef 12231567Ssef /* 12331567Ssef * If truss starts the process itself, it will ignore some signals -- 12431567Ssef * they should be passed off to the process, which may or may not 12531567Ssef * exit. If, however, we are examining an already-running process, 12631567Ssef * then we restore the event mask on these same signals. 12731567Ssef */ 12831567Ssef 12931567Ssef if (pid == 0) { /* Start a command ourselves */ 13031567Ssef command = av; 13131567Ssef pid = setup_and_wait(command); 13231567Ssef signal(SIGINT, SIG_IGN); 13331567Ssef signal(SIGTERM, SIG_IGN); 13431567Ssef signal(SIGQUIT, SIG_IGN); 13531567Ssef } else { 13631567Ssef extern void restore_proc(int); 13731567Ssef signal(SIGINT, restore_proc); 13831567Ssef signal(SIGTERM, restore_proc); 13931567Ssef signal(SIGQUIT, restore_proc); 14031567Ssef } 14131567Ssef 14231567Ssef 14331567Ssef /* 14431567Ssef * At this point, if we started the process, it is stopped waiting to 14531567Ssef * be woken up, either in exit() or in execve(). 14631567Ssef */ 14731567Ssef 14831567Ssef Procfd = start_tracing(pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | 14931567Ssef (nosigs ? 0 : S_SIG)); 15031567Ssef pfs.why = 0; 15131567Ssef 15231567Ssef funcs = set_etype(); 15331567Ssef /* 15431567Ssef * At this point, it's a simple loop, waiting for the process to 15531567Ssef * stop, finding out why, printing out why, and then continuing it. 15631567Ssef * All of the grunt work is done in the support routines. 15731567Ssef */ 15831567Ssef 15931567Ssef do { 16031567Ssef int val = 0; 16131567Ssef 16231567Ssef if (ioctl(Procfd, PIOCWAIT, &pfs) == -1) 16331567Ssef perror("PIOCWAIT top of loop"); 16431567Ssef else { 16531567Ssef switch(i = pfs.why) { 16631567Ssef case S_SCE: 16731567Ssef funcs->enter_syscall(pid, pfs.val); 16831567Ssef break; 16931567Ssef case S_SCX: 17031567Ssef /* 17131567Ssef * This is so we don't get two messages for an exec -- one 17231567Ssef * for the S_EXEC, and one for the syscall exit. It also, 17331567Ssef * conveniently, ensures that the first message printed out 17431567Ssef * isn't the return-from-syscall used to create the process. 17531567Ssef */ 17631567Ssef 17731567Ssef if (in_exec) { 17831567Ssef in_exec = 0; 17931567Ssef break; 18031567Ssef } 18131567Ssef funcs->exit_syscall(pid, pfs.val); 18231567Ssef break; 18331567Ssef case S_SIG: 18431567Ssef fprintf(outfile, "SIGNAL %d\n", pfs.val); 18531567Ssef break; 18631567Ssef case S_EXIT: 18731567Ssef fprintf (outfile, "process exit, rval = %d\n", pfs.val); 18831567Ssef break; 18931567Ssef case S_EXEC: 19031567Ssef funcs = set_etype(); 19131567Ssef in_exec = 1; 19231567Ssef break; 19331567Ssef default: 19431567Ssef fprintf (outfile, "Process stopped because of: %d\n", i); 19531567Ssef break; 19631567Ssef } 19731567Ssef } 19831567Ssef if (ioctl(Procfd, PIOCCONT, &val) == -1) 19931567Ssef perror("PIOCCONT"); 20031567Ssef } while (pfs.why != S_EXIT); 20131567Ssef return 0; 20231567Ssef} 203