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