1 /* Copyright 1996-2005,2007-2009 Alain Knaff.
2 * This file is part of mtools.
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.
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.
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/>.
18 #include "sysincludes.h"
21 #include "mtoolsPaths.h"
23 /* global variables */
24 /* they are not really harmful here, because there is only one configuration
25 * file per invocations */
27 #define MAX_LINE_LEN 256
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
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) */
44 static int flag_mask; /* mask of currently set flags */
47 static 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 int nr_dev; /* number of devices that the current table can hold */
51 struct device *devices; /* the device table */
52 static int token_nr; /* number of tokens in line */
54 static char default_drive='\0'; /* default drive */
56 /* "environment" variables */
57 unsigned int mtools_skip_check=0;
58 unsigned int mtools_fat_compatibility=0;
59 unsigned int mtools_ignore_short_case=0;
60 unsigned int mtools_rate_0=0;
61 unsigned int mtools_rate_any=0;
62 unsigned int mtools_no_vfat=0;
63 unsigned int mtools_numeric_tail=1;
64 unsigned int mtools_dotted_dir=0;
65 unsigned int mtools_twenty_four_hour_clock=1;
66 unsigned int mtools_default_codepage=850;
67 const char *mtools_date_string="yyyy-mm-dd";
68 char *country_string=0;
70 typedef struct switches_l {
80 static switches_t global_switches[] = {
81 { "MTOOLS_LOWER_CASE", (caddr_t) & mtools_ignore_short_case, T_UINT },
82 { "MTOOLS_FAT_COMPATIBILITY", (caddr_t) & mtools_fat_compatibility, T_UINT },
83 { "MTOOLS_SKIP_CHECK", (caddr_t) & mtools_skip_check, T_UINT },
84 { "MTOOLS_NO_VFAT", (caddr_t) & mtools_no_vfat, T_UINT },
85 { "MTOOLS_RATE_0", (caddr_t) &mtools_rate_0, T_UINT },
86 { "MTOOLS_RATE_ANY", (caddr_t) &mtools_rate_any, T_UINT },
87 { "MTOOLS_NAME_NUMERIC_TAIL", (caddr_t) &mtools_numeric_tail, T_UINT },
88 { "MTOOLS_DOTTED_DIR", (caddr_t) &mtools_dotted_dir, T_UINT },
89 { "MTOOLS_TWENTY_FOUR_HOUR_CLOCK",
90 (caddr_t) &mtools_twenty_four_hour_clock, T_UINT },
91 { "MTOOLS_DATE_STRING",
92 (caddr_t) &mtools_date_string, T_STRING },
93 { "DEFAULT_CODEPAGE", (caddr_t) &mtools_default_codepage, T_UINT }
101 static flags_t openflags[] = {
106 { "nodelay", O_NDELAY },
109 { "exclusive", O_EXCL },
111 { "none", 0 } /* hack for those compilers that choke on commas
112 * after the last element of an array */
115 static flags_t misc_flags[] = {
117 { "use_xdf", USE_XDF_FLAG },
119 { "scsi", SCSI_FLAG },
120 { "nolock", NOLOCK_FLAG },
121 { "mformat_only", MFORMAT_ONLY_FLAG },
122 { "filter", FILTER_FLAG },
123 { "privileged", PRIV_FLAG },
124 { "vold", VOLD_FLAG },
125 { "remote", FLOPPYD_FLAG },
126 { "swap", SWAP_FLAG },
131 signed char fat_bits;
133 unsigned short heads;
134 unsigned short sectors;
135 } default_formats[] = {
136 { "hd514", 12, 80, 2, 15 },
137 { "high-density-5-1/4", 12, 80, 2, 15 },
138 { "1.2m", 12, 80, 2, 15 },
140 { "hd312", 12, 80, 2, 18 },
141 { "high-density-3-1/2", 12, 80, 2, 18 },
142 { "1.44m", 12, 80, 2, 18 },
144 { "dd312", 12, 80, 2, 9 },
145 { "double-density-3-1/2", 12, 80, 2, 9 },
146 { "720k", 12, 80, 2, 9 },
148 { "dd514", 12, 40, 2, 9 },
149 { "double-density-5-1/4", 12, 40, 2, 9 },
150 { "360k", 12, 40, 2, 9 },
152 { "320k", 12, 40, 2, 8 },
153 { "180k", 12, 40, 1, 9 },
154 { "160k", 12, 40, 1, 8 }
157 #define OFFS(x) ((caddr_t)&((struct device *)0)->x)
159 static switches_t dswitches[]= {
160 { "FILE", OFFS(name), T_STRING },
161 { "OFFSET", OFFS(offset), T_UINT },
162 { "PARTITION", OFFS(partition), T_UINT },
163 { "FAT", OFFS(fat_bits), T_INT },
164 { "FAT_BITS", OFFS(fat_bits), T_UINT },
165 { "MODE", OFFS(mode), T_UINT },
166 { "TRACKS", OFFS(tracks), T_UINT },
167 { "CYLINDERS", OFFS(tracks), T_UINT },
168 { "HEADS", OFFS(heads), T_UINT },
169 { "SECTORS", OFFS(sectors), T_UINT },
170 { "HIDDEN", OFFS(hidden), T_UINT },
171 { "PRECMD", OFFS(precmd), T_STRING },
172 { "BLOCKSIZE", OFFS(blocksize), T_UINT },
173 { "CODEPAGE", OFFS(codepage), T_UINT }
176 static void maintain_default_drive(char drive)
178 if(default_drive == ':')
179 return; /* we have an image */
180 if(default_drive == '\0' ||
181 default_drive > drive)
182 default_drive = drive;
185 char get_default_drive(void)
187 if(default_drive != '\0')
188 return default_drive;
193 static void syntax(const char *msg, int thisLine)
197 lastTokenLinenumber = linenumber;
199 drive = devices[cur_dev].drive;
200 fprintf(stderr,"Syntax error at line %d ", lastTokenLinenumber);
201 if(drive) fprintf(stderr, "for drive %c: ", drive);
202 if(token) fprintf(stderr, "column %ld ", (long)(token - buffer));
203 fprintf(stderr, "in file %s: %s\n", filename, msg);
207 static void get_env_conf(void)
212 for(i=0; i< sizeof(global_switches) / sizeof(*global_switches); i++) {
213 s = getenv(global_switches[i].name);
215 if(global_switches[i].type == T_INT)
216 * ((int *)global_switches[i].address) = (int) strtol(s,0,0);
217 if(global_switches[i].type == T_UINT)
218 * ((int *)global_switches[i].address) = (unsigned int) strtoul(s,0,0);
219 else if (global_switches[i].type == T_STRING)
220 * ((char **)global_switches[i].address) = s;
225 static int mtools_getline(void)
227 if(!fp || !fgets(buffer, MAX_LINE_LEN, fp))
232 buffer[MAX_LINE_LEN] = '\0';
233 if(strlen(buffer) == MAX_LINE_LEN)
234 syntax("line too long", 1);
238 static void skip_junk(int expect)
240 lastTokenLinenumber = linenumber;
241 while(!pos || !*pos || strchr(" #\n\t", *pos)) {
242 if(!pos || !*pos || *pos == '#') {
243 if(mtools_getline()) {
246 syntax("end of file unexpected", 1);
255 /* get the next token */
256 static char *get_next_token(void)
265 token_length = strcspn(token, " \t\n#:=");
270 static int match_token(const char *template)
272 return (strlen(template) == token_length &&
273 !strncasecmp(template, token, token_length));
276 static void expect_char(char c)
282 sprintf(buf, "expected %c", c);
288 static char *get_string(void)
294 syntax(" \" expected", 0);
296 end = strchr(str, '\"');
298 syntax("unterminated string constant", 1);
304 static unsigned int get_unumber(void)
311 n=(unsigned int) strtoul(pos, &pos, 0);
313 syntax("numeral expected", 0);
319 static unsigned int get_number(void)
326 n=(int) strtol(pos, &pos, 0);
328 syntax("numeral expected", 0);
334 /* purge all entries pertaining to a given drive from the table */
335 static void purge(char drive, int fn)
339 drive = toupper(drive);
340 for(j=0, i=0; i < cur_devs; i++) {
341 if(devices[i].drive != drive ||
342 devices[i].file_nr == fn)
343 devices[j++] = devices[i];
348 static void grow(void)
350 if(cur_devs >= nr_dev - 2) {
351 nr_dev = (cur_devs + 2) << 1;
352 if(!(devices=Grow(devices, nr_dev, struct device))){
360 static void init_drive(void)
362 memset((char *)&devices[cur_dev], 0, sizeof(struct device));
363 devices[cur_dev].ssize = 2;
366 /* prepends a device to the table */
367 static void prepend(void)
372 for(i=cur_devs; i>0; i--)
373 devices[i] = devices[i-1];
380 /* appends a device to the table */
381 static void append(void)
390 static void finish_drive_clause(void)
397 drive = devices[cur_dev].drive;
398 if(!devices[cur_dev].name)
399 syntax("missing filename", 0);
400 if(devices[cur_dev].tracks ||
401 devices[cur_dev].heads ||
402 devices[cur_dev].sectors) {
403 if(!devices[cur_dev].tracks ||
404 !devices[cur_dev].heads ||
405 !devices[cur_dev].sectors)
406 syntax("incomplete geometry: either indicate all of track/heads/sectors or none of them", 0);
407 if(!(devices[cur_dev].misc_flags &
408 (MFORMAT_ONLY_FLAG | FILTER_FLAG)))
409 syntax("if you supply a geometry, you also must supply one of the `mformat_only' or `filter' flags", 0);
411 devices[cur_dev].file_nr = file_nr;
412 devices[cur_dev].cfg_filename = filename;
413 if(! (flag_mask & PRIV_FLAG) && IS_SCSI(&devices[cur_dev]))
414 devices[cur_dev].misc_flags |= PRIV_FLAG;
415 if(!trusted && (devices[cur_dev].misc_flags & PRIV_FLAG)) {
417 "Warning: privileged flag ignored for drive %c: defined in file %s\n",
418 toupper(devices[cur_dev].drive), filename);
419 devices[cur_dev].misc_flags &= ~PRIV_FLAG;
425 static int set_var(struct switches_l *switches, int nr,
426 caddr_t base_address)
429 for(i=0; i < nr; i++) {
430 if(match_token(switches[i].name)) {
432 if(switches[i].type == T_UINT)
433 * ((int *)((long)switches[i].address+base_address)) =
435 if(switches[i].type == T_INT)
436 * ((int *)((long)switches[i].address+base_address)) =
438 else if (switches[i].type == T_STRING)
439 * ((char**)((long)switches[i].address+base_address))=
440 strdup(get_string());
447 static int set_openflags(struct device *dev)
451 for(i=0; i < sizeof(openflags) / sizeof(*openflags); i++) {
452 if(match_token(openflags[i].name)) {
453 dev->mode |= openflags[i].flag;
460 static int set_misc_flags(struct device *dev)
464 for(i=0; i < sizeof(misc_flags) / sizeof(*misc_flags); i++) {
465 if(match_token(misc_flags[i].name)) {
466 flag_mask |= misc_flags[i].flag;
468 if(pos && *pos == '=') {
470 switch(get_number()) {
476 syntax("expected 0 or 1", 0);
479 dev->misc_flags |= misc_flags[i].flag;
486 static int set_def_format(struct device *dev)
490 for(i=0; i < sizeof(default_formats)/sizeof(*default_formats); i++) {
491 if(match_token(default_formats[i].name)) {
495 dev->tracks = default_formats[i].tracks;
497 dev->heads = default_formats[i].heads;
499 dev->sectors = default_formats[i].sectors;
501 dev->fat_bits = default_formats[i].fat_bits;
508 static int parse_one(int privilege);
510 /* check for offset embedded in file name, in the form file@@offset[SKMG] */
511 static off_t get_offset(char *name) {
512 char s, *ofsp, *endp = NULL;
515 ofsp = strstr(devices[cur_dev].name, "@@");
517 return 0; /* no separator */
518 ofs = strtol(ofsp+2, &endp, 0);
520 return 0; /* invalid or missing offset */
522 if (s) { /* trailing char, see if it is a size specifier */
524 if (s == 's' || s == 'S') /* sector */
526 else if (s == 'k' || s == 'K') /* kb */
528 else if (s == 'm' || s == 'M') /* Mb */
530 else if (s == 'g' || s == 'G') /* Gb */
533 return 0; /* invalid character */
535 return 0; /* extra char, invalid */
537 *ofsp = '\0'; /* truncate file name */
541 void set_cmd_line_image(char *img, int flags) {
544 devices[cur_dev].drive = ':';
546 devices[cur_dev].name = name = strdup(img);
547 devices[cur_dev].fat_bits = 0;
548 devices[cur_dev].tracks = 0;
549 devices[cur_dev].heads = 0;
550 devices[cur_dev].sectors = 0;
551 devices[cur_dev].offset = get_offset(name);
552 if (strchr(devices[cur_dev].name, '|')) {
553 char *pipechar = strchr(devices[cur_dev].name, '|');
555 strncpy(buffer, pipechar+1, MAX_LINE_LEN);
556 buffer[MAX_LINE_LEN] = '\0';
558 filename = "{command line}";
560 lastTokenLinenumber = 0;
563 while (parse_one(0));
567 static void parse_old_device_line(char drive)
569 char name[MAXPATHLEN];
573 /* finish any old drive */
574 finish_drive_clause();
576 /* purge out data of old configuration files */
577 purge(drive, file_nr);
581 items = sscanf(token,"%c %s %i %i %i %i %li",
582 &devices[cur_dev].drive,name,&devices[cur_dev].fat_bits,
583 &devices[cur_dev].tracks,&devices[cur_dev].heads,
584 &devices[cur_dev].sectors, &offset);
585 devices[cur_dev].offset = (off_t) offset;
588 devices[cur_dev].fat_bits = 0;
591 devices[cur_dev].sectors = 0;
592 devices[cur_dev].heads = 0;
593 devices[cur_dev].tracks = 0;
596 devices[cur_dev].offset = 0;
604 syntax("bad number of parameters", 1);
607 if(!devices[cur_dev].tracks){
608 devices[cur_dev].sectors = 0;
609 devices[cur_dev].heads = 0;
612 devices[cur_dev].drive = toupper(devices[cur_dev].drive);
613 maintain_default_drive(devices[cur_dev].drive);
614 if (!(devices[cur_dev].name = strdup(name))) {
618 finish_drive_clause();
622 static int parse_one(int privilege)
630 if((match_token("drive") && ((action = 1)))||
631 (match_token("drive+") && ((action = 2))) ||
632 (match_token("+drive") && ((action = 3))) ||
633 (match_token("clear_drive") && ((action = 4))) ) {
634 /* finish off the previous drive */
635 finish_drive_clause();
638 if(token_length != 1)
639 syntax("drive letter expected", 0);
641 if(action==1 || action==4)
642 /* replace existing drive */
643 purge(token[0], file_nr);
650 memset((char*)(devices+cur_dev), 0, sizeof(*devices));
653 devices[cur_dev].drive = toupper(token[0]);
654 maintain_default_drive(devices[cur_dev].drive);
658 if(token_nr == 1 && token_length == 1) {
659 parse_old_device_line(token[0]);
665 sizeof(dswitches)/sizeof(*dswitches),
666 (caddr_t)&devices[cur_dev]) &&
667 set_openflags(&devices[cur_dev]) &&
668 set_misc_flags(&devices[cur_dev]) &&
669 set_def_format(&devices[cur_dev]))) &&
670 set_var(global_switches,
671 sizeof(global_switches)/sizeof(*global_switches), 0))
672 syntax("unrecognized keyword", 1);
676 static int parse(const char *name, int privilege)
679 fprintf(stderr, "File descriptor already set (%p)!\n", fp);
682 fp = fopen(name, "r");
686 filename = name; /* no strdup needed: although lifetime of variable
687 exceeds this function (due to dev->cfg_filename),
688 we know that the name is always either
690 2. a statically allocate buffer
691 3. an environment variable that stays unchanged
694 lastTokenLinenumber = 0;
697 cur_dev = -1; /* no current device */
699 while(parse_one(privilege));
700 finish_drive_clause();
707 void read_config(void)
711 static char conf_file[MAXPATHLEN+sizeof(CFG_FILE1)];
714 /* copy compiled-in devices */
716 cur_devs = nr_const_devices;
717 nr_dev = nr_const_devices + 2;
718 devices = NewArray(nr_dev, struct device);
724 memcpy(devices, const_devices,
725 nr_const_devices*sizeof(struct device));
727 (void) ((parse(CONF_FILE,1) |
728 parse(LOCAL_CONF_FILE,1) |
729 parse(SYS_CONF_FILE,1)) ||
730 (parse(OLD_CONF_FILE,1) |
731 parse(OLD_LOCAL_CONF_FILE,1)));
732 /* the old-name configuration files only get executed if none of the
733 * new-name config files were used */
735 homedir = get_homedir();
737 strncpy(conf_file, homedir, MAXPATHLEN );
738 conf_file[MAXPATHLEN]='\0';
739 strcat( conf_file, CFG_FILE1);
742 memset((char *)&devices[cur_devs],0,sizeof(struct device));
744 envConfFile = getenv("MTOOLSRC");
746 parse(envConfFile,0);
748 /* environmental variables */
750 if(mtools_skip_check)
751 mtools_fat_compatibility=1;
754 void mtoolstest(int argc, char **argv, int type)
756 /* testing purposes only */
760 if(argc > 1 && argv[1][0] && argv[1][1] == ':') {
761 drive = toupper(argv[1][0]);
764 for (dev=devices; dev->name; dev++) {
765 if(drive && drive != dev->drive)
767 printf("drive %c:\n", dev->drive);
768 printf("\t#fn=%d mode=%d ",
769 dev->file_nr, dev->mode);
770 if(dev->cfg_filename)
771 printf("defined in %s\n", dev->cfg_filename);
774 printf("\tfile=\"%s\" fat_bits=%d \n",
775 dev->name,dev->fat_bits);
776 printf("\ttracks=%d heads=%d sectors=%d hidden=%d\n",
777 dev->tracks, dev->heads, dev->sectors, dev->hidden);
778 printf("\toffset=0x%lx\n", (long) dev->offset);
779 printf("\tpartition=%d\n", dev->partition);
788 if(IS_PRIVILEGED(dev))
789 printf("privileged");
790 if(IS_MFORMAT_ONLY(dev))
791 printf("mformat_only ");
792 if(SHOULD_USE_VOLD(dev))
795 if(SHOULD_USE_XDF(dev))
804 if(dev->mode & O_SYNC)
808 if((dev->mode & O_NDELAY))
812 if((dev->mode & O_EXCL))
813 printf("exclusive ");
819 printf("\tprecmd=%s\n", dev->precmd);
824 printf("mtools_fat_compatibility=%d\n",mtools_fat_compatibility);
825 printf("mtools_skip_check=%d\n",mtools_skip_check);
826 printf("mtools_lower_case=%d\n",mtools_ignore_short_case);