1/*
2 * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
3 * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
4 *
5 *	This program is free software; you can redistribute it and/or modify it
6 *	under the terms of the GNU General Public License as published by the
7 *	Free Software Foundation version 2 of the License.
8 *
9 *	This program is distributed in the hope that it will be useful, but
10 *	WITHOUT ANY WARRANTY; without even the implied warranty of
11 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 *	General Public License for more details.
13 *
14 *	You should have received a copy of the GNU General Public License along
15 *	with this program; if not, write to the Free Software Foundation, Inc.,
16 *	51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 */
19
20#include <stdlib.h>
21#include <string.h>
22#include <stdio.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <errno.h>
26#include <ctype.h>
27#include <syslog.h>
28
29#include "udev.h"
30
31/* global variables */
32char udev_root[PATH_SIZE];
33char udev_config_filename[PATH_SIZE];
34char udev_rules_dir[PATH_SIZE];
35int udev_log_priority;
36int udev_run;
37
38static int get_key(char **line, char **key, char **value)
39{
40	char *linepos;
41	char *temp;
42
43	linepos = *line;
44	if (!linepos)
45		return -1;
46
47	/* skip whitespace */
48	while (isspace(linepos[0]))
49		linepos++;
50
51	/* get the key */
52	*key = linepos;
53	while (1) {
54		linepos++;
55		if (linepos[0] == '\0')
56			return -1;
57		if (isspace(linepos[0]))
58			break;
59		if (linepos[0] == '=')
60			break;
61	}
62
63	/* terminate key */
64	linepos[0] = '\0';
65	linepos++;
66
67	/* skip whitespace */
68	while (isspace(linepos[0]))
69		linepos++;
70
71	/* get the value*/
72	if (linepos[0] == '"')
73		linepos++;
74	else
75		return -1;
76	*value = linepos;
77
78	temp = strchr(linepos, '"');
79	if (!temp)
80		return -1;
81	temp[0] = '\0';
82
83	return 0;
84}
85
86static int parse_config_file(void)
87{
88	char line[LINE_SIZE];
89	char *bufline;
90	char *linepos;
91	char *variable;
92	char *value;
93	char *buf;
94	size_t bufsize;
95	size_t cur;
96	size_t count;
97	int lineno;
98	int retval = 0;
99
100	if (file_map(udev_config_filename, &buf, &bufsize) != 0) {
101		err("can't open '%s' as config file: %s", udev_config_filename, strerror(errno));
102		return -ENODEV;
103	}
104
105	/* loop through the whole file */
106	lineno = 0;
107	cur = 0;
108	while (cur < bufsize) {
109		count = buf_get_line(buf, bufsize, cur);
110		bufline = &buf[cur];
111		cur += count+1;
112		lineno++;
113
114		if (count >= sizeof(line)) {
115			err("line too long, conf line skipped %s, line %d", udev_config_filename, lineno);
116			continue;
117		}
118
119		/* eat the whitespace */
120		while ((count > 0) && isspace(bufline[0])) {
121			bufline++;
122			count--;
123		}
124		if (count == 0)
125			continue;
126
127		/* see if this is a comment */
128		if (bufline[0] == COMMENT_CHARACTER)
129			continue;
130
131		memcpy(line, bufline, count);
132		line[count] = '\0';
133
134		linepos = line;
135		retval = get_key(&linepos, &variable, &value);
136		if (retval != 0) {
137			err("error parsing %s, line %d:%d", udev_config_filename, lineno, (int)(linepos-line));
138			continue;
139		}
140
141		if (strcasecmp(variable, "udev_root") == 0) {
142			strlcpy(udev_root, value, sizeof(udev_root));
143			remove_trailing_chars(udev_root, '/');
144			continue;
145		}
146
147		if (strcasecmp(variable, "udev_rules") == 0) {
148			strlcpy(udev_rules_dir, value, sizeof(udev_rules_dir));
149			remove_trailing_chars(udev_rules_dir, '/');
150			continue;
151		}
152
153		if (strcasecmp(variable, "udev_log") == 0) {
154			udev_log_priority = log_priority(value);
155			continue;
156		}
157	}
158
159	file_unmap(buf, bufsize);
160	return retval;
161}
162
163void udev_config_init(void)
164{
165	const char *env;
166
167	strcpy(udev_root, UDEV_ROOT);
168	strcpy(udev_config_filename, UDEV_CONFIG_FILE);
169	strcpy(udev_rules_dir, UDEV_RULES_DIR);
170	udev_log_priority = LOG_ERR;
171	udev_run = 1;
172
173	/* disable RUN key execution */
174	env = getenv("UDEV_RUN");
175	if (env && !string_is_true(env))
176		udev_run = 0;
177
178	env = getenv("UDEV_CONFIG_FILE");
179	if (env) {
180		strlcpy(udev_config_filename, env, sizeof(udev_config_filename));
181		remove_trailing_chars(udev_config_filename, '/');
182	}
183
184	parse_config_file();
185
186	env = getenv("UDEV_ROOT");
187	if (env) {
188		strlcpy(udev_root, env, sizeof(udev_root));
189		remove_trailing_chars(udev_root, '/');
190	}
191
192	env = getenv("UDEV_LOG");
193	if (env)
194		udev_log_priority = log_priority(env);
195
196	dbg("UDEV_CONFIG_FILE='%s'", udev_config_filename);
197	dbg("udev_root='%s'", udev_root);
198	dbg("udev_rules='%s'", udev_rules_dir);
199	dbg("udev_log=%d", udev_log_priority);
200}
201