1174294Sobrien/* 2310490Scy * Copyright (c) 1997-2014 Erez Zadok 3174294Sobrien * Copyright (c) 1990 Jan-Simon Pendry 4174294Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5174294Sobrien * Copyright (c) 1990 The Regents of the University of California. 6174294Sobrien * All rights reserved. 7174294Sobrien * 8174294Sobrien * This code is derived from software contributed to Berkeley by 9174294Sobrien * Jan-Simon Pendry at Imperial College, London. 10174294Sobrien * 11174294Sobrien * Redistribution and use in source and binary forms, with or without 12174294Sobrien * modification, are permitted provided that the following conditions 13174294Sobrien * are met: 14174294Sobrien * 1. Redistributions of source code must retain the above copyright 15174294Sobrien * notice, this list of conditions and the following disclaimer. 16174294Sobrien * 2. Redistributions in binary form must reproduce the above copyright 17174294Sobrien * notice, this list of conditions and the following disclaimer in the 18174294Sobrien * documentation and/or other materials provided with the distribution. 19310490Scy * 3. Neither the name of the University nor the names of its contributors 20174294Sobrien * may be used to endorse or promote products derived from this software 21174294Sobrien * without specific prior written permission. 22174294Sobrien * 23174294Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24174294Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25174294Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26174294Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27174294Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28174294Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29174294Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30174294Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31174294Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32174294Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33174294Sobrien * SUCH DAMAGE. 34174294Sobrien * 35174294Sobrien * 36174294Sobrien * File: am-utils/amd/amfs_generic.c 37174294Sobrien * 38174294Sobrien */ 39174294Sobrien 40174294Sobrien/* 41174294Sobrien * generic functions used by amfs filesystems, ripped out of amfs_auto.c. 42174294Sobrien */ 43174294Sobrien 44174294Sobrien#ifdef HAVE_CONFIG_H 45174294Sobrien# include <config.h> 46174294Sobrien#endif /* HAVE_CONFIG_H */ 47174294Sobrien#include <am_defs.h> 48174294Sobrien#include <amd.h> 49174294Sobrien 50174294Sobrien 51174294Sobrien/**************************************************************************** 52174294Sobrien *** MACROS *** 53174294Sobrien ****************************************************************************/ 54310490Scy#define IN_PROGRESS(cp) ((cp)->mp->am_al->al_mnt->mf_flags & MFF_MOUNTING) 55174294Sobrien 56174294Sobrien 57174294Sobrien/**************************************************************************** 58174294Sobrien *** STRUCTURES *** 59174294Sobrien ****************************************************************************/ 60174294Sobrien/* 61174294Sobrien * Mounting a file system may take a significant period of time. The 62174294Sobrien * problem is that if this is done in the main process thread then the 63174294Sobrien * entire automounter could be blocked, possibly hanging lots of processes 64174294Sobrien * on the system. Instead we use a continuation scheme to allow mounts to 65174294Sobrien * be attempted in a sub-process. When the sub-process exits we pick up the 66174294Sobrien * exit status (by convention a UN*X error number) and continue in a 67174294Sobrien * notifier. The notifier gets handed a data structure and can then 68174294Sobrien * determine whether the mount was successful or not. If not, it updates 69174294Sobrien * the data structure and tries again until there are no more ways to try 70174294Sobrien * the mount, or some other permanent error occurs. In the mean time no RPC 71174294Sobrien * reply is sent, even after the mount is successful. We rely on the RPC 72174294Sobrien * retry mechanism to resend the lookup request which can then be handled. 73174294Sobrien */ 74174294Sobrienstruct continuation { 75174294Sobrien am_node *mp; /* Node we are trying to mount */ 76174294Sobrien int retry; /* Try again? */ 77174294Sobrien time_t start; /* Time we started this mount */ 78174294Sobrien int callout; /* Callout identifier */ 79310490Scy am_loc **al; /* Current location */ 80174294Sobrien}; 81174294Sobrien 82174294Sobrien 83174294Sobrien/**************************************************************************** 84174294Sobrien *** FORWARD DEFINITIONS *** 85174294Sobrien ****************************************************************************/ 86174294Sobrienstatic am_node *amfs_lookup_node(am_node *mp, char *fname, int *error_return); 87310490Scystatic am_loc *amfs_lookup_one_location(am_node *new_mp, mntfs *mf, char *ivec, 88174294Sobrien char *def_opts, char *pfname); 89310490Scystatic am_loc **amfs_lookup_loc(am_node *new_mp, int *error_return); 90174294Sobrienstatic void amfs_cont(int rc, int term, opaque_t arg); 91174294Sobrienstatic void amfs_retry(int rc, int term, opaque_t arg); 92174294Sobrienstatic void free_continuation(struct continuation *cp); 93174294Sobrienstatic int amfs_bgmount(struct continuation *cp); 94174294Sobrienstatic char *amfs_parse_defaults(am_node *mp, mntfs *mf, char *def_opts); 95174294Sobrien 96174294Sobrien 97174294Sobrien/**************************************************************************** 98174294Sobrien *** FUNCTIONS *** 99174294Sobrien ****************************************************************************/ 100174294Sobrienstatic am_node * 101174294Sobrienamfs_lookup_node(am_node *mp, char *fname, int *error_return) 102174294Sobrien{ 103174294Sobrien am_node *new_mp; 104174294Sobrien int error = 0; /* Error so far */ 105174294Sobrien int in_progress = 0; /* # of (un)mount in progress */ 106174294Sobrien mntfs *mf; 107310490Scy char *expanded_fname = NULL; 108174294Sobrien 109174294Sobrien dlog("in amfs_lookup_node"); 110174294Sobrien 111174294Sobrien /* 112174294Sobrien * If the server is shutting down 113174294Sobrien * then don't return information 114174294Sobrien * about the mount point. 115174294Sobrien */ 116174294Sobrien if (amd_state == Finishing) { 117310490Scy if (mp->am_al == NULL || mp->am_al->al_mnt == NULL || mp->am_al->al_mnt->mf_fsflags & FS_DIRECT) { 118174294Sobrien dlog("%s mount ignored - going down", fname); 119174294Sobrien } else { 120174294Sobrien dlog("%s/%s mount ignored - going down", mp->am_path, fname); 121174294Sobrien } 122174294Sobrien ereturn(ENOENT); 123174294Sobrien } 124174294Sobrien 125174294Sobrien /* 126174294Sobrien * Handle special case of "." and ".." 127174294Sobrien */ 128174294Sobrien if (fname[0] == '.') { 129174294Sobrien if (fname[1] == '\0') 130174294Sobrien return mp; /* "." is the current node */ 131174294Sobrien if (fname[1] == '.' && fname[2] == '\0') { 132174294Sobrien if (mp->am_parent) { 133174294Sobrien dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path); 134174294Sobrien return mp->am_parent; /* ".." is the parent node */ 135174294Sobrien } 136174294Sobrien ereturn(ESTALE); 137174294Sobrien } 138174294Sobrien } 139174294Sobrien 140174294Sobrien /* 141174294Sobrien * Check for valid key name. 142174294Sobrien * If it is invalid then pretend it doesn't exist. 143174294Sobrien */ 144174294Sobrien if (!valid_key(fname)) { 145174294Sobrien plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname); 146174294Sobrien ereturn(ENOENT); 147174294Sobrien } 148174294Sobrien 149174294Sobrien /* 150174294Sobrien * Expand key name. 151174294Sobrien * expanded_fname is now a private copy. 152174294Sobrien */ 153174294Sobrien expanded_fname = expand_selectors(fname); 154174294Sobrien 155174294Sobrien /* 156174294Sobrien * Search children of this node 157174294Sobrien */ 158174294Sobrien for (new_mp = mp->am_child; new_mp; new_mp = new_mp->am_osib) { 159174294Sobrien if (FSTREQ(new_mp->am_name, expanded_fname)) { 160174294Sobrien if (new_mp->am_error) { 161174294Sobrien error = new_mp->am_error; 162174294Sobrien continue; 163174294Sobrien } 164174294Sobrien 165174294Sobrien /* 166174294Sobrien * If the error code is undefined then it must be 167174294Sobrien * in progress. 168174294Sobrien */ 169310490Scy mf = new_mp->am_al->al_mnt; 170174294Sobrien if (mf->mf_error < 0) 171174294Sobrien goto in_progrss; 172174294Sobrien 173174294Sobrien /* 174174294Sobrien * If there was a previous error with this node 175174294Sobrien * then return that error code. 176174294Sobrien */ 177174294Sobrien if (mf->mf_flags & MFF_ERROR) { 178174294Sobrien error = mf->mf_error; 179174294Sobrien continue; 180174294Sobrien } 181174294Sobrien if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) { 182174294Sobrien in_progrss: 183174294Sobrien /* 184174294Sobrien * If the fs is not mounted or it is unmounting then there 185174294Sobrien * is a background (un)mount in progress. In this case 186174294Sobrien * we just drop the RPC request (return nil) and 187174294Sobrien * wait for a retry, by which time the (un)mount may 188174294Sobrien * have completed. 189174294Sobrien */ 190174294Sobrien dlog("ignoring mount of %s in %s -- %smounting in progress, flags %x", 191174294Sobrien expanded_fname, mf->mf_mount, 192174294Sobrien (mf->mf_flags & MFF_UNMOUNTING) ? "un" : "", mf->mf_flags); 193174294Sobrien in_progress++; 194174294Sobrien if (mf->mf_flags & MFF_UNMOUNTING) { 195174294Sobrien dlog("will remount later"); 196174294Sobrien new_mp->am_flags |= AMF_REMOUNT; 197174294Sobrien } 198174294Sobrien continue; 199174294Sobrien } 200174294Sobrien 201174294Sobrien /* 202174294Sobrien * Otherwise we have a hit: return the current mount point. 203174294Sobrien */ 204174294Sobrien dlog("matched %s in %s", expanded_fname, new_mp->am_path); 205174294Sobrien XFREE(expanded_fname); 206174294Sobrien return new_mp; 207174294Sobrien } 208174294Sobrien } 209174294Sobrien 210174294Sobrien if (in_progress) { 211174294Sobrien dlog("Waiting while %d mount(s) in progress", in_progress); 212174294Sobrien XFREE(expanded_fname); 213174294Sobrien ereturn(-1); 214174294Sobrien } 215174294Sobrien 216174294Sobrien /* 217174294Sobrien * If an error occurred then return it. 218174294Sobrien */ 219174294Sobrien if (error) { 220174294Sobrien dlog("Returning error: %s", strerror(error)); 221174294Sobrien XFREE(expanded_fname); 222174294Sobrien ereturn(error); 223174294Sobrien } 224174294Sobrien 225174294Sobrien /* 226174294Sobrien * If the server is going down then just return, 227174294Sobrien * don't try to mount any more file systems 228174294Sobrien */ 229174294Sobrien if ((int) amd_state >= (int) Finishing) { 230174294Sobrien dlog("not found - server going down anyway"); 231174294Sobrien ereturn(ENOENT); 232174294Sobrien } 233174294Sobrien 234174294Sobrien /* 235174294Sobrien * Allocate a new map 236174294Sobrien */ 237174294Sobrien new_mp = get_ap_child(mp, expanded_fname); 238174294Sobrien XFREE(expanded_fname); 239310490Scy if (new_mp == NULL) 240174294Sobrien ereturn(ENOSPC); 241174294Sobrien 242174294Sobrien *error_return = -1; 243174294Sobrien return new_mp; 244174294Sobrien} 245174294Sobrien 246174294Sobrien 247174294Sobrien 248310490Scystatic am_loc * 249310490Scyamfs_lookup_one_location(am_node *new_mp, mntfs *mf, char *ivec, 250310490Scy char *def_opts, char *pfname) 251174294Sobrien{ 252174294Sobrien am_ops *p; 253174294Sobrien am_opts *fs_opts; 254310490Scy am_loc *new_al; 255174294Sobrien mntfs *new_mf; 256310490Scy char *mp_dir = NULL; 257174294Sobrien#ifdef HAVE_FS_AUTOFS 258174294Sobrien int on_autofs = 1; 259174294Sobrien#endif /* HAVE_FS_AUTOFS */ 260174294Sobrien 261174294Sobrien /* match the operators */ 262310490Scy /* 263310490Scy * although we alloc the fs_opts here, the pointer is 'owned' by the am_loc and will 264310490Scy * be free'd on destruction of the am_loc. If we don't allocate a loc, then we need 265310490Scy * to free this. 266310490Scy */ 267174294Sobrien fs_opts = CALLOC(am_opts); 268174294Sobrien p = ops_match(fs_opts, ivec, def_opts, new_mp->am_path, 269174294Sobrien pfname, mf->mf_info); 270174294Sobrien#ifdef HAVE_FS_AUTOFS 271174294Sobrien /* XXX: this should be factored out into an autofs-specific function */ 272174294Sobrien if (new_mp->am_flags & AMF_AUTOFS) { 273174294Sobrien /* ignore user-provided fs if we're using autofs */ 274310490Scy if (fs_opts->opt_sublink && fs_opts->opt_sublink[0]) { 275174294Sobrien /* 276174294Sobrien * For sublinks we need to use a hack with autofs: 277174294Sobrien * mount the filesystem on the original opt_fs (which is NOT an 278174294Sobrien * autofs mountpoint) and symlink (or lofs-mount) to it from 279174294Sobrien * the autofs mountpoint. 280174294Sobrien */ 281174294Sobrien on_autofs = 0; 282174294Sobrien mp_dir = fs_opts->opt_fs; 283174294Sobrien } else { 284174294Sobrien if (p->autofs_fs_flags & FS_ON_AUTOFS) { 285174294Sobrien mp_dir = new_mp->am_path; 286174294Sobrien } else { 287174294Sobrien mp_dir = fs_opts->opt_fs; 288174294Sobrien on_autofs = 0; 289174294Sobrien } 290174294Sobrien } 291174294Sobrien } else 292174294Sobrien#endif /* HAVE_FS_AUTOFS */ 293174294Sobrien mp_dir = fs_opts->opt_fs; 294174294Sobrien 295174294Sobrien /* 296174294Sobrien * Find or allocate a filesystem for this node. 297310490Scy * we search for a matching backend share, since 298310490Scy * we will construct our own al_loc to handle 299310490Scy * any customisations for this usage. 300174294Sobrien */ 301174294Sobrien new_mf = find_mntfs(p, fs_opts, 302174294Sobrien mp_dir, 303174294Sobrien fs_opts->fs_mtab, 304174294Sobrien def_opts, 305174294Sobrien fs_opts->opt_opts, 306174294Sobrien fs_opts->opt_remopts); 307174294Sobrien 308310490Scy 309174294Sobrien /* 310174294Sobrien * See whether this is a real filesystem 311174294Sobrien */ 312174294Sobrien p = new_mf->mf_ops; 313174294Sobrien if (p == &amfs_error_ops) { 314174294Sobrien plog(XLOG_MAP, "Map entry %s for %s did not match", ivec, new_mp->am_path); 315174294Sobrien free_mntfs(new_mf); 316310490Scy free_opts(fs_opts); 317310490Scy XFREE(fs_opts); 318174294Sobrien return NULL; 319174294Sobrien } 320174294Sobrien 321174294Sobrien dlog("Got a hit with %s", p->fs_type); 322310490Scy new_al = new_loc(); 323310490Scy free_mntfs(new_al->al_mnt); 324310490Scy new_al->al_mnt = new_mf; 325310490Scy new_al->al_fo = fs_opts; /* now the loc is in charge of free'ing this mem */ 326174294Sobrien 327174294Sobrien#ifdef HAVE_FS_AUTOFS 328174294Sobrien if (new_mp->am_flags & AMF_AUTOFS && on_autofs) { 329174294Sobrien new_mf->mf_flags |= MFF_ON_AUTOFS; 330174294Sobrien new_mf->mf_fsflags = new_mf->mf_ops->autofs_fs_flags; 331174294Sobrien } 332174294Sobrien /* 333174294Sobrien * A new filesystem is an autofs filesystems if: 334174294Sobrien * 1. it claims it can be one (has the FS_AUTOFS flag) 335174294Sobrien * 2. autofs is enabled system-wide 336174294Sobrien * 3. either has an autofs parent, 337174294Sobrien * or it is explicitly requested to be autofs. 338174294Sobrien */ 339174294Sobrien if (new_mf->mf_ops->autofs_fs_flags & FS_AUTOFS && 340174294Sobrien amd_use_autofs && 341174294Sobrien ((mf->mf_flags & MFF_IS_AUTOFS) || 342174294Sobrien (new_mf->mf_fo && new_mf->mf_fo->opt_mount_type && 343174294Sobrien STREQ(new_mf->mf_fo->opt_mount_type, "autofs")))) 344174294Sobrien new_mf->mf_flags |= MFF_IS_AUTOFS; 345174294Sobrien#endif /* HAVE_FS_AUTOFS */ 346174294Sobrien 347310490Scy return new_al; 348174294Sobrien} 349174294Sobrien 350174294Sobrien 351310490Scystatic am_loc ** 352310490Scyamfs_lookup_loc(am_node *new_mp, int *error_return) 353174294Sobrien{ 354174294Sobrien am_node *mp; 355174294Sobrien char *info; /* Mount info - where to get the file system */ 356174294Sobrien char **ivecs, **cur_ivec; /* Split version of info */ 357174294Sobrien int num_ivecs; 358174294Sobrien char *orig_def_opts; /* Original Automount options */ 359174294Sobrien char *def_opts; /* Automount options */ 360174294Sobrien int error = 0; /* Error so far */ 361174294Sobrien char path_name[MAXPATHLEN]; /* General path name buffer */ 362174294Sobrien char *pfname; /* Path for database lookup */ 363310490Scy mntfs* mf; /* The mntfs for the map of our parent */ 364310490Scy am_loc **al_array; /* the generated list of locations */ 365174294Sobrien int count; 366174294Sobrien 367310490Scy dlog("in amfs_lookup_loc"); 368174294Sobrien 369174294Sobrien mp = new_mp->am_parent; 370174294Sobrien 371174294Sobrien /* 372174294Sobrien * If we get here then this is a reference to an, 373174294Sobrien * as yet, unknown name so we need to search the mount 374174294Sobrien * map for it. 375174294Sobrien */ 376174294Sobrien if (mp->am_pref) { 377174294Sobrien if (strlen(mp->am_pref) + strlen(new_mp->am_name) >= sizeof(path_name)) 378174294Sobrien ereturn(ENAMETOOLONG); 379174294Sobrien xsnprintf(path_name, sizeof(path_name), "%s%s", mp->am_pref, new_mp->am_name); 380174294Sobrien pfname = path_name; 381174294Sobrien } else { 382174294Sobrien pfname = new_mp->am_name; 383174294Sobrien } 384174294Sobrien 385310490Scy mf = mp->am_al->al_mnt; 386174294Sobrien 387174294Sobrien dlog("will search map info in %s to find %s", mf->mf_info, pfname); 388174294Sobrien /* 389174294Sobrien * Consult the oracle for some mount information. 390174294Sobrien * info is malloc'ed and belongs to this routine. 391174294Sobrien * It ends up being free'd in free_continuation(). 392174294Sobrien * 393174294Sobrien * Note that this may return -1 indicating that information 394174294Sobrien * is not yet available. 395174294Sobrien */ 396174294Sobrien error = mapc_search((mnt_map *) mf->mf_private, pfname, &info); 397174294Sobrien if (error) { 398174294Sobrien if (error > 0) 399174294Sobrien plog(XLOG_MAP, "No map entry for %s", pfname); 400174294Sobrien else 401174294Sobrien plog(XLOG_MAP, "Waiting on map entry for %s", pfname); 402174294Sobrien ereturn(error); 403174294Sobrien } 404174294Sobrien dlog("mount info is %s", info); 405174294Sobrien 406174294Sobrien /* 407174294Sobrien * Split info into an argument vector. 408174294Sobrien * The vector is malloc'ed and belongs to 409174294Sobrien * this routine. It is free'd further down. 410174294Sobrien * 411174294Sobrien * Note: the vector pointers point into info, so don't free it! 412174294Sobrien */ 413174294Sobrien ivecs = strsplit(info, ' ', '\"'); 414174294Sobrien 415174294Sobrien if (mf->mf_auto) 416174294Sobrien def_opts = mf->mf_auto; 417174294Sobrien else 418174294Sobrien def_opts = ""; 419174294Sobrien 420310490Scy orig_def_opts = amfs_parse_defaults(mp, mf, xstrdup(def_opts)); 421310490Scy def_opts = xstrdup(orig_def_opts); 422174294Sobrien 423174294Sobrien /* first build our defaults */ 424174294Sobrien num_ivecs = 0; 425174294Sobrien for (cur_ivec = ivecs; *cur_ivec; cur_ivec++) { 426174294Sobrien if (**cur_ivec == '-') { 427174294Sobrien /* 428174294Sobrien * Pick up new defaults 429174294Sobrien */ 430174294Sobrien char *new_def_opts = str3cat(NULL, def_opts, ";", *cur_ivec + 1); 431174294Sobrien XFREE(def_opts); 432174294Sobrien def_opts = new_def_opts; 433174294Sobrien dlog("Setting def_opts to \"%s\"", def_opts); 434174294Sobrien continue; 435174294Sobrien } else 436174294Sobrien num_ivecs++; 437174294Sobrien } 438174294Sobrien 439310490Scy al_array = calloc(num_ivecs + 1, sizeof(am_loc *)); 440174294Sobrien 441310490Scy /* construct the array of struct locations for this key */ 442174294Sobrien for (count = 0, cur_ivec = ivecs; *cur_ivec; cur_ivec++) { 443310490Scy am_loc *new_al; 444174294Sobrien 445174294Sobrien if (**cur_ivec == '-') { 446174294Sobrien XFREE(def_opts); 447174294Sobrien if ((*cur_ivec)[1] == '\0') { 448174294Sobrien /* 449174294Sobrien * If we have a single dash '-' than we need to reset the 450174294Sobrien * default options. 451174294Sobrien */ 452310490Scy def_opts = xstrdup(orig_def_opts); 453174294Sobrien dlog("Resetting the default options, a single dash '-' was found."); 454174294Sobrien } else { 455174294Sobrien /* append options to /default options */ 456310490Scy def_opts = str3cat((char *) NULL, orig_def_opts, ";", *cur_ivec + 1); 457174294Sobrien dlog("Resetting def_opts to \"%s\"", def_opts); 458174294Sobrien } 459174294Sobrien continue; 460174294Sobrien } 461174294Sobrien 462174294Sobrien /* 463310490Scy * If a loc has already been found, and we find 464174294Sobrien * a cut then don't try any more locations. 465174294Sobrien * 466174294Sobrien * XXX: we do not know when the "/" was added as an equivalent for "||". 467174294Sobrien * It's undocumented, it might go away at any time. Caveat emptor. 468174294Sobrien */ 469174294Sobrien if (STREQ(*cur_ivec, "/") || STREQ(*cur_ivec, "||")) { 470174294Sobrien if (count > 0) { 471310490Scy dlog("Cut: not trying any more locations for %s", pfname); 472174294Sobrien break; 473174294Sobrien } 474174294Sobrien continue; 475174294Sobrien } 476174294Sobrien 477310490Scy new_al = amfs_lookup_one_location(new_mp, mf, *cur_ivec, def_opts, pfname); 478310490Scy if (new_al == NULL) 479174294Sobrien continue; 480310490Scy al_array[count++] = new_al; 481174294Sobrien } 482174294Sobrien 483174294Sobrien /* We're done with ivecs */ 484174294Sobrien XFREE(ivecs); 485174294Sobrien XFREE(info); 486174294Sobrien XFREE(orig_def_opts); 487174294Sobrien XFREE(def_opts); 488174294Sobrien if (count == 0) { /* no match */ 489310490Scy XFREE(al_array); 490174294Sobrien ereturn(ENOENT); 491174294Sobrien } 492174294Sobrien 493310490Scy return al_array; 494174294Sobrien} 495174294Sobrien 496174294Sobrien 497174294Sobrien/* 498174294Sobrien * The continuation function. This is called by 499174294Sobrien * the task notifier when a background mount attempt 500174294Sobrien * completes. 501174294Sobrien */ 502174294Sobrienstatic void 503174294Sobrienamfs_cont(int rc, int term, opaque_t arg) 504174294Sobrien{ 505174294Sobrien struct continuation *cp = (struct continuation *) arg; 506174294Sobrien am_node *mp = cp->mp; 507310490Scy mntfs *mf = mp->am_al->al_mnt; 508174294Sobrien 509174294Sobrien dlog("amfs_cont: '%s'", mp->am_path); 510174294Sobrien 511174294Sobrien /* 512174294Sobrien * Definitely not trying to mount at the moment 513174294Sobrien */ 514174294Sobrien mf->mf_flags &= ~MFF_MOUNTING; 515174294Sobrien 516174294Sobrien /* 517174294Sobrien * While we are mounting - try to avoid race conditions 518174294Sobrien */ 519174294Sobrien new_ttl(mp); 520174294Sobrien 521174294Sobrien /* 522174294Sobrien * Wakeup anything waiting for this mount 523174294Sobrien */ 524174294Sobrien wakeup(get_mntfs_wchan(mf)); 525174294Sobrien 526174294Sobrien /* 527174294Sobrien * Check for termination signal or exit status... 528174294Sobrien */ 529174294Sobrien if (rc || term) { 530174294Sobrien#ifdef HAVE_FS_AUTOFS 531174294Sobrien if (mf->mf_flags & MFF_IS_AUTOFS && 532174294Sobrien !(mf->mf_flags & MFF_MOUNTED)) 533174294Sobrien autofs_release_fh(mp); 534174294Sobrien#endif /* HAVE_FS_AUTOFS */ 535174294Sobrien 536174294Sobrien if (term) { 537174294Sobrien /* 538174294Sobrien * Not sure what to do for an error code. 539174294Sobrien */ 540174294Sobrien mf->mf_error = EIO; /* XXX ? */ 541174294Sobrien mf->mf_flags |= MFF_ERROR; 542174294Sobrien plog(XLOG_ERROR, "mount for %s got signal %d", mp->am_path, term); 543174294Sobrien } else { 544174294Sobrien /* 545174294Sobrien * Check for exit status... 546174294Sobrien */ 547174294Sobrien#ifdef __linux__ 548174294Sobrien /* 549174294Sobrien * HACK ALERT! 550174294Sobrien * 551174294Sobrien * On Linux (and maybe not only) it's possible to run 552174294Sobrien * an amd which "knows" how to mount certain combinations 553174294Sobrien * of nfs_proto/nfs_version which the kernel doesn't grok. 554174294Sobrien * So if we got an EINVAL and we have a server that's not 555174294Sobrien * using NFSv2/UDP, try again with NFSv2/UDP. 556174294Sobrien * 557174294Sobrien * Too bad that there is no way to dynamically determine 558174294Sobrien * what combinations the _client_ supports, as opposed to 559174294Sobrien * what the _server_ supports... 560174294Sobrien */ 561174294Sobrien if (rc == EINVAL && 562174294Sobrien mf->mf_server && 563174294Sobrien (mf->mf_server->fs_version != 2 || 564174294Sobrien !STREQ(mf->mf_server->fs_proto, "udp"))) 565174294Sobrien mf->mf_flags |= MFF_NFS_SCALEDOWN; 566174294Sobrien else 567174294Sobrien#endif /* __linux__ */ 568174294Sobrien { 569174294Sobrien mf->mf_error = rc; 570174294Sobrien mf->mf_flags |= MFF_ERROR; 571174294Sobrien errno = rc; /* XXX */ 572310490Scy if (!STREQ(mp->am_al->al_mnt->mf_ops->fs_type, "linkx")) 573174294Sobrien plog(XLOG_ERROR, "%s: mount (amfs_cont): %m", mp->am_path); 574174294Sobrien } 575174294Sobrien } 576174294Sobrien 577174294Sobrien if (!(mf->mf_flags & MFF_NFS_SCALEDOWN)) { 578174294Sobrien /* 579174294Sobrien * If we get here then that attempt didn't work, so 580174294Sobrien * move the info vector pointer along by one and 581174294Sobrien * call the background mount routine again 582174294Sobrien */ 583174294Sobrien amd_stats.d_merr++; 584310490Scy cp->al++; 585174294Sobrien } 586174294Sobrien amfs_bgmount(cp); 587174294Sobrien if (mp->am_error > 0) 588174294Sobrien assign_error_mntfs(mp); 589174294Sobrien } else { 590174294Sobrien /* 591174294Sobrien * The mount worked. 592174294Sobrien */ 593174294Sobrien dlog("Mounting %s returned success", cp->mp->am_path); 594174294Sobrien am_mounted(cp->mp); 595174294Sobrien free_continuation(cp); 596174294Sobrien } 597174294Sobrien 598174294Sobrien reschedule_timeout_mp(); 599174294Sobrien} 600174294Sobrien 601174294Sobrien 602174294Sobrien/* 603174294Sobrien * Retry a mount 604174294Sobrien */ 605174294Sobrienstatic void 606174294Sobrienamfs_retry(int rc, int term, opaque_t arg) 607174294Sobrien{ 608174294Sobrien struct continuation *cp = (struct continuation *) arg; 609174294Sobrien am_node *mp = cp->mp; 610174294Sobrien int error = 0; 611174294Sobrien 612174294Sobrien dlog("Commencing retry for mount of %s", mp->am_path); 613174294Sobrien 614174294Sobrien new_ttl(mp); 615174294Sobrien 616174294Sobrien if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime(NULL)) { 617174294Sobrien /* 618174294Sobrien * The entire mount has timed out. Set the error code and skip past all 619174294Sobrien * the mntfs's so that amfs_bgmount will not have any more 620174294Sobrien * ways to try the mount, thus causing an error. 621174294Sobrien */ 622174294Sobrien plog(XLOG_INFO, "mount of \"%s\" has timed out", mp->am_path); 623174294Sobrien error = ETIMEDOUT; 624310490Scy while (*cp->al) 625310490Scy cp->al++; 626174294Sobrien /* explicitly forbid further retries after timeout */ 627174294Sobrien cp->retry = FALSE; 628174294Sobrien } 629174294Sobrien if (error || !IN_PROGRESS(cp)) 630174294Sobrien error = amfs_bgmount(cp); 631310490Scy else 632310490Scy /* Normally it's amfs_bgmount() which frees the continuation. However, if 633310490Scy * the mount is already in progress and we're in amfs_retry() for another 634310490Scy * node we don't try mounting the filesystem once again. Still, we have 635310490Scy * to free the continuation as we won't get called again and thus would 636310490Scy * leak the continuation structure and our am_loc references. 637310490Scy */ 638310490Scy free_continuation(cp); 639174294Sobrien 640174294Sobrien reschedule_timeout_mp(); 641174294Sobrien} 642174294Sobrien 643174294Sobrien 644174294Sobrien/* 645174294Sobrien * Discard an old continuation 646174294Sobrien */ 647174294Sobrienstatic void 648174294Sobrienfree_continuation(struct continuation *cp) 649174294Sobrien{ 650310490Scy am_loc **alp; 651174294Sobrien 652174294Sobrien dlog("free_continuation"); 653174294Sobrien if (cp->callout) 654174294Sobrien untimeout(cp->callout); 655174294Sobrien /* 656174294Sobrien * we must free the mntfs's in the list. 657174294Sobrien * so free all of them if there was an error, 658174294Sobrien */ 659310490Scy for (alp = cp->mp->am_alarray; *alp; alp++) { 660310490Scy free_loc(*alp); 661174294Sobrien } 662310490Scy XFREE(cp->mp->am_alarray); 663310490Scy cp->mp->am_alarray = 0; 664174294Sobrien XFREE(cp); 665174294Sobrien} 666174294Sobrien 667174294Sobrien 668174294Sobrien/* 669174294Sobrien * Pick a file system to try mounting and 670174294Sobrien * do that in the background if necessary 671174294Sobrien * 672174294SobrienFor each location: 673174294Sobrien discard previous mount location if required 674174294Sobrien fetch next mount location 675174294Sobrien if the filesystem failed to be mounted then 676174294Sobrien this_error = error from filesystem 677174294Sobrien goto failed 678174294Sobrien if the filesystem is mounting or unmounting then 679174294Sobrien goto retry; 680174294Sobrien if the fileserver is down then 681174294Sobrien this_error = EIO 682174294Sobrien continue; 683174294Sobrien if the filesystem is already mounted 684174294Sobrien break 685174294Sobrien fi 686174294Sobrien 687174294Sobrien this_error = initialize mount point 688174294Sobrien 689174294Sobrien if no error on this mount and mount is delayed then 690174294Sobrien this_error = -1 691174294Sobrien fi 692174294Sobrien if this_error < 0 then 693174294Sobrien retry = true 694174294Sobrien fi 695174294Sobrien if no error on this mount then 696174294Sobrien if mount in background then 697174294Sobrien run mount in background 698174294Sobrien return -1 699174294Sobrien else 700174294Sobrien this_error = mount in foreground 701174294Sobrien fi 702174294Sobrien fi 703174294Sobrien if an error occurred on this mount then 704174294Sobrien update stats 705174294Sobrien save error in mount point 706174294Sobrien fi 707174294Sobrienendfor 708174294Sobrien */ 709174294Sobrienstatic int 710174294Sobrienamfs_bgmount(struct continuation *cp) 711174294Sobrien{ 712174294Sobrien am_node *mp = cp->mp; 713310490Scy am_loc *loc; 714310490Scy mntfs *mf; 715174294Sobrien int this_error = -1; /* Per-mount error */ 716174294Sobrien int hard_error = -1; /* Cumulative per-node error */ 717174294Sobrien 718310490Scy if (mp->am_al) 719310490Scy free_loc(mp->am_al); 720174294Sobrien 721174294Sobrien /* 722174294Sobrien * Try to mount each location. 723174294Sobrien * At the end: 724174294Sobrien * hard_error == 0 indicates something was mounted. 725174294Sobrien * hard_error > 0 indicates everything failed with a hard error 726174294Sobrien * hard_error < 0 indicates nothing could be mounted now 727174294Sobrien */ 728310490Scy for (mp->am_al = *cp->al; *cp->al; cp->al++, mp->am_al = *cp->al) { 729174294Sobrien am_ops *p; 730174294Sobrien 731310490Scy loc = dup_loc(mp->am_al); 732310490Scy mf = loc->al_mnt; 733174294Sobrien p = mf->mf_ops; 734174294Sobrien 735174294Sobrien if (hard_error < 0) 736174294Sobrien hard_error = this_error; 737174294Sobrien this_error = 0; 738174294Sobrien 739174294Sobrien if (mf->mf_error > 0) { 740174294Sobrien this_error = mf->mf_error; 741174294Sobrien goto failed; 742174294Sobrien } 743174294Sobrien 744174294Sobrien if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) { 745174294Sobrien /* 746174294Sobrien * Still mounting - retry later 747174294Sobrien */ 748174294Sobrien dlog("mount of \"%s\" already pending", mf->mf_info); 749174294Sobrien goto retry; 750174294Sobrien } 751174294Sobrien 752174294Sobrien if (FSRV_ISDOWN(mf->mf_server)) { 753174294Sobrien /* 754174294Sobrien * Would just mount from the same place 755174294Sobrien * as a hung mount - so give up 756174294Sobrien */ 757174294Sobrien dlog("%s is already hung - giving up", mf->mf_server->fs_host); 758174294Sobrien this_error = EIO; 759174294Sobrien goto failed; 760174294Sobrien } 761174294Sobrien 762310490Scy XFREE(mp->am_link); 763310490Scy mp->am_link = NULL; 764174294Sobrien 765310490Scy if (loc->al_fo && loc->al_fo->opt_sublink && loc->al_fo->opt_sublink[0]) 766310490Scy mp->am_link = xstrdup(loc->al_fo->opt_sublink); 767310490Scy 768174294Sobrien /* 769174294Sobrien * Will usually need to play around with the mount nodes 770174294Sobrien * file attribute structure. This must be done here. 771174294Sobrien * Try and get things initialized, even if the fileserver 772174294Sobrien * is not known to be up. In the common case this will 773174294Sobrien * progress things faster. 774174294Sobrien */ 775174294Sobrien 776174294Sobrien /* 777174294Sobrien * Fill in attribute fields. 778174294Sobrien */ 779174294Sobrien if (mf->mf_fsflags & FS_DIRECTORY) 780174294Sobrien mk_fattr(&mp->am_fattr, NFDIR); 781174294Sobrien else 782174294Sobrien mk_fattr(&mp->am_fattr, NFLNK); 783174294Sobrien 784174294Sobrien if (mf->mf_flags & MFF_MOUNTED) { 785174294Sobrien dlog("duplicate mount of \"%s\" ...", mf->mf_info); 786174294Sobrien /* 787174294Sobrien * Skip initial processing of the mountpoint if already mounted. 788174294Sobrien * This could happen if we have multiple sublinks into the same f/s, 789174294Sobrien * or if we are restarting an already-mounted filesystem. 790174294Sobrien */ 791174294Sobrien goto already_mounted; 792174294Sobrien } 793174294Sobrien 794174294Sobrien if (mf->mf_fo && mf->mf_fo->fs_mtab) { 795174294Sobrien plog(XLOG_MAP, "Trying mount of %s on %s fstype %s mount_type %s", 796174294Sobrien mf->mf_fo->fs_mtab, mf->mf_mount, p->fs_type, 797174294Sobrien mp->am_flags & AMF_AUTOFS ? "autofs" : "non-autofs"); 798174294Sobrien } 799174294Sobrien 800174294Sobrien if (p->fs_init && !(mf->mf_flags & MFF_RESTART)) 801174294Sobrien this_error = p->fs_init(mf); 802174294Sobrien 803174294Sobrien if (this_error > 0) 804174294Sobrien goto failed; 805174294Sobrien if (this_error < 0) 806174294Sobrien goto retry; 807174294Sobrien 808310490Scy if (loc->al_fo && loc->al_fo->opt_delay) { 809174294Sobrien /* 810310490Scy * If there is a delay timer on the location 811174294Sobrien * then don't try to mount if the timer 812174294Sobrien * has not expired. 813174294Sobrien */ 814310490Scy int i = atoi(loc->al_fo->opt_delay); 815174294Sobrien time_t now = clocktime(NULL); 816174294Sobrien if (i > 0 && now < (cp->start + i)) { 817174294Sobrien dlog("Mount of %s delayed by %lds", mf->mf_mount, (long) (i - now + cp->start)); 818174294Sobrien goto retry; 819174294Sobrien } 820174294Sobrien } 821174294Sobrien 822174294Sobrien /* 823174294Sobrien * If the directory is not yet made and it needs to be made, then make it! 824174294Sobrien */ 825174294Sobrien if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_fsflags & FS_MKMNT) { 826174294Sobrien plog(XLOG_INFO, "creating mountpoint directory '%s'", mf->mf_mount); 827174294Sobrien this_error = mkdirs(mf->mf_mount, 0555); 828174294Sobrien if (this_error) { 829174294Sobrien plog(XLOG_ERROR, "mkdirs failed: %s", strerror(this_error)); 830174294Sobrien goto failed; 831174294Sobrien } 832174294Sobrien mf->mf_flags |= MFF_MKMNT; 833174294Sobrien } 834174294Sobrien 835174294Sobrien#ifdef HAVE_FS_AUTOFS 836174294Sobrien if (mf->mf_flags & MFF_IS_AUTOFS) 837174294Sobrien if ((this_error = autofs_get_fh(mp))) 838174294Sobrien goto failed; 839174294Sobrien#endif /* HAVE_FS_AUTOFS */ 840174294Sobrien 841174294Sobrien already_mounted: 842174294Sobrien mf->mf_flags |= MFF_MOUNTING; 843174294Sobrien if (mf->mf_fsflags & FS_MBACKGROUND) { 844174294Sobrien dlog("backgrounding mount of \"%s\"", mf->mf_mount); 845174294Sobrien if (cp->callout) { 846174294Sobrien untimeout(cp->callout); 847174294Sobrien cp->callout = 0; 848174294Sobrien } 849174294Sobrien 850174294Sobrien /* actually run the task, backgrounding as necessary */ 851174294Sobrien run_task(mount_node, (opaque_t) mp, amfs_cont, (opaque_t) cp); 852174294Sobrien return -1; 853174294Sobrien } else { 854174294Sobrien dlog("foreground mount of \"%s\" ...", mf->mf_mount); 855174294Sobrien this_error = mount_node((opaque_t) mp); 856174294Sobrien } 857174294Sobrien 858174294Sobrien mf->mf_flags &= ~MFF_MOUNTING; 859174294Sobrien if (this_error > 0) 860174294Sobrien goto failed; 861174294Sobrien if (this_error == 0) { 862174294Sobrien am_mounted(mp); 863174294Sobrien break; /* Success */ 864174294Sobrien } 865174294Sobrien 866174294Sobrien retry: 867174294Sobrien if (!cp->retry) 868174294Sobrien continue; 869174294Sobrien dlog("will retry ...\n"); 870174294Sobrien 871174294Sobrien /* 872174294Sobrien * Arrange that amfs_bgmount is called 873174294Sobrien * after anything else happens. 874174294Sobrien */ 875174294Sobrien dlog("Arranging to retry mount of %s", mp->am_path); 876174294Sobrien sched_task(amfs_retry, (opaque_t) cp, get_mntfs_wchan(mf)); 877174294Sobrien if (cp->callout) 878174294Sobrien untimeout(cp->callout); 879174294Sobrien cp->callout = timeout(RETRY_INTERVAL, wakeup, 880174294Sobrien (opaque_t) get_mntfs_wchan(mf)); 881174294Sobrien 882174294Sobrien mp->am_ttl = clocktime(NULL) + RETRY_INTERVAL; 883174294Sobrien 884174294Sobrien /* 885174294Sobrien * Not done yet - so don't return anything 886174294Sobrien */ 887174294Sobrien return -1; 888174294Sobrien 889174294Sobrien failed: 890310490Scy if (!FSRV_ISDOWN(mf->mf_server)) { 891310490Scy /* mark the mount as failed unless the server is down */ 892310490Scy amd_stats.d_merr++; 893310490Scy mf->mf_error = this_error; 894310490Scy mf->mf_flags |= MFF_ERROR; 895174294Sobrien#ifdef HAVE_FS_AUTOFS 896310490Scy if (mp->am_autofs_fh) 897310490Scy autofs_release_fh(mp); 898174294Sobrien#endif /* HAVE_FS_AUTOFS */ 899310490Scy if (mf->mf_flags & MFF_MKMNT) { 900310490Scy rmdirs(mf->mf_mount); 901310490Scy mf->mf_flags &= ~MFF_MKMNT; 902310490Scy } 903174294Sobrien } 904174294Sobrien /* 905174294Sobrien * Wakeup anything waiting for this mount 906174294Sobrien */ 907174294Sobrien wakeup(get_mntfs_wchan(mf)); 908310490Scy free_loc(loc); 909174294Sobrien /* continue */ 910174294Sobrien } 911174294Sobrien 912174294Sobrien /* 913174294Sobrien * If we get here, then either the mount succeeded or 914174294Sobrien * there is no more mount information available. 915174294Sobrien */ 916174294Sobrien if (this_error) { 917310490Scy if (mp->am_al) 918310490Scy free_loc(mp->am_al); 919310490Scy mp->am_al = loc = new_loc(); 920310490Scy mf = loc->al_mnt; 921174294Sobrien 922174294Sobrien#ifdef HAVE_FS_AUTOFS 923174294Sobrien if (mp->am_flags & AMF_AUTOFS) 924174294Sobrien autofs_mount_failed(mp); 925174294Sobrien else 926174294Sobrien#endif /* HAVE_FS_AUTOFS */ 927174294Sobrien nfs_quick_reply(mp, this_error); 928174294Sobrien 929174294Sobrien if (hard_error <= 0) 930174294Sobrien hard_error = this_error; 931174294Sobrien if (hard_error < 0) 932174294Sobrien hard_error = ETIMEDOUT; 933174294Sobrien 934174294Sobrien /* 935174294Sobrien * Set a small(ish) timeout on an error node if 936174294Sobrien * the error was not a time out. 937174294Sobrien */ 938174294Sobrien switch (hard_error) { 939174294Sobrien case ETIMEDOUT: 940174294Sobrien case EWOULDBLOCK: 941174294Sobrien case EIO: 942174294Sobrien mp->am_timeo = 17; 943174294Sobrien break; 944174294Sobrien default: 945174294Sobrien mp->am_timeo = 5; 946174294Sobrien break; 947174294Sobrien } 948174294Sobrien new_ttl(mp); 949174294Sobrien } else { 950310490Scy mf = loc->al_mnt; 951174294Sobrien /* 952174294Sobrien * Wakeup anything waiting for this mount 953174294Sobrien */ 954174294Sobrien wakeup(get_mntfs_wchan(mf)); 955174294Sobrien hard_error = 0; 956174294Sobrien } 957174294Sobrien 958174294Sobrien /* 959174294Sobrien * Make sure that the error value in the mntfs has a 960174294Sobrien * reasonable value. 961174294Sobrien */ 962174294Sobrien if (mf->mf_error < 0) { 963174294Sobrien mf->mf_error = hard_error; 964174294Sobrien if (hard_error) 965174294Sobrien mf->mf_flags |= MFF_ERROR; 966174294Sobrien } 967174294Sobrien 968174294Sobrien /* 969174294Sobrien * In any case we don't need the continuation any more 970174294Sobrien */ 971174294Sobrien free_continuation(cp); 972174294Sobrien 973174294Sobrien return hard_error; 974174294Sobrien} 975174294Sobrien 976174294Sobrien 977174294Sobrienstatic char * 978174294Sobrienamfs_parse_defaults(am_node *mp, mntfs *mf, char *def_opts) 979174294Sobrien{ 980174294Sobrien char *dflts; 981174294Sobrien char *dfl; 982174294Sobrien char **rvec = NULL; 983174294Sobrien struct mnt_map *mm = (mnt_map *) mf->mf_private; 984174294Sobrien 985174294Sobrien dlog("determining /defaults entry value"); 986174294Sobrien 987174294Sobrien /* 988174294Sobrien * Find out if amd.conf overrode any map-specific /defaults. 989174294Sobrien */ 990174294Sobrien if (mm->cfm && mm->cfm->cfm_defaults) { 991174294Sobrien dlog("map %s map_defaults override: %s", mf->mf_mount, mm->cfm->cfm_defaults); 992310490Scy dflts = xstrdup(mm->cfm->cfm_defaults); 993174294Sobrien } else if (mapc_search(mm, "/defaults", &dflts) == 0) { 994174294Sobrien dlog("/defaults gave %s", dflts); 995174294Sobrien } else { 996174294Sobrien return def_opts; /* if nothing found */ 997174294Sobrien } 998174294Sobrien 999174294Sobrien /* trim leading '-' in case thee's one */ 1000174294Sobrien if (*dflts == '-') 1001174294Sobrien dfl = dflts + 1; 1002174294Sobrien else 1003174294Sobrien dfl = dflts; 1004174294Sobrien 1005174294Sobrien /* 1006174294Sobrien * Chop the defaults up 1007174294Sobrien */ 1008174294Sobrien rvec = strsplit(dfl, ' ', '\"'); 1009174294Sobrien 1010174294Sobrien if (gopt.flags & CFM_SELECTORS_IN_DEFAULTS) { 1011174294Sobrien /* 1012174294Sobrien * Pick whichever first entry matched the list of selectors. 1013174294Sobrien * Strip the selectors from the string, and assign to dfl the 1014174294Sobrien * rest of the string. 1015174294Sobrien */ 1016174294Sobrien if (rvec) { 1017174294Sobrien am_opts ap; 1018174294Sobrien am_ops *pt; 1019174294Sobrien char **sp = rvec; 1020174294Sobrien while (*sp) { /* loop until you find something, if any */ 1021174294Sobrien memset((char *) &ap, 0, sizeof(am_opts)); 1022174294Sobrien /* 1023174294Sobrien * This next routine cause many spurious "expansion of ... is" 1024174294Sobrien * messages, which are ignored, b/c all we need out of this 1025174294Sobrien * routine is to match selectors. These spurious messages may 1026174294Sobrien * be wrong, esp. if they try to expand ${key} b/c it will 1027174294Sobrien * get expanded to "/defaults" 1028174294Sobrien */ 1029174294Sobrien pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults", 1030310490Scy mp->am_parent->am_al->al_mnt->mf_info); 1031174294Sobrien free_opts(&ap); /* don't leak */ 1032174294Sobrien if (pt == &amfs_error_ops) { 1033174294Sobrien plog(XLOG_MAP, "did not match defaults for \"%s\"", *sp); 1034174294Sobrien } else { 1035174294Sobrien dfl = strip_selectors(*sp, "/defaults"); 1036174294Sobrien plog(XLOG_MAP, "matched default selectors \"%s\"", dfl); 1037174294Sobrien break; 1038174294Sobrien } 1039174294Sobrien ++sp; 1040174294Sobrien } 1041174294Sobrien } 1042174294Sobrien } else { /* not selectors_in_defaults */ 1043174294Sobrien /* 1044174294Sobrien * Extract first value 1045174294Sobrien */ 1046174294Sobrien dfl = rvec[0]; 1047174294Sobrien } 1048174294Sobrien 1049174294Sobrien /* 1050174294Sobrien * If there were any values at all... 1051174294Sobrien */ 1052174294Sobrien if (dfl) { 1053174294Sobrien /* 1054174294Sobrien * Log error if there were other values 1055174294Sobrien */ 1056174294Sobrien if (!(gopt.flags & CFM_SELECTORS_IN_DEFAULTS) && rvec[1]) { 1057174294Sobrien dlog("/defaults chopped into %s", dfl); 1058174294Sobrien plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info); 1059174294Sobrien } 1060174294Sobrien 1061174294Sobrien /* 1062174294Sobrien * Prepend to existing defaults if they exist, 1063174294Sobrien * otherwise just use these defaults. 1064174294Sobrien */ 1065174294Sobrien if (*def_opts && *dfl) { 1066174294Sobrien size_t l = strlen(def_opts) + strlen(dfl) + 2; 1067174294Sobrien char *nopts = (char *) xmalloc(l); 1068174294Sobrien xsnprintf(nopts, l, "%s;%s", dfl, def_opts); 1069174294Sobrien XFREE(def_opts); 1070174294Sobrien def_opts = nopts; 1071174294Sobrien } else if (*dfl) { 1072174294Sobrien def_opts = strealloc(def_opts, dfl); 1073174294Sobrien } 1074174294Sobrien } 1075174294Sobrien 1076174294Sobrien XFREE(dflts); 1077174294Sobrien 1078174294Sobrien /* don't need info vector any more */ 1079174294Sobrien if (rvec) 1080174294Sobrien XFREE(rvec); 1081174294Sobrien 1082174294Sobrien return def_opts; 1083174294Sobrien} 1084174294Sobrien 1085174294Sobrien 1086174294Sobrienam_node * 1087174294Sobrienamfs_generic_mount_child(am_node *new_mp, int *error_return) 1088174294Sobrien{ 1089174294Sobrien int error; 1090174294Sobrien struct continuation *cp; /* Continuation structure if need to mount */ 1091174294Sobrien 1092174294Sobrien dlog("in amfs_generic_mount_child"); 1093174294Sobrien 1094174294Sobrien *error_return = error = 0; /* Error so far */ 1095174294Sobrien 1096174294Sobrien /* we have an errorfs attached to the am_node, free it */ 1097310490Scy if (new_mp->am_al) 1098310490Scy free_loc(new_mp->am_al); 1099310490Scy new_mp->am_al = NULL; 1100174294Sobrien 1101174294Sobrien /* 1102174294Sobrien * Construct a continuation 1103174294Sobrien */ 1104174294Sobrien cp = ALLOC(struct continuation); 1105174294Sobrien cp->callout = 0; 1106174294Sobrien cp->mp = new_mp; 1107174294Sobrien cp->retry = TRUE; 1108174294Sobrien cp->start = clocktime(NULL); 1109310490Scy cp->al = new_mp->am_alarray; 1110174294Sobrien 1111174294Sobrien /* 1112174294Sobrien * Try and mount the file system. If this succeeds immediately (possible 1113174294Sobrien * for a ufs file system) then return the attributes, otherwise just 1114174294Sobrien * return an error. 1115174294Sobrien */ 1116174294Sobrien error = amfs_bgmount(cp); 1117174294Sobrien reschedule_timeout_mp(); 1118174294Sobrien if (!error) 1119174294Sobrien return new_mp; 1120174294Sobrien 1121174294Sobrien /* 1122174294Sobrien * Code for quick reply. If current_transp is set, then it's the 1123310490Scy * transp that's been passed down from nfs_dispatcher() or from 1124174294Sobrien * autofs_program_[123](). 1125174294Sobrien * If new_mp->am_transp is not already set, set it by copying in 1126174294Sobrien * current_transp. Once am_transp is set, nfs_quick_reply() and 1127174294Sobrien * autofs_mount_succeeded() can use it to send a reply to the 1128174294Sobrien * client that requested this mount. 1129174294Sobrien */ 1130174294Sobrien if (current_transp && !new_mp->am_transp) { 1131174294Sobrien dlog("Saving RPC transport for %s", new_mp->am_path); 1132174294Sobrien new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); 1133174294Sobrien *(new_mp->am_transp) = *current_transp; 1134174294Sobrien } 1135310490Scy if (error && new_mp->am_al && new_mp->am_al->al_mnt && 1136310490Scy (new_mp->am_al->al_mnt->mf_ops == &amfs_error_ops)) 1137174294Sobrien new_mp->am_error = error; 1138174294Sobrien 1139174294Sobrien if (new_mp->am_error > 0) 1140174294Sobrien assign_error_mntfs(new_mp); 1141174294Sobrien 1142174294Sobrien ereturn(error); 1143174294Sobrien} 1144174294Sobrien 1145174294Sobrien 1146174294Sobrien/* 1147174294Sobrien * Automount interface to RPC lookup routine 1148174294Sobrien * Find the corresponding entry and return 1149174294Sobrien * the file handle for it. 1150174294Sobrien */ 1151174294Sobrienam_node * 1152174294Sobrienamfs_generic_lookup_child(am_node *mp, char *fname, int *error_return, int op) 1153174294Sobrien{ 1154174294Sobrien am_node *new_mp; 1155310490Scy am_loc **al_array; 1156174294Sobrien int mp_error; 1157174294Sobrien 1158174294Sobrien dlog("in amfs_generic_lookup_child"); 1159174294Sobrien 1160174294Sobrien *error_return = 0; 1161174294Sobrien new_mp = amfs_lookup_node(mp, fname, error_return); 1162174294Sobrien 1163174294Sobrien /* return if we got an error */ 1164174294Sobrien if (!new_mp || *error_return > 0) 1165174294Sobrien return new_mp; 1166174294Sobrien 1167174294Sobrien /* also return if it's already mounted and known to be up */ 1168310490Scy if (*error_return == 0 && FSRV_ISUP(new_mp->am_al->al_mnt->mf_server)) 1169174294Sobrien return new_mp; 1170174294Sobrien 1171174294Sobrien switch (op) { 1172174294Sobrien case VLOOK_DELETE: 1173174294Sobrien /* 1174174294Sobrien * If doing a delete then don't create again! 1175174294Sobrien */ 1176174294Sobrien ereturn(ENOENT); 1177174294Sobrien case VLOOK_LOOKUP: 1178174294Sobrien return new_mp; 1179174294Sobrien } 1180174294Sobrien 1181174294Sobrien /* save error_return */ 1182174294Sobrien mp_error = *error_return; 1183174294Sobrien 1184310490Scy al_array = amfs_lookup_loc(new_mp, error_return); 1185310490Scy if (!al_array) { 1186310490Scy new_mp->am_error = new_mp->am_al->al_mnt->mf_error = *error_return; 1187174294Sobrien free_map(new_mp); 1188174294Sobrien return NULL; 1189174294Sobrien } 1190174294Sobrien 1191174294Sobrien /* store the array inside the am_node */ 1192310490Scy new_mp->am_alarray = al_array; 1193174294Sobrien 1194174294Sobrien /* 1195174294Sobrien * Note: while it might seem like a good idea to prioritize 1196174294Sobrien * the list of mntfs's we got here, it probably isn't. 1197174294Sobrien * It would ignore the ordering of entries specified by the user, 1198174294Sobrien * which is counterintuitive and confusing. 1199174294Sobrien */ 1200174294Sobrien return new_mp; 1201174294Sobrien} 1202174294Sobrien 1203174294Sobrien 1204174294Sobrienvoid 1205174294Sobrienamfs_generic_mounted(mntfs *mf) 1206174294Sobrien{ 1207174294Sobrien amfs_mkcacheref(mf); 1208174294Sobrien} 1209174294Sobrien 1210174294Sobrien 1211174294Sobrien/* 1212174294Sobrien * Unmount an automount sub-node 1213174294Sobrien */ 1214174294Sobrienint 1215174294Sobrienamfs_generic_umount(am_node *mp, mntfs *mf) 1216174294Sobrien{ 1217174294Sobrien int error = 0; 1218174294Sobrien 1219174294Sobrien#ifdef HAVE_FS_AUTOFS 1220174294Sobrien int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0; 1221174294Sobrien if (mf->mf_flags & MFF_IS_AUTOFS) 1222174294Sobrien error = UMOUNT_FS(mp->am_path, mnttab_file_name, unmount_flags); 1223174294Sobrien#endif /* HAVE_FS_AUTOFS */ 1224174294Sobrien 1225174294Sobrien return error; 1226174294Sobrien} 1227174294Sobrien 1228174294Sobrien 1229174294Sobrienchar * 1230174294Sobrienamfs_generic_match(am_opts *fo) 1231174294Sobrien{ 1232174294Sobrien char *p; 1233174294Sobrien 1234174294Sobrien if (!fo->opt_rfs) { 1235174294Sobrien plog(XLOG_USER, "amfs_generic_match: no mount point named (rfs:=)"); 1236174294Sobrien return 0; 1237174294Sobrien } 1238174294Sobrien if (!fo->opt_fs) { 1239174294Sobrien plog(XLOG_USER, "amfs_generic_match: no map named (fs:=)"); 1240174294Sobrien return 0; 1241174294Sobrien } 1242174294Sobrien 1243174294Sobrien /* 1244174294Sobrien * Swap round fs:= and rfs:= options 1245174294Sobrien * ... historical (jsp) 1246174294Sobrien */ 1247174294Sobrien p = fo->opt_rfs; 1248174294Sobrien fo->opt_rfs = fo->opt_fs; 1249174294Sobrien fo->opt_fs = p; 1250174294Sobrien 1251174294Sobrien /* 1252174294Sobrien * mtab entry turns out to be the name of the mount map 1253174294Sobrien */ 1254310490Scy return xstrdup(fo->opt_rfs ? fo->opt_rfs : "."); 1255174294Sobrien} 1256