void autofs_mount_succeeded(am_node *mp) { SVCXPRT *transp = mp->am_transp; struct stat stb; char *space_hack; if (transp) { /* this was a mount request */ mntres res; res.status = 0; if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_mntres, (SVC_IN_ARG_TYPE) &res)) svcerr_systemerr(transp); dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount); XFREE(transp); mp->am_transp = NULL; } space_hack = autofs_strdup_space_hack(mp->am_path); if (!lstat(space_hack, &stb)) { mp->am_dev = stb.st_dev; mp->am_rdev = stb.st_rdev; } XFREE(space_hack); /* don't expire the entries -- the kernel will do it for us */ mp->am_flags |= AMF_NOTIMEOUT; plog(XLOG_INFO, "autofs: mounting %s succeeded", mp->am_path); }
int autofs_umount_fs(am_node *mp, mntfs *mf) { int err = 0; char *space_hack = autofs_strdup_space_hack(mp->am_path); /* * Autofs v1 doesn't support symlinks, * so we ignore the CFM_AUTOFS_USE_LOFS flag */ if (!(mf->mf_flags & MFF_ON_AUTOFS)) { err = UMOUNT_FS(mp->am_path, mnttab_file_name, 1); if (err) goto out; rmdir(space_hack); } /* * Multiple sublinks could reference this f/s. * Don't actually unmount it unless we're holding the last reference. */ if (mf->mf_refc == 1) { if ((err = mf->mf_ops->umount_fs(mp, mf))) goto out; if (mf->mf_flags & MFF_ON_AUTOFS) rmdir(space_hack); } out: XFREE(space_hack); return err; }
int umount_fs(char *mntdir, const char *mnttabname, u_int unmount_flags) { mntlist *mlist, *mp, *mp_save = NULL; int error = 0; mp = mlist = read_mtab(mntdir, mnttabname); /* * Search the mount table looking for * the correct (ie last) matching entry */ while (mp) { if (STREQ(mp->mnt->mnt_dir, mntdir)) mp_save = mp; mp = mp->mnext; } if (mp_save) { dlog("Trying unmount(%s)", mp_save->mnt->mnt_dir); #ifdef MOUNT_TABLE_ON_FILE /* * This unmount may hang leaving this process with an exclusive lock on * /etc/mtab. Therefore it is necessary to unlock mtab, do the unmount, * then lock mtab (again) and reread it and finally update it. */ unlock_mntlist(); #endif /* MOUNT_TABLE_ON_FILE */ #ifdef NEED_AUTOFS_SPACE_HACK if (unmount_flags & AMU_UMOUNT_AUTOFS) { char *mnt_dir_save = mp_save->mnt->mnt_dir; mp_save->mnt->mnt_dir = autofs_strdup_space_hack(mnt_dir_save); error = UNMOUNT_TRAP(mp_save->mnt); XFREE(mp_save->mnt->mnt_dir); mp_save->mnt->mnt_dir = mnt_dir_save; } else #endif /* NEED_AUTOFS_SPACE_HACK */ error = UNMOUNT_TRAP(mp_save->mnt); if (error < 0) { switch ((error = errno)) { case EINVAL: case ENOTBLK: plog(XLOG_WARNING, "unmount: %s is not mounted", mp_save->mnt->mnt_dir); error = 0; /* Not really an error */ break; case ENOENT: /* * This could happen if the kernel insists on following symlinks * when we try to unmount a direct mountpoint. We need to propagate * the error up so that the top layers know it failed and don't * try to rmdir() the mountpoint or other silly things. */ plog(XLOG_ERROR, "mount point %s: %m", mp_save->mnt->mnt_dir); break; #if defined(MNT2_GEN_OPT_FORCE) && defined(HAVE_UVMOUNT) case EBUSY: case EIO: case ESTALE: /* caller determines if forced unmounts should be used */ if (unmount_flags & AMU_UMOUNT_FORCE) { error = umount2_fs(mntdir, unmount_flags); if (error < 0) error = errno; else break; /* all is OK */ } /* fallthrough */ #endif /* MNT2_GEN_OPT_FORCE && HAVE_UVMOUNT */ default: dlog("%s: unmount: %m", mp_save->mnt->mnt_dir); break; } } dlog("Finished unmount(%s)", mp_save->mnt->mnt_dir); if (!error) { #ifdef MOUNT_TABLE_ON_FILE free_mntlist(mlist); mp = mlist = read_mtab(mntdir, mnttabname); /* * Search the mount table looking for * the correct (ie last) matching entry */ mp_save = NULL; while (mp) { if (STREQ(mp->mnt->mnt_dir, mntdir)) mp_save = mp; mp = mp->mnext; } if (mp_save) { mnt_free(mp_save->mnt); mp_save->mnt = NULL; rewrite_mtab(mlist, mnttabname); } #endif /* MOUNT_TABLE_ON_FILE */ } } else { plog(XLOG_ERROR, "Couldn't find how to unmount %s", mntdir); /* * Assume it is already unmounted */ error = 0; } /* end of "if (mp_save)" statement */ free_mntlist(mlist); return error; }
int autofs_mount_fs(am_node *mp, mntfs *mf) { int err = 0; char *target, *target2 = NULL; char *space_hack = autofs_strdup_space_hack(mp->am_path); struct stat buf; if (mf->mf_flags & MFF_ON_AUTOFS) { if ((err = mkdir(space_hack, 0555))) goto out; } /* * For sublinks, we could end up here with an already mounted f/s. * Don't do anything in that case. */ if (!(mf->mf_flags & MFF_MOUNTED)) err = mf->mf_ops->mount_fs(mp, mf); if (err) { if (mf->mf_flags & MFF_ON_AUTOFS) rmdir(space_hack); errno = err; goto out; } /* * Autofs v1 doesn't support symlinks, * so we ignore the CFM_AUTOFS_USE_LOFS flag */ if (mf->mf_flags & MFF_ON_AUTOFS) /* Nothing to do */ goto out; if (mp->am_link) target = mp->am_link; else target = mf->mf_mount; if (target[0] != '/') target2 = str3cat(NULL, mp->am_parent->am_path, "/", target); else target2 = xstrdup(target); plog(XLOG_INFO, "autofs: converting from link to lofs (%s -> %s)", mp->am_path, target2); /* * we need to stat() the destination, because the bind mount does not * follow symlinks and/or allow for non-existent destinations. * * WARNING: we will deadlock if this function is called from the master * amd process and it happens to trigger another auto mount. Therefore, * this function should be called only from a child amd process, or * at the very least it should not be called from the parent unless we * know for sure that it won't cause a recursive mount. We refuse to * cause the recursive mount anyway if called from the parent amd. */ if (!foreground) { if ((err = stat(target2, &buf))) goto out; } if ((err = lstat(target2, &buf))) goto out; if ((err = mkdir(space_hack, 0555))) goto out; if ((err = mount_lofs(mp->am_path, target2, mf->mf_mopts, 1))) { errno = err; goto out; } out: XFREE(space_hack); if (target2) XFREE(target2); if (err) return errno; return 0; }
int mount_fs(mntent_t *mnt, int flags, caddr_t mnt_data, int retry, MTYPE_TYPE type, u_long nfs_version, const char *nfs_proto, const char *mnttabname, int on_autofs) { int error = 0; #ifdef MOUNT_TABLE_ON_FILE char *zopts = NULL, *xopts = NULL; size_t l; #endif /* MOUNT_TABLE_ON_FILE */ char *mnt_dir = NULL; #ifdef NEED_AUTOFS_SPACE_HACK char *old_mnt_dir = NULL; /* perform space hack */ if (on_autofs) { old_mnt_dir = mnt->mnt_dir; mnt->mnt_dir = mnt_dir = autofs_strdup_space_hack(old_mnt_dir); } else #endif /* NEED_AUTOFS_SPACE_HACK */ mnt_dir = strdup(mnt->mnt_dir); dlog("'%s' fstype " MTYPE_PRINTF_TYPE " (%s) flags %#x (%s)", mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts); again: error = MOUNT_TRAP(type, mnt, flags, mnt_data); if (error < 0) { plog(XLOG_ERROR, "'%s': mount: %m", mnt_dir); /* * The following code handles conditions which shouldn't * occur. They are possible either because amd screws up * in preparing for the mount, or because some human * messed with the mount point. Both have been known to * happen. -- stolcke 2/22/95 */ if (errno == EBUSY) { /* * Also, sometimes unmount isn't called, e.g., because * our mountlist is garbled. This leaves old mount * points around which need to be removed before we * can mount something new in their place. */ errno = umount_fs(mnt_dir, mnttabname, on_autofs); if (errno != 0) plog(XLOG_ERROR, "'%s': umount: %m", mnt_dir); else { plog(XLOG_WARNING, "extra umount required for '%s'", mnt_dir); error = MOUNT_TRAP(type, mnt, flags, mnt_data); } } } if (error < 0 && --retry > 0) { sleep(1); goto again; } #ifdef NEED_AUTOFS_SPACE_HACK /* Undo space hack */ if (on_autofs) mnt->mnt_dir = old_mnt_dir; #endif /* NEED_AUTOFS_SPACE_HACK */ if (error < 0) { error = errno; goto out; } #ifdef MOUNT_TABLE_ON_FILE /* * Allocate memory for options: * dev=..., vers={2,3}, proto={tcp,udp} */ l = strlen(mnt->mnt_opts) + 48; zopts = (char *) xmalloc(l); /* copy standard options */ xopts = mnt->mnt_opts; xstrlcpy(zopts, xopts, l); # ifdef MNTTAB_OPT_DEV { /* add the extra dev= field to the mount table */ struct stat stb; if (lstat(mnt_dir, &stb) == 0) { char optsbuf[48]; if (sizeof(stb.st_dev) == 2) /* e.g. SunOS 4.1 */ xsnprintf(optsbuf, sizeof(optsbuf), "%s=%04lx", MNTTAB_OPT_DEV, (u_long) stb.st_dev & 0xffff); else /* e.g. System Vr4 */ xsnprintf(optsbuf, sizeof(optsbuf), "%s=%08lx", MNTTAB_OPT_DEV, (u_long) stb.st_dev); append_opts(zopts, l, optsbuf); } } # endif /* MNTTAB_OPT_DEV */ # if defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS) /* * add the extra vers={2,3} field to the mount table, * unless already specified by user */ if (nfs_version == NFS_VERSION3 && hasmntval(mnt, MNTTAB_OPT_VERS) != NFS_VERSION3) { char optsbuf[48]; xsnprintf(optsbuf, sizeof(optsbuf), "%s=%d", MNTTAB_OPT_VERS, NFS_VERSION3); append_opts(zopts, l, optsbuf); } # endif /* defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS) */ # ifdef MNTTAB_OPT_PROTO /* * add the extra proto={tcp,udp} field to the mount table, * unless already specified by user. */ if (nfs_proto && !amu_hasmntopt(mnt, MNTTAB_OPT_PROTO)) { char optsbuf[48]; xsnprintf(optsbuf, sizeof(optsbuf), "%s=%s", MNTTAB_OPT_PROTO, nfs_proto); append_opts(zopts, l, optsbuf); } # endif /* MNTTAB_OPT_PROTO */ /* finally, store the options into the mount table structure */ mnt->mnt_opts = zopts; /* * Additional fields in mntent_t * are fixed up here */ # ifdef HAVE_MNTENT_T_MNT_CNODE mnt->mnt_cnode = 0; # endif /* HAVE_MNTENT_T_MNT_CNODE */ # ifdef HAVE_MNTENT_T_MNT_RO mnt->mnt_ro = (amu_hasmntopt(mnt, MNTTAB_OPT_RO) != NULL); # endif /* HAVE_MNTENT_T_MNT_RO */ # ifdef HAVE_MNTENT_T_MNT_TIME # ifdef HAVE_MNTENT_T_MNT_TIME_STRING { /* allocate enough space for a long */ size_t l = 13 * sizeof(char); char *str = (char *) xmalloc(l); xsnprintf(str, l, "%ld", time((time_t *) NULL)); mnt->mnt_time = str; } # else /* not HAVE_MNTENT_T_MNT_TIME_STRING */ mnt->mnt_time = time((time_t *) NULL); # endif /* not HAVE_MNTENT_T_MNT_TIME_STRING */ # endif /* HAVE_MNTENT_T_MNT_TIME */ write_mntent(mnt, mnttabname); # ifdef MNTTAB_OPT_DEV if (xopts) { XFREE(mnt->mnt_opts); mnt->mnt_opts = xopts; } # endif /* MNTTAB_OPT_DEV */ #endif /* MOUNT_TABLE_ON_FILE */ out: XFREE(mnt_dir); return error; }