3368aba90e96e38ef0c83bbbc7d70dde2f6978d7
[ltt-control.git] / liblttd / liblttdutils.c
1 /* liblttdutils
2 *
3 * Linux Trace Toolkit utility library
4 *
5 * This is a simple daemon implementation that reads a few relay+debugfs
6 * channels and save them in a trace.
7 *
8 * CPU hot-plugging is supported using inotify.
9 *
10 * Copyright 2005 -
11 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
12 * Copyright 2010 -
13 * Michael Sills-Lavoie <michael.sills-lavoie@polymtl.ca>
14 * Oumarou Dicko <oumarou.dicko@polymtl.ca>
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #define _REENTRANT
22 #define _GNU_SOURCE
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <dirent.h>
30 #include <pthread.h>
31 #include <sys/stat.h>
32
33 #include "liblttdutils.h"
34
35 struct liblttdutils_channel_data {
36 int trace;
37 };
38
39 struct liblttdutils_data {
40 char path_trace[PATH_MAX];
41 char *end_path_trace;
42 int path_trace_len;
43 int append_mode;
44 int verbose_mode;
45 };
46
47 static __thread int thread_pipe[2];
48
49 #define printf_verbose(fmt, args...) \
50 do { \
51 if (callbacks_data->verbose_mode) \
52 printf(fmt, ##args); \
53 } while (0)
54
55 int liblttdutils_local_on_open_channel(struct liblttd_callbacks *data, struct fd_pair *pair, char *relative_channel_path)
56 {
57 int open_ret = 0;
58 int ret;
59 struct stat stat_buf;
60 struct liblttdutils_channel_data *channel_data;
61
62 pair->user_data = malloc(sizeof(struct liblttdutils_channel_data));
63 channel_data = pair->user_data;
64
65 struct liblttdutils_data* callbacks_data = data->user_data;
66
67 strncpy(callbacks_data->end_path_trace, relative_channel_path, PATH_MAX - callbacks_data->path_trace_len);
68 printf_verbose("Creating trace file %s\n", callbacks_data->path_trace);
69
70 ret = stat(callbacks_data->path_trace, &stat_buf);
71 if(ret == 0) {
72 if(callbacks_data->append_mode) {
73 printf_verbose("Appending to file %s as requested\n",
74 callbacks_data->path_trace);
75
76 channel_data->trace = open(callbacks_data->path_trace, O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO);
77 if(channel_data->trace == -1) {
78 perror(callbacks_data->path_trace);
79 open_ret = -1;
80 goto end;
81 }
82 ret = lseek(channel_data->trace, 0, SEEK_END);
83 if (ret < 0) {
84 perror(callbacks_data->path_trace);
85 open_ret = -1;
86 close(channel_data->trace);
87 goto end;
88 }
89 } else {
90 printf("File %s exists, cannot open. Try append mode.\n", callbacks_data->path_trace);
91 open_ret = -1;
92 goto end;
93 }
94 } else {
95 if(errno == ENOENT) {
96 channel_data->trace =
97 open(callbacks_data->path_trace, O_WRONLY|O_CREAT|O_EXCL, S_IRWXU|S_IRWXG|S_IRWXO);
98 if(channel_data->trace == -1) {
99 perror(callbacks_data->path_trace);
100 open_ret = -1;
101 goto end;
102 }
103 }
104 }
105
106 end:
107 return open_ret;
108
109 }
110
111 int liblttdutils_local_on_close_channel(struct liblttd_callbacks *data, struct fd_pair *pair)
112 {
113 int ret;
114 ret = close(((struct liblttdutils_channel_data *)(pair->user_data))->trace);
115 free(pair->user_data);
116 return ret;
117 }
118
119 int liblttdutils_local_on_new_channels_folder(struct liblttd_callbacks *data, char *relative_folder_path)
120 {
121 int ret;
122 int open_ret = 0;
123 struct liblttdutils_data* callbacks_data = data->user_data;
124
125 strncpy(callbacks_data->end_path_trace, relative_folder_path, PATH_MAX - callbacks_data->path_trace_len);
126 printf_verbose("Creating trace subdirectory %s\n", callbacks_data->path_trace);
127
128 ret = mkdir(callbacks_data->path_trace, S_IRWXU|S_IRWXG|S_IRWXO);
129 if(ret == -1) {
130 if(errno != EEXIST) {
131 perror(callbacks_data->path_trace);
132 open_ret = -1;
133 goto end;
134 }
135 }
136
137 end:
138 return open_ret;
139 }
140
141 int liblttdutils_local_on_read_subbuffer(struct liblttd_callbacks *data, struct fd_pair *pair, unsigned int len)
142 {
143 long ret;
144 off_t offset = 0;
145
146 struct liblttdutils_data* callbacks_data = data->user_data;
147
148 while (len > 0) {
149 printf_verbose("splice chan to pipe offset %lu\n",
150 (unsigned long)offset);
151 ret = splice(pair->channel, &offset, thread_pipe[1], NULL,
152 len, SPLICE_F_MOVE | SPLICE_F_MORE);
153 printf_verbose("splice chan to pipe ret %ld\n", ret);
154 if (ret < 0) {
155 perror("Error in relay splice");
156 goto write_error;
157 }
158 ret = splice(thread_pipe[0], NULL,
159 ((struct liblttdutils_channel_data *)(pair->user_data))->trace,
160 NULL, ret, SPLICE_F_MOVE | SPLICE_F_MORE);
161 printf_verbose("splice pipe to file %ld\n", ret);
162 if (ret < 0) {
163 perror("Error in file splice");
164 goto write_error;
165 }
166 len -= ret;
167 }
168
169 write_error:
170 return ret;
171 }
172
173 int liblttdutils_local_on_new_thread(struct liblttd_callbacks *data, unsigned long thread_num)
174 {
175 int ret;
176 ret = pipe(thread_pipe);
177 if (ret < 0) {
178 perror("Error creating pipe");
179 return ret;
180 }
181 return 0;
182 }
183
184 int liblttdutils_local_on_close_thread(struct liblttd_callbacks *data, unsigned long thread_num)
185 {
186 close(thread_pipe[0]); /* close read end */
187 close(thread_pipe[1]); /* close write end */
188 return 0;
189 }
190
191 int liblttdutils_local_on_trace_end(struct liblttd_instance *instance)
192 {
193 struct liblttd_callbacks *callbacks = instance->callbacks;
194 struct liblttdutils_data *data = callbacks->user_data;
195
196 free(data);
197 free(callbacks);
198 }
199
200 struct liblttd_callbacks* liblttdutils_local_new_callbacks(char* trace_name,
201 int append_mode, int verbose_mode)
202 {
203 struct liblttdutils_data *data;
204 struct liblttd_callbacks *callbacks;
205
206 if(!trace_name) return NULL;
207
208 data = malloc(sizeof(struct liblttdutils_data));
209
210 strncpy(data->path_trace, trace_name, PATH_MAX-1);
211 data->path_trace_len = strlen(data->path_trace);
212 data->end_path_trace = data->path_trace + data->path_trace_len;
213 data->append_mode = append_mode;
214 data->verbose_mode = verbose_mode;
215
216 callbacks = malloc(sizeof(struct liblttd_callbacks));
217
218 callbacks->on_open_channel = liblttdutils_local_on_open_channel;
219 callbacks->on_close_channel = liblttdutils_local_on_close_channel;
220 callbacks->on_new_channels_folder = liblttdutils_local_on_new_channels_folder;
221 callbacks->on_read_subbuffer = liblttdutils_local_on_read_subbuffer;
222 callbacks->on_trace_end = liblttdutils_local_on_trace_end;
223 callbacks->on_new_thread = liblttdutils_local_on_new_thread;
224 callbacks->on_close_thread = liblttdutils_local_on_close_thread;
225 callbacks->user_data = data;
226
227 return callbacks;
228 }
229
This page took 0.03219 seconds and 3 git commands to generate.