147479Spendry /* 247479Spendry * $Id: fsi_analyze.c,v 5.2.1.2 90/12/21 16:46:44 jsp Alpha $ 347479Spendry * 447479Spendry * Copyright (c) 1989 Jan-Simon Pendry 547479Spendry * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 647479Spendry * Copyright (c) 1989 The Regents of the University of California. 747479Spendry * All rights reserved. 847479Spendry * 947479Spendry * This code is derived from software contributed to Berkeley by 1047479Spendry * Jan-Simon Pendry at Imperial College, London. 1147479Spendry * 12*47530Spendry * %sccs.include.redist.c% 1347479Spendry * 14*47530Spendry * @(#)fsi_analyze.c 5.2 (Berkeley) 03/17/91 1547479Spendry * 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 */ 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 */ 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 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 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 */ 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 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 */ 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 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 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 */ 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 */ 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 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 */ 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 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 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