3 * Linux Trace Toolkit Daemon
5 * This is a simple daemon that reads a few relayfs channels and save them in a
10 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
18 #include <sys/types.h>
29 #include <asm/ioctl.h>
30 #include <asm/types.h>
32 /* Get the next sub buffer that can be read. */
33 #define RELAYFS_GET_SUBBUF _IOR(0xF4, 0x00,__u32)
34 /* Release the oldest reserved (by "get") sub buffer. */
35 #define RELAYFS_PUT_SUBBUF _IO(0xF4, 0x01)
36 /* returns the number of sub buffers in the per cpu channel. */
37 #define RELAYFS_GET_N_SUBBUFS _IOR(0xF4, 0x02,__u32)
38 /* returns the size of the sub buffers. */
39 #define RELAYFS_GET_SUBBUF_SIZE _IOR(0xF4, 0x03,__u32)
53 unsigned int n_subbufs
;
54 unsigned int subbuf_size
;
58 struct channel_trace_fd
{
63 static char *trace_name
= NULL
;
64 static char *channel_name
= NULL
;
65 static int daemon_mode
= 0;
66 static int append_mode
= 0;
67 static int sig_parent
= 0;
68 volatile static int quit_program
= 0; /* For signal handler */
72 * -t directory Directory name of the trace to write to. Will be created.
73 * -c directory Root directory of the relayfs trace channels.
74 * -d Run in background (daemon).
75 * -a Trace append mode.
76 * -s Send SIGIO to parent when ready for IO.
78 void show_arguments(void)
80 printf("Please use the following arguments :\n");
82 printf("-t directory Directory name of the trace to write to.\n"
83 " It will be created.\n");
84 printf("-c directory Root directory of the relayfs trace channels.\n");
85 printf("-d Run in background (daemon).\n");
86 printf("-a Append to an possibly existing trace.\n");
87 printf("-s Send SIGIO to parent when ready for IO.\n");
94 * Parses the command line arguments.
96 * Returns 1 if the arguments were correct, but doesn't ask for program
97 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
99 int parse_arguments(int argc
, char **argv
)
105 if(strcmp(argv
[1], "-h") == 0) {
112 switch(argv
[argn
][0]) {
114 switch(argv
[argn
][1]) {
117 trace_name
= argv
[argn
+1];
123 channel_name
= argv
[argn
+1];
137 printf("Invalid argument '%s'.\n", argv
[argn
]);
143 printf("Invalid argument '%s'.\n", argv
[argn
]);
150 if(trace_name
== NULL
) {
151 printf("Please specify a trace name.\n");
156 if(channel_name
== NULL
) {
157 printf("Please specify a channel name.\n");
167 printf("Linux Trace Toolkit Trace Daemon\n");
169 printf("Reading from relayfs directory : %s\n", channel_name
);
170 printf("Writing to trace directory : %s\n", trace_name
);
175 /* signal handling */
177 static void handler(int signo
)
179 printf("Signal %d received : exiting cleanly\n", signo
);
185 int open_channel_trace_pairs(char *subchannel_name
, char *subtrace_name
,
186 struct channel_trace_fd
*fd_pairs
)
188 DIR *channel_dir
= opendir(subchannel_name
);
189 struct dirent
*entry
;
190 struct stat stat_buf
;
192 char path_channel
[PATH_MAX
];
193 int path_channel_len
;
194 char *path_channel_ptr
;
195 char path_trace
[PATH_MAX
];
197 char *path_trace_ptr
;
199 if(channel_dir
== NULL
) {
200 perror(subchannel_name
);
204 printf("Creating trace subdirectory %s\n", subtrace_name
);
205 ret
= mkdir(subtrace_name
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
207 if(errno
== EEXIST
&& append_mode
) {
208 printf("Appending to directory %s as resquested\n", subtrace_name
);
210 perror(subtrace_name
);
215 strncpy(path_channel
, subchannel_name
, PATH_MAX
-1);
216 path_channel_len
= strlen(path_channel
);
217 path_channel
[path_channel_len
] = '/';
219 path_channel_ptr
= path_channel
+ path_channel_len
;
221 strncpy(path_trace
, subtrace_name
, PATH_MAX
-1);
222 path_trace_len
= strlen(path_trace
);
223 path_trace
[path_trace_len
] = '/';
225 path_trace_ptr
= path_trace
+ path_trace_len
;
227 while((entry
= readdir(channel_dir
)) != NULL
) {
229 if(entry
->d_name
[0] == '.') continue;
231 strncpy(path_channel_ptr
, entry
->d_name
, PATH_MAX
- path_channel_len
);
232 strncpy(path_trace_ptr
, entry
->d_name
, PATH_MAX
- path_trace_len
);
234 ret
= stat(path_channel
, &stat_buf
);
236 perror(path_channel
);
240 printf("Channel file : %s\n", path_channel
);
242 if(S_ISDIR(stat_buf
.st_mode
)) {
244 printf("Entering channel subdirectory...\n");
245 ret
= open_channel_trace_pairs(path_channel
, path_trace
, fd_pairs
);
246 if(ret
< 0) continue;
247 } else if(S_ISREG(stat_buf
.st_mode
)) {
248 printf("Opening file.\n");
250 fd_pairs
->pair
= realloc(fd_pairs
->pair
,
251 ++fd_pairs
->num_pairs
* sizeof(struct fd_pair
));
253 /* Open the channel in read mode */
254 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
=
255 open(path_channel
, O_RDONLY
| O_NONBLOCK
);
256 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
== -1) {
257 perror(path_channel
);
258 fd_pairs
->num_pairs
--;
261 /* Open the trace in write mode, only append if append_mode */
262 ret
= stat(path_trace
, &stat_buf
);
265 printf("Appending to file %s as requested\n", path_trace
);
267 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
268 open(path_trace
, O_WRONLY
|O_APPEND
,
269 S_IRWXU
|S_IRWXG
|S_IRWXO
);
271 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
275 printf("File %s exists, cannot open. Try append mode.\n", path_trace
);
279 if(errno
== ENOENT
) {
280 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
281 open(path_trace
, O_WRONLY
|O_CREAT
|O_EXCL
,
282 S_IRWXU
|S_IRWXG
|S_IRWXO
);
283 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
291 closedir(channel_dir
);
297 int read_subbuffer(struct fd_pair
*pair
)
299 unsigned int subbuf_index
;
303 err
= ioctl(pair
->channel
, RELAYFS_GET_SUBBUF
,
305 printf("index : %u\n", subbuf_index
);
307 perror("Error in reserving sub buffer");
312 err
= TEMP_FAILURE_RETRY(write(pair
->trace
,
313 pair
->mmap
+ (subbuf_index
* pair
->subbuf_size
),
317 perror("Error in writing to file");
324 err
= ioctl(pair
->channel
, RELAYFS_PUT_SUBBUF
);
326 perror("Error in unreserving sub buffer");
338 * Read the realyfs channels and write them in the paired tracefiles.
340 * @fd_pairs : paired channels and trace files.
342 * returns 0 on success, -1 on error.
344 * Note that the high priority polled channels are consumed first. We then poll
345 * again to see if these channels are still in priority. Only when no
346 * high priority channel is left, we start reading low priority channels.
348 * Note that a channel is considered high priority when the buffer is almost
352 int read_channels(struct channel_trace_fd
*fd_pairs
)
354 struct pollfd
*pollfd
;
356 int num_rdy
, num_hup
;
360 if(fd_pairs
->num_pairs
<= 0) {
361 printf("No channel to read\n");
365 /* Get the subbuf sizes and number */
367 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
368 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
370 ret
= ioctl(pair
->channel
, RELAYFS_GET_N_SUBBUFS
,
373 perror("Error in getting the number of subbuffers");
376 ret
= ioctl(pair
->channel
, RELAYFS_GET_SUBBUF_SIZE
,
379 perror("Error in getting the size of the subbuffers");
385 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
386 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
388 pair
->mmap
= mmap(0, pair
->subbuf_size
* pair
->n_subbufs
, PROT_READ
,
389 MAP_SHARED
, pair
->channel
, 0);
390 if(pair
->mmap
== MAP_FAILED
) {
391 perror("Mmap error");
397 /* Start polling the FD */
399 pollfd
= malloc(fd_pairs
->num_pairs
* sizeof(struct pollfd
));
401 /* Note : index in pollfd is the same index as fd_pair->pair */
402 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
403 pollfd
[i
].fd
= fd_pairs
->pair
[i
].channel
;
404 pollfd
[i
].events
= POLLIN
|POLLPRI
;
407 /* Signal the parent that ready for IO */
408 if(sig_parent
) kill(getppid(), SIGIO
);
414 printf("Press a key for next poll...\n");
416 read(STDIN_FILENO
, &buf
, 1);
417 printf("Next poll (polling %d fd) :\n", fd_pairs
->num_pairs
);
420 /* Have we received a signal ? */
421 if(quit_program
) break;
423 num_rdy
= poll(pollfd
, fd_pairs
->num_pairs
, -1);
425 perror("Poll error");
429 printf("Data received\n");
431 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
432 switch(pollfd
[i
].revents
) {
434 printf("Error returned in polling fd %d.\n", pollfd
[i
].fd
);
438 printf("Polling fd %d tells it has hung up.\n", pollfd
[i
].fd
);
442 printf("Polling fd %d tells fd is not open.\n", pollfd
[i
].fd
);
446 printf("Urgent read on fd %d\n", pollfd
[i
].fd
);
447 /* Take care of high priority channels first. */
449 ret
|= read_subbuffer(&fd_pairs
->pair
[i
]);
453 /* If every FD has hung up, we end the read loop here */
454 if(num_hup
== fd_pairs
->num_pairs
) break;
457 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
458 switch(pollfd
[i
].revents
) {
460 /* Take care of low priority channels. */
461 printf("Normal read on fd %d\n", pollfd
[i
].fd
);
462 ret
|= read_subbuffer(&fd_pairs
->pair
[i
]);
473 /* munmap only the successfully mmapped indexes */
474 i
= fd_pairs
->num_pairs
;
478 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
481 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
483 perror("Error in munmap");
493 void close_channel_trace_pairs(struct channel_trace_fd
*fd_pairs
)
498 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
499 ret
= close(fd_pairs
->pair
[i
].channel
);
500 if(ret
== -1) perror("Close error on channel");
501 ret
= close(fd_pairs
->pair
[i
].trace
);
502 if(ret
== -1) perror("Close error on trace");
504 free(fd_pairs
->pair
);
507 int main(int argc
, char ** argv
)
511 struct channel_trace_fd fd_pairs
= { NULL
, 0 };
512 struct sigaction act
;
514 ret
= parse_arguments(argc
, argv
);
516 if(ret
!= 0) show_arguments();
517 if(ret
< 0) return EINVAL
;
518 if(ret
> 0) return 0;
530 printf("An error occured while forking.\n");
533 /* else, we are the child, continue... */
536 /* Connect the signal handlers */
537 act
.sa_handler
= handler
;
539 sigemptyset(&(act
.sa_mask
));
540 sigaddset(&(act
.sa_mask
), SIGTERM
);
541 sigaddset(&(act
.sa_mask
), SIGQUIT
);
542 sigaddset(&(act
.sa_mask
), SIGINT
);
543 sigaction(SIGTERM
, &act
, NULL
);
544 sigaction(SIGQUIT
, &act
, NULL
);
545 sigaction(SIGINT
, &act
, NULL
);
548 if(ret
= open_channel_trace_pairs(channel_name
, trace_name
, &fd_pairs
))
551 ret
= read_channels(&fd_pairs
);
554 close_channel_trace_pairs(&fd_pairs
);