Index: mkheaders.c
===================================================================
--- mkheaders.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ mkheaders.c (.../tags/patch-1-rc1) (revision 51)
@@ -162,6 +162,7 @@
struct nvlist *nv;
FILE *fp;
+
(void)snprintf(nfname, sizeof(nfname), "%s.h", head->nv_name);
(void)snprintf(tfname, sizeof(tfname), "tmp_%s", nfname);
@@ -376,17 +377,31 @@
const char *tfname;
FILE *tfp;
struct devbase *d;
+ struct nvlist *nv;
+ struct nvlist *lkmlist = NULL; /* to remember LKM devices */
tfname = "tmp_ioconf.h";
if ((tfp = fopen(tfname, "w")) == NULL)
return (herr("open", tfname, NULL));
TAILQ_FOREACH(d, &allbases, d_next) {
- if (!devbase_has_instances(d, WILD))
- continue;
- fprintf(tfp, "extern struct cfdriver %s_cd;\n", d->d_name);
+ if (devbase_has_instances(d, WILD))
+ fprintf(tfp, "extern struct cfdriver %s_cd;\n", d->d_name);
+ else if (devbase_has_any_instance(d, WILD, DEVI_MODULE, 0))
+ lkmlist = newnv(d->d_name, NULL, d, 0, lkmlist);
}
+ if (lkmlist) {
+ fprintf(tfp, "\n/* for LKMs */\n");
+ for (nv = lkmlist; nv; nv = nv->nv_next) {
+ d = nv->nv_ptr;
+ fprintf(tfp, "extern struct cfdriver %s_cd;\n",
+ d->d_name);
+ }
+ nvfreel(lkmlist);
+ lkmlist = NULL;
+ }
+
fflush(tfp);
if (ferror(tfp))
return herr("writ", tfname, tfp);
Index: mkmakefile.c
===================================================================
--- mkmakefile.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ mkmakefile.c (.../tags/patch-1-rc1) (revision 51)
@@ -64,52 +64,103 @@
static const char *filetype_prologue(struct filetype *);
-static void emitdefs(FILE *);
+static void emitdefs(FILE *, const char *);
static void emitfiles(FILE *, int, int);
-static void emitobjs(FILE *);
-static void emitcfiles(FILE *);
-static void emitsfiles(FILE *);
-static void emitrules(FILE *);
-static void emitload(FILE *);
-static void emitincludes(FILE *);
-static void emitappmkoptions(FILE *);
+static void emitobjs(FILE *, void *);
+static void emitcfiles(FILE *, void *);
+static void emitsfiles(FILE *, void *);
+static void emitrules(FILE *, void *);
+static void emitload(FILE *, void *);
+static void emitincludes(FILE *, void *);
+static void emitappmkoptions(FILE *, void *);
int
mkmakefile(void)
{
+ static const struct makefile_constructs c[] = {
+ { "OBJS", emitobjs },
+ { "CFILES", emitcfiles },
+ { "SFILES", emitsfiles },
+ { "RULES", emitrules },
+ { "LOAD", emitload },
+ { "INCLUDES", emitincludes },
+ { "MAKEOPTIONSAPPEND", emitappmkoptions },
+ { "KMOD", emitkmod },
+ { NULL, NULL }
+ };
+
+ return mkmakefile_common(c, "", ".", NULL);
+}
+
+int
+mkmakefile_common(const struct makefile_constructs *cset,
+ const char *template_suffix,
+ const char *output_dir,
+ void *aux)
+{
FILE *ifp, *ofp;
int lineno;
- void (*fn)(FILE *);
char *ifname;
- char line[BUFSIZ], buf[200];
+ char line[BUFSIZ];
+ char buf[MAXPATHLEN];
+ char makefilename[MAXPATHLEN], tempfilename[MAXPATHLEN];
+ const char *srcdirprepend = "";
+ int i;
+ int lkm = aux != NULL;
/* Try a makefile for the port first.
*/
- (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s",
- machine, machine);
+ (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile%s.%s",
+ machine, template_suffix, machine);
ifname = sourcepath(buf);
if ((ifp = fopen(ifname, "r")) == NULL) {
/* Try a makefile for the architecture second.
*/
- (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s",
- machinearch, machinearch);
+ (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile%s.%s",
+ machinearch, template_suffix, machinearch);
free(ifname);
ifname = sourcepath(buf);
ifp = fopen(ifname, "r");
}
+ if (ifp == NULL && lkm) {
+ /* for LKM makefile, try MI template */
+ (void)snprintf(buf, sizeof buf, "conf/Makefile%s",
+ template_suffix);
+ ifname = sourcepath(buf);
+ ifp = fopen(ifname, "r");
+ }
if (ifp == NULL) {
warn("cannot read %s", ifname);
goto bad2;
}
- if ((ofp = fopen("Makefile.tmp", "w")) == NULL) {
- warn("cannot write Makefile");
+
+ snprintf(makefilename, sizeof buf, "%s/Makefile", output_dir);
+ snprintf(tempfilename, sizeof tempfilename, "%s.tmp", makefilename);
+
+ if ((ofp = fopen(tempfilename, "w")) == NULL) {
+ warn("cannot write %s", tempfilename);
goto bad1;
}
- emitdefs(ofp);
+ if (*srcdir == '/')
+ srcdirprepend = "";
+ else if (lkm)
+ srcdirprepend = "../../";
+ else {
+ /*
+ * libkern and libcompat "Makefile.inc"s want relative S
+ * specification to begin with '.'.
+ */
+ if (*srcdir == '.')
+ srcdirprepend = "";
+ else
+ srcdirprepend = "./";
+ }
+ emitdefs(ofp, srcdirprepend);
+
lineno = 0;
while (fgets(line, sizeof(line), ifp) != NULL) {
lineno++;
@@ -117,26 +168,21 @@
fputs(line, ofp);
continue;
}
- if (strcmp(line, "%OBJS\n") == 0)
- fn = emitobjs;
- else if (strcmp(line, "%CFILES\n") == 0)
- fn = emitcfiles;
- else if (strcmp(line, "%SFILES\n") == 0)
- fn = emitsfiles;
- else if (strcmp(line, "%RULES\n") == 0)
- fn = emitrules;
- else if (strcmp(line, "%LOAD\n") == 0)
- fn = emitload;
- else if (strcmp(line, "%INCLUDES\n") == 0)
- fn = emitincludes;
- else if (strcmp(line, "%MAKEOPTIONSAPPEND\n") == 0)
- fn = emitappmkoptions;
- else {
+ for (i=0; cset[i].str != NULL; ++i) {
+ /* chomp line */
+ char *p = strchr(line+1, '\n');
+ if (p)
+ *p = '\0';
+
+ if (strcmp(line+1, cset[i].str) == 0) {
+ cset[i].func(ofp, aux);
+ break;
+ }
+ }
+ if (cset[i].str == NULL) {
cfgxerror(ifname, lineno,
"unknown %% construct ignored: %s", line);
- continue;
}
- (*fn)(ofp);
}
fflush(ofp);
@@ -154,21 +200,21 @@
}
(void)fclose(ifp);
- if (moveifchanged("Makefile.tmp", "Makefile") != 0) {
- warn("error renaming Makefile");
+ if (moveifchanged(tempfilename, makefilename) != 0) {
+ warn("error renaming %s", makefilename);
goto bad2;
}
free(ifname);
return (0);
wrerror:
- warn("error writing Makefile");
+ warn("error writing %s", makefilename);
bad:
if (ofp != NULL)
(void)fclose(ofp);
bad1:
(void)fclose(ifp);
- /* (void)unlink("Makefile.tmp"); */
+ /* (void)unlink(tempfilename); */
bad2:
free(ifname);
return (1);
@@ -219,7 +265,7 @@
}
static void
-emitdefs(FILE *fp)
+emitdefs(FILE *fp, const char *srcdirprepend)
{
struct nvlist *nv;
char *sp;
@@ -240,21 +286,14 @@
putc('\n', fp);
fprintf(fp, "PARAM=-DMAXUSERS=%d\n", maxusers);
fprintf(fp, "MACHINE=%s\n", machine);
- if (*srcdir == '/' || *srcdir == '.') {
- fprintf(fp, "S=\t%s\n", srcdir);
- } else {
- /*
- * libkern and libcompat "Makefile.inc"s want relative S
- * specification to begin with '.'.
- */
- fprintf(fp, "S=\t./%s\n", srcdir);
- }
+ fprintf(fp, "S=\t%s%s\n", srcdirprepend, srcdir);
for (nv = mkoptions; nv != NULL; nv = nv->nv_next)
fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str);
}
static void
-emitobjs(FILE *fp)
+/*ARGSUSED*/
+emitobjs(FILE *fp, void *aux)
{
struct files *fi;
struct objects *oi;
@@ -314,14 +353,16 @@
}
static void
-emitcfiles(FILE *fp)
+/*ARGSUSED*/
+emitcfiles(FILE *fp, void *aux)
{
emitfiles(fp, 'c', 0);
}
static void
-emitsfiles(FILE *fp)
+/*ARGSUSED*/
+emitsfiles(FILE *fp, void *aux)
{
emitfiles(fp, 's', 'S');
@@ -402,7 +443,8 @@
* Emit the make-rules.
*/
static void
-emitrules(FILE *fp)
+/*ARGSUSED*/
+emitrules(FILE *fp, void *aux)
{
struct files *fi;
const char *cp, *fpath;
@@ -445,7 +487,8 @@
* This function is not to be called `spurt'.
*/
static void
-emitload(FILE *fp)
+/*ARGSUSED*/
+emitload(FILE *fp, void *aux)
{
struct config *cf;
const char *nm, *swname;
@@ -475,7 +518,8 @@
* Emit include headers (for any prefixes encountered)
*/
static void
-emitincludes(FILE *fp)
+/*ARGSUSED*/
+emitincludes(FILE *fp, void *aux)
{
struct prefix *pf;
@@ -504,7 +548,8 @@
* Emit appending makeoptions.
*/
static void
-emitappmkoptions(FILE *fp)
+/*ARGSUSED*/
+emitappmkoptions(FILE *fp, void *aux)
{
struct nvlist *nv;
Index: mkioconf.c
===================================================================
--- mkioconf.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ mkioconf.c (.../tags/patch-1-rc1) (revision 51)
@@ -61,7 +61,7 @@
static void emitcfdrivers(FILE *);
static void emitexterns(FILE *);
static void emitcfattachinit(FILE *);
-static void emithdr(FILE *);
+//static void emithdr(FILE *);
static void emitloc(FILE *);
static void emitpseudo(FILE *);
static void emitparents(FILE *);
@@ -89,7 +89,7 @@
return (1);
}
- emithdr(fp);
+ ioconf_emithdr(fp, "ioconf.c");
emitcfdrivers(fp);
emitexterns(fp);
emitcfattachinit(fp);
@@ -129,15 +129,15 @@
return (n1 - n2);
}
-static void
-emithdr(FILE *ofp)
+void
+ioconf_emithdr(FILE *ofp, const char *filename)
{
FILE *ifp;
int n;
char ifnbuf[200], buf[BUFSIZ];
char *ifn;
- autogen_comment(ofp, "ioconf.c");
+ autogen_comment(ofp, filename);
(void)snprintf(ifnbuf, sizeof(ifnbuf), "arch/%s/conf/ioconf.incl.%s",
machine, machine);
@@ -174,7 +174,7 @@
if (a->a_locs) {
fprintf(fp,
- "static const struct cfiattrdata %scf_iattrdata = {\n",
+ "const struct cfiattrdata %scf_iattrdata = {\n",
name);
fprintf(fp, "\t\"%s\", %d,\n\t{\n", name, a->a_loclen);
for (nv = a->a_locs; nv; nv = nv->nv_next)
@@ -185,7 +185,7 @@
fprintf(fp, "\t}\n};\n");
} else {
fprintf(fp,
- "static const struct cfiattrdata %scf_iattrdata = {\n"
+ "const struct cfiattrdata %scf_iattrdata = {\n"
"\t\"%s\", 0, {\n\t\t{ NULL, NULL, 0 },\n\t}\n};\n",
name, name);
}
@@ -197,9 +197,6 @@
emitcfdrivers(FILE *fp)
{
struct devbase *d;
- struct nvlist *nv;
- struct attr *a;
- int has_iattrs;
NEWLINE;
ht_enumerate(attrtab, cf_locators_print, fp);
@@ -208,28 +205,7 @@
TAILQ_FOREACH(d, &allbases, d_next) {
if (!devbase_has_instances(d, WILD))
continue;
- has_iattrs = 0;
- for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
- a = nv->nv_ptr;
- if (a->a_iattr == 0)
- continue;
- if (has_iattrs == 0)
- fprintf(fp,
- "static const struct cfiattrdata * const %s_attrs[] = { ",
- d->d_name);
- has_iattrs = 1;
- fprintf(fp, "&%scf_iattrdata, ", a->a_name);
- }
- if (has_iattrs)
- fprintf(fp, "NULL };\n");
- fprintf(fp, "CFDRIVER_DECL(%s, %s, ", d->d_name, /* ) */
- d->d_classattr != NULL ? d->d_classattr->a_devclass
- : "DV_DULL");
- if (has_iattrs)
- fprintf(fp, "%s_attrs", d->d_name);
- else
- fprintf(fp, "NULL");
- fprintf(fp, /* ( */ ");\n\n");
+ ioconf_emit_cfdriver(d, fp);
}
NEWLINE;
@@ -242,6 +218,63 @@
fprintf(fp, "\tNULL\n};\n");
}
+
+/* This function is used for LKM ioconf */
+void
+ioconf_emit_ref_iattrs(struct devbase *d, FILE *fp)
+{
+ struct nvlist *nv;
+ struct attr *a;
+
+ for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
+ a = nv->nv_ptr;
+ if (a->a_iattr == 0)
+ continue;
+
+ a = nv->nv_ptr;
+ fprintf(fp,
+ "extern const struct cfiattrdata %scf_iattrdata;\n",
+ a->a_name);
+ }
+}
+
+void
+ioconf_emit_cfdriver(struct devbase *d, FILE *fp)
+{
+ struct nvlist *nv;
+ struct attr *a;
+ int has_iattrs;
+
+ has_iattrs = 0;
+ for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
+ a = nv->nv_ptr;
+ if (a->a_iattr == 0)
+ continue;
+ if (!has_iattrs) {
+ fprintf(fp,
+ "const struct cfiattrdata * const %s_attrs[] = { ",
+ d->d_name);
+ }
+
+ a = nv->nv_ptr;
+ fprintf(fp, "&%scf_iattrdata, ", a->a_name);
+ has_iattrs = 1;
+ }
+
+ if (has_iattrs)
+ fprintf(fp, "NULL };\n");
+
+ fprintf(fp, "CFDRIVER_DECL(%s, %s, ", d->d_name, /* ) */
+ d->d_classattr != NULL ? d->d_classattr->a_devclass
+ : "DV_DULL");
+ if (has_iattrs)
+ fprintf(fp, "%s_attrs", d->d_name);
+ else
+ fprintf(fp, "NULL");
+ fprintf(fp, /* ( */ ");\n\n");
+}
+
+
static void
emitexterns(FILE *fp)
{
@@ -324,23 +357,32 @@
NEWLINE;
TAILQ_FOREACH(p, &allpspecs, p_list) {
- if (p->p_devs == NULL || p->p_active != DEVI_ACTIVE)
- continue;
- fprintf(fp,
- "static const struct cfparent pspec%d = {\n", p->p_inst);
- fprintf(fp, "\t\"%s\", ", p->p_iattr->a_name);
- if (p->p_atdev != NULL) {
- fprintf(fp, "\"%s\", ", p->p_atdev->d_name);
- if (p->p_atunit == WILD)
- fprintf(fp, "DVUNIT_ANY");
- else
- fprintf(fp, "%d", p->p_atunit);
- } else
- fprintf(fp, "NULL, 0");
- fprintf(fp, "\n};\n");
+ ioconf_emit_pspec(fp, p, 0);
}
}
+void
+ioconf_emit_pspec(FILE *fp, struct pspec *p, int force)
+{
+ /* force==1 when creating _MODULE_ioconf.c */
+ if (!force &&
+ (p->p_devs == NULL || p->p_active != DEVI_ACTIVE))
+ return;
+
+ fprintf(fp,
+ "static const struct cfparent pspec%d = {\n", p->p_inst);
+ fprintf(fp, "\t\"%s\", ", p->p_iattr->a_name);
+ if (p->p_atdev != NULL) {
+ fprintf(fp, "\"%s\", ", p->p_atdev->d_name);
+ if (p->p_atunit == WILD)
+ fprintf(fp, "DVUNIT_ANY");
+ else
+ fprintf(fp, "%d", p->p_atunit);
+ } else
+ fprintf(fp, "NULL, 0");
+ fprintf(fp, "\n};\n");
+}
+
/*
* Emit the cfdata array.
*/
@@ -348,6 +390,32 @@
emitcfdata(FILE *fp)
{
struct devi **p, *i;
+ const char *dataname = "cfdata";
+
+ ioconf_cfdata_start(fp, dataname);
+ for (p = packed; (i = *p) != NULL; p++) {
+ /* the description */
+ ioconf_cfdata_entry(fp, i);
+ }
+
+ ioconf_cfdata_end(fp, dataname);
+}
+
+void
+ioconf_cfdata_start(FILE *fp, const char *array_name)
+{
+ fprintf(fp, "\n"
+ "#define NORM FSTATE_NOTFOUND\n"
+ "#define STAR FSTATE_STAR\n"
+ "\n"
+ "struct cfdata %s[] = {\n"
+ " /* driver attachment unit state "
+ "loc flags pspec */\n", array_name);
+}
+
+void
+ioconf_cfdata_entry(FILE *fp, struct devi *i)
+{
struct pspec *ps;
int unit, v;
const char *state, *basename, *attachment;
@@ -357,78 +425,75 @@
char locbuf[20];
const char *lastname = "";
- fprintf(fp, "\n"
- "#define NORM FSTATE_NOTFOUND\n"
- "#define STAR FSTATE_STAR\n"
- "\n"
- "struct cfdata cfdata[] = {\n"
- " /* driver attachment unit state "
- "loc flags pspec */\n");
- for (p = packed; (i = *p) != NULL; p++) {
- /* the description */
- fprintf(fp, "/*%3d: %s at ", i->i_cfindex, i->i_name);
- if ((ps = i->i_pspec) != NULL) {
- if (ps->p_atdev != NULL &&
- ps->p_atunit != WILD) {
- fprintf(fp, "%s%d", ps->p_atdev->d_name,
- ps->p_atunit);
- } else if (ps->p_atdev != NULL) {
- fprintf(fp, "%s?", ps->p_atdev->d_name);
+ fprintf(fp, "/*%3d: %s at ", i->i_cfindex, i->i_name);
+ if ((ps = i->i_pspec) != NULL) {
+ if (ps->p_atdev != NULL &&
+ ps->p_atunit != WILD) {
+ fprintf(fp, "%s%d", ps->p_atdev->d_name,
+ ps->p_atunit);
+ } else if (ps->p_atdev != NULL) {
+ fprintf(fp, "%s?", ps->p_atdev->d_name);
+ } else {
+ fprintf(fp, "%s?", ps->p_iattr->a_name);
+ }
+
+ a = ps->p_iattr;
+ for (nv = a->a_locs, v = 0; nv != NULL;
+ nv = nv->nv_next, v++) {
+ if (ARRNAME(nv->nv_name, lastname)) {
+ fprintf(fp, " %s %s",
+ nv->nv_name, i->i_locs[v]);
} else {
- fprintf(fp, "%s?", ps->p_iattr->a_name);
+ fprintf(fp, " %s %s",
+ nv->nv_name,
+ i->i_locs[v]);
+ lastname = nv->nv_name;
}
-
- a = ps->p_iattr;
- for (nv = a->a_locs, v = 0; nv != NULL;
- nv = nv->nv_next, v++) {
- if (ARRNAME(nv->nv_name, lastname)) {
- fprintf(fp, " %s %s",
- nv->nv_name, i->i_locs[v]);
- } else {
- fprintf(fp, " %s %s",
- nv->nv_name,
- i->i_locs[v]);
- lastname = nv->nv_name;
- }
- }
- } else {
- a = NULL;
- fputs("root", fp);
}
+ } else {
+ a = NULL;
+ fputs("root", fp);
+ }
- fputs(" */\n", fp);
+ fputs(" */\n", fp);
- /* then the actual defining line */
- basename = i->i_base->d_name;
- attachment = i->i_atdeva->d_name;
- if (i->i_unit == STAR) {
- unit = i->i_base->d_umax;
- state = "STAR";
- } else {
- unit = i->i_unit;
- state = "NORM";
- }
- if (i->i_locoff >= 0) {
- (void)snprintf(locbuf, sizeof(locbuf), "loc+%3d",
- i->i_locoff);
- loc = locbuf;
- } else
- loc = "loc";
- fprintf(fp, " {\"%s\",%s\"%s\",%s%2d, %s, %7s, %#6x, ",
- basename, strlen(basename) < 8 ? "\t\t"
- : "\t",
- attachment, strlen(attachment) < 5 ? "\t\t"
- : "\t",
- unit, state, loc, i->i_cfflags);
- if (ps != NULL)
- fprintf(fp, "&pspec%d},\n", ps->p_inst);
- else
- fputs("NULL},\n", fp);
+ /* then the actual defining line */
+ basename = i->i_base->d_name;
+ attachment = i->i_atdeva->d_name;
+ if (i->i_unit == STAR) {
+ unit = i->i_base->d_umax;
+ state = "STAR";
+ } else {
+ unit = i->i_unit;
+ state = "NORM";
}
+ if (i->i_locoff >= 0) {
+ (void)snprintf(locbuf, sizeof(locbuf), "loc+%3d",
+ i->i_locoff);
+ loc = locbuf;
+ } else
+ loc = "loc";
+ fprintf(fp, " {\"%s\",%s\"%s\",%s%2d, %s, %7s, %#6x, ",
+ basename, strlen(basename) < 8 ? "\t\t"
+ : "\t",
+ attachment, strlen(attachment) < 5 ? "\t\t"
+ : "\t",
+ unit, state, loc, i->i_cfflags);
+ if (ps != NULL)
+ fprintf(fp, "&pspec%d},\n", ps->p_inst);
+ else
+ fputs("NULL},\n", fp);
+}
+
+void
+/*ARGSUSED*/
+ioconf_cfdata_end(FILE *fp, const char *array_name)
+{
fprintf(fp, " {%s,%s%s,%s%2d, %s, %7s, %#6x, %s}\n};\n",
"NULL", "\t\t", "NULL", "\t\t", 0, "0", "NULL", 0, "NULL");
}
+
/*
* Emit the table of potential roots.
*/
@@ -461,11 +526,15 @@
fputs("\n/* pseudo-devices */\n", fp);
TAILQ_FOREACH(i, &allpseudo, i_next) {
+ if (i->i_module)
+ continue;
fprintf(fp, "void %sattach(int);\n",
i->i_base->d_name);
}
fputs("\nstruct pdevinit pdevinit[] = {\n", fp);
TAILQ_FOREACH(i, &allpseudo, i_next) {
+ if (i->i_module)
+ continue;
d = i->i_base;
fprintf(fp, "\t{ %sattach, %d },\n",
d->d_name, d->d_umax);
Index: gram.y
===================================================================
--- gram.y (.../vendor/netbsd/current-20080118) (revision 51)
+++ gram.y (.../tags/patch-1-rc1) (revision 51)
@@ -108,7 +108,7 @@
%token ENDFILE
%token XFILE FILE_SYSTEM FLAGS
%token IDENT
-%token XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR
+%token XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR MODULE
%token NEEDS_COUNT NEEDS_FLAG NO
%token XOBJECT OBSOLETE ON OPTIONS
%token PACKAGE PLUSEQ PREFIX PSEUDO_DEVICE
@@ -453,7 +453,8 @@
config_spec:
one_def |
- NO FILE_SYSTEM no_fs_list |
+ NO opt_module FILE_SYSTEM no_fs_list |
+ MODULE FILE_SYSTEM mod_fs_list |
FILE_SYSTEM fs_list |
NO MAKEOPTIONS no_mkopt_list |
MAKEOPTIONS mkopt_list |
@@ -464,22 +465,34 @@
CONFIG conf root_spec sysparam_list
{ addconf(&conf); } |
NO CONFIG WORD { delconf($3); } |
- NO PSEUDO_DEVICE WORD { delpseudo($3); } |
- PSEUDO_DEVICE WORD npseudo { addpseudo($2, $3); } |
- NO device_instance AT attachment
- { deldevi($2, $4); } |
+ NO opt_module PSEUDO_DEVICE WORD { delpseudo($4); } |
+ PSEUDO_DEVICE WORD npseudo
+ { addpseudo($2, $3, 0); } |
+ MODULE PSEUDO_DEVICE WORD npseudo
+ { addpseudo($3, $4, 1); } |
+ NO opt_module device_instance AT attachment
+ { deldevi($3, $5); } |
NO DEVICE AT attachment { deldeva($4); } |
- NO device_instance { deldev($2); } |
+ NO opt_module device_instance { deldev($3); } |
device_instance AT attachment locators flags_opt
- { adddev($1, $3, $4, $5); };
+ { adddev($1, $3, $4, $5, 0); } |
+ MODULE device_instance AT attachment locators flags_opt
+ { adddev($2, $4, $5, $6, 1); };
fs_list:
fs_list ',' fsoption |
fsoption;
fsoption:
- WORD { addfsoption($1); };
+ WORD { addfsoption($1, 0); };
+mod_fs_list:
+ mod_fs_list ',' mod_fsoption |
+ mod_fsoption;
+
+mod_fsoption:
+ WORD { addfsoption($1, 1); };
+
no_fs_list:
no_fs_list ',' no_fsoption |
no_fsoption;
@@ -590,6 +603,9 @@
FLAGS NUMBER { $$ = $2.val; } |
/* empty */ { $$ = 0; };
+opt_module:
+ MODULE | /* empty */;
+
%%
void
Index: util.c
===================================================================
--- util.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ util.c (.../tags/patch-1-rc1) (revision 51)
@@ -45,6 +45,7 @@
#endif
#include <sys/types.h>
+#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -52,6 +53,7 @@
#include <stdarg.h>
#include <util.h>
#include <err.h>
+#include <errno.h>
#include "defs.h"
static void cfgvxerror(const char *, int, const char *, va_list)
@@ -295,3 +297,21 @@
" */\n\n",
targetfile, conffile);
}
+
+/*
+ * Create a directory if not exists. Die when fails.
+ */
+void
+make_directory(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) == -1) {
+ if (errno != ENOENT)
+ warn("can't find %s", path);
+ if (mkdir(path, 0777) == -1)
+ err(EXIT_FAILURE, "cannot create %s", path);
+ } else if (!S_ISDIR(st.st_mode))
+ errx(EXIT_FAILURE, "%s is not a directory", path);
+}
+
Index: mkdevsw.c
===================================================================
--- mkdevsw.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ mkdevsw.c (.../tags/patch-1-rc1) (revision 51)
@@ -109,7 +109,8 @@
for (i = 0 ; i <= maxbdevm ; i++) {
(void)snprintf(mstr, sizeof(mstr), "%d", i);
- if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL)
+ if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL ||
+ dm->dm_active != DEVM_INKERNEL)
continue;
fprintf(fp, "extern const struct bdevsw %s_bdevsw;\n",
@@ -120,7 +121,8 @@
for (i = 0 ; i <= maxbdevm ; i++) {
(void)snprintf(mstr, sizeof(mstr), "%d", i);
- if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL) {
+ if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL ||
+ dm->dm_active != DEVM_INKERNEL) {
fprintf(fp, "\tNULL,\n");
} else {
fprintf(fp, "\t&%s_bdevsw,\n", dm->dm_name);
@@ -136,7 +138,8 @@
for (i = 0 ; i <= maxcdevm ; i++) {
(void)snprintf(mstr, sizeof(mstr), "%d", i);
- if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL)
+ if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL ||
+ dm->dm_active != DEVM_INKERNEL)
continue;
fprintf(fp, "extern const struct cdevsw %s_cdevsw;\n",
@@ -147,7 +150,8 @@
for (i = 0 ; i <= maxcdevm ; i++) {
(void)snprintf(mstr, sizeof(mstr), "%d", i);
- if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL) {
+ if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL ||
+ dm->dm_active != DEVM_INKERNEL) {
fprintf(fp, "\tNULL,\n");
} else {
fprintf(fp, "\t&%s_cdevsw,\n", dm->dm_name);
Index: lkm.c
===================================================================
--- lkm.c (.../vendor/netbsd/current-20080118) (revision 0)
+++ lkm.c (.../tags/patch-1-rc1) (revision 51)
@@ -0,0 +1,1573 @@
+/*-
+ * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Hiroyuki Bessho.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#ifndef MAKE_BOOTSTRAP
+#include <sys/cdefs.h>
+#define COPYRIGHT(x) __COPYRIGHT(x)
+#else
+#define COPYRIGHT(x) static const char copyright[] = x
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+#include <assert.h>
+
+#include "defs.h"
+#include "sem.h" /* for expandattr */
+
+#define KMODDIR "modules"
+#define KMODWORK_SUFFIX ".work"
+
+static int fixlkm_devbase(struct devbase *);
+static int fixlkm_deva(struct deva *);
+static int fixlkm_devi(struct devi *);
+static struct module *newmodule(const char *, enum module_type);
+static struct module *getmodule(const char *, enum module_type);
+static int lkm_select_device(struct module *, void (*)(struct attr *, void *));
+static int lkm_select_cb(const char *, void *, void *);
+static void lkm_select_attr(struct attr *, void *);
+static void lkm_record_require(struct attr *, void *);
+//static int for_all_module_files(struct module *, int (* )(struct files *, struct module *, void *), void *);
+static int lkm_fixfile_cb(const char *, void *, void *);
+static int lkm_fixsel(const char *, void *);
+static void lkm_emit_parents(struct module *, FILE *fp);
+static int lkm_emit_modulelist_cb(const char *, void *, void *);
+//static int lkm_emit_moduledefs_cb(const char *, void *, void *);
+static int lkm_make_files_cb(const char *, void *, void *);
+static int lkm_make_makefile(struct module *, const char *);
+static int lkm_make_lkmfile(struct module *, const char *);
+static void lkm_emit_loc(struct module *, FILE *);
+static int add_lkm_file_cb(const char *, void *, void *);
+static int lkm_emit_ioconf(struct module *, struct files *, FILE *);
+static int lkm_emit_ioconf_pseudo(struct module *, struct files *, FILE *, char **);
+struct emit_require_args {
+ FILE *fp;
+ struct module *cur_module;
+};
+static int lkm_emitrequire_cb(const char *, void *, void *);
+static int lkm_emitprovide_cb(const char *, void *, void *);
+
+static void lkm_emitsrcs(FILE *, void *);
+static void lkm_emitobjs(FILE *, void *);
+static void lkm_emitkmod(FILE *, void *);
+
+int merge_modules(struct module *, struct module *);
+
+#ifndef STAILQ_APPEND
+#define STAILQ_APPEND(q0, q1, field) do { \
+ if (!STAILQ_EMPTY(q1)) { \
+ *(q0)->stqh_last = STAILQ_FIRST(q1); \
+ (q0)->stqh_last = (q1)->stqh_last; \
+ } \
+} while (/*CONSTCOND*/0)
+#endif
+
+
+int
+fixlkmdevs(void)
+{
+ struct devbase *d;
+ struct deva *da;
+ struct devi *i, *j;
+
+ TAILQ_FOREACH(d, &allbases, d_next) {
+
+ if (fixlkm_devbase(d))
+ return -1;
+
+ for (da = d->d_ahead; da != NULL; da = da->d_bsame) {
+ if (da->d_name == d->d_name) {
+ /* the device doesn't have separate
+ attachment attribute. */
+ continue;
+ }
+
+ if (fixlkm_deva(da))
+ return -1;
+ }
+
+ for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
+ for (j=i; j != NULL; j = j->i_alias) {
+ if (fixlkm_devi(j))
+ return -1;
+ }
+ }
+ }
+
+ /* select new modules required by already selected modules */
+ ht_enumerate(moduletab, lkm_select_cb, lkm_select_attr);
+ /* and record dependencies between selected modules */
+ ht_enumerate(moduletab, lkm_select_cb, lkm_record_require);
+
+ return 0;
+}
+
+static int
+fixlkm_devbase(struct devbase *d)
+{
+ struct devi *i, *j;
+ struct module *m;
+ int d_module = 0;
+
+ /* if it's in the kernel, don't make an LKM for it */
+ if (ht_lookup(selecttab, d->d_name) != NULL)
+ return 0;
+
+ /* if device instance is in the module, we also need its base */
+ for (i = d->d_ihead; i != NULL; i = i->i_bsame)
+ for (j = i; j != NULL; j = j->i_alias) {
+ if (j->i_active == DEVI_MODULE) {
+ ++d_module;
+ /* break; */
+ }
+ }
+
+ if (d_module == 0)
+ return 0;
+
+ /* make a module for this devbase
+ the name of the module is device name */
+ m = getmodule(d->d_name,
+ d->d_ispseudo ? M_PSEUDO: M_DEVICE);
+ if (m == NULL)
+ return -1;
+ STAILQ_INSERT_TAIL(&m->m_base, d, d_mnext);
+ d->d_module = m;
+
+ return 0;
+}
+
+
+/*
+ */
+static int
+fixlkm_deva(struct deva *a)
+{
+ struct devi *i;
+ struct devbase *base;
+ struct module *m;
+ int a_module = 0;
+
+ /* if it's in the kernel, don't make LKM */
+ if (ht_lookup(selecttab, a->d_name) != NULL)
+ return 0;
+
+ /* if device instance is in the module, we also need its attachment */
+ for (i = a->d_ihead; i != NULL; i = i->i_asame) {
+ if (i->i_active == DEVI_MODULE) {
+ ++a_module;
+ }
+ }
+
+ if (!a_module)
+ return 0;
+
+ /* this device attachment is compiled as LKM */
+
+ m = getmodule(a->d_name, M_DEVICE);
+ if (m == NULL)
+ return -1;
+
+ a->d_module = m;
+ STAILQ_INSERT_TAIL(&m->m_deva, a, d_mnext);
+
+ base = a->d_devbase;
+ if (base && base->d_module)
+ ht_insert(m->m_require, base->d_name, base->d_module);
+
+ return 0;
+}
+
+static int
+fixlkm_devi(struct devi *i)
+{
+ struct module *m = NULL;
+ struct devbase *b;
+ struct deva *a;
+ char *instname;
+
+ if (i->i_active != DEVI_MODULE)
+ return 0;
+
+ a = i->i_atdeva;
+ b = i->i_base;
+ if (a && a->d_module)
+ m = a->d_module;
+ else if (b && b->d_module)
+ m = b->d_module;
+
+
+ if (m) {
+ STAILQ_INSERT_TAIL(&m->m_devi, i, i_mnext);
+ }
+ else {
+ /* This instance has its base and attachment in the
+ * kernel */
+#if 0
+ /* make one module for each device instance */
+ m = getmodule(i->i_name, M_DEVICE);
+#else
+ /* pack those device instances into one module */
+ char devi_modname[100];
+
+ snprintf(devi_modname, sizeof devi_modname, "%s_",
+ i->i_base->d_name);
+ m = getmodule(intern(devi_modname), M_DEVICE);
+#endif
+ if (m == NULL)
+ return -1;
+
+ STAILQ_INSERT_TAIL(&m->m_devi, i, i_mnext);
+ }
+ i->i_module = m;
+
+ /* for lkm.provide */
+ if (m->m_type == M_DEVICE) {
+ if (i->i_at)
+ asprintf(&instname, "%s@%s", i->i_name, i->i_at);
+ else
+ instname = __UNCONST(i->i_name);
+ ht_insert(m->m_selecttab, instname, i);
+ }
+
+
+ return 0;
+}
+
+static struct module *
+newmodule(const char *name, enum module_type type)
+{
+ struct module *m;
+
+ m = ecalloc(1, sizeof *m);
+ m->m_name = name;
+ m->m_type = type;
+ STAILQ_INIT(&m->m_base);
+ STAILQ_INIT(&m->m_devi);
+ STAILQ_INIT(&m->m_deva);
+ STAILQ_INIT(&m->m_files);
+ m->m_selecttab = ht_new();
+ m->m_require = ht_new();
+ return m;
+}
+
+static struct module *
+getmodule(const char *name, enum module_type type)
+{
+ struct module *m = NULL;
+ static int anonymous_modules = 0;
+
+ if (name != NULL)
+ m = ht_lookup(moduletab, name);
+ else {
+ char *n;
+ asprintf(&n, "M%03d", anonymous_modules++);
+ name = n;
+ }
+
+ if (m == NULL) {
+ m = newmodule(name, type);
+ ht_insert(moduletab, name, m);
+ return m;
+ }
+
+ if (m->m_type != type) {
+ cfgerror("%s: duplicate module", name);
+ return (NULL);
+ }
+
+ return m;
+}
+
+
+static void
+lkm_select_attr(struct attr *a, void *context)
+{
+ struct module *cur_module = context;
+ struct module *m;
+
+ if (ht_lookup(selecttab, a->a_name)) {
+ /* it's in the kernel. skip */
+ return;
+ }
+
+ /* We need this attribute for cur_module. */
+#if 0
+ printf("%s: %s -> %s\n", __FUNCTION__,
+ cur_module->m_name, a->a_name);
+#endif
+
+ m = ht_lookup(moduletab, a->a_name);
+ if (m == NULL) {
+ m = getmodule(a->a_name, M_ATTRIBUTE);
+ ht_insert(m->m_selecttab, a->a_name, __UNCONST(a->a_name));
+ m->u.m_attr = a;
+ }
+ else if (m == cur_module) {
+ /* no need to record dependency */
+ return;
+ }
+}
+
+static void
+lkm_record_require(struct attr *a, void *context)
+{
+ struct module *cur_module = context;
+
+ if (ht_lookup(selecttab, a->a_name)) {
+ /* it's in the kernel. skip */
+ return;
+ }
+
+#if 0
+ printf("%s: %s -> %s\n", __FUNCTION__,
+ cur_module->m_name, a->a_name);
+#endif
+
+ ht_insert(cur_module->m_require, a->a_name, a);
+}
+
+
+static int
+/*ARGSUSED*/
+lkm_select_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = (struct module *)value;
+
+ switch (m->m_type) {
+ case M_DEVICE:
+ case M_PSEUDO:
+ return lkm_select_device(m, aux);
+ default:
+ if (m->u.m_attr)
+ expandattr(m->u.m_attr, m, aux);
+ }
+
+ return 0;
+}
+
+
+
+static int
+lkm_select_device(struct module *m, void (* attr_func)(struct attr *, void *))
+{
+ struct devbase *d;
+ struct deva *da;
+ struct attr *a;
+ struct nvlist *nv;
+
+ STAILQ_FOREACH(d, &m->m_base, d_mnext) {
+ if (ht_lookup(selecttab, d->d_name) != NULL)
+ continue;
+
+ ht_insert(m->m_selecttab, d->d_name, __UNCONST(d->d_name));
+ for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
+ a = nv->nv_ptr;
+ expandattr(a, m, attr_func);
+ }
+ }
+
+ STAILQ_FOREACH(da, &m->m_deva, d_mnext) {
+ if (ht_lookup(selecttab, da->d_name) != NULL)
+ continue;
+ ht_insert(m->m_selecttab, da->d_name, __UNCONST(da->d_name));
+ for (nv = da->d_attrs; nv != NULL; nv = nv->nv_next) {
+ a = nv->nv_ptr;
+ expandattr(a, m, attr_func);
+ }
+ }
+ return 0;
+}
+
+static void
+fixlkmfiles2(struct filetype *ft, struct nvlist *expr)
+{
+ struct module *m;
+ struct nvlist *p;
+
+ if (ft->fit_nmods == 0) {
+ /* not for modules */
+ }
+ else if (ft->fit_nmods == 1) {
+ /* required by just one module. This file simply
+ * becomes a part of the modules. */
+ m = ft->fit_modules->nv_ptr;
+ STAILQ_INSERT_TAIL(&m->m_files, ft, fit_msame);
+
+ nvfree(ft->fit_modules);
+ ft->fit_modules = NULL;
+ }
+ else {
+ /* This file is required by multiple modules. */
+#if 1
+ /* Merge those modules that share this file into one module */
+ struct module *mmod;
+
+ mmod = getmodule(NULL, M_MERGE);
+ mmod->m_modules = NULL;
+ mmod->u.m_attr = NULL;
+
+ for (p = ft->fit_modules; p; p = p->nv_next) {
+ m = p->nv_ptr;
+ while (m->m_merged)
+ m = m->m_merged;
+ if (m == mmod)
+ continue;
+
+ mmod->m_modules =
+ newnv(m->m_name, NULL, m, 0, mmod->m_modules);
+ m->m_merged = mmod;
+ }
+
+ /* add this file to the merged module */
+ STAILQ_INSERT_TAIL(&mmod->m_files, ft, fit_msame);
+ ft->fit_flags |= FI_MODULE;
+#else
+ /* This is an another way to handle files shared by
+ multiple modules: Create a new module to have
+ shared files. */
+
+ char *expr_str = expr_canonstr(expr);
+ struct module *fg, *m;
+
+ /* make a group of files which are turned on/off by
+ * the same expression. */
+
+ fg = ht_lookup(moduletab, expr_str);
+ if (fg) {
+ free(expr_str);
+ assert(fg->m_type == M_FILEGROUP);
+ }
+ else {
+ /* create a new filegroup */
+ fg = newmodule(expr_str, M_FILEGROUP);
+ assert(fg != NULL);
+ ht_insert(moduletab, expr_str, fg);
+ }
+
+ /* add this file to the filegroup */
+ STAILQ_INSERT_TAIL(&fg->m_files, ft, fit_msame);
+ ft->fit_flags |= FI_MODULE;
+
+ for (p = ft->fit_modules; p; p = p->nv_next) {
+ m = p->nv_ptr;
+ ht_insert(m->m_require, fg->m_name, fg);
+ }
+#endif
+ }
+}
+
+#if 0
+static int
+/*ARGSUSED*/
+fix_filegroup_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = (struct module *)value;
+ char buf[MAXPATHLEN];
+ struct filetype *ft;
+
+ if (m->m_type != M_FILEGROUP)
+ return 0;
+
+ /* currently, this module has a name generated from an
+ * expression. rename it to a normal module name based on the
+ * files included in this filegroup */
+
+ buf[0] = '\0';
+
+ STAILQ_FOREACH(ft, &m->m_files, fit_msame) {
+ /* XXX .o */
+ struct files *fi = (struct files *)ft;
+
+ /* XXX: I know you can optimize this...*/
+ strlcat(buf, "_", sizeof buf);
+ strlcat(buf, fi->fi_base, sizeof buf);
+ }
+
+ m->m_name = estrdup(buf);
+
+ /* Now this module has a new name, but the key in moduletab is
+ * unchanged.
+ */
+ return 0;
+}
+#endif
+
+static int
+/*ARGSUSED*/
+mark_empty_attr_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = (struct module *)value;
+
+ if (m->m_merged == NULL &&
+ m->m_type == M_ATTRIBUTE && m->u.m_attr != NULL &&
+ STAILQ_EMPTY(&m->m_files)) {
+#if 0
+ printf("%s is empty\n", m->u.m_attr->a_name);
+#endif
+ ht_insert(emptyattrtab, m->u.m_attr->a_name,
+ m->u.m_attr);
+ }
+ return 0;
+}
+
+static int
+/*ARGSUSED*/
+fix_merged_cb(const char *key, void *value, void *aux)
+{
+ struct nvlist *p;
+ struct module *m = (struct module *)value;
+ struct module *devmod = NULL;
+ int device = 0;
+
+ if (m->m_type != M_MERGE)
+ return 0;
+
+ if (m->m_merged != NULL)
+ return 0;
+
+ for (p=m->m_modules; p; p = p->nv_next) {
+ struct module *n = p->nv_ptr;
+ if (n->m_type == M_DEVICE) {
+ ++device;
+ devmod = n;
+ }
+ else if (n->m_type == M_MERGE) {
+ struct nvlist *q0, *q1;
+ /* insert module list from *n */
+ q0 = p->nv_next;
+ p->nv_next = q1 = n->m_modules;
+ while (q1->nv_next)
+ q1 = q1->nv_next;
+ q1->nv_next = q0;
+ }
+
+ merge_modules(m, n);
+ }
+
+ /* name the merged module */
+ /* if there is only one device in the merged module, use the
+ * device name for the module. */
+ if (device == 1) {
+ m->m_name = devmod->m_name;
+ }
+ /* if the merged module has only one file, use it for
+ * the module's name */
+ else if (!STAILQ_EMPTY(&m->m_files) &&
+ STAILQ_NEXT(STAILQ_FIRST(&m->m_files), fit_msame) == NULL) {
+ /* XXX */
+ struct files *f = (struct files *)STAILQ_FIRST(&m->m_files);
+ m->m_name = f->fi_base;
+ }
+ else {
+ /* Otherwise, keep autogenerated name such as "M001".
+ FIXME: Maybe better to use the first file name?
+ or, append all file names?
+ */
+ }
+
+ if (device)
+ m->m_type = M_DEVICE;
+ else
+ m->m_type = M_ATTRIBUTE;
+
+ return 0;
+}
+
+/*
+ * Check which file is needed by which modules.
+ */
+int
+fixlkmfiles(void)
+{
+ struct files *fi;
+
+ if (ht_enumerate(moduletab, lkm_fixfile_cb, NULL))
+ return -1;
+
+ TAILQ_FOREACH(fi, &allfiles, fi_next) {
+ fixlkmfiles2(&fi->fi_fit, fi->fi_optx);
+ }
+
+#if 0
+ /* fix filegroup modules */
+ if (ht_enumerate(moduletab, fix_filegroup_cb, NULL))
+ return -1;
+#endif
+
+ if (ht_enumerate(moduletab, fix_merged_cb, NULL))
+ return -1;
+
+ if (ht_enumerate(moduletab, mark_empty_attr_cb, NULL))
+ return -1;
+
+ if (ht_enumerate(moduletab, add_lkm_file_cb, NULL))
+ return -1;
+
+ return 0;
+}
+
+static void
+add_module_for_file(struct filetype *ft, struct module *m)
+{
+ ft->fit_modules = newnv(m->m_name, NULL, m, 0, ft->fit_modules);
+ ft->fit_nmods++;
+}
+
+static int
+/*ARGSUSED*/
+lkm_fixfile_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = (struct module *)value;
+ struct files *fi;
+ struct objects *oi;
+
+ TAILQ_FOREACH(fi, &allfiles, fi_next) {
+ if (fi->fi_flags & (FI_HIDDEN|FI_SEL)) {
+ /* if the files is in the kernel, skip it */
+ continue;
+ }
+
+ if (expr_eval(fi->fi_optx, lkm_fixsel, m)) {
+ /* Mark this file is required by modules */
+
+ add_module_for_file(&fi->fi_fit, m);
+ }
+ }
+
+ TAILQ_FOREACH(oi, &allobjects, oi_next) {
+ if (oi->oi_flags & (FI_HIDDEN|FI_SEL)) {
+ /* if the files is in the kernel, skip it */
+ continue;
+ }
+ if (oi->oi_flags & FI_MODULE) {
+ /* We already know about this file */
+ continue;
+ }
+ if (expr_eval(oi->oi_optx, lkm_fixsel, m)) {
+ /* Mark this file is required by modules */
+ oi->oi_flags |= FI_MODULE;
+
+ STAILQ_INSERT_HEAD(&m->m_files, &oi->oi_fit, fit_msame);
+ }
+ }
+
+ return 0;
+}
+
+static int
+lkm_fixsel(const char *name, void *context)
+{
+ struct module *m = context;
+ return ht_lookup(selecttab, name) != NULL ||
+ ht_lookup(m->m_selecttab, name) != NULL;
+}
+
+static int
+/*ARGSUSED*/
+add_lkm_file_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = (struct module *)value;
+ struct files *fi;
+ char *pathname;
+
+ assert(m->m_lkmfile == NULL);
+
+ if (m->m_merged != NULL) {
+ /* This module has been merged into the other module. */
+ return 0;
+ }
+
+ switch (m->m_type) {
+ case M_DEVICE:
+ if (STAILQ_EMPTY(&m->m_files)) {
+ if (!STAILQ_EMPTY(&m->m_devi)) {
+ /* devi only module */
+ }
+ else if (!STAILQ_EMPTY(&m->m_base)) {
+ /* config staff only */
+ }
+ else {
+ /* we won't create this module if this
+ * module is empty. */
+ return 0;
+ }
+ }
+ break;
+ case M_ATTRIBUTE:
+ default:
+ if (STAILQ_EMPTY(&m->m_files))
+ return 0;
+ }
+
+ /* add _MODULE_lkm.c */
+ asprintf(&pathname, "%s/%s/%s%s/_%s_lkm.c",
+ builddir, KMODDIR,
+ m->m_name, KMODWORK_SUFFIX, m->m_name);
+
+ fi = addfile(pathname, NULL, FI_MODULE, NULL);
+ if (fi == NULL) {
+ cfgerror("can't create file %s", pathname);
+ return -1;
+ }
+
+ m->m_lkmfile = fi;
+
+ return 0;
+}
+
+/*
+ * Try to reduce the number of LKMs by packing many modules into one.
+ * This routine is called if option -G is given.
+ */
+int
+packlkms(void)
+{
+ /* not yet */
+ return 0;
+}
+
+/*
+ * merge module m1 into module m0
+ */
+int
+merge_modules(struct module *m0, struct module *m1)
+{
+ if (m1->m_type == M_DEVICE) {
+
+ STAILQ_APPEND(&m0->m_base, &m1->m_base, d_mnext);
+ STAILQ_INIT(&m1->m_base);
+ STAILQ_APPEND(&m0->m_deva, &m1->m_deva, d_mnext);
+ STAILQ_INIT(&m1->m_deva);
+ STAILQ_APPEND(&m0->m_devi, &m1->m_devi, i_mnext);
+ STAILQ_INIT(&m1->m_devi);
+ }
+
+ ht_concat(m0->m_selecttab, m1->m_selecttab, 0);
+ ht_concat(m0->m_require, m1->m_require, 0);
+
+ /* append file list */
+ STAILQ_APPEND(&m0->m_files, &m1->m_files, fit_msame);
+ STAILQ_INIT(&m1->m_files);
+
+ m1->m_merged = m0;
+ return 0;
+}
+
+/*
+ * check device major numbers for LKMs
+ */
+int
+fixlkmdevsw(void)
+{
+ int er = 0;
+
+ /* XXX: CodeMe! */
+
+ return er;
+}
+
+/*
+ *
+ */
+int
+mklkms(void)
+{
+ char moddir[MAXPATHLEN];
+
+ if (ht_isempty(moduletab)) {
+ return 0;
+ }
+
+ snprintf(moddir, sizeof moddir, "%s/%s", builddir, KMODDIR);
+ make_directory(moddir);
+ return ht_enumerate(moduletab, lkm_make_files_cb, NULL);
+}
+
+static int
+/*ARGSUSED*/
+lkm_make_files_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = value;
+ char moddir[MAXPATHLEN];
+
+ if (m->m_lkmfile == NULL)
+ return 0;
+
+ snprintf(moddir, sizeof moddir, "%s/%s/%s%s",
+ builddir, KMODDIR, m->m_name, KMODWORK_SUFFIX);
+ make_directory(moddir);
+
+ return lkm_make_makefile(m, moddir) || lkm_make_lkmfile(m, moddir);
+}
+
+static int
+lkm_make_makefile(struct module *m, const char *moddir)
+{
+ static const struct makefile_constructs c[] = {
+ { "OBJS", lkm_emitobjs },
+ { "SRCS", lkm_emitsrcs },
+ { "KMOD", lkm_emitkmod },
+ { NULL, NULL }
+ };
+
+ return mkmakefile_common(c, ".lkm", moddir, m);
+}
+
+static void
+lkm_lkmfile_header(struct module *m, struct files *f,
+ const char *conffile, FILE *fp)
+{
+ fprintf(fp, "/*\n"
+ " * MACHINE GENERATED: DO NOT EDIT\n"
+ " *\n"
+ " * %s, from \"%s\"\n"
+ " */\n\n"
+ "#include <sys/param.h>\n"
+ "#include <sys/conf.h>\n"
+ "#include <sys/device.h>\n"
+ "#include <sys/mount.h>\n"
+ "#include <sys/lkm.h>\n"
+ "\n\n",
+
+ f->fi_base, conffile);
+}
+
+
+static void
+lkm_devsw(struct module *m, FILE *fp, char **entry_func_name)
+{
+ struct devbase *d;
+ struct devm *dm;
+ int bmaj, cmaj;
+ int count = 0;
+ char bdevbuf[30], cdevbuf[30];
+ char *bdev, *cdev;
+
+ STAILQ_FOREACH(d, &m->m_base, d_mnext) {
+ bmaj = cmaj = -1;
+
+ dm = ht_lookup(bdevmtab, d->d_name);
+ if (dm && dm->dm_active != DEVM_INKERNEL)
+ bmaj = dm->dm_bmajor;
+
+ dm = ht_lookup(cdevmtab, d->d_name);
+ if (dm && dm->dm_active != DEVM_INKERNEL)
+ cmaj = dm->dm_cmajor;
+
+ if (bmaj < 0 && cmaj < 0)
+ continue;
+
+ if (count++ <= 0) {
+ asprintf(entry_func_name, "%s_devsw", dm->dm_name);
+ fprintf(fp,
+ "\nstatic int\n"
+ "%s(struct lkm_table *lkmtp, int cmd)\n"
+ "{\n"
+ "\tint b, c, er;\n",
+ *entry_func_name);
+ }
+
+ if (cmaj < 0)
+ cdev = "NULL";
+ else {
+ snprintf(cdevbuf, sizeof cdevbuf, "&%s_cdevsw",
+ d->d_name);
+ fprintf(fp, "\textern struct cdevsw %s;\n", cdevbuf+1);
+ cdev = cdevbuf;
+ }
+
+ if (bmaj < 0)
+ bdev = "NULL";
+ else {
+ snprintf(bdevbuf, sizeof bdevbuf, "&%s_bdevsw",
+ d->d_name);
+ fprintf(fp, "\textern struct bdevsw %s;\n", bdevbuf+1);
+ bdev = bdevbuf;
+ }
+
+ fprintf(fp, "\tswitch(cmd) {\n\tcase LKM_E_LOAD:\n");
+
+ fprintf(fp,
+ "\t\tb = %d; c = %d;\n"
+ "\t\ter = devsw_attach(\"%s\", %s, &b, %s, &c);\n"
+ "\t\tif (er) return er;\n"
+ "\t\tbreak;\n"
+ "\tcase LKM_E_UNLOAD:\n"
+ "\t\tdevsw_detach(%s, %s);\n"
+ "\t\tbreak;\n"
+ "\t}\n",
+ bmaj, cmaj, d->d_name, bdev, cdev,
+ bdev, cdev);
+ }
+
+ if (count > 0) {
+ fprintf(fp, "\n\treturn 0;\n}\n\n");
+ }
+
+}
+
+static int
+lkm_make_lkmfile(struct module *m, const char *moddir)
+{
+ FILE *fp;
+ char tmpname[MAXPATHLEN];
+ struct files *f = m->m_lkmfile;
+ char *entry_func = "lkm_nofunc";
+ struct emit_require_args args;
+
+ if (f == NULL)
+ return 0;
+
+#if 0
+ if (m->m_type == M_DEVICE &&
+ (STAILQ_EMPTY(&m->m_devi) && STAILQ_EMPTY(&m->m_base)) )
+ return 0;
+#endif
+
+ snprintf(tmpname, sizeof tmpname, "%s/tmp_lkm.c", moddir);
+
+ if ((fp = fopen(tmpname, "w")) == NULL) {
+ warn("cannot write %s", tmpname);
+ return 1;
+ }
+
+ switch (m->m_type) {
+ case M_DEVICE:
+ lkm_emit_ioconf(m, f, fp);
+ lkm_devsw(m, fp, &entry_func);
+ break;
+ case M_PSEUDO:
+ lkm_emit_ioconf_pseudo(m, f, fp, &entry_func);
+ break;
+ default:
+ lkm_lkmfile_header(m, f, conffile, fp);
+
+ fprintf(fp, "MOD_MISC(\"%s\");\n", m->m_name);
+ }
+
+ fprintf(fp,
+ "int __%s_lkmentry(struct lkm_table*, int, int);\n"
+ "int\n"
+ "__%s_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)\n"
+ "{ DISPATCH(lkmtp, cmd, ver, %s, lkm_nofunc, lkm_nofunc); }\n"
+ "__weak_alias(%s_lkmentry, __%s_lkmentry);\n",
+
+ m->m_name,
+ m->m_name,
+ entry_func,
+ m->m_name, m->m_name);
+
+ /* emit required module list */
+ fprintf(fp,
+ "\n\nasm(\" .section \\\".note.netbsd.lkm.require\\\",\\\"\\\"\\n\"\n");
+ args.fp = fp;
+ args.cur_module = m;
+ ht_enumerate(m->m_require, lkm_emitrequire_cb, &args);
+ fprintf(fp, " \" .byte 0\\n\");\n");
+
+ /* emit provided attributes */
+ fprintf(fp,
+ "\n\nasm(\" .section \\\".note.netbsd.lkm.provide\\\",\\\"\\\"\\n\"\n");
+ ht_enumerate(m->m_selecttab, lkm_emitprovide_cb, fp);
+ fprintf(fp, " \" .byte 0\\n\");\n");
+
+ fclose(fp);
+
+ return (moveifchanged(tmpname, f->fi_path));
+}
+
+static int
+lkm_emit_ioconf(struct module *m, struct files *f, FILE *fp)
+{
+ char cfdataname[80];
+ struct devi *i;
+ struct devbase *d = NULL;
+ struct deva *da;
+ struct devi *di;
+ struct nvlist *att_list = NULL;
+ struct nvlist *nv;
+
+ ioconf_emithdr(fp, f->fi_tail);
+
+ fprintf(fp, "#include <sys/lkm.h>\n\n");
+
+ STAILQ_FOREACH(d, &m->m_base, d_mnext) {
+ /* This module has the devbase */
+ ioconf_emit_ref_iattrs(d, fp);
+ ioconf_emit_cfdriver(d, fp);
+
+ for (da = d->d_ahead; da != NULL; da = da->d_bsame) {
+ if (da->d_name == d->d_name) {
+ /* the devbase is also an attachment */
+ att_list = newnv(da->d_name, NULL, da, 0,
+ att_list);
+
+ fprintf(fp, "extern struct cfattach %s_ca;\n",
+ da->d_name);
+ }
+ }
+ }
+
+ STAILQ_FOREACH(da, &m->m_deva, d_mnext) {
+ att_list = newnv(da->d_name, NULL, da, 0, att_list);
+ }
+ fprintf(fp, "\n\n");
+
+ if (!STAILQ_EMPTY(&m->m_devi)) {
+ lkm_emit_parents(m, fp);
+ fprintf(fp, "\n");
+ lkm_emit_loc(m, fp);
+ fprintf(fp, "\n");
+ }
+
+ snprintf(cfdataname, sizeof cfdataname, "%s_cfdata", m->m_name);
+ ioconf_cfdata_start(fp, cfdataname);
+
+ STAILQ_FOREACH(i, &m->m_devi, i_mnext) {
+ ioconf_cfdata_entry(fp, i);
+ }
+
+ ioconf_cfdata_end(fp, cfdataname);
+
+ fprintf(fp, "static struct cfdriver *%s_cfdrivers[] = {\n",
+ m->m_name);
+ STAILQ_FOREACH(d, &m->m_base, d_mnext)
+ fprintf(fp, "\t&%s_cd,\n", d->d_name);
+ fprintf(fp, "\tNULL\n};\n");
+
+ if (att_list != NULL) {
+ for (nv = att_list; nv; nv = nv->nv_next) {
+ fprintf(fp, "extern struct cfattach %s_ca;\n", nv->nv_name);
+ }
+ fprintf(fp, "static struct cfattach *%s_cfattachs[] = {\n",
+ m->m_name);
+ for (nv = att_list; nv; nv = nv->nv_next) {
+ fprintf(fp, "\t&%s_ca,\n", nv->nv_name);
+ }
+ fprintf(fp, "\tNULL\n};\n");
+ }
+
+ /* We want devbase name for this module */
+ d = STAILQ_FIRST(&m->m_base);
+ if (d == NULL) {
+ da = STAILQ_FIRST(&m->m_deva);
+ if (da)
+ d = da->d_devbase;
+ if (d == NULL) {
+ di = STAILQ_FIRST(&m->m_devi);
+ if (di)
+ d = di->i_base;
+ }
+ }
+
+ if (d == NULL) {
+ cfgerror("can't get device base name for module %s",
+ m->m_name);
+ }
+ else {
+ fprintf(fp,
+ "static const struct cfattachlkminit %s_cfattachinit[] = {\n",
+ m->m_name);
+ if (att_list != NULL) {
+ fprintf(fp,
+ "\t{\"%s\", %s_cfattachs},\n",
+ d->d_name, m->m_name);
+ }
+ fprintf(fp,
+ "\t{NULL, NULL}\n"
+ "};\n");
+ }
+
+ fprintf(fp,
+ "int __%s_lkmentry(struct lkm_table*, int, int);\n"
+ "MOD_DRV(\"%s\", %s_cfdrivers, %s_cfattachinit, %s_cfdata);\n",
+ m->m_name,
+ m->m_name, m->m_name, m->m_name, m->m_name);
+
+ if (att_list)
+ nvfreel(att_list);
+
+ return 0;
+}
+
+static int
+lkm_emit_ioconf_pseudo(struct module *m, struct files *f, FILE *fp, char **entry_func_ret)
+{
+ char cfdataname[80];
+ struct devbase *d = NULL;
+
+ ioconf_emithdr(fp, f->fi_tail);
+
+ fprintf(fp, "#include <sys/lkm.h>\n\n");
+
+ d = STAILQ_FIRST(&m->m_base);
+ assert(d != NULL);
+
+ snprintf(cfdataname, sizeof cfdataname, "%s_cfdata", m->m_name);
+
+ if (devbase_has_instances(d, WILD)) {
+ ioconf_emit_ref_iattrs(d, fp);
+ ioconf_emit_cfdriver(d, fp);
+
+ fprintf(fp, "static struct cfdriver *%s_cfdrivers[] = {\n",
+ m->m_name);
+ fprintf(fp, "\t&%s_cd,\n", d->d_name);
+ fprintf(fp, "\tNULL\n};\n");
+
+ ioconf_cfdata_start(fp, cfdataname);
+ ioconf_cfdata_end(fp, cfdataname);
+
+ fprintf(fp,
+ "static const struct cfattachlkminit %s_cfattachinit[] = {\n",
+ d->d_name);
+ fprintf(fp,
+ "\t{NULL, NULL}\n"
+ "};\n");
+
+ fprintf(fp,
+ "MOD_DRV(\"%s\", %s_cfdrivers, %s_cfattachinit, %s_cfdata);\n",
+ d->d_name, d->d_name, d->d_name, d->d_name);
+ }
+ else {
+ fprintf(fp,
+ "MOD_MISC(\"%s\");\n",
+ d->d_name);
+ }
+
+ fprintf(fp,
+ "static int __%s_load(struct lkm_table *lkmtp, int cmd)\n"
+ "{\n"
+ "\textern void %sattach(int);\n"
+ "\t%sattach(%d);\n"
+ "\treturn 0;\n"
+ "}\n\n",
+ d->d_name,
+ d->d_name, d->d_name, d->d_umax);
+
+ if (entry_func_ret) {
+ asprintf(entry_func_ret, "__%s_load", d->d_name);
+ }
+
+ return 0;
+}
+
+
+static void
+lkm_emit_parents(struct module *m, FILE *fp)
+{
+ struct devi *i;
+ struct nvlist *nv, *list = NULL;
+ struct pspec *ps;
+
+
+ STAILQ_FOREACH(i, &m->m_devi, i_mnext) {
+ ps = i->i_pspec;
+ if (ps == NULL)
+ continue;
+ /* Check if we already emit this pspec */
+
+ for (nv = list; nv; nv = nv->nv_next)
+ if (nv->nv_ptr == ps)
+ break;
+
+ if (nv)
+ continue;
+
+ ioconf_emit_pspec(fp, ps, 1);
+
+ /* remember the pspec */
+ list = newnv("", NULL, ps, 0, list);
+ }
+
+ if (list)
+ nvfreel(list);
+}
+
+static void
+lkm_emit_loc(struct module *m, FILE *fp)
+{
+ struct pspec *ps;
+ struct devi *i;
+ int l, k;
+ int n = 0;
+
+ fprintf(fp, "\nstatic int loc[] = {");
+
+ STAILQ_FOREACH(i, &m->m_devi, i_mnext) {
+ if ((ps = i->i_pspec) != NULL &&
+ (l = ps->p_iattr->a_loclen) > 0) {
+
+ if (n == 0)
+ fprintf(fp, "\n");
+ fprintf(fp, "\t/* %d */\t", n);
+ for (k = 0; k < l; ++k) {
+ fprintf(fp, "%s, ", i->i_locs[k]);
+ }
+ fprintf(fp, "\n");
+
+ i->i_locoff = n;
+ n += l;
+ }
+ }
+
+ if (n > 0) {
+ fprintf(fp, "}; /* %d */\n\n", n);
+ }
+ else {
+ fprintf(fp, " -1 };\n");
+ }
+}
+
+void
+/*ARGSUSED*/
+emitkmod(FILE *fp, void *aux)
+{
+ if (ht_isempty(moduletab)) {
+ fprintf(fp, "# No LKMs\n");
+ return;
+ }
+
+ fprintf(fp, "MODULES= \\\n");
+ ht_enumerate(moduletab, lkm_emit_modulelist_cb, fp);
+ fprintf(fp, "\n");
+
+#if 0
+ ht_enumerate(moduletab, lkm_emit_moduledefs_cb, fp);
+
+ fprintf(fp,
+ "\n"
+ ".if exists(\"$S/arch/%s/conf/Makefile.kmod.inc.%s\")\n"
+ ".include \"$S/arch/%s/conf/Makefile.kmod.inc.%s\"\n"
+ ".elif exists(\"$S/arch/%s/conf/Makefile.kmod.inc.%s\")\n"
+ ".include \"$S/arch/%s/conf/Makefile.kmod.inc.%s\"\n"
+ ".else\n"
+ ".include \"$S/conf/Makefile.kmod.inc\"\n"
+ ".endif\n",
+ machine, machine, machine, machine,
+ machinearch, machinearch, machinearch, machinearch);
+#endif
+}
+
+static int
+/*ARGSUSED*/
+lkm_emit_modulelist_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = (struct module *)value;
+ FILE *fp = aux;
+
+ if (m->m_merged != NULL)
+ return 0;
+
+ if (m_empty(m))
+ return 0;
+
+ fprintf(fp, "\t%s \\\n", m->m_name);
+
+ return 1;
+}
+
+#if 0
+static int
+/*ARGSUSED*/
+lkm_emit_moduledefs_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = (struct module *)value;
+ FILE *fp = aux;
+ struct filetype *f;
+ int has_o = 0;
+
+ if (m_empty(m)) {
+ fprintf(fp, "#MODULE.%s: no files for module %s\n",
+ m->m_name, m->m_name);
+ return 0;
+ }
+
+ fprintf(fp, "MODULE.%s.SRCS=\t", m->m_name);
+
+ STAILQ_FOREACH(f, &m->m_files, fit_msame) {
+ if (f->fit_path[0] == '/')
+ fprintf(fp, "%s ", f->fit_path);
+ else
+ fprintf(fp, "${S}/%s ", f->fit_path);
+
+ if (f->fit_lastc == 'o')
+ ++has_o;
+ }
+ if (m->m_lkmfile)
+ fprintf(fp, "%s", m->m_lkmfile->fi_path);
+ fprintf(fp, "\n");
+
+ if (!has_o)
+ return 0;
+
+ STAILQ_FOREACH(f, &m->m_files, fit_msame) {
+ if (f->fit_lastc != 'o')
+ continue;
+ fprintf(fp, "OBJFILE_%s_MODULE=%s\n",
+ f->fit_path, m->m_name);
+ }
+
+ return 0;
+}
+#endif
+
+static void
+lkm_emitkmod(FILE *fp, void *aux)
+{
+ struct module *m = aux;
+
+ /* .LKM is appended to module name to avoid conflict in case
+ we have MODULE.c */
+ fprintf(fp, "KMOD=\t%s\n", m->m_name);
+}
+
+static void
+lkm_emitobjs(FILE *fp, void *aux)
+{
+ struct module *m = aux;
+ struct filetype *ft;
+ const char *sep;
+
+ if (m_empty(m)) {
+ fprintf(fp, "# no files for module %s\n",
+ m->m_name);
+ return;
+ }
+
+ fprintf(fp, "OBJS=\t");
+ sep = "";
+ STAILQ_FOREACH(ft, &m->m_files, fit_msame) {
+ if (ft->fit_lastc != 'o')
+ continue;
+ fprintf(fp, "%s%s", sep, ft->fit_path);
+ sep = "\t\\\n\t";
+ }
+ fprintf(fp, "\n");
+}
+
+static int
+lkm_emitpath_cb(const char *key, void *value, void *aux)
+{
+ FILE *fp = aux;
+ if (*key == '/')
+ fprintf(fp, "%s ", key);
+ else
+ fprintf(fp, "${S}/%s ", key);
+ return 0;
+}
+
+static void
+lkm_emitsrcs(FILE *fp, void *aux)
+{
+ struct module *m = aux;
+ struct filetype *ft;
+ struct files *f;
+ const char *sep;
+ struct hashtab *ht;
+
+ if (m_empty(m)) {
+ fprintf(fp, "# no files for module %s\n",
+ m->m_name);
+ return;
+ }
+
+ /* set .PATH for sources */
+ ht = ht_new();
+ STAILQ_FOREACH(ft, &m->m_files, fit_msame) {
+ f = (struct files *)ft;
+ char buf[MAXPATHLEN];
+
+ if (ft->fit_lastc == 'o')
+ continue;
+
+ if (f->fi_path == f->fi_tail) {
+ /* No directory part */
+ continue;
+ }
+ strlcpy(buf, f->fi_path,
+ MIN(sizeof buf, f->fi_tail - f->fi_path));
+ ht_insert(ht, intern(buf), f);
+ }
+ if (!ht_isempty(ht)) {
+ fprintf(fp, ".PATH: ");
+ ht_enumerate(ht, lkm_emitpath_cb, fp);
+ fprintf(fp, "\n");
+ }
+ ht_free(ht);
+
+ fprintf(fp, "SRCS=\t");
+ sep = "";
+ STAILQ_FOREACH(ft, &m->m_files, fit_msame) {
+ if (ft->fit_lastc == 'o')
+ continue;
+ f = (struct files *)ft;
+ fprintf(fp, "%s%s", sep, f->fi_tail);
+ sep = "\t\\\n\t";
+ }
+
+ if (m->m_lkmfile)
+ fprintf(fp, "%s%s", sep, m->m_lkmfile->fi_tail);
+ fprintf(fp, "\n");
+}
+
+
+
+static int
+/*ARGSUSED*/
+lkm_emitrequire_cb(const char *key, void *value, void *aux)
+{
+ struct emit_require_args *args = aux;
+ struct module *m = value;
+
+#if 0
+ printf("%s: %s -> %s\n", __FUNCTION__, args->cur_module->m_name, m->m_name);
+#endif
+
+ if (!ht_lookup(emptyattrtab, m->m_name) &&
+ !ht_lookup(args->cur_module->m_selecttab, m->m_name))
+ fprintf(args->fp, " \"\t.asciz \\\"%s\\\"\\n\"\n", m->m_name);
+ return 0;
+}
+
+static int
+/*ARGSUSED*/
+lkm_emitprovide_cb(const char *key, void *value, void *aux)
+{
+ FILE *fp = aux;
+
+ fprintf(fp, " \"\t.asciz \\\"%s\\\"\\n\"\n", key);
+ return 0;
+}
+
+
+#if 0
+static int
+for_all_module_files(struct module *m,
+ int (* fn)(struct files *, struct module *, void *),
+ void *arg)
+{
+ struct files *fi;
+ struct module *m2;
+
+ TAILQ_FOREACH(fi, &allfiles, fi_next) {
+ if (STAILQ_EMPTY(&fi->fi_modules))
+ continue;
+ STAILQ_FOREACH(m2, &fi->fi_modules, m_filenext) {
+ if (m2 == m) {
+ if (fn(fi, m, arg) != 0)
+ return 1;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+static int
+/*ARGSUSED*/
+dump_module_cb2(const char *key, void *value, void *aux)
+{
+ printf("%s=%p ", key, value);
+ return 0;
+}
+
+static int
+/*ARGSUSED*/
+dump_module_cb(const char *key, void *value, void *aux)
+{
+ struct module *m = (struct module *)value;
+ struct devbase *d;
+ struct devi *i;
+ struct deva *a;
+ struct filetype *f;
+
+ printf("module %p %s type=%d\n", m, m->m_name, m->m_type);
+ printf(" base=");
+ STAILQ_FOREACH(d, &m->m_base, d_mnext)
+ printf("%p(%s) ", d, d->d_name);
+ printf(" deva=");
+ STAILQ_FOREACH(a, &m->m_deva, d_mnext) {
+ printf("%p(%s) ", a, a->d_name);
+ }
+ printf(" devis=");
+ STAILQ_FOREACH(i, &m->m_devi, i_mnext) {
+ printf("%p(%s) ", i, i->i_name);
+ }
+ printf("\n selections: ");
+
+ ht_enumerate(m->m_selecttab, dump_module_cb2, NULL);
+ printf("\n files: ");
+
+ STAILQ_FOREACH(f, &m->m_files, fit_msame) {
+ printf("%s ", f->fit_path);
+ }
+ printf("\n requires: ");
+
+ ht_enumerate(m->m_require, dump_module_cb2, NULL);
+ printf("\n");
+ return 0;
+}
+
+void
+dump_module_devis(void)
+{
+ struct devi *i;
+
+ printf("================\n");
+ TAILQ_FOREACH(i, &alldevi, i_next) {
+ if (i->i_module || i->i_active == DEVI_MODULE) {
+ printf("devi %p %s i_module=%p i_active=%d\n",
+ i, i->i_name, i->i_module, i->i_active);
+ }
+ else {
+ printf("devi %s is not module\n", i->i_name);
+ }
+ }
+
+ ht_enumerate(moduletab, dump_module_cb, NULL);
+}
Index: hash.c
===================================================================
--- hash.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ hash.c (.../tags/patch-1-rc1) (revision 51)
@@ -315,3 +315,37 @@
}
return rval;
}
+
+/*
+ * return 1 if the hash table is empty.
+ */
+int
+ht_isempty(struct hashtab *ht)
+{
+ return ht->ht_used == 0;
+}
+
+/*
+ * concat two hash tables
+ */
+struct concat_arg {
+ struct hashtab *ht;
+ int replace;
+};
+
+static int
+concat_cb(const char *name, void *value, void *arg)
+{
+ struct concat_arg *a = arg;
+
+ return ht_insrep(a->ht, name, value, a->replace);
+}
+
+int
+ht_concat(struct hashtab *ht0, struct hashtab *ht1, int replace)
+{
+ struct concat_arg a;
+ a.replace = replace;
+ a.ht = ht0;
+ return ht_enumerate(ht1, concat_cb, &a);
+}
Index: main.c
===================================================================
--- main.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ main.c (.../tags/patch-1-rc1) (revision 51)
@@ -82,6 +82,7 @@
int vflag; /* verbose output */
int Pflag; /* pack locators */
int Lflag; /* lint config generation */
+int Gflag; /* reduce the number of LKMs */
int yyparse(void);
@@ -110,7 +111,6 @@
static int mksymlinks(void);
static int mkident(void);
static int devbase_has_dead_instances(const char *, void *, void *);
-static int devbase_has_any_instance(struct devbase *, int, int, int);
static int check_dead_devi(const char *, void *, void *);
static void kill_orphans(void);
static void do_kill_orphans(struct devbase *, struct attr *,
@@ -120,7 +120,6 @@
static const char *strtolower(const char *);
void defopt(struct hashtab *ht, const char *fname,
struct nvlist *opts, struct nvlist *deps, int obs);
-
#define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE"
#define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG"
@@ -147,7 +146,7 @@
pflag = 0;
xflag = 0;
- while ((ch = getopt(argc, argv, "DLPgpvb:s:x")) != -1) {
+ while ((ch = getopt(argc, argv, "DGLPgpvb:s:x")) != -1) {
switch (ch) {
#ifndef MAKE_BOOTSTRAP
@@ -156,6 +155,9 @@
break;
#endif
+ case 'G':
+ Gflag = 1;
+ break;
case 'L':
Lflag = 1;
break;
@@ -280,6 +282,8 @@
nextmkopt = &mkoptions;
nextappmkopt = &appmkoptions;
nextfsopt = &fsoptions;
+ moduletab = ht_new();
+ emptyattrtab = ht_new();
/*
* Handle profiling (must do this before we try to create any
@@ -363,7 +367,7 @@
/*
* Select devices and pseudo devices and their attributes
*/
- if (fixdevis())
+ if (fixdevis() || fixlkmdevs())
stop();
/*
@@ -384,9 +388,20 @@
stop();
/*
+ * Fix files for LKMs, then group the files into modules.
+ */
+ if (fixlkmfiles())
+ stop();
+
+ if (Gflag) {
+ if (packlkms())
+ stop();
+ }
+
+ /*
* Fix device-majors.
*/
- if (fixdevsw())
+ if (fixdevsw() || fixlkmdevsw())
stop();
/*
@@ -421,7 +436,8 @@
* Ready to go. Build all the various files.
*/
if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() ||
- mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident())
+ mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident() ||
+ mklkms())
stop();
(void)printf("Build directory is %s\n", builddir);
(void)printf("Don't forget to run \"make depend\"\n");
@@ -481,7 +497,7 @@
if (a->a_iattr)
panic("do_depend(%s): dep `%s' is an iattr",
nv->nv_name, a->a_name);
- expandattr(a, selectattr);
+ expandattr(a, NULL, selectattr);
} else {
if (ht_lookup(opttab, nv->nv_name) == NULL)
addoption(nv->nv_name, NULL);
@@ -878,7 +894,7 @@
* file system type. The name is then treated like a standard option.
*/
void
-addfsoption(const char *name)
+addfsoption(const char *name, int module)
{
const char *n;
@@ -888,6 +904,12 @@
return;
}
+ /* XXX */
+ if (module) {
+ cfgerror("module for file-system %s: not supported yet", name);
+ return;
+ }
+
/*
* Convert to lower case. This will be used in the select
* table, to verify root file systems.
@@ -1206,11 +1228,7 @@
if (builddir == NULL)
builddir = defbuilddir;
- if (stat(builddir, &st) == -1) {
- if (mkdir(builddir, 0777) == -1)
- errx(EXIT_FAILURE, "cannot create %s", builddir);
- } else if (!S_ISDIR(st.st_mode))
- errx(EXIT_FAILURE, "%s is not a directory", builddir);
+ make_directory(builddir);
if (chdir(builddir) == -1)
err(EXIT_FAILURE, "cannot change to %s", builddir);
if (stat(srcdir, &st) == -1)
@@ -1519,16 +1537,22 @@
* may have special considerations regarding ignored instances.
*/
-static int
+int
devbase_has_any_instance(struct devbase *dev, int unit, int state, int level)
{
struct deva *da;
struct devi *i;
if (dev->d_ispseudo) {
- if (dev->d_ihead != NULL)
- return 1;
- else if (state != DEVI_IGNORED)
+ if (dev->d_ihead != NULL) {
+ i = dev->d_ihead;
+ if (state == DEVI_MODULE && i->i_module)
+ return 1;
+ if (state == DEVI_ACTIVE && i->i_module == NULL)
+ return 1;
+ }
+
+ if (state != DEVI_IGNORED)
return 0;
if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL)
return 0;
@@ -1538,6 +1562,7 @@
for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
for (i = da->d_ihead; i != NULL; i = i->i_asame)
if ((i->i_active == DEVI_ACTIVE ||
+ i->i_active == DEVI_MODULE ||
i->i_active == state) &&
(unit == WILD || unit == i->i_unit ||
i->i_unit == STAR))
@@ -1613,7 +1638,9 @@
*/
if (d->d_ispseudo) {
if (d->d_ihead != NULL)
- d->d_ihead->i_active = active = DEVI_ACTIVE;
+ d->d_ihead->i_active = active =
+ d->d_ihead->i_module != NULL ?
+ DEVI_MODULE : DEVI_ACTIVE;
else {
if (ht_lookup(deaddevitab, d->d_name) != NULL)
active = DEVI_IGNORED;
@@ -1623,41 +1650,84 @@
} else {
int seen = 0;
- for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
- for (j = i; j != NULL; j = j->i_alias) {
- p = j->i_pspec;
- if ((p == NULL && at == NULL) ||
- (p != NULL && p->p_iattr == at &&
- (p->p_atdev == NULL ||
- p->p_atdev == parent))) {
- if (p != NULL &&
- !devbase_has_any_instance(parent,
- p->p_atunit, state, j->i_level))
- continue;
+#define FOR_ALL_ALIASES(i, j, d) \
+ for (i = d->d_ihead; i != NULL; i = i->i_bsame) \
+ for (j = i; j != NULL; j = j->i_alias)
+
+ FOR_ALL_ALIASES(i, j, d) {
+ p = j->i_pspec;
+ if ((p == NULL && at == NULL) ||
+ (p != NULL && p->p_iattr == at &&
+ (p->p_atdev == NULL ||
+ p->p_atdev == parent))) {
+ if (p != NULL &&
+ !devbase_has_any_instance(parent,
+ p->p_atunit, state, j->i_level))
+ continue;
+ /*
+ * There are Fry-like devices which can
+ * be their own grand-parent (or even
+ * parent, like uhub). We don't want
+ * to loop, so if we've already reached
+ * an instance for one reason or
+ * another, stop there.
+ */
+ if (j->i_active == DEVI_ACTIVE ||
+ j->i_active == DEVI_MODULE ||
+ j->i_active == state) {
/*
- * There are Fry-like devices which can
- * be their own grand-parent (or even
- * parent, like uhub). We don't want
- * to loop, so if we've already reached
- * an instance for one reason or
- * another, stop there.
+ * Device has already been
+ * seen. However it might
+ * have siblings who still
+ * have to be activated or
+ * orphaned.
*/
- if (j->i_active == DEVI_ACTIVE ||
- j->i_active == state) {
- /*
- * Device has already been
- * seen. However it might
- * have siblings who still
- * have to be activated or
- * orphaned.
- */
- seen = 1;
- continue;
- }
+ seen = 1;
+ continue;
+ }
+
+ if (state == DEVI_MODULE &&
+ j->i_module == NULL) {
+
+ /* We are looking at children
+ of a LKM device. leave
+ this non-LKM device as
+ orphan.
+ */
+ printf("Leave as orphan %s\n",
+ j->i_name);
+ continue;
+ }
+
+ if (j->i_module) {
+ j->i_active =
+ state == DEVI_ACTIVE ?
+ DEVI_MODULE : state;
+ if (active != DEVI_ACTIVE)
+ active = j->i_active;
+ }
+ else {
j->i_active = active = state;
- if (p != NULL)
- p->p_active = state;
}
+
+ if (p == NULL)
+ continue;
+
+ /* change p->p_active:
+ ORPHAN->ACTIVE or MODULE
+ ACTIVE->MODULE */
+
+ if (p->p_active == DEVI_ORPHAN)
+ p->p_active = active;
+ else {
+#if 0
+ printf("%s: p_active: %d %d\n",
+ p->p_iattr->a_name,
+ p->p_active, active);
+#endif
+ if (active == DEVI_ACTIVE)
+ p->p_active = active;
+ }
}
}
/*
@@ -1686,10 +1756,19 @@
}
}
+ if (active == DEVI_MODULE)
+ active = DEVI_ACTIVE;
+
for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
a = nv->nv_ptr;
- for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next)
+ for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) {
+#if 0
+ struct devbase *b = nv1->nv_ptr;
+ printf(" attr %s=>dev %s state/active=%d/%d\n",
+ a->a_name, b->d_name, state, active);
+#endif
do_kill_orphans(nv1->nv_ptr, a, d, active);
+ }
}
}
@@ -1704,5 +1783,31 @@
static void
kill_orphans(void)
{
+
ht_enumerate(devroottab, kill_orphans_cb, NULL);
}
+
+
+#if 0
+/*----------------------------------------------------------------*/
+static void
+find_orphan_modules(void)
+{
+ struct devi *i;
+
+ TAILQ_FOREACH(i, &alldevi, i_next){
+ if (i->i_active == DEVI_ORPHAN &&
+ i->i_module != NULL) {
+ printf("%s is orphan module. pspec=%p\n",
+ i->i_name, i->i_pspec);
+ if (i->i_pspec) {
+ printf(" p_iattr=%p p_atdev=%p\n",
+ i->i_pspec->p_iattr,
+ i->i_pspec->p_atdev);
+ }
+ }
+ }
+
+}
+#endif
+
Index: sem.c
===================================================================
--- sem.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ sem.c (.../tags/patch-1-rc1) (revision 51)
@@ -265,7 +265,7 @@
a->a_expanding = 0;
/* Expand the attribute to check for cycles in the graph. */
- expandattr(a, NULL);
+ expandattr(a, NULL, NULL);
return (0);
}
@@ -592,7 +592,7 @@
* cycles, and invoking a callback for each attribute found.
*/
void
-expandattr(struct attr *a, void (*callback)(struct attr *))
+expandattr(struct attr *a, void *data, void (*callback)(struct attr *, void *))
{
struct nvlist *nv;
struct attr *dep;
@@ -607,12 +607,12 @@
/* First expand all of this attribute's dependencies. */
for (nv = a->a_deps; nv != NULL; nv = nv->nv_next) {
dep = nv->nv_ptr;
- expandattr(dep, callback);
+ expandattr(dep, data, callback);
}
/* ...and now invoke the callback for ourself. */
if (callback != NULL)
- (*callback)(a);
+ (*callback)(a, data);
a->a_expanding = 0;
}
@@ -907,6 +907,7 @@
i->i_atdeva = NULL;
i->i_locs = NULL;
i->i_cfflags = 0;
+ i->i_module = NULL;
i->i_lineno = currentline();
i->i_srcfile = yyfile;
i->i_active = DEVI_ORPHAN; /* Proper analysis comes later */
@@ -921,7 +922,8 @@
* another device instead) plus unit number.
*/
void
-adddev(const char *name, const char *at, struct nvlist *loclist, int flags)
+adddev(const char *name, const char *at, struct nvlist *loclist, int flags,
+ int module_flag)
{
struct devi *i; /* the new instance */
struct pspec *p; /* and its pspec */
@@ -1055,6 +1057,7 @@
i->i_pspec = p;
i->i_atdeva = iba;
i->i_cfflags = flags;
+ i->i_module = module_flag ? module_mark : NULL;
*iba->d_ipp = i;
iba->d_ipp = &i->i_asame;
@@ -1396,12 +1399,21 @@
}
void
-addpseudo(const char *name, int number)
+addpseudo(const char *name, int number, int module_flag)
{
struct devbase *d;
struct devi *i;
d = ht_lookup(devbasetab, name);
+
+#if 1
+ if (module_flag) { /* XXX */
+ cfgerror("module for pseudo-device %s: not supported yet",
+ name);
+ return;
+ }
+#endif
+
if (d == NULL) {
cfgerror("undefined pseudo-device %s", name);
return;
@@ -1419,7 +1431,15 @@
panic("addpseudo(%s)", name);
/* Useful to retrieve the instance from the devbase */
d->d_ihead = i;
- i->i_active = DEVI_ACTIVE;
+
+ if (module_flag) {
+ i->i_active = DEVI_MODULE;
+ i->i_module = module_mark;
+ }
+ else {
+ i->i_active = DEVI_ACTIVE;
+ i->i_module = NULL;
+ }
TAILQ_INSERT_TAIL(&allpseudo, i, i_next);
}
@@ -1655,7 +1675,7 @@
}
void
-selectattr(struct attr *a)
+selectattr(struct attr *a, void *context)
{
(void)ht_insert(selecttab, a->a_name, __UNCONST(a->a_name));
@@ -1674,13 +1694,13 @@
(void)ht_insert(selecttab, d->d_name, __UNCONST(d->d_name));
for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
a = nv->nv_ptr;
- expandattr(a, selectattr);
+ expandattr(a, NULL, selectattr);
}
if (da != NULL) {
(void)ht_insert(selecttab, da->d_name, __UNCONST(da->d_name));
for (nv = da->d_attrs; nv != NULL; nv = nv->nv_next) {
a = nv->nv_ptr;
- expandattr(a, selectattr);
+ expandattr(a, NULL, selectattr);
}
}
}
Index: modload.py
===================================================================
--- modload.py (.../vendor/netbsd/current-20080118) (revision 0)
+++ modload.py (.../tags/patch-1-rc1) (revision 51)
@@ -0,0 +1,252 @@
+#!/usr/bin/env python
+"""Wrapper for /sbin/modload
+
+Usage: modload.py [-Mpath1:path2...] [-Adinvs] [-o output] files ...
+
+ -A automatically load required LKMs.
+ -d passed to /sbin/modload.
+ -i print dependencies for LKM files.
+ -M path module search path.
+ -n don't run. print what to do.
+ -n don't run. print what to do.
+ -o output passed to /sbin/modload.
+ -s passed to /sbin/modload.
+ -v be verbose.
+"""
+
+import sys, getopt, os, re
+from sys import stderr
+from os.path import basename, dirname
+
+def usage_and_exit(r):
+ "print usage to stderr, then exit"
+ print >> stderr, """\
+Usage: %(program)s [-Ainvs] [-M path1:path2...] [-o output] files...""" % \
+ {"program": sys.argv[0]}
+ sys.exit(r)
+
+
+#modload_prog = "/bin/echo"
+modload_prog = "/sbin/modload"
+
+options = {}
+lkm_pool = None
+module_path = ['.', "/usr/lkm"]
+
+class LkmPool:
+ def __init__(self):
+ self.all_lkms = {}
+ self.features = {}
+
+ def add(self, lkm):
+ if self.all_lkms.has_key(lkm.basename):
+ # print >> stderr, "LKM file " + lkm.basename + " is ignored."
+ pass
+ else:
+ self.all_lkms[lkm.basename] = lkm
+ for f in lkm.provide:
+ self.features[f] = lkm
+
+ def find(self, req):
+ "Find an LKM that provides required feature"
+ try:
+ return self.features[req]
+ except KeyError:
+ return None
+
+ def scan_dir(self, dir):
+ print >> stderr, "Scanning", dir
+ files = os.listdir(dir)
+ for f in files:
+ ff = os.path.join(dir,f)
+ if os.path.splitext(f)[1] == ".o" and \
+ not os.path.isdir(ff):
+ self.add(LoadableKernelModule(ff))
+
+ def get(self, fname):
+ base = basename(fname)
+ if self.all_lkms.has_key(base):
+ return self.all_lkms[base]
+ new_lkm = LoadableKernelModule(fname)
+ self.all_lkms[base] = new_lkm
+ return new_lkm
+
+class LoadableKernelModule:
+ "A class to represent LKM"
+
+ def read_dependencies(self, offset, size):
+ f = open(self.filename,"r")
+ f.seek(offset)
+ data = f.read(size)
+ f.close()
+ data = data.rstrip('\x00')
+ if len(data) == 0: # We need this because
+ return [] # "".split('\x00') returns ['']
+ return data.split('\x00')
+
+ def __init__(self,fname):
+ self.filename = fname
+ self.basename = basename(fname)
+ self.dirname = dirname(fname)
+ self.follows = {}
+ self.provide = self.require = {}
+
+ objdump = os.popen("objdump -h %(fname)s" % {"fname": fname},
+ "r");
+ for line in objdump:
+ m = re.search(r"^\s*\d+\s+.note.netbsd.lkm.(require|provide)\s*",
+ line)
+ if m:
+ reqpro = m.group(1)
+ postmatch = line[m.end():]
+ size, vma, lma, fileoff, align = postmatch.split()
+ a = self.read_dependencies(int(fileoff,16),
+ int(size, 16))
+ if reqpro == "require":
+ self.require = a
+ else:
+ self.provide = a
+
+ objdump.close()
+
+
+ def __str__(self):
+ return "LKM<" + self.filename + ">"
+
+
+ def print_info(self):
+ print self.filename, "requires:"
+ for a in self.require:
+ print "\t", a
+ print self.filename, "provides:"
+ for a in self.provide:
+ print "\t", a
+
+#
+# for modload -i files...
+#
+def list_provide_and_require(fname):
+ "print LKM depedency informations for `filename'"
+ lkm = lkm_pool.get(fname)
+ lkm.print_info()
+
+def resolve(files):
+ """find all LKMs required by ones in `files',
+ and sort all LKMs in loading order"""
+
+ dir_searched = False
+ lkms_to_load = {}
+
+ for f in files:
+ lkm = LoadableKernelModule(f)
+ lkms_to_load[lkm] = True
+ lkm_pool.add(lkm)
+
+ def scan_dirs(dirs):
+ for dir in dirs:
+ if dir == "":
+ dir = "."
+ lkm_pool.scan_dir(dir)
+
+ changed = True
+ while changed:
+ changed = False
+ for o in lkms_to_load.keys():
+ # print >> stderr, "Checking for", o
+ for d in o.require:
+ # print >> stderr, " requires", d
+ lkm = lkm_pool.find(d)
+ if lkm:
+ # print >> stderr, " provided by", lkm
+ if lkms_to_load.has_key(lkm):
+ pass # already in the list
+ else:
+ lkms_to_load[lkm] = o
+ changed = True
+ o.follows[lkm] = True
+ else:
+ if not dir_searched:
+ scan_dirs( module_path )
+ dir_searched = True
+ changed = True
+ else:
+ print >> stderr, "No modules for feature", d
+
+# for k, v in lkms_to_load.iteritems():
+# print k, "<-", v
+# print k.require
+
+ order = []
+ while len(lkms_to_load) > 0:
+ a = lkms_to_load.keys()
+ for lkm in a:
+ leaf = True
+ for p in lkm.follows.keys():
+ if lkms_to_load.has_key(p):
+ leaf = False
+ if leaf:
+ order.append(lkm)
+ del lkms_to_load[lkm]
+ return order
+
+def run_modload(file):
+ args = [modload_prog]
+ for o in ["-o", "-v", "-d"]:
+ if options.has_key(o): args.append(o + options[o])
+ if options.has_key("-s") or options.has_key("-A"): args.append("-s")
+ args.append(file)
+
+ if options.has_key("-n"):
+ if options.has_key("-v"): print "Loading", file, "..."
+ print " ".join(args)
+ status = 0
+ else:
+ if options.has_key("-v"): print >> stderr, "Loading", file + "..."
+ status = os.spawnv(os.P_WAIT, modload_prog, args)
+ return status
+
+
+def main():
+ global lkm_pool
+ global options
+ global module_path
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "AdiM:nvso:")
+ except getopt.GetoptError, errmsg:
+ print >> stderr, "%(program)s: %(errmsg)s" %\
+ {"program": sys.argv[0], "errmsg": errmsg}
+ usage_and_exit(2)
+
+ lkm_pool = LkmPool()
+
+ for o, a in opts:
+ options[o] = a
+
+ if len(args) == 0:
+ print >> stderr, "Too few arguments"
+ usage_and_exit(2)
+
+ if options.has_key("-i"):
+ for f in args:
+ list_provide_and_require(f)
+ sys.exit(0)
+
+ if options.has_key("-M"):
+ module_path = options["-M"].split(":")
+ else:
+ module_path = [ dirname(args[0]), "/usr/lkm" ]
+
+ if not options.has_key("-A"):
+ err = 0
+ for f in args:
+ if run_modload(f) != 0: err += 1
+ sys.exit(err)
+
+ load_order = resolve(args)
+
+ for lkm in load_order:
+ run_modload(lkm.filename)
+
+if __name__ == "__main__":
+ main()
Property changes on: modload.py
___________________________________________________________________
Name: svn:executable
+ *
Index: defs.h
===================================================================
--- defs.h (.../vendor/netbsd/current-20080118) (revision 51)
+++ defs.h (.../tags/patch-1-rc1) (revision 51)
@@ -208,6 +208,8 @@
struct deva *d_ahead; /* first attachment, if any */
struct deva **d_app; /* used for tacking on attachments */
struct attr *d_classattr; /* device class attribute (if any) */
+ struct module *d_module; /* this device is compiled in the LKM */
+ STAILQ_ENTRY(devbase) d_mnext; /* devices in the same LKM */
};
struct deva {
@@ -220,6 +222,9 @@
struct nvlist *d_attrs; /* attributes, if any */
struct devi *d_ihead; /* first instance, if any */
struct devi **d_ipp; /* used for tacking on more instances */
+ struct module *d_module; /* this device is compiled in the LKM */
+ STAILQ_ENTRY(deva) d_mnext; /* devices in the same LKM */
+
};
/*
@@ -241,6 +246,8 @@
struct devi *i_bsame; /* list on same base */
struct devi *i_asame; /* list on same base attachment */
struct devi *i_alias; /* other aliases of this instance */
+ struct module *i_module; /* this device is compiled in the LKM */
+ STAILQ_ENTRY(devi) i_mnext; /* devices in the same LKM */
const char *i_at; /* where this is "at" (NULL if at root) */
struct pspec *i_pspec; /* parent spec (NULL if at root) */
struct deva *i_atdeva;
@@ -254,6 +261,7 @@
#define DEVI_ACTIVE 1 /* instance has an active parent */
#define DEVI_IGNORED 2 /* instance's parent has been removed */
#define DEVI_BROKEN 3 /* instance is broken (syntax error) */
+#define DEVI_MODULE 4 /* instance is compiled as LKM */
/* created during packing or ioconf.c generation */
short i_collapsed; /* set => this alias no longer needed */
@@ -277,6 +285,10 @@
char fit_lastc; /* last char from path */
const char *fit_path; /* full file path */
const char *fit_prefix; /* any file prefix */
+
+ STAILQ_ENTRY(filetype) fit_msame; /* list of files in the same module */
+ struct nvlist *fit_modules; /* list of modules which need this file */
+ int fit_nmods; /* the number of modules which need this file */
};
/* Anything less than 0x10 is sub-type specific */
#define FIT_NOPROLOGUE 0x10 /* Don't prepend $S/ */
@@ -310,12 +322,14 @@
#define fi_lastc fi_fit.fit_lastc
#define fi_path fi_fit.fit_path
#define fi_prefix fi_fit.fit_prefix
+#define fi_msame fi_fit.fit_msame
/* flags */
#define FI_SEL 0x01 /* selected */
#define FI_NEEDSCOUNT 0x02 /* needs-count */
#define FI_NEEDSFLAG 0x04 /* needs-flag */
#define FI_HIDDEN 0x08 /* obscured by other(s), base names overlap */
+#define FI_MODULE 0x10 /* Used only for modules */
/*
* Objects and libraries. This allows precompiled object and library
@@ -324,8 +338,8 @@
struct objects {
struct filetype oi_fit;
TAILQ_ENTRY(objects) oi_next;
- struct nvlist *oi_optx;/* options expression */
- struct nvlist *oi_optf;/* flattened version of above, if needed */
+ struct nvlist *oi_optx; /* options expression */
+ struct nvlist *oi_optf; /* flattened version of above, if needed */
};
#define oi_srcfile oi_fit.fit_srcfile
@@ -334,6 +348,7 @@
#define oi_lastc oi_fit.fit_lastc
#define oi_path oi_fit.fit_path
#define oi_prefix oi_fit.fit_prefix
+#define oi_msame oi_fit.fit_msame
/* flags */
#define OI_SEL 0x01 /* selected */
@@ -364,9 +379,64 @@
int dm_cmajor; /* character major */
int dm_bmajor; /* block major */
struct nvlist *dm_opts; /* options */
+ enum { DEVM_IDLE, DEVM_MODULE, DEVM_INKERNEL } dm_active;
};
/*
+ * Modules.
+ */
+struct module {
+ const char *m_name;
+ struct hashtab *m_selecttab; /* selects things that goes to
+ * this module */
+ struct hashtab *m_require; /* modules this module needs */
+
+ enum module_type {
+ M_DEVICE,
+ M_PSEUDO,
+ M_FILESYSTEM,
+ M_ATTRIBUTE,
+#if 1
+ M_MERGE
+#else
+ M_FILEGROUP
+#endif
+ } m_type;
+
+ union {
+ /* for M_DEVICE */
+ struct {
+ STAILQ_HEAD(, devbase) md_base;
+ STAILQ_HEAD(, deva) md_deva;
+ STAILQ_HEAD(, devi) md_devi;
+ } m_dev;
+
+ /* M_ATTRIBUTE */
+ struct attr *m_attr;
+ } u;
+
+ struct files *m_lkmfile; /* _MODULE_lkm.c */
+ STAILQ_HEAD(, filetype) m_files;
+
+ struct nvlist *m_modules; /* M_MERGE */
+ struct module *m_merged; /* merged into the other module */
+};
+
+#define m_base u.m_dev.md_base
+#define m_deva u.m_dev.md_deva
+#define m_devi u.m_dev.md_devi
+
+/* No files for the module. */
+#define m_empty(m) ((m)->m_lkmfile == NULL && STAILQ_EMPTY(&(m)->m_files))
+
+/*
+ * Used to indicate a device is compiled as an LKM.
+ * struct devi.i_module is first set to this value, then
+ * changed to a correct struct module object.
+ */
+#define module_mark ((struct module *)0x00000001)
+
+/*
* Hash tables look up name=value pairs. The pointer value of the name
* is assumed to be constant forever; this can be arranged by interning
* the name. (This is fairly convenient since our lexer does this for
@@ -415,6 +485,8 @@
struct hashtab *attrtab; /* attributes (locators, etc.) */
struct hashtab *bdevmtab; /* block devm lookup */
struct hashtab *cdevmtab; /* character devm lookup */
+struct hashtab *moduletab; /* LKM lookup */
+struct hashtab *emptyattrtab; /* attributes with no codes */
TAILQ_HEAD(, devbase) allbases; /* list of all devbase structures */
TAILQ_HEAD(, deva) alldevas; /* list of all devbase attachments */
@@ -458,8 +530,10 @@
int fixfiles(void); /* finalize */
int fixobjects(void);
int fixdevsw(void);
-void addfile(const char *, struct nvlist *, int, const char *);
+struct files *addfile(const char *, struct nvlist *, int, const char *);
void addobject(const char *, struct nvlist *, int);
+int expr_eval(struct nvlist *, int (*)(const char *, void *), void *);
+char *expr_canonstr(struct nvlist *);
/* hash.c */
struct hashtab *ht_new(void);
@@ -473,6 +547,8 @@
const char *intern(const char *);
typedef int (*ht_callback)(const char *, void *, void *);
int ht_enumerate(struct hashtab *, ht_callback, void *);
+int ht_isempty(struct hashtab *);
+int ht_concat(struct hashtab *, struct hashtab *, int);
/* lint.c */
void emit_instances(void);
@@ -481,7 +557,7 @@
/* main.c */
void addoption(const char *, const char *);
-void addfsoption(const char *);
+void addfsoption(const char *, int);
void addmkoption(const char *, const char *);
void appendmkoption(const char *, const char *);
void appendcondmkoption(const char *, const char *, const char *);
@@ -493,6 +569,8 @@
void delfsoption(const char *);
void delmkoption(const char *);
int devbase_has_instances(struct devbase *, int);
+int devbase_has_any_instance(struct devbase *, int, int, int);
+
struct nvlist * find_declared_option(const char *);
int deva_has_instances(struct deva *, int);
void setupdirs(void);
@@ -517,9 +595,22 @@
/* mkioconf.c */
int mkioconf(void);
+void ioconf_emithdr(FILE *, const char *);
+void ioconf_cfdata_start(FILE *, const char *);
+void ioconf_cfdata_entry(FILE *, struct devi *);
+void ioconf_cfdata_end(FILE *, const char *);
+void ioconf_emit_pspec(FILE *, struct pspec *, int);
+void ioconf_emit_cfdriver(struct devbase *, FILE *);
+void ioconf_emit_ref_iattrs(struct devbase *d, FILE *fp);
/* mkmakefile.c */
int mkmakefile(void);
+struct makefile_constructs {
+ const char *str;
+ void (* func)(FILE *, void *);
+};
+int mkmakefile_common(const struct makefile_constructs *,
+ const char *, const char *, void *);
/* mkswap.c */
int mkswap(void);
@@ -527,6 +618,15 @@
/* pack.c */
void pack(void);
+/* lkm.c */
+int fixlkmdevs(void);
+int fixlkmfiles(void);
+int packlkms(void);
+int mklkms(void);
+void emitkmod(FILE *, void *);
+void dump_module_devis(void);
+int fixlkmdevsw(void);
+
/* scan.l */
int currentline(void);
int firstfile(const char *);
@@ -556,6 +656,7 @@
void nvfreel(struct nvlist *);
struct nvlist *nvcat(struct nvlist *, struct nvlist *);
void autogen_comment(FILE *, const char *);
+void make_directory(const char *);
/* liby */
void yyerror(const char *);
Index: moddep
===================================================================
--- moddep (.../vendor/netbsd/current-20080118) (revision 0)
+++ moddep (.../tags/patch-1-rc1) (revision 51)
@@ -0,0 +1,32 @@
+#!/usr/pkg/bin/perl
+
+use English;
+
+for $f (@ARGV) {
+ die "can't find $f" unless -r $f;
+
+ open(SECTION, "objdump -h $f|") || die "$!";
+ while (<SECTION>) {
+
+ if (/^\s*\d+\s+.note.netbsd.lkm.(require|provide)\s*/) {
+ $reqpro = $1;
+ ($size, $vma, $lma, $fileoff, $align) = split(/\s+/, $POSTMATCH);
+ $D{$reqpro}->{OFF} = hex $fileoff;
+ $D{$reqpro}->{SIZE} = hex $size;
+ }
+ }
+ close(SECTION);
+
+ open(LKM, $f) || die "$!";
+ for $k (keys %D) {
+
+ seek LKM, $D{$k}->{OFF}, 0;
+ read LKM, $_, $D{$k}->{SIZE};
+ $D{$k}->{DATA} = $_;
+
+ print "$f ${k}s:\n";
+ map {print "\t$_\n";} split(/\000/, $_);
+ }
+
+
+}
Property changes on: moddep
___________________________________________________________________
Name: svn:executable
+ *
Index: sem.h
===================================================================
--- sem.h (.../vendor/netbsd/current-20080118) (revision 51)
+++ sem.h (.../tags/patch-1-rc1) (revision 51)
@@ -53,18 +53,18 @@
struct devbase *getdevbase(const char *);
struct deva *getdevattach(const char *);
struct attr *getattr(const char *);
-void expandattr(struct attr *, void (*)(struct attr *));
-void selectattr(struct attr *);
+void expandattr(struct attr *, void *, void (*)(struct attr *, void *));
+void selectattr(struct attr *, void *);
void setmajor(struct devbase *, int);
void addconf(struct config *);
void setconf(struct nvlist **, const char *, struct nvlist *);
void delconf(const char *);
void setfstype(const char **, const char *);
-void adddev(const char *, const char *, struct nvlist *, int);
+void adddev(const char *, const char *, struct nvlist *, int, int);
void deldevi(const char *, const char *);
void deldeva(const char *);
void deldev(const char *);
-void addpseudo(const char *, int);
+void addpseudo(const char *, int, int);
void delpseudo(const char *);
void adddevm(const char *, int, int, struct nvlist *);
int fixdevis(void);
Index: Makefile
===================================================================
--- Makefile (.../vendor/netbsd/current-20080118) (revision 51)
+++ Makefile (.../tags/patch-1-rc1) (revision 51)
@@ -5,7 +5,7 @@
PROG= config
SRCS= files.c gram.y hash.c lint.c main.c mkdevsw.c mkheaders.c mkioconf.c \
- mkmakefile.c mkswap.c pack.c scan.l sem.c util.c
+ mkmakefile.c mkswap.c pack.c lkm.c scan.l sem.c util.c
.PATH: ${NETBSDSRCDIR}/usr.bin/cksum
SRCS+= crc.c
Index: scan.l
===================================================================
--- scan.l (.../vendor/netbsd/current-20080118) (revision 51)
+++ scan.l (.../tags/patch-1-rc1) (revision 51)
@@ -149,6 +149,7 @@
maxpartitions return MAXPARTITIONS;
maxusers return MAXUSERS;
minor return MINOR;
+module return MODULE;
needs-count return NEEDS_COUNT;
needs-flag return NEEDS_FLAG;
no return NO;
Property changes on: .
___________________________________________________________________
Name: svn:ignore
+ TAGS
obj.*
Index: files.c
===================================================================
--- files.c (.../vendor/netbsd/current-20080118) (revision 51)
+++ files.c (.../tags/patch-1-rc1) (revision 51)
@@ -69,9 +69,10 @@
static int fixcount(const char *, void *);
static int fixfsel(const char *, void *);
static int fixsel(const char *, void *);
-static int expr_eval(struct nvlist *,
- int (*)(const char *, void *), void *);
static void expr_free(struct nvlist *);
+//static char *expr_canonstr_sub(struct nvlist *, char *, size_t);
+static int getlastc(const char *);
+static int fixdevmtab_sub(int, struct hashtab *, struct devm *);
void
initfiles(void)
@@ -84,7 +85,7 @@
TAILQ_INIT(&allobjects);
}
-void
+struct files *
addfile(const char *path, struct nvlist *optx, int flags, const char *rule)
{
struct files *fi;
@@ -140,7 +141,7 @@
if (rule != NULL && optx == NULL && flags == 0 &&
yyfile != fi->fi_srcfile) {
fi->fi_mkrule = rule;
- return;
+ return NULL;
}
cfgerror("duplicate file %s", path);
cfgxerror(fi->fi_srcfile, fi->fi_srcline,
@@ -161,9 +162,10 @@
fi->fi_optf = NULL;
fi->fi_mkrule = rule;
TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
- return;
+ return fi;
bad:
expr_free(optx);
+ return NULL;
}
void
@@ -188,6 +190,7 @@
oi->oi_srcline = currentline();
oi->oi_flags = flags;
oi->oi_path = path;
+ oi->oi_lastc = getlastc(path);
oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
SLIST_FIRST(&prefixes)->pf_prefix;
oi->oi_optx = optx;
@@ -251,8 +254,9 @@
err = 0;
TAILQ_FOREACH(fi, &allfiles, fi_next) {
- /* Skip files that generated counted-device complaints. */
- if (fi->fi_flags & FI_HIDDEN)
+ /* Skip files that generated counted-device complaints.
+ or that are only for modules (ex. _MOD_lkm.c) */
+ if (fi->fi_flags & (FI_HIDDEN|FI_MODULE))
continue;
/* Optional: see if it is to be included. */
@@ -343,7 +347,7 @@
int error;
struct devm *dm, *res;
struct hashtab *fixdevmtab;
- char mstr[16];
+ struct devbase *d;
error = 0;
fixdevmtab = ht_new();
@@ -378,53 +382,39 @@
dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
}
- if (dm->dm_opts != NULL &&
- !expr_eval(dm->dm_opts, fixsel, NULL))
+ if (dm->dm_opts == NULL ||
+ expr_eval(dm->dm_opts, fixsel, NULL)) {
+#if 0
+ printf("devm %s bmajor=%d cmajor=%d\n",
+ dm->dm_name, dm->dm_bmajor, dm->dm_cmajor);
+#endif
+ dm->dm_active = DEVM_INKERNEL;
+ }
+ else if ((d = ht_lookup(devbasetab, dm->dm_name)) != NULL &&
+ d->d_module != NULL) {
+#if 0
+ printf("devm %s base=%s bmajor=%d cmajor=%d\n",
+ dm->dm_name, d->d_name,
+ dm->dm_bmajor, dm->dm_cmajor);
+#endif
+ dm->dm_active = DEVM_MODULE;
+ }
+ else {
continue;
+ }
+
if (dm->dm_cmajor != -1) {
- if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
- cfgxerror(dm->dm_srcfile, dm->dm_srcline,
- "device-major of character device '%s' "
- "is already defined", dm->dm_name);
+ if (fixdevmtab_sub(0, cdevmtab, dm)) {
error = 1;
goto out;
}
- (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
- if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
- cfgxerror(dm->dm_srcfile, dm->dm_srcline,
- "device-major of character major '%d' "
- "is already defined", dm->dm_cmajor);
- error = 1;
- goto out;
- }
- if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
- ht_insert(cdevmtab, intern(mstr), dm)) {
- panic("fixdevsw: %s character major %d",
- dm->dm_name, dm->dm_cmajor);
- }
}
if (dm->dm_bmajor != -1) {
- if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
- cfgxerror(dm->dm_srcfile, dm->dm_srcline,
- "device-major of block device '%s' "
- "is already defined", dm->dm_name);
+ if (fixdevmtab_sub(1, bdevmtab, dm)) {
error = 1;
goto out;
}
- (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
- if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
- cfgxerror(dm->dm_srcfile, dm->dm_srcline,
- "device-major of block major '%d' "
- "is already defined", dm->dm_bmajor);
- error = 1;
- goto out;
- }
- if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
- ht_insert(bdevmtab, intern(mstr), dm)) {
- panic("fixdevsw: %s block major %d",
- dm->dm_name, dm->dm_bmajor);
- }
}
}
@@ -433,6 +423,57 @@
return (error);
}
+static int
+fixdevmtab_sub(int block, struct hashtab *ht, struct devm *dm)
+{
+ char mstrbuf[16];
+ const char *mstr;
+ const char *type = block ? "block" : "character";
+ int maj = block ? dm->dm_bmajor : dm->dm_cmajor;
+ struct devm *dm2;
+ const char *name = intern(dm->dm_name);
+
+ dm2 = ht_lookup(ht, name);
+ if (dm2 == NULL) {
+ if (ht_insert(ht, name, dm))
+ goto bad;
+ }
+ else if (dm->dm_active == DEVM_INKERNEL ||
+ dm2->dm_active == DEVM_INKERNEL) {
+ cfgxerror(dm->dm_srcfile, dm->dm_srcline,
+ "device-major of %s device '%s' is already defined",
+ type, dm->dm_name);
+ return -1;
+ }
+
+ (void)snprintf(mstrbuf, sizeof(mstrbuf), "%d", maj);
+ mstr = intern(mstrbuf);
+ dm2 = ht_lookup(ht, mstr);
+ if (dm2 == NULL) {
+ if (ht_insert(ht, mstr, dm))
+ goto bad;
+ }
+ else if (dm2->dm_active == DEVM_INKERNEL ||
+ dm->dm_active == DEVM_INKERNEL) {
+ cfgxerror(dm->dm_srcfile, dm->dm_srcline,
+ "device-major of %s major '%d' is already defined"
+ ": %s, %s",
+ type, maj, dm2->dm_name, dm->dm_name);
+ return -1;
+ }
+
+#if 0
+ printf("%s: %s: bmajor=%d cmajor=%d\n",
+ __FUNCTION__,
+ dm->dm_name, dm->dm_bmajor, dm->dm_cmajor);
+#endif
+ return 0;
+ bad:
+ panic("fixdevsw: ht_insert FAILED: %s %s major %d", dm->dm_name, type, maj);
+ /*NOTREACHED*/
+ return -1; /* this is bogus */
+}
+
/*
* Called when evaluating a needs-count expression. Make sure the
* atom is a countable device. The expression succeeds iff there
@@ -496,7 +537,7 @@
* No short circuiting ever occurs. fn must return 0 or 1 (otherwise
* our mixing of C's bitwise & boolean here may give surprises).
*/
-static int
+int
expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context)
{
int lhs, rhs;
@@ -555,15 +596,95 @@
}
}
+#if 0
+#define EXPR_STR_LEN 256
+/*
+ * Generate string form of expr.
+ * Returns the same string for logically equiverent exprs. ex:
+ * both a | b & c and c & b | a make "a|(b&c)".
+ * XXX:
+ * but it doesn't canonicalize !(a&b) and !a|!b to the same string.
+ */
+char *
+expr_canonstr(struct nvlist *expr)
+{
+ char buf[EXPR_STR_LEN];
+
+ return estrdup(expr_canonstr_sub(expr, buf, sizeof buf));
+}
+
+
+static char *
+expr_canonstr_sub(struct nvlist *expr, char *buf, size_t buflen)
+{
+ char buf_r[EXPR_STR_LEN], buf_l[EXPR_STR_LEN];
+ int op;
+ const char *lo, *lc, *ro, *rc;
+
+ switch (expr->nv_int) {
+ case FX_ATOM:
+ snprintf(buf, buflen, "%s", expr->nv_name);
+ break;
+ case FX_NOT:
+ snprintf(buf, buflen, "!%s", expr_canonstr_sub(expr->nv_next,
+ buf_r,
+ sizeof buf_r));
+ break;
+ case FX_AND:
+ case FX_OR:
+ lo = ro = ""; /* open */
+ lc = rc = ""; /* close */
+
+ expr_canonstr_sub(expr->nv_ptr, buf_l, sizeof buf_l);
+ if (expr->nv_int < ((struct nvlist *)(expr->nv_ptr))->nv_int) {
+ lo = "("; lc = ")";
+ }
+
+ expr_canonstr_sub(expr->nv_next, buf_r, sizeof buf_r);
+ if (expr->nv_int < expr->nv_next->nv_int) {
+ ro = "("; rc = ")";
+ }
+
+ op = expr->nv_int == FX_AND ? '&' : '|';
+
+ if (strcmp(buf_l, buf_r) <= 0)
+ snprintf(buf, buflen, "%s%s%s%c%s%s%s",
+ lo, buf_l, lc,
+ op,
+ ro, buf_r, rc);
+ else
+ snprintf(buf, buflen, "%s%s%s%c%s%s%s",
+ ro, buf_r, rc,
+ op,
+ lo, buf_l, lc);
+ break;
+ default:
+ panic("expr_canonstr %d", expr->nv_int);
+ }
+
+ return buf;
+}
+#endif
+
+static int
+getlastc(const char *path)
+{
+ int len;
+ len = strlen(path);
+ if (len <= 0)
+ return '\0';
+ return path[len-1];
+}
+
#ifdef DEBUG
+static void pr0();
+
/*
* Print expression tree.
*/
void
prexpr(struct nvlist *expr)
{
- static void pr0();
-
printf("expr =");
pr0(expr);
printf("\n");