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