/* * Find a file server. * Returns: fserver of found server, or NULL if not found. */ static fserver * amfs_nfsl_ffserver(mntfs *mf) { char *cp, *ho; struct stat stb; if (mf->mf_fo == NULL) { plog(XLOG_ERROR, "%s: NULL mf_fo", __func__); return NULL; } ho = mf->mf_fo->opt_rhost; if (mf->mf_fo->opt_sublink && mf->mf_fo->opt_sublink[0]) cp = mf->mf_fo->opt_sublink; else cp = mf->mf_fo->opt_fs; /* * If this host is not the same as $rhost, or if link does not exist, * call amfs_link_ops.ffserver(). * If link value exists (or same host), then call ops_nfs.ffserver(). */ if ((!STRCEQ(ho, am_get_hostname()) && !STRCEQ(ho, hostd)) || lstat(cp, &stb) < 0) { return nfs_ops.ffserver(mf); } else { mf->mf_flags |= MFF_NFSLINK; /* remove the FS_MKMNT flag, we don't want amd touching the mountpoint */ mf->mf_fsflags &= ~FS_MKMNT; return amfs_link_ops.ffserver(mf); } }
/* * Check that f/s has all needed fields. * Returns: matched string if found, NULL otherwise. */ static char * amfs_nfsl_match(am_opts *fo) { char *cp = fo->opt_fs; char *ho = fo->opt_rhost; struct stat stb; if (!cp || !ho) { plog(XLOG_USER, "amfs_nfsl: host $fs and $rhost must be specified"); return NULL; } /* * If this host is not the same as $rhost, or if link does not exist, * perform nfs_match(), same as for type:=nfs. * If link value exists (or same host), then perform amfs_link_match(), * same as for linkx. */ if (!STRCEQ(ho, am_get_hostname())) { plog(XLOG_INFO, "amfs_nfsl: \"%s\" is not local host, using type:=nfs", ho); return nfs_match(fo); } else if (lstat(cp, &stb) < 0) { plog(XLOG_INFO, "amfs_nfsl: \"%s\" does not exist, using type:=nfs", cp); return nfs_match(fo); } else { plog(XLOG_INFO, "amfs_nfsl: \"%s\" exists, using type:=link", cp); return amfs_link_match(fo); } }
/* * Check that f/s has all needed fields. * Returns: matched string if found, NULL otherwise. */ static char * amfs_nfsl_match(am_opts *fo) { char *cp; char *ho = fo->opt_rhost; char *retval; struct stat stb; if (fo->opt_sublink && fo->opt_sublink[0]) cp = fo->opt_sublink; else cp = fo->opt_fs; if (!cp || !ho) { plog(XLOG_USER, "amfs_nfsl: host $fs and $rhost must be specified"); return NULL; } /* * If this host is not the same as $rhost, or if link does not exist, * call nfs_ops.fs_match(). * If link value exists (or same host), call amfs_link_ops.fs_match(). */ if (!STRCEQ(ho, am_get_hostname()) && !STRCEQ(ho, hostd)) { plog(XLOG_INFO, "amfs_nfsl: \"%s\" is not the local host \"%s\", " "or \"%s\" using type:=nfs", ho, am_get_hostname(), hostd); retval = nfs_ops.fs_match(fo); } else if (lstat(cp, &stb) < 0) { plog(XLOG_INFO, "amfs_nfsl: \"%s\" does not exist, using type:=nfs", cp); retval = nfs_ops.fs_match(fo); } else { plog(XLOG_INFO, "amfs_nfsl: \"%s\" exists, using type:=link", cp); retval = amfs_link_ops.fs_match(fo); } return retval; }
/* * Output the time of day and hostname to the logfile */ static void show_time_host_and_name(int lvl) { static time_t last_t = 0; static char *last_ctime = 0; time_t t = clocktime(); char *sev; if (t != last_t) { last_ctime = ctime(&t); last_t = t; } switch (lvl) { case XLOG_FATAL: sev = "fatal:"; break; case XLOG_ERROR: sev = "error:"; break; case XLOG_USER: sev = "user: "******"warn: "; break; case XLOG_INFO: sev = "info: "; break; case XLOG_DEBUG: sev = "debug:"; break; case XLOG_MAP: sev = "map: "; break; case XLOG_STATS: sev = "stats:"; break; default: sev = "hmm: "; break; } fprintf(logfp, "%15.15s %s %s[%ld]/%s ", last_ctime + 4, am_get_hostname(), am_get_progname(), (long) am_mypid, sev); }
/* * Find a file server. * Returns: fserver of found server, or NULL if not found. */ static fserver * amfs_nfsl_ffserver(mntfs *mf) { char *cp = mf->mf_fo->opt_fs; char *ho = mf->mf_fo->opt_rhost; struct stat stb; /* * If this host is not the same as $rhost, or if link does not exist, * perform find_nfs_srvr(), same as for type:=nfs. * If link value exists (or same host), then perform * find_amfs_auto_srvr(), same as for linkx. */ if (!STRCEQ(ho, am_get_hostname()) || lstat(cp, &stb) < 0) { return find_nfs_srvr(mf); } else { mf->mf_flags |= MFF_NFSLINK; return find_amfs_auto_srvr(mf); } }
int eval_fs_opts(am_opts *fo, char *opts, char *g_opts, char *path, char *key, char *map) { int ok = TRUE; free_opts(fo); /* * Clear out the option table */ memset((voidp) &fs_static, 0, sizeof(fs_static)); memset((voidp) vars, 0, sizeof(vars)); memset((voidp) fo, 0, sizeof(*fo)); /* set hostname */ opt_host = (char *) am_get_hostname(); /* * Set key, map & path before expansion */ opt_key = key; opt_map = map; opt_path = path; opt_dkey = strchr(key, '.'); if (!opt_dkey) { opt_dkey = NullStr; opt_keyd = key; } else { opt_keyd = strnsave(key, opt_dkey - key); opt_dkey++; if (*opt_dkey == '\0') /* check for 'host.' */ opt_dkey = NullStr; } /* * Expand global options */ fs_static.fs_glob = expand_selectors(g_opts); /* * Expand local options */ fs_static.fs_local = expand_selectors(opts); /* break global options into fs_static fields */ if ((ok = split_opts(fs_static.fs_glob, key))) { dlog("global split_opts ok"); /* * evaluate local selectors */ if ((ok = eval_selectors(fs_static.fs_local, key))) { dlog("local eval_selectors ok"); /* if the local selectors matched, then do the local overrides */ ok = split_opts(fs_static.fs_local, key); if (ok) dlog("local split_opts ok"); } } /* * Normalize remote host name. * 1. Expand variables * 2. Normalize relative to host tables * 3. Strip local domains from the remote host * name before using it in other expansions. * This makes mount point names and other things * much shorter, while allowing cross domain * sharing of mount maps. */ apply_opts(expand_opts, rhost_expansion, FALSE); if (ok && fs_static.opt_rhost && *fs_static.opt_rhost) host_normalize(&fs_static.opt_rhost); /* * Macro expand the options. * Do this regardless of whether we are accepting * this mount - otherwise nasty things happen * with memory allocation. */ apply_opts(expand_opts, expansions, FALSE); /* * Strip trailing slashes from local pathname... */ deslashify(fs_static.opt_fs); /* * ok... copy the data back out. */ *fo = fs_static; /* * Clear defined options */ if (opt_keyd != key && opt_keyd != nullstr) XFREE(opt_keyd); opt_keyd = nullstr; opt_dkey = NullStr; opt_key = opt_map = opt_path = nullstr; return ok; }
/* * Return the version string (dynamic buffer) */ char * get_version_string(void) { char *vers = NULL; char tmpbuf[1024]; char *wire_buf; int wire_buf_len = 0; size_t len; /* max allocated length (to avoid buf overflow) */ /* * First get dynamic string listing all known networks. * This could be a long list, if host has lots of interfaces. */ wire_buf = print_wires(); if (wire_buf) wire_buf_len = strlen(wire_buf); len = 2048 + wire_buf_len; vers = xmalloc(len); xsnprintf(vers, len, "%s\n%s\n%s\n%s\n", "Copyright (c) 1997-2006 Erez Zadok", "Copyright (c) 1990 Jan-Simon Pendry", "Copyright (c) 1990 Imperial College of Science, Technology & Medicine", "Copyright (c) 1990 The Regents of the University of California."); xsnprintf(tmpbuf, sizeof(tmpbuf), "%s version %s (build %d).\n", PACKAGE_NAME, PACKAGE_VERSION, AMU_BUILD_VERSION); strlcat(vers, tmpbuf, len); xsnprintf(tmpbuf, sizeof(tmpbuf), "Report bugs to %s.\n", PACKAGE_BUGREPORT); strlcat(vers, tmpbuf, len); xsnprintf(tmpbuf, sizeof(tmpbuf), "Configured by %s@%s on date %s.\n", USER_NAME, HOST_NAME, CONFIG_DATE); strlcat(vers, tmpbuf, len); xsnprintf(tmpbuf, sizeof(tmpbuf), "Built by %s@%s.\n", BUILD_USER, BUILD_HOST); strlcat(vers, tmpbuf, len); xsnprintf(tmpbuf, sizeof(tmpbuf), "cpu=%s (%s-endian), arch=%s, karch=%s.\n", cpu, endian, gopt.arch, gopt.karch); strlcat(vers, tmpbuf, len); xsnprintf(tmpbuf, sizeof(tmpbuf), "full_os=%s, os=%s, osver=%s, vendor=%s, distro=%s.\n", gopt.op_sys_full, gopt.op_sys, gopt.op_sys_ver, gopt.op_sys_vendor, DISTRO_NAME); strlcat(vers, tmpbuf, len); xsnprintf(tmpbuf, sizeof(tmpbuf), "domain=%s, host=%s, hostd=%s.\n", hostdomain, am_get_hostname(), hostd); strlcat(vers, tmpbuf, len); strlcat(vers, "Map support for: ", len); mapc_showtypes(tmpbuf, sizeof(tmpbuf)); strlcat(vers, tmpbuf, len); strlcat(vers, ".\nAMFS: ", len); ops_showamfstypes(tmpbuf, sizeof(tmpbuf)); strlcat(vers, tmpbuf, len); strlcat(vers, ", inherit.\nFS: ", len); /* hack: "show" that we support type:=inherit */ ops_showfstypes(tmpbuf, sizeof(tmpbuf)); strlcat(vers, tmpbuf, len); /* append list of networks if available */ if (wire_buf) { strlcat(vers, wire_buf, len); XFREE(wire_buf); } return vers; }
/* * Output the time of day and hostname to the logfile */ static void show_time_host_and_name(int lvl) { static time_t last_t = 0; static char *last_ctime = NULL; time_t t; #if defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) struct timespec ts; #endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */ char nsecs[11]; /* '.' + 9 digits + '\0' */ char *sev; nsecs[0] = '\0'; #if defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) /* * Some systems (AIX 4.3) seem to implement clock_gettime() as stub * returning ENOSYS. */ if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { t = ts.tv_sec; if (amuDebug(D_HRTIME)) xsnprintf(nsecs, sizeof(nsecs), ".%09ld", ts.tv_nsec); } else #endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */ t = clocktime(NULL); if (t != last_t) { last_ctime = ctime(&t); last_t = t; } switch (lvl) { case XLOG_FATAL: sev = "fatal:"; break; case XLOG_ERROR: sev = "error:"; break; case XLOG_USER: sev = "user: "******"warn: "; break; case XLOG_INFO: sev = "info: "; break; case XLOG_DEBUG: sev = "debug:"; break; case XLOG_MAP: sev = "map: "; break; case XLOG_STATS: sev = "stats:"; break; default: sev = "hmm: "; break; } fprintf(logfp, "%15.15s%s %s %s[%ld]/%s ", last_ctime + 4, nsecs, am_get_hostname(), am_get_progname(), (long) am_mypid, sev); }
/* * Mount an automounter directory. * The automounter is connected into the system * as a user-level NFS server. mount_amfs_toplvl constructs * the necessary NFS parameters to be given to the * kernel so that it will talk back to us. * * NOTE: automounter mounts in themselves are using NFS Version 2. */ static int mount_amfs_toplvl(char *dir, char *opts) { char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; int retry, error, genflags; mntent_t mnt; nfs_args_t nfs_args; am_nfs_fh *fhp; am_nfs_handle_t anh; MTYPE_TYPE type = MOUNT_TYPE_NFS; #ifndef HAVE_TRANSPORT_TYPE_TLI u_short port; struct sockaddr_in sin; #endif /* not HAVE_TRANSPORT_TYPE_TLI */ memset((voidp) &mnt, 0, sizeof(mnt)); mnt.mnt_dir = dir; mnt.mnt_fsname = pid_fsname; mnt.mnt_opts = opts; /* * Make sure that amd's top-level NFS mounts are hidden by default * from df. * If they don't appear to support the either the "ignore" mnttab * option entry, or the "auto" one, set the mount type to "nfs". */ mnt.mnt_type = HIDE_MOUNT_TYPE; retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); if (retry <= 0) retry = 2; /* XXX */ /* * SET MOUNT ARGS */ /* * get fhandle of remote path for automount point */ fhp = root_fh(dir); if (!fhp) { plog(XLOG_FATAL, "Can't find root file handle for %s", dir); return EINVAL; } #ifndef HAVE_TRANSPORT_TYPE_TLI /* * Create sockaddr to point to the local machine. 127.0.0.1 * is not used since that will not work in HP-UX clusters and * this is no more expensive. */ memset((voidp) &sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr = myipaddr; port = hasmntval(&mnt, MNTTAB_OPT_PORT); if (port) { sin.sin_port = htons(port); } else { plog(XLOG_ERROR, "no port number specified for %s", dir); return EINVAL; } #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /* * Make a ``hostname'' string for the kernel */ sprintf(fs_hostname, "pid%ld@%s:%s", (long) (foreground ? am_mypid : getppid()), am_get_hostname(), dir); /* * Most kernels have a name length restriction (64 bytes)... */ if (strlen(fs_hostname) >= MAXHOSTNAMELEN) strcpy(fs_hostname + MAXHOSTNAMELEN - 3, ".."); #ifdef HOSTNAMESZ /* * ... and some of these restrictions are 32 bytes (HOSTNAMESZ) * If you need to get the definition for HOSTNAMESZ found, you may * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file. */ if (strlen(fs_hostname) >= HOSTNAMESZ) strcpy(fs_hostname + HOSTNAMESZ - 3, ".."); #endif /* HOSTNAMESZ */ /* * Finally we can compute the mount genflags set above, * and add any automounter specific flags. */ genflags = compute_mount_flags(&mnt); genflags |= compute_automounter_mount_flags(&mnt); /* setup the many fields and flags within nfs_args */ memmove(&anh.v2.fhs_fh, fhp, sizeof(*fhp)); #ifdef HAVE_TRANSPORT_TYPE_TLI compute_nfs_args(&nfs_args, &mnt, genflags, nfsncp, NULL, /* remote host IP addr is set below */ NFS_VERSION, /* version 2 */ "udp", &anh, fs_hostname, pid_fsname); /* * IMPORTANT: set the correct IP address AFTERWARDS. It cannot * be done using the normal mechanism of compute_nfs_args(), because * that one will allocate a new address and use NFS_SA_DREF() to copy * parts to it, while assuming that the ip_addr passed is always * a "struct sockaddr_in". That assumption is incorrect on TLI systems, * because they define a special macro HOST_SELF which is DIFFERENT * than localhost (127.0.0.1)! */ nfs_args.addr = &nfsxprt->xp_ltaddr; #else /* not HAVE_TRANSPORT_TYPE_TLI */ compute_nfs_args(&nfs_args, &mnt, genflags, &sin, NFS_VERSION, /* version 2 */ "udp", &anh, fs_hostname, pid_fsname); #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /************************************************************************* * NOTE: while compute_nfs_args() works ok for regular NFS mounts * * the toplvl one is not, and so some options must be corrected by hand * * more carefully, *after* compute_nfs_args() runs. * *************************************************************************/ compute_automounter_nfs_args(&nfs_args, &mnt); /* This is it! Here we try to mount amd on its mount points */ #ifdef DEBUG amuDebug(D_TRACE) { print_nfs_args(&nfs_args, 0); plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags); } #endif /* DEBUG */ error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name); #ifdef HAVE_TRANSPORT_TYPE_TLI free_knetconfig(nfs_args.knconf); /* * local automounter mounts do not allocate a special address, so * no need to XFREE(nfs_args.addr) under TLI. */ #endif /* HAVE_TRANSPORT_TYPE_TLI */ return error; }
/* * Map from conventional mount arguments to AIX 3,x style arguments. * But we avoid all the messy BIS stuff for AIX 5.x */ int mount_aix3(char *fsname, char *dir, int flags, int type, void *data, char *mnt_opts) { char buf[4096]; int size, ret; int real_size = sizeof(nfs_args_t); /* size passed to aix5_mkvp() */ char *real_args = data; /* args passed to aix5_mkvp() */ char *host, *rfs, *idx; int aix_type = type; #ifdef HAVE_FS_NFS3 struct nfs_args v2args; nfs_args_t *v3args = (nfs_args_t *) data; #endif /* HAVE_FS_NFS3 */ #ifdef DEBUG dlog("mount_aix3: fsname %s, dir %s, type %d", fsname, dir, type); #endif /* DEBUG */ switch (aix_type) { case MOUNT_TYPE_NFS: #ifdef HAVE_FS_NFS3 /* * This is tricky. If we have v3 support, but this nfs mount is v2, * then I must copy the arguments from the v3 nfs_args to the v2 one. */ memmove((voidp) &v2args.addr, (voidp) &v3args->addr, sizeof(struct sockaddr_in)); v2args.hostname = v3args->hostname; v2args.netname = v3args->netname; memmove((voidp) v2args.fh.x, v3args->fh, FHSIZE); v2args.flags = v3args->flags; v2args.wsize = v3args->wsize; v2args.rsize = v3args->rsize; v2args.timeo = v3args->timeo; v2args.retrans = v3args->retrans; v2args.acregmin = v3args->acregmin; v2args.acregmax = v3args->acregmax; v2args.acdirmin = v3args->acdirmin; v2args.acdirmax = v3args->acdirmax; v2args.pathconf = v3args->pathconf; /* now set real_* stuff */ real_size = sizeof(v2args); real_args = (char *) &v2args; case MOUNT_TYPE_NFS3: #endif /* HAVE_FS_NFS3 */ idx = strchr(fsname, ':'); if (idx) { *idx = '\0'; rfs = strdup(idx + 1); host = strdup(fsname); *idx = ':'; } else { rfs = strdup(fsname); host = strdup(am_get_hostname()); } size = aix5_mkvp(buf, type, flags, rfs, dir, host, real_args, real_size, mnt_opts); XFREE(rfs); XFREE(host); break; case MOUNT_TYPE_UFS: /* Need to open block device and extract log device info from sblk. */ return EINVAL; default: return EINVAL; } /* * XXX: Warning, if vmount() hangs your amd in AIX 5.1, it * is because of a kernel bug in the NFS code. Get a patch from IBM * or upgrade to 5.2. */ ret = vmount((struct vmount *)buf, size); if (ret < 0) { plog(XLOG_ERROR, "mount_aix3: vmount failed with errno %d", errno); perror ("vmount"); } return ret; }
int mount_automounter(int ppid) { /* * Old code replaced by rpc-trash patch. * Erez Zadok <*****@*****.**> int so = socket(AF_INET, SOCK_DGRAM, 0); */ SVCXPRT *udp_amqp = NULL, *tcp_amqp = NULL; int nmount, ret; int soNFS; int udp_soAMQ, tcp_soAMQ; struct netconfig *udp_amqncp, *tcp_amqncp; /* * This must be done first, because it attempts to bind * to various UDP ports and we don't want anything else * potentially taking over those ports before we get a chance * to reserve them. */ if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS) restart_automounter_nodes(); /* * Start RPC forwarding */ if (fwd_init() != 0) return 3; /* * Construct the root automount node */ make_root_node(); /* * Pick up the pieces from a previous run * This is likely to (indirectly) need the rpc_fwd package * so it *must* come after the call to fwd_init(). */ if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS) restart(); /* * Create the nfs service for amd * If nfs_port is already initialized, it means we * already created the service during restart_automounter_nodes(). */ if (nfs_port == 0) { ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); if (ret != 0) return ret; } xsnprintf(pid_fsname, sizeof(pid_fsname), "%s:(pid%ld,port%u)", am_get_hostname(), (long) am_mypid, nfs_port); /* security: if user sets -D noamq, don't even create listening socket */ if (amuDebug(D_AMQ)) { ret = create_amq_service(&udp_soAMQ, &udp_amqp, &udp_amqncp, &tcp_soAMQ, &tcp_amqp, &tcp_amqncp, gopt.preferred_amq_port); if (ret != 0) return ret; } #ifdef HAVE_FS_AUTOFS if (amd_use_autofs) { /* * Create the autofs service for amd. */ ret = create_autofs_service(); /* if autofs service fails it is OK if using a test amd */ if (ret != 0) { plog(XLOG_WARNING, "autofs service registration failed, turning off autofs support"); amd_use_autofs = 0; } } #endif /* HAVE_FS_AUTOFS */ /* * Mount the top-level auto-mountpoints */ nmount = mount_exported(); /* * Now safe to tell parent that we are up and running */ if (ppid) kill(ppid, SIGQUIT); if (nmount == 0) { plog(XLOG_FATAL, "No work to do - quitting"); amd_state = Done; return 0; } if (amuDebug(D_AMQ)) { /* * Complete registration of amq (first TCP service then UDP) */ int tcp_ok = 0, udp_ok = 0; unregister_amq(); /* unregister leftover Amd, if any, just in case */ tcp_ok = amu_svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION, amq_program_1, IPPROTO_TCP, tcp_amqncp); if (!tcp_ok) plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%lu, AMQ_VERSION, tcp)", get_amd_program_number()); udp_ok = amu_svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION, amq_program_1, IPPROTO_UDP, udp_amqncp); if (!udp_ok) plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%lu, AMQ_VERSION, udp)", get_amd_program_number()); /* return error only if both failed */ if (!tcp_ok && !udp_ok) { amd_state = Done; return 3; } } /* * Start timeout_mp rolling */ reschedule_timeout_mp(); /* * Start the server */ if (run_rpc() != Done) { plog(XLOG_FATAL, "run_rpc failed"); amd_state = Done; } return 0; }
/* * Mount an automounter directory. * The automounter is connected into the system * as a user-level NFS server. amfs_mount constructs * the necessary NFS parameters to be given to the * kernel so that it will talk back to us. * * NOTE: automounter mounts in themselves are using NFS Version 2 (UDP). * * NEW: on certain systems, mounting can be done using the * kernel-level automount (autofs) support. In that case, * we don't need NFS at all here. */ int amfs_mount(am_node *mp, mntfs *mf, char *opts) { char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; int retry, error = 0, genflags; int on_autofs = mf->mf_flags & MFF_ON_AUTOFS; char *dir = mf->mf_mount; mntent_t mnt; MTYPE_TYPE type; int forced_unmount = 0; /* are we using forced unmounts? */ u_long nfs_version = get_nfs_dispatcher_version(nfs_dispatcher); memset(&mnt, 0, sizeof(mnt)); mnt.mnt_dir = dir; mnt.mnt_fsname = pid_fsname; mnt.mnt_opts = opts; #ifdef HAVE_FS_AUTOFS if (mf->mf_flags & MFF_IS_AUTOFS) { type = MOUNT_TYPE_AUTOFS; /* * Make sure that amd's top-level autofs mounts are hidden by default * from df. * XXX: It works ok on Linux, might not work on other systems. */ mnt.mnt_type = "autofs"; } else #endif /* HAVE_FS_AUTOFS */ { type = MOUNT_TYPE_NFS; /* * Make sure that amd's top-level NFS mounts are hidden by default * from df. * If they don't appear to support the either the "ignore" mnttab * option entry, or the "auto" one, set the mount type to "nfs". */ mnt.mnt_type = HIDE_MOUNT_TYPE; } retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); if (retry <= 0) retry = 2; /* XXX: default to 2 retries */ /* * SET MOUNT ARGS */ /* * Make a ``hostname'' string for the kernel */ xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s", get_server_pid(), am_get_hostname(), dir); /* * Most kernels have a name length restriction (64 bytes)... */ if (strlen(fs_hostname) >= MAXHOSTNAMELEN) xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..", sizeof(fs_hostname) - MAXHOSTNAMELEN + 3); #ifdef HOSTNAMESZ /* * ... and some of these restrictions are 32 bytes (HOSTNAMESZ) * If you need to get the definition for HOSTNAMESZ found, you may * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file. */ if (strlen(fs_hostname) >= HOSTNAMESZ) xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..", sizeof(fs_hostname) - HOSTNAMESZ + 3); #endif /* HOSTNAMESZ */ /* * Finally we can compute the mount genflags set above, * and add any automounter specific flags. */ genflags = compute_mount_flags(&mnt); #ifdef HAVE_FS_AUTOFS if (on_autofs) genflags |= autofs_compute_mount_flags(&mnt); #endif /* HAVE_FS_AUTOFS */ genflags |= compute_automounter_mount_flags(&mnt); again: if (!(mf->mf_flags & MFF_IS_AUTOFS)) { nfs_args_t nfs_args; am_nfs_handle_t *fhp, anh; #ifndef HAVE_TRANSPORT_TYPE_TLI u_short port; struct sockaddr_in sin; #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /* * get fhandle of remote path for automount point */ fhp = get_root_nfs_fh(dir, &anh); if (!fhp) { plog(XLOG_FATAL, "Can't find root file handle for %s", dir); return EINVAL; } #ifndef HAVE_TRANSPORT_TYPE_TLI /* * Create sockaddr to point to the local machine. */ memset(&sin, 0, sizeof(sin)); /* as per POSIX, sin_len need not be set (used internally by kernel) */ sin.sin_family = AF_INET; sin.sin_addr = myipaddr; port = hasmntval(&mnt, MNTTAB_OPT_PORT); if (port) { sin.sin_port = htons(port); } else { plog(XLOG_ERROR, "no port number specified for %s", dir); return EINVAL; } #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /* setup the many fields and flags within nfs_args */ #ifdef HAVE_TRANSPORT_TYPE_TLI compute_nfs_args(&nfs_args, &mnt, genflags, nfsncp, NULL, /* remote host IP addr is set below */ nfs_version, "udp", fhp, fs_hostname, pid_fsname); /* * IMPORTANT: set the correct IP address AFTERWARDS. It cannot * be done using the normal mechanism of compute_nfs_args(), because * that one will allocate a new address and use NFS_SA_DREF() to copy * parts to it, while assuming that the ip_addr passed is always * a "struct sockaddr_in". That assumption is incorrect on TLI systems, * because they define a special macro HOST_SELF which is DIFFERENT * than localhost (127.0.0.1)! */ nfs_args.addr = &nfsxprt->xp_ltaddr; #else /* not HAVE_TRANSPORT_TYPE_TLI */ compute_nfs_args(&nfs_args, &mnt, genflags, NULL, &sin, nfs_version, "udp", fhp, fs_hostname, pid_fsname); #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /************************************************************************* * NOTE: while compute_nfs_args() works ok for regular NFS mounts * * the toplvl one is not quite regular, and so some options must be * * corrected by hand more carefully, *after* compute_nfs_args() runs. * *************************************************************************/ compute_automounter_nfs_args(&nfs_args, &mnt); if (amuDebug(D_TRACE)) { print_nfs_args(&nfs_args, 0); plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags); } /* This is it! Here we try to mount amd on its mount points */ error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, on_autofs); #ifdef HAVE_TRANSPORT_TYPE_TLI free_knetconfig(nfs_args.knconf); /* * local automounter mounts do not allocate a special address, so * no need to XFREE(nfs_args.addr) under TLI. */ #endif /* HAVE_TRANSPORT_TYPE_TLI */ #ifdef HAVE_FS_AUTOFS } else { /* This is it! Here we try to mount amd on its mount points */ error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh, retry, type, 0, NULL, mnttab_file_name, on_autofs); #endif /* HAVE_FS_AUTOFS */ } if (error == 0 || forced_unmount) return error; /* * If user wants forced/lazy unmount semantics, then try it iff the * current mount failed with EIO or ESTALE. */ if (gopt.flags & CFM_FORCED_UNMOUNTS) { switch (errno) { case ESTALE: case EIO: forced_unmount = errno; plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path); if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name, AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) { plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path); errno = forced_unmount; } else goto again; default: break; } } return error; }