libltrace.c revision 02bd9eca0b439b6950ab72ba64b67181e5bf0fbd
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 || p_proc->leader == proc->leader) { 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 //alarm(1); 58} 59 60static void 61normal_exit(void) { 62 output_line(0, 0); 63 if (options.summary) { 64 show_summary(); 65 } 66 if (options.output) { 67 fclose(options.output); 68 options.output = NULL; 69 } 70} 71 72void 73ltrace_init(int argc, char **argv) { 74 struct opt_p_t *opt_p_tmp; 75 76 atexit(normal_exit); 77 signal(SIGINT, signal_exit); /* Detach processes when interrupted */ 78 signal(SIGTERM, signal_exit); /* ... or killed */ 79 80 argv = process_options(argc, argv); 81 while (opt_F) { 82 /* If filename begins with ~, expand it to the user's home */ 83 /* directory. This does not correctly handle ~yoda, but that */ 84 /* isn't as bad as it seems because the shell will normally */ 85 /* be doing the expansion for us; only the hardcoded */ 86 /* ~/.ltrace.conf should ever use this code. */ 87 if (opt_F->filename[0] == '~') { 88 char path[PATH_MAX]; 89 char *home_dir = getenv("HOME"); 90 if (home_dir) { 91 strncpy(path, home_dir, PATH_MAX - 1); 92 path[PATH_MAX - 1] = '\0'; 93 strncat(path, opt_F->filename + 1, 94 PATH_MAX - strlen(path) - 1); 95 read_config_file(path); 96 } 97 } else { 98 read_config_file(opt_F->filename); 99 } 100 opt_F = opt_F->next; 101 } 102 if (opt_e) { 103 struct opt_e_t *tmp = opt_e; 104 while (tmp) { 105 debug(1, "Option -e: %s\n", tmp->name); 106 tmp = tmp->next; 107 } 108 } 109 if (command) { 110 /* Check that the binary ABI is supported before 111 * calling execute_program. */ 112 struct ltelf lte = {}; 113 open_elf(<e, command); 114 115 open_program(command, execute_program(command, argv), 0); 116 } 117 opt_p_tmp = opt_p; 118 while (opt_p_tmp) { 119 open_pid(opt_p_tmp->pid); 120 opt_p_tmp = opt_p_tmp->next; 121 } 122} 123 124static int num_ltrace_callbacks[EVENT_MAX]; 125static callback_func * ltrace_callbacks[EVENT_MAX]; 126 127void 128ltrace_add_callback(callback_func func, Event_type type) { 129 ltrace_callbacks[type] = realloc(ltrace_callbacks[type], (num_ltrace_callbacks[type]+1)*sizeof(callback_func)); 130 ltrace_callbacks[type][num_ltrace_callbacks[type]++] = func; 131} 132 133static void 134dispatch_callbacks(Event * ev) { 135 int i; 136 /* Ignoring case 1: signal into a dying tracer */ 137 if (ev->type==EVENT_SIGNAL && 138 exiting && ev->e_un.signum == SIGSTOP) { 139 return; 140 } 141 /* Ignoring case 2: process being born before a clone event */ 142 if (ev->proc && ev->proc->state == STATE_IGNORED) { 143 return; 144 } 145 for (i=0; i<num_ltrace_callbacks[ev->type]; i++) { 146 ltrace_callbacks[ev->type][i](ev); 147 } 148} 149 150void 151ltrace_main(void) { 152 Event * ev; 153 while (1) { 154 ev = next_event(); 155 dispatch_callbacks(ev); 156 handle_event(ev); 157 } 158} 159