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