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