2 * libuci - Library for the Unified Configuration Interface
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
16 * This file contains misc utility functions and wrappers to standard
17 * functions, which throw exceptions upon failure.
20 #include <sys/types.h>
33 #include "uci_internal.h"
35 __private
void *uci_malloc(struct uci_context
*ctx
, size_t size
)
39 ptr
= calloc(1, size
);
41 UCI_THROW(ctx
, UCI_ERR_MEM
);
46 __private
void *uci_realloc(struct uci_context
*ctx
, void *ptr
, size_t size
)
48 ptr
= realloc(ptr
, size
);
50 UCI_THROW(ctx
, UCI_ERR_MEM
);
55 __private
char *uci_strdup(struct uci_context
*ctx
, const char *str
)
61 UCI_THROW(ctx
, UCI_ERR_MEM
);
67 * validate strings for names and types, reject special characters
68 * for names, only alphanum and _ is allowed (shell compatibility)
69 * for types, we allow more characters
71 __private
bool uci_validate_str(const char *str
, bool name
, bool package
)
77 unsigned char c
= *str
;
79 if (isalnum(c
) || c
== '_')
82 if (c
== '-' && package
)
85 if (name
|| (c
< 33) || (c
> 126))
91 bool uci_validate_text(const char *str
)
94 unsigned char c
= *str
;
96 if (c
< 32 && c
!= '\t' && c
!= '\n' && c
!= '\r')
104 __private
void uci_alloc_parse_context(struct uci_context
*ctx
)
106 ctx
->pctx
= (struct uci_parse_context
*) uci_malloc(ctx
, sizeof(struct uci_parse_context
));
109 int uci_parse_ptr(struct uci_context
*ctx
, struct uci_ptr
*ptr
, char *str
)
115 UCI_ASSERT(ctx
, str
);
116 UCI_ASSERT(ctx
, ptr
);
118 memset(ptr
, 0, sizeof(struct uci_ptr
));
121 last
= strchr(str
, '=');
128 ptr
->package
= strsep(&str
, ".");
132 ptr
->section
= strsep(&str
, ".");
134 ptr
->target
= UCI_TYPE_PACKAGE
;
138 ptr
->option
= strsep(&str
, ".");
140 ptr
->target
= UCI_TYPE_SECTION
;
143 ptr
->target
= UCI_TYPE_OPTION
;
146 tmp
= strsep(&str
, ".");
151 if (ptr
->package
&& !uci_validate_package(ptr
->package
))
153 if (ptr
->section
&& !uci_validate_name(ptr
->section
))
154 ptr
->flags
|= UCI_LOOKUP_EXTENDED
;
155 if (ptr
->option
&& !uci_validate_name(ptr
->option
))
157 if (ptr
->value
&& !uci_validate_text(ptr
->value
))
163 memset(ptr
, 0, sizeof(struct uci_ptr
));
164 UCI_THROW(ctx
, UCI_ERR_PARSE
);
168 __private
void uci_parse_error(struct uci_context
*ctx
, char *reason
)
170 struct uci_parse_context
*pctx
= ctx
->pctx
;
172 pctx
->reason
= reason
;
173 pctx
->byte
= pctx_pos(pctx
);
174 UCI_THROW(ctx
, UCI_ERR_PARSE
);
180 * open a stream and go to the right position
182 * note: when opening for write and seeking to the beginning of
183 * the stream, truncate the file
185 __private
FILE *uci_open_stream(struct uci_context
*ctx
, const char *filename
, const char *origfilename
, int pos
, bool write
, bool create
)
190 int flags
= (write
? O_RDWR
: O_RDONLY
);
191 mode_t mode
= UCI_FILEMODE
;
193 char *filename2
= NULL
;
198 name
= basename((char *) origfilename
);
200 name
= basename((char *) filename
);
202 if ((asprintf(&filename2
, "%s/%s", ctx
->confdir
, name
) < 0) || !filename2
) {
203 UCI_THROW(ctx
, UCI_ERR_MEM
);
205 if (stat(filename2
, &statbuf
) == 0)
206 mode
= statbuf
.st_mode
;
212 if (!write
&& ((stat(filename
, &statbuf
) < 0) ||
213 ((statbuf
.st_mode
& S_IFMT
) != S_IFREG
))) {
214 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
217 fd
= open(filename
, flags
, mode
);
221 ret
= flock(fd
, (write
? LOCK_EX
: LOCK_SH
));
222 if ((ret
< 0) && (errno
!= ENOSYS
))
225 ret
= lseek(fd
, 0, pos
);
230 file
= fdopen(fd
, (write
? "w+" : "r"));
239 UCI_THROW(ctx
, UCI_ERR_IO
);
244 __private
void uci_close_stream(FILE *stream
)