1 /*
2  *   toconf.c
3  *
4  *   Configuration file support for tosha.
5  *
6  *   Oliver Fromme  <olli@fromme.com>
7  *
8  *   Copyright (C) 1997,1998,1999
9  *        Oliver Fromme.  All rights reserved.
10  *
11  *   Redistribution and use in source and binary forms, with or without
12  *   modification, are permitted provided that the following conditions
13  *   are met:
14  *   1. Redistributions of source code must retain the above copyright
15  *      notice, this list of conditions and the following disclaimer.
16  *   2. Redistributions in binary form must reproduce the above copyright
17  *      notice, this list of conditions and the following disclaimer in the
18  *      documentation and/or other materials provided with the distribution.
19  *   3. Neither the name of the author nor the names of any co-contributors
20  *      may be used to endorse or promote products derived from this software
21  *      without specific prior written permission.
22  *
23  *   THIS SOFTWARE IS PROVIDED BY OLIVER FROMME AND CONTRIBUTORS ``AS IS'' AND
24  *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  *   ARE DISCLAIMED.  IN NO EVENT SHALL OLIVER FROMME OR CONTRIBUTORS BE LIABLE
27  *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  *   SUCH DAMAGE.
34  *
35  *   @(#)$Id: toconf.c,v 1.4 1999/01/01 23:31:56 olli Exp $
36  */
37 
38 static const char cvsid[]
39     = "@(#)$Id: toconf.c,v 1.4 1999/01/01 23:31:56 olli Exp $";
40 
41 #include <stdlib.h>
42 #include <limits.h>
43 
44 #include "utils.h"
45 #include "global.h"
46 #include "toconf.h"
47 
48 toconf_entry *toconf = NULL;
49 int toconf_num = 0;
50 
51 #ifndef GLOBAL_ETC_DIR
52 #	define GLOBAL_ETC_DIR "/usr/local/etc"
53 #endif
54 
55 const char *configfile[] = {
56 #ifndef NO_HOME_TOSHARC
57 #	ifdef LOCAL_TOSHARC
58 		LOCAL_TOSHARC
59 #	else
60 		"~/.tosharc",
61 #	endif
62 #endif
63 #ifdef ADDITIONAL_TOSHARC
64 	ADDITIONAL_TOSHARC ,
65 #endif
66 	GLOBAL_ETC_DIR "/tosharc",
67 	NULL
68 };
69 
70 static bool
whitespace(char c)71 whitespace (char c)
72 {
73 	return c == ' ' || c == '\t' || c == '\r' || c == '\n';
74 }
75 
76 static void
skipwhitespace(char ** c2ptr)77 skipwhitespace (char **c2ptr)
78 {
79 	while (**c2ptr && whitespace(**c2ptr))
80 		(*c2ptr)++;
81 }
82 
83 typedef struct {
84 	const char *name;
85 	char *buf;
86 	int line;
87 } filestate;
88 
89 static void
file_error(filestate * fs,const char * msg,const char * par,const char * pos)90 file_error (filestate *fs, const char *msg, const char *par, const char *pos)
91 {
92 	fprintf (stderr, "%s:  Error in %s line %d column %d:\n   ",
93 	    me, fs->name, fs->line, pos - fs->buf);
94 	fprintf (stderr, msg, par);
95 	fprintf (stderr, "\n");
96 	exit (1);
97 }
98 
99 static char *
readstring(char ** c2ptr,const char * field,filestate * fs)100 readstring (char **c2ptr, const char *field, filestate *fs)
101 {
102 	char *cptr, *qptr, *s;
103 
104 	cptr = *c2ptr;
105 	if (*cptr++ != '\"')
106 		file_error (fs, "Expected quoted %s string.", field, cptr);
107 	if (!(qptr = strchr(cptr, '\"')))
108 		file_error (fs, "Unterminated %s string.", field, cptr);
109 	if (!(s = (char *) malloc(1 + qptr - cptr)))
110 		out_of_memory();
111 	strncpy (s, cptr, qptr - cptr);
112 	s[qptr - cptr] = 0;
113 	*c2ptr = qptr + 1;
114 	skipwhitespace (c2ptr);
115 	return s;
116 }
117 
118 static bool
readbool(char ** c2ptr,const char * field,filestate * fs)119 readbool (char **c2ptr, const char *field, filestate *fs)
120 {
121 	char *cptr;
122 	bool result;
123 
124 	cptr = *c2ptr;
125 	result = FALSE;
126 	if (*cptr == '1')
127 		result = TRUE;
128 	else if (*cptr != '0')
129 		file_error (fs, "Expected 0 or 1 for \"%s\".", field, cptr);
130 	*c2ptr = cptr + 1;
131 	skipwhitespace (c2ptr);
132 	return result;
133 }
134 
135 static int
readint(char ** c2ptr,int min,int max,const char * field,filestate * fs)136 readint (char **c2ptr, int min, int max, const char *field, filestate *fs)
137 {
138 	char *cptr, *eptr;
139 	int result;
140 
141 	cptr = *c2ptr;
142 	if (!*cptr)
143 		file_error (fs, "Missing \"%s\" field.", field, cptr);
144 	result = strtol(cptr, &eptr, 0);
145 	if (eptr == cptr || (*eptr && !whitespace(*eptr)))
146 		file_error (fs, "Illegal characters in \"%s\" field.",
147 		    field, eptr);
148 	if (result < min || result > max)
149 		file_error (fs, "\"%s\" field out of range.", field, cptr);
150 	*c2ptr = eptr;
151 	skipwhitespace (c2ptr);
152 	return result;
153 }
154 
155 static int
readconfigfile(const char * filename)156 readconfigfile (const char *filename)
157 {
158 	FILE *f;
159 	char buf[8192];
160 	char *cptr, *jptr;
161 	int cn;
162 	filestate fs;
163 
164 	if (!(f = fopen(filename, "r")))
165 		return 0;
166 	fs.name = filename;
167 	fs.buf = buf;
168 	fs.line = 0;
169 	while ((cptr = fgets(buf, 8192, f))) {
170 		fs.line++;
171 		skipwhitespace (&cptr);
172 		if (!*cptr || *cptr == '#')
173 			continue;
174 		cn = toconf_num++;
175 		if (!(toconf = (toconf_entry *) realloc(toconf,
176 		    sizeof(toconf_entry) * toconf_num)))
177 			out_of_memory();
178 		toconf[cn].vendor  = readstring(&cptr, "vendor", &fs);
179 		toconf[cn].product = readstring(&cptr, "product", &fs);
180 		toconf[cn].version = readstring(&cptr, "version", &fs);
181 		toconf[cn].readcmd = readint(&cptr, 0, 255, "readcmd", &fs);
182 		toconf[cn].mdchng  = readbool(&cptr, "mdchng", &fs);
183 		toconf[cn].density = readint(&cptr, 0, 255, "density", &fs);
184 		toconf[cn].swab    = readbool(&cptr, "swap bytes", &fs);
185 		toconf[cn].blocks  = readint(&cptr, 1, MAX_SECTORSPERBUF,
186 		    "blocks", &fs);
187 		jptr = cptr;
188 		toconf[cn].jitter  = readint(&cptr, 0, MAX_SECTORSPERBUF,
189 		    "jitter", &fs);
190 		if (toconf[cn].jitter >= toconf[cn].blocks)
191 			file_error (&fs, "\"jitter\" value must be less "
192 			    "than \"blocks\" value.", "", jptr);
193 		if (*cptr)
194 			file_error (&fs, "Invalid characters at the end "
195 			    "of the line.", "", cptr);
196 	}
197 	fclose (f);
198 	return 1;
199 }
200 
201 static int
getfilename(int number,char ** fn)202 getfilename (int number, char **fn)
203 {
204 	const char *filename, *home;
205 
206 	if (!(filename = configfile[number]))
207 		return -1;	/* end of list */
208 	if (*filename == '~') {
209 		if (!(home = getenv("HOME")) || *home != '/') {
210 			fprintf (stderr,
211 			    "%s: Warning: $HOME not set or invalid.\n", me);
212 			return 0;	/* skip */
213 		}
214 		if (!(*fn = (char *) malloc(strlen(home) + strlen(filename))))
215 			out_of_memory();
216 		strcpy (*fn, home);
217 		strcat (*fn, filename + 1);
218 	}
219 	else {
220 		if (!(*fn = strdup(filename)))
221 			out_of_memory();
222 	}
223 	return 1;	/* success */
224 }
225 
226 /*
227  *   toconf_readconfig()
228  *   reads all files in the list configfile[] (see above).
229  *   At least one of those _must_ exist and contain at least
230  *   one CD-ROM drive configuration entry!
231  */
232 
233 int
toconf_readconfig(void)234 toconf_readconfig (void)
235 {
236 	int result, i;
237 	char *fn;
238 
239 	i = 0;
240 	for (i = 0; (result = getfilename(i, &fn)) >= 0; i++)
241 		if (result) {
242 			readconfigfile (fn);
243 			free (fn);
244 		}
245 	if (!toconf_num) {
246 		fprintf (stderr, "%s:  No configuration entries found!  "
247 		    "Searched at the following places:\n", me);
248 		for (i = 0; (result = getfilename(i, &fn)) >= 0; i++)
249 			if (result) {
250 				fprintf (stderr, "   %s\n", fn);
251 				free (fn);
252 			}
253 		exit (1);
254 	}
255 	return toconf_num;
256 }
257 
258 toconf_entry *
toconf_searchentry(const char * vendor,const char * product,const char * version)259 toconf_searchentry
260     (const char *vendor, const char *product, const char *version)
261 {
262 	toconf_entry *te;
263 	int i, l1, l2, l3;
264 
265 	for (i = 0; i < toconf_num; i++) {
266 		te = toconf + i;
267 		l1 = strlen(te->vendor);
268 		l2 = strlen(te->product);
269 		l3 = strlen(te->version);
270 		if (!l1 && !l2 && !l3) {
271 			fprintf (stderr, "%s: Warning: Unknown drive, "
272 			    "using default configuration!\n", me);
273 			return te;
274 		}
275 		if ((!l1 || !strncmp(te->vendor, vendor, l1)) &&
276 		    (!l2 || !strncmp(te->product, product, l2)) &&
277 		    (!l3 || !strncmp(te->version, version, l3)))
278 			return te;
279 	}
280 	fprintf (stderr,
281 	    "%s: Error: Unknown drive and missing default entry!\n", me);
282 	exit (1);
283 }
284 
285 /* EOF */
286