1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <[email protected]>
4 *
5 */
6 #define _LARGEFILE64_SOURCE
7 #include <dirent.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <getopt.h>
12 #include <limits.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/wait.h>
16 #include <netdb.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <signal.h>
20 #include <errno.h>
21
22 #ifdef VSOCK
23 #include <linux/vm_sockets.h>
24 #endif
25
26 #include "trace-local.h"
27 #include "trace-msg.h"
28
29 #define dprint(fmt, ...) tracecmd_debug(fmt, ##__VA_ARGS__)
30
31 #define MAX_OPTION_SIZE 4096
32
33 #define _VAR_DIR_Q(dir) #dir
34 #define VAR_DIR_Q(dir) _VAR_DIR_Q(dir)
35
36 #define VAR_RUN_DIR VAR_DIR_Q(VAR_DIR) "/run"
37
38 static char *default_output_dir = ".";
39 static char *output_dir;
40 static char *default_output_file = "trace";
41 static char *output_file;
42
43 static bool use_vsock;
44
45 static int backlog = 5;
46
47 static int do_daemon;
48
49 /* Used for signaling INT to finish */
50 static struct tracecmd_msg_handle *stop_msg_handle;
51 static bool done;
52
53 #define pdie(fmt, ...) \
54 do { \
55 tracecmd_plog_error(fmt, ##__VA_ARGS__);\
56 remove_pid_file(); \
57 exit(-1); \
58 } while (0)
59
60 #define TEMP_FILE_STR "%s.%s:%s.cpu%d", output_file, host, port, cpu
get_temp_file(const char * host,const char * port,int cpu)61 static char *get_temp_file(const char *host, const char *port, int cpu)
62 {
63 char *file = NULL;
64 int size;
65
66 size = snprintf(file, 0, TEMP_FILE_STR);
67 file = malloc(size + 1);
68 if (!file)
69 return NULL;
70 sprintf(file, TEMP_FILE_STR);
71
72 return file;
73 }
74
put_temp_file(char * file)75 static void put_temp_file(char *file)
76 {
77 free(file);
78 }
79
signal_setup(int sig,sighandler_t handle)80 static void signal_setup(int sig, sighandler_t handle)
81 {
82 struct sigaction action;
83
84 sigaction(sig, NULL, &action);
85 /* Make accept return EINTR */
86 action.sa_flags &= ~SA_RESTART;
87 action.sa_handler = handle;
88 sigaction(sig, &action, NULL);
89 }
90
delete_temp_file(const char * host,const char * port,int cpu)91 static void delete_temp_file(const char *host, const char *port, int cpu)
92 {
93 char file[PATH_MAX];
94
95 snprintf(file, PATH_MAX, TEMP_FILE_STR);
96 unlink(file);
97 }
98
read_string(int fd,char * buf,size_t size)99 static int read_string(int fd, char *buf, size_t size)
100 {
101 size_t i;
102 int n;
103
104 for (i = 0; i < size; i++) {
105 n = read(fd, buf+i, 1);
106 if (!buf[i] || n <= 0)
107 break;
108 }
109
110 return i;
111 }
112
process_option(struct tracecmd_msg_handle * msg_handle,char * option)113 static int process_option(struct tracecmd_msg_handle *msg_handle, char *option)
114 {
115 /* currently the only option we have is to us TCP */
116 if (strcmp(option, "TCP") == 0) {
117 msg_handle->flags |= TRACECMD_MSG_FL_USE_TCP;
118 return 1;
119 }
120 return 0;
121 }
122
finish(int sig)123 static void finish(int sig)
124 {
125 if (stop_msg_handle)
126 tracecmd_msg_set_done(stop_msg_handle);
127 done = true;
128 }
129
make_pid_name(int mode,char * buf)130 static void make_pid_name(int mode, char *buf)
131 {
132 snprintf(buf, PATH_MAX, VAR_RUN_DIR "/trace-cmd-net.pid");
133 }
134
remove_pid_file(void)135 static void remove_pid_file(void)
136 {
137 char buf[PATH_MAX];
138 int mode = do_daemon;
139
140 if (!do_daemon)
141 return;
142
143 make_pid_name(mode, buf);
144
145 unlink(buf);
146 }
147
process_child(int sfd,const char * host,const char * port,int cpu,int page_size,enum port_type type)148 static int process_child(int sfd, const char *host, const char *port,
149 int cpu, int page_size, enum port_type type)
150 {
151 struct sockaddr_storage peer_addr;
152 #ifdef VSOCK
153 struct sockaddr_vm vm_addr;
154 #endif
155 struct sockaddr *addr;
156 socklen_t addr_len;
157 char buf[page_size];
158 char *tempfile;
159 int left;
160 int cfd;
161 int fd;
162 int r, w;
163 int once = 0;
164
165 signal_setup(SIGUSR1, finish);
166
167 tempfile = get_temp_file(host, port, cpu);
168 if (!tempfile)
169 return -ENOMEM;
170
171 fd = open(tempfile, O_WRONLY | O_TRUNC | O_CREAT, 0644);
172 if (fd < 0)
173 pdie("creating %s", tempfile);
174
175 if (type == USE_TCP) {
176 addr = (struct sockaddr *)&peer_addr;
177 addr_len = sizeof(peer_addr);
178 #ifdef VSOCK
179 } else if (type == USE_VSOCK) {
180 addr = (struct sockaddr *)&vm_addr;
181 addr_len = sizeof(vm_addr);
182 #endif
183 }
184
185 if (type == USE_TCP || type == USE_VSOCK) {
186 if (listen(sfd, backlog) < 0)
187 pdie("listen");
188
189 cfd = accept(sfd, addr, &addr_len);
190 if (cfd < 0 && errno == EINTR)
191 goto done;
192 if (cfd < 0)
193 pdie("accept");
194 close(sfd);
195 sfd = cfd;
196 }
197
198 for (;;) {
199 /* TODO, make this copyless! */
200 r = read(sfd, buf, page_size);
201 if (r < 0) {
202 if (errno == EINTR)
203 break;
204 pdie("reading pages from client");
205 }
206 if (!r)
207 break;
208 /* UDP requires that we get the full size in one go */
209 if (type == USE_UDP && r < page_size && !once) {
210 once = 1;
211 warning("read %d bytes, expected %d", r, page_size);
212 }
213
214 left = r;
215 do {
216 w = write(fd, buf + (r - left), left);
217 if (w > 0)
218 left -= w;
219 } while (w >= 0 && left);
220 }
221
222 done:
223 put_temp_file(tempfile);
224 exit(0);
225 }
226
setup_vsock_port(int start_port,int * sfd)227 static int setup_vsock_port(int start_port, int *sfd)
228 {
229 int sd;
230
231 sd = trace_vsock_make(start_port);
232 if (sd < 0)
233 return -errno;
234 *sfd = sd;
235
236 return start_port;
237 }
238
trace_net_make(int port,enum port_type type)239 int trace_net_make(int port, enum port_type type)
240 {
241 struct addrinfo hints;
242 struct addrinfo *result, *rp;
243 char buf[BUFSIZ];
244 int sd;
245 int s;
246
247 snprintf(buf, BUFSIZ, "%d", port);
248
249 memset(&hints, 0, sizeof(hints));
250 hints.ai_family = AF_UNSPEC;
251 hints.ai_flags = AI_PASSIVE;
252
253 switch (type) {
254 case USE_TCP:
255 hints.ai_socktype = SOCK_STREAM;
256 break;
257 case USE_UDP:
258 hints.ai_socktype = SOCK_DGRAM;
259 break;
260 default:
261 return -1;
262 }
263
264 s = getaddrinfo(NULL, buf, &hints, &result);
265 if (s != 0)
266 pdie("getaddrinfo: error opening socket");
267
268 for (rp = result; rp != NULL; rp = rp->ai_next) {
269 sd = socket(rp->ai_family, rp->ai_socktype,
270 rp->ai_protocol);
271 if (sd < 0)
272 continue;
273
274 if (bind(sd, rp->ai_addr, rp->ai_addrlen) == 0)
275 break;
276
277 close(sd);
278 }
279 freeaddrinfo(result);
280
281 if (rp == NULL)
282 return -1;
283
284 dprint("Create listen port: %d fd:%d\n", port, sd);
285
286 return sd;
287 }
288
trace_net_search(int start_port,int * sfd,enum port_type type)289 int trace_net_search(int start_port, int *sfd, enum port_type type)
290 {
291 int num_port = start_port;
292
293 if (type == USE_VSOCK)
294 return setup_vsock_port(start_port, sfd);
295 again:
296 *sfd = trace_net_make(num_port, type);
297 if (*sfd < 0) {
298 if (++num_port > MAX_PORT_SEARCH)
299 pdie("No available ports to bind");
300 goto again;
301 }
302
303 return num_port;
304 }
305
fork_reader(int sfd,const char * node,const char * port,int * pid,int cpu,int pagesize,enum port_type type)306 static void fork_reader(int sfd, const char *node, const char *port,
307 int *pid, int cpu, int pagesize, enum port_type type)
308 {
309 int ret;
310
311 *pid = fork();
312
313 if (*pid < 0)
314 pdie("creating reader");
315
316 if (!*pid) {
317 ret = process_child(sfd, node, port, cpu, pagesize, type);
318 if (ret < 0)
319 pdie("Problem with reader %d", ret);
320 }
321
322 close(sfd);
323 }
324
open_port(const char * node,const char * port,int * pid,int cpu,int pagesize,int start_port,enum port_type type)325 static int open_port(const char *node, const char *port, int *pid,
326 int cpu, int pagesize, int start_port, enum port_type type)
327 {
328 int sfd;
329 int num_port;
330
331 /*
332 * trace_net_search() currently does not return an error, but if that
333 * changes in the future, we have a check for it now.
334 */
335 num_port = trace_net_search(start_port, &sfd, type);
336 if (num_port < 0)
337 return num_port;
338
339 fork_reader(sfd, node, port, pid, cpu, pagesize, type);
340
341 return num_port;
342 }
343
communicate_with_client(struct tracecmd_msg_handle * msg_handle)344 static int communicate_with_client(struct tracecmd_msg_handle *msg_handle)
345 {
346 char *last_proto = NULL;
347 char buf[BUFSIZ];
348 char *option;
349 int pagesize = 0;
350 int options;
351 int size;
352 int cpus;
353 int n, s, t, i;
354 int ret = -EINVAL;
355 int fd = msg_handle->fd;
356
357 /* Let the client know what we are */
358 write(fd, "tracecmd", 8);
359
360 try_again:
361 /* read back the CPU count */
362 n = read_string(fd, buf, BUFSIZ);
363 if (n == BUFSIZ)
364 /** ERROR **/
365 return -EINVAL;
366
367 cpus = atoi(buf);
368
369 /* Is the client using the new protocol? */
370 if (cpus == -1) {
371 if (memcmp(buf, V3_CPU, n) != 0) {
372 /* If it did not send a version, then bail */
373 if (memcmp(buf, "-1V", 3)) {
374 tracecmd_plog("Unknown string %s\n", buf);
375 goto out;
376 }
377 /* Skip "-1" */
378 tracecmd_plog("Cannot handle the protocol %s\n", buf+2);
379
380 /* If it returned the same command as last time, bail! */
381 if (last_proto && strncmp(last_proto, buf, n) == 0) {
382 tracecmd_plog("Repeat of version %s sent\n", last_proto);
383 goto out;
384 }
385 free(last_proto);
386 last_proto = malloc(n + 1);
387 if (last_proto) {
388 memcpy(last_proto, buf, n);
389 last_proto[n] = 0;
390 }
391 /* Return the highest protocol we can use */
392 write(fd, "V3", 3);
393 goto try_again;
394 }
395
396 /* Let the client know we use v3 protocol */
397 write(fd, "V3", 3);
398
399 /* read the rest of dummy data */
400 n = read(fd, buf, sizeof(V3_MAGIC));
401 if (memcmp(buf, V3_MAGIC, n) != 0)
402 goto out;
403
404 /* We're off! */
405 write(fd, "OK", 2);
406
407 msg_handle->version = V3_PROTOCOL;
408
409 /* read the CPU count, the page size, and options */
410 if ((pagesize = tracecmd_msg_initial_setting(msg_handle)) < 0)
411 goto out;
412 } else {
413 /* The client is using the v1 protocol */
414
415 tracecmd_plog("cpus=%d\n", cpus);
416 if (cpus < 0)
417 goto out;
418
419 msg_handle->cpu_count = cpus;
420
421 /* next read the page size */
422 n = read_string(fd, buf, BUFSIZ);
423 if (n == BUFSIZ)
424 /** ERROR **/
425 goto out;
426
427 pagesize = atoi(buf);
428
429 tracecmd_plog("pagesize=%d\n", pagesize);
430 if (pagesize <= 0)
431 goto out;
432
433 /* Now the number of options */
434 n = read_string(fd, buf, BUFSIZ);
435 if (n == BUFSIZ)
436 /** ERROR **/
437 return -EINVAL;
438
439 options = atoi(buf);
440
441 for (i = 0; i < options; i++) {
442 /* next is the size of the options */
443 n = read_string(fd, buf, BUFSIZ);
444 if (n == BUFSIZ)
445 /** ERROR **/
446 goto out;
447 size = atoi(buf);
448 /* prevent a client from killing us */
449 if (size > MAX_OPTION_SIZE)
450 goto out;
451
452 ret = -ENOMEM;
453 option = malloc(size);
454 if (!option)
455 goto out;
456
457 ret = -EIO;
458 do {
459 t = size;
460 s = 0;
461 s = read(fd, option+s, t);
462 if (s <= 0)
463 goto out;
464 t -= s;
465 s = size - t;
466 } while (t);
467
468 s = process_option(msg_handle, option);
469 free(option);
470 /* do we understand this option? */
471 ret = -EINVAL;
472 if (!s)
473 goto out;
474 }
475 }
476
477 if (msg_handle->flags & TRACECMD_MSG_FL_USE_TCP)
478 tracecmd_plog("Using TCP for live connection\n");
479
480 ret = pagesize;
481 out:
482 free(last_proto);
483
484 return ret;
485 }
486
create_client_file(const char * node,const char * port)487 static int create_client_file(const char *node, const char *port)
488 {
489 char buf[BUFSIZ];
490 int ofd;
491
492 snprintf(buf, BUFSIZ, "%s.%s:%s.dat", output_file, node, port);
493
494 ofd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0644);
495 if (ofd < 0)
496 pdie("Can not create file %s", buf);
497 return ofd;
498 }
499
destroy_all_readers(int cpus,int * pid_array,const char * node,const char * port)500 static void destroy_all_readers(int cpus, int *pid_array, const char *node,
501 const char *port)
502 {
503 int cpu;
504
505 for (cpu = 0; cpu < cpus; cpu++) {
506 if (pid_array[cpu] > 0) {
507 kill(pid_array[cpu], SIGKILL);
508 waitpid(pid_array[cpu], NULL, 0);
509 delete_temp_file(node, port, cpu);
510 pid_array[cpu] = 0;
511 }
512 }
513
514 free(pid_array);
515 }
516
create_all_readers(const char * node,const char * port,int pagesize,struct tracecmd_msg_handle * msg_handle)517 static int *create_all_readers(const char *node, const char *port,
518 int pagesize, struct tracecmd_msg_handle *msg_handle)
519 {
520 enum port_type port_type = USE_UDP;
521 char buf[BUFSIZ];
522 unsigned int *port_array;
523 int *pid_array;
524 unsigned int start_port;
525 unsigned int connect_port;
526 int cpus = msg_handle->cpu_count;
527 int cpu;
528 int pid;
529
530 if (!pagesize)
531 return NULL;
532
533 if (msg_handle->flags & TRACECMD_MSG_FL_USE_TCP)
534 port_type = USE_TCP;
535 else if (msg_handle->flags & TRACECMD_MSG_FL_USE_VSOCK)
536 port_type = USE_VSOCK;
537
538 port_array = malloc(sizeof(*port_array) * cpus);
539 if (!port_array)
540 return NULL;
541
542 pid_array = malloc(sizeof(*pid_array) * cpus);
543 if (!pid_array) {
544 free(port_array);
545 return NULL;
546 }
547
548 memset(pid_array, 0, sizeof(int) * cpus);
549
550 start_port = START_PORT_SEARCH;
551
552 /* Now create a port for each CPU */
553 for (cpu = 0; cpu < cpus; cpu++) {
554 connect_port = open_port(node, port, &pid, cpu,
555 pagesize, start_port, port_type);
556 if (connect_port < 0)
557 goto out_free;
558 port_array[cpu] = connect_port;
559 pid_array[cpu] = pid;
560 /*
561 * Due to some bugging finding ports,
562 * force search after last port
563 */
564 start_port = connect_port + 1;
565 }
566
567 if (msg_handle->version == V3_PROTOCOL) {
568 /* send set of port numbers to the client */
569 if (tracecmd_msg_send_port_array(msg_handle, port_array) < 0) {
570 tracecmd_plog("Failed sending port array\n");
571 goto out_free;
572 }
573 } else {
574 /* send the client a comma deliminated set of port numbers */
575 for (cpu = 0; cpu < cpus; cpu++) {
576 snprintf(buf, BUFSIZ, "%s%d",
577 cpu ? "," : "", port_array[cpu]);
578 write(msg_handle->fd, buf, strlen(buf));
579 }
580 /* end with null terminator */
581 write(msg_handle->fd, "\0", 1);
582 }
583
584 free(port_array);
585 return pid_array;
586
587 out_free:
588 free(port_array);
589 destroy_all_readers(cpus, pid_array, node, port);
590 return NULL;
591 }
592
593 static int
collect_metadata_from_client(struct tracecmd_msg_handle * msg_handle,int ofd)594 collect_metadata_from_client(struct tracecmd_msg_handle *msg_handle,
595 int ofd)
596 {
597 char buf[BUFSIZ];
598 int n, s, t;
599 int ifd = msg_handle->fd;
600 int ret = 0;
601
602 do {
603 n = read(ifd, buf, BUFSIZ);
604 if (n < 0) {
605 if (errno == EINTR)
606 continue;
607 ret = -errno;
608 break;
609 }
610 t = n;
611 s = 0;
612 do {
613 s = write(ofd, buf+s, t);
614 if (s < 0) {
615 if (errno == EINTR)
616 break;
617 ret = -errno;
618 goto out;
619 }
620 t -= s;
621 s = n - t;
622 } while (t);
623 } while (n > 0 && !tracecmd_msg_done(msg_handle));
624
625 out:
626 return ret;
627 }
628
stop_all_readers(int cpus,int * pid_array)629 static void stop_all_readers(int cpus, int *pid_array)
630 {
631 int cpu;
632
633 for (cpu = 0; cpu < cpus; cpu++) {
634 if (pid_array[cpu] > 0)
635 kill(pid_array[cpu], SIGUSR1);
636 }
637 }
638
put_together_file(int cpus,int ofd,const char * node,const char * port,bool write_options)639 static int put_together_file(int cpus, int ofd, const char *node,
640 const char *port, bool write_options)
641 {
642 struct tracecmd_output *handle = NULL;
643 char **temp_files;
644 int cpu;
645 int ret = -ENOMEM;
646
647 /* Now put together the file */
648 temp_files = malloc(sizeof(*temp_files) * cpus);
649 if (!temp_files)
650 return -ENOMEM;
651
652 for (cpu = 0; cpu < cpus; cpu++) {
653 temp_files[cpu] = get_temp_file(node, port, cpu);
654 if (!temp_files[cpu])
655 goto out;
656 }
657
658 handle = tracecmd_get_output_handle_fd(ofd);
659 if (!handle) {
660 ret = -1;
661 goto out;
662 }
663
664 if (write_options) {
665 ret = tracecmd_write_cpus(handle, cpus);
666 if (ret)
667 goto out;
668 ret = tracecmd_write_buffer_info(handle);
669 if (ret)
670 goto out;
671 ret = tracecmd_write_options(handle);
672 if (ret)
673 goto out;
674 }
675 ret = tracecmd_write_cpu_data(handle, cpus, temp_files, NULL);
676
677 out:
678 tracecmd_output_close(handle);
679 for (cpu--; cpu >= 0; cpu--) {
680 put_temp_file(temp_files[cpu]);
681 }
682 free(temp_files);
683 return ret;
684 }
685
process_client(struct tracecmd_msg_handle * msg_handle,const char * node,const char * port)686 static int process_client(struct tracecmd_msg_handle *msg_handle,
687 const char *node, const char *port)
688 {
689 int *pid_array;
690 int pagesize;
691 int cpus;
692 int ofd;
693 int ret;
694
695 pagesize = communicate_with_client(msg_handle);
696 if (pagesize < 0)
697 return pagesize;
698
699 ofd = create_client_file(node, port);
700
701 pid_array = create_all_readers(node, port, pagesize, msg_handle);
702 if (!pid_array)
703 return -ENOMEM;
704
705 /* on signal stop this msg */
706 stop_msg_handle = msg_handle;
707
708 /* Now we are ready to start reading data from the client */
709 if (msg_handle->version == V3_PROTOCOL)
710 ret = tracecmd_msg_collect_data(msg_handle, ofd);
711 else
712 ret = collect_metadata_from_client(msg_handle, ofd);
713 stop_msg_handle = NULL;
714
715 /* wait a little to let our readers finish reading */
716 sleep(1);
717
718 cpus = msg_handle->cpu_count;
719
720 /* stop our readers */
721 stop_all_readers(cpus, pid_array);
722
723 /* wait a little to have the readers clean up */
724 sleep(1);
725
726 if (!ret)
727 ret = put_together_file(cpus, ofd, node, port,
728 msg_handle->version < V3_PROTOCOL);
729
730 destroy_all_readers(cpus, pid_array, node, port);
731
732 return ret;
733 }
734
do_fork(int cfd)735 static int do_fork(int cfd)
736 {
737 pid_t pid;
738
739 /* in debug mode, we do not fork off children */
740 if (tracecmd_get_debug())
741 return 0;
742
743 pid = fork();
744 if (pid < 0) {
745 warning("failed to create child");
746 return -1;
747 }
748
749 if (pid > 0) {
750 close(cfd);
751 return pid;
752 }
753
754 signal_setup(SIGINT, finish);
755
756 return 0;
757 }
758
trace_net_cmp_connection(struct sockaddr_storage * addr,const char * name)759 bool trace_net_cmp_connection(struct sockaddr_storage *addr, const char *name)
760 {
761 char host[NI_MAXHOST], nhost[NI_MAXHOST];
762 char service[NI_MAXSERV];
763 socklen_t addr_len = sizeof(*addr);
764 struct addrinfo *result, *rp;
765 struct addrinfo hints;
766 bool found = false;
767 int s;
768
769 if (getnameinfo((struct sockaddr *)addr, addr_len,
770 host, NI_MAXHOST,
771 service, NI_MAXSERV, NI_NUMERICSERV))
772 return -1;
773
774 if (strcmp(host, name) == 0)
775 return true;
776
777 /* Check other IPs that name could be for */
778
779 memset(&hints, 0, sizeof(hints));
780 hints.ai_family = AF_UNSPEC;
781 hints.ai_socktype = SOCK_STREAM;
782
783 /* Check other IPs that name could be for */
784 s = getaddrinfo(name, NULL, &hints, &result);
785 if (s != 0)
786 return false;
787
788 for (rp = result; rp != NULL; rp = rp->ai_next) {
789 if (getnameinfo(rp->ai_addr, rp->ai_addrlen,
790 nhost, NI_MAXHOST,
791 service, NI_MAXSERV, NI_NUMERICSERV))
792 continue;
793 if (strcmp(host, nhost) == 0) {
794 found = 1;
795 break;
796 }
797 }
798
799 freeaddrinfo(result);
800 return found;
801 }
802
trace_net_cmp_connection_fd(int fd,const char * name)803 bool trace_net_cmp_connection_fd(int fd, const char *name)
804 {
805 struct sockaddr_storage addr;
806 socklen_t addr_len = sizeof(addr);
807
808 if (getpeername(fd, (struct sockaddr *)&addr, &addr_len))
809 return false;
810
811 return trace_net_cmp_connection(&addr, name);
812 };
813
trace_net_print_connection(int fd)814 int trace_net_print_connection(int fd)
815 {
816 char host[NI_MAXHOST], service[NI_MAXSERV];
817 struct sockaddr_storage net_addr;
818 socklen_t addr_len;
819
820 addr_len = sizeof(net_addr);
821 if (getpeername(fd, (struct sockaddr *)&net_addr, &addr_len))
822 return -1;
823
824 if (getnameinfo((struct sockaddr *)&net_addr, addr_len,
825 host, NI_MAXHOST,
826 service, NI_MAXSERV, NI_NUMERICSERV))
827 return -1;
828
829 if (tracecmd_get_debug())
830 tracecmd_debug("Connected to %s:%s fd:%d\n", host, service, fd);
831 else
832 tracecmd_plog("Connected to %s:%s\n", host, service);
833 return 0;
834 }
835
do_connection(int cfd,struct sockaddr * addr,socklen_t addr_len)836 static int do_connection(int cfd, struct sockaddr *addr,
837 socklen_t addr_len)
838 {
839 struct tracecmd_msg_handle *msg_handle;
840 char host[NI_MAXHOST], service[NI_MAXSERV];
841 int s;
842 int ret;
843
844 ret = do_fork(cfd);
845 if (ret)
846 return ret;
847
848 msg_handle = tracecmd_msg_handle_alloc(cfd, 0);
849
850 if (use_vsock) {
851 #ifdef VSOCK
852 struct sockaddr_vm *vm_addr = (struct sockaddr_vm *)addr;
853 snprintf(host, NI_MAXHOST, "V%d", vm_addr->svm_cid);
854 snprintf(service, NI_MAXSERV, "%d", vm_addr->svm_port);
855 #endif
856 } else {
857 s = getnameinfo((struct sockaddr *)addr, addr_len,
858 host, NI_MAXHOST,
859 service, NI_MAXSERV, NI_NUMERICSERV);
860
861 if (s == 0)
862 tracecmd_plog("Connected with %s:%s\n", host, service);
863 else {
864 tracecmd_plog("Error with getnameinfo: %s\n", gai_strerror(s));
865 close(cfd);
866 tracecmd_msg_handle_close(msg_handle);
867 return -1;
868 }
869 }
870
871 process_client(msg_handle, host, service);
872
873 tracecmd_msg_handle_close(msg_handle);
874
875 if (!tracecmd_get_debug())
876 exit(0);
877
878 return 0;
879 }
880
881 static int *client_pids;
882 static int free_pids;
883 static int saved_pids;
884
add_process(int pid)885 static void add_process(int pid)
886 {
887 int *client = NULL;
888 int i;
889
890 if (free_pids) {
891 for (i = 0; i < saved_pids; i++) {
892 if (!client_pids[i]) {
893 client = &client_pids[i];
894 break;
895 }
896 }
897 free_pids--;
898 if (!client)
899 warning("Could not find free pid");
900 }
901 if (!client) {
902 client_pids = realloc(client_pids,
903 sizeof(*client_pids) * (saved_pids + 1));
904 if (!client_pids)
905 pdie("allocating pids");
906 client = &client_pids[saved_pids++];
907 }
908 *client = pid;
909 }
910
remove_process(int pid)911 static void remove_process(int pid)
912 {
913 int i;
914
915 for (i = 0; i < saved_pids; i++) {
916 if (client_pids[i] == pid)
917 break;
918 }
919
920 if (i == saved_pids)
921 return;
922
923 client_pids[i] = 0;
924 free_pids++;
925 }
926
kill_clients(void)927 static void kill_clients(void)
928 {
929 int status;
930 int i;
931
932 for (i = 0; i < saved_pids; i++) {
933 if (!client_pids[i])
934 continue;
935 /* Only kill the clients if we received SIGINT or SIGTERM */
936 if (done)
937 kill(client_pids[i], SIGINT);
938 waitpid(client_pids[i], &status, 0);
939 }
940
941 saved_pids = 0;
942 }
943
clean_up(void)944 static void clean_up(void)
945 {
946 int status;
947 int ret;
948
949 /* Clean up any children that has started before */
950 do {
951 ret = waitpid(0, &status, WNOHANG);
952 if (ret > 0)
953 remove_process(ret);
954 } while (ret > 0);
955 }
956
do_accept_loop(int sfd)957 static void do_accept_loop(int sfd)
958 {
959 struct sockaddr_storage peer_addr;
960 #ifdef VSOCK
961 struct sockaddr_vm vm_addr;
962 #endif
963 struct sockaddr *addr;
964 socklen_t addr_len;
965 int cfd, pid;
966
967 if (use_vsock) {
968 #ifdef VSOCK
969 addr = (struct sockaddr *)&vm_addr;
970 addr_len = sizeof(vm_addr);
971 #endif
972 } else {
973 addr = (struct sockaddr *)&peer_addr;
974 addr_len = sizeof(peer_addr);
975 }
976
977 do {
978 cfd = accept(sfd, addr, &addr_len);
979 if (cfd < 0 && errno == EINTR) {
980 clean_up();
981 continue;
982 }
983 if (cfd < 0)
984 pdie("connecting");
985
986 pid = do_connection(cfd, addr, addr_len);
987 if (pid > 0)
988 add_process(pid);
989
990 } while (!done);
991 /* Get any final stragglers */
992 clean_up();
993 }
994
make_pid_file(void)995 static void make_pid_file(void)
996 {
997 char buf[PATH_MAX];
998 int mode = do_daemon;
999 int fd;
1000
1001 if (!do_daemon)
1002 return;
1003
1004 make_pid_name(mode, buf);
1005
1006 fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1007 if (fd < 0) {
1008 perror(buf);
1009 return;
1010 }
1011
1012 sprintf(buf, "%d\n", getpid());
1013 write(fd, buf, strlen(buf));
1014 close(fd);
1015 }
1016
sigstub(int sig)1017 static void sigstub(int sig)
1018 {
1019 }
1020
get_vsock(const char * port)1021 static int get_vsock(const char *port)
1022 {
1023 unsigned int cid;
1024 int sd;
1025
1026 sd = trace_vsock_make(atoi(port));
1027 if (sd < 0)
1028 return sd;
1029
1030 cid = trace_vsock_local_cid();
1031 if (cid >= 0)
1032 printf("listening on @%u:%s\n", cid, port);
1033
1034 return sd;
1035 }
1036
get_network(char * port)1037 static int get_network(char *port)
1038 {
1039 struct addrinfo hints;
1040 struct addrinfo *result, *rp;
1041 int sfd, s;
1042
1043 memset(&hints, 0, sizeof(hints));
1044 hints.ai_family = AF_UNSPEC;
1045 hints.ai_socktype = SOCK_STREAM;
1046 hints.ai_flags = AI_PASSIVE;
1047
1048 s = getaddrinfo(NULL, port, &hints, &result);
1049 if (s != 0)
1050 pdie("getaddrinfo: error opening %s", port);
1051
1052 for (rp = result; rp != NULL; rp = rp->ai_next) {
1053 sfd = socket(rp->ai_family, rp->ai_socktype,
1054 rp->ai_protocol);
1055 if (sfd < 0)
1056 continue;
1057
1058 if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
1059 break;
1060
1061 close(sfd);
1062 }
1063
1064 if (rp == NULL)
1065 pdie("Could not bind");
1066
1067 freeaddrinfo(result);
1068
1069 return sfd;
1070 }
1071
do_listen(char * port)1072 static void do_listen(char *port)
1073 {
1074 int sfd;
1075
1076 if (!tracecmd_get_debug())
1077 signal_setup(SIGCHLD, sigstub);
1078
1079 make_pid_file();
1080
1081 if (use_vsock)
1082 sfd = get_vsock(port);
1083 else
1084 sfd = get_network(port);
1085
1086
1087 if (listen(sfd, backlog) < 0)
1088 pdie("listen");
1089
1090 do_accept_loop(sfd);
1091
1092 kill_clients();
1093
1094 remove_pid_file();
1095 }
1096
start_daemon(void)1097 static void start_daemon(void)
1098 {
1099 do_daemon = 1;
1100
1101 if (daemon(1, 0) < 0)
1102 die("starting daemon");
1103 }
1104
1105 enum {
1106 OPT_verbose = 254,
1107 OPT_debug = 255,
1108 };
1109
trace_listen(int argc,char ** argv)1110 void trace_listen(int argc, char **argv)
1111 {
1112 char *logfile = NULL;
1113 char *port = NULL;
1114 int daemon = 0;
1115 int c;
1116
1117 if (argc < 2)
1118 usage(argv);
1119
1120 if (strcmp(argv[1], "listen") != 0)
1121 usage(argv);
1122
1123 for (;;) {
1124 int option_index = 0;
1125 static struct option long_options[] = {
1126 {"port", required_argument, NULL, 'p'},
1127 {"help", no_argument, NULL, '?'},
1128 {"debug", no_argument, NULL, OPT_debug},
1129 {"verbose", optional_argument, NULL, OPT_verbose},
1130 {NULL, 0, NULL, 0}
1131 };
1132
1133 c = getopt_long (argc-1, argv+1, "+hp:Vo:d:l:D",
1134 long_options, &option_index);
1135 if (c == -1)
1136 break;
1137 switch (c) {
1138 case 'h':
1139 usage(argv);
1140 break;
1141 case 'p':
1142 port = optarg;
1143 break;
1144 case 'd':
1145 output_dir = optarg;
1146 break;
1147 case 'V':
1148 use_vsock = true;
1149 break;
1150 case 'o':
1151 output_file = optarg;
1152 break;
1153 case 'l':
1154 logfile = optarg;
1155 break;
1156 case 'D':
1157 daemon = 1;
1158 break;
1159 case OPT_debug:
1160 tracecmd_set_debug(true);
1161 break;
1162 case OPT_verbose:
1163 if (trace_set_verbose(optarg) < 0)
1164 die("invalid verbose level %s", optarg);
1165 break;
1166 default:
1167 usage(argv);
1168 }
1169 }
1170
1171 if (!port)
1172 usage(argv);
1173
1174 if ((argc - optind) >= 2)
1175 usage(argv);
1176
1177 if (!output_file)
1178 output_file = default_output_file;
1179
1180 if (!output_dir)
1181 output_dir = default_output_dir;
1182
1183 if (logfile) {
1184 /* set the writes to a logfile instead */
1185 if (tracecmd_set_logfile(logfile) < 0)
1186 die("creating log file %s", logfile);
1187 }
1188
1189 if (chdir(output_dir) < 0)
1190 die("Can't access directory %s", output_dir);
1191
1192 if (daemon)
1193 start_daemon();
1194
1195 signal_setup(SIGINT, finish);
1196 signal_setup(SIGTERM, finish);
1197
1198 do_listen(port);
1199
1200 return;
1201 }
1202