3 * Linux Trace Toolkit Daemon
5 * This is a simple daemon that reads a few relay+debugfs channels and save
8 * CPU hot-plugging is supported using inotify.
10 * Copyright 2009-2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 #include <sys/types.h>
47 #include <sys/syscall.h>
49 #include <asm/ioctls.h>
51 #include <linux/version.h>
54 #include <asm/ioctl.h>
55 #include <asm/types.h>
57 /* Get the next sub buffer that can be read. */
58 #define RELAY_GET_SB _IOR(0xF5, 0x00,__u32)
59 /* Release the oldest reserved (by "get") sub buffer. */
60 #define RELAY_PUT_SB _IOW(0xF5, 0x01,__u32)
61 /* returns the number of sub buffers in the per cpu channel. */
62 #define RELAY_GET_N_SB _IOR(0xF5, 0x02,__u32)
63 /* returns the size of the current sub buffer. */
64 #define RELAY_GET_SB_SIZE _IOR(0xF5, 0x03, __u32)
65 /* returns the size of data to consume in the current sub-buffer. */
66 #define RELAY_GET_MAX_SB_SIZE _IOR(0xF5, 0x04, __u32)
69 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
70 #include <sys/inotify.h>
71 #if 0 /* should now be provided by libc. */
72 /* From the inotify-tools 2.6 package */
73 static inline int inotify_init (void)
75 return syscall (__NR_inotify_init
);
78 static inline int inotify_add_watch (int fd
, const char *name
, __u32 mask
)
80 return syscall (__NR_inotify_add_watch
, fd
, name
, mask
);
83 static inline int inotify_rm_watch (int fd
, __u32 wd
)
85 return syscall (__NR_inotify_rm_watch
, fd
, wd
);
90 static inline int inotify_init (void)
95 static inline int inotify_add_watch (int fd
, const char *name
, __u32 mask
)
100 static inline int inotify_rm_watch (int fd
, __u32 wd
)
111 unsigned int max_sb_size
;
113 pthread_mutex_t mutex
;
116 struct channel_trace_fd
{
117 struct fd_pair
*pair
;
121 struct inotify_watch
{
123 char path_channel
[PATH_MAX
];
124 char path_trace
[PATH_MAX
];
127 struct inotify_watch_array
{
128 struct inotify_watch
*elem
;
132 static __thread
int thread_pipe
[2];
134 struct channel_trace_fd fd_pairs
= { NULL
, 0 };
136 struct inotify_watch_array inotify_watch_array
= { NULL
, 0 };
138 /* protects fd_pairs and inotify_watch_array */
139 pthread_rwlock_t fd_pairs_lock
= PTHREAD_RWLOCK_INITIALIZER
;
142 static char *trace_name
= NULL
;
143 static char *channel_name
= NULL
;
144 static int daemon_mode
= 0;
145 static int append_mode
= 0;
146 static unsigned long num_threads
= 1;
147 volatile static int quit_program
= 0; /* For signal handler */
148 static int dump_flight_only
= 0;
149 static int dump_normal_only
= 0;
150 static int verbose_mode
= 0;
152 #define printf_verbose(fmt, args...) \
155 printf(fmt, ##args); \
160 * -t directory Directory name of the trace to write to. Will be created.
161 * -c directory Root directory of the debugfs trace channels.
162 * -d Run in background (daemon).
163 * -a Trace append mode.
164 * -s Send SIGUSR1 to parent when ready for IO.
166 void show_arguments(void)
168 printf("Please use the following arguments :\n");
170 printf("-t directory Directory name of the trace to write to.\n"
171 " It will be created.\n");
172 printf("-c directory Root directory of the debugfs trace channels.\n");
173 printf("-d Run in background (daemon).\n");
174 printf("-a Append to an possibly existing trace.\n");
175 printf("-N Number of threads to start.\n");
176 printf("-f Dump only flight recorder channels.\n");
177 printf("-n Dump only normal channels.\n");
178 printf("-v Verbose mode.\n");
185 * Parses the command line arguments.
187 * Returns 1 if the arguments were correct, but doesn't ask for program
188 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
190 int parse_arguments(int argc
, char **argv
)
196 if(strcmp(argv
[1], "-h") == 0) {
203 switch(argv
[argn
][0]) {
205 switch(argv
[argn
][1]) {
208 trace_name
= argv
[argn
+1];
214 channel_name
= argv
[argn
+1];
226 num_threads
= strtoul(argv
[argn
+1], NULL
, 0);
231 dump_flight_only
= 1;
234 dump_normal_only
= 1;
240 printf("Invalid argument '%s'.\n", argv
[argn
]);
246 printf("Invalid argument '%s'.\n", argv
[argn
]);
253 if(trace_name
== NULL
) {
254 printf("Please specify a trace name.\n");
259 if(channel_name
== NULL
) {
260 printf("Please specify a channel name.\n");
270 printf("Linux Trace Toolkit Trace Daemon " VERSION
"\n");
272 printf("Reading from debugfs directory : %s\n", channel_name
);
273 printf("Writing to trace directory : %s\n", trace_name
);
278 /* signal handling */
280 static void handler(int signo
)
282 printf("Signal %d received : exiting cleanly\n", signo
);
287 int open_buffer_file(char *filename
, char *path_channel
, char *path_trace
,
288 struct channel_trace_fd
*fd_pairs
)
292 struct stat stat_buf
;
294 if(strncmp(filename
, "flight-", sizeof("flight-")-1) != 0) {
295 if(dump_flight_only
) {
296 printf_verbose("Skipping normal channel %s\n",
301 if(dump_normal_only
) {
302 printf_verbose("Skipping flight channel %s\n",
307 printf_verbose("Opening file.\n");
309 fd_pairs
->pair
= realloc(fd_pairs
->pair
,
310 ++fd_pairs
->num_pairs
* sizeof(struct fd_pair
));
312 /* Open the channel in read mode */
313 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
=
314 open(path_channel
, O_RDONLY
| O_NONBLOCK
);
315 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
== -1) {
316 perror(path_channel
);
317 fd_pairs
->num_pairs
--;
318 return 0; /* continue */
320 /* Open the trace in write mode, only append if append_mode */
321 ret
= stat(path_trace
, &stat_buf
);
324 printf_verbose("Appending to file %s as requested\n",
327 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
328 open(path_trace
, O_WRONLY
,
329 S_IRWXU
|S_IRWXG
|S_IRWXO
);
330 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
333 close(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
);
334 fd_pairs
->num_pairs
--;
337 ret
= lseek(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
,
342 close(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
);
343 close(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
);
344 fd_pairs
->num_pairs
--;
348 printf("File %s exists, cannot open. Try append mode.\n", path_trace
);
350 close(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
);
351 fd_pairs
->num_pairs
--;
355 if(errno
== ENOENT
) {
356 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
357 open(path_trace
, O_WRONLY
|O_CREAT
|O_EXCL
,
358 S_IRWXU
|S_IRWXG
|S_IRWXO
);
359 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
362 close(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
);
363 fd_pairs
->num_pairs
--;
372 int open_channel_trace_pairs(char *subchannel_name
, char *subtrace_name
,
373 struct channel_trace_fd
*fd_pairs
, int *inotify_fd
,
374 struct inotify_watch_array
*iwatch_array
)
376 DIR *channel_dir
= opendir(subchannel_name
);
377 struct dirent
*entry
;
378 struct stat stat_buf
;
380 char path_channel
[PATH_MAX
];
381 int path_channel_len
;
382 char *path_channel_ptr
;
383 char path_trace
[PATH_MAX
];
385 char *path_trace_ptr
;
388 if(channel_dir
== NULL
) {
389 perror(subchannel_name
);
394 printf_verbose("Creating trace subdirectory %s\n", subtrace_name
);
395 ret
= mkdir(subtrace_name
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
397 if(errno
!= EEXIST
) {
398 perror(subtrace_name
);
404 strncpy(path_channel
, subchannel_name
, PATH_MAX
-1);
405 path_channel_len
= strlen(path_channel
);
406 path_channel
[path_channel_len
] = '/';
408 path_channel_ptr
= path_channel
+ path_channel_len
;
410 strncpy(path_trace
, subtrace_name
, PATH_MAX
-1);
411 path_trace_len
= strlen(path_trace
);
412 path_trace
[path_trace_len
] = '/';
414 path_trace_ptr
= path_trace
+ path_trace_len
;
417 iwatch_array
->elem
= realloc(iwatch_array
->elem
,
418 ++iwatch_array
->num
* sizeof(struct inotify_watch
));
420 printf_verbose("Adding inotify for channel %s\n", path_channel
);
421 iwatch_array
->elem
[iwatch_array
->num
-1].wd
= inotify_add_watch(*inotify_fd
, path_channel
, IN_CREATE
);
422 strcpy(iwatch_array
->elem
[iwatch_array
->num
-1].path_channel
, path_channel
);
423 strcpy(iwatch_array
->elem
[iwatch_array
->num
-1].path_trace
, path_trace
);
424 printf_verbose("Added inotify for channel %s, wd %u\n",
425 iwatch_array
->elem
[iwatch_array
->num
-1].path_channel
,
426 iwatch_array
->elem
[iwatch_array
->num
-1].wd
);
429 while((entry
= readdir(channel_dir
)) != NULL
) {
431 if(entry
->d_name
[0] == '.') continue;
433 strncpy(path_channel_ptr
, entry
->d_name
, PATH_MAX
- path_channel_len
);
434 strncpy(path_trace_ptr
, entry
->d_name
, PATH_MAX
- path_trace_len
);
436 ret
= stat(path_channel
, &stat_buf
);
438 perror(path_channel
);
442 printf_verbose("Channel file : %s\n", path_channel
);
444 if(S_ISDIR(stat_buf
.st_mode
)) {
446 printf_verbose("Entering channel subdirectory...\n");
447 ret
= open_channel_trace_pairs(path_channel
, path_trace
, fd_pairs
,
448 inotify_fd
, iwatch_array
);
449 if(ret
< 0) continue;
450 } else if(S_ISREG(stat_buf
.st_mode
)) {
451 open_ret
= open_buffer_file(entry
->d_name
, path_channel
, path_trace
,
459 closedir(channel_dir
);
465 int read_subbuffer(struct fd_pair
*pair
)
467 unsigned int consumed_old
, len
;
473 err
= ioctl(pair
->channel
, RELAY_GET_SB
, &consumed_old
);
474 printf_verbose("cookie : %u\n", consumed_old
);
477 perror("Reserving sub buffer failed (everything is normal, it is due to concurrency)");
481 err
= TEMP_FAILURE_RETRY(write(pair
->trace
,
483 + (consumed_old
& ((pair
->n_subbufs
* pair
->subbuf_size
)-1)),
488 perror("Error in writing to file");
492 err
= ioctl(pair
->channel
, RELAY_GET_SB_SIZE
, &len
);
495 perror("Getting sub-buffer len failed.");
501 printf_verbose("splice chan to pipe offset %lu\n",
502 (unsigned long)offset
);
503 ret
= splice(pair
->channel
, &offset
, thread_pipe
[1], NULL
,
504 len
, SPLICE_F_MOVE
| SPLICE_F_MORE
);
505 printf_verbose("splice chan to pipe ret %ld\n", ret
);
507 perror("Error in relay splice");
510 ret
= splice(thread_pipe
[0], NULL
, pair
->trace
, NULL
,
511 ret
, SPLICE_F_MOVE
| SPLICE_F_MORE
);
512 printf_verbose("splice pipe to file %ld\n", ret
);
514 perror("Error in file splice");
521 err
= fsync(pair
->trace
);
524 perror("Error in writing to file");
530 err
= ioctl(pair
->channel
, RELAY_PUT_SB
, &consumed_old
);
533 if(errno
== EFAULT
) {
534 perror("Error in unreserving sub buffer\n");
535 } else if(errno
== EIO
) {
536 /* Should never happen with newer LTTng versions */
537 perror("Reader has been pushed by the writer, last sub-buffer corrupted.");
547 int map_channels(struct channel_trace_fd
*fd_pairs
,
548 int idx_begin
, int idx_end
)
553 if(fd_pairs
->num_pairs
<= 0) {
554 printf("No channel to read\n");
558 /* Get the subbuf sizes and number */
560 for(i
=idx_begin
;i
<idx_end
;i
++) {
561 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
563 ret
= ioctl(pair
->channel
, RELAY_GET_N_SB
, &pair
->n_sb
);
565 perror("Error in getting the number of sub-buffers");
568 ret
= ioctl(pair
->channel
, RELAY_GET_MAX_SB_SIZE
,
571 perror("Error in getting the max sub-buffer size");
574 ret
= pthread_mutex_init(&pair
->mutex
, NULL
); /* Fast mutex */
576 perror("Error in mutex init");
583 for(i
=idx_begin
;i
<idx_end
;i
++) {
584 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
586 pair
->mmap
= mmap(0, pair
->subbuf_size
* pair
->n_subbufs
, PROT_READ
,
587 MAP_SHARED
, pair
->channel
, 0);
588 if(pair
->mmap
== MAP_FAILED
) {
589 perror("Mmap error");
594 goto end
; /* success */
597 /* munmap only the successfully mmapped indexes */
600 for(j
=idx_begin
;j
<i
;j
++) {
601 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
604 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
606 perror("Error in munmap");
616 int unmap_channels(struct channel_trace_fd
*fd_pairs
)
622 for(j
=0;j
<fd_pairs
->num_pairs
;j
++) {
623 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
627 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
629 perror("Error in munmap");
633 err_ret
= pthread_mutex_destroy(&pair
->mutex
);
635 perror("Error in mutex destroy");
644 /* Inotify event arrived.
646 * Only support add file for now.
649 int read_inotify(int inotify_fd
,
650 struct channel_trace_fd
*fd_pairs
,
651 struct inotify_watch_array
*iwatch_array
)
653 char buf
[sizeof(struct inotify_event
) + PATH_MAX
];
654 char path_channel
[PATH_MAX
];
655 char path_trace
[PATH_MAX
];
657 struct inotify_event
*ievent
;
664 len
= read(inotify_fd
, buf
, sizeof(struct inotify_event
) + PATH_MAX
);
668 return 0; /* another thread got the data before us */
670 printf("Error in read from inotify FD %s.\n", strerror(len
));
673 while(offset
< len
) {
674 ievent
= (struct inotify_event
*)&(buf
[offset
]);
675 for(i
=0; i
<iwatch_array
->num
; i
++) {
676 if(iwatch_array
->elem
[i
].wd
== ievent
->wd
&&
677 ievent
->mask
== IN_CREATE
) {
679 "inotify wd %u event mask : %u for %s%s\n",
680 ievent
->wd
, ievent
->mask
,
681 iwatch_array
->elem
[i
].path_channel
,
683 old_num
= fd_pairs
->num_pairs
;
684 strcpy(path_channel
, iwatch_array
->elem
[i
].path_channel
);
685 strcat(path_channel
, ievent
->name
);
686 strcpy(path_trace
, iwatch_array
->elem
[i
].path_trace
);
687 strcat(path_trace
, ievent
->name
);
688 if(ret
= open_buffer_file(ievent
->name
, path_channel
,
689 path_trace
, fd_pairs
)) {
690 printf("Error opening buffer file\n");
693 if(ret
= map_channels(fd_pairs
, old_num
, fd_pairs
->num_pairs
)) {
694 printf("Error mapping channel\n");
700 offset
+= sizeof(*ievent
) + ievent
->len
;
709 * Read the debugfs channels and write them in the paired tracefiles.
711 * @fd_pairs : paired channels and trace files.
713 * returns 0 on success, -1 on error.
715 * Note that the high priority polled channels are consumed first. We then poll
716 * again to see if these channels are still in priority. Only when no
717 * high priority channel is left, we start reading low priority channels.
719 * Note that a channel is considered high priority when the buffer is almost
723 int read_channels(unsigned long thread_num
, struct channel_trace_fd
*fd_pairs
,
724 int inotify_fd
, struct inotify_watch_array
*iwatch_array
)
726 struct pollfd
*pollfd
= NULL
;
729 int num_rdy
, num_hup
;
733 unsigned int old_num
;
741 pthread_rwlock_rdlock(&fd_pairs_lock
);
743 /* Start polling the FD. Keep one fd for inotify */
744 pollfd
= malloc((inotify_fds
+ fd_pairs
->num_pairs
) * sizeof(struct pollfd
));
747 pollfd
[0].fd
= inotify_fd
;
748 pollfd
[0].events
= POLLIN
|POLLPRI
;
751 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
752 pollfd
[inotify_fds
+i
].fd
= fd_pairs
->pair
[i
].channel
;
753 pollfd
[inotify_fds
+i
].events
= POLLIN
|POLLPRI
;
755 num_pollfd
= inotify_fds
+ fd_pairs
->num_pairs
;
758 pthread_rwlock_unlock(&fd_pairs_lock
);
764 printf("Press a key for next poll...\n");
766 read(STDIN_FILENO
, &buf
, 1);
767 printf("Next poll (polling %d fd) :\n", num_pollfd
);
770 /* Have we received a signal ? */
771 if(quit_program
) break;
773 num_rdy
= poll(pollfd
, num_pollfd
, -1);
776 perror("Poll error");
780 printf_verbose("Data received\n");
782 switch(pollfd
[0].revents
) {
785 "Error returned in polling inotify fd %d.\n",
790 "Polling inotify fd %d tells it has hung up.\n",
795 "Polling inotify fd %d tells fd is not open.\n",
801 "Polling inotify fd %d : data ready.\n",
804 pthread_rwlock_wrlock(&fd_pairs_lock
);
805 read_inotify(inotify_fd
, fd_pairs
, iwatch_array
);
806 pthread_rwlock_unlock(&fd_pairs_lock
);
812 for(i
=inotify_fds
;i
<num_pollfd
;i
++) {
813 switch(pollfd
[i
].revents
) {
816 "Error returned in polling fd %d.\n",
822 "Polling fd %d tells it has hung up.\n",
828 "Polling fd %d tells fd is not open.\n",
833 pthread_rwlock_rdlock(&fd_pairs_lock
);
834 if(pthread_mutex_trylock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
) == 0) {
836 "Urgent read on fd %d\n",
838 /* Take care of high priority channels first. */
840 /* it's ok to have an unavailable sub-buffer */
841 ret
= read_subbuffer(&fd_pairs
->pair
[i
-inotify_fds
]);
842 if(ret
== EAGAIN
) ret
= 0;
844 ret
= pthread_mutex_unlock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
);
846 printf("Error in mutex unlock : %s\n", strerror(ret
));
848 pthread_rwlock_unlock(&fd_pairs_lock
);
852 /* If every buffer FD has hung up, we end the read loop here */
853 if(num_hup
== num_pollfd
- inotify_fds
) break;
856 for(i
=inotify_fds
;i
<num_pollfd
;i
++) {
857 switch(pollfd
[i
].revents
) {
859 pthread_rwlock_rdlock(&fd_pairs_lock
);
860 if(pthread_mutex_trylock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
) == 0) {
861 /* Take care of low priority channels. */
863 "Normal read on fd %d\n",
865 /* it's ok to have an unavailable subbuffer */
866 ret
= read_subbuffer(&fd_pairs
->pair
[i
-inotify_fds
]);
867 if(ret
== EAGAIN
) ret
= 0;
869 ret
= pthread_mutex_unlock(&fd_pairs
->pair
[i
-inotify_fds
].mutex
);
871 printf("Error in mutex unlock : %s\n", strerror(ret
));
873 pthread_rwlock_unlock(&fd_pairs_lock
);
879 /* Update pollfd array if an entry was added to fd_pairs */
880 pthread_rwlock_rdlock(&fd_pairs_lock
);
881 if((inotify_fds
+ fd_pairs
->num_pairs
) != num_pollfd
) {
882 pollfd
= realloc(pollfd
,
883 (inotify_fds
+ fd_pairs
->num_pairs
) * sizeof(struct pollfd
));
884 for(i
=num_pollfd
-inotify_fds
;i
<fd_pairs
->num_pairs
;i
++) {
885 pollfd
[inotify_fds
+i
].fd
= fd_pairs
->pair
[i
].channel
;
886 pollfd
[inotify_fds
+i
].events
= POLLIN
|POLLPRI
;
888 num_pollfd
= fd_pairs
->num_pairs
+ inotify_fds
;
890 pthread_rwlock_unlock(&fd_pairs_lock
);
892 /* NB: If the fd_pairs structure is updated by another thread from this
893 * point forward, the current thread will wait in the poll without
894 * monitoring the new channel. However, this thread will add the
895 * new channel on next poll (and this should not take too much time
896 * on a loaded system).
898 * This event is quite unlikely and can only occur if a CPU is
899 * hot-plugged while multple lttd threads are running.
911 void close_channel_trace_pairs(struct channel_trace_fd
*fd_pairs
, int inotify_fd
,
912 struct inotify_watch_array
*iwatch_array
)
917 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
918 ret
= close(fd_pairs
->pair
[i
].channel
);
919 if(ret
== -1) perror("Close error on channel");
920 ret
= close(fd_pairs
->pair
[i
].trace
);
921 if(ret
== -1) perror("Close error on trace");
923 free(fd_pairs
->pair
);
924 free(iwatch_array
->elem
);
928 void * thread_main(void *arg
)
931 unsigned long thread_num
= (unsigned long)arg
;
933 ret
= pipe(thread_pipe
);
935 perror("Error creating pipe");
938 ret
= read_channels(thread_num
, &fd_pairs
, inotify_fd
, &inotify_watch_array
);
939 close(thread_pipe
[0]); /* close read end */
940 close(thread_pipe
[1]); /* close write end */
949 inotify_fd
= inotify_init();
950 fcntl(inotify_fd
, F_SETFL
, O_NONBLOCK
);
952 if(ret
= open_channel_trace_pairs(channel_name
, trace_name
, &fd_pairs
,
953 &inotify_fd
, &inotify_watch_array
))
955 if (fd_pairs
.num_pairs
== 0) {
956 printf("No channel available for reading, exiting\n");
960 if(ret
= map_channels(&fd_pairs
, 0, fd_pairs
.num_pairs
))
965 close_channel_trace_pairs(&fd_pairs
, inotify_fd
, &inotify_watch_array
);
972 int main(int argc
, char ** argv
)
975 struct sigaction act
;
980 ret
= parse_arguments(argc
, argv
);
982 if(ret
!= 0) show_arguments();
983 if(ret
< 0) return EINVAL
;
984 if(ret
> 0) return 0;
988 /* Connect the signal handlers */
989 act
.sa_handler
= handler
;
991 sigemptyset(&(act
.sa_mask
));
992 sigaddset(&(act
.sa_mask
), SIGTERM
);
993 sigaddset(&(act
.sa_mask
), SIGQUIT
);
994 sigaddset(&(act
.sa_mask
), SIGINT
);
995 sigaction(SIGTERM
, &act
, NULL
);
996 sigaction(SIGQUIT
, &act
, NULL
);
997 sigaction(SIGINT
, &act
, NULL
);
999 if(ret
= channels_init())
1006 perror("An error occured while daemonizing.");
1011 tids
= malloc(sizeof(pthread_t
) * num_threads
);
1012 for(i
=0; i
<num_threads
; i
++) {
1014 ret
= pthread_create(&tids
[i
], NULL
, thread_main
, (void*)i
);
1016 perror("Error creating thread");
1021 for(i
=0; i
<num_threads
; i
++) {
1022 ret
= pthread_join(tids
[i
], &tret
);
1024 perror("Error joining thread");
1027 if((long)tret
!= 0) {
1028 printf("Error %s occured in thread %u\n",
1029 strerror((long)tret
), i
);
1034 ret
= unmap_channels(&fd_pairs
);
1035 close_channel_trace_pairs(&fd_pairs
, inotify_fd
, &inotify_watch_array
);