diff options
author | Alfred Perlstein <alfred@FreeBSD.org> | 2005-03-27 12:47:04 +0000 |
---|---|---|
committer | Alfred Perlstein <alfred@FreeBSD.org> | 2005-03-27 12:47:04 +0000 |
commit | 5321ae8649f5b7d80cd7d870892941c2bd04f91e (patch) | |
tree | 2455ba9de956e732e4192e0e6894a749db47fa75 /usr.bin | |
parent | e0c8c9460c51199bf09838f2d5b8defa0e9fc80f (diff) | |
download | src-5321ae8649f5b7d80cd7d870892941c2bd04f91e.tar.gz src-5321ae8649f5b7d80cd7d870892941c2bd04f91e.zip |
I've been working on this somewhat so I'm moving the
parts I'm touching to be as style(9) compliant as I can.
Notes
Notes:
svn path=/head/; revision=144177
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/truss/main.c | 449 | ||||
-rw-r--r-- | usr.bin/truss/setup.c | 193 |
2 files changed, 329 insertions, 313 deletions
diff --git a/usr.bin/truss/main.c b/usr.bin/truss/main.c index 8822d9ed32b3..ce61db26fe95 100644 --- a/usr.bin/truss/main.c +++ b/usr.bin/truss/main.c @@ -66,13 +66,13 @@ __FBSDID("$FreeBSD$"); int Procfd; -static __inline void +static void usage(void) { - fprintf(stderr, "%s\n%s\n", - "usage: truss [-faedDS] [-o file] -p pid", - " truss [-faedDS] [-o file] command [args]"); - exit(1); + fprintf(stderr, "%s\n%s\n", + "usage: truss [-faedDS] [-o file] -p pid", + " truss [-faedDS] [-o file] command [args]"); + exit(1); } /* @@ -80,29 +80,29 @@ usage(void) * work correctly. */ struct ex_types { - const char *type; - void (*enter_syscall)(struct trussinfo *, int); - long (*exit_syscall)(struct trussinfo *, int); + const char *type; + void (*enter_syscall)(struct trussinfo *, int); + long (*exit_syscall)(struct trussinfo *, int); } ex_types[] = { #ifdef __alpha__ - { "FreeBSD ELF", alpha_syscall_entry, alpha_syscall_exit }, + { "FreeBSD ELF", alpha_syscall_entry, alpha_syscall_exit }, #endif #ifdef __amd64__ - { "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit }, + { "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit }, #endif #ifdef __i386__ - { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit }, - { "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit }, - { "FreeBSD ELF32", i386_syscall_entry, i386_syscall_exit }, - { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit }, + { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit }, + { "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit }, + { "FreeBSD ELF32", i386_syscall_entry, i386_syscall_exit }, + { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit }, #endif #ifdef __ia64__ - { "FreeBSD ELF64", ia64_syscall_entry, ia64_syscall_exit }, + { "FreeBSD ELF64", ia64_syscall_entry, ia64_syscall_exit }, #endif #ifdef __sparc64__ - { "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit }, + { "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit }, #endif - { 0, 0, 0 }, + { 0, 0, 0 }, }; /* @@ -112,31 +112,32 @@ struct ex_types { */ static struct ex_types * -set_etype(struct trussinfo *trussinfo) { - struct ex_types *funcs; - char etype[24]; - char progt[32]; - int fd; - - sprintf(etype, "/proc/%d/etype", trussinfo->pid); - if ((fd = open(etype, O_RDONLY)) == -1) { - strcpy(progt, "FreeBSD a.out"); - } else { - int len = read(fd, progt, sizeof(progt)); - progt[len-1] = '\0'; - close(fd); - } - - for (funcs = ex_types; funcs->type; funcs++) - if (!strcmp(funcs->type, progt)) - break; - - if (funcs->type == NULL) { - funcs = &ex_types[0]; - warn("execution type %s is not supported -- using %s", - progt, funcs->type); - } - return funcs; +set_etype(struct trussinfo *trussinfo) +{ + struct ex_types *funcs; + char etype[24]; + char progt[32]; + int fd; + + sprintf(etype, "/proc/%d/etype", trussinfo->pid); + if ((fd = open(etype, O_RDONLY)) == -1) { + strcpy(progt, "FreeBSD a.out"); + } else { + int len = read(fd, progt, sizeof(progt)); + progt[len-1] = '\0'; + close(fd); + } + + for (funcs = ex_types; funcs->type; funcs++) + if (!strcmp(funcs->type, progt)) + break; + + if (funcs->type == NULL) { + funcs = &ex_types[0]; + warn("execution type %s is not supported -- using %s", + progt, funcs->type); + } + return (funcs); } char * @@ -157,187 +158,199 @@ strsig(int sig) } int -main(int ac, char **av) { - int c; - int i; - char **command; - struct procfs_status pfs; - struct ex_types *funcs; - int in_exec = 0; - char *fname = NULL; - int sigexit = 0; - struct trussinfo *trussinfo; - char *signame; - - /* Initialize the trussinfo struct */ - trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo)); - if (trussinfo == NULL) - errx(1, "malloc() failed"); - bzero(trussinfo, sizeof(struct trussinfo)); - trussinfo->outfile = stderr; - - while ((c = getopt(ac, av, "p:o:faedDS")) != -1) { - switch (c) { - case 'p': /* specified pid */ - trussinfo->pid = atoi(optarg); - break; - case 'f': /* Follow fork()'s */ - trussinfo->flags |= FOLLOWFORKS; - break; - case 'a': /* Print execve() argument strings. */ - trussinfo->flags |= EXECVEARGS; - break; - case 'e': /* Print execve() environment strings. */ - trussinfo->flags |= EXECVEENVS; - break; - case 'd': /* Absolute timestamps */ - trussinfo->flags |= ABSOLUTETIMESTAMPS; - break; - case 'D': /* Relative timestamps */ - trussinfo->flags |= RELATIVETIMESTAMPS; - break; - case 'o': /* Specified output file */ - fname = optarg; - break; - case 'S': /* Don't trace signals */ - trussinfo->flags |= NOSIGS; - break; - default: - usage(); - } - } - - ac -= optind; av += optind; - if ((trussinfo->pid == 0 && ac == 0) || (trussinfo->pid != 0 && ac != 0)) - usage(); - - if (fname != NULL) { /* Use output file */ - if ((trussinfo->outfile = fopen(fname, "w")) == NULL) - errx(1, "cannot open %s", fname); - } - - /* - * If truss starts the process itself, it will ignore some signals -- - * they should be passed off to the process, which may or may not - * exit. If, however, we are examining an already-running process, - * then we restore the event mask on these same signals. - */ - - if (trussinfo->pid == 0) { /* Start a command ourselves */ - command = av; - trussinfo->pid = setup_and_wait(command); - signal(SIGINT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - } else { - signal(SIGINT, restore_proc); - signal(SIGTERM, restore_proc); - signal(SIGQUIT, restore_proc); - } - - - /* - * At this point, if we started the process, it is stopped waiting to - * be woken up, either in exit() or in execve(). - */ +main(int ac, char **av) +{ + int c; + int i; + char **command; + struct procfs_status pfs; + struct ex_types *funcs; + int in_exec = 0; + char *fname = NULL; + int sigexit = 0; + struct trussinfo *trussinfo; + char *signame; + + /* Initialize the trussinfo struct */ + trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo)); + if (trussinfo == NULL) + errx(1, "malloc() failed"); + bzero(trussinfo, sizeof(struct trussinfo)); + trussinfo->outfile = stderr; + + while ((c = getopt(ac, av, "p:o:faedDS")) != -1) { + switch (c) { + case 'p': /* specified pid */ + trussinfo->pid = atoi(optarg); + break; + case 'f': /* Follow fork()'s */ + trussinfo->flags |= FOLLOWFORKS; + break; + case 'a': /* Print execve() argument strings. */ + trussinfo->flags |= EXECVEARGS; + break; + case 'e': /* Print execve() environment strings. */ + trussinfo->flags |= EXECVEENVS; + break; + case 'd': /* Absolute timestamps */ + trussinfo->flags |= ABSOLUTETIMESTAMPS; + break; + case 'D': /* Relative timestamps */ + trussinfo->flags |= RELATIVETIMESTAMPS; + break; + case 'o': /* Specified output file */ + fname = optarg; + break; + case 'S': /* Don't trace signals */ + trussinfo->flags |= NOSIGS; + break; + default: + usage(); + } + } + + ac -= optind; av += optind; + if ((trussinfo->pid == 0 && ac == 0) || + (trussinfo->pid != 0 && ac != 0)) + usage(); + + if (fname != NULL) { /* Use output file */ + if ((trussinfo->outfile = fopen(fname, "w")) == NULL) + errx(1, "cannot open %s", fname); + } -START_TRACE: - Procfd = start_tracing( - trussinfo->pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | - ((trussinfo->flags & NOSIGS) ? 0 : S_SIG), - ((trussinfo->flags & FOLLOWFORKS) ? PF_FORK : 0)); - if (Procfd == -1) - return 0; - - pfs.why = 0; - - funcs = set_etype(trussinfo); - /* - * At this point, it's a simple loop, waiting for the process to - * stop, finding out why, printing out why, and then continuing it. - * All of the grunt work is done in the support routines. - */ - - clock_gettime(CLOCK_REALTIME, &trussinfo->start_time); - - do { - int val = 0; - - if (ioctl(Procfd, PIOCWAIT, &pfs) == -1) - warn("PIOCWAIT top of loop"); - else { - switch(i = pfs.why) { - case S_SCE: - funcs->enter_syscall(trussinfo, pfs.val); - clock_gettime(CLOCK_REALTIME, &trussinfo->before); - break; - case S_SCX: - clock_gettime(CLOCK_REALTIME, &trussinfo->after); /* - * This is so we don't get two messages for an exec -- one - * for the S_EXEC, and one for the syscall exit. It also, - * conveniently, ensures that the first message printed out - * isn't the return-from-syscall used to create the process. + * If truss starts the process itself, it will ignore some signals -- + * they should be passed off to the process, which may or may not + * exit. If, however, we are examining an already-running process, + * then we restore the event mask on these same signals. */ - if (in_exec) { - in_exec = 0; - break; + if (trussinfo->pid == 0) { /* Start a command ourselves */ + command = av; + trussinfo->pid = setup_and_wait(command); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + } else { + signal(SIGINT, restore_proc); + signal(SIGTERM, restore_proc); + signal(SIGQUIT, restore_proc); } - if (trussinfo->in_fork && (trussinfo->flags & FOLLOWFORKS)) { - int childpid; - - trussinfo->in_fork = 0; - childpid = funcs->exit_syscall(trussinfo, pfs.val); - - /* - * Fork a new copy of ourself to trace the child of the - * original traced process. - */ - if (fork() == 0) { - trussinfo->pid = childpid; - goto START_TRACE; - } - break; - } - funcs->exit_syscall(trussinfo, pfs.val); - break; - case S_SIG: - signame = strsig(pfs.val); - fprintf(trussinfo->outfile, "SIGNAL %lu (%s)\n", pfs.val, - signame == NULL ? "?" : signame); - free(signame); - sigexit = pfs.val; - break; - case S_EXIT: - fprintf (trussinfo->outfile, "process exit, rval = %lu\n", pfs.val); - break; - case S_EXEC: + + /* + * At this point, if we started the process, it is stopped waiting to + * be woken up, either in exit() or in execve(). + */ + +START_TRACE: + Procfd = start_tracing( + trussinfo->pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | + ((trussinfo->flags & NOSIGS) ? 0 : S_SIG), + ((trussinfo->flags & FOLLOWFORKS) ? PF_FORK : 0)); + if (Procfd == -1) + return (0); + + pfs.why = 0; + funcs = set_etype(trussinfo); - in_exec = 1; - break; - default: - fprintf (trussinfo->outfile, "Process stopped because of: %d\n", i); - break; - } - } - if (ioctl(Procfd, PIOCCONT, val) == -1) { - if (kill(trussinfo->pid, 0) == -1 && errno == ESRCH) - break; - else - warn("PIOCCONT"); - } - } while (pfs.why != S_EXIT); - fflush(trussinfo->outfile); - if (sigexit) { - struct rlimit rlp; - - rlp.rlim_cur = 0; - rlp.rlim_max = 0; - setrlimit(RLIMIT_CORE, &rlp); - (void) signal(sigexit, SIG_DFL); - (void) kill(getpid(), sigexit); - } - return 0; + /* + * At this point, it's a simple loop, waiting for the process to + * stop, finding out why, printing out why, and then continuing it. + * All of the grunt work is done in the support routines. + */ + + clock_gettime(CLOCK_REALTIME, &trussinfo->start_time); + + do { + int val = 0; + + if (ioctl(Procfd, PIOCWAIT, &pfs) == -1) + warn("PIOCWAIT top of loop"); + else { + switch(i = pfs.why) { + case S_SCE: + funcs->enter_syscall(trussinfo, pfs.val); + clock_gettime(CLOCK_REALTIME, + &trussinfo->before); + break; + case S_SCX: + clock_gettime(CLOCK_REALTIME, + &trussinfo->after); + /* + * This is so we don't get two messages for + * an exec -- one for the S_EXEC, and one for + * the syscall exit. It also, conveniently, + * ensures that the first message printed out + * isn't the return-from-syscall used to + * create the process. + */ + if (in_exec) { + in_exec = 0; + break; + } + + if (trussinfo->in_fork && + (trussinfo->flags & FOLLOWFORKS)) { + int childpid; + + trussinfo->in_fork = 0; + childpid = + funcs->exit_syscall(trussinfo, + pfs.val); + + /* + * Fork a new copy of ourself to trace + * the child of the original traced + * process. + */ + if (fork() == 0) { + trussinfo->pid = childpid; + goto START_TRACE; + } + break; + } + funcs->exit_syscall(trussinfo, pfs.val); + break; + case S_SIG: + signame = strsig(pfs.val); + fprintf(trussinfo->outfile, + "SIGNAL %lu (%s)\n", pfs.val, + signame == NULL ? "?" : signame); + free(signame); + sigexit = pfs.val; + break; + case S_EXIT: + fprintf(trussinfo->outfile, + "process exit, rval = %lu\n", pfs.val); + break; + case S_EXEC: + funcs = set_etype(trussinfo); + in_exec = 1; + break; + default: + fprintf(trussinfo->outfile, + "Process stopped because of: %d\n", i); + break; + } + } + if (ioctl(Procfd, PIOCCONT, val) == -1) { + if (kill(trussinfo->pid, 0) == -1 && errno == ESRCH) + break; + else + warn("PIOCCONT"); + } + } while (pfs.why != S_EXIT); + fflush(trussinfo->outfile); + if (sigexit) { + struct rlimit rlp; + + rlp.rlim_cur = 0; + rlp.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlp); + (void) signal(sigexit, SIG_DFL); + (void) kill(getpid(), sigexit); + } + return (0); } diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c index 91cd1cf60cb4..fa52dd67ad7c 100644 --- a/usr.bin/truss/setup.c +++ b/usr.bin/truss/setup.c @@ -64,61 +64,62 @@ static int evflags = 0; */ int -setup_and_wait(char *command[]) { - struct procfs_status pfs; - char buf[32]; - int fd; - int pid; - int flags; - - pid = fork(); - if (pid == -1) { - err(1, "fork failed"); - } - if (pid == 0) { /* Child */ - int mask = S_EXEC | S_EXIT; - fd = open("/proc/curproc/mem", O_WRONLY); - if (fd == -1) - err(2, "cannot open /proc/curproc/mem"); - fcntl(fd, F_SETFD, 1); - if (ioctl(fd, PIOCBIS, mask) == -1) - err(3, "PIOCBIS"); - flags = PF_LINGER; - /* - * The PF_LINGER flag tells procfs not to wake up the - * process on last close; normally, this is the behaviour - * we want. - */ - if (ioctl(fd, PIOCSFL, flags) == -1) - warn("cannot set PF_LINGER"); - execvp(command[0], command); - mask = ~0; - ioctl(fd, PIOCBIC, ~0); - err(4, "execvp %s", command[0]); - } - /* Only in the parent here */ - - if (waitpid(pid, NULL, WNOHANG) != 0) { - /* - * Process exited before it got to us -- meaning the exec failed - * miserably -- so we just quietly exit. - */ - exit(1); - } - - sprintf(buf, "/proc/%d/mem", pid); - if ((fd = open(buf, O_RDWR)) == -1) - err(5, "cannot open %s", buf); - if (ioctl(fd, PIOCWAIT, &pfs) == -1) - err(6, "PIOCWAIT"); - if (pfs.why == S_EXIT) { - warnx("process exited before exec'ing"); - ioctl(fd, PIOCCONT, 0); - wait(0); - exit(7); - } - close(fd); - return pid; +setup_and_wait(char *command[]) +{ + struct procfs_status pfs; + char buf[32]; + int fd; + int pid; + int flags; + + pid = fork(); + if (pid == -1) { + err(1, "fork failed"); + } + if (pid == 0) { /* Child */ + int mask = S_EXEC | S_EXIT; + fd = open("/proc/curproc/mem", O_WRONLY); + if (fd == -1) + err(2, "cannot open /proc/curproc/mem"); + fcntl(fd, F_SETFD, 1); + if (ioctl(fd, PIOCBIS, mask) == -1) + err(3, "PIOCBIS"); + flags = PF_LINGER; + /* + * The PF_LINGER flag tells procfs not to wake up the + * process on last close; normally, this is the behaviour + * we want. + */ + if (ioctl(fd, PIOCSFL, flags) == -1) + warn("cannot set PF_LINGER"); + execvp(command[0], command); + mask = ~0; + ioctl(fd, PIOCBIC, ~0); + err(4, "execvp %s", command[0]); + } + /* Only in the parent here */ + + if (waitpid(pid, NULL, WNOHANG) != 0) { + /* + * Process exited before it got to us -- meaning the exec failed + * miserably -- so we just quietly exit. + */ + exit(1); + } + + sprintf(buf, "/proc/%d/mem", pid); + if ((fd = open(buf, O_RDWR)) == -1) + err(5, "cannot open %s", buf); + if (ioctl(fd, PIOCWAIT, &pfs) == -1) + err(6, "PIOCWAIT"); + if (pfs.why == S_EXIT) { + warnx("process exited before exec'ing"); + ioctl(fd, PIOCCONT, 0); + wait(0); + exit(7); + } + close(fd); + return (pid); } /* @@ -128,42 +129,44 @@ setup_and_wait(char *command[]) { */ int -start_tracing(int pid, int eventflags, int flags) { - int fd; - char buf[32]; - struct procfs_status tmp; - sprintf(buf, "/proc/%d/mem", pid); - - fd = open(buf, O_RDWR); - if (fd == -1) { - /* - * The process may have run away before we could start -- this - * happens with SUGID programs. So we need to see if it still - * exists before we complain bitterly. - */ - if (kill(pid, 0) == -1) - return -1; - err(8, "cannot open %s", buf); - } - - if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { - err(10, "cannot get procfs status struct"); - } - evflags = tmp.events; - - if (ioctl(fd, PIOCBIS, eventflags) == -1) - err(9, "cannot set procfs event bit mask"); - - /* - * This clears the PF_LINGER set above in setup_and_wait(); - * if truss happens to die before this, then the process - * needs to be woken up via procctl. - */ - - if (ioctl(fd, PIOCSFL, flags) == -1) - warn("cannot clear PF_LINGER"); - - return fd; +start_tracing(int pid, int eventflags, int flags) +{ + int fd; + char buf[32]; + struct procfs_status tmp; + + sprintf(buf, "/proc/%d/mem", pid); + + fd = open(buf, O_RDWR); + if (fd == -1) { + /* + * The process may have run away before we could start -- this + * happens with SUGID programs. So we need to see if it still + * exists before we complain bitterly. + */ + if (kill(pid, 0) == -1) + return -1; + err(8, "cannot open %s", buf); + } + + if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { + err(10, "cannot get procfs status struct"); + } + evflags = tmp.events; + + if (ioctl(fd, PIOCBIS, eventflags) == -1) + err(9, "cannot set procfs event bit mask"); + + /* + * This clears the PF_LINGER set above in setup_and_wait(); + * if truss happens to die before this, then the process + * needs to be woken up via procctl. + */ + + if (ioctl(fd, PIOCSFL, flags) == -1) + warn("cannot clear PF_LINGER"); + + return (fd); } /* @@ -175,8 +178,8 @@ start_tracing(int pid, int eventflags, int flags) { void restore_proc(int signo __unused) { - ioctl(Procfd, PIOCBIC, ~0); - if (evflags) - ioctl(Procfd, PIOCBIS, evflags); - exit(0); + ioctl(Procfd, PIOCBIC, ~0); + if (evflags) + ioctl(Procfd, PIOCBIS, evflags); + exit(0); } |