1*47479Spendry /* 2*47479Spendry * $Id: fsi_analyze.c,v 5.2.1.2 90/12/21 16:46:44 jsp Alpha $ 3*47479Spendry * 4*47479Spendry * Copyright (c) 1989 Jan-Simon Pendry 5*47479Spendry * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 6*47479Spendry * Copyright (c) 1989 The Regents of the University of California. 7*47479Spendry * All rights reserved. 8*47479Spendry * 9*47479Spendry * This code is derived from software contributed to Berkeley by 10*47479Spendry * Jan-Simon Pendry at Imperial College, London. 11*47479Spendry * 12*47479Spendry * Redistribution and use in source and binary forms are permitted provided 13*47479Spendry * that: (1) source distributions retain this entire copyright notice and 14*47479Spendry * comment, and (2) distributions including binaries display the following 15*47479Spendry * acknowledgement: ``This product includes software developed by the 16*47479Spendry * University of California, Berkeley and its contributors'' in the 17*47479Spendry * documentation or other materials provided with the distribution and in 18*47479Spendry * all advertising materials mentioning features or use of this software. 19*47479Spendry * Neither the name of the University nor the names of its contributors may 20*47479Spendry * be used to endorse or promote products derived from this software without 21*47479Spendry * specific prior written permission. 22*47479Spendry * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 23*47479Spendry * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 24*47479Spendry * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 25*47479Spendry * 26*47479Spendry * @(#)fsi_analyze.c 5.1 (Berkeley) 03/17/91 27*47479Spendry * 28*47479Spendry */ 29*47479Spendry 30*47479Spendry /* 31*47479Spendry * Analyze filesystem declarations 32*47479Spendry * 33*47479Spendry * Note: most of this is magic! 34*47479Spendry */ 35*47479Spendry 36*47479Spendry #include "../fsinfo/fsinfo.h" 37*47479Spendry 38*47479Spendry char *disk_fs_strings[] = { 39*47479Spendry "fstype", "opts", "dumpset", "passno", "freq", "mount", "log", 0, 40*47479Spendry }; 41*47479Spendry 42*47479Spendry char *mount_strings[] = { 43*47479Spendry "volname", "exportfs", 0, 44*47479Spendry }; 45*47479Spendry 46*47479Spendry char *fsmount_strings[] = { 47*47479Spendry "as", "volname", "fstype", "opts", "from", 0, 48*47479Spendry }; 49*47479Spendry 50*47479Spendry char *host_strings[] = { 51*47479Spendry "host", "netif", "config", "arch", "cluster", "os", 0, 52*47479Spendry }; 53*47479Spendry 54*47479Spendry char *ether_if_strings[] = { 55*47479Spendry "inaddr", "netmask", "hwaddr", 0, 56*47479Spendry }; 57*47479Spendry 58*47479Spendry /* 59*47479Spendry * Strip off the trailing part of a domain 60*47479Spendry * to produce a short-form domain relative 61*47479Spendry * to the local host domain. 62*47479Spendry * Note that this has no effect if the domain 63*47479Spendry * names do not have the same number of 64*47479Spendry * components. If that restriction proves 65*47479Spendry * to be a problem then the loop needs recoding 66*47479Spendry * to skip from right to left and do partial 67*47479Spendry * matches along the way -- ie more expensive. 68*47479Spendry */ 69*47479Spendry void domain_strip(otherdom, localdom) 70*47479Spendry char *otherdom, *localdom; 71*47479Spendry { 72*47479Spendry #ifdef PARTIAL_DOMAINS 73*47479Spendry char *p1 = otherdom-1; 74*47479Spendry char *p2 = localdom-1; 75*47479Spendry 76*47479Spendry do { 77*47479Spendry if (p1 = strchr(p1+1, '.')) 78*47479Spendry if (p2 = strchr(p2+1, '.')) 79*47479Spendry if (STREQ(p1+1, p2+1)) { 80*47479Spendry *p1 = '\0'; 81*47479Spendry break; 82*47479Spendry } 83*47479Spendry } while (p1 && p2); 84*47479Spendry #else 85*47479Spendry char *p1, *p2; 86*47479Spendry 87*47479Spendry if ((p1 = strchr(otherdom, '.')) && 88*47479Spendry (p2 = strchr(localdom, '.')) && 89*47479Spendry (strcmp(p1+1, p2+1) == 0)) 90*47479Spendry *p1 = '\0'; 91*47479Spendry #endif /* PARTIAL_DOMAINS */ 92*47479Spendry } 93*47479Spendry 94*47479Spendry /* 95*47479Spendry * Take a little-endian domain name and 96*47479Spendry * transform into a big-endian Un*x pathname. 97*47479Spendry * For example: kiska.doc.ic -> ic/doc/kiska 98*47479Spendry */ 99*47479Spendry static char *compute_hostpath(hn) 100*47479Spendry char *hn; 101*47479Spendry { 102*47479Spendry char *p = strdup(hn); 103*47479Spendry char *d; 104*47479Spendry char path[MAXPATHLEN]; 105*47479Spendry 106*47479Spendry domain_strip(p, hostname); 107*47479Spendry path[0] = '\0'; 108*47479Spendry 109*47479Spendry do { 110*47479Spendry d = strrchr(p, '.'); 111*47479Spendry if (d) { 112*47479Spendry *d = 0; 113*47479Spendry strcat(path, d+1); 114*47479Spendry strcat(path, "/"); 115*47479Spendry } else { 116*47479Spendry strcat(path, p); 117*47479Spendry } 118*47479Spendry } while (d); 119*47479Spendry 120*47479Spendry log("hostpath of '%s' is '%s'", hn, path); 121*47479Spendry 122*47479Spendry strcpy(p, path); 123*47479Spendry return p; 124*47479Spendry } 125*47479Spendry 126*47479Spendry static dict_ent *find_volname(nn) 127*47479Spendry char *nn; 128*47479Spendry { 129*47479Spendry dict_ent *de; 130*47479Spendry char *p = strdup(nn); 131*47479Spendry char *q; 132*47479Spendry 133*47479Spendry do { 134*47479Spendry log("Searching for volname %s", p); 135*47479Spendry de = dict_locate(dict_of_volnames, p); 136*47479Spendry q = strrchr(p, '/'); 137*47479Spendry if (q) *q = '\0'; 138*47479Spendry } while (!de && q); 139*47479Spendry 140*47479Spendry free(p); 141*47479Spendry return de; 142*47479Spendry } 143*47479Spendry 144*47479Spendry static show_required(l, mask, info, hostname, strings) 145*47479Spendry ioloc *l; 146*47479Spendry int mask; 147*47479Spendry char *info; 148*47479Spendry char *hostname; 149*47479Spendry char *strings[]; 150*47479Spendry { 151*47479Spendry int i; 152*47479Spendry log("mask left for %s:%s is %#x", hostname, info, mask); 153*47479Spendry 154*47479Spendry for (i = 0; strings[i]; i++) 155*47479Spendry if (ISSET(mask, i)) 156*47479Spendry lerror(l, "%s:%s needs field \"%s\"", hostname, info, strings[i]); 157*47479Spendry } 158*47479Spendry 159*47479Spendry /* 160*47479Spendry * Check and fill in "exportfs" details. 161*47479Spendry * Make sure the m_exported field references 162*47479Spendry * the most local node with an "exportfs" entry. 163*47479Spendry */ 164*47479Spendry static int check_exportfs(q, e) 165*47479Spendry qelem *q; 166*47479Spendry mount *e; 167*47479Spendry { 168*47479Spendry mount *mp; 169*47479Spendry int errors = 0; 170*47479Spendry 171*47479Spendry ITER(mp, mount, q) { 172*47479Spendry if (ISSET(mp->m_mask, DM_EXPORTFS)) { 173*47479Spendry if (e) 174*47479Spendry lwarning(mp->m_ioloc, "%s has duplicate exportfs data", mp->m_name); 175*47479Spendry mp->m_exported = mp; 176*47479Spendry if (!ISSET(mp->m_mask, DM_VOLNAME)) 177*47479Spendry set_mount(mp, DM_VOLNAME, strdup(mp->m_name)); 178*47479Spendry } else { 179*47479Spendry mp->m_exported = e; 180*47479Spendry } 181*47479Spendry 182*47479Spendry /* 183*47479Spendry * Recursively descend the mount tree 184*47479Spendry */ 185*47479Spendry if (mp->m_mount) 186*47479Spendry errors += check_exportfs(mp->m_mount, mp->m_exported); 187*47479Spendry 188*47479Spendry /* 189*47479Spendry * If a volume name has been specified, but this node and none 190*47479Spendry * of its parents has been exported, report an error. 191*47479Spendry */ 192*47479Spendry if (ISSET(mp->m_mask, DM_VOLNAME) && !mp->m_exported) { 193*47479Spendry lerror(mp->m_ioloc, "%s has a volname but no exportfs data", mp->m_name); 194*47479Spendry errors++; 195*47479Spendry } 196*47479Spendry } 197*47479Spendry 198*47479Spendry return errors; 199*47479Spendry } 200*47479Spendry 201*47479Spendry static int analyze_dkmount_tree(q, parent, dk) 202*47479Spendry qelem *q; 203*47479Spendry mount *parent; 204*47479Spendry disk_fs *dk; 205*47479Spendry { 206*47479Spendry mount *mp; 207*47479Spendry int errors = 0; 208*47479Spendry 209*47479Spendry ITER(mp, mount, q) { 210*47479Spendry log("Mount %s:", mp->m_name); 211*47479Spendry if (parent) { 212*47479Spendry char n[MAXPATHLEN]; 213*47479Spendry sprintf(n, "%s/%s", parent->m_name, mp->m_name); 214*47479Spendry if (*mp->m_name == '/') 215*47479Spendry lerror(mp->m_ioloc, "sub-directory %s of %s starts with '/'", mp->m_name, parent->m_name); 216*47479Spendry else if (STREQ(mp->m_name, "default")) 217*47479Spendry lwarning(mp->m_ioloc, "sub-directory of %s is named \"default\"", parent->m_name); 218*47479Spendry log("Changing name %s to %s", mp->m_name, n); 219*47479Spendry free(mp->m_name); 220*47479Spendry mp->m_name = strdup(n); 221*47479Spendry } 222*47479Spendry mp->m_name_len = strlen(mp->m_name); 223*47479Spendry mp->m_parent = parent; 224*47479Spendry mp->m_dk = dk; 225*47479Spendry if (mp->m_mount) 226*47479Spendry analyze_dkmount_tree(mp->m_mount, mp, dk); 227*47479Spendry } 228*47479Spendry 229*47479Spendry return errors; 230*47479Spendry } 231*47479Spendry 232*47479Spendry /* 233*47479Spendry * The mount tree is a singleton list 234*47479Spendry * containing the top-level mount 235*47479Spendry * point for a disk. 236*47479Spendry */ 237*47479Spendry static int analyze_dkmounts(dk, q) 238*47479Spendry disk_fs *dk; 239*47479Spendry qelem *q; 240*47479Spendry { 241*47479Spendry int errors = 0; 242*47479Spendry mount *mp, *mp2 = 0; 243*47479Spendry int i = 0; 244*47479Spendry 245*47479Spendry /* 246*47479Spendry * First scan the list of subdirs to make 247*47479Spendry * sure there is only one - and remember it 248*47479Spendry */ 249*47479Spendry if (q) { 250*47479Spendry ITER(mp, mount, q) { 251*47479Spendry mp2 = mp; 252*47479Spendry i++; 253*47479Spendry } 254*47479Spendry } 255*47479Spendry 256*47479Spendry /* 257*47479Spendry * Check... 258*47479Spendry */ 259*47479Spendry if (i < 1) { 260*47479Spendry lerror(dk->d_ioloc, "%s:%s has no mount point", dk->d_host->h_hostname, dk->d_dev); 261*47479Spendry return 1; 262*47479Spendry } 263*47479Spendry if (i > 1) { 264*47479Spendry lerror(dk->d_ioloc, "%s:%s has more than one mount point", dk->d_host->h_hostname, dk->d_dev); 265*47479Spendry errors++; 266*47479Spendry } 267*47479Spendry /* 268*47479Spendry * Now see if a default mount point is required 269*47479Spendry */ 270*47479Spendry if (STREQ(mp2->m_name, "default")) { 271*47479Spendry if (ISSET(mp2->m_mask, DM_VOLNAME)) { 272*47479Spendry char nbuf[1024]; 273*47479Spendry compute_automount_point(nbuf, dk->d_host, mp2->m_volname); 274*47479Spendry free(mp2->m_name); 275*47479Spendry mp2->m_name = strdup(nbuf); 276*47479Spendry log("%s:%s has default mount on %s", dk->d_host->h_hostname, dk->d_dev, mp2->m_name); 277*47479Spendry } else { 278*47479Spendry lerror(dk->d_ioloc, "no volname given for %s:%s", dk->d_host->h_hostname, dk->d_dev); 279*47479Spendry errors++; 280*47479Spendry } 281*47479Spendry } 282*47479Spendry /* 283*47479Spendry * Fill in the disk mount point 284*47479Spendry */ 285*47479Spendry if (!errors && mp2 && mp2->m_name) 286*47479Spendry dk->d_mountpt = strdup(mp2->m_name); 287*47479Spendry else 288*47479Spendry dk->d_mountpt = strdup("error"); 289*47479Spendry 290*47479Spendry /* 291*47479Spendry * Analyze the mount tree 292*47479Spendry */ 293*47479Spendry errors += analyze_dkmount_tree(q, 0, dk); 294*47479Spendry 295*47479Spendry /* 296*47479Spendry * Analyze the export tree 297*47479Spendry */ 298*47479Spendry errors += check_exportfs(q, 0); 299*47479Spendry 300*47479Spendry return errors; 301*47479Spendry } 302*47479Spendry 303*47479Spendry static void fixup_required_disk_info(dp) 304*47479Spendry disk_fs *dp; 305*47479Spendry { 306*47479Spendry /* 307*47479Spendry * "fstype" 308*47479Spendry */ 309*47479Spendry if (ISSET(dp->d_mask, DF_FSTYPE)) { 310*47479Spendry if (STREQ(dp->d_fstype, "swap")) { 311*47479Spendry /* 312*47479Spendry * Fixup for a swap device 313*47479Spendry */ 314*47479Spendry if (!ISSET(dp->d_mask, DF_PASSNO)) { 315*47479Spendry dp->d_passno = 0; 316*47479Spendry BITSET(dp->d_mask, DF_PASSNO); 317*47479Spendry } else if (dp->d_freq != 0) { 318*47479Spendry lwarning(dp->d_ioloc, 319*47479Spendry "Pass number for %s:%s is non-zero", 320*47479Spendry dp->d_host->h_hostname, dp->d_dev); 321*47479Spendry } 322*47479Spendry 323*47479Spendry /* 324*47479Spendry * "freq" 325*47479Spendry */ 326*47479Spendry if (!ISSET(dp->d_mask, DF_FREQ)) { 327*47479Spendry dp->d_freq = 0; 328*47479Spendry BITSET(dp->d_mask, DF_FREQ); 329*47479Spendry } else if (dp->d_freq != 0) { 330*47479Spendry lwarning(dp->d_ioloc, 331*47479Spendry "dump frequency for %s:%s is non-zero", 332*47479Spendry dp->d_host->h_hostname, dp->d_dev); 333*47479Spendry } 334*47479Spendry 335*47479Spendry /* 336*47479Spendry * "opts" 337*47479Spendry */ 338*47479Spendry if (!ISSET(dp->d_mask, DF_OPTS)) 339*47479Spendry set_disk_fs(dp, DF_OPTS, strdup("swap")); 340*47479Spendry 341*47479Spendry /* 342*47479Spendry * "mount" 343*47479Spendry */ 344*47479Spendry if (!ISSET(dp->d_mask, DF_MOUNT)) { 345*47479Spendry qelem *q = new_que(); 346*47479Spendry mount *m = new_mount(); 347*47479Spendry m->m_name = strdup("swap"); 348*47479Spendry m->m_mount = new_que(); 349*47479Spendry ins_que(&m->m_q, q->q_back); 350*47479Spendry dp->d_mount = q; 351*47479Spendry BITSET(dp->d_mask, DF_MOUNT); 352*47479Spendry } else { 353*47479Spendry lerror(dp->d_ioloc, "%s: mount field specified for swap partition", dp->d_host->h_hostname); 354*47479Spendry } 355*47479Spendry } else if (STREQ(dp->d_fstype, "export")) { 356*47479Spendry /* 357*47479Spendry * "passno" 358*47479Spendry */ 359*47479Spendry if (!ISSET(dp->d_mask, DF_PASSNO)) { 360*47479Spendry dp->d_passno = 0; 361*47479Spendry BITSET(dp->d_mask, DF_PASSNO); 362*47479Spendry } else if (dp->d_passno != 0) { 363*47479Spendry lwarning(dp->d_ioloc, 364*47479Spendry "pass number for %s:%s is non-zero", 365*47479Spendry dp->d_host->h_hostname, dp->d_dev); 366*47479Spendry } 367*47479Spendry 368*47479Spendry /* 369*47479Spendry * "freq" 370*47479Spendry */ 371*47479Spendry if (!ISSET(dp->d_mask, DF_FREQ)) { 372*47479Spendry dp->d_freq = 0; 373*47479Spendry BITSET(dp->d_mask, DF_FREQ); 374*47479Spendry } else if (dp->d_freq != 0) { 375*47479Spendry lwarning(dp->d_ioloc, 376*47479Spendry "dump frequency for %s:%s is non-zero", 377*47479Spendry dp->d_host->h_hostname, dp->d_dev); 378*47479Spendry } 379*47479Spendry 380*47479Spendry /* 381*47479Spendry * "opts" 382*47479Spendry */ 383*47479Spendry if (!ISSET(dp->d_mask, DF_OPTS)) 384*47479Spendry set_disk_fs(dp, DF_OPTS, strdup("rw,defaults")); 385*47479Spendry 386*47479Spendry } 387*47479Spendry } 388*47479Spendry } 389*47479Spendry 390*47479Spendry static void fixup_required_mount_info(fp, de) 391*47479Spendry fsmount *fp; 392*47479Spendry dict_ent *de; 393*47479Spendry { 394*47479Spendry if (!ISSET(fp->f_mask, FM_FROM)) { 395*47479Spendry if (de->de_count != 1) { 396*47479Spendry lerror(fp->f_ioloc, "ambiguous mount: %s is a replicated filesystem", fp->f_volname); 397*47479Spendry } else { 398*47479Spendry dict_data *dd; 399*47479Spendry mount *mp = 0; 400*47479Spendry ITER(dd, dict_data, &de->de_q) { 401*47479Spendry mp = (mount *) dd->dd_data; 402*47479Spendry break; 403*47479Spendry } 404*47479Spendry if (!mp) 405*47479Spendry abort(); 406*47479Spendry fp->f_ref = mp; 407*47479Spendry set_fsmount(fp, FM_FROM, mp->m_dk->d_host->h_hostname); 408*47479Spendry log("set: %s comes from %s", fp->f_volname, fp->f_from); 409*47479Spendry } 410*47479Spendry } 411*47479Spendry 412*47479Spendry if (!ISSET(fp->f_mask, FM_FSTYPE)) { 413*47479Spendry set_fsmount(fp, FM_FSTYPE, strdup("nfs")); 414*47479Spendry log("set: fstype is %s", fp->f_fstype); 415*47479Spendry } 416*47479Spendry 417*47479Spendry if (!ISSET(fp->f_mask, FM_OPTS)) { 418*47479Spendry set_fsmount(fp, FM_OPTS, strdup("rw,nosuid,grpid,defaults")); 419*47479Spendry log("set: opts are %s", fp->f_opts); 420*47479Spendry } 421*47479Spendry 422*47479Spendry if (!ISSET(fp->f_mask, FM_LOCALNAME)) { 423*47479Spendry if (fp->f_ref) { 424*47479Spendry set_fsmount(fp, FM_LOCALNAME, strdup(fp->f_volname)); 425*47479Spendry log("set: localname is %s", fp->f_localname); 426*47479Spendry } else { 427*47479Spendry lerror(fp->f_ioloc, "cannot determine localname since volname %s is not uniquely defined", fp->f_volname); 428*47479Spendry } 429*47479Spendry } 430*47479Spendry } 431*47479Spendry 432*47479Spendry /* 433*47479Spendry * For each disk on a host 434*47479Spendry * analyze the mount information 435*47479Spendry * and fill in any derivable 436*47479Spendry * details. 437*47479Spendry */ 438*47479Spendry static void analyze_drives(hp) 439*47479Spendry host *hp; 440*47479Spendry { 441*47479Spendry qelem *q = hp->h_disk_fs; 442*47479Spendry disk_fs *dp; 443*47479Spendry 444*47479Spendry ITER(dp, disk_fs, q) { 445*47479Spendry int req; 446*47479Spendry log("Disk %s:", dp->d_dev); 447*47479Spendry dp->d_host = hp; 448*47479Spendry fixup_required_disk_info(dp); 449*47479Spendry req = ~dp->d_mask & DF_REQUIRED; 450*47479Spendry if (req) 451*47479Spendry show_required(dp->d_ioloc, req, dp->d_dev, hp->h_hostname, disk_fs_strings); 452*47479Spendry analyze_dkmounts(dp, dp->d_mount); 453*47479Spendry } 454*47479Spendry } 455*47479Spendry 456*47479Spendry /* 457*47479Spendry * Check that all static mounts make sense and 458*47479Spendry * that the source volumes exist. 459*47479Spendry */ 460*47479Spendry static void analyze_mounts(hp) 461*47479Spendry host *hp; 462*47479Spendry { 463*47479Spendry qelem *q = hp->h_mount; 464*47479Spendry fsmount *fp; 465*47479Spendry int netbootp = 0; 466*47479Spendry 467*47479Spendry ITER(fp, fsmount, q) { 468*47479Spendry char *p; 469*47479Spendry char *nn = strdup(fp->f_volname); 470*47479Spendry int req; 471*47479Spendry dict_ent *de; 472*47479Spendry int found = 0; 473*47479Spendry int matched = 0; 474*47479Spendry do { 475*47479Spendry p = 0; 476*47479Spendry de = find_volname(nn); 477*47479Spendry log("Mount: %s (trying %s)", fp->f_volname, nn); 478*47479Spendry 479*47479Spendry if (de) { 480*47479Spendry found = 1; 481*47479Spendry /* 482*47479Spendry * Check that the from field is really exporting 483*47479Spendry * the filesystem requested. 484*47479Spendry */ 485*47479Spendry if (ISSET(fp->f_mask, FM_FROM)) { 486*47479Spendry dict_data *dd; 487*47479Spendry mount *mp2 = 0; 488*47479Spendry ITER(dd, dict_data, &de->de_q) { 489*47479Spendry mount *mp = (mount *) dd->dd_data; 490*47479Spendry if (STREQ(mp->m_dk->d_host->h_hostname, fp->f_from)) { 491*47479Spendry mp2 = mp; 492*47479Spendry break; 493*47479Spendry } 494*47479Spendry } 495*47479Spendry 496*47479Spendry if (mp2) { 497*47479Spendry fp->f_ref = mp2; 498*47479Spendry matched = 1; 499*47479Spendry break; 500*47479Spendry } 501*47479Spendry } else { 502*47479Spendry matched = 1; 503*47479Spendry break; 504*47479Spendry } 505*47479Spendry } 506*47479Spendry p = strrchr(nn, '/'); 507*47479Spendry if (p) 508*47479Spendry *p = 0; 509*47479Spendry } while (de && p); 510*47479Spendry free(nn); 511*47479Spendry 512*47479Spendry if (!found) { 513*47479Spendry lerror(fp->f_ioloc, "volname %s unknown", fp->f_volname); 514*47479Spendry } else if (matched) { 515*47479Spendry fixup_required_mount_info(fp, de); 516*47479Spendry req = ~fp->f_mask & FM_REQUIRED; 517*47479Spendry if (req) { 518*47479Spendry show_required(fp->f_ioloc, req, fp->f_volname, hp->h_hostname, 519*47479Spendry fsmount_strings); 520*47479Spendry } else if (strcmp(fp->f_localname, "/") == 0) { 521*47479Spendry hp->h_netroot = fp; 522*47479Spendry netbootp |= FM_NETROOT; 523*47479Spendry } else if (strcmp(fp->f_localname, "swap") == 0) { 524*47479Spendry hp->h_netswap = fp; 525*47479Spendry netbootp |= FM_NETSWAP; 526*47479Spendry } 527*47479Spendry } else { 528*47479Spendry lerror(fp->f_ioloc, "volname %s not exported from %s", fp->f_volname, 529*47479Spendry fp->f_from ? fp->f_from : "anywhere"); 530*47479Spendry } 531*47479Spendry } 532*47479Spendry 533*47479Spendry if (netbootp && (netbootp != FM_NETBOOT)) 534*47479Spendry lerror(hp->h_ioloc, "network booting requires both root and swap areas"); 535*47479Spendry } 536*47479Spendry 537*47479Spendry void analyze_hosts(q) 538*47479Spendry qelem *q; 539*47479Spendry { 540*47479Spendry host *hp; 541*47479Spendry 542*47479Spendry show_area_being_processed("analyze hosts", 5); 543*47479Spendry 544*47479Spendry /* 545*47479Spendry * Check all drives 546*47479Spendry */ 547*47479Spendry ITER(hp, host, q) { 548*47479Spendry log("disks on host %s", hp->h_hostname); 549*47479Spendry show_new("ana-host"); 550*47479Spendry hp->h_hostpath = compute_hostpath(hp->h_hostname); 551*47479Spendry 552*47479Spendry if (hp->h_disk_fs) 553*47479Spendry analyze_drives(hp); 554*47479Spendry 555*47479Spendry } 556*47479Spendry 557*47479Spendry show_area_being_processed("analyze mounts", 5); 558*47479Spendry 559*47479Spendry /* 560*47479Spendry * Check static mounts 561*47479Spendry */ 562*47479Spendry ITER(hp, host, q) { 563*47479Spendry log("mounts on host %s", hp->h_hostname); 564*47479Spendry show_new("ana-mount"); 565*47479Spendry if (hp->h_mount) 566*47479Spendry analyze_mounts(hp); 567*47479Spendry 568*47479Spendry } 569*47479Spendry } 570*47479Spendry 571*47479Spendry /* 572*47479Spendry * Check an automount request 573*47479Spendry */ 574*47479Spendry static void analyze_automount(ap) 575*47479Spendry automount *ap; 576*47479Spendry { 577*47479Spendry dict_ent *de = find_volname(ap->a_volname); 578*47479Spendry if (de) { 579*47479Spendry ap->a_mounted = de; 580*47479Spendry } else { 581*47479Spendry if (STREQ(ap->a_volname, ap->a_name)) 582*47479Spendry lerror(ap->a_ioloc, "unknown volname %s automounted", ap->a_volname); 583*47479Spendry else 584*47479Spendry lerror(ap->a_ioloc, "unknown volname %s automounted on %s", ap->a_volname, ap->a_name); 585*47479Spendry } 586*47479Spendry } 587*47479Spendry 588*47479Spendry static void analyze_automount_tree(q, pref, lvl) 589*47479Spendry qelem *q; 590*47479Spendry char *pref; 591*47479Spendry int lvl; 592*47479Spendry { 593*47479Spendry automount *ap; 594*47479Spendry 595*47479Spendry ITER(ap, automount, q) { 596*47479Spendry char nname[1024]; 597*47479Spendry if (lvl > 0 || ap->a_mount) 598*47479Spendry if (ap->a_name[1] && strchr(ap->a_name+1, '/')) 599*47479Spendry lerror(ap->a_ioloc, "not allowed '/' in a directory name"); 600*47479Spendry sprintf(nname, "%s/%s", pref, ap->a_name); 601*47479Spendry free(ap->a_name); 602*47479Spendry ap->a_name = strdup(nname[1] == '/' ? nname+1 : nname); 603*47479Spendry log("automount point %s:", ap->a_name); 604*47479Spendry show_new("ana-automount"); 605*47479Spendry if (ap->a_mount) { 606*47479Spendry analyze_automount_tree(ap->a_mount, ap->a_name, lvl+1); 607*47479Spendry } else if (ap->a_volname) { 608*47479Spendry log("\tautomount from %s", ap->a_volname); 609*47479Spendry analyze_automount(ap); 610*47479Spendry } else if (ap->a_symlink) { 611*47479Spendry log("\tsymlink to %s", ap->a_symlink); 612*47479Spendry } else { 613*47479Spendry ap->a_volname = strdup(ap->a_name); 614*47479Spendry log("\timplicit automount from %s", ap->a_volname); 615*47479Spendry analyze_automount(ap); 616*47479Spendry } 617*47479Spendry } 618*47479Spendry } 619*47479Spendry 620*47479Spendry void analyze_automounts(q) 621*47479Spendry qelem *q; 622*47479Spendry { 623*47479Spendry auto_tree *tp; 624*47479Spendry 625*47479Spendry show_area_being_processed("analyze automount", 5); 626*47479Spendry /* 627*47479Spendry * q is a list of automounts 628*47479Spendry */ 629*47479Spendry ITER(tp, auto_tree, q) 630*47479Spendry analyze_automount_tree(tp->t_mount, "", 0); 631*47479Spendry } 632