From 3ba01b7fdaf7f68c756ebb0ded2829575afec497 Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Fri, 14 Jul 2017 19:08:10 +0200 Subject: extrace.c: KNF --- extrace.c | 667 ++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 339 insertions(+), 328 deletions(-) diff --git a/extrace.c b/extrace.c index b82a6a0..7dad447 100644 --- a/extrace.c +++ b/extrace.c @@ -14,7 +14,7 @@ * -l print full path of argv[0] * -q don't print exec() arguments * - * Copyright (C) 2014-2016 Leah Neukirchen + * Copyright (C) 2014-2017 Leah Neukirchen * * hacked from sources of: */ @@ -76,8 +76,8 @@ #define RECV_MESSAGE_LEN (NLMSG_LENGTH(sizeof (struct cn_msg) + \ sizeof (struct proc_event))) -#define SEND_MESSAGE_SIZE (NLMSG_SPACE(SEND_MESSAGE_LEN)) -#define RECV_MESSAGE_SIZE (NLMSG_SPACE(RECV_MESSAGE_LEN)) +#define SEND_MESSAGE_SIZE (NLMSG_SPACE(SEND_MESSAGE_LEN)) +#define RECV_MESSAGE_SIZE (NLMSG_SPACE(RECV_MESSAGE_LEN)) #define BUFF_SIZE (max(max(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE), 1024)) #define MIN_RECV_SIZE (min(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE)) @@ -97,370 +97,381 @@ sig_atomic_t quit = 0; #define PID_DB_SIZE 1024 struct { - pid_t pid; - int depth; - struct timespec start; - char cmdline[CMDLINE_DB_MAX]; + pid_t pid; + int depth; + struct timespec start; + char cmdline[CMDLINE_DB_MAX]; } pid_db[PID_DB_SIZE]; static int pid_depth(pid_t pid) { - pid_t ppid = 0; - FILE *f; - char name[PATH_MAX]; - int d; + pid_t ppid = 0; + FILE *f; + char name[PATH_MAX]; + int d; - snprintf(name, sizeof name, "/proc/%d/stat", pid); + snprintf(name, sizeof name, "/proc/%d/stat", pid); - if ((f = fopen(name, "r"))) { - if (fscanf(f, "%*d (%*[^)]) %*c %d", &ppid) < 0) - ppid = 0; - fclose(f); - } + if ((f = fopen(name, "r"))) { + if (fscanf(f, "%*d (%*[^)]) %*c %d", &ppid) < 0) + ppid = 0; + fclose(f); + } - if (ppid == parent) - return 0; + if (ppid == parent) + return 0; - if (ppid == 0) - return -1; /* a parent we are not interested in */ + if (ppid == 0) + return -1; /* a parent we are not interested in */ - d = pid_depth(ppid); - if (d == -1) - return -1; + d = pid_depth(ppid); + if (d == -1) + return -1; - return d+1; + return d+1; } static void sigint(int sig) { - (void)sig; - quit = 1; + (void)sig; + quit = 1; } static void sigchld(int sig) { - (void)sig; - while (waitpid(-1, NULL, WNOHANG) > 0) - ; - quit = 1; + (void)sig; + while (waitpid(-1, NULL, WNOHANG) > 0) + ; + quit = 1; } static void print_shquoted(const char *s) { - if (*s && !strpbrk(s, - "\001\002\003\004\005\006\007\010" - "\011\012\013\014\015\016\017\020" - "\021\022\023\024\025\026\027\030" - "\031\032\033\034\035\036\037\040" - "`^#*[]=|\\?${}()'\"<>&;\177")) { - fprintf(output, "%s", s); - return; - } + if (*s && !strpbrk(s, + "\001\002\003\004\005\006\007\010" + "\011\012\013\014\015\016\017\020" + "\021\022\023\024\025\026\027\030" + "\031\032\033\034\035\036\037\040" + "`^#*[]=|\\?${}()'\"<>&;\177")) { + fprintf(output, "%s", s); + return; + } + + putc('\'', output); + for (; *s; s++) + if (*s == '\'') + fprintf(output, "'\\''"); + else if (*s == '\n') + fprintf(output, "'$'\\n''"); + else + putc(*s, output); + putc('\'', output); +} - putc('\'', output); - for (; *s; s++) - if (*s == '\'') - fprintf(output, "'\\''"); - else if (*s == '\n') - fprintf(output, "'$'\\n''"); - else - putc(*s, output); - putc('\'', output); +static void +print_env(pid_t pid) +{ + char name[PATH_MAX]; + FILE *env; + + fprintf(output, " "); + snprintf(name, sizeof name, "/proc/%d/environ", pid); + if ((env = fopen(name, "r"))) { + char *line = 0, *eq = 0; + size_t linelen = 0; + while (getdelim(&line, &linelen, '\0', env) >= 0) { + putc(' ', output); + if ((eq = strchr(line, '='))) { + /* print split so = doesn't trigger escaping. */ + *eq = 0; + print_shquoted(line); + putc('=', output); + print_shquoted(eq+1); + } else { + /* weird env entry without equal sign. */ + print_shquoted(line); + } + } + free(line); + fclose(env); + } else { + fprintf(output, " -"); + } } static void handle_msg(struct cn_msg *cn_hdr) { - char cmdline[CMDLINE_MAX], name[PATH_MAX]; - char exe[PATH_MAX]; - char cwd[PATH_MAX]; - char *argvrest; - - int r = 0, r2 = 0, r3 = 0, fd, d; - struct proc_event *ev = (struct proc_event *)cn_hdr->data; - - if (ev->what == PROC_EVENT_EXEC) { - pid_t pid = ev->event_data.exec.process_pid; - int i = 0; - - d = pid_depth(pid); - if (d < 0) - return; - - if (show_exit) { - for (i = 0; i < PID_DB_SIZE - 1; i++) - if (pid_db[i].pid == 0) - break; - if (i == PID_DB_SIZE - 1) - fprintf(stderr, - "extrace: warning pid_db of size %d overflowed\n", PID_DB_SIZE); - - pid_db[i].pid = pid; - pid_db[i].depth = d; - clock_gettime(CLOCK_MONOTONIC_RAW, &pid_db[i].start); - } - - snprintf(name, sizeof name, "/proc/%d/cmdline", pid); - - memset(&cmdline, 0, sizeof cmdline); - fd = open(name, O_RDONLY); - if (fd > 0) { - r = read(fd, cmdline, sizeof cmdline); - close(fd); - - if (r > 0) - cmdline[r] = 0; - - if (full_path) { - snprintf(name, sizeof name, "/proc/%d/exe", pid); - r2 = readlink(name, exe, sizeof exe); - if (r2 > 0) - exe[r2] = 0; - } - - argvrest = strchr(cmdline, 0) + 1; - } - - if (show_cwd) { - snprintf(name, sizeof name, "/proc/%d/cwd", pid); - r3 = readlink(name, cwd, sizeof cwd); - if (r3 > 0) - cwd[r3] = 0; - } - - if (!flat) - fprintf(output, "%*s", 2*d, ""); - fprintf(output, "%d", pid); - if (show_exit) { - putc('+', output); - strncpy(pid_db[i].cmdline, cmdline, CMDLINE_DB_MAX-1); - pid_db[i].cmdline[CMDLINE_DB_MAX-1] = 0; - } - putc(' ', output); - if (show_cwd) { - print_shquoted(cwd); - fprintf(output, " %% "); - } - - if (full_path) - print_shquoted(exe); - else - print_shquoted(cmdline); - - if (show_args && r > 0) { - while (argvrest - cmdline < r) { - putc(' ', output); - print_shquoted(argvrest); - argvrest = strchr(argvrest, 0)+1; - } - } - - if (r == sizeof cmdline) - fprintf(output, "... "); - - if (show_env) { - FILE *env; - fprintf(output, " "); - snprintf(name, sizeof name, "/proc/%d/environ", pid); - if ((env = fopen(name, "r"))) { - char *line = 0, *eq = 0; - size_t linelen = 0; - while (getdelim(&line, &linelen, '\0', env) >= 0) { - putc(' ', output); - if ((eq = strchr(line, '='))) { - /* print split so = doesn't trigger escaping. */ - *eq = 0; - print_shquoted(line); - putc('=', output); - print_shquoted(eq+1); - } else { - /* weird env entry without equal sign. */ - print_shquoted(line); - } - } - free(line); - fclose(env); - } else { - fprintf(output, " -"); - } - } - - fprintf(output, "\n"); - fflush(output); - } else if (show_exit && ev->what == PROC_EVENT_EXIT) { - pid_t pid = ev->event_data.exit.process_pid; - int i; - - for (i = 0; i < PID_DB_SIZE; i++) - if (pid_db[i].pid == pid) { - struct timespec now, diff; - - pid_db[i].pid = 0; - if (!flat) - fprintf(output, "%*s", 2*pid_db[i].depth, ""); - clock_gettime(CLOCK_MONOTONIC_RAW, &now); - - if ((now.tv_nsec - pid_db[i].start.tv_nsec) < 0) { - diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec - 1; - diff.tv_nsec = 1000000000 + now.tv_nsec - pid_db[i].start.tv_nsec; - } else { - diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec; - diff.tv_nsec = now.tv_nsec - pid_db[i].start.tv_nsec; - } - - fprintf(output, "%d- ", pid); - print_shquoted(pid_db[i].cmdline); - fprintf(output, " exited %s=%d time=%ld.%03lds\n", - ev->event_data.exit.exit_code >= 256 ? "signal" : "status", - ev->event_data.exit.exit_code >= 256 ? - ev->event_data.exit.exit_signal : - ev->event_data.exit.exit_code, - diff.tv_sec, - diff.tv_nsec / 1000000); - fflush(output); - break; - } - } + char cmdline[CMDLINE_MAX], name[PATH_MAX]; + char exe[PATH_MAX]; + char cwd[PATH_MAX]; + char *argvrest; + + int r = 0, r2 = 0, r3 = 0, fd, d; + struct proc_event *ev = (struct proc_event *)cn_hdr->data; + + if (ev->what == PROC_EVENT_EXEC) { + pid_t pid = ev->event_data.exec.process_pid; + int i = 0; + + d = pid_depth(pid); + if (d < 0) + return; + + if (show_exit) { + for (i = 0; i < PID_DB_SIZE - 1; i++) + if (pid_db[i].pid == 0) + break; + if (i == PID_DB_SIZE - 1) + fprintf(stderr, "extrace: warning pid_db of " + "size %d overflowed\n", PID_DB_SIZE); + + pid_db[i].pid = pid; + pid_db[i].depth = d; + clock_gettime(CLOCK_MONOTONIC_RAW, &pid_db[i].start); + } + + snprintf(name, sizeof name, "/proc/%d/cmdline", pid); + + memset(&cmdline, 0, sizeof cmdline); + fd = open(name, O_RDONLY); + if (fd > 0) { + r = read(fd, cmdline, sizeof cmdline); + close(fd); + + if (r > 0) + cmdline[r] = 0; + + if (full_path) { + snprintf(name, sizeof name, "/proc/%d/exe", pid); + r2 = readlink(name, exe, sizeof exe); + if (r2 > 0) + exe[r2] = 0; + } + + argvrest = strchr(cmdline, 0) + 1; + } + + if (show_cwd) { + snprintf(name, sizeof name, "/proc/%d/cwd", pid); + r3 = readlink(name, cwd, sizeof cwd); + if (r3 > 0) + cwd[r3] = 0; + } + + if (!flat) + fprintf(output, "%*s", 2*d, ""); + fprintf(output, "%d", pid); + if (show_exit) { + putc('+', output); + strncpy(pid_db[i].cmdline, cmdline, CMDLINE_DB_MAX-1); + pid_db[i].cmdline[CMDLINE_DB_MAX-1] = 0; + } + putc(' ', output); + if (show_cwd) { + print_shquoted(cwd); + fprintf(output, " %% "); + } + + if (full_path) + print_shquoted(exe); + else + print_shquoted(cmdline); + + if (show_args && r > 0) { + while (argvrest - cmdline < r) { + putc(' ', output); + print_shquoted(argvrest); + argvrest = strchr(argvrest, 0)+1; + } + } + + if (r == sizeof cmdline) + fprintf(output, "... "); + + if (show_env) { + print_env(pid); + } + + fprintf(output, "\n"); + fflush(output); + } else if (show_exit && ev->what == PROC_EVENT_EXIT) { + pid_t pid = ev->event_data.exit.process_pid; + struct timespec now, diff; + int i; + + for (i = 0; i < PID_DB_SIZE; i++) + if (pid_db[i].pid == pid) + break; + if (i == PID_DB_SIZE) + return; + + pid_db[i].pid = 0; + if (!flat) + fprintf(output, "%*s", + 2*pid_db[i].depth, ""); + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + + if ((now.tv_nsec - pid_db[i].start.tv_nsec) < 0) { + diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec - 1; + diff.tv_nsec = 1000000000 + now.tv_nsec - pid_db[i].start.tv_nsec; + } else { + diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec; + diff.tv_nsec = now.tv_nsec - pid_db[i].start.tv_nsec; + } + + fprintf(output, "%d- ", pid); + print_shquoted(pid_db[i].cmdline); + fprintf(output, " exited %s=%d time=%ld.%03lds\n", + ev->event_data.exit.exit_code >= 256 ? "signal" : "status", + ev->event_data.exit.exit_code >= 256 ? + ev->event_data.exit.exit_signal : + ev->event_data.exit.exit_code, + diff.tv_sec, + diff.tv_nsec / 1000000); + fflush(output); + } } int main(int argc, char *argv[]) { - int sk_nl; - struct sockaddr_nl my_nla, kern_nla, from_nla; - socklen_t from_nla_len; - char buff[BUFF_SIZE]; - struct nlmsghdr *nl_hdr, *nlh; - struct cn_msg *cn_hdr; - enum proc_cn_mcast_op *mcop_msg; - size_t recv_len = 0; - int rc = -1, opt; - - output = stdout; - - while ((opt = getopt(argc, argv, "+deflo:p:qtw")) != -1) - switch (opt) { - case 'd': show_cwd = 1; break; - case 'e': show_env = 1; break; - case 'f': flat = 1; break; - case 'l': full_path = 1; break; - case 'p': parent = atoi(optarg); break; - case 'q': show_args = 0; break; - case 't': show_exit = 1; break; - case 'o': - output = fopen(optarg, "w"); - if (!output) { - perror("fopen"); - exit(1); - } - break; - case 'w': /* obsoleted, ignore */; break; - default: goto usage; - } - - if (parent != 1 && optind != argc) { -usage: - fprintf(stderr, "Usage: extrace [-deflq] [-o FILE] [-p PID|CMD...]\n"); - exit(1); - } - - sk_nl = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); - if (sk_nl == -1) { - perror("socket sk_nl error"); - exit(1); - } - - my_nla.nl_family = AF_NETLINK; - my_nla.nl_groups = CN_IDX_PROC; - my_nla.nl_pid = getpid(); - - kern_nla.nl_family = AF_NETLINK; - kern_nla.nl_groups = CN_IDX_PROC; - kern_nla.nl_pid = 1; - - if (bind(sk_nl, (struct sockaddr *)&my_nla, sizeof my_nla) == -1) { - perror("binding sk_nl error"); - goto close_and_exit; - } - nl_hdr = (struct nlmsghdr *)buff; - cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr); - mcop_msg = (enum proc_cn_mcast_op*)&cn_hdr->data[0]; - - memset(buff, 0, sizeof buff); - *mcop_msg = PROC_CN_MCAST_LISTEN; - - nl_hdr->nlmsg_len = SEND_MESSAGE_LEN; - nl_hdr->nlmsg_type = NLMSG_DONE; - nl_hdr->nlmsg_flags = 0; - nl_hdr->nlmsg_seq = 0; - nl_hdr->nlmsg_pid = getpid(); - - cn_hdr->id.idx = CN_IDX_PROC; - cn_hdr->id.val = CN_VAL_PROC; - cn_hdr->seq = 0; - cn_hdr->ack = 0; - cn_hdr->len = sizeof (enum proc_cn_mcast_op); - - if (send(sk_nl, nl_hdr, nl_hdr->nlmsg_len, 0) != nl_hdr->nlmsg_len) { - printf("failed to send proc connector mcast ctl op!\n"); - goto close_and_exit; + int sk_nl; + struct sockaddr_nl my_nla, kern_nla, from_nla; + socklen_t from_nla_len; + char buff[BUFF_SIZE]; + struct nlmsghdr *nl_hdr, *nlh; + struct cn_msg *cn_hdr; + enum proc_cn_mcast_op *mcop_msg; + size_t recv_len = 0; + int rc = -1, opt; + + output = stdout; + + while ((opt = getopt(argc, argv, "+deflo:p:qtw")) != -1) + switch (opt) { + case 'd': show_cwd = 1; break; + case 'e': show_env = 1; break; + case 'f': flat = 1; break; + case 'l': full_path = 1; break; + case 'p': parent = atoi(optarg); break; + case 'q': show_args = 0; break; + case 't': show_exit = 1; break; + case 'o': + output = fopen(optarg, "w"); + if (!output) { + perror("fopen"); + exit(1); + } + break; + case 'w': /* obsoleted, ignore */; break; + default: goto usage; + } + + if (parent != 1 && optind != argc) { + usage: + fprintf(stderr, "Usage: extrace [-deflq] [-o FILE] [-p PID|CMD...]\n"); + exit(1); } - if (*mcop_msg == PROC_CN_MCAST_IGNORE) { - rc = 0; - goto close_and_exit; - } - - if (optind != argc) { - pid_t child; - - parent = getpid(); - signal(SIGCHLD, sigchld); - - child = fork(); - if (child == -1) { - perror("fork"); - goto close_and_exit; - } - if (child == 0) { - execvp(argv[optind], argv+optind); - perror("execvp"); - goto close_and_exit; - } - } - - signal(SIGINT, sigint); - - rc = 0; - while (!quit) { - memset(buff, 0, sizeof buff); - from_nla_len = sizeof from_nla; - nlh = (struct nlmsghdr *)buff; - memcpy(&from_nla, &kern_nla, sizeof from_nla); - recv_len = recvfrom(sk_nl, buff, BUFF_SIZE, 0, - (struct sockaddr *)&from_nla, &from_nla_len); - if (from_nla.nl_pid != 0 || recv_len < 1) - continue; - - while (NLMSG_OK(nlh, recv_len)) { - if (nlh->nlmsg_type == NLMSG_NOOP) - continue; - if (nlh->nlmsg_type == NLMSG_ERROR || nlh->nlmsg_type == NLMSG_OVERRUN) - break; - - handle_msg(NLMSG_DATA(nlh)); - - if (nlh->nlmsg_type == NLMSG_DONE) - break; - nlh = NLMSG_NEXT(nlh, recv_len); - } - } + sk_nl = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); + if (sk_nl == -1) { + perror("socket sk_nl error"); + exit(1); + } + + my_nla.nl_family = AF_NETLINK; + my_nla.nl_groups = CN_IDX_PROC; + my_nla.nl_pid = getpid(); + + kern_nla.nl_family = AF_NETLINK; + kern_nla.nl_groups = CN_IDX_PROC; + kern_nla.nl_pid = 1; + + if (bind(sk_nl, (struct sockaddr *)&my_nla, sizeof my_nla) == -1) { + perror("binding sk_nl error"); + goto close_and_exit; + } + nl_hdr = (struct nlmsghdr *)buff; + cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr); + mcop_msg = (enum proc_cn_mcast_op*)&cn_hdr->data[0]; + + memset(buff, 0, sizeof buff); + *mcop_msg = PROC_CN_MCAST_LISTEN; + + nl_hdr->nlmsg_len = SEND_MESSAGE_LEN; + nl_hdr->nlmsg_type = NLMSG_DONE; + nl_hdr->nlmsg_flags = 0; + nl_hdr->nlmsg_seq = 0; + nl_hdr->nlmsg_pid = getpid(); + + cn_hdr->id.idx = CN_IDX_PROC; + cn_hdr->id.val = CN_VAL_PROC; + cn_hdr->seq = 0; + cn_hdr->ack = 0; + cn_hdr->len = sizeof (enum proc_cn_mcast_op); + + if (send(sk_nl, nl_hdr, nl_hdr->nlmsg_len, 0) != nl_hdr->nlmsg_len) { + printf("failed to send proc connector mcast ctl op!\n"); + goto close_and_exit; + } + + if (*mcop_msg == PROC_CN_MCAST_IGNORE) { + rc = 0; + goto close_and_exit; + } + + if (optind != argc) { + pid_t child; + + parent = getpid(); + signal(SIGCHLD, sigchld); + + child = fork(); + if (child == -1) { + perror("fork"); + goto close_and_exit; + } + if (child == 0) { + execvp(argv[optind], argv+optind); + perror("execvp"); + goto close_and_exit; + } + } + + signal(SIGINT, sigint); + + rc = 0; + while (!quit) { + memset(buff, 0, sizeof buff); + from_nla_len = sizeof from_nla; + nlh = (struct nlmsghdr *)buff; + memcpy(&from_nla, &kern_nla, sizeof from_nla); + recv_len = recvfrom(sk_nl, buff, BUFF_SIZE, 0, + (struct sockaddr *)&from_nla, &from_nla_len); + if (from_nla.nl_pid != 0 || recv_len < 1) + continue; + + while (NLMSG_OK(nlh, recv_len)) { + if (nlh->nlmsg_type == NLMSG_NOOP) + continue; + if (nlh->nlmsg_type == NLMSG_ERROR || + nlh->nlmsg_type == NLMSG_OVERRUN) + break; + + handle_msg(NLMSG_DATA(nlh)); + + if (nlh->nlmsg_type == NLMSG_DONE) + break; + nlh = NLMSG_NEXT(nlh, recv_len); + } + } close_and_exit: - close(sk_nl); - return rc; + close(sk_nl); + return rc; } -- cgit 1.4.1