/src/util-linux/libblkid/src/config.c
Line | Count | Source |
1 | | /* |
2 | | * config.c - blkid.conf routines |
3 | | * |
4 | | * Copyright (C) 2009 Karel Zak <kzak@redhat.com> |
5 | | * |
6 | | * This file may be redistributed under the terms of the |
7 | | * GNU Lesser General Public License. |
8 | | */ |
9 | | |
10 | | #include <stdio.h> |
11 | | #include <string.h> |
12 | | #include <stdlib.h> |
13 | | #include <unistd.h> |
14 | | #include <fcntl.h> |
15 | | #include <ctype.h> |
16 | | #include <sys/types.h> |
17 | | #ifdef HAVE_SYS_STAT_H |
18 | | #include <sys/stat.h> |
19 | | #endif |
20 | | #ifdef HAVE_ERRNO_H |
21 | | #include <errno.h> |
22 | | #endif |
23 | | #include <stdint.h> |
24 | | #include <stdarg.h> |
25 | | #if defined (HAVE_LIBECONF) |
26 | | # include <libeconf.h> |
27 | | # include "pathnames.h" |
28 | | #endif |
29 | | |
30 | | #include "blkidP.h" |
31 | | #include "env.h" |
32 | | #include "cctype.h" |
33 | | |
34 | | static int parse_evaluate(struct blkid_config *conf, char *s) |
35 | 0 | { |
36 | 0 | while(s && *s) { |
37 | 0 | char *sep; |
38 | |
|
39 | 0 | if (conf->nevals >= __BLKID_EVAL_LAST) |
40 | 0 | goto err; |
41 | 0 | sep = strchr(s, ','); |
42 | 0 | if (sep) |
43 | 0 | *sep = '\0'; |
44 | 0 | if (strcmp(s, "udev") == 0) |
45 | 0 | conf->eval[conf->nevals] = BLKID_EVAL_UDEV; |
46 | 0 | else if (strcmp(s, "scan") == 0) |
47 | 0 | conf->eval[conf->nevals] = BLKID_EVAL_SCAN; |
48 | 0 | else |
49 | 0 | goto err; |
50 | 0 | conf->nevals++; |
51 | 0 | if (sep) |
52 | 0 | s = sep + 1; |
53 | 0 | else |
54 | 0 | break; |
55 | 0 | } |
56 | 0 | return 0; |
57 | 0 | err: |
58 | 0 | DBG(CONFIG, ul_debug( |
59 | 0 | "config file: unknown evaluation method '%s'.", s)); |
60 | 0 | return -1; |
61 | 0 | } |
62 | | |
63 | | #ifndef HAVE_LIBECONF |
64 | | static int parse_next(FILE *fd, struct blkid_config *conf) |
65 | 0 | { |
66 | 0 | char buf[BUFSIZ]; |
67 | 0 | char *s; |
68 | | |
69 | | /* read the next non-blank non-comment line */ |
70 | 0 | do { |
71 | 0 | if (fgets (buf, sizeof(buf), fd) == NULL) |
72 | 0 | return feof(fd) ? 0 : -1; |
73 | 0 | s = strchr (buf, '\n'); |
74 | 0 | if (!s) { |
75 | | /* Missing final newline? Otherwise extremely */ |
76 | | /* long line - assume file was corrupted */ |
77 | 0 | if (feof(fd)) |
78 | 0 | s = strchr (buf, '\0'); |
79 | 0 | else { |
80 | 0 | DBG(CONFIG, ul_debug( |
81 | 0 | "config file: missing newline at line '%s'.", |
82 | 0 | buf)); |
83 | 0 | return -1; |
84 | 0 | } |
85 | 0 | } |
86 | 0 | *s = '\0'; |
87 | 0 | if (--s >= buf && *s == '\r') |
88 | 0 | *s = '\0'; |
89 | |
|
90 | 0 | s = buf; |
91 | 0 | while (*s == ' ' || *s == '\t') /* skip space */ |
92 | 0 | s++; |
93 | |
|
94 | 0 | } while (*s == '\0' || *s == '#'); |
95 | | |
96 | 0 | if (!strncmp(s, "SEND_UEVENT=", 12)) { |
97 | 0 | s += 12; |
98 | 0 | if (*s && !c_strcasecmp(s, "yes")) |
99 | 0 | conf->uevent = TRUE; |
100 | 0 | else if (*s) |
101 | 0 | conf->uevent = FALSE; |
102 | 0 | } else if (!strncmp(s, "CACHE_FILE=", 11)) { |
103 | 0 | s += 11; |
104 | 0 | free(conf->cachefile); |
105 | 0 | if (*s) |
106 | 0 | conf->cachefile = strdup(s); |
107 | 0 | else |
108 | 0 | conf->cachefile = NULL; |
109 | 0 | } else if (!strncmp(s, "EVALUATE=", 9)) { |
110 | 0 | s += 9; |
111 | 0 | if (*s && parse_evaluate(conf, s) == -1) |
112 | 0 | return -1; |
113 | 0 | } else { |
114 | 0 | DBG(CONFIG, ul_debug( |
115 | 0 | "config file: unknown option '%s'.", s)); |
116 | 0 | return -1; |
117 | 0 | } |
118 | 0 | return 0; |
119 | 0 | } |
120 | | #endif /* !HAVE_LIBECONF */ |
121 | | |
122 | | /* return real config data or built-in default */ |
123 | | struct blkid_config *blkid_read_config(const char *filename) |
124 | 0 | { |
125 | 0 | struct blkid_config *conf; |
126 | |
|
127 | 0 | conf = calloc(1, sizeof(*conf)); |
128 | 0 | if (!conf) |
129 | 0 | return NULL; |
130 | 0 | conf->uevent = -1; |
131 | | |
132 | |
|
133 | 0 | if (!filename) |
134 | 0 | filename = safe_getenv("BLKID_CONF"); |
135 | |
|
136 | 0 | #ifndef HAVE_LIBECONF |
137 | |
|
138 | 0 | FILE *f; |
139 | 0 | if (!filename) |
140 | 0 | filename = BLKID_CONFIG_FILE; |
141 | |
|
142 | 0 | DBG(CONFIG, ul_debug("reading config file: %s.", filename)); |
143 | 0 | f = fopen(filename, "r" UL_CLOEXECSTR); |
144 | 0 | if (!f) { |
145 | 0 | DBG(CONFIG, ul_debug("%s: does not exist, using built-in default", filename)); |
146 | 0 | goto dflt; |
147 | 0 | } |
148 | 0 | while (!feof(f)) { |
149 | 0 | if (parse_next(f, conf)) { |
150 | 0 | DBG(CONFIG, ul_debug("%s: parse error", filename)); |
151 | 0 | goto err; |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | | #else /* !HAVE_LIBECONF */ |
156 | | |
157 | | econf_file *file = NULL; |
158 | | char *line = NULL; |
159 | | bool uevent = false; |
160 | | econf_err error; |
161 | | |
162 | | if (filename) { |
163 | | DBG(CONFIG, ul_debug("reading config file: %s.", filename)); |
164 | | error = econf_readFile(&file, filename, "= \t", "#"); |
165 | | } else { |
166 | | #ifdef HAVE_ECONF_READCONFIG |
167 | | error = econf_readConfig(&file, NULL, |
168 | | UL_VENDORDIR_PATH, "blkid", "conf", "= \t", "#"); |
169 | | #else |
170 | | error = econf_readDirs(&file, |
171 | | UL_VENDORDIR_PATH, "/etc", "blkid", "conf", "= \t", "#"); |
172 | | #endif |
173 | | } |
174 | | |
175 | | if (error) { |
176 | | if (error == ECONF_NOFILE) { |
177 | | if (filename) |
178 | | DBG(CONFIG, |
179 | | ul_debug("%s: does not exist, using built-in default", filename)); |
180 | | else |
181 | | DBG(CONFIG, |
182 | | ul_debug("No configuration file blkid.conf found, using built-in default ")); |
183 | | goto dflt; |
184 | | } else { |
185 | | if (filename) |
186 | | DBG(CONFIG, ul_debug("%s: parse error:%s", filename, econf_errString(error))); |
187 | | else |
188 | | DBG(CONFIG, ul_debug("parse error:%s", econf_errString(error))); |
189 | | |
190 | | goto err; |
191 | | } |
192 | | } |
193 | | |
194 | | if ((error = econf_getBoolValue(file, NULL, "SEND_UEVENT", &uevent))) { |
195 | | if (error != ECONF_NOKEY) { |
196 | | DBG(CONFIG, ul_debug("couldn't fetch SEND_UEVENT currently: %s", econf_errString(error))); |
197 | | goto err; |
198 | | } else { |
199 | | DBG(CONFIG, ul_debug("key SEND_UEVENT not found, using built-in default ")); |
200 | | } |
201 | | } else { |
202 | | conf->uevent = uevent ? TRUE : FALSE; |
203 | | } |
204 | | |
205 | | if ((error = econf_getStringValue(file, NULL, "CACHE_FILE", &(conf->cachefile)))) { |
206 | | conf->cachefile = NULL; |
207 | | if (error != ECONF_NOKEY) { |
208 | | DBG(CONFIG, ul_debug("couldn't fetch CACHE_FILE correctly: %s", econf_errString(error))); |
209 | | goto err; |
210 | | } else { |
211 | | DBG(CONFIG, ul_debug("key CACHE_FILE not found, using built-in default ")); |
212 | | } |
213 | | } |
214 | | |
215 | | if ((error = econf_getStringValue(file, NULL, "EVALUATE", &line))) { |
216 | | conf->nevals = 0; |
217 | | if (error != ECONF_NOKEY) { |
218 | | DBG(CONFIG, ul_debug("couldn't fetch EVALUATE correctly: %s", econf_errString(error))); |
219 | | goto err; |
220 | | } else { |
221 | | DBG(CONFIG, ul_debug("key CACHE_FILE not found, using built-in default ")); |
222 | | } |
223 | | } else { |
224 | | if (line && *line && parse_evaluate(conf, line) == -1) |
225 | | goto err; |
226 | | } |
227 | | |
228 | | #endif /* HAVE_LIBECONF */ |
229 | 0 | dflt: |
230 | 0 | if (!conf->nevals) { |
231 | 0 | conf->eval[0] = BLKID_EVAL_UDEV; |
232 | 0 | conf->eval[1] = BLKID_EVAL_SCAN; |
233 | 0 | conf->nevals = 2; |
234 | 0 | } |
235 | 0 | if (!conf->cachefile) |
236 | 0 | conf->cachefile = strdup(BLKID_CACHE_FILE); |
237 | 0 | if (conf->uevent == -1) |
238 | 0 | conf->uevent = TRUE; |
239 | 0 | #ifndef HAVE_LIBECONF |
240 | 0 | if (f) |
241 | 0 | fclose(f); |
242 | | #else |
243 | | econf_free(file); |
244 | | free(line); |
245 | | #endif |
246 | 0 | return conf; |
247 | 0 | err: |
248 | 0 | free(conf->cachefile); |
249 | 0 | free(conf); |
250 | 0 | #ifndef HAVE_LIBECONF |
251 | 0 | fclose(f); |
252 | | #else |
253 | | econf_free(file); |
254 | | free(line); |
255 | | #endif |
256 | 0 | return NULL; |
257 | 0 | } |
258 | | |
259 | | void blkid_free_config(struct blkid_config *conf) |
260 | 0 | { |
261 | 0 | if (!conf) |
262 | 0 | return; |
263 | 0 | free(conf->cachefile); |
264 | 0 | free(conf); |
265 | 0 | } |
266 | | |
267 | | #ifdef TEST_PROGRAM |
268 | | /* |
269 | | * usage: tst_config [<filename>] |
270 | | */ |
271 | | int main(int argc, char *argv[]) |
272 | | { |
273 | | int i; |
274 | | struct blkid_config *conf; |
275 | | char *filename = NULL; |
276 | | |
277 | | blkid_init_debug(BLKID_DEBUG_ALL); |
278 | | |
279 | | if (argc == 2) |
280 | | filename = argv[1]; |
281 | | |
282 | | conf = blkid_read_config(filename); |
283 | | if (!conf) |
284 | | return EXIT_FAILURE; |
285 | | |
286 | | printf("EVALUATE: "); |
287 | | for (i = 0; i < conf->nevals; i++) |
288 | | printf("%s ", conf->eval[i] == BLKID_EVAL_UDEV ? "udev" : "scan"); |
289 | | printf("\n"); |
290 | | |
291 | | printf("SEND UEVENT: %s\n", conf->uevent ? "TRUE" : "FALSE"); |
292 | | printf("CACHE_FILE: %s\n", conf->cachefile); |
293 | | |
294 | | blkid_free_config(conf); |
295 | | return EXIT_SUCCESS; |
296 | | } |
297 | | #endif |