1 /* 2 * libuci - Library for the Unified Configuration Interface 3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> 4 * 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 8 * 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. 13 */ 14 15 /* 16 * This file contains misc utility functions and wrappers to standard 17 * functions, which throw exceptions upon failure. 18 */ 19 #define _GNU_SOURCE 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <sys/file.h> 23 #include <stdbool.h> 24 #include <unistd.h> 25 #include <ctype.h> 26 #include <fcntl.h> 27 #include <errno.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <libgen.h> 31 32 #include "uci.h" 33 #include "uci_internal.h" 34 35 __private void *uci_malloc(struct uci_context *ctx, size_t size) 36 { 37 void *ptr; 38 39 ptr = calloc(1, size); 40 if (!ptr) 41 UCI_THROW(ctx, UCI_ERR_MEM); 42 43 return ptr; 44 } 45 46 __private void *uci_realloc(struct uci_context *ctx, void *ptr, size_t size) 47 { 48 ptr = realloc(ptr, size); 49 if (!ptr) 50 UCI_THROW(ctx, UCI_ERR_MEM); 51 52 return ptr; 53 } 54 55 __private char *uci_strdup(struct uci_context *ctx, const char *str) 56 { 57 char *ptr; 58 59 ptr = strdup(str); 60 if (!ptr) 61 UCI_THROW(ctx, UCI_ERR_MEM); 62 63 return ptr; 64 } 65 66 /* 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 70 */ 71 __private bool uci_validate_str(const char *str, bool name, bool package) 72 { 73 if (!*str) 74 return false; 75 76 for (; *str; str++) { 77 unsigned char c = *str; 78 79 if (isalnum(c) || c == '_') 80 continue; 81 82 if (c == '-' && package) 83 continue; 84 85 if (name || (c < 33) || (c > 126)) 86 return false; 87 } 88 return true; 89 } 90 91 bool uci_validate_text(const char *str) 92 { 93 while (*str) { 94 unsigned char c = *str; 95 96 if (c < 32 && c != '\t' && c != '\n' && c != '\r') 97 return false; 98 99 str++; 100 } 101 return true; 102 } 103 104 __private void uci_alloc_parse_context(struct uci_context *ctx) 105 { 106 ctx->pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context)); 107 } 108 109 int uci_parse_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str) 110 { 111 char *last = NULL; 112 char *tmp; 113 114 UCI_HANDLE_ERR(ctx); 115 UCI_ASSERT(ctx, str); 116 UCI_ASSERT(ctx, ptr); 117 118 memset(ptr, 0, sizeof(struct uci_ptr)); 119 120 /* value */ 121 last = strchr(str, '='); 122 if (last) { 123 *last = 0; 124 last++; 125 ptr->value = last; 126 } 127 128 ptr->package = strsep(&str, "."); 129 if (!ptr->package) 130 goto error; 131 132 ptr->section = strsep(&str, "."); 133 if (!ptr->section) { 134 ptr->target = UCI_TYPE_PACKAGE; 135 goto lastval; 136 } 137 138 ptr->option = strsep(&str, "."); 139 if (!ptr->option) { 140 ptr->target = UCI_TYPE_SECTION; 141 goto lastval; 142 } else { 143 ptr->target = UCI_TYPE_OPTION; 144 } 145 146 tmp = strsep(&str, "."); 147 if (tmp) 148 goto error; 149 150 lastval: 151 if (ptr->package && !uci_validate_package(ptr->package)) 152 goto error; 153 if (ptr->section && !uci_validate_name(ptr->section)) 154 ptr->flags |= UCI_LOOKUP_EXTENDED; 155 if (ptr->option && !uci_validate_name(ptr->option)) 156 goto error; 157 if (ptr->value && !uci_validate_text(ptr->value)) 158 goto error; 159 160 return 0; 161 162 error: 163 memset(ptr, 0, sizeof(struct uci_ptr)); 164 UCI_THROW(ctx, UCI_ERR_PARSE); 165 } 166 167 168 __private void uci_parse_error(struct uci_context *ctx, char *reason) 169 { 170 struct uci_parse_context *pctx = ctx->pctx; 171 172 pctx->reason = reason; 173 pctx->byte = pctx_pos(pctx); 174 UCI_THROW(ctx, UCI_ERR_PARSE); 175 } 176 177 178 179 /* 180 * open a stream and go to the right position 181 * 182 * note: when opening for write and seeking to the beginning of 183 * the stream, truncate the file 184 */ 185 __private FILE *uci_open_stream(struct uci_context *ctx, const char *filename, const char *origfilename, int pos, bool write, bool create) 186 { 187 struct stat statbuf; 188 FILE *file = NULL; 189 int fd, ret; 190 int flags = (write ? O_RDWR : O_RDONLY); 191 mode_t mode = UCI_FILEMODE; 192 char *name = NULL; 193 char *filename2 = NULL; 194 195 if (create) { 196 flags |= O_CREAT; 197 if (origfilename) { 198 name = basename((char *) origfilename); 199 } else { 200 name = basename((char *) filename); 201 } 202 if ((asprintf(&filename2, "%s/%s", ctx->confdir, name) < 0) || !filename2) { 203 UCI_THROW(ctx, UCI_ERR_MEM); 204 } else { 205 if (stat(filename2, &statbuf) == 0) 206 mode = statbuf.st_mode; 207 208 free(filename2); 209 } 210 } 211 212 if (!write && ((stat(filename, &statbuf) < 0) || 213 ((statbuf.st_mode & S_IFMT) != S_IFREG))) { 214 UCI_THROW(ctx, UCI_ERR_NOTFOUND); 215 } 216 217 fd = open(filename, flags, mode); 218 if (fd < 0) 219 goto error; 220 221 ret = flock(fd, (write ? LOCK_EX : LOCK_SH)); 222 if ((ret < 0) && (errno != ENOSYS)) 223 goto error_close; 224 225 ret = lseek(fd, 0, pos); 226 227 if (ret < 0) 228 goto error_unlock; 229 230 file = fdopen(fd, (write ? "w+" : "r")); 231 if (file) 232 goto done; 233 234 error_unlock: 235 flock(fd, LOCK_UN); 236 error_close: 237 close(fd); 238 error: 239 UCI_THROW(ctx, UCI_ERR_IO); 240 done: 241 return file; 242 } 243 244 __private void uci_close_stream(FILE *stream) 245 { 246 int fd; 247 248 if (!stream) 249 return; 250 251 fflush(stream); 252 fd = fileno(stream); 253 flock(fd, LOCK_UN); 254 fclose(stream); 255 } 256 257 258
This page was automatically generated by LXR 0.3.1. • OpenWrt