summaryrefslogtreecommitdiff
path: root/uci.h
blob: d7fd1e2f5fbd543919a6fd949f070cff26894e04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
/*
 * libuci - Library for the Unified Configuration Interface
 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __LIBUCI_H
#define __LIBUCI_H

#include "uci_config.h"

/*
 * you can use these defines to enable debugging behavior for
 * apps compiled against libuci:
 *
 * #define UCI_DEBUG_TYPECAST:
 *   enable uci_element typecast checking at run time
 *
 */

#include <stdbool.h>
#include <setjmp.h>
#include <stdio.h>

#define UCI_CONFDIR "/etc/config"
#define UCI_SAVEDIR "/tmp/.uci"
#define UCI_DIRMODE 0700
#define UCI_FILEMODE 0600

enum
{
	UCI_OK = 0,
	UCI_ERR_MEM,
	UCI_ERR_INVAL,
	UCI_ERR_NOTFOUND,
	UCI_ERR_IO,
	UCI_ERR_PARSE,
	UCI_ERR_DUPLICATE,
	UCI_ERR_UNKNOWN,
	UCI_ERR_LAST
};

struct uci_list;
struct uci_list
{
	struct uci_list *next;
	struct uci_list *prev;
};

struct uci_element;
struct uci_package;
struct uci_section;
struct uci_option;
struct uci_history;
struct uci_context;
struct uci_backend;
struct uci_parse_context;


/**
 * uci_parse_tuple: Parse an uci tuple
 * @ctx: uci context
 * @str: input string
 * @package: output package pointer
 * @section: output section pointer
 * @option: output option pointer
 * @value: output value pointer
 *
 * format: <package>[.<section>[.<option>]][=<value>]
 */
extern int uci_parse_tuple(struct uci_context *ctx, char *str, char **package, char **section, char **option, char **value);

/**
 * uci_alloc_context: Allocate a new uci context
 */
extern struct uci_context *uci_alloc_context(void);

/**
 * uci_free_context: Free the uci context including all of its data
 */
extern void uci_free_context(struct uci_context *ctx);

/**
 * uci_perror: Print the last uci error that occured
 * @ctx: uci context
 * @str: string to print before the error message
 */
extern void uci_perror(struct uci_context *ctx, const char *str);

/**
 * uci_import: Import uci config data from a stream
 * @ctx: uci context
 * @stream: file stream to import from
 * @name: (optional) assume the config has the given name
 * @package: (optional) store the last parsed config package in this variable
 * @single: ignore the 'package' keyword and parse everything into a single package
 *
 * the name parameter is for config files that don't explicitly use the 'package <...>' keyword
 * if 'package' points to a non-null struct pointer, enable history tracking and merge 
 */
extern int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct uci_package **package, bool single);

/**
 * uci_export: Export one or all uci config packages
 * @ctx: uci context
 * @stream: output stream
 * @package: (optional) uci config package to export
 * @header: include the package header
 */
extern int uci_export(struct uci_context *ctx, FILE *stream, struct uci_package *package, bool header);

/**
 * uci_load: Parse an uci config file and store it in the uci context
 *
 * @ctx: uci context
 * @name: name of the config file (relative to the config directory)
 * @package: store the loaded config package in this variable
 */
extern int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package);

/**
 * uci_unload: Unload a config file from the uci context
 *
 * @ctx: uci context
 * @package: pointer to the uci_package struct
 */
extern int uci_unload(struct uci_context *ctx, struct uci_package *p);

/**
 * uci_lookup: Look up an uci element
 *
 * @ctx: uci context
 * @res: where to store the result
 * @package: uci_package struct 
 * @section: config section (optional)
 * @option: option to search for (optional)
 *
 * If section is omitted, then a pointer to the config package is returned
 * If option is omitted, then a pointer to the config section is returned
 */
extern int uci_lookup(struct uci_context *ctx, struct uci_element **res, struct uci_package *package, const char *section, const char *option);

