Cleanup: identical code for different branches
[babeltrace.git] / plugins / utils / trimmer / trimmer.c
1 /*
2 * trimmer.c
3 *
4 * Babeltrace Trace Trimmer
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #define BT_LOG_TAG "PLUGIN-UTILS-TRIMMER-FLT"
30 #include "logging.h"
31
32 #include <babeltrace/compat/utc-internal.h>
33 #include <babeltrace/plugin/plugin-dev.h>
34 #include <babeltrace/graph/component.h>
35 #include <babeltrace/graph/private-component.h>
36 #include <babeltrace/graph/component-filter.h>
37 #include <babeltrace/graph/notification.h>
38 #include <babeltrace/graph/notification-iterator.h>
39 #include <babeltrace/graph/private-notification-iterator.h>
40 #include <babeltrace/graph/private-component-filter.h>
41 #include <babeltrace/graph/notification-event.h>
42 #include <plugins-common.h>
43 #include "trimmer.h"
44 #include "iterator.h"
45 #include <assert.h>
46
47 static
48 void destroy_trimmer_data(struct trimmer *trimmer)
49 {
50 g_free(trimmer);
51 }
52
53 static
54 struct trimmer *create_trimmer_data(void)
55 {
56 return g_new0(struct trimmer, 1);
57 }
58
59 void finalize_trimmer(struct bt_private_component *component)
60 {
61 void *data = bt_private_component_get_user_data(component);
62
63 destroy_trimmer_data(data);
64 }
65
66 /*
67 * Parses a timestamp, figuring out its format.
68 *
69 * Returns a negative value if anything goes wrong.
70 *
71 * Expected formats:
72 *
73 * YYYY-MM-DD hh:mm:ss.ns
74 * hh:mm:ss.ns
75 * -ss.ns
76 * ss.ns
77 * YYYY-MM-DD hh:mm:ss
78 * hh:mm:ss
79 * -ss
80 * ss
81 */
82 static
83 int timestamp_from_arg(const char *arg, struct trimmer *trimmer,
84 struct trimmer_bound *result_bound, bt_bool gmt)
85 {
86 int ret;
87 int64_t value;
88 unsigned int year, month, day, hh, mm, ss, ns;
89
90 /* YYYY-MM-DD hh:mm:ss.ns */
91 ret = sscanf(arg, "%u-%u-%u %u:%u:%u.%u",
92 &year, &month, &day, &hh, &mm, &ss, &ns);
93 if (ret == 7) {
94 struct tm tm = {
95 .tm_sec = ss,
96 .tm_min = mm,
97 .tm_hour = hh,
98 .tm_mday = day,
99 .tm_mon = month - 1,
100 .tm_year = year - 1900,
101 .tm_isdst = -1,
102 };
103 time_t result;
104
105 if (gmt) {
106 result = bt_timegm(&tm);
107 if (result < 0) {
108 return -1;
109 }
110 } else {
111 result = mktime(&tm);
112 if (result < 0) {
113 return -1;
114 }
115 }
116 value = (int64_t) result;
117 value *= NSEC_PER_SEC;
118 value += ns;
119 if (!trimmer->date) {
120 trimmer->year = year;
121 trimmer->month = month;
122 trimmer->day = day;
123 trimmer->date = true;
124 }
125 goto set;
126 }
127 /* hh:mm:ss.ns */
128 ret = sscanf(arg, "%u:%u:%u.%u",
129 &hh, &mm, &ss, &ns);
130 if (ret == 4) {
131 if (!trimmer->date) {
132 /* We don't know which day until we get an event. */
133 result_bound->lazy_values.hh = hh;
134 result_bound->lazy_values.mm = mm;
135 result_bound->lazy_values.ss = ss;
136 result_bound->lazy_values.ns = ns;
137 result_bound->lazy_values.gmt = gmt;
138 goto lazy;
139 } else {
140 struct tm tm = {
141 .tm_sec = ss,
142 .tm_min = mm,
143 .tm_hour = hh,
144 .tm_mday = trimmer->day,
145 .tm_mon = trimmer->month - 1,
146 .tm_year = trimmer->year - 1900,
147 .tm_isdst = -1,
148 };
149 time_t result;
150
151 if (gmt) {
152 result = bt_timegm(&tm);
153 if (result < 0) {
154 return -1;
155 }
156 } else {
157 result = mktime(&tm);
158 if (result < 0) {
159 return -1;
160 }
161 }
162 value = (int64_t) result;
163 value *= NSEC_PER_SEC;
164 value += ns;
165 goto set;
166 }
167 }
168 /* -ss.ns */
169 ret = sscanf(arg, "-%u.%u",
170 &ss, &ns);
171 if (ret == 2) {
172 value = -ss * NSEC_PER_SEC;
173 value -= ns;
174 goto set;
175 }
176 /* ss.ns */
177 ret = sscanf(arg, "%u.%u",
178 &ss, &ns);
179 if (ret == 2) {
180 value = ss * NSEC_PER_SEC;
181 value += ns;
182 goto set;
183 }
184
185 /* YYYY-MM-DD hh:mm:ss */
186 ret = sscanf(arg, "%u-%u-%u %u:%u:%u",
187 &year, &month, &day, &hh, &mm, &ss);
188 if (ret == 6) {
189 struct tm tm = {
190 .tm_sec = ss,
191 .tm_min = mm,
192 .tm_hour = hh,
193 .tm_mday = day,
194 .tm_mon = month - 1,
195 .tm_year = year - 1900,
196 .tm_isdst = -1,
197 };
198
199 if (gmt) {
200 value = bt_timegm(&tm);
201 if (value < 0) {
202 return -1;
203 }
204 } else {
205 value = mktime(&tm);
206 if (value < 0) {
207 return -1;
208 }
209 }
210 value *= NSEC_PER_SEC;
211 if (!trimmer->date) {
212 trimmer->year = year;
213 trimmer->month = month;
214 trimmer->day = day;
215 trimmer->date = true;
216 }
217 goto set;
218 }
219 /* hh:mm:ss */
220 ret = sscanf(arg, "%u:%u:%u",
221 &hh, &mm, &ss);
222 if (ret == 3) {
223 if (!trimmer->date) {
224 /* We don't know which day until we get an event. */
225 result_bound->lazy_values.hh = hh;
226 result_bound->lazy_values.mm = mm;
227 result_bound->lazy_values.ss = ss;
228 result_bound->lazy_values.ns = 0;
229 result_bound->lazy_values.gmt = gmt;
230 goto lazy;
231 } else {
232 struct tm tm = {
233 .tm_sec = ss,
234 .tm_min = mm,
235 .tm_hour = hh,
236 .tm_mday = trimmer->day,
237 .tm_mon = trimmer->month - 1,
238 .tm_year = trimmer->year - 1900,
239 .tm_isdst = -1,
240 };
241 time_t result;
242
243 if (gmt) {
244 result = bt_timegm(&tm);
245 if (result < 0) {
246 return -1;
247 }
248 } else {
249 result = mktime(&tm);
250 if (result < 0) {
251 return -1;
252 }
253 }
254 value = (int64_t) result;
255 value *= NSEC_PER_SEC;
256 goto set;
257 }
258 }
259 /* -ss */
260 ret = sscanf(arg, "-%u",
261 &ss);
262 if (ret == 1) {
263 value = -ss * NSEC_PER_SEC;
264 goto set;
265 }
266 /* ss */
267 ret = sscanf(arg, "%u",
268 &ss);
269 if (ret == 1) {
270 value = ss * NSEC_PER_SEC;
271 goto set;
272 }
273
274 /* Not found. */
275 return -1;
276
277 set:
278 result_bound->value = value;
279 result_bound->set = true;
280 return 0;
281
282 lazy:
283 result_bound->lazy = true;
284 return 0;
285 }
286
287 static
288 enum bt_component_status init_from_params(struct trimmer *trimmer,
289 struct bt_value *params)
290 {
291 struct bt_value *value = NULL;
292 bt_bool gmt = BT_FALSE;
293 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
294
295 assert(params);
296
297 value = bt_value_map_get(params, "clock-gmt");
298 if (value) {
299 enum bt_value_status value_ret;
300
301 value_ret = bt_value_bool_get(value, &gmt);
302 if (value_ret) {
303 ret = BT_COMPONENT_STATUS_INVALID;
304 BT_LOGE_STR("Failed to retrieve clock-gmt value. Expecting a boolean");
305 }
306 }
307 bt_put(value);
308 if (ret != BT_COMPONENT_STATUS_OK) {
309 goto end;
310 }
311
312 value = bt_value_map_get(params, "begin");
313 if (value) {
314 enum bt_value_status value_ret;
315 const char *str;
316
317 value_ret = bt_value_string_get(value, &str);
318 if (value_ret || timestamp_from_arg(str,
319 trimmer, &trimmer->begin, gmt)) {
320 ret = BT_COMPONENT_STATUS_INVALID;
321 BT_LOGE_STR("Failed to retrieve begin value. Expecting a timestamp string");
322 }
323 }
324 bt_put(value);
325 if (ret != BT_COMPONENT_STATUS_OK) {
326 goto end;
327 }
328
329 value = bt_value_map_get(params, "end");
330 if (value) {
331 enum bt_value_status value_ret;
332 const char *str;
333
334 value_ret = bt_value_string_get(value, &str);
335 if (value_ret || timestamp_from_arg(str,
336 trimmer, &trimmer->end, gmt)) {
337 ret = BT_COMPONENT_STATUS_INVALID;
338 BT_LOGE_STR("Failed to retrieve end value. Expecting a timestamp string");
339 }
340 }
341 bt_put(value);
342 end:
343 if (trimmer->begin.set && trimmer->end.set) {
344 if (trimmer->begin.value > trimmer->end.value) {
345 BT_LOGE_STR("Unexpected: time range begin value is above end value");
346 ret = BT_COMPONENT_STATUS_INVALID;
347 }
348 }
349 return ret;
350 }
351
352 enum bt_component_status trimmer_component_init(
353 struct bt_private_component *component, struct bt_value *params,
354 UNUSED_VAR void *init_method_data)
355 {
356 enum bt_component_status ret;
357 struct trimmer *trimmer = create_trimmer_data();
358
359 if (!trimmer) {
360 ret = BT_COMPONENT_STATUS_NOMEM;
361 goto end;
362 }
363
364 /* Create input and output ports */
365 ret = bt_private_component_filter_add_input_private_port(
366 component, "in", NULL, NULL);
367 if (ret != BT_COMPONENT_STATUS_OK) {
368 goto error;
369 }
370
371 ret = bt_private_component_filter_add_output_private_port(
372 component, "out", NULL, NULL);
373 if (ret != BT_COMPONENT_STATUS_OK) {
374 goto error;
375 }
376
377 ret = bt_private_component_set_user_data(component, trimmer);
378 if (ret != BT_COMPONENT_STATUS_OK) {
379 goto error;
380 }
381
382 ret = init_from_params(trimmer, params);
383 end:
384 return ret;
385 error:
386 destroy_trimmer_data(trimmer);
387 ret = BT_COMPONENT_STATUS_ERROR;
388 return ret;
389 }
This page took 0.03656 seconds and 4 git commands to generate.