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
26 #include "blkidP.h"
27 #include "env.h"
28
29 static int parse_evaluate(struct blkid_config *conf, char *s)
30 {
31 while(s && *s) {
32 char *sep;
33
34 if (conf->nevals >= __BLKID_EVAL_LAST)
35 goto err;
36 sep = strchr(s, ',');
37 if (sep)
38 *sep = '\0';
39 if (strcmp(s, "udev") == 0)
40 conf->eval[conf->nevals] = BLKID_EVAL_UDEV;
41 else if (strcmp(s, "scan") == 0)
42 conf->eval[conf->nevals] = BLKID_EVAL_SCAN;
43 else
44 goto err;
45 conf->nevals++;
46 if (sep)
47 s = sep + 1;
48 else
49 break;
50 }
51 return 0;
52 err:
53 DBG(CONFIG, ul_debug(
54 "config file: unknown evaluation method '%s'.", s));
55 return -1;
56 }
57
58 static int parse_next(FILE *fd, struct blkid_config *conf)
59 {
60 char buf[BUFSIZ];
61 char *s;
62
63 /* read the next non-blank non-comment line */
64 do {
65 if (fgets (buf, sizeof(buf), fd) == NULL)
66 return feof(fd) ? 0 : -1;
67 s = strchr (buf, '\n');
68 if (!s) {
69 /* Missing final newline? Otherwise extremely */
70 /* long line - assume file was corrupted */
71 if (feof(fd))
72 s = strchr (buf, '\0');
73 else {
74 DBG(CONFIG, ul_debug(
75 "config file: missing newline at line '%s'.",
76 buf));
77 return -1;
78 }
79 }
80 *s = '\0';
81 if (--s >= buf && *s == '\r')
82 *s = '\0';
83
84 s = buf;
85 while (*s == ' ' || *s == '\t') /* skip space */
86 s++;
87
88 } while (*s == '\0' || *s == '#');
89
90 if (!strncmp(s, "SEND_UEVENT=", 12)) {
91 s += 12;
92 if (*s && !strcasecmp(s, "yes"))
93 conf->uevent = TRUE;
94 else if (*s)
95 conf->uevent = FALSE;
96 } else if (!strncmp(s, "CACHE_FILE=", 11)) {
97 s += 11;
98 free(conf->cachefile);
99 if (*s)
100 conf->cachefile = strdup(s);
101 else
102 conf->cachefile = NULL;
103 } else if (!strncmp(s, "EVALUATE=", 9)) {
104 s += 9;
105 if (*s && parse_evaluate(conf, s) == -1)
106 return -1;
107 } else {
108 DBG(CONFIG, ul_debug(
109 "config file: unknown option '%s'.", s));
110 return -1;
111 }
112 return 0;
113 }
114
115 /* return real config data or built-in default */
116 struct blkid_config *blkid_read_config(const char *filename)
117 {
118 struct blkid_config *conf;
119 FILE *f;
120
121 if (!filename)
122 filename = safe_getenv("BLKID_CONF");
123 if (!filename)
124 filename = BLKID_CONFIG_FILE;
125
126 conf = calloc(1, sizeof(*conf));
127 if (!conf)
128 return NULL;
129 conf->uevent = -1;
130
131 DBG(CONFIG, ul_debug("reading config file: %s.", filename));
132
133 f = fopen(filename, "r" UL_CLOEXECSTR);
134 if (!f) {
135 DBG(CONFIG, ul_debug("%s: does not exist, using built-in default", filename));
136 goto dflt;
137 }
138 while (!feof(f)) {
139 if (parse_next(f, conf)) {
140 DBG(CONFIG, ul_debug("%s: parse error", filename));
141 goto err;
142 }
143 }
144 dflt:
145 if (!conf->nevals) {
146 conf->eval[0] = BLKID_EVAL_UDEV;
147 conf->eval[1] = BLKID_EVAL_SCAN;
148 conf->nevals = 2;
149 }
150 if (!conf->cachefile)
151 conf->cachefile = strdup(BLKID_CACHE_FILE);
152 if (conf->uevent == -1)
153 conf->uevent = TRUE;
154 if (f)
155 fclose(f);
156 return conf;
157 err:
158 free(conf);
159 fclose(f);
160 return NULL;
161 }
162
163 void blkid_free_config(struct blkid_config *conf)
164 {
165 if (!conf)
166 return;
167 free(conf->cachefile);
168 free(conf);
169 }
170
171 #ifdef TEST_PROGRAM
172 /*
173 * usage: tst_config [<filename>]
174 */
175 int main(int argc, char *argv[])
176 {
177 int i;
178 struct blkid_config *conf;
179 char *filename = NULL;
180
181 blkid_init_debug(BLKID_DEBUG_ALL);
182
183 if (argc == 2)
184 filename = argv[1];
185
186 conf = blkid_read_config(filename);
187 if (!conf)
188 return EXIT_FAILURE;
189
190 printf("EVALUATE: ");
191 for (i = 0; i < conf->nevals; i++)
192 printf("%s ", conf->eval[i] == BLKID_EVAL_UDEV ? "udev" : "scan");
193 printf("\n");
194
195 printf("SEND UEVENT: %s\n", conf->uevent ? "TRUE" : "FALSE");
196 printf("CACHE_FILE: %s\n", conf->cachefile);
197
198 blkid_free_config(conf);
199 return EXIT_SUCCESS;
200 }
201 #endif