You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
926 lines
22 KiB
926 lines
22 KiB
/* Copyright 1996-2005,2007-2009,2011 Alain Knaff.
|
|
* This file is part of mtools.
|
|
*
|
|
* Mtools is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Mtools is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
#include "sysincludes.h"
|
|
#include "mtools.h"
|
|
#include "codepage.h"
|
|
#include "mtoolsPaths.h"
|
|
|
|
/* global variables */
|
|
/* they are not really harmful here, because there is only one configuration
|
|
* file per invocations */
|
|
|
|
#define MAX_LINE_LEN 256
|
|
|
|
/* scanner */
|
|
static char buffer[MAX_LINE_LEN+1]; /* buffer for the whole line */
|
|
static char *pos; /* position in line */
|
|
static char *token; /* last scanned token */
|
|
static size_t token_length; /* length of the token */
|
|
static FILE *fp; /* file pointer for configuration file */
|
|
static int linenumber; /* current line number. Only used for printing
|
|
* error messages */
|
|
static int lastTokenLinenumber; /* line numnber for last token */
|
|
static const char *filename=NULL; /* current file name. Used for printing
|
|
* error messages, and for storing in
|
|
* the device definition (mtoolstest) */
|
|
static int file_nr=0;
|
|
|
|
|
|
static unsigned int flag_mask; /* mask of currently set flags */
|
|
|
|
/* devices */
|
|
static unsigned int cur_devs; /* current number of defined devices */
|
|
static int cur_dev; /* device being filled in. If negative, none */
|
|
static int trusted=0; /* is the currently parsed device entry trusted? */
|
|
static unsigned int nr_dev; /* number of devices that the current table can
|
|
hold */
|
|
struct device *devices; /* the device table */
|
|
static int token_nr; /* number of tokens in line */
|
|
|
|
static char default_drive='\0'; /* default drive */
|
|
|
|
/* "environment" variables */
|
|
unsigned int mtools_skip_check=0;
|
|
unsigned int mtools_fat_compatibility=0;
|
|
unsigned int mtools_ignore_short_case=0;
|
|
uint8_t mtools_rate_0=0;
|
|
uint8_t mtools_rate_any=0;
|
|
unsigned int mtools_no_vfat=0;
|
|
unsigned int mtools_numeric_tail=1;
|
|
unsigned int mtools_dotted_dir=0;
|
|
unsigned int mtools_twenty_four_hour_clock=1;
|
|
unsigned int mtools_lock_timeout=30;
|
|
unsigned int mtools_default_codepage=850;
|
|
const char *mtools_date_string="yyyy-mm-dd";
|
|
char *country_string=0;
|
|
|
|
typedef struct switches_l {
|
|
const char *name;
|
|
caddr_t address;
|
|
enum {
|
|
T_INT,
|
|
T_STRING,
|
|
T_UINT,
|
|
T_UINT8,
|
|
T_UINT16
|
|
} type;
|
|
} switches_t;
|
|
|
|
static switches_t global_switches[] = {
|
|
{ "MTOOLS_LOWER_CASE", (caddr_t) & mtools_ignore_short_case, T_UINT },
|
|
{ "MTOOLS_FAT_COMPATIBILITY", (caddr_t) & mtools_fat_compatibility, T_UINT },
|
|
{ "MTOOLS_SKIP_CHECK", (caddr_t) & mtools_skip_check, T_UINT },
|
|
{ "MTOOLS_NO_VFAT", (caddr_t) & mtools_no_vfat, T_UINT },
|
|
{ "MTOOLS_RATE_0", (caddr_t) &mtools_rate_0, T_UINT8 },
|
|
{ "MTOOLS_RATE_ANY", (caddr_t) &mtools_rate_any, T_UINT8 },
|
|
{ "MTOOLS_NAME_NUMERIC_TAIL", (caddr_t) &mtools_numeric_tail, T_UINT },
|
|
{ "MTOOLS_DOTTED_DIR", (caddr_t) &mtools_dotted_dir, T_UINT },
|
|
{ "MTOOLS_TWENTY_FOUR_HOUR_CLOCK",
|
|
(caddr_t) &mtools_twenty_four_hour_clock, T_UINT },
|
|
{ "MTOOLS_DATE_STRING",
|
|
(caddr_t) &mtools_date_string, T_STRING },
|
|
{ "MTOOLS_LOCK_TIMEOUT", (caddr_t) &mtools_lock_timeout, T_UINT },
|
|
{ "DEFAULT_CODEPAGE", (caddr_t) &mtools_default_codepage, T_UINT }
|
|
};
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
unsigned int flag;
|
|
} flags_t;
|
|
|
|
static flags_t openflags[] = {
|
|
#ifdef O_SYNC
|
|
{ "sync", O_SYNC },
|
|
#endif
|
|
#ifdef O_NDELAY
|
|
{ "nodelay", O_NDELAY },
|
|
#endif
|
|
#ifdef O_EXCL
|
|
{ "exclusive", O_EXCL },
|
|
#endif
|
|
{ "none", 0 } /* hack for those compilers that choke on commas
|
|
* after the last element of an array */
|
|
};
|
|
|
|
static flags_t misc_flags[] = {
|
|
#ifdef USE_XDF
|
|
{ "use_xdf", USE_XDF_FLAG },
|
|
#endif
|
|
{ "scsi", SCSI_FLAG },
|
|
{ "nolock", NOLOCK_FLAG },
|
|
{ "mformat_only", MFORMAT_ONLY_FLAG },
|
|
{ "filter", FILTER_FLAG },
|
|
{ "privileged", PRIV_FLAG },
|
|
{ "vold", VOLD_FLAG },
|
|
{ "remote", FLOPPYD_FLAG },
|
|
{ "swap", SWAP_FLAG },
|
|
};
|
|
|
|
static struct {
|
|
const char *name;
|
|
signed char fat_bits;
|
|
unsigned int tracks;
|
|
unsigned short heads;
|
|
unsigned short sectors;
|
|
} default_formats[] = {
|
|
{ "hd514", 12, 80, 2, 15 },
|
|
{ "high-density-5-1/4", 12, 80, 2, 15 },
|
|
{ "1.2m", 12, 80, 2, 15 },
|
|
|
|
{ "hd312", 12, 80, 2, 18 },
|
|
{ "high-density-3-1/2", 12, 80, 2, 18 },
|
|
{ "1.44m", 12, 80, 2, 18 },
|
|
|
|
{ "dd312", 12, 80, 2, 9 },
|
|
{ "double-density-3-1/2", 12, 80, 2, 9 },
|
|
{ "720k", 12, 80, 2, 9 },
|
|
|
|
{ "dd514", 12, 40, 2, 9 },
|
|
{ "double-density-5-1/4", 12, 40, 2, 9 },
|
|
{ "360k", 12, 40, 2, 9 },
|
|
|
|
{ "320k", 12, 40, 2, 8 },
|
|
{ "180k", 12, 40, 1, 9 },
|
|
{ "160k", 12, 40, 1, 8 }
|
|
};
|
|
|
|
#define OFFS(x) ((caddr_t)&((struct device *)0)->x)
|
|
|
|
static switches_t dswitches[]= {
|
|
{ "FILE", OFFS(name), T_STRING },
|
|
{ "OFFSET", OFFS(offset), T_UINT },
|
|
{ "PARTITION", OFFS(partition), T_UINT },
|
|
{ "FAT", OFFS(fat_bits), T_INT },
|
|
{ "FAT_BITS", OFFS(fat_bits), T_UINT },
|
|
{ "MODE", OFFS(mode), T_UINT },
|
|
{ "TRACKS", OFFS(tracks), T_UINT },
|
|
{ "CYLINDERS", OFFS(tracks), T_UINT },
|
|
{ "HEADS", OFFS(heads), T_UINT16 },
|
|
{ "SECTORS", OFFS(sectors), T_UINT16 },
|
|
{ "HIDDEN", OFFS(hidden), T_UINT },
|
|
{ "PRECMD", OFFS(precmd), T_STRING },
|
|
{ "BLOCKSIZE", OFFS(blocksize), T_UINT },
|
|
{ "CODEPAGE", OFFS(codepage), T_UINT }
|
|
};
|
|
|
|
#if (defined HAVE_TOUPPER_L || defined HAVE_STRNCASECMP_L)
|
|
static locale_t C=NULL;
|
|
|
|
static void init_canon(void) {
|
|
if(C == NULL)
|
|
C = newlocale(LC_CTYPE_MASK, "C", NULL);
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_TOUPPER_L
|
|
static int canon_drv(int drive) {
|
|
int ret;
|
|
init_canon();
|
|
ret = toupper_l(drive, C);
|
|
return ret;
|
|
}
|
|
#else
|
|
static int canon_drv(int drive) {
|
|
return toupper(drive);
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_STRNCASECMP_L
|
|
static int cmp_tok(const char *a, const char *b, int len) {
|
|
init_canon();
|
|
return strncasecmp_l(a, b, len, C);
|
|
}
|
|
#else
|
|
static int cmp_tok(const char *a, const char *b, int len) {
|
|
return strncasecmp(a, b, len);
|
|
}
|
|
#endif
|
|
|
|
|
|
static char ch_canon_drv(char drive) {
|
|
return (char) canon_drv( (unsigned char) drive);
|
|
}
|
|
|
|
static void maintain_default_drive(char drive)
|
|
{
|
|
if(default_drive == ':')
|
|
return; /* we have an image */
|
|
if(default_drive == '\0' ||
|
|
default_drive > drive)
|
|
default_drive = drive;
|
|
}
|
|
|
|
char get_default_drive(void)
|
|
{
|
|
if(default_drive != '\0')
|
|
return default_drive;
|
|
else
|
|
return 'A';
|
|
}
|
|
|
|
static void syntax(const char *msg, int thisLine) NORETURN;
|
|
static void syntax(const char *msg, int thisLine)
|
|
{
|
|
char drive='\0';
|
|
if(thisLine)
|
|
lastTokenLinenumber = linenumber;
|
|
if(cur_dev >= 0)
|
|
drive = devices[cur_dev].drive;
|
|
fprintf(stderr,"Syntax error at line %d ", lastTokenLinenumber);
|
|
if(drive) fprintf(stderr, "for drive %c: ", drive);
|
|
if(token) fprintf(stderr, "column %ld ", (long)(token - buffer));
|
|
fprintf(stderr, "in file %s: %s", filename, msg);
|
|
if(errno != 0)
|
|
fprintf(stderr, " (%s)", strerror(errno));
|
|
fprintf(stderr, "\n");
|
|
exit(1);
|
|
}
|
|
|
|
static void get_env_conf(void)
|
|
{
|
|
char *s;
|
|
unsigned int i;
|
|
|
|
for(i=0; i< sizeof(global_switches) / sizeof(*global_switches); i++) {
|
|
s = getenv(global_switches[i].name);
|
|
if(s) {
|
|
errno = 0;
|
|
switch(global_switches[i].type) {
|
|
case T_INT:
|
|
* ((int *)global_switches[i].address) = strtoi(s,0,0);
|
|
break;
|
|
case T_UINT:
|
|
* ((unsigned int *)global_switches[i].address) = strtoui(s,0,0);
|
|
break;
|
|
case T_UINT8:
|
|
* ((uint8_t *)global_switches[i].address) = strtou8(s,0,0);
|
|
break;
|
|
case T_UINT16:
|
|
* ((uint16_t *)global_switches[i].address) = strtou16(s,0,0);
|
|
break;
|
|
case T_STRING:
|
|
* ((char **)global_switches[i].address) = s;
|
|
break;
|
|
}
|
|
if(errno != 0) {
|
|
fprintf(stderr, "Bad number %s for %s (%s)\n", s,
|
|
global_switches[i].name,
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int mtools_getline(void)
|
|
{
|
|
if(!fp || !fgets(buffer, MAX_LINE_LEN+1, fp))
|
|
return -1;
|
|
linenumber++;
|
|
pos = buffer;
|
|
token_nr = 0;
|
|
buffer[MAX_LINE_LEN] = '\0';
|
|
if(strlen(buffer) == MAX_LINE_LEN)
|
|
syntax("line too long", 1);
|
|
return 0;
|
|
}
|
|
|
|
static void skip_junk(int expect)
|
|
{
|
|
lastTokenLinenumber = linenumber;
|
|
while(!pos || !*pos || strchr(" #\n\t", *pos)) {
|
|
if(!pos || !*pos || *pos == '#') {
|
|
if(mtools_getline()) {
|
|
pos = 0;
|
|
if(expect)
|
|
syntax("end of file unexpected", 1);
|
|
return;
|
|
}
|
|
} else
|
|
pos++;
|
|
}
|
|
token_nr++;
|
|
}
|
|
|
|
/* get the next token */
|
|
static char *get_next_token(void)
|
|
{
|
|
skip_junk(0);
|
|
if(!pos) {
|
|
token_length = 0;
|
|
token = 0;
|
|
return 0;
|
|
}
|
|
token = pos;
|
|
token_length = strcspn(token, " \t\n#:=");
|
|
pos += token_length;
|
|
return token;
|
|
}
|
|
|
|
static int match_token(const char *template)
|
|
{
|
|
return (strlen(template) == token_length &&
|
|
!cmp_tok(template, token, token_length));
|
|
}
|
|
|
|
static void expect_char(char c)
|
|
{
|
|
char buf[11];
|
|
|
|
skip_junk(1);
|
|
if(*pos != c) {
|
|
sprintf(buf, "expected %c", c);
|
|
syntax(buf, 1);
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
static char *get_string(void)
|
|
{
|
|
char *end, *str;
|
|
|
|
skip_junk(1);
|
|
if(*pos != '"')
|
|
syntax(" \" expected", 0);
|
|
str = pos+1;
|
|
end = strchr(str, '\"');
|
|
if(!end)
|
|
syntax("unterminated string constant", 1);
|
|
*end = '\0';
|
|
pos = end+1;
|
|
return str;
|
|
}
|
|
|
|
static unsigned long get_unumber(unsigned long max)
|
|
{
|
|
char *last;
|
|
unsigned long n;
|
|
|
|
skip_junk(1);
|
|
last = pos;
|
|
n=strtoul(pos, &pos, 0);
|
|
if(errno)
|
|
syntax("bad number", 0);
|
|
if(last == pos)
|
|
syntax("numeral expected", 0);
|
|
if(n > max)
|
|
syntax("number too big", 0);
|
|
pos++;
|
|
token_nr++;
|
|
return n;
|
|
}
|
|
|
|
static int get_number(void)
|
|
{
|
|
char *last;
|
|
int n;
|
|
|
|
skip_junk(1);
|
|
last = pos;
|
|
n=(int) strtol(pos, &pos, 0);
|
|
if(errno)
|
|
syntax("bad number", 0);
|
|
if(last == pos)
|
|
syntax("numeral expected", 0);
|
|
pos++;
|
|
token_nr++;
|
|
return n;
|
|
}
|
|
|
|
/* purge all entries pertaining to a given drive from the table */
|
|
static void purge(char drive, int fn)
|
|
{
|
|
unsigned int i, j;
|
|
|
|
drive = ch_canon_drv(drive);
|
|
for(j=0, i=0; i < cur_devs; i++) {
|
|
if(devices[i].drive != drive ||
|
|
devices[i].file_nr == fn)
|
|
devices[j++] = devices[i];
|
|
}
|
|
cur_devs = j;
|
|
}
|
|
|
|
static void grow(void)
|
|
{
|
|
if(cur_devs >= nr_dev - 2) {
|
|
nr_dev = (cur_devs + 2) << 1;
|
|
if(!(devices=Grow(devices, nr_dev, struct device))){
|
|
printOom();
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void init_drive(void)
|
|
{
|
|
memset((char *)&devices[cur_dev], 0, sizeof(struct device));
|
|
devices[cur_dev].ssize = 2;
|
|
}
|
|
|
|
/* prepends a device to the table */
|
|
static void prepend(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
grow();
|
|
for(i=cur_devs; i>0; i--)
|
|
devices[i] = devices[i-1];
|
|
cur_dev = 0;
|
|
cur_devs++;
|
|
init_drive();
|
|
}
|
|
|
|
|
|
/* appends a device to the table */
|
|
static void append(void)
|
|
{
|
|
grow();
|
|
cur_dev = cur_devs;
|
|
cur_devs++;
|
|
init_drive();
|
|
}
|
|
|
|
|
|
static void finish_drive_clause(void)
|
|
{
|
|
if(cur_dev == -1) {
|
|
trusted = 0;
|
|
return;
|
|
}
|
|
if(!devices[cur_dev].name)
|
|
syntax("missing filename", 0);
|
|
if(devices[cur_dev].tracks ||
|
|
devices[cur_dev].heads ||
|
|
devices[cur_dev].sectors) {
|
|
if(!devices[cur_dev].tracks ||
|
|
!devices[cur_dev].heads ||
|
|
!devices[cur_dev].sectors)
|
|
syntax("incomplete geometry: either indicate all of track/heads/sectors or none of them", 0);
|
|
if(!(devices[cur_dev].misc_flags &
|
|
(MFORMAT_ONLY_FLAG | FILTER_FLAG)))
|
|
syntax("if you supply a geometry, you also must supply one of the `mformat_only' or `filter' flags", 0);
|
|
}
|
|
devices[cur_dev].file_nr = file_nr;
|
|
devices[cur_dev].cfg_filename = filename;
|
|
if(! (flag_mask & PRIV_FLAG) && IS_SCSI(&devices[cur_dev]))
|
|
devices[cur_dev].misc_flags |= PRIV_FLAG;
|
|
if(!trusted && (devices[cur_dev].misc_flags & PRIV_FLAG)) {
|
|
fprintf(stderr,
|
|
"Warning: privileged flag ignored for drive %c: defined in file %s\n",
|
|
canon_drv(devices[cur_dev].drive), filename);
|
|
devices[cur_dev].misc_flags &= ~PRIV_FLAG;
|
|
}
|
|
trusted = 0;
|
|
cur_dev = -1;
|
|
}
|
|
|
|
static int set_var(struct switches_l *switches, int nr,
|
|
caddr_t base_address)
|
|
{
|
|
int i;
|
|
for(i=0; i < nr; i++) {
|
|
if(match_token(switches[i].name)) {
|
|
expect_char('=');
|
|
if(switches[i].type == T_UINT)
|
|
* ((unsigned int *)((long)switches[i].address+base_address)) =
|
|
(unsigned int) get_unumber(UINT_MAX);
|
|
else if(switches[i].type == T_UINT8)
|
|
* ((uint8_t *)((long)switches[i].address+base_address)) =
|
|
(uint8_t) get_unumber(UINT8_MAX);
|
|
else if(switches[i].type == T_UINT16)
|
|
* ((uint16_t *)((long)switches[i].address+base_address)) =
|
|
(uint16_t) get_unumber(UINT16_MAX);
|
|
else if(switches[i].type == T_INT)
|
|
* ((int *)((long)switches[i].address+base_address)) =
|
|
get_number();
|
|
else if (switches[i].type == T_STRING)
|
|
* ((char**)((long)switches[i].address+base_address))=
|
|
strdup(get_string());
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int set_openflags(struct device *dev)
|
|
{
|
|
unsigned int i;
|
|
|
|
for(i=0; i < sizeof(openflags) / sizeof(*openflags); i++) {
|
|
if(match_token(openflags[i].name)) {
|
|
dev->mode |= openflags[i].flag;
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int set_misc_flags(struct device *dev)
|
|
{
|
|
unsigned int i;
|
|
for(i=0; i < sizeof(misc_flags) / sizeof(*misc_flags); i++) {
|
|
if(match_token(misc_flags[i].name)) {
|
|
flag_mask |= misc_flags[i].flag;
|
|
skip_junk(0);
|
|
if(pos && *pos == '=') {
|
|
pos++;
|
|
switch(get_number()) {
|
|
case 0:
|
|
return 0;
|
|
case 1:
|
|
break;
|
|
default:
|
|
syntax("expected 0 or 1", 0);
|
|
}
|
|
}
|
|
dev->misc_flags |= misc_flags[i].flag;
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int set_def_format(struct device *dev)
|
|
{
|
|
unsigned int i;
|
|
|
|
for(i=0; i < sizeof(default_formats)/sizeof(*default_formats); i++) {
|
|
if(match_token(default_formats[i].name)) {
|
|
if(!dev->ssize)
|
|
dev->ssize = 2;
|
|
if(!dev->tracks)
|
|
dev->tracks = default_formats[i].tracks;
|
|
if(!dev->heads)
|
|
dev->heads = default_formats[i].heads;
|
|
if(!dev->sectors)
|
|
dev->sectors = default_formats[i].sectors;
|
|
if(!dev->fat_bits)
|
|
dev->fat_bits = default_formats[i].fat_bits;
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void parse_all(int privilege);
|
|
|
|
void set_cmd_line_image(char *img) {
|
|
char *ofsp;
|
|
|
|
prepend();
|
|
devices[cur_dev].drive = ':';
|
|
default_drive = ':';
|
|
|
|
ofsp = strstr(img, "@@");
|
|
if (ofsp == NULL) {
|
|
/* no separator => no offset */
|
|
devices[cur_dev].name = strdup(img);
|
|
devices[cur_dev].offset = 0;
|
|
} else {
|
|
devices[cur_dev].name = strndup(img, ofsp - img);
|
|
devices[cur_dev].offset = str_to_offset(ofsp+2);
|
|
}
|
|
|
|
devices[cur_dev].fat_bits = 0;
|
|
devices[cur_dev].tracks = 0;
|
|
devices[cur_dev].heads = 0;
|
|
devices[cur_dev].sectors = 0;
|
|
if (strchr(devices[cur_dev].name, '|')) {
|
|
char *pipechar = strchr(devices[cur_dev].name, '|');
|
|
*pipechar = 0;
|
|
strncpy(buffer, pipechar+1, MAX_LINE_LEN);
|
|
buffer[MAX_LINE_LEN] = '\0';
|
|
fp = NULL;
|
|
filename = "{command line}";
|
|
linenumber = 0;
|
|
lastTokenLinenumber = 0;
|
|
pos = buffer;
|
|
token = 0;
|
|
parse_all(0);
|
|
}
|
|
}
|
|
|
|
void check_number_parse_errno(char c, const char *oarg, char *endptr) {
|
|
if(endptr && *endptr) {
|
|
fprintf(stderr, "Bad number %s\n", oarg);
|
|
exit(1);
|
|
}
|
|
if(errno) {
|
|
fprintf(stderr, "Bad number %s for -%c (%s)\n", oarg,
|
|
c, strerror(errno));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static uint16_t tou16(int in, const char *comment) {
|
|
if(in > UINT16_MAX) {
|
|
fprintf(stderr, "Number of %s %d too big\n", comment, in);
|
|
exit(1);
|
|
}
|
|
if(in < 0) {
|
|
fprintf(stderr, "Number of %s %d negative\n", comment, in);
|
|
exit(1);
|
|
}
|
|
return (uint16_t) in;
|
|
|
|
}
|
|
|
|
static void parse_old_device_line(char drive)
|
|
{
|
|
char name[MAXPATHLEN];
|
|
int items;
|
|
long offset;
|
|
|
|
int heads, sectors;
|
|
|
|
/* finish any old drive */
|
|
finish_drive_clause();
|
|
|
|
/* purge out data of old configuration files */
|
|
purge(drive, file_nr);
|
|
|
|
/* reserve slot */
|
|
append();
|
|
items = sscanf(token,"%c %s %i %i %i %i %li",
|
|
&devices[cur_dev].drive,name,&devices[cur_dev].fat_bits,
|
|
&devices[cur_dev].tracks,&heads,
|
|
§ors, &offset);
|
|
devices[cur_dev].heads = tou16(heads, "heads");
|
|
devices[cur_dev].sectors = tou16(sectors, "sectors");
|
|
|
|
devices[cur_dev].offset = (off_t) offset;
|
|
switch(items){
|
|
case 2:
|
|
devices[cur_dev].fat_bits = 0;
|
|
/* fall thru */
|
|
case 3:
|
|
devices[cur_dev].sectors = 0;
|
|
devices[cur_dev].heads = 0;
|
|
devices[cur_dev].tracks = 0;
|
|
/* fall thru */
|
|
case 6:
|
|
devices[cur_dev].offset = 0;
|
|
/* fall thru */
|
|
default:
|
|
break;
|
|
case 0:
|
|
case 1:
|
|
case 4:
|
|
case 5:
|
|
syntax("bad number of parameters", 1);
|
|
}
|
|
if(!devices[cur_dev].tracks){
|
|
devices[cur_dev].sectors = 0;
|
|
devices[cur_dev].heads = 0;
|
|
}
|
|
|
|
devices[cur_dev].drive = ch_canon_drv(devices[cur_dev].drive);
|
|
maintain_default_drive(devices[cur_dev].drive);
|
|
if (!(devices[cur_dev].name = strdup(name))) {
|
|
printOom();
|
|
exit(1);
|
|
}
|
|
devices[cur_dev].misc_flags |= MFORMAT_ONLY_FLAG;
|
|
finish_drive_clause();
|
|
pos=0;
|
|
}
|
|
|
|
static int parse_one(int privilege)
|
|
{
|
|
int action=0;
|
|
|
|
get_next_token();
|
|
if(!token)
|
|
return 0;
|
|
|
|
if((match_token("drive") && ((action = 1)))||
|
|
(match_token("drive+") && ((action = 2))) ||
|
|
(match_token("+drive") && ((action = 3))) ||
|
|
(match_token("clear_drive") && ((action = 4))) ) {
|
|
/* finish off the previous drive */
|
|
finish_drive_clause();
|
|
|
|
get_next_token();
|
|
if(token_length != 1)
|
|
syntax("drive letter expected", 0);
|
|
|
|
if(action==1 || action==4)
|
|
/* replace existing drive */
|
|
purge(token[0], file_nr);
|
|
if(action==4)
|
|
return 1;
|
|
if(action==3)
|
|
prepend();
|
|
else
|
|
append();
|
|
memset((char*)(devices+cur_dev), 0, sizeof(*devices));
|
|
trusted = privilege;
|
|
flag_mask = 0;
|
|
devices[cur_dev].drive = ch_canon_drv(token[0]);
|
|
maintain_default_drive(devices[cur_dev].drive);
|
|
expect_char(':');
|
|
return 1;
|
|
}
|
|
if(token_nr == 1 && token_length == 1) {
|
|
parse_old_device_line(token[0]);
|
|
return 1;
|
|
}
|
|
|
|
if((cur_dev < 0 ||
|
|
(set_var(dswitches,
|
|
sizeof(dswitches)/sizeof(*dswitches),
|
|
(caddr_t)&devices[cur_dev]) &&
|
|
set_openflags(&devices[cur_dev]) &&
|
|
set_misc_flags(&devices[cur_dev]) &&
|
|
set_def_format(&devices[cur_dev]))) &&
|
|
set_var(global_switches,
|
|
sizeof(global_switches)/sizeof(*global_switches), 0))
|
|
syntax("unrecognized keyword", 1);
|
|
return 1;
|
|
}
|
|
|
|
static void parse_all(int privilege) {
|
|
errno=0;
|
|
while (parse_one(privilege));
|
|
}
|
|
|
|
|
|
static int parse(const char *name, int privilege)
|
|
{
|
|
if(fp) {
|
|
fprintf(stderr, "File descriptor already set!\n");
|
|
exit(1);
|
|
}
|
|
fp = fopen(name, "r");
|
|
if(!fp)
|
|
return 0;
|
|
file_nr++;
|
|
filename = name; /* no strdup needed: although lifetime of variable
|
|
exceeds this function (due to dev->cfg_filename),
|
|
we know that the name is always either
|
|
1. a constant
|
|
2. a statically allocate buffer
|
|
3. an environment variable that stays unchanged
|
|
*/
|
|
linenumber = 0;
|
|
lastTokenLinenumber = 0;
|
|
pos = 0;
|
|
token = 0;
|
|
cur_dev = -1; /* no current device */
|
|
|
|
parse_all(privilege);
|
|
finish_drive_clause();
|
|
fclose(fp);
|
|
filename = NULL;
|
|
fp = NULL;
|
|
return 1;
|
|
}
|
|
|
|
void read_config(void)
|
|
{
|
|
char *homedir;
|
|
char *envConfFile;
|
|
static char conf_file[MAXPATHLEN+sizeof(CFG_FILE1)];
|
|
|
|
|
|
/* copy compiled-in devices */
|
|
file_nr = 0;
|
|
cur_devs = nr_const_devices;
|
|
nr_dev = nr_const_devices + 2;
|
|
devices = NewArray(nr_dev, struct device);
|
|
if(!devices) {
|
|
printOom();
|
|
exit(1);
|
|
}
|
|
if(nr_const_devices)
|
|
memcpy(devices, const_devices,
|
|
nr_const_devices*sizeof(struct device));
|
|
|
|
(void) ((parse(CONF_FILE,1) |
|
|
parse(LOCAL_CONF_FILE,1) |
|
|
parse(SYS_CONF_FILE,1)) ||
|
|
(parse(OLD_CONF_FILE,1) |
|
|
parse(OLD_LOCAL_CONF_FILE,1)));
|
|
/* the old-name configuration files only get executed if none of the
|
|
* new-name config files were used */
|
|
|
|
homedir = get_homedir();
|
|
if ( homedir ){
|
|
strncpy(conf_file, homedir, MAXPATHLEN );
|
|
conf_file[MAXPATHLEN]='\0';
|
|
strcat( conf_file, CFG_FILE1);
|
|
parse(conf_file,0);
|
|
}
|
|
memset((char *)&devices[cur_devs],0,sizeof(struct device));
|
|
|
|
envConfFile = getenv("MTOOLSRC");
|
|
if(envConfFile)
|
|
parse(envConfFile,0);
|
|
|
|
/* environmental variables */
|
|
get_env_conf();
|
|
if(mtools_skip_check)
|
|
mtools_fat_compatibility=1;
|
|
}
|
|
|
|
void mtoolstest(int argc, char **argv, int type UNUSEDP) NORETURN;
|
|
void mtoolstest(int argc, char **argv, int type UNUSEDP)
|
|
{
|
|
/* testing purposes only */
|
|
struct device *dev;
|
|
char drive='\0';
|
|
|
|
if(argc > 1 && argv[1][0] && argv[1][1] == ':') {
|
|
drive = ch_canon_drv(argv[1][0]);
|
|
}
|
|
|
|
for (dev=devices; dev->name; dev++) {
|
|
if(drive && drive != dev->drive)
|
|
continue;
|
|
printf("drive %c:\n", dev->drive);
|
|
printf("\t#fn=%d mode=%d ",
|
|
dev->file_nr, dev->mode);
|
|
if(dev->cfg_filename)
|
|
printf("defined in %s\n", dev->cfg_filename);
|
|
else
|
|
printf("builtin\n");
|
|
printf("\tfile=\"%s\" fat_bits=%d \n",
|
|
dev->name,dev->fat_bits);
|
|
printf("\ttracks=%d heads=%d sectors=%d hidden=%d\n",
|
|
dev->tracks, dev->heads, dev->sectors, dev->hidden);
|
|
printf("\toffset=0x%lx\n", (long) dev->offset);
|
|
printf("\tpartition=%d\n", dev->partition);
|
|
|
|
if(dev->misc_flags)
|
|
printf("\t");
|
|
|
|
if(DO_SWAP(dev))
|
|
printf("swap ");
|
|
if(IS_SCSI(dev))
|
|
printf("scsi ");
|
|
if(IS_PRIVILEGED(dev))
|
|
printf("privileged");
|
|
if(IS_MFORMAT_ONLY(dev))
|
|
printf("mformat_only ");
|
|
if(SHOULD_USE_VOLD(dev))
|
|
printf("vold ");
|
|
#ifdef USE_XDF
|
|
if(SHOULD_USE_XDF(dev))
|
|
printf("use_xdf ");
|
|
#endif
|
|
if(dev->misc_flags)
|
|
printf("\n");
|
|
|
|
if(dev->mode)
|
|
printf("\t");
|
|
#ifdef O_SYNC
|
|
if(dev->mode & O_SYNC)
|
|
printf("sync ");
|
|
#endif
|
|
#ifdef O_NDELAY
|
|
if((dev->mode & O_NDELAY))
|
|
printf("nodelay ");
|
|
#endif
|
|
#ifdef O_EXCL
|
|
if((dev->mode & O_EXCL))
|
|
printf("exclusive ");
|
|
#endif
|
|
if(dev->mode)
|
|
printf("\n");
|
|
|
|
if(dev->precmd)
|
|
printf("\tprecmd=%s\n", dev->precmd);
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
printf("mtools_fat_compatibility=%d\n",mtools_fat_compatibility);
|
|
printf("mtools_skip_check=%d\n",mtools_skip_check);
|
|
printf("mtools_lower_case=%d\n",mtools_ignore_short_case);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
/*
|
|
* Local Variables:
|
|
* c-basic-offset: 4
|
|
* End:
|
|
*/
|