devfs: fix locking and ignore undocumented "fsdev:\n" configuration signature
The confstr was shared between readers so seprintconf() could write concurrently to that buffer which is not safe. This replaces the shared static confstr[Maxconf] buffer with a pointer that is initially nil and a buffer that is alloced on demand. The new confstr pointer (and buffer) is now only updated while wlock()ed from the new setconfstr() function. This is now done by mconfig() / mdelctl() just before releasing the wlock. Now, rdconf() will check if confstr has been initialized, and test for it again while wlock()ed; making sure the configuration is read only once. Also, rdconf() used to check for a undocumented "fsdev:\n" string at the beginning of config data tho that was never documented. This changes mconfig() to ignore that particular signature so the example from the manpage will work as documented.
This commit is contained in:
parent
4a83ce37c6
commit
a2ebe5c79a
|
@ -117,12 +117,10 @@ static int qidvers;
|
|||
static char *disk; /* default tree name used */
|
||||
static char *source; /* default inner device used */
|
||||
static int sectorsz = Sectorsz; /* default sector size */
|
||||
static char confstr[Maxconf]; /* textual configuration */
|
||||
static char *confstr; /* textual configuration */
|
||||
|
||||
static int debug;
|
||||
|
||||
static char cfgstr[] = "fsdev:\n";
|
||||
|
||||
static Qid tqid = {Qtop, 0, QTDIR};
|
||||
static Qid cqid = {Qctl, 0, 0};
|
||||
|
||||
|
@ -180,6 +178,36 @@ seprintdev(char *s, char *e, Fsdev *mp)
|
|||
return s;
|
||||
}
|
||||
|
||||
static char*
|
||||
seprintconf(char *s, char *e)
|
||||
{
|
||||
int i, j;
|
||||
Tree *t;
|
||||
|
||||
*s = 0;
|
||||
for(i = 0; i < ntrees; i++){
|
||||
t = trees[i];
|
||||
if(t != nil)
|
||||
for(j = 0; j < t->nadevs; j++)
|
||||
if(t->devs[j] != nil)
|
||||
s = seprintdev(s, e, t->devs[j]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* called with lck w */
|
||||
static void
|
||||
setconfstr(void)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = confstr;
|
||||
if(s == nil)
|
||||
s = smalloc(Maxconf);
|
||||
seprintconf(s, s+Maxconf);
|
||||
confstr = s;
|
||||
}
|
||||
|
||||
static vlong
|
||||
mkpath(int tree, int devno)
|
||||
{
|
||||
|
@ -405,6 +433,8 @@ Again:
|
|||
}
|
||||
}
|
||||
}
|
||||
if(some)
|
||||
setconfstr();
|
||||
wunlock(&lck);
|
||||
if(some == 0 && alltrees == 0)
|
||||
error(Enonexist);
|
||||
|
@ -560,7 +590,11 @@ mconfig(char* a, long n)
|
|||
Tree *t;
|
||||
|
||||
/* ignore comments & empty lines */
|
||||
if (*a == '\0' || *a == '#' || *a == '\n')
|
||||
if (n < 1 || *a == '\0' || *a == '#' || *a == '\n')
|
||||
return;
|
||||
|
||||
/* ignore historical config signature */
|
||||
if (n >= 6 && memcmp(a, "fsdev:", 6) == 0)
|
||||
return;
|
||||
|
||||
dprint("mconfig\n");
|
||||
|
@ -722,8 +756,9 @@ Fail:
|
|||
}
|
||||
setdsize(mp, ilen);
|
||||
|
||||
poperror();
|
||||
setconfstr();
|
||||
wunlock(&lck);
|
||||
poperror();
|
||||
free(idev);
|
||||
free(ilen);
|
||||
free(cb);
|
||||
|
@ -732,21 +767,30 @@ Fail:
|
|||
static void
|
||||
rdconf(void)
|
||||
{
|
||||
int mustrd;
|
||||
char *c, *e, *p, *s;
|
||||
Chan *cc;
|
||||
static int configed;
|
||||
int mustrd;
|
||||
|
||||
/* only read config file once */
|
||||
if (configed)
|
||||
if (confstr != nil)
|
||||
return;
|
||||
configed = 1;
|
||||
|
||||
wlock(&lck);
|
||||
if (confstr != nil) {
|
||||
wunlock(&lck);
|
||||
return; /* already done */
|
||||
}
|
||||
|
||||
/* add the std "fs" tree */
|
||||
if(ntrees == 0){
|
||||
fstree.name = "fs";
|
||||
trees[ntrees++] = &fstree;
|
||||
}
|
||||
|
||||
setconfstr();
|
||||
wunlock(&lck);
|
||||
|
||||
dprint("rdconf\n");
|
||||
/* add the std "fs" tree */
|
||||
trees[0] = &fstree;
|
||||
ntrees++;
|
||||
fstree.name = "fs";
|
||||
|
||||
/* identify the config file */
|
||||
s = getconf("fsconfig");
|
||||
|
@ -756,7 +800,9 @@ rdconf(void)
|
|||
} else
|
||||
mustrd = 1;
|
||||
|
||||
c = smalloc(Maxconf+1);
|
||||
if(waserror()){
|
||||
free(c);
|
||||
if(!mustrd)
|
||||
return;
|
||||
nexterror();
|
||||
|
@ -768,23 +814,12 @@ rdconf(void)
|
|||
cclose(cc);
|
||||
nexterror();
|
||||
}
|
||||
devtab[cc->type]->read(cc, confstr, sizeof confstr, 0);
|
||||
poperror();
|
||||
devtab[cc->type]->read(cc, c, Maxconf, 0);
|
||||
cclose(cc);
|
||||
poperror();
|
||||
|
||||
/* validate, copy and erase config; mconfig will repopulate confstr */
|
||||
if (strncmp(confstr, cfgstr, sizeof cfgstr - 1) != 0)
|
||||
error("bad #k config, first line must be: 'fsdev:\\n'");
|
||||
|
||||
c = nil;
|
||||
kstrdup(&c, confstr + sizeof cfgstr - 1);
|
||||
if(waserror()){
|
||||
free(c);
|
||||
nexterror();
|
||||
}
|
||||
memset(confstr, 0, sizeof confstr);
|
||||
/* process config copy one line at a time */
|
||||
for (p = c; p != nil && *p != '\0'; p = e){
|
||||
for (p = c; *p != '\0'; p = e){
|
||||
e = strchr(p, '\n');
|
||||
if (e == nil)
|
||||
e = p + strlen(p);
|
||||
|
@ -792,10 +827,9 @@ rdconf(void)
|
|||
e++;
|
||||
mconfig(p, e - p);
|
||||
}
|
||||
poperror();
|
||||
free(c);
|
||||
|
||||
poperror(); /* mustrd */
|
||||
free(c);
|
||||
poperror(); /* c */
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1138,23 +1172,6 @@ interio(Fsdev *mp, int isread, void *a, long n, vlong off)
|
|||
return res;
|
||||
}
|
||||
|
||||
static char*
|
||||
seprintconf(char *s, char *e)
|
||||
{
|
||||
int i, j;
|
||||
Tree *t;
|
||||
|
||||
*s = 0;
|
||||
for(i = 0; i < ntrees; i++){
|
||||
t = trees[i];
|
||||
if(t != nil)
|
||||
for(j = 0; j < t->nadevs; j++)
|
||||
if(t->devs[j] != nil)
|
||||
s = seprintdev(s, e, t->devs[j]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static long
|
||||
mread(Chan *c, void *a, long n, vlong off)
|
||||
{
|
||||
|
@ -1175,7 +1192,6 @@ mread(Chan *c, void *a, long n, vlong off)
|
|||
goto Done;
|
||||
}
|
||||
if(c->qid.path == Qctl){
|
||||
seprintconf(confstr, confstr + sizeof(confstr));
|
||||
res = readstr((long)off, a, n, confstr);
|
||||
goto Done;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue