ust: cleanups and functionality
[ust.git] / libtracectl / tracectl.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <signal.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7 #include <sched.h>
8
9 #include "marker.h"
10
11 #define UNIX_PATH_MAX 108
12
13 //#define SOCKETDIR "/var/run/ust/socks"
14 #define SOCKETDIR "/tmp/socks"
15 #define SOCKETDIRLEN sizeof(SOCKETDIR)
16 #define USTSIGNAL SIGIO
17
18 #define DBG(fmt, args...) fprintf(stderr, fmt "\n", ## args)
19 #define WARN(fmt, args...) fprintf(stderr, "usertrace: WARNING: " fmt "\n", ## args)
20 #define ERR(fmt, args...) fprintf(stderr, "usertrace: ERROR: " fmt "\n", ## args)
21 #define PERROR(call) perror("usertrace: ERROR: " call)
22
23 #define MAX_MSG_SIZE (100)
24 #define MSG_NOTIF 1
25 #define MSG_REGISTER_NOTIF 2
26
27 struct tracecmd { /* no padding */
28 uint32_t size;
29 uint16_t command;
30 };
31
32 //struct listener_arg {
33 // int pipe_fd;
34 //};
35
36 struct trctl_msg {
37 /* size: the size of all the fields except size itself */
38 uint32_t size;
39 uint16_t type;
40 /* Only the necessary part of the payload is transferred. It
41 * may even be none of it.
42 */
43 char payload[94];
44 };
45
46 pid_t mypid;
47 char mysocketfile[UNIX_PATH_MAX] = "";
48 int pfd = -1;
49
50
51 static void print_markers(void)
52 {
53 struct marker_iter iter;
54
55 marker_iter_reset(&iter);
56 marker_iter_start(&iter);
57
58 while(iter.marker) {
59 fprintf(stderr, "marker: %s_%s \"%s\"\n", iter.marker->channel, iter.marker->name, iter.marker->format);
60 marker_iter_next(&iter);
61 }
62 }
63
64 void do_command(struct tracecmd *cmd)
65 {
66 }
67
68 void receive_commands()
69 {
70 }
71
72 int fd_notif = -1;
73 void notif_cb(void)
74 {
75 int result;
76 struct trctl_msg msg;
77
78 /* FIXME: fd_notif should probably be protected by a spinlock */
79
80 if(fd_notif == -1)
81 return;
82
83 msg.type = MSG_NOTIF;
84 msg.size = sizeof(msg.type);
85
86 /* FIXME: don't block here */
87 result = write(fd_notif, &msg, msg.size+sizeof(msg.size));
88 if(result == -1) {
89 PERROR("write");
90 return;
91 }
92 }
93
94 char recvbuf[10000];
95
96 int listener_main(void *p)
97 {
98 int result;
99
100 for(;;) {
101 uint32_t size;
102 struct sockaddr_un addr;
103 socklen_t addrlen = sizeof(addr);
104
105 for(;;) {
106 struct trctl_msg msg;
107 int len;
108
109 result = len = recvfrom(pfd, recvbuf, sizeof(recvbuf), 0, &addr, &addrlen);
110 if(result == -1) {
111 PERROR("recvfrom");
112 continue;
113 }
114
115 if(recvbuf[len-2] == '\n')
116 recvbuf[len-2] = '\0';
117
118 fprintf(stderr, "received a message! it's: %s\n", recvbuf);
119
120
121 if(!strcmp(recvbuf, "print_markers")) {
122 print_markers();
123 }
124 else if(!strcmp(recvbuf, "trace_setup")) {
125 DBG("trace setup");
126 }
127 else if(!strcmp(recvbuf, "trace_alloc")) {
128 DBG("trace alloc");
129 }
130 else if(!strcmp(recvbuf, "trace_start")) {
131 DBG("trace start");
132 }
133 else if(!strcmp(recvbuf, "trace_stop")) {
134 DBG("trace stop");
135 }
136 }
137 next_conn:;
138 }
139 }
140
141 void create_listener(void)
142 {
143 int result;
144 static char listener_stack[16384];
145
146 result = clone(listener_main, listener_stack+sizeof(listener_stack)-1, CLONE_FS | CLONE_FILES | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD, NULL);
147 if(result == -1) {
148 perror("clone");
149 }
150 }
151
152 /* The signal handler itself. */
153
154 void sighandler(int sig)
155 {
156 DBG("sighandler");
157 create_listener();
158 }
159
160 /* Called by the app signal handler to chain it to us. */
161
162 void chain_signal(void)
163 {
164 sighandler(USTSIGNAL);
165 }
166
167 static int init_socket(void)
168 {
169 int result;
170 int fd;
171 char pidstr[6];
172 int pidlen;
173
174 struct sockaddr_un addr;
175
176 result = fd = socket(PF_UNIX, SOCK_DGRAM, 0);
177 if(result == -1) {
178 PERROR("socket");
179 return -1;
180 }
181
182 addr.sun_family = AF_UNIX;
183
184 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s/%d", SOCKETDIR, mypid);
185 if(result >= UNIX_PATH_MAX) {
186 ERR("string overflow allocating socket name");
187 goto close_sock;
188 }
189 //DBG("opening socket at %s", addr.sun_path);
190
191 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
192 if(result == -1) {
193 PERROR("bind");
194 goto close_sock;
195 }
196
197 strcpy(mysocketfile, addr.sun_path);
198
199 pfd = fd;
200 return 0;
201
202 close_sock:
203 close(fd);
204
205 return -1;
206 }
207
208 static void destroy_socket(void)
209 {
210 int result;
211
212 if(mysocketfile[0] == '\0')
213 return;
214
215 result = unlink(mysocketfile);
216 if(result == -1) {
217 PERROR("unlink");
218 }
219 }
220
221 static int init_signal_handler(void)
222 {
223 /* Attempt to handler SIGIO. If the main program wants to
224 * handle it, fine, it'll override us. They it'll have to
225 * use the chaining function.
226 */
227
228 int result;
229 struct sigaction act;
230
231 result = sigemptyset(&act.sa_mask);
232 if(result == -1) {
233 PERROR("sigemptyset");
234 return -1;
235 }
236
237 act.sa_handler = sighandler;
238 act.sa_flags = SA_RESTART;
239
240 /* Only defer ourselves. Also, try to restart interrupted
241 * syscalls to disturb the traced program as little as possible.
242 */
243 result = sigaction(SIGIO, &act, NULL);
244 if(result == -1) {
245 PERROR("sigaction");
246 return -1;
247 }
248
249 return 0;
250 }
251
252 static void __attribute__((constructor)) init()
253 {
254 int result;
255
256 mypid = getpid();
257
258 if(getenv("UST_TRACE")) {
259 char trace_name[] = "auto";
260 char trace_type[] = "ustrelay";
261
262 DBG("starting early tracing");
263
264 /* Ensure marker control is initialized */
265 init_marker_control();
266
267 /* Ensure relay is initialized */
268 init_ustrelay_transport();
269
270 /* Ensure markers are initialized */
271 init_markers();
272
273 result = ltt_marker_connect("foo", "bar", "default");
274 if(result)
275 ERR("ltt_marker_connect");
276
277 result = ltt_trace_setup(trace_name);
278 if(result < 0) {
279 ERR("ltt_trace_setup failed");
280 return;
281 }
282
283 result = ltt_trace_set_type(trace_name, trace_type);
284 if(result < 0) {
285 ERR("ltt_trace_set_type failed");
286 return;
287 }
288
289 result = ltt_trace_alloc(trace_name);
290 if(result < 0) {
291 ERR("ltt_trace_alloc failed");
292 return;
293 }
294
295 result = ltt_trace_start(trace_name);
296 if(result < 0) {
297 ERR("ltt_trace_start failed");
298 return;
299 }
300 }
301
302 /* Must create socket before signal handler to prevent races
303 * on pfd variable.
304 */
305 result = init_socket();
306 if(result == -1) {
307 ERR("init_socket error");
308 return;
309 }
310 result = init_signal_handler();
311 if(result == -1) {
312 ERR("init_signal_handler error");
313 return;
314 }
315
316 return;
317
318 /* should decrementally destroy stuff if error */
319
320 }
321
322 /* This is only called if we terminate normally, not with an unhandled signal,
323 * so we cannot rely on it. */
324
325 static void __attribute__((destructor)) fini()
326 {
327 destroy_socket();
328 }
This page took 0.035517 seconds and 4 git commands to generate.