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