157488Storek /*
2*61818Sbostic * Copyright (c) 1992, 1993
3*61818Sbostic * The Regents of the University of California. All rights reserved.
457488Storek *
557488Storek * This software was developed by the Computer Systems Engineering group
657488Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
757488Storek * contributed to Berkeley.
857488Storek *
957488Storek * All advertising materials mentioning features or use of this software
1057488Storek * must display the following acknowledgement:
1157488Storek * This product includes software developed by the University of
1257488Storek * California, Lawrence Berkeley Laboratories.
1357488Storek *
1457488Storek * %sccs.include.redist.c%
1557488Storek *
16*61818Sbostic * @(#)files.c 8.1 (Berkeley) 06/06/93
1757488Storek */
1857488Storek
1957488Storek #include <sys/param.h>
2057488Storek #include <errno.h>
2157488Storek #include <stdio.h>
2257488Storek #include <stdlib.h>
2357488Storek #include <string.h>
2457488Storek #include "config.h"
2557488Storek
2657488Storek extern const char *yyfile;
2757488Storek
2857488Storek /*
2957488Storek * We check that each full path name is unique. File base names
3057488Storek * should generally also be unique, e.g., having both a net/xx.c and
3157488Storek * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
3257488Storek * wrong, but is permitted under some conditions.
3357488Storek */
3457488Storek static struct hashtab *basetab; /* file base names */
3557488Storek static struct hashtab *pathtab; /* full path names */
3657488Storek
3757488Storek static struct files **nextfile;
3857488Storek static struct files **unchecked;
3957488Storek
4057488Storek void
initfiles()4157488Storek initfiles()
4257488Storek {
4357488Storek
4457488Storek basetab = ht_new();
4557488Storek pathtab = ht_new();
4657488Storek nextfile = &allfiles;
4757488Storek unchecked = &allfiles;
4857488Storek }
4957488Storek
5057488Storek static void
showprev(pref,fi)5157488Storek showprev(pref, fi)
5257488Storek const char *pref;
5357488Storek register struct files *fi;
5457488Storek {
5557488Storek
5657488Storek xerror(fi->fi_srcfile, fi->fi_srcline,
5757488Storek "%sfile %s ...", pref, fi->fi_path);
5857488Storek errors--;
5957488Storek }
6057488Storek
6157488Storek void
addfile(path,opts,flags,rule)6257488Storek addfile(path, opts, flags, rule)
6357488Storek const char *path;
6457488Storek struct nvlist *opts;
6557488Storek int flags;
6657488Storek const char *rule;
6757488Storek {
6857488Storek struct files *fi;
6957488Storek const char *base, *dotp, *tail;
7057488Storek size_t baselen;
7157488Storek int needc, needf;
7257488Storek char buf[200];
7357488Storek
7457488Storek /* check various errors */
7557488Storek needc = flags & FI_NEEDSCOUNT;
7657488Storek needf = flags & FI_NEEDSFLAG;
7757488Storek if (needc && needf) {
7857488Storek error("cannot mix needs-count and needs-flag");
7957488Storek goto bad;
8057488Storek }
8157488Storek if (opts == NULL && (needc || needf)) {
8257488Storek error("nothing to %s for %s", needc ? "count" : "flag", path);
8357488Storek goto bad;
8457488Storek }
8557488Storek if ((fi = ht_lookup(pathtab, path)) != NULL) {
8657488Storek showprev("", fi);
8757488Storek error("file %s listed again", path);
8857488Storek goto bad;
8957488Storek }
9057488Storek
9157488Storek /* find last part of pathname, and same without trailing suffix */
9257488Storek tail = rindex(path, '/');
9357488Storek if (tail == NULL)
9457488Storek tail = path;
9557488Storek else
9657488Storek tail++;
9757488Storek dotp = rindex(tail, '.');
9857488Storek if (dotp == NULL || dotp[1] == 0 ||
9957488Storek (baselen = dotp - tail) >= sizeof(buf)) {
10057488Storek error("invalid pathname `%s'", path);
10157488Storek goto bad;
10257488Storek }
10357488Storek
10457488Storek /*
10557488Storek * Make a copy of the path without the .c/.s/whatever suffix.
10657488Storek * This must be unique per "files" file (e.g., a specific
10757488Storek * file can override a standard file, but no standard file
10857488Storek * can override another standard file). This is not perfect
10957488Storek * but should catch any major errors.
11057488Storek */
11157488Storek bcopy(tail, buf, baselen);
11257488Storek buf[baselen] = 0;
11357488Storek base = intern(buf);
11457488Storek if ((fi = ht_lookup(basetab, base)) != NULL) {
11557488Storek if (fi->fi_srcfile != yyfile) {
11657488Storek showprev("note: ", fi);
11757488Storek error("is overriden by %s", path);
11857488Storek errors--; /* take it away */
11957488Storek fi->fi_flags |= FI_HIDDEN;
12057488Storek } else {
12157488Storek showprev("", fi);
12257488Storek error("collides with %s (both make %s.o)",
12357488Storek path, base);
12457488Storek goto bad;
12557488Storek }
12657488Storek }
12757488Storek
12857488Storek /*
12957488Storek * Commit this file to memory.
13057488Storek */
13157488Storek fi = emalloc(sizeof *fi);
13257488Storek fi->fi_next = NULL;
13357488Storek fi->fi_srcfile = yyfile;
13457488Storek fi->fi_srcline = currentline();
13557488Storek fi->fi_flags = flags;
13657488Storek fi->fi_lastc = dotp[strlen(dotp) - 1];
13757488Storek fi->fi_path = path;
13857488Storek fi->fi_tail = tail;
13957488Storek fi->fi_base = base;
14057488Storek fi->fi_opt = opts;
14157488Storek fi->fi_mkrule = rule;
14257488Storek if (ht_insert(pathtab, path, fi))
14357488Storek panic("addfile: ht_insert(%s)", path);
14457488Storek (void)ht_replace(basetab, base, fi);
14557488Storek *nextfile = fi;
14657488Storek nextfile = &fi->fi_next;
14757488Storek return;
14857488Storek bad:
14957488Storek nvfreel(opts);
15057488Storek }
15157488Storek
15257488Storek /*
15357488Storek * We have finished reading some "files" file, either ../../conf/files
15457488Storek * or ./files.$machine. Make sure that everything that is flagged as
15557488Storek * needing a count is reasonable. (This prevents ../../conf/files from
15657488Storek * depending on some machine-specific device.)
15757488Storek */
15857488Storek void
checkfiles()15957488Storek checkfiles()
16057488Storek {
16157488Storek register struct files *fi, *last;
16257488Storek register struct nvlist *nv;
16357488Storek
16457488Storek last = NULL;
16557488Storek for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next) {
16657488Storek if ((fi->fi_flags & FI_NEEDSCOUNT) == 0)
16757488Storek continue;
16857488Storek for (nv = fi->fi_opt; nv != NULL; nv = nv->nv_next)
16957488Storek if (ht_lookup(devbasetab, nv->nv_name) == NULL) {
17057488Storek xerror(fi->fi_srcfile, fi->fi_srcline,
17157488Storek "`%s' is not a countable device",
17257488Storek nv->nv_name);
17357488Storek /* keep fixfiles() from complaining again */
17457488Storek fi->fi_flags |= FI_HIDDEN;
17557488Storek }
17657488Storek }
17757488Storek if (last != NULL)
17857488Storek unchecked = &last->fi_next;
17957488Storek }
18057488Storek
18157488Storek /*
18257488Storek * We have finished reading everything. Tack the files down: calculate
18357488Storek * selection and counts as needed.
18457488Storek */
18557488Storek int
fixfiles()18657488Storek fixfiles()
18757488Storek {
18857488Storek register struct files *fi;
18957488Storek register struct nvlist *nv;
19057488Storek register struct devbase *dev;
19157488Storek int sel, err;
19257488Storek
19357488Storek err = 0;
19457488Storek for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
19557488Storek if (fi->fi_flags & FI_HIDDEN)
19657488Storek continue;
19757488Storek if ((nv = fi->fi_opt) == NULL) { /* standard */
19857488Storek fi->fi_flags |= FI_SEL;
19957488Storek continue;
20057488Storek }
20157488Storek /* figure out whether it is selected */
20257488Storek sel = 0;
20357488Storek if (fi->fi_flags & FI_NEEDSCOUNT) {
20457488Storek /* ... and compute counts too */
20557488Storek do {
20657488Storek dev = ht_lookup(devbasetab, nv->nv_name);
20757488Storek if (dev == NULL) {
20857488Storek xerror(fi->fi_srcfile, fi->fi_srcline,
20957488Storek "`%s' is not a countable device",
21057488Storek nv->nv_name);
21157488Storek err = 1;
21257488Storek } else {
21357488Storek if (dev->d_umax)
21457488Storek sel = 1;
21557488Storek nv->nv_int = dev->d_umax;
21657488Storek (void)ht_insert(needcnttab,
21757488Storek nv->nv_name, nv);
21857488Storek }
21957488Storek } while ((nv = nv->nv_next) != NULL);
22057488Storek } else {
22157488Storek do {
22257488Storek if (ht_lookup(selecttab, nv->nv_name)) {
22357488Storek sel = 1;
22457488Storek break;
22557488Storek }
22657488Storek } while ((nv = nv->nv_next) != NULL);
22757488Storek if (fi->fi_flags & FI_NEEDSFLAG)
22857488Storek for (nv = fi->fi_opt; nv; nv = nv->nv_next)
22957488Storek nv->nv_int = sel;
23057488Storek }
23157488Storek /* if selected, we are go */
23257488Storek if (sel)
23357488Storek fi->fi_flags |= FI_SEL;
23457488Storek }
23557488Storek return (err);
23657488Storek }
237