147479Spendry /*
247479Spendry * Copyright (c) 1989 Jan-Simon Pendry
347479Spendry * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
4*61793Sbostic * Copyright (c) 1989, 1993
5*61793Sbostic * The Regents of the University of California. All rights reserved.
647479Spendry *
747479Spendry * This code is derived from software contributed to Berkeley by
847479Spendry * Jan-Simon Pendry at Imperial College, London.
947479Spendry *
1047530Spendry * %sccs.include.redist.c%
1147479Spendry *
12*61793Sbostic * @(#)fsi_analyze.c 8.1 (Berkeley) 06/06/93
1347479Spendry *
1452455Spendry * $Id: fsi_analyze.c,v 5.2.2.1 1992/02/09 15:09:41 jsp beta $
1549686Spendry *
1647479Spendry */
1747479Spendry
1847479Spendry /*
1947479Spendry * Analyze filesystem declarations
2047479Spendry *
2147479Spendry * Note: most of this is magic!
2247479Spendry */
2347479Spendry
2447479Spendry #include "../fsinfo/fsinfo.h"
2547479Spendry
2647479Spendry char *disk_fs_strings[] = {
2747479Spendry "fstype", "opts", "dumpset", "passno", "freq", "mount", "log", 0,
2847479Spendry };
2947479Spendry
3047479Spendry char *mount_strings[] = {
3147479Spendry "volname", "exportfs", 0,
3247479Spendry };
3347479Spendry
3447479Spendry char *fsmount_strings[] = {
3547479Spendry "as", "volname", "fstype", "opts", "from", 0,
3647479Spendry };
3747479Spendry
3847479Spendry char *host_strings[] = {
3947479Spendry "host", "netif", "config", "arch", "cluster", "os", 0,
4047479Spendry };
4147479Spendry
4247479Spendry char *ether_if_strings[] = {
4347479Spendry "inaddr", "netmask", "hwaddr", 0,
4447479Spendry };
4547479Spendry
4647479Spendry /*
4747479Spendry * Strip off the trailing part of a domain
4847479Spendry * to produce a short-form domain relative
4947479Spendry * to the local host domain.
5047479Spendry * Note that this has no effect if the domain
5147479Spendry * names do not have the same number of
5247479Spendry * components. If that restriction proves
5347479Spendry * to be a problem then the loop needs recoding
5447479Spendry * to skip from right to left and do partial
5547479Spendry * matches along the way -- ie more expensive.
5647479Spendry */
domain_strip(otherdom,localdom)5747479Spendry void domain_strip(otherdom, localdom)
5847479Spendry char *otherdom, *localdom;
5947479Spendry {
6047479Spendry #ifdef PARTIAL_DOMAINS
6147479Spendry char *p1 = otherdom-1;
6247479Spendry char *p2 = localdom-1;
6347479Spendry
6447479Spendry do {
6547479Spendry if (p1 = strchr(p1+1, '.'))
6647479Spendry if (p2 = strchr(p2+1, '.'))
6747479Spendry if (STREQ(p1+1, p2+1)) {
6847479Spendry *p1 = '\0';
6947479Spendry break;
7047479Spendry }
7147479Spendry } while (p1 && p2);
7247479Spendry #else
7347479Spendry char *p1, *p2;
7447479Spendry
7547479Spendry if ((p1 = strchr(otherdom, '.')) &&
7647479Spendry (p2 = strchr(localdom, '.')) &&
7747479Spendry (strcmp(p1+1, p2+1) == 0))
7847479Spendry *p1 = '\0';
7947479Spendry #endif /* PARTIAL_DOMAINS */
8047479Spendry }
8147479Spendry
8247479Spendry /*
8347479Spendry * Take a little-endian domain name and
8447479Spendry * transform into a big-endian Un*x pathname.
8547479Spendry * For example: kiska.doc.ic -> ic/doc/kiska
8647479Spendry */
compute_hostpath(hn)8747479Spendry static char *compute_hostpath(hn)
8847479Spendry char *hn;
8947479Spendry {
9047479Spendry char *p = strdup(hn);
9147479Spendry char *d;
9247479Spendry char path[MAXPATHLEN];
9347479Spendry
9447479Spendry domain_strip(p, hostname);
9547479Spendry path[0] = '\0';
9647479Spendry
9747479Spendry do {
9847479Spendry d = strrchr(p, '.');
9947479Spendry if (d) {
10047479Spendry *d = 0;
10147479Spendry strcat(path, d+1);
10247479Spendry strcat(path, "/");
10347479Spendry } else {
10447479Spendry strcat(path, p);
10547479Spendry }
10647479Spendry } while (d);
10747479Spendry
10847479Spendry log("hostpath of '%s' is '%s'", hn, path);
10947479Spendry
11047479Spendry strcpy(p, path);
11147479Spendry return p;
11247479Spendry }
11347479Spendry
find_volname(nn)11447479Spendry static dict_ent *find_volname(nn)
11547479Spendry char *nn;
11647479Spendry {
11747479Spendry dict_ent *de;
11847479Spendry char *p = strdup(nn);
11947479Spendry char *q;
12047479Spendry
12147479Spendry do {
12247479Spendry log("Searching for volname %s", p);
12347479Spendry de = dict_locate(dict_of_volnames, p);
12447479Spendry q = strrchr(p, '/');
12547479Spendry if (q) *q = '\0';
12647479Spendry } while (!de && q);
12747479Spendry
12847479Spendry free(p);
12947479Spendry return de;
13047479Spendry }
13147479Spendry
show_required(l,mask,info,hostname,strings)13247479Spendry static show_required(l, mask, info, hostname, strings)
13347479Spendry ioloc *l;
13447479Spendry int mask;
13547479Spendry char *info;
13647479Spendry char *hostname;
13747479Spendry char *strings[];
13847479Spendry {
13947479Spendry int i;
14047479Spendry log("mask left for %s:%s is %#x", hostname, info, mask);
14147479Spendry
14247479Spendry for (i = 0; strings[i]; i++)
14347479Spendry if (ISSET(mask, i))
14447479Spendry lerror(l, "%s:%s needs field \"%s\"", hostname, info, strings[i]);
14547479Spendry }
14647479Spendry
14747479Spendry /*
14847479Spendry * Check and fill in "exportfs" details.
14947479Spendry * Make sure the m_exported field references
15047479Spendry * the most local node with an "exportfs" entry.
15147479Spendry */
check_exportfs(q,e)15247479Spendry static int check_exportfs(q, e)
15347479Spendry qelem *q;
15447479Spendry mount *e;
15547479Spendry {
15647479Spendry mount *mp;
15747479Spendry int errors = 0;
15847479Spendry
15947479Spendry ITER(mp, mount, q) {
16047479Spendry if (ISSET(mp->m_mask, DM_EXPORTFS)) {
16147479Spendry if (e)
16247479Spendry lwarning(mp->m_ioloc, "%s has duplicate exportfs data", mp->m_name);
16347479Spendry mp->m_exported = mp;
16447479Spendry if (!ISSET(mp->m_mask, DM_VOLNAME))
16547479Spendry set_mount(mp, DM_VOLNAME, strdup(mp->m_name));
16647479Spendry } else {
16747479Spendry mp->m_exported = e;
16847479Spendry }
16947479Spendry
17047479Spendry /*
17147479Spendry * Recursively descend the mount tree
17247479Spendry */
17347479Spendry if (mp->m_mount)
17447479Spendry errors += check_exportfs(mp->m_mount, mp->m_exported);
17547479Spendry
17647479Spendry /*
17747479Spendry * If a volume name has been specified, but this node and none
17847479Spendry * of its parents has been exported, report an error.
17947479Spendry */
18047479Spendry if (ISSET(mp->m_mask, DM_VOLNAME) && !mp->m_exported) {
18147479Spendry lerror(mp->m_ioloc, "%s has a volname but no exportfs data", mp->m_name);
18247479Spendry errors++;
18347479Spendry }
18447479Spendry }
18547479Spendry
18647479Spendry return errors;
18747479Spendry }
18847479Spendry
analyze_dkmount_tree(q,parent,dk)18947479Spendry static int analyze_dkmount_tree(q, parent, dk)
19047479Spendry qelem *q;
19147479Spendry mount *parent;
19247479Spendry disk_fs *dk;
19347479Spendry {
19447479Spendry mount *mp;
19547479Spendry int errors = 0;
19647479Spendry
19747479Spendry ITER(mp, mount, q) {
19847479Spendry log("Mount %s:", mp->m_name);
19947479Spendry if (parent) {
20047479Spendry char n[MAXPATHLEN];
20147479Spendry sprintf(n, "%s/%s", parent->m_name, mp->m_name);
20247479Spendry if (*mp->m_name == '/')
20347479Spendry lerror(mp->m_ioloc, "sub-directory %s of %s starts with '/'", mp->m_name, parent->m_name);
20447479Spendry else if (STREQ(mp->m_name, "default"))
20547479Spendry lwarning(mp->m_ioloc, "sub-directory of %s is named \"default\"", parent->m_name);
20647479Spendry log("Changing name %s to %s", mp->m_name, n);
20747479Spendry free(mp->m_name);
20847479Spendry mp->m_name = strdup(n);
20947479Spendry }
21047479Spendry mp->m_name_len = strlen(mp->m_name);
21147479Spendry mp->m_parent = parent;
21247479Spendry mp->m_dk = dk;
21347479Spendry if (mp->m_mount)
21447479Spendry analyze_dkmount_tree(mp->m_mount, mp, dk);
21547479Spendry }
21647479Spendry
21747479Spendry return errors;
21847479Spendry }
21947479Spendry
22047479Spendry /*
22147479Spendry * The mount tree is a singleton list
22247479Spendry * containing the top-level mount
22347479Spendry * point for a disk.
22447479Spendry */
analyze_dkmounts(dk,q)22547479Spendry static int analyze_dkmounts(dk, q)
22647479Spendry disk_fs *dk;
22747479Spendry qelem *q;
22847479Spendry {
22947479Spendry int errors = 0;
23047479Spendry mount *mp, *mp2 = 0;
23147479Spendry int i = 0;
23247479Spendry
23347479Spendry /*
23447479Spendry * First scan the list of subdirs to make
23547479Spendry * sure there is only one - and remember it
23647479Spendry */
23747479Spendry if (q) {
23847479Spendry ITER(mp, mount, q) {
23947479Spendry mp2 = mp;
24047479Spendry i++;
24147479Spendry }
24247479Spendry }
24347479Spendry
24447479Spendry /*
24547479Spendry * Check...
24647479Spendry */
24747479Spendry if (i < 1) {
24847479Spendry lerror(dk->d_ioloc, "%s:%s has no mount point", dk->d_host->h_hostname, dk->d_dev);
24947479Spendry return 1;
25047479Spendry }
25147479Spendry if (i > 1) {
25247479Spendry lerror(dk->d_ioloc, "%s:%s has more than one mount point", dk->d_host->h_hostname, dk->d_dev);
25347479Spendry errors++;
25447479Spendry }
25547479Spendry /*
25647479Spendry * Now see if a default mount point is required
25747479Spendry */
25847479Spendry if (STREQ(mp2->m_name, "default")) {
25947479Spendry if (ISSET(mp2->m_mask, DM_VOLNAME)) {
26047479Spendry char nbuf[1024];
26147479Spendry compute_automount_point(nbuf, dk->d_host, mp2->m_volname);
26247479Spendry free(mp2->m_name);
26347479Spendry mp2->m_name = strdup(nbuf);
26447479Spendry log("%s:%s has default mount on %s", dk->d_host->h_hostname, dk->d_dev, mp2->m_name);
26547479Spendry } else {
26647479Spendry lerror(dk->d_ioloc, "no volname given for %s:%s", dk->d_host->h_hostname, dk->d_dev);
26747479Spendry errors++;
26847479Spendry }
26947479Spendry }
27047479Spendry /*
27147479Spendry * Fill in the disk mount point
27247479Spendry */
27347479Spendry if (!errors && mp2 && mp2->m_name)
27447479Spendry dk->d_mountpt = strdup(mp2->m_name);
27547479Spendry else
27647479Spendry dk->d_mountpt = strdup("error");
27747479Spendry
27847479Spendry /*
27947479Spendry * Analyze the mount tree
28047479Spendry */
28147479Spendry errors += analyze_dkmount_tree(q, 0, dk);
28247479Spendry
28347479Spendry /*
28447479Spendry * Analyze the export tree
28547479Spendry */
28647479Spendry errors += check_exportfs(q, 0);
28747479Spendry
28847479Spendry return errors;
28947479Spendry }
29047479Spendry
fixup_required_disk_info(dp)29147479Spendry static void fixup_required_disk_info(dp)
29247479Spendry disk_fs *dp;
29347479Spendry {
29447479Spendry /*
29547479Spendry * "fstype"
29647479Spendry */
29747479Spendry if (ISSET(dp->d_mask, DF_FSTYPE)) {
29847479Spendry if (STREQ(dp->d_fstype, "swap")) {
29947479Spendry /*
30047479Spendry * Fixup for a swap device
30147479Spendry */
30247479Spendry if (!ISSET(dp->d_mask, DF_PASSNO)) {
30347479Spendry dp->d_passno = 0;
30447479Spendry BITSET(dp->d_mask, DF_PASSNO);
30547479Spendry } else if (dp->d_freq != 0) {
30647479Spendry lwarning(dp->d_ioloc,
30747479Spendry "Pass number for %s:%s is non-zero",
30847479Spendry dp->d_host->h_hostname, dp->d_dev);
30947479Spendry }
31047479Spendry
31147479Spendry /*
31247479Spendry * "freq"
31347479Spendry */
31447479Spendry if (!ISSET(dp->d_mask, DF_FREQ)) {
31547479Spendry dp->d_freq = 0;
31647479Spendry BITSET(dp->d_mask, DF_FREQ);
31747479Spendry } else if (dp->d_freq != 0) {
31847479Spendry lwarning(dp->d_ioloc,
31947479Spendry "dump frequency for %s:%s is non-zero",
32047479Spendry dp->d_host->h_hostname, dp->d_dev);
32147479Spendry }
32247479Spendry
32347479Spendry /*
32447479Spendry * "opts"
32547479Spendry */
32647479Spendry if (!ISSET(dp->d_mask, DF_OPTS))
32747479Spendry set_disk_fs(dp, DF_OPTS, strdup("swap"));
32847479Spendry
32947479Spendry /*
33047479Spendry * "mount"
33147479Spendry */
33247479Spendry if (!ISSET(dp->d_mask, DF_MOUNT)) {
33347479Spendry qelem *q = new_que();
33447479Spendry mount *m = new_mount();
33547479Spendry m->m_name = strdup("swap");
33647479Spendry m->m_mount = new_que();
33747479Spendry ins_que(&m->m_q, q->q_back);
33847479Spendry dp->d_mount = q;
33947479Spendry BITSET(dp->d_mask, DF_MOUNT);
34047479Spendry } else {
34147479Spendry lerror(dp->d_ioloc, "%s: mount field specified for swap partition", dp->d_host->h_hostname);
34247479Spendry }
34347479Spendry } else if (STREQ(dp->d_fstype, "export")) {
34447479Spendry /*
34547479Spendry * "passno"
34647479Spendry */
34747479Spendry if (!ISSET(dp->d_mask, DF_PASSNO)) {
34847479Spendry dp->d_passno = 0;
34947479Spendry BITSET(dp->d_mask, DF_PASSNO);
35047479Spendry } else if (dp->d_passno != 0) {
35147479Spendry lwarning(dp->d_ioloc,
35247479Spendry "pass number for %s:%s is non-zero",
35347479Spendry dp->d_host->h_hostname, dp->d_dev);
35447479Spendry }
35547479Spendry
35647479Spendry /*
35747479Spendry * "freq"
35847479Spendry */
35947479Spendry if (!ISSET(dp->d_mask, DF_FREQ)) {
36047479Spendry dp->d_freq = 0;
36147479Spendry BITSET(dp->d_mask, DF_FREQ);
36247479Spendry } else if (dp->d_freq != 0) {
36347479Spendry lwarning(dp->d_ioloc,
36447479Spendry "dump frequency for %s:%s is non-zero",
36547479Spendry dp->d_host->h_hostname, dp->d_dev);
36647479Spendry }
36747479Spendry
36847479Spendry /*
36947479Spendry * "opts"
37047479Spendry */
37147479Spendry if (!ISSET(dp->d_mask, DF_OPTS))
37247479Spendry set_disk_fs(dp, DF_OPTS, strdup("rw,defaults"));
37347479Spendry
37447479Spendry }
37547479Spendry }
37647479Spendry }
37747479Spendry
fixup_required_mount_info(fp,de)37847479Spendry static void fixup_required_mount_info(fp, de)
37947479Spendry fsmount *fp;
38047479Spendry dict_ent *de;
38147479Spendry {
38247479Spendry if (!ISSET(fp->f_mask, FM_FROM)) {
38347479Spendry if (de->de_count != 1) {
38447479Spendry lerror(fp->f_ioloc, "ambiguous mount: %s is a replicated filesystem", fp->f_volname);
38547479Spendry } else {
38647479Spendry dict_data *dd;
38747479Spendry mount *mp = 0;
38847479Spendry ITER(dd, dict_data, &de->de_q) {
38947479Spendry mp = (mount *) dd->dd_data;
39047479Spendry break;
39147479Spendry }
39247479Spendry if (!mp)
39347479Spendry abort();
39447479Spendry fp->f_ref = mp;
39547479Spendry set_fsmount(fp, FM_FROM, mp->m_dk->d_host->h_hostname);
39647479Spendry log("set: %s comes from %s", fp->f_volname, fp->f_from);
39747479Spendry }
39847479Spendry }
39947479Spendry
40047479Spendry if (!ISSET(fp->f_mask, FM_FSTYPE)) {
40147479Spendry set_fsmount(fp, FM_FSTYPE, strdup("nfs"));
40247479Spendry log("set: fstype is %s", fp->f_fstype);
40347479Spendry }
40447479Spendry
40547479Spendry if (!ISSET(fp->f_mask, FM_OPTS)) {
40647479Spendry set_fsmount(fp, FM_OPTS, strdup("rw,nosuid,grpid,defaults"));
40747479Spendry log("set: opts are %s", fp->f_opts);
40847479Spendry }
40947479Spendry
41047479Spendry if (!ISSET(fp->f_mask, FM_LOCALNAME)) {
41147479Spendry if (fp->f_ref) {
41247479Spendry set_fsmount(fp, FM_LOCALNAME, strdup(fp->f_volname));
41347479Spendry log("set: localname is %s", fp->f_localname);
41447479Spendry } else {
41547479Spendry lerror(fp->f_ioloc, "cannot determine localname since volname %s is not uniquely defined", fp->f_volname);
41647479Spendry }
41747479Spendry }
41847479Spendry }
41947479Spendry
42047479Spendry /*
42147479Spendry * For each disk on a host
42247479Spendry * analyze the mount information
42347479Spendry * and fill in any derivable
42447479Spendry * details.
42547479Spendry */
analyze_drives(hp)42647479Spendry static void analyze_drives(hp)
42747479Spendry host *hp;
42847479Spendry {
42947479Spendry qelem *q = hp->h_disk_fs;
43047479Spendry disk_fs *dp;
43147479Spendry
43247479Spendry ITER(dp, disk_fs, q) {
43347479Spendry int req;
43447479Spendry log("Disk %s:", dp->d_dev);
43547479Spendry dp->d_host = hp;
43647479Spendry fixup_required_disk_info(dp);
43747479Spendry req = ~dp->d_mask & DF_REQUIRED;
43847479Spendry if (req)
43947479Spendry show_required(dp->d_ioloc, req, dp->d_dev, hp->h_hostname, disk_fs_strings);
44047479Spendry analyze_dkmounts(dp, dp->d_mount);
44147479Spendry }
44247479Spendry }
44347479Spendry
44447479Spendry /*
44547479Spendry * Check that all static mounts make sense and
44647479Spendry * that the source volumes exist.
44747479Spendry */
analyze_mounts(hp)44847479Spendry static void analyze_mounts(hp)
44947479Spendry host *hp;
45047479Spendry {
45147479Spendry qelem *q = hp->h_mount;
45247479Spendry fsmount *fp;
45347479Spendry int netbootp = 0;
45447479Spendry
45547479Spendry ITER(fp, fsmount, q) {
45647479Spendry char *p;
45747479Spendry char *nn = strdup(fp->f_volname);
45847479Spendry int req;
45947479Spendry dict_ent *de;
46047479Spendry int found = 0;
46147479Spendry int matched = 0;
46247479Spendry do {
46347479Spendry p = 0;
46447479Spendry de = find_volname(nn);
46547479Spendry log("Mount: %s (trying %s)", fp->f_volname, nn);
46647479Spendry
46747479Spendry if (de) {
46847479Spendry found = 1;
46947479Spendry /*
47047479Spendry * Check that the from field is really exporting
47147479Spendry * the filesystem requested.
47247479Spendry */
47347479Spendry if (ISSET(fp->f_mask, FM_FROM)) {
47447479Spendry dict_data *dd;
47547479Spendry mount *mp2 = 0;
47647479Spendry ITER(dd, dict_data, &de->de_q) {
47747479Spendry mount *mp = (mount *) dd->dd_data;
47847479Spendry if (STREQ(mp->m_dk->d_host->h_hostname, fp->f_from)) {
47947479Spendry mp2 = mp;
48047479Spendry break;
48147479Spendry }
48247479Spendry }
48347479Spendry
48447479Spendry if (mp2) {
48547479Spendry fp->f_ref = mp2;
48647479Spendry matched = 1;
48747479Spendry break;
48847479Spendry }
48947479Spendry } else {
49047479Spendry matched = 1;
49147479Spendry break;
49247479Spendry }
49347479Spendry }
49447479Spendry p = strrchr(nn, '/');
49547479Spendry if (p)
49647479Spendry *p = 0;
49747479Spendry } while (de && p);
49847479Spendry free(nn);
49947479Spendry
50047479Spendry if (!found) {
50147479Spendry lerror(fp->f_ioloc, "volname %s unknown", fp->f_volname);
50247479Spendry } else if (matched) {
50347479Spendry fixup_required_mount_info(fp, de);
50447479Spendry req = ~fp->f_mask & FM_REQUIRED;
50547479Spendry if (req) {
50647479Spendry show_required(fp->f_ioloc, req, fp->f_volname, hp->h_hostname,
50747479Spendry fsmount_strings);
50847479Spendry } else if (strcmp(fp->f_localname, "/") == 0) {
50947479Spendry hp->h_netroot = fp;
51047479Spendry netbootp |= FM_NETROOT;
51147479Spendry } else if (strcmp(fp->f_localname, "swap") == 0) {
51247479Spendry hp->h_netswap = fp;
51347479Spendry netbootp |= FM_NETSWAP;
51447479Spendry }
51547479Spendry } else {
51647479Spendry lerror(fp->f_ioloc, "volname %s not exported from %s", fp->f_volname,
51747479Spendry fp->f_from ? fp->f_from : "anywhere");
51847479Spendry }
51947479Spendry }
52047479Spendry
52147479Spendry if (netbootp && (netbootp != FM_NETBOOT))
52247479Spendry lerror(hp->h_ioloc, "network booting requires both root and swap areas");
52347479Spendry }
52447479Spendry
analyze_hosts(q)52547479Spendry void analyze_hosts(q)
52647479Spendry qelem *q;
52747479Spendry {
52847479Spendry host *hp;
52947479Spendry
53047479Spendry show_area_being_processed("analyze hosts", 5);
53147479Spendry
53247479Spendry /*
53347479Spendry * Check all drives
53447479Spendry */
53547479Spendry ITER(hp, host, q) {
53647479Spendry log("disks on host %s", hp->h_hostname);
53747479Spendry show_new("ana-host");
53847479Spendry hp->h_hostpath = compute_hostpath(hp->h_hostname);
53947479Spendry
54047479Spendry if (hp->h_disk_fs)
54147479Spendry analyze_drives(hp);
54247479Spendry
54347479Spendry }
54447479Spendry
54547479Spendry show_area_being_processed("analyze mounts", 5);
54647479Spendry
54747479Spendry /*
54847479Spendry * Check static mounts
54947479Spendry */
55047479Spendry ITER(hp, host, q) {
55147479Spendry log("mounts on host %s", hp->h_hostname);
55247479Spendry show_new("ana-mount");
55347479Spendry if (hp->h_mount)
55447479Spendry analyze_mounts(hp);
55547479Spendry
55647479Spendry }
55747479Spendry }
55847479Spendry
55947479Spendry /*
56047479Spendry * Check an automount request
56147479Spendry */
analyze_automount(ap)56247479Spendry static void analyze_automount(ap)
56347479Spendry automount *ap;
56447479Spendry {
56547479Spendry dict_ent *de = find_volname(ap->a_volname);
56647479Spendry if (de) {
56747479Spendry ap->a_mounted = de;
56847479Spendry } else {
56947479Spendry if (STREQ(ap->a_volname, ap->a_name))
57047479Spendry lerror(ap->a_ioloc, "unknown volname %s automounted", ap->a_volname);
57147479Spendry else
57247479Spendry lerror(ap->a_ioloc, "unknown volname %s automounted on %s", ap->a_volname, ap->a_name);
57347479Spendry }
57447479Spendry }
57547479Spendry
analyze_automount_tree(q,pref,lvl)57647479Spendry static void analyze_automount_tree(q, pref, lvl)
57747479Spendry qelem *q;
57847479Spendry char *pref;
57947479Spendry int lvl;
58047479Spendry {
58147479Spendry automount *ap;
58247479Spendry
58347479Spendry ITER(ap, automount, q) {
58447479Spendry char nname[1024];
58547479Spendry if (lvl > 0 || ap->a_mount)
58647479Spendry if (ap->a_name[1] && strchr(ap->a_name+1, '/'))
58747479Spendry lerror(ap->a_ioloc, "not allowed '/' in a directory name");
58847479Spendry sprintf(nname, "%s/%s", pref, ap->a_name);
58947479Spendry free(ap->a_name);
59047479Spendry ap->a_name = strdup(nname[1] == '/' ? nname+1 : nname);
59147479Spendry log("automount point %s:", ap->a_name);
59247479Spendry show_new("ana-automount");
59347479Spendry if (ap->a_mount) {
59447479Spendry analyze_automount_tree(ap->a_mount, ap->a_name, lvl+1);
59547479Spendry } else if (ap->a_volname) {
59647479Spendry log("\tautomount from %s", ap->a_volname);
59747479Spendry analyze_automount(ap);
59847479Spendry } else if (ap->a_symlink) {
59947479Spendry log("\tsymlink to %s", ap->a_symlink);
60047479Spendry } else {
60147479Spendry ap->a_volname = strdup(ap->a_name);
60247479Spendry log("\timplicit automount from %s", ap->a_volname);
60347479Spendry analyze_automount(ap);
60447479Spendry }
60547479Spendry }
60647479Spendry }
60747479Spendry
analyze_automounts(q)60847479Spendry void analyze_automounts(q)
60947479Spendry qelem *q;
61047479Spendry {
61147479Spendry auto_tree *tp;
61247479Spendry
61347479Spendry show_area_being_processed("analyze automount", 5);
61447479Spendry /*
61547479Spendry * q is a list of automounts
61647479Spendry */
61747479Spendry ITER(tp, auto_tree, q)
61847479Spendry analyze_automount_tree(tp->t_mount, "", 0);
61947479Spendry }
620