Add a save command based on the save API to the lttng client
[lttng-tools.git] / src / common / config / config.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2013 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _GNU_SOURCE
19#include <assert.h>
20#include <ctype.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <inttypes.h>
25
26#include <common/defaults.h>
27#include <common/error.h>
28#include <common/macros.h>
29#include <common/utils.h>
30#include <common/config/config-session-internal.h>
31#include <lttng/lttng-error.h>
32#include <libxml/parser.h>
33#include <libxml/valid.h>
34#include <libxml/xmlschemas.h>
35
36#include "config.h"
37#include "config-internal.h"
38
39struct handler_filter_args {
40 const char* section;
41 config_entry_handler_cb handler;
42 void *user_data;
43};
44
45const char * const config_str_yes = "yes";
46const char * const config_str_true = "true";
47const char * const config_str_on = "on";
48const char * const config_str_no = "no";
49const char * const config_str_false = "false";
50const char * const config_str_off = "off";
51const char * const config_xml_encoding = "UTF-8";
52const size_t config_xml_encoding_bytes_per_char = 2; /* Size of the encoding's largest character */
53const char * const config_xml_indent_string = "\t";
54const char * const config_xml_true = "true";
55const char * const config_xml_false = "false";
56
57const char * const config_element_channel = "channel";
58const char * const config_element_channels = "channels";
59const char * const config_element_domain = "domain";
60const char * const config_element_domains = "domains";
61const char * const config_element_event = "event";
62const char * const config_element_events = "events";
63const char * const config_element_context = "context";
64const char * const config_element_contexts = "contexts";
65const char * const config_element_attributes = "attributes";
66const char * const config_element_exclusion = "exclusion";
67const char * const config_element_exclusions = "exclusions";
68const char * const config_element_function_attributes = "function_attributes";
69const char * const config_element_probe_attributes = "probe_attributes";
70const char * const config_element_symbol_name = "symbol_name";
71const char * const config_element_address = "address";
72const char * const config_element_offset = "offset";
73const char * const config_element_name = "name";
74const char * const config_element_enabled = "enabled";
75const char * const config_element_overwrite_mode = "overwrite_mode";
76const char * const config_element_subbuf_size = "subbuffer_size";
77const char * const config_element_num_subbuf = "subbuffer_count";
78const char * const config_element_switch_timer_interval = "switch_timer_interval";
79const char * const config_element_read_timer_interval = "read_timer_interval";
80const char * const config_element_output = "output";
81const char * const config_element_output_type = "output_type";
82const char * const config_element_tracefile_size = "tracefile_size";
83const char * const config_element_tracefile_count = "tracefile_count";
84const char * const config_element_live_timer_interval = "live_timer_interval";
85const char * const config_element_type = "type";
86const char * const config_element_buffer_type = "buffer_type";
87const char * const config_element_session = "session";
88const char * const config_element_sessions = "sessions";
89const char * const config_element_perf = "perf";
90const char * const config_element_config = "config";
91const char * const config_element_started = "started";
92const char * const config_element_snapshot_mode = "snapshot_mode";
93const char * const config_element_loglevel = "loglevel";
94const char * const config_element_loglevel_type = "loglevel_type";
95const char * const config_element_filter = "filter";
96const char * const config_element_snapshot_outputs = "snapshot_outputs";
97const char * const config_element_consumer_output = "consumer_output";
98const char * const config_element_destination = "destination";
99const char * const config_element_path = "path";
100const char * const config_element_net_output = "net_output";
101const char * const config_element_control_uri = "control_uri";
102const char * const config_element_data_uri = "data_uri";
103const char * const config_element_max_size = "max_size";
104
105const char * const config_domain_type_kernel = "KERNEL";
106const char * const config_domain_type_ust = "UST";
107const char * const config_domain_type_jul = "JUL";
108
109const char * const config_buffer_type_per_pid = "PER_PID";
110const char * const config_buffer_type_per_uid = "PER_UID";
111const char * const config_buffer_type_global = "GLOBAL";
112
113const char * const config_overwrite_mode_discard = "DISCARD";
114const char * const config_overwrite_mode_overwrite = "OVERWRITE";
115
116const char * const config_output_type_splice = "SPLICE";
117const char * const config_output_type_mmap = "MMAP";
118
119const char * const config_loglevel_type_all = "ALL";
120const char * const config_loglevel_type_range = "RANGE";
121const char * const config_loglevel_type_single = "SINGLE";
122
123const char * const config_event_type_all = "ALL";
124const char * const config_event_type_tracepoint = "TRACEPOINT";
125const char * const config_event_type_probe = "PROBE";
126const char * const config_event_type_function = "FUNCTION";
127const char * const config_event_type_function_entry = "FUNCTION_ENTRY";
128const char * const config_event_type_noop = "NOOP";
129const char * const config_event_type_syscall = "SYSCALL";
130const char * const config_event_type_kprobe = "KPROBE";
131const char * const config_event_type_kretprobe = "KRETPROBE";
132
133const char * const config_event_context_pid = "PID";
134const char * const config_event_context_procname = "PROCNAME";
135const char * const config_event_context_prio = "PRIO";
136const char * const config_event_context_nice = "NICE";
137const char * const config_event_context_vpid = "VPID";
138const char * const config_event_context_tid = "TID";
139const char * const config_event_context_vtid = "VTID";
140const char * const config_event_context_ppid = "PPID";
141const char * const config_event_context_vppid = "VPPID";
142const char * const config_event_context_pthread_id = "PTHREAD_ID";
143const char * const config_event_context_hostname = "HOSTNAME";
144const char * const config_event_context_ip = "IP";
145
146static int config_entry_handler_filter(struct handler_filter_args *args,
147 const char *section, const char *name, const char *value)
148{
149 int ret = 0;
150 struct config_entry entry = { section, name, value };
151
152 assert(args);
153
154 if (!section || !name || !value) {
155 ret = -EIO;
156 goto end;
157 }
158
159 if (args->section) {
160 if (strcmp(args->section, section)) {
161 goto end;
162 }
163 }
164
165 ret = args->handler(&entry, args->user_data);
166end:
167 return ret;
168}
169
170LTTNG_HIDDEN
171int config_get_section_entries(const char *override_path, const char *section,
172 config_entry_handler_cb handler, void *user_data)
173{
174 int ret = 0;
175 FILE *config_file = NULL;
176 struct handler_filter_args filter = { section, handler, user_data };
177
178 if (override_path) {
179 config_file = fopen(override_path, "r");
180 if (config_file) {
181 DBG("Loaded daemon configuration file at %s",
182 override_path);
183 } else {
184 ERR("Failed to open daemon configuration file at %s",
185 override_path);
186 ret = -ENOENT;
187 goto end;
188 }
189 } else {
190 char *path = utils_get_home_dir();
191
192 /* Try to open the user's daemon configuration file */
193 if (path) {
194 ret = asprintf(&path, DEFAULT_DAEMON_HOME_CONFIGPATH, path);
195 if (ret < 0) {
196 goto end;
197 }
198
199 ret = 0;
200 config_file = fopen(path, "r");
201 if (config_file) {
202 DBG("Loaded daemon configuration file at %s", path);
203 }
204
205 free(path);
206 }
207
208 /* Try to open the system daemon configuration file */
209 if (!config_file) {
210 config_file = fopen(DEFAULT_DAEMON_HOME_CONFIGPATH, "r");
211 }
212 }
213
214 if (!config_file) {
215 DBG("No daemon configuration file found.");
216 goto end;
217 }
218
219 ret = ini_parse_file(config_file,
220 (ini_entry_handler) config_entry_handler_filter, (void *) &filter);
221
222end:
223 return ret;
224}
225
226LTTNG_HIDDEN
227int config_parse_value(const char *value)
228{
229 int i, ret = 0;
230 char *endptr, *lower_str;
231 size_t len;
232 unsigned long v;
233
234 len = strlen(value);
235 if (!len) {
236 ret = -1;
237 goto end;
238 }
239
240 v = strtoul(value, &endptr, 10);
241 if (endptr != value) {
242 ret = v;
243 goto end;
244 }
245
246 lower_str = zmalloc(len + 1);
247 if (!lower_str) {
248 PERROR("zmalloc");
249 ret = -errno;
250 goto end;
251 }
252
253 for (i = 0; i < len; i++) {
254 lower_str[i] = tolower(value[i]);
255 }
256
257 if (!strcmp(lower_str, config_str_yes) ||
258 !strcmp(lower_str, config_str_true) ||
259 !strcmp(lower_str, config_str_on)) {
260 ret = 1;
261 } else if (!strcmp(lower_str, config_str_no) ||
262 !strcmp(lower_str, config_str_false) ||
263 !strcmp(lower_str, config_str_off)) {
264 ret = 0;
265 } else {
266 ret = -1;
267 }
268
269 free(lower_str);
270end:
271 return ret;
272}
273
274/*
275 * Returns a xmlChar string which must be released using xmlFree().
276 */
277static xmlChar *encode_string(const char *in_str)
278{
279 xmlChar *out_str = NULL;
280 xmlCharEncodingHandlerPtr handler;
281 int out_len, ret, in_len;
282
283 assert(in_str);
284
285 handler = xmlFindCharEncodingHandler(config_xml_encoding);
286 if (!handler) {
287 ERR("xmlFindCharEncodingHandler return NULL!. Configure issue!");
288 goto end;
289 }
290
291 in_len = strlen(in_str);
292 /*
293 * Add 1 byte for the NULL terminted character. The factor 2 here is
294 * because UTF-8 can be on two bytes so this fits the worst case for each
295 * bytes.
296 */
297 out_len = (in_len * 2) + 1;
298 out_str = xmlMalloc(out_len);
299 if (!out_str) {
300 goto end;
301 }
302
303 ret = handler->input(out_str, &out_len, (const xmlChar *) in_str, &in_len);
304 if (ret < 0) {
305 xmlFree(out_str);
306 out_str = NULL;
307 goto end;
308 }
309
310 /* out_len is now the size of out_str */
311 out_str[out_len] = '\0';
312end:
313 return out_str;
314}
315
316LTTNG_HIDDEN
317struct config_writer *config_writer_create(int fd_output)
318{
319 int ret;
320 struct config_writer *writer;
321 xmlOutputBufferPtr buffer;
322
323 writer = zmalloc(sizeof(struct config_writer));
324 if (!writer) {
325 PERROR("zmalloc config_writer_create");
326 goto end;
327 }
328
329 buffer = xmlOutputBufferCreateFd(fd_output, NULL);
330 if (!buffer) {
331 goto error_destroy;
332 }
333
334 writer->writer = xmlNewTextWriter(buffer);
335 ret = xmlTextWriterStartDocument(writer->writer, NULL,
336 config_xml_encoding, NULL);
337 if (ret < 0) {
338 goto error_destroy;
339 }
340
341 ret = xmlTextWriterSetIndentString(writer->writer,
342 BAD_CAST config_xml_indent_string);
343 if (ret) {
344 goto error_destroy;
345 }
346
347 ret = xmlTextWriterSetIndent(writer->writer, 1);
348 if (ret) {
349 goto error_destroy;
350 }
351
352end:
353 return writer;
354error_destroy:
355 config_writer_destroy(writer);
356 return NULL;
357}
358
359LTTNG_HIDDEN
360int config_writer_destroy(struct config_writer *writer)
361{
362 int ret = 0;
363
364 if (!writer) {
365 ret = -EINVAL;
366 goto end;
367 }
368
369 if (xmlTextWriterEndDocument(writer->writer) < 0) {
370 WARN("Could not close XML document");
371 ret = -EIO;
372 }
373
374 if (writer->writer) {
375 xmlFreeTextWriter(writer->writer);
376 }
377
378 free(writer);
379end:
380 return ret;
381}
382
383LTTNG_HIDDEN
384int config_writer_open_element(struct config_writer *writer,
385 const char *element_name)
386{
387 int ret;
388 xmlChar *encoded_element_name;
389
390 if (!writer || !writer->writer || !element_name || !element_name[0]) {
391 ret = -1;
392 goto end;
393 }
394
395 encoded_element_name = encode_string(element_name);
396 if (!encoded_element_name) {
397 ret = -1;
398 goto end;
399 }
400
401 ret = xmlTextWriterStartElement(writer->writer, encoded_element_name);
402 xmlFree(encoded_element_name);
403end:
404 return ret > 0 ? 0 : ret;
405}
406
407LTTNG_HIDDEN
408int config_writer_close_element(struct config_writer *writer)
409{
410 int ret;
411
412 if (!writer || !writer->writer) {
413 ret = -1;
414 goto end;
415 }
416
417 ret = xmlTextWriterEndElement(writer->writer);
418end:
419 return ret > 0 ? 0 : ret;
420}
421
422LTTNG_HIDDEN
423int config_writer_write_element_unsigned_int(struct config_writer *writer,
424 const char *element_name, uint64_t value)
425{
426 int ret;
427 xmlChar *encoded_element_name;
428
429 if (!writer || !writer->writer || !element_name || !element_name[0]) {
430 ret = -1;
431 goto end;
432 }
433
434 encoded_element_name = encode_string(element_name);
435 if (!encoded_element_name) {
436 ret = -1;
437 goto end;
438 }
439
440 ret = xmlTextWriterWriteFormatElement(writer->writer,
441 encoded_element_name, "%" PRIu64, value);
442 xmlFree(encoded_element_name);
443end:
444 return ret > 0 ? 0 : ret;
445}
446
447LTTNG_HIDDEN
448int config_writer_write_element_signed_int(struct config_writer *writer,
449 const char *element_name, int64_t value)
450{
451 int ret;
452 xmlChar *encoded_element_name;
453
454 if (!writer || !writer->writer || !element_name || !element_name[0]) {
455 ret = -1;
456 goto end;
457 }
458
459 encoded_element_name = encode_string(element_name);
460 if (!encoded_element_name) {
461 ret = -1;
462 goto end;
463 }
464
465 ret = xmlTextWriterWriteFormatElement(writer->writer,
466 encoded_element_name, "%" PRIi64, value);
467 xmlFree(encoded_element_name);
468end:
469 return ret > 0 ? 0 : ret;
470}
471
472LTTNG_HIDDEN
473int config_writer_write_element_bool(struct config_writer *writer,
474 const char *element_name, int value)
475{
476 return config_writer_write_element_string(writer, element_name,
477 value ? config_xml_true : config_xml_false);
478}
479
480LTTNG_HIDDEN
481int config_writer_write_element_string(struct config_writer *writer,
482 const char *element_name, const char *value)
483{
484 int ret;
485 xmlChar *encoded_element_name = NULL;
486 xmlChar *encoded_value = NULL;
487
488 if (!writer || !writer->writer || !element_name || !element_name[0] ||
489 !value) {
490 ret = -1;
491 goto end;
492 }
493
494 encoded_element_name = encode_string(element_name);
495 if (!encoded_element_name) {
496 ret = -1;
497 goto end;
498 }
499
500 encoded_value = encode_string(value);
501 if (!encoded_value) {
502 ret = -1;
503 goto end;
504 }
505
506 ret = xmlTextWriterWriteElement(writer->writer, encoded_element_name,
507 encoded_value);
508end:
509 xmlFree(encoded_element_name);
510 xmlFree(encoded_value);
511 return ret > 0 ? 0 : ret;
512}
This page took 0.024184 seconds and 4 git commands to generate.