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