libltrace.c revision cebb88491e68bdf4d466b03970c9ca77f65615f8
1#include "config.h" 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <unistd.h> 6#include <string.h> 7#include <errno.h> 8#include <sys/param.h> 9#include <signal.h> 10#include <sys/wait.h> 11 12#include "common.h" 13 14char *command = NULL; 15 16int exiting = 0; /* =1 if a SIGINT or SIGTERM has been received */ 17 18static enum pcb_status 19stop_non_p_processes (Process * proc, void * data) 20{ 21 int stop = 1; 22 23 struct opt_p_t *it; 24 for (it = opt_p; it != NULL; it = it->next) { 25 Process * p_proc = pid2proc(it->pid); 26 if (p_proc == NULL) { 27 printf("stop_non_p_processes: %d terminated?\n", it->pid); 28 continue; 29 } 30 if (p_proc == proc) { 31 stop = 0; 32 break; 33 } 34 } 35 36 if (stop) { 37 debug(2, "Sending SIGSTOP to process %u", proc->pid); 38 kill(proc->pid, SIGSTOP); 39 } 40 41 return pcb_cont; 42} 43 44static void 45signal_alarm(int sig) { 46 signal(SIGALRM, SIG_DFL); 47 each_process(NULL, &stop_non_p_processes, NULL); 48} 49 50static void 51signal_exit(int sig) { 52 exiting = 1; 53 debug(1, "Received interrupt signal; exiting..."); 54 signal(SIGINT, SIG_IGN); 55 signal(SIGTERM, SIG_IGN); 56 signal(SIGALRM, signal_alarm); 57 if (opt_p) { 58 struct opt_p_t *tmp = opt_p; 59 while (tmp) { 60 debug(2, "Sending SIGSTOP to process %u\n", tmp->pid); 61 kill(tmp->pid, SIGSTOP); 62 tmp = tmp->next; 63 } 64 } 65 alarm(1); 66} 67 68static void 69normal_exit(void) { 70 output_line(0, 0); 71 if (options.summary) { 72 show_summary(); 73 } 74 if (options.output) { 75 fclose(options.output); 76 options.output = NULL; 77 } 78} 79 80void 81ltrace_init(int argc, char **argv) { 82 struct opt_p_t *opt_p_tmp; 83 84 atexit(normal_exit); 85 signal(SIGINT, signal_exit); /* Detach processes when interrupted */ 86 signal(SIGTERM, signal_exit); /* ... or killed */ 87 88 argv = process_options(argc, argv); 89 while (opt_F) { 90 /* If filename begins with ~, expand it to the user's home */ 91 /* directory. This does not correctly handle ~yoda, but that */ 92 /* isn't as bad as it seems because the shell will normally */ 93 /* be doing the expansion for us; only the hardcoded */ 94 /* ~/.ltrace.conf should ever use this code. */ 95 if (opt_F->filename[0] == '~') { 96 char path[PATH_MAX]; 97 char *home_dir = getenv("HOME"); 98 if (home_dir) { 99 strncpy(path, home_dir, PATH_MAX - 1); 100 path[PATH_MAX - 1] = '\0'; 101 strncat(path, opt_F->filename + 1, 102 PATH_MAX - strlen(path) - 1); 103 read_config_file(path); 104 } 105 } else { 106 read_config_file(opt_F->filename); 107 } 108 opt_F = opt_F->next; 109 } 110 if (opt_e) { 111 struct opt_e_t *tmp = opt_e; 112 while (tmp) { 113 debug(1, "Option -e: %s\n", tmp->name); 114 tmp = tmp->next; 115 } 116 } 117 if (command) { 118 open_program(command, execute_program(command, argv), 0); 119 } 120 opt_p_tmp = opt_p; 121 while (opt_p_tmp) { 122 open_pid(opt_p_tmp->pid); 123 opt_p_tmp = opt_p_tmp->next; 124 } 125} 126 127static int num_ltrace_callbacks[EVENT_MAX]; 128static callback_func * ltrace_callbacks[EVENT_MAX]; 129 130void 131ltrace_add_callback(callback_func func, Event_type type) { 132 ltrace_callbacks[type] = realloc(ltrace_callbacks[type], (num_ltrace_callbacks[type]+1)*sizeof(callback_func)); 133 ltrace_callbacks[type][num_ltrace_callbacks[type]++] = func; 134} 135 136static void 137dispatch_callbacks(Event * ev) { 138 int i; 139 /* Ignoring case 1: signal into a dying tracer */ 140 if (ev->type==EVENT_SIGNAL && 141 exiting && ev->e_un.signum == SIGSTOP) { 142 return; 143 } 144 /* Ignoring case 2: process being born before a clone event */ 145 if (ev->proc && ev->proc->state == STATE_IGNORED) { 146 return; 147 } 148 for (i=0; i<num_ltrace_callbacks[ev->type]; i++) { 149 ltrace_callbacks[ev->type][i](ev); 150 } 151} 152 153void 154ltrace_main(void) { 155 Event * ev; 156 while (1) { 157 ev = next_event(); 158 dispatch_callbacks(ev); 159 handle_event(ev); 160 } 161} 162