xref: /aosp_15_r20/external/mtools/config.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1 /*  Copyright 1996-2005,2007-2009,2011 Alain Knaff.
2  *  This file is part of mtools.
3  *
4  *  Mtools is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Mtools is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 #include "sysincludes.h"
19 #include "mtools.h"
20 #include "codepage.h"
21 #include "mtoolsPaths.h"
22 
23 /* global variables */
24 /* they are not really harmful here, because there is only one configuration
25  * file per invocations */
26 
27 #define MAX_LINE_LEN 256
28 
29 /* scanner */
30 static char buffer[MAX_LINE_LEN+1]; /* buffer for the whole line */
31 static char *pos; /* position in line */
32 static char *token; /* last scanned token */
33 static size_t token_length; /* length of the token */
34 static FILE *fp; /* file pointer for configuration file */
35 static int linenumber; /* current line number. Only used for printing
36 						* error messages */
37 static int lastTokenLinenumber; /* line numnber for last token */
38 static const char *filename=NULL; /* current file name. Used for printing
39 				   * error messages, and for storing in
40 				   * the device definition (mtoolstest) */
41 static int file_nr=0;
42 
43 
44 static unsigned int flag_mask; /* mask of currently set flags */
45 
46 /* devices */
47 static unsigned int cur_devs; /* current number of defined devices */
48 static int cur_dev; /* device being filled in. If negative, none */
49 static int trusted=0; /* is the currently parsed device entry trusted? */
50 static unsigned int nr_dev; /* number of devices that the current table can
51 			       hold */
52 struct device *devices; /* the device table */
53 static int token_nr; /* number of tokens in line */
54 
55 static char default_drive='\0'; /* default drive */
56 
57 /* "environment" variables */
58 unsigned int mtools_skip_check=0;
59 unsigned int mtools_fat_compatibility=0;
60 unsigned int mtools_ignore_short_case=0;
61 uint8_t mtools_rate_0=0;
62 uint8_t mtools_rate_any=0;
63 unsigned int mtools_no_vfat=0;
64 unsigned int mtools_numeric_tail=1;
65 unsigned int mtools_dotted_dir=0;
66 unsigned int mtools_twenty_four_hour_clock=1;
67 unsigned int mtools_lock_timeout=30;
68 unsigned int mtools_default_codepage=850;
69 const char *mtools_date_string="yyyy-mm-dd";
70 char *country_string=0;
71 
72 typedef struct switches_l {
73     const char *name;
74     caddr_t address;
75     enum {
76 	T_INT,
77 	T_STRING,
78 	T_UINT,
79 	T_UINT8,
80 	T_UINT16,
81 	T_UQSTRING
82     } type;
83 } switches_t;
84 
85 static switches_t global_switches[] = {
86     { "MTOOLS_LOWER_CASE", (caddr_t) & mtools_ignore_short_case, T_UINT },
87     { "MTOOLS_FAT_COMPATIBILITY", (caddr_t) & mtools_fat_compatibility, T_UINT },
88     { "MTOOLS_SKIP_CHECK", (caddr_t) & mtools_skip_check, T_UINT },
89     { "MTOOLS_NO_VFAT", (caddr_t) & mtools_no_vfat, T_UINT },
90     { "MTOOLS_RATE_0", (caddr_t) &mtools_rate_0, T_UINT8 },
91     { "MTOOLS_RATE_ANY", (caddr_t) &mtools_rate_any, T_UINT8 },
92     { "MTOOLS_NAME_NUMERIC_TAIL", (caddr_t) &mtools_numeric_tail, T_UINT },
93     { "MTOOLS_DOTTED_DIR", (caddr_t) &mtools_dotted_dir, T_UINT },
94     { "MTOOLS_TWENTY_FOUR_HOUR_CLOCK",
95       (caddr_t) &mtools_twenty_four_hour_clock, T_UINT },
96     { "MTOOLS_DATE_STRING",
97       (caddr_t) &mtools_date_string, T_STRING },
98     { "MTOOLS_LOCK_TIMEOUT", (caddr_t) &mtools_lock_timeout, T_UINT },
99     { "DEFAULT_CODEPAGE", (caddr_t) &mtools_default_codepage, T_UINT }
100 };
101 
102 typedef struct {
103     const char *name;
104     unsigned int flag;
105 } flags_t;
106 
107 static flags_t openflags[] = {
108 #ifdef O_SYNC
109     { "sync",		O_SYNC },
110 #endif
111 #ifdef O_NDELAY
112     { "nodelay",	O_NDELAY },
113 #endif
114 #ifdef O_EXCL
115     { "exclusive",	O_EXCL },
116 #endif
117     { "none", 0 }  /* hack for those compilers that choke on commas
118 		    * after the last element of an array */
119 };
120 
121 static flags_t misc_flags[] = {
122 #ifdef USE_XDF
123     { "use_xdf",		USE_XDF_FLAG },
124 #endif
125     { "scsi",			SCSI_FLAG },
126     { "nolock",			NOLOCK_FLAG },
127     { "mformat_only",	MFORMAT_ONLY_FLAG },
128     { "filter",			FILTER_FLAG },
129     { "privileged",		PRIV_FLAG },
130     { "vold",			VOLD_FLAG },
131     { "remote",			FLOPPYD_FLAG },
132     { "swap",			SWAP_FLAG },
133 };
134 
135 static struct {
136     const char *name;
137     signed char fat_bits;
138     unsigned int tracks;
139     unsigned short heads;
140     unsigned short sectors;
141 } default_formats[] = {
142     { "hd514",			12, 80, 2, 15 },
143     { "high-density-5-1/4",	12, 80, 2, 15 },
144     { "1.2m",			12, 80, 2, 15 },
145 
146     { "hd312",			12, 80, 2, 18 },
147     { "high-density-3-1/2",	12, 80, 2, 18 },
148     { "1.44m",	 		12, 80, 2, 18 },
149 
150     { "dd312",			12, 80, 2, 9 },
151     { "double-density-3-1/2",	12, 80, 2, 9 },
152     { "720k",			12, 80, 2, 9 },
153 
154     { "dd514",			12, 40, 2, 9 },
155     { "double-density-5-1/4",	12, 40, 2, 9 },
156     { "360k",			12, 40, 2, 9 },
157 
158     { "320k",			12, 40, 2, 8 },
159     { "180k",			12, 40, 1, 9 },
160     { "160k",			12, 40, 1, 8 }
161 };
162 
163 #define OFFS(x) ((caddr_t)&((struct device *)0)->x)
164 
165 static switches_t dswitches[]= {
166     { "FILE", OFFS(name), T_STRING },
167     { "OFFSET", OFFS(offset), T_UINT },
168     { "PARTITION", OFFS(partition), T_UINT },
169     { "FAT", OFFS(fat_bits), T_INT },
170     { "FAT_BITS", OFFS(fat_bits), T_UINT },
171     { "MODE", OFFS(mode), T_UINT },
172     { "TRACKS",  OFFS(tracks), T_UINT },
173     { "CYLINDERS",  OFFS(tracks), T_UINT },
174     { "HEADS", OFFS(heads), T_UINT16 },
175     { "SECTORS", OFFS(sectors), T_UINT16 },
176     { "HIDDEN", OFFS(hidden), T_UINT },
177     { "PRECMD", OFFS(precmd), T_STRING },
178     { "BLOCKSIZE", OFFS(blocksize), T_UINT },
179     { "CODEPAGE", OFFS(codepage), T_UINT },
180     { "DATA_MAP", OFFS(data_map), T_UQSTRING }
181 };
182 
183 #if (defined  HAVE_TOUPPER_L || defined HAVE_STRNCASECMP_L)
184 static locale_t C=NULL;
185 
init_canon(void)186 static void init_canon(void) {
187     if(C == NULL)
188 	C = newlocale(LC_CTYPE_MASK, "C", NULL);
189 }
190 #endif
191 
192 #ifdef HAVE_TOUPPER_L
canon_drv(int drive)193 static int canon_drv(int drive) {
194     int ret;
195     init_canon();
196     ret = toupper_l(drive, C);
197     return ret;
198 }
199 #else
canon_drv(int drive)200 static int canon_drv(int drive) {
201     return toupper(drive);
202 }
203 #endif
204 
205 #ifdef HAVE_STRNCASECMP_L
cmp_tok(const char * a,const char * b,size_t len)206 static int cmp_tok(const char *a, const char *b, size_t len) {
207     init_canon();
208     return strncasecmp_l(a, b, len, C);
209 }
210 #else
cmp_tok(const char * a,const char * b,size_t len)211 static int cmp_tok(const char *a, const char *b, size_t len) {
212     return strncasecmp(a, b, len);
213 }
214 #endif
215 
216 
ch_canon_drv(char drive)217 static char ch_canon_drv(char drive) {
218     return (char) canon_drv( (unsigned char) drive);
219 }
220 
maintain_default_drive(char drive)221 static void maintain_default_drive(char drive)
222 {
223     if(default_drive == ':')
224 	return; /* we have an image */
225     if(default_drive == '\0' ||
226        default_drive > drive)
227 	default_drive = drive;
228 }
229 
get_default_drive(void)230 char get_default_drive(void)
231 {
232     if(default_drive != '\0')
233 	return default_drive;
234     else
235 	return 'A';
236 }
237 
238 static void syntax(const char *msg, int thisLine) NORETURN;
syntax(const char * msg,int thisLine)239 static void syntax(const char *msg, int thisLine)
240 {
241     char drive='\0';
242     if(thisLine)
243 	lastTokenLinenumber = linenumber;
244     if(cur_dev >= 0)
245 	drive = devices[cur_dev].drive;
246     fprintf(stderr,"Syntax error at line %d ", lastTokenLinenumber);
247     if(drive) fprintf(stderr, "for drive %c: ", drive);
248     if(token) fprintf(stderr, "column %ld ", (long)(token - buffer));
249     fprintf(stderr, "in file %s: %s", filename, msg);
250     if(errno != 0)
251 	fprintf(stderr, " (%s)", strerror(errno));
252     fprintf(stderr, "\n");
253     exit(1);
254 }
255 
256 #pragma GCC diagnostic push
257 #pragma GCC diagnostic ignored "-Wcast-align"
get_env_conf(void)258 static void get_env_conf(void)
259 {
260     char *s;
261     unsigned int i;
262 
263     for(i=0; i< sizeof(global_switches) / sizeof(*global_switches); i++) {
264 	s = getenv(global_switches[i].name);
265 	if(s) {
266 	    errno = 0;
267 	    switch(global_switches[i].type) {
268 	    case T_INT:
269 		* ((int *)global_switches[i].address) = strtoi(s,0,0);
270 		break;
271 	    case T_UINT:
272 		* ((unsigned int *)global_switches[i].address) = strtoui(s,0,0);
273 		break;
274 	    case T_UINT8:
275 		* ((uint8_t *)global_switches[i].address) = strtou8(s,0,0);
276 		break;
277 	    case T_UINT16:
278 		* ((uint16_t *)global_switches[i].address) = strtou16(s,0,0);
279 		break;
280 	    case T_STRING:
281 	    case T_UQSTRING:
282 		* ((char **)global_switches[i].address) = s;
283 		break;
284 	    }
285 	    if(errno != 0) {
286 		fprintf(stderr, "Bad number %s for %s (%s)\n", s,
287 			global_switches[i].name,
288 			strerror(errno));
289 		exit(1);
290 	    }
291 	}
292     }
293 }
294 #pragma GCC diagnostic pop
295 
mtools_getline(void)296 static int mtools_getline(void)
297 {
298     if(!fp || !fgets(buffer, MAX_LINE_LEN+1, fp))
299 	return -1;
300     linenumber++;
301     pos = buffer;
302     token_nr = 0;
303     buffer[MAX_LINE_LEN] = '\0';
304     if(strlen(buffer) == MAX_LINE_LEN)
305 	syntax("line too long", 1);
306     return 0;
307 }
308 
skip_junk(int expect)309 static void skip_junk(int expect)
310 {
311     lastTokenLinenumber = linenumber;
312     while(!pos || !*pos || strchr(" #\n\t", *pos)) {
313 	if(!pos || !*pos || *pos == '#') {
314 	    if(mtools_getline()) {
315 		pos = 0;
316 		if(expect)
317 		    syntax("end of file unexpected", 1);
318 		return;
319 	    }
320 	} else
321 	    pos++;
322     }
323     token_nr++;
324 }
325 
326 /* get the next token */
get_next_token(void)327 static char *get_next_token(void)
328 {
329     skip_junk(0);
330     if(!pos) {
331 	token_length = 0;
332 	token = 0;
333 	return 0;
334     }
335     token = pos;
336     token_length = strcspn(token, " \t\n#:=");
337     pos += token_length;
338     return token;
339 }
340 
match_token(const char * template)341 static int match_token(const char *template)
342 {
343     return (strlen(template) == token_length &&
344 	    !cmp_tok(template, token, token_length));
345 }
346 
expect_char(char c)347 static void expect_char(char c)
348 {
349     char buf[11];
350 
351     skip_junk(1);
352     if(*pos != c) {
353 	sprintf(buf, "expected %c", c);
354 	syntax(buf, 1);
355     }
356     pos++;
357 }
358 
get_string(void)359 static char *get_string(void)
360 {
361     char *end, *str;
362 
363     skip_junk(1);
364     if(*pos != '"')
365 	syntax(" \" expected", 0);
366     str = pos+1;
367     end = strchr(str, '\"');
368     if(!end)
369 	syntax("unterminated string constant", 1);
370     str = strndup(str, ptrdiff(end, str));
371     pos = end+1;
372     return str;
373 }
374 
get_unquoted_string(void)375 static char *get_unquoted_string(void)
376 {
377     if(*pos == '"')
378 	return get_string();
379     else {
380 	char *str=get_next_token();
381 	return strndup(str, token_length);
382     }
383 }
384 
get_unumber(unsigned long max)385 static unsigned long get_unumber(unsigned long max)
386 {
387     char *last;
388     unsigned long n;
389 
390     skip_junk(1);
391     last = pos;
392     n=strtoul(pos, &pos, 0);
393     if(errno)
394 	syntax("bad number", 0);
395     if(last == pos)
396 	syntax("numeral expected", 0);
397     if(n > max)
398 	syntax("number too big", 0);
399     pos++;
400     token_nr++;
401     return n;
402 }
403 
get_number(void)404 static int get_number(void)
405 {
406     char *last;
407     int n;
408 
409     skip_junk(1);
410     last = pos;
411     n=(int) strtol(pos, &pos, 0);
412     if(errno)
413 	syntax("bad number", 0);
414     if(last == pos)
415 	syntax("numeral expected", 0);
416     pos++;
417     token_nr++;
418     return n;
419 }
420 
421 /* purge all entries pertaining to a given drive from the table */
purge(char drive,int fn)422 static void purge(char drive, int fn)
423 {
424     unsigned int i, j;
425 
426     drive = ch_canon_drv(drive);
427     for(j=0, i=0; i < cur_devs; i++) {
428 	if(devices[i].drive != drive ||
429 	   devices[i].file_nr == fn)
430 	    devices[j++] = devices[i];
431     }
432     cur_devs = j;
433 }
434 
grow(void)435 static void grow(void)
436 {
437     if(cur_devs >= nr_dev - 2) {
438 	nr_dev = (cur_devs + 2) << 1;
439 	if(!(devices=Grow(devices, nr_dev, struct device))){
440 	    printOom();
441 	    exit(1);
442 	}
443     }
444 }
445 
446 
init_drive(void)447 static void init_drive(void)
448 {
449     memset((char *)&devices[cur_dev], 0, sizeof(struct device));
450     devices[cur_dev].ssize = 2;
451 }
452 
453 /* prepends a device to the table */
prepend(void)454 static void prepend(void)
455 {
456     unsigned int i;
457 
458     grow();
459     for(i=cur_devs; i>0; i--)
460 	devices[i] = devices[i-1];
461     cur_dev = 0;
462     cur_devs++;
463     init_drive();
464 }
465 
466 
467 /* appends a device to the table */
append(void)468 static void append(void)
469 {
470     grow();
471     cur_dev = (int) cur_devs;
472     cur_devs++;
473     init_drive();
474 }
475 
476 
finish_drive_clause(void)477 static void finish_drive_clause(void)
478 {
479     if(cur_dev == -1) {
480 	trusted = 0;
481 	return;
482     }
483     if(!devices[cur_dev].name)
484 	syntax("missing filename", 0);
485     if(devices[cur_dev].tracks ||
486        devices[cur_dev].heads ||
487        devices[cur_dev].sectors) {
488 	if(!devices[cur_dev].tracks ||
489 	   !devices[cur_dev].heads ||
490 	   !devices[cur_dev].sectors)
491 	    syntax("incomplete geometry: either indicate all of track/heads/sectors or none of them", 0);
492 	if(!(devices[cur_dev].misc_flags &
493 	     (MFORMAT_ONLY_FLAG | FILTER_FLAG)))
494 	    syntax("if you supply a geometry, you also must supply one of the `mformat_only' or `filter' flags", 0);
495     }
496     devices[cur_dev].file_nr = file_nr;
497     devices[cur_dev].cfg_filename = filename;
498     if(!trusted && (devices[cur_dev].misc_flags & PRIV_FLAG)) {
499 	fprintf(stderr,
500 		"Warning: privileged flag ignored for drive %c: defined in file %s\n",
501 		canon_drv(devices[cur_dev].drive), filename);
502 	devices[cur_dev].misc_flags &= ~PRIV_FLAG;
503     }
504     trusted = 0;
505     cur_dev = -1;
506 }
507 
508 #pragma GCC diagnostic push
509 #pragma GCC diagnostic ignored "-Wcast-align"
set_var(struct switches_l * switches,int nr,caddr_t base_address)510 static int set_var(struct switches_l *switches, int nr,
511 		   caddr_t base_address)
512 {
513     int i;
514     for(i=0; i < nr; i++) {
515 	if(match_token(switches[i].name)) {
516 	    expect_char('=');
517 	    /* All pointers cast back to pointers with alignment
518 	     * constraints were such pointers with alignment
519 	     * constraints initially, thus they do indeed fit the
520 	     * constraint */
521 
522 	    if(switches[i].type == T_UINT)
523 		* ((unsigned int *)((long)switches[i].address+base_address)) =
524 		    (unsigned int) get_unumber(UINT_MAX);
525 	    else if(switches[i].type == T_UINT8)
526 		* ((uint8_t *)((long)switches[i].address+base_address)) =
527 		    (uint8_t) get_unumber(UINT8_MAX);
528 	    else if(switches[i].type == T_UINT16)
529 		* ((uint16_t *)((long)switches[i].address+base_address)) =
530 		    (uint16_t) get_unumber(UINT16_MAX);
531 	    else if(switches[i].type == T_INT)
532 		* ((int *)((long)switches[i].address+base_address)) =
533 		    get_number();
534 	    else if (switches[i].type == T_STRING)
535 		* ((char**)((long)switches[i].address+base_address))=
536 		    get_string();
537 	    else if (switches[i].type == T_UQSTRING)
538 		* ((char**)((long)switches[i].address+base_address))=
539 		    get_unquoted_string();
540 	    return 0;
541 	}
542     }
543     return 1;
544 }
545 #pragma GCC diagnostic pop
546 
set_openflags(struct device * dev)547 static int set_openflags(struct device *dev)
548 {
549     unsigned int i;
550 
551     for(i=0; i < sizeof(openflags) / sizeof(*openflags); i++) {
552 	if(match_token(openflags[i].name)) {
553 	    dev->mode |= openflags[i].flag;
554 	    return 0;
555 	}
556     }
557     return 1;
558 }
559 
set_misc_flags(struct device * dev)560 static int set_misc_flags(struct device *dev)
561 {
562     unsigned int i;
563     for(i=0; i < sizeof(misc_flags) / sizeof(*misc_flags); i++) {
564 	if(match_token(misc_flags[i].name)) {
565 	    flag_mask |= misc_flags[i].flag;
566 	    skip_junk(0);
567 	    if(pos && *pos == '=') {
568 		pos++;
569 		switch(get_number()) {
570 		    case 0:
571 			return 0;
572 		    case 1:
573 			break;
574 		    default:
575 			syntax("expected 0 or 1", 0);
576 		}
577 	    }
578 	    dev->misc_flags |= misc_flags[i].flag;
579 	    return 0;
580 	}
581     }
582     return 1;
583 }
584 
set_def_format(struct device * dev)585 static int set_def_format(struct device *dev)
586 {
587     unsigned int i;
588 
589     for(i=0; i < sizeof(default_formats)/sizeof(*default_formats); i++) {
590 	if(match_token(default_formats[i].name)) {
591 	    if(!dev->ssize)
592 		dev->ssize = 2;
593 	    if(!dev->tracks)
594 		dev->tracks = default_formats[i].tracks;
595 	    if(!dev->heads)
596 		dev->heads = default_formats[i].heads;
597 	    if(!dev->sectors)
598 		dev->sectors = default_formats[i].sectors;
599 	    if(!dev->fat_bits)
600 		dev->fat_bits = default_formats[i].fat_bits;
601 	    return 0;
602 	}
603     }
604     return 1;
605 }
606 
607 static void parse_all(int privilege);
608 
set_cmd_line_image(char * img)609 void set_cmd_line_image(char *img) {
610   char *ofsp;
611 
612   prepend();
613   devices[cur_dev].drive = ':';
614   default_drive = ':';
615 
616   ofsp = strstr(img, "@@");
617   if (ofsp == NULL) {
618     /* no separator => no offset */
619     devices[cur_dev].name = strdup(img);
620     devices[cur_dev].offset = 0;
621   } else {
622     devices[cur_dev].name = strndup(img, ptrdiff(ofsp, img));
623     devices[cur_dev].offset = str_to_offset(ofsp+2);
624   }
625 
626   devices[cur_dev].fat_bits = 0;
627   devices[cur_dev].tracks = 0;
628   devices[cur_dev].heads = 0;
629   devices[cur_dev].sectors = 0;
630   if (strchr(devices[cur_dev].name, '|')) {
631     char *pipechar = strchr(devices[cur_dev].name, '|');
632     *pipechar = 0;
633     strncpy(buffer, pipechar+1, MAX_LINE_LEN);
634     buffer[MAX_LINE_LEN] = '\0';
635     fp = NULL;
636     filename = "{command line}";
637     linenumber = 0;
638     lastTokenLinenumber = 0;
639     pos = buffer;
640     token = 0;
641     parse_all(0);
642   }
643 }
644 
check_number_parse_errno(char c,const char * oarg,char * endptr)645 void check_number_parse_errno(char c, const char *oarg, char *endptr) {
646     if(endptr && *endptr) {
647 	fprintf(stderr, "Bad number %s\n", oarg);
648 	exit(1);
649     }
650     if(errno) {
651 	fprintf(stderr, "Bad number %s for -%c (%s)\n", oarg,
652 		c, strerror(errno));
653 	exit(1);
654     }
655 }
656 
tou16(int in,const char * comment)657 static uint16_t tou16(int in, const char *comment) {
658     if(in > (int) UINT16_MAX) {
659 	fprintf(stderr, "Number of %s %d too big\n", comment, in);
660 	exit(1);
661     }
662     if(in < 0) {
663 	fprintf(stderr, "Number of %s %d negative\n", comment, in);
664 	exit(1);
665     }
666     return (uint16_t) in;
667 }
668 
parse_old_device_line(char drive)669 static void parse_old_device_line(char drive)
670 {
671     char name[MAXPATHLEN];
672     int items;
673     long offset;
674 
675     int heads, sectors, tracks;
676 
677     /* finish any old drive */
678     finish_drive_clause();
679 
680     /* purge out data of old configuration files */
681     purge(drive, file_nr);
682 
683     /* reserve slot */
684     append();
685     items = sscanf(token,"%c %s %i %i %i %i %li",
686 		   &devices[cur_dev].drive,name,&devices[cur_dev].fat_bits,
687 		   &tracks,&heads,&sectors, &offset);
688     devices[cur_dev].heads = tou16(heads, "heads");
689     devices[cur_dev].sectors = tou16(sectors, "sectors");
690     devices[cur_dev].tracks = (unsigned int) tracks;
691     devices[cur_dev].offset = (off_t) offset;
692     switch(items){
693 	case 2:
694 	    devices[cur_dev].fat_bits = 0;
695 	    /* fall thru */
696 	case 3:
697 	    devices[cur_dev].sectors = 0;
698 	    devices[cur_dev].heads = 0;
699 	    devices[cur_dev].tracks = 0;
700 	    /* fall thru */
701 	case 6:
702 	    devices[cur_dev].offset = 0;
703 	    /* fall thru */
704 	default:
705 	    break;
706 	case 0:
707 	case 1:
708 	case 4:
709 	case 5:
710 	    syntax("bad number of parameters", 1);
711     }
712     if(!devices[cur_dev].tracks){
713 	devices[cur_dev].sectors = 0;
714 	devices[cur_dev].heads = 0;
715     }
716 
717     devices[cur_dev].drive = ch_canon_drv(devices[cur_dev].drive);
718     maintain_default_drive(devices[cur_dev].drive);
719     if (!(devices[cur_dev].name = strdup(name))) {
720 	printOom();
721 	exit(1);
722     }
723     devices[cur_dev].misc_flags |= MFORMAT_ONLY_FLAG;
724     finish_drive_clause();
725     pos=0;
726 }
727 
parse_one(int privilege)728 static int parse_one(int privilege)
729 {
730     int action=0;
731 
732     get_next_token();
733     if(!token)
734 	return 0;
735 
736     if((match_token("drive") && ((action = 1)))||
737        (match_token("drive+") && ((action = 2))) ||
738        (match_token("+drive") && ((action = 3))) ||
739        (match_token("clear_drive") && ((action = 4))) ) {
740 	/* finish off the previous drive */
741 	finish_drive_clause();
742 
743 	get_next_token();
744 	if(token_length != 1)
745 	    syntax("drive letter expected", 0);
746 
747 	if(action==1 || action==4)
748 	    /* replace existing drive */
749 	    purge(token[0], file_nr);
750 	if(action==4)
751 	    return 1;
752 	if(action==3)
753 	    prepend();
754 	else
755 	    append();
756 	memset((char*)(devices+cur_dev), 0, sizeof(*devices));
757 	trusted = privilege;
758 	flag_mask = 0;
759 	devices[cur_dev].drive = ch_canon_drv(token[0]);
760 	maintain_default_drive(devices[cur_dev].drive);
761 	expect_char(':');
762 	return 1;
763     }
764     if(token_nr == 1 && token_length == 1) {
765 	parse_old_device_line(token[0]);
766 	return 1;
767     }
768 
769     if((cur_dev < 0 ||
770 	(set_var(dswitches,
771 		 sizeof(dswitches)/sizeof(*dswitches),
772 		 (caddr_t)&devices[cur_dev]) &&
773 	 set_openflags(&devices[cur_dev]) &&
774 	 set_misc_flags(&devices[cur_dev]) &&
775 	 set_def_format(&devices[cur_dev]))) &&
776        set_var(global_switches,
777 	       sizeof(global_switches)/sizeof(*global_switches), 0))
778 	syntax("unrecognized keyword", 1);
779     return 1;
780 }
781 
parse_all(int privilege)782 static void parse_all(int privilege) {
783     errno=0;
784     while (parse_one(privilege));
785 }
786 
787 
parse(const char * name,int privilege)788 static int parse(const char *name, int privilege)
789 {
790     if(fp) {
791 	fprintf(stderr, "File descriptor already set!\n");
792 	exit(1);
793     }
794     fp = fopen(name, "r");
795     if(!fp)
796 	return 0;
797     file_nr++;
798     filename = name; /* no strdup needed: although lifetime of variable
799 			exceeds this function (due to dev->cfg_filename),
800 			we know that the name is always either
801 			1. a constant
802 			2. a statically allocate buffer
803 			3. an environment variable that stays unchanged
804 		     */
805     linenumber = 0;
806     lastTokenLinenumber = 0;
807     pos = 0;
808     token = 0;
809     cur_dev = -1; /* no current device */
810 
811     parse_all(privilege);
812     finish_drive_clause();
813     fclose(fp);
814     filename = NULL;
815     fp = NULL;
816     return 1;
817 }
818 
read_config(void)819 void read_config(void)
820 {
821     char *homedir;
822     char *envConfFile;
823     static char conf_file[MAXPATHLEN+sizeof(CFG_FILE1)];
824 
825 
826     /* copy compiled-in devices */
827     file_nr = 0;
828     cur_devs = nr_const_devices;
829     nr_dev = nr_const_devices + 2;
830     devices = NewArray(nr_dev, struct device);
831     if(!devices) {
832 	printOom();
833 	exit(1);
834     }
835     if(nr_const_devices)
836 	memcpy(devices, const_devices,
837 	       nr_const_devices*sizeof(struct device));
838 
839     (void) ((parse(CONF_FILE,1) |
840 	     parse(LOCAL_CONF_FILE,1) |
841 	     parse(SYS_CONF_FILE,1)) ||
842 	    (parse(OLD_CONF_FILE,1) |
843 	     parse(OLD_LOCAL_CONF_FILE,1)));
844     /* the old-name configuration files only get executed if none of the
845      * new-name config files were used */
846 
847     homedir = get_homedir();
848     if ( homedir ){
849 	strncpy(conf_file, homedir, MAXPATHLEN );
850 	conf_file[MAXPATHLEN]='\0';
851 	strcat( conf_file, CFG_FILE1);
852 	parse(conf_file,0);
853     }
854     memset((char *)&devices[cur_devs],0,sizeof(struct device));
855 
856     envConfFile = getenv("MTOOLSRC");
857     if(envConfFile)
858 	parse(envConfFile,0);
859 
860     /* environmental variables */
861     get_env_conf();
862     if(mtools_skip_check)
863 	mtools_fat_compatibility=1;
864 }
865 
866 void mtoolstest(int argc, char **argv, int type  UNUSEDP) NORETURN;
mtoolstest(int argc,char ** argv,int type UNUSEDP)867 void mtoolstest(int argc, char **argv, int type  UNUSEDP)
868 {
869     /* testing purposes only */
870     struct device *dev;
871     char drive='\0';
872 
873     if(argc > 1 && argv[1][0] && argv[1][1] == ':') {
874 	drive = ch_canon_drv(argv[1][0]);
875     }
876 
877     for (dev=devices; dev->name; dev++) {
878 	if(drive && drive != dev->drive)
879 	    continue;
880 	printf("drive %c:\n", dev->drive);
881 	printf("\t#fn=%d mode=%d ",
882 	       dev->file_nr, dev->mode);
883 	if(dev->cfg_filename)
884 	    printf("defined in %s\n", dev->cfg_filename);
885 	else
886 	    printf("builtin\n");
887 	printf("\tfile=\"%s\" fat_bits=%d \n",
888 	       dev->name,dev->fat_bits);
889 	printf("\ttracks=%d heads=%d sectors=%d hidden=%d\n",
890 	       dev->tracks, dev->heads, dev->sectors, dev->hidden);
891 	printf("\toffset=0x%lx\n", (long) dev->offset);
892 	printf("\tpartition=%d\n", dev->partition);
893 
894 	if(dev->misc_flags)
895 	    printf("\t");
896 
897 	if(DO_SWAP(dev))
898 	    printf("swap ");
899 	if(IS_SCSI(dev))
900 	    printf("scsi ");
901 	if(IS_PRIVILEGED(dev))
902 	    printf("privileged");
903 	if(IS_MFORMAT_ONLY(dev))
904 	    printf("mformat_only ");
905 	if(SHOULD_USE_VOLD(dev))
906 	    printf("vold ");
907 #ifdef USE_XDF
908 	if(SHOULD_USE_XDF(dev))
909 	    printf("use_xdf ");
910 #endif
911 	if(dev->misc_flags)
912 	    printf("\n");
913 
914 	if(dev->mode)
915 	    printf("\t");
916 #ifdef O_SYNC
917 	if(dev->mode & O_SYNC)
918 	    printf("sync ");
919 #endif
920 #ifdef O_NDELAY
921 	if((dev->mode & O_NDELAY))
922 	    printf("nodelay ");
923 #endif
924 #ifdef O_EXCL
925 	if((dev->mode & O_EXCL))
926 	    printf("exclusive ");
927 #endif
928 	if(dev->mode)
929 	    printf("\n");
930 
931 	if(dev->precmd)
932 	    printf("\tprecmd=%s\n", dev->precmd);
933 
934 	printf("\n");
935     }
936 
937     printf("mtools_fat_compatibility=%d\n",mtools_fat_compatibility);
938     printf("mtools_skip_check=%d\n",mtools_skip_check);
939     printf("mtools_lower_case=%d\n",mtools_ignore_short_case);
940 
941     exit(0);
942 }
943 
944 /*
945  * Local Variables:
946  * c-basic-offset: 4
947  * End:
948  */
949