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