blob: 731ead26712cd2849ba9665f2a21316748d8381e [file] [log] [blame]
Juan Cespedesf7281232009-06-25 16:11:21 +02001#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"
Juan Cespedesf7281232009-06-25 16:11:21 +020015
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) {
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200117 open_pid(opt_p_tmp->pid);
Juan Cespedesf7281232009-06-25 16:11:21 +0200118 opt_p_tmp = opt_p_tmp->next;
119 }
120}
121
Juan Cespedes40dc6352009-06-25 19:54:10 +0200122static 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
Juan Cespedesf7281232009-06-25 16:11:21 +0200141void
142ltrace_main(void) {
Juan Cespedes40dc6352009-06-25 19:54:10 +0200143 int i;
144 Event * ev;
Juan Cespedesf7281232009-06-25 16:11:21 +0200145 while (1) {
Juan Cespedes40dc6352009-06-25 19:54:10 +0200146 ev = next_event();
147 for (i=0; i<num_ltrace_callbacks; i++) {
148 ltrace_callbacks[i](ev);
149 }
Juan Cespedes03192f82009-07-03 10:16:22 +0200150 handle_event(ev);
Juan Cespedesf7281232009-06-25 16:11:21 +0200151 }
152}