blob: 550bfbf9ff789bcdc3f1f57cae5b67d8442f51e1 [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* 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 */
30static char buffer[MAX_LINE_LEN+1]; /* buffer for the whole line */
31static char *pos; /* position in line */
32static char *token; /* last scanned token */
33static size_t token_length; /* length of the token */
34static FILE *fp; /* file pointer for configuration file */
35static int linenumber; /* current line number. Only used for printing
36 * error messages */
37static int lastTokenLinenumber; /* line numnber for last token */
38static const char *filename=NULL; /* current file name. Used for printing
39 * error messages, and for storing in
40 * the device definition (mtoolstest) */
41static int file_nr=0;
42
43
44static unsigned int flag_mask; /* mask of currently set flags */
45
46/* devices */
47static unsigned int cur_devs; /* current number of defined devices */
48static int cur_dev; /* device being filled in. If negative, none */
49static int trusted=0; /* is the currently parsed device entry trusted? */
50static unsigned int nr_dev; /* number of devices that the current table can
51 hold */
52struct device *devices; /* the device table */
53static int token_nr; /* number of tokens in line */
54
55static char default_drive='\0'; /* default drive */
56
57/* "environment" variables */
58unsigned int mtools_skip_check=0;
59unsigned int mtools_fat_compatibility=0;
60unsigned int mtools_ignore_short_case=0;
61uint8_t mtools_rate_0=0;
62uint8_t mtools_rate_any=0;
63unsigned int mtools_no_vfat=0;
64unsigned int mtools_numeric_tail=1;
65unsigned int mtools_dotted_dir=0;
66unsigned int mtools_twenty_four_hour_clock=1;
67unsigned int mtools_lock_timeout=30;
68unsigned int mtools_default_codepage=850;
69const char *mtools_date_string="yyyy-mm-dd";
70char *country_string=0;
71
72typedef 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
84static 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
101typedef struct {
102 const char *name;
103 unsigned int flag;
104} flags_t;
105
106static 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
120static 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
134static 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
164static 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)
182static locale_t C=NULL;
183
184static 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
191static int canon_drv(int drive) {
192 int ret;
193 init_canon();
194 ret = toupper_l(drive, C);
195 return ret;
196}
197#else
198static int canon_drv(int drive) {
199 return toupper(drive);
200}
201#endif
202
203#ifdef HAVE_STRNCASECMP_L
204static 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
209static int cmp_tok(const char *a, const char *b, int len) {
210 return strncasecmp(a, b, len);
211}
212#endif
213
214
215static char ch_canon_drv(char drive) {
216 return (char) canon_drv( (unsigned char) drive);
217}
218
219static 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
228char get_default_drive(void)
229{
230 if(default_drive != '\0')
231 return default_drive;
232 else
233 return 'A';
234}
235
236static void syntax(const char *msg, int thisLine) NORETURN;
237static 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
254static 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
290static 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
303static 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 */
321static 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
335static int match_token(const char *template)
336{
337 return (strlen(template) == token_length &&
338 !cmp_tok(template, token, token_length));
339}
340
341static 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
353static 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
369static 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
388static 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 */
406static 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
419static 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
431static 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 */
438static 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 */
452static void append(void)
453{
454 grow();
455 cur_dev = cur_devs;
456 cur_devs++;
457 init_drive();
458}
459
460
461static 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
494static 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
522static 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
535static 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
560static 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
582static void parse_all(int privilege);
583
584void 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
620void 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
632static 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
645static 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
705static 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
759static void parse_all(int privilege) {
760 errno=0;
761 while (parse_one(privilege));
762}
763
764
765static 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
796void 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
843void mtoolstest(int argc, char **argv, int type UNUSEDP) NORETURN;
844void 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 */