Add a save API to lttng-ctl
[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
31#include "config.h"
32#include "config-internal.h"
33
34struct handler_filter_args {
35 const char* section;
36 config_entry_handler_cb handler;
37 void *user_data;
38};
39
40const char * const config_str_yes = "yes";
41const char * const config_str_true = "true";
42const char * const config_str_on = "on";
43const char * const config_str_no = "no";
44const char * const config_str_false = "false";
45const char * const config_str_off = "off";
46const char * const config_xml_encoding = "UTF-8";
47/* Size of the encoding's largest character */
48const size_t config_xml_encoding_bytes_per_char = 2;
49const char * const config_xml_indent_string = "\t";
50const char * const config_xml_true = "true";
51const char * const config_xml_false = "false";
52
53static int config_entry_handler_filter(struct handler_filter_args *args,
54 const char *section, const char *name, const char *value)
55{
56 int ret = 0;
57 struct config_entry entry = { section, name, value };
58
59 assert(args);
60
61 if (!section || !name || !value) {
62 ret = -EIO;
63 goto end;
64 }
65
66 if (args->section) {
67 if (strcmp(args->section, section)) {
68 goto end;
69 }
70 }
71
72 ret = args->handler(&entry, args->user_data);
73end:
74 return ret;
75}
76
77LTTNG_HIDDEN
78int config_get_section_entries(const char *override_path, const char *section,
79 config_entry_handler_cb handler, void *user_data)
80{
81 int ret = 0;
82 FILE *config_file = NULL;
83 struct handler_filter_args filter = { section, handler, user_data };
84
85 if (override_path) {
86 config_file = fopen(override_path, "r");
87 if (config_file) {
88 DBG("Loaded daemon configuration file at %s",
89 override_path);
90 } else {
91 ERR("Failed to open daemon configuration file at %s",
92 override_path);
93 ret = -ENOENT;
94 goto end;
95 }
96 } else {
97 char *path = utils_get_home_dir();
98
99 /* Try to open the user's daemon configuration file */
100 if (path) {
101 ret = asprintf(&path, DEFAULT_DAEMON_HOME_CONFIGPATH, path);
102 if (ret < 0) {
103 goto end;
104 }
105
106 ret = 0;
107 config_file = fopen(path, "r");
108 if (config_file) {
109 DBG("Loaded daemon configuration file at %s", path);
110 }
111
112 free(path);
113 }
114
115 /* Try to open the system daemon configuration file */
116 if (!config_file) {
117 config_file = fopen(DEFAULT_DAEMON_HOME_CONFIGPATH, "r");
118 }
119 }
120
121 if (!config_file) {
122 DBG("No daemon configuration file found.");
123 goto end;
124 }
125
126 ret = ini_parse_file(config_file,
127 (ini_entry_handler) config_entry_handler_filter, (void *) &filter);
128
129end:
130 return ret;
131}
132
133LTTNG_HIDDEN
134int config_parse_value(const char *value)
135{
136 int i, ret = 0;
137 char *endptr, *lower_str;
138 size_t len;
139 unsigned long v;
140
141 len = strlen(value);
142 if (!len) {
143 ret = -1;
144 goto end;
145 }
146
147 v = strtoul(value, &endptr, 10);
148 if (endptr != value) {
149 ret = v;
150 goto end;
151 }
152
153 lower_str = zmalloc(len + 1);
154 if (!lower_str) {
155 PERROR("zmalloc");
156 ret = -errno;
157 goto end;
158 }
159
160 for (i = 0; i < len; i++) {
161 lower_str[i] = tolower(value[i]);
162 }
163
164 if (!strcmp(lower_str, config_str_yes) ||
165 !strcmp(lower_str, config_str_true) ||
166 !strcmp(lower_str, config_str_on)) {
167 ret = 1;
168 } else if (!strcmp(lower_str, config_str_no) ||
169 !strcmp(lower_str, config_str_false) ||
170 !strcmp(lower_str, config_str_off)) {
171 ret = 0;
172 } else {
173 ret = -1;
174 }
175
176 free(lower_str);
177end:
178 return ret;
179}
180
181/*
182 * Returns a xmlChar string which must be released using xmlFree().
183 */
184static xmlChar *encode_string(const char *in_str)
185{
186 xmlChar *out_str = NULL;
187 xmlCharEncodingHandlerPtr handler;
188 int out_len, ret, in_len;
189
190 assert(in_str);
191
192 handler = xmlFindCharEncodingHandler(config_xml_encoding);
193 if (!handler) {
194 ERR("xmlFindCharEncodingHandler return NULL!. Configure issue!");
195 goto end;
196 }
197
198 in_len = strlen(in_str);
199 /*
200 * Add 1 byte for the NULL terminted character. The factor 2 here is
201 * because UTF-8 can be on two bytes so this fits the worst case for each
202 * bytes.
203 */
204 out_len = (in_len * 2) + 1;
205 out_str = xmlMalloc(out_len);
206 if (!out_str) {
207 goto end;
208 }
209
210 ret = handler->input(out_str, &out_len, (const xmlChar *) in_str, &in_len);
211 if (ret < 0) {
212 xmlFree(out_str);
213 out_str = NULL;
214 goto end;
215 }
216
217 /* out_len is now the size of out_str */
218 out_str[out_len] = '\0';
219end:
220 return out_str;
221}
222
223LTTNG_HIDDEN
224struct config_writer *config_writer_create(int fd_output)
225{
226 int ret;
227 struct config_writer *writer;
228 xmlOutputBufferPtr buffer;
229
230 writer = zmalloc(sizeof(struct config_writer));
231 if (!writer) {
232 PERROR("zmalloc config_writer_create");
233 goto end;
234 }
235
236 buffer = xmlOutputBufferCreateFd(fd_output, NULL);
237 if (!buffer) {
238 goto error_destroy;
239 }
240
241 writer->writer = xmlNewTextWriter(buffer);
242 ret = xmlTextWriterStartDocument(writer->writer, NULL,
243 config_xml_encoding, NULL);
244 if (ret < 0) {
245 goto error_destroy;
246 }
247
248 ret = xmlTextWriterSetIndentString(writer->writer,
249 BAD_CAST config_xml_indent_string);
250 if (ret) {
251 goto error_destroy;
252 }
253
254 ret = xmlTextWriterSetIndent(writer->writer, 1);
255 if (ret) {
256 goto error_destroy;
257 }
258
259end:
260 return writer;
261error_destroy:
262 config_writer_destroy(writer);
263 return NULL;
264}
265
266LTTNG_HIDDEN
267int config_writer_destroy(struct config_writer *writer)
268{
269 int ret = 0;
270
271 if (!writer) {
272 ret = -EINVAL;
273 goto end;
274 }
275
276 if (xmlTextWriterEndDocument(writer->writer) < 0) {
277 WARN("Could not close XML document");
278 ret = -EIO;
279 }
280
281 if (writer->writer) {
282 xmlFreeTextWriter(writer->writer);
283 }
284
285 free(writer);
286end:
287 return ret;
288}
289
290LTTNG_HIDDEN
291int config_writer_open_element(struct config_writer *writer,
292 const char *element_name)
293{
294 int ret;
295 xmlChar *encoded_element_name;
296
297 if (!writer || !writer->writer || !element_name || !element_name[0]) {
298 ret = -1;
299 goto end;
300 }
301
302 encoded_element_name = encode_string(element_name);
303 if (!encoded_element_name) {
304 ret = -1;
305 goto end;
306 }
307
308 ret = xmlTextWriterStartElement(writer->writer, encoded_element_name);
309 xmlFree(encoded_element_name);
310end:
311 return ret > 0 ? 0 : ret;
312}
313
314LTTNG_HIDDEN
315int config_writer_close_element(struct config_writer *writer)
316{
317 int ret;
318
319 if (!writer || !writer->writer) {
320 ret = -1;
321 goto end;
322 }
323
324 ret = xmlTextWriterEndElement(writer->writer);
325end:
326 return ret > 0 ? 0 : ret;
327}
328
329LTTNG_HIDDEN
330int config_writer_write_element_unsigned_int(struct config_writer *writer,
331 const char *element_name, uint64_t value)
332{
333 int ret;
334 xmlChar *encoded_element_name;
335
336 if (!writer || !writer->writer || !element_name || !element_name[0]) {
337 ret = -1;
338 goto end;
339 }
340
341 encoded_element_name = encode_string(element_name);
342 if (!encoded_element_name) {
343 ret = -1;
344 goto end;
345 }
346
347 ret = xmlTextWriterWriteFormatElement(writer->writer,
348 encoded_element_name, "%" PRIu64, value);
349 xmlFree(encoded_element_name);
350end:
351 return ret > 0 ? 0 : ret;
352}
353
354LTTNG_HIDDEN
355int config_writer_write_element_signed_int(struct config_writer *writer,
356 const char *element_name, int64_t value)
357{
358 int ret;
359 xmlChar *encoded_element_name;
360
361 if (!writer || !writer->writer || !element_name || !element_name[0]) {
362 ret = -1;
363 goto end;
364 }
365
366 encoded_element_name = encode_string(element_name);
367 if (!encoded_element_name) {
368 ret = -1;
369 goto end;
370 }
371
372 ret = xmlTextWriterWriteFormatElement(writer->writer,
373 encoded_element_name, "%" PRIi64, value);
374 xmlFree(encoded_element_name);
375end:
376 return ret > 0 ? 0 : ret;
377}
378
379LTTNG_HIDDEN
380int config_writer_write_element_bool(struct config_writer *writer,
381 const char *element_name, int value)
382{
383 return config_writer_write_element_string(writer, element_name,
384 value ? config_xml_true : config_xml_false);
385}
386
387LTTNG_HIDDEN
388int config_writer_write_element_string(struct config_writer *writer,
389 const char *element_name, const char *value)
390{
391 int ret;
392 xmlChar *encoded_element_name = NULL;
393 xmlChar *encoded_value = NULL;
394
395 if (!writer || !writer->writer || !element_name || !element_name[0] ||
396 !value) {
397 ret = -1;
398 goto end;
399 }
400
401 encoded_element_name = encode_string(element_name);
402 if (!encoded_element_name) {
403 ret = -1;
404 goto end;
405 }
406
407 encoded_value = encode_string(value);
408 if (!encoded_value) {
409 ret = -1;
410 goto end;
411 }
412
413 ret = xmlTextWriterWriteElement(writer->writer, encoded_element_name,
414 encoded_value);
415end:
416 xmlFree(encoded_element_name);
417 xmlFree(encoded_value);
418 return ret > 0 ? 0 : ret;
419}
This page took 0.023296 seconds and 4 git commands to generate.