Imported Upstream version 0.5.3
[platform/upstream/ltrace.git] / libltrace.c
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
14 char *command = NULL;
15 Process *list_of_processes = NULL;
16
17 int exiting = 0;                /* =1 if a SIGINT or SIGTERM has been received */
18
19 static void
20 signal_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
43 static void
44 signal_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
61 static void
62 normal_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
73 void
74 ltrace_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
120 static int num_ltrace_callbacks[EVENT_MAX];
121 static callback_func * ltrace_callbacks[EVENT_MAX];
122
123 void
124 ltrace_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
129 static void
130 dispatch_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
146 void
147 ltrace_main(void) {
148         Event * ev;
149         while (1) {
150                 ev = next_event();
151                 dispatch_callbacks(ev);
152                 handle_event(ev);
153         }
154 }