blob: caccb48c422cc0c7e9f7fea3d735056ee49f3b04 [file] [log] [blame]
Juan Cespedesf7281232009-06-25 16:11:21 +02001#include "config.h"
Juan Cespedesf7281232009-06-25 16:11:21 +02002
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"
Juan Cespedesf7281232009-06-25 16:11:21 +020013
14char *command = NULL;
Juan Cespedesf7281232009-06-25 16:11:21 +020015
16int exiting = 0; /* =1 if a SIGINT or SIGTERM has been received */
17
Petr Machatacebb8842011-07-09 11:14:11 +020018static enum pcb_status
19stop_non_p_processes (Process * proc, void * data)
20{
21 int stop = 1;
22
23 struct opt_p_t *it;
24 for (it = opt_p; it != NULL; it = it->next) {
25 Process * p_proc = pid2proc(it->pid);
26 if (p_proc == NULL) {
27 printf("stop_non_p_processes: %d terminated?\n", it->pid);
28 continue;
29 }
Petr Machata9a5420c2011-07-09 11:21:23 +020030 if (p_proc == proc || p_proc->leader == proc->leader) {
Petr Machatacebb8842011-07-09 11:14:11 +020031 stop = 0;
32 break;
33 }
34 }
35
36 if (stop) {
37 debug(2, "Sending SIGSTOP to process %u", proc->pid);
38 kill(proc->pid, SIGSTOP);
39 }
40
41 return pcb_cont;
42}
43
Juan Cespedesf7281232009-06-25 16:11:21 +020044static void
45signal_alarm(int sig) {
Juan Cespedesf7281232009-06-25 16:11:21 +020046 signal(SIGALRM, SIG_DFL);
Petr Machatacebb8842011-07-09 11:14:11 +020047 each_process(NULL, &stop_non_p_processes, NULL);
Juan Cespedesf7281232009-06-25 16:11:21 +020048}
49
50static void
51signal_exit(int sig) {
52 exiting = 1;
53 debug(1, "Received interrupt signal; exiting...");
54 signal(SIGINT, SIG_IGN);
55 signal(SIGTERM, SIG_IGN);
56 signal(SIGALRM, signal_alarm);
57 if (opt_p) {
58 struct opt_p_t *tmp = opt_p;
59 while (tmp) {
60 debug(2, "Sending SIGSTOP to process %u\n", tmp->pid);
61 kill(tmp->pid, SIGSTOP);
62 tmp = tmp->next;
63 }
64 }
65 alarm(1);
66}
67
68static void
69normal_exit(void) {
70 output_line(0, 0);
71 if (options.summary) {
72 show_summary();
73 }
74 if (options.output) {
75 fclose(options.output);
76 options.output = NULL;
77 }
78}
79
80void
81ltrace_init(int argc, char **argv) {
82 struct opt_p_t *opt_p_tmp;
83
84 atexit(normal_exit);
85 signal(SIGINT, signal_exit); /* Detach processes when interrupted */
86 signal(SIGTERM, signal_exit); /* ... or killed */
87
88 argv = process_options(argc, argv);
89 while (opt_F) {
90 /* If filename begins with ~, expand it to the user's home */
91 /* directory. This does not correctly handle ~yoda, but that */
92 /* isn't as bad as it seems because the shell will normally */
93 /* be doing the expansion for us; only the hardcoded */
94 /* ~/.ltrace.conf should ever use this code. */
95 if (opt_F->filename[0] == '~') {
96 char path[PATH_MAX];
97 char *home_dir = getenv("HOME");
98 if (home_dir) {
99 strncpy(path, home_dir, PATH_MAX - 1);
100 path[PATH_MAX - 1] = '\0';
101 strncat(path, opt_F->filename + 1,
102 PATH_MAX - strlen(path) - 1);
103 read_config_file(path);
104 }
105 } else {
106 read_config_file(opt_F->filename);
107 }
108 opt_F = opt_F->next;
109 }
110 if (opt_e) {
111 struct opt_e_t *tmp = opt_e;
112 while (tmp) {
113 debug(1, "Option -e: %s\n", tmp->name);
114 tmp = tmp->next;
115 }
116 }
117 if (command) {
Petr Machatac7585b62011-07-08 22:58:12 +0200118 open_program(command, execute_program(command, argv), 0);
Juan Cespedesf7281232009-06-25 16:11:21 +0200119 }
120 opt_p_tmp = opt_p;
121 while (opt_p_tmp) {
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200122 open_pid(opt_p_tmp->pid);
Juan Cespedesf7281232009-06-25 16:11:21 +0200123 opt_p_tmp = opt_p_tmp->next;
124 }
125}
126
Juan Cespedes61da3372009-07-03 11:55:44 +0200127static int num_ltrace_callbacks[EVENT_MAX];
128static callback_func * ltrace_callbacks[EVENT_MAX];
Juan Cespedes40dc6352009-06-25 19:54:10 +0200129
130void
Juan Cespedes61da3372009-07-03 11:55:44 +0200131ltrace_add_callback(callback_func func, Event_type type) {
132 ltrace_callbacks[type] = realloc(ltrace_callbacks[type], (num_ltrace_callbacks[type]+1)*sizeof(callback_func));
133 ltrace_callbacks[type][num_ltrace_callbacks[type]++] = func;
134}
Juan Cespedes40dc6352009-06-25 19:54:10 +0200135
Juan Cespedes61da3372009-07-03 11:55:44 +0200136static void
137dispatch_callbacks(Event * ev) {
138 int i;
139 /* Ignoring case 1: signal into a dying tracer */
140 if (ev->type==EVENT_SIGNAL &&
141 exiting && ev->e_un.signum == SIGSTOP) {
142 return;
143 }
144 /* Ignoring case 2: process being born before a clone event */
145 if (ev->proc && ev->proc->state == STATE_IGNORED) {
146 return;
147 }
148 for (i=0; i<num_ltrace_callbacks[ev->type]; i++) {
149 ltrace_callbacks[ev->type][i](ev);
Juan Cespedes40dc6352009-06-25 19:54:10 +0200150 }
151}
152
Juan Cespedesf7281232009-06-25 16:11:21 +0200153void
154ltrace_main(void) {
Juan Cespedes40dc6352009-06-25 19:54:10 +0200155 Event * ev;
Juan Cespedesf7281232009-06-25 16:11:21 +0200156 while (1) {
Juan Cespedes40dc6352009-06-25 19:54:10 +0200157 ev = next_event();
Juan Cespedes61da3372009-07-03 11:55:44 +0200158 dispatch_callbacks(ev);
Juan Cespedes03192f82009-07-03 10:16:22 +0200159 handle_event(ev);
Juan Cespedesf7281232009-06-25 16:11:21 +0200160 }
161}