/**
 * uci_lookup_ext: Extended lookup for an uci element
 *
 * @ctx: uci context
 * @res: where to store the result
 * @ptr: uci pointer tuple
 *
 * Looks up an element using the extended syntax, which is a superset of what
 * uci_parse_tuple accepts. It can look up sections by an index with an optional
 * type.
 *
 * Examples:
 *   network.@interface[0].ifname ('ifname' option of the first interface section)
 *   network.@interface[-1]       (last interface section)
 * Note: uci_lookup_ext will automatically load a config package if necessary
 */
extern int uci_lookup_ext(struct uci_context *ctx, struct uci_element **res, char *ptr);

/**
 * uci_add_section: Add an unnamed section
 * @ctx: uci context
 * @p: package to add the section to
 * @type: section type
 * @res: pointer to store a reference to the new section in
 */
extern int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res);

/**
 * uci_set_element_value: Replace an element's value with a new one
 * @ctx: uci context
 * @element: pointer to an uci_element struct pointer
 * @value: new value
 * 
 * Only valid for uci_option and uci_section. Will replace the type string
 * when used with an uci_section
 */
extern int uci_set_element_value(struct uci_context *ctx, struct uci_element **element, const char *value);

/**
 * uci_set: Set an element's value; create the element if necessary
 * @ctx: uci context
 * @package: package name
 * @section: section name
 * @option: option name
 * @value: value (option) or type (section)
 * @result: store the updated element in this variable (optional)
 */
extern int uci_set(struct uci_context *ctx, struct uci_package *p, const char *section, const char *option, const char *value, struct uci_element **result);

/**
 * uci_rename: Rename an element
 * @ctx: uci context
 * @package: package name
 * @section: section name
 * @option: option name
 * @name: new name
 */
extern int uci_rename(struct uci_context *ctx, struct uci_package *p, char *section, char *option, char *name);

/**
 * uci_delete_element: Delete a section or option
 * @ctx: uci context
 * @e: element (section or option)
 */
extern int uci_delete_element(struct uci_context *ctx, struct uci_element *e);

/**
 * uci_delete: Delete a section or option
 * @ctx: uci context
 * @p: uci package
 * @section: section name
 * @option: option name (optional)
 */
extern int uci_delete(struct uci_context *ctx, struct uci_package *p, const char *section, const char *option);

/**
 * uci_save: save change history for a package
 * @ctx: uci context
 * @p: uci_package struct
 */
extern int uci_save(struct uci_context *ctx, struct uci_package *p);

/**
 * uci_commit: commit changes to a package
 * @ctx: uci context
 * @p: uci_package struct pointer
 * @overwrite: overwrite existing config data and flush history
 *
 * committing may reload the whole uci_package data,
 * the supplied pointer is updated accordingly
 */
extern int uci_commit(struct uci_context *ctx, struct uci_package **p, bool overwrite);

/**
 * uci_list_configs: List available uci config files
 * @ctx: uci context
 *
 * caller is responsible for freeing the allocated memory behind list
 */
extern int uci_list_configs(struct uci_context *ctx, char ***list);

/** 
 * uci_set_savedir: override the default history save directory
 * @ctx: uci context
 * @dir: directory name
 */
extern int uci_set_savedir(struct uci_context *ctx, const char *dir);

/** 
 * uci_set_savedir: override the default config storage directory
 * @ctx: uci context
 * @dir: directory name
 */
extern int uci_set_confdir(struct uci_context *ctx, const char *dir);

/**
 * uci_add_history_path: add a directory to the search path for change history files
 * @ctx: uci context
 * @dir: directory name
 *
 * This function allows you to add directories, which contain 'overlays'
 * for the active config, that will never be committed.
 */
extern int uci_add_history_path(struct uci_context *ctx, const char *dir);

/**
 * uci_revert: revert all changes to a config item
 * @ctx: uci context
 * @p: pointer to a uci_package struct ptr (will be replaced by the revert)
 * @section: section name (optional)
 * @option option name (optional)
 */
extern int uci_revert(struct uci_context *ctx, struct uci_package **p, const char *section, const char *option);

/**
 * uci_parse_argument: parse a shell-style argument, with an arbitrary quoting style
 * @ctx: uci context
 * @stream: input stream
 * @str: pointer to the current line (use NULL for parsing the next line)
 * @result: pointer for the result
 */
extern int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result);

/**
 * uci_set_backend: change the default backend
 * @ctx: uci context
 * @name: name of the backend
 *
 * The default backend is "file", which uses /etc/config for config storage
 */
extern int uci_set_backend(struct uci_context *ctx, const char *name);

/**
 * uci_validate_text: validate a value string for uci options
 * @str: value
 *
 * this function checks whether a given string is acceptable as value
 * for uci options
 */
extern bool uci_validate_text(const char *str);

/* UCI data structures */
enum uci_type {
	UCI_TYPE_HISTORY = 0,
	UCI_TYPE_PACKAGE = 1,
	UCI_TYPE_SECTION = 2,
	UCI_TYPE_OPTION = 3,
	UCI_TYPE_PATH = 4,
	UCI_TYPE_BACKEND = 5,
};

enum uci_option_type {
	UCI_TYPE_STRING = 0,
};

enum uci_flags {
	UCI_FLAG_STRICT =        (1 << 0), /* strict mode for the parser */
	UCI_FLAG_PERROR =        (1 << 1), /* print parser error messages */
	UCI_FLAG_EXPORT_NAME =   (1 << 2), /* when exporting, name unnamed sections */
	UCI_FLAG_SAVED_HISTORY = (1 << 3), /* store the saved history in memory as well */
};

struct uci_element
{
	struct uci_list list;
	enum uci_type type;
	char *name;
};

struct uci_backend
{
	struct uci_element e;
	char **(*list_configs)(struct uci_context *ctx);
	struct uci_package *(*load)(struct uci_context *ctx, const char *name);
	void (*commit)(struct uci_context *ctx, struct uci_package **p, bool overwrite);

	/* private: */
	const void *ptr;
	void *priv;
};

struct uci_context
{
	/* list of config packages */
	struct uci_list root;

	/* parser context, use for error handling only */
	struct uci_parse_context *pctx;

	/* backend for import and export */
	struct uci_backend *backend;
	struct uci_list backends;

	/* uci runtime flags */
	enum uci_flags flags;

	char *confdir;
	char *savedir;

	/* search path for history files */
	struct uci_list history_path;

	/* private: */
	int err;
	const char *func;
	jmp_buf trap;
	bool internal;
	char *buf;
	int bufsz;
};

struct uci_package
{
	struct uci_element e;
	struct uci_list sections;
	struct uci_context *ctx;
	bool has_history;
	char *path;

	/* private: */
	struct uci_backend *backend;
	void *priv;
	int n_section;
	struct uci_list history;
	struct uci_list saved_history;
};

struct uci_section
{
	struct uci_element e;
	struct uci_list options;
	struct uci_package *package;
	bool anonymous;
	char *type;
};

struct uci_option
{
	struct uci_element e;
	struct uci_section *section;
	enum uci_option_type type;
	union {
		struct uci_element *list;
		char *string;
	} v;
};

enum uci_command {
	UCI_CMD_ADD,
	UCI_CMD_REMOVE,
	UCI_CMD_CHANGE,
	UCI_CMD_RENAME
};

struct uci_history
{
	struct uci_element e;
	enum uci_command cmd;
	char *section;
	char *value;
};


/* linked list handling */
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:   the type of the container struct this is embedded in.
 * @member: the name of the member within the struct.
 */
#define container_of(ptr, type, member) \
	((type *) ((char *)ptr - offsetof(type,member)))


/**
 * uci_list_entry: casts an uci_list pointer to the containing struct.
 * @_type: config, section or option
 * @_ptr: pointer to the uci_list struct
 */
#define list_to_element(ptr) \
	container_of(ptr, struct uci_element, list)

/**
 * uci_foreach_entry: loop through a list of uci elements
 * @_list: pointer to the uci_list struct
 * @_ptr: iteration variable, struct uci_element
 *
 * use like a for loop, e.g:
 *   uci_foreach(&list, p) {
 *   	...
 *   }
 */
#define uci_foreach_element(_list, _ptr)		\
	for(_ptr = list_to_element((_list)->next);	\
		&_ptr->list != (_list);			\
		_ptr = list_to_element(_ptr->list.next))

/**
 * uci_foreach_entry_safe: like uci_foreach_safe, but safe for deletion
 * @_list: pointer to the uci_list struct
 * @_tmp: temporary variable, struct uci_element *
 * @_ptr: iteration variable, struct uci_element *
 *
 * use like a for loop, e.g:
 *   uci_foreach(&list, p) {
 *   	...
 *   }
 */
#define uci_foreach_element_safe(_list, _tmp, _ptr)		\
	for(_ptr = list_to_element((_list)->next),		\
		_tmp = list_to_element(_ptr->list.next);	\
		&_ptr->list != (_list);			\
		_ptr = _tmp, _tmp = list_to_element(_ptr->list.next))

/**
 * uci_list_empty: returns true if a list is empty
 * @list: list head
 */
#define uci_list_empty(list) ((list)->next == (list))

/* wrappers for dynamic type handling */
#define uci_type_backend UCI_TYPE_BACKEND
#define uci_type_history UCI_TYPE_HISTORY
#define uci_type_package UCI_TYPE_PACKAGE
#define uci_type_section UCI_TYPE_SECTION
#define uci_type_option UCI_TYPE_OPTION

/* element typecasting */
#ifdef UCI_DEBUG_TYPECAST
static const char *uci_typestr[] = {
	[uci_type_backend] = "backend",
	[uci_type_history] = "history",
	[uci_type_package] = "package",
	[uci_type_section] = "section",
	[uci_type_option] = "option",
};

static void uci_typecast_error(int from, int to)
{
	fprintf(stderr, "Invalid typecast from '%s' to '%s'\n", uci_typestr[from], uci_typestr[to]);
}

#define BUILD_CAST(_type) \
	static inline struct uci_ ## _type *uci_to_ ## _type (struct uci_element *e) \
	{ \
		if (e->type != uci_type_ ## _type) { \
			uci_typecast_error(e->type, uci_type_ ## _type); \
		} \
		return (struct uci_ ## _type *) e; \
	}

BUILD_CAST(backend)
BUILD_CAST(history)
BUILD_CAST(package)
BUILD_CAST(section)
BUILD_CAST(option)

#else
#define uci_to_backend(ptr) container_of(ptr, struct uci_backend, e)
#define uci_to_history(ptr) container_of(ptr, struct uci_history, e)
#define uci_to_package(ptr) container_of(ptr, struct uci_package, e)
#define uci_to_section(ptr) container_of(ptr, struct uci_section, e)
#define uci_to_option(ptr)  container_of(ptr, struct uci_option, e)
#endif

/**
 * uci_alloc_element: allocate a generic uci_element, reserve a buffer and typecast
 * @ctx: uci context
 * @type: {package,section,option}
 * @name: string containing the name of the element
 * @datasize: additional buffer size to reserve at the end of the struct
 */
#define uci_alloc_element(ctx, type, name, datasize) \
	uci_to_ ## type (uci_alloc_generic(ctx, uci_type_ ## type, name, sizeof(struct uci_ ## type) + datasize))

#define uci_dataptr(ptr) \
	(((char *) ptr) + sizeof(*ptr))

#endif