static int try_mount(struct libmnt_context *cxt, int bg) { struct libmnt_fs *fs; const char *p; char *src = NULL, *tgt = NULL, *type = NULL, *opts = NULL; unsigned long flags = 0; int fake, ret = 0; fs = mnt_context_get_fs(cxt); /* libmount returns read-only pointers (const char) * so, reallocate for nfsmount() functions. */ if ((p = mnt_fs_get_source(fs))) /* spec */ src = strdup(p); if ((p = mnt_fs_get_target(fs))) /* mountpoint */ tgt = strdup(p); if ((p = mnt_fs_get_fstype(fs))) /* FS type */ type = strdup(p); if ((p = mnt_fs_get_fs_options(fs))) /* mount options */ opts = strdup(p); mnt_context_get_mflags(cxt, &flags); /* mount(2) flags */ fake = mnt_context_is_fake(cxt); if (string) ret = nfsmount_string(src, tgt, type, flags, &opts, fake, bg); else if (strcmp(type, "nfs4") == 0) ret = nfs4mount(src, tgt, flags, &opts, fake, bg); else ret = nfsmount(src, tgt, flags, &opts, fake, bg); /* Store mount options if not called with mount --no-mtab */ if (!ret && !mnt_context_is_nomtab(cxt)) store_mount_options(fs, opts); free(src); free(tgt); free(type); free(opts); return ret; }
/** * mnt_context_do_umount: * @cxt: mount context * * Umount filesystem by umount(2) or fork()+exec(/sbin/umount.type). * Unnecessary for mnt_context_umount(). * * See also mnt_context_disable_helpers(). * * WARNING: non-zero return code does not mean that umount(2) syscall or * umount.type helper wasn't successfully called. * * Check mnt_context_get_status() after error! * * Returns: 0 on success; * >0 in case of umount(2) error (returns syscall errno), * <0 in case of other errors. */ int mnt_context_do_umount(struct libmnt_context *cxt) { int rc; assert(cxt); assert(cxt->fs); assert(cxt->helper_exec_status == 1); assert(cxt->syscall_status == 1); assert((cxt->flags & MNT_FL_PREPARED)); assert((cxt->action == MNT_ACT_UMOUNT)); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); rc = do_umount(cxt); if (rc) return rc; if (mnt_context_get_status(cxt) && !mnt_context_is_fake(cxt)) { /* * Umounted, do some post-umount operations * - remove loopdev * - refresh in-memory mtab stuff if remount rather than * umount has been performed */ if (mnt_context_is_loopdel(cxt) && !(cxt->mountflags & MS_REMOUNT)) rc = mnt_context_delete_loopdev(cxt); if (!mnt_context_is_nomtab(cxt) && mnt_context_get_status(cxt) && !cxt->helper && mnt_context_is_rdonly_umount(cxt) && (cxt->mountflags & MS_REMOUNT)) { /* use "remount" instead of "umount" in /etc/mtab */ if (!rc && cxt->update && cxt->mtab_writable) rc = mnt_update_set_fs(cxt->update, cxt->mountflags, NULL, cxt->fs); } } return rc; }
static int exec_helper(struct libmnt_context *cxt) { int rc; assert(cxt); assert(cxt->fs); assert(cxt->helper); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); assert(cxt->helper_exec_status == 1); DBG_FLUSH; switch (fork()) { case 0: { const char *args[10], *type; int i = 0; if (setgid(getgid()) < 0) exit(EXIT_FAILURE); if (setuid(getuid()) < 0) exit(EXIT_FAILURE); type = mnt_fs_get_fstype(cxt->fs); args[i++] = cxt->helper; /* 1 */ args[i++] = mnt_fs_get_target(cxt->fs); /* 2 */ if (mnt_context_is_nomtab(cxt)) args[i++] = "-n"; /* 3 */ if (mnt_context_is_lazy(cxt)) args[i++] = "-l"; /* 4 */ if (mnt_context_is_force(cxt)) args[i++] = "-f"; /* 5 */ if (mnt_context_is_verbose(cxt)) args[i++] = "-v"; /* 6 */ if (mnt_context_is_rdonly_umount(cxt)) args[i++] = "-r"; /* 7 */ if (type && !endswith(cxt->helper, type)) { args[i++] = "-t"; /* 8 */ args[i++] = (char *) type; /* 9 */ } args[i] = NULL; /* 10 */ #ifdef CONFIG_LIBMOUNT_DEBUG for (i = 0; args[i]; i++) DBG(CXT, mnt_debug_h(cxt, "argv[%d] = \"%s\"", i, args[i])); #endif DBG_FLUSH; execv(cxt->helper, (char * const *) args); exit(EXIT_FAILURE); } default: { int st; wait(&st); cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1; DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]", cxt->helper, cxt->helper_status)); cxt->helper_exec_status = rc = 0; break; } case -1: cxt->helper_exec_status = rc = -errno; DBG(CXT, mnt_debug_h(cxt, "fork() failed")); break; } return rc; }
static int exec_helper(struct libmnt_context *cxt) { char *o = NULL; int rc; assert(cxt); assert(cxt->fs); assert(cxt->helper); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); DBG(CXT, mnt_debug_h(cxt, "mount: executing helper %s", cxt->helper)); rc = generate_helper_optstr(cxt, &o); if (rc) return -EINVAL; DBG_FLUSH; switch (fork()) { case 0: { const char *args[12], *type; int i = 0; if (setgid(getgid()) < 0) exit(EXIT_FAILURE); if (setuid(getuid()) < 0) exit(EXIT_FAILURE); type = mnt_fs_get_fstype(cxt->fs); args[i++] = cxt->helper; /* 1 */ args[i++] = mnt_fs_get_srcpath(cxt->fs);/* 2 */ args[i++] = mnt_fs_get_target(cxt->fs); /* 3 */ /* * TODO: remove the exception for "nfs", -s is documented * for years should be usable everywhere. */ if (mnt_context_is_sloppy(cxt) && type && startswith(type, "nfs")) args[i++] = "-s"; /* 4 */ if (mnt_context_is_fake(cxt)) args[i++] = "-f"; /* 5 */ if (mnt_context_is_nomtab(cxt)) args[i++] = "-n"; /* 6 */ if (mnt_context_is_verbose(cxt)) args[i++] = "-v"; /* 7 */ if (o) { args[i++] = "-o"; /* 8 */ args[i++] = o; /* 9 */ } if (type && !endswith(cxt->helper, type)) { args[i++] = "-t"; /* 10 */ args[i++] = type; /* 11 */ } args[i] = NULL; /* 12 */ #ifdef CONFIG_LIBMOUNT_DEBUG for (i = 0; args[i]; i++) DBG(CXT, mnt_debug_h(cxt, "argv[%d] = \"%s\"", i, args[i])); #endif DBG_FLUSH; execv(cxt->helper, (char * const *) args); exit(EXIT_FAILURE); } default: { int st; wait(&st); cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1; DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]", cxt->helper, cxt->helper_status)); cxt->helper_exec_status = rc = 0; break; } case -1: cxt->helper_exec_status = rc = -errno; DBG(CXT, mnt_debug_h(cxt, "fork() failed")); break; } return rc; }
static int mount_main(struct libmnt_context *cxt, int argc, char **argv) { int rc, c; struct libmnt_fs *fs; char *spec = NULL, *mount_point = NULL, *opts = NULL; static const struct option longopts[] = { { "fake", 0, 0, 'f' }, { "help", 0, 0, 'h' }, { "no-mtab", 0, 0, 'n' }, { "read-only", 0, 0, 'r' }, { "ro", 0, 0, 'r' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { "read-write", 0, 0, 'w' }, { "rw", 0, 0, 'w' }, { "options", 1, 0, 'o' }, { "sloppy", 0, 0, 's' }, { NULL, 0, 0, 0 } }; mount_config_init(progname); mnt_context_init_helper(cxt, MNT_ACT_MOUNT, 0); while ((c = getopt_long(argc, argv, "fhnrVvwo:s", longopts, NULL)) != -1) { rc = mnt_context_helper_setopt(cxt, c, optarg); if (rc == 0) /* valid option */ continue; if (rc < 0) /* error (probably ENOMEM) */ goto err; /* rc==1 means unknow option */ switch (c) { case 'V': printf("%s: ("PACKAGE_STRING")\n", progname); return EX_SUCCESS; case 'h': default: mount_usage(); return EX_USAGE; } } if (optind < argc) spec = argv[optind++]; if (optind < argc) mount_point = argv[optind++]; if (!mount_point) { nfs_error(_("%s: no mount point provided"), progname); goto err; } if (!spec) { nfs_error(_("%s: no mount spec provided"), progname); goto err; } if (geteuid() != 0) { nfs_error(_("%s: not installed setuid - " "\"user\" NFS mounts not supported."), progname); goto err; } verbose = mnt_context_is_verbose(cxt); sloppy = mnt_context_is_sloppy(cxt); nomtab = mnt_context_is_nomtab(cxt); if (strcmp(progname, "mount.nfs4") == 0) mnt_context_set_fstype(cxt, "nfs4"); else mnt_context_set_fstype(cxt, "nfs"); /* default */ rc = mnt_context_set_source(cxt, spec); if (!rc) mnt_context_set_target(cxt, mount_point); if (rc) { nfs_error(_("%s: failed to set spec or mountpoint: %s"), progname, strerror(errno)); goto err; } mount_point = mnt_resolve_path(mount_point, mnt_context_get_cache(cxt)); if (chk_mountpoint(mount_point)) goto err; /* * Concatenate mount options from the configuration file */ fs = mnt_context_get_fs(cxt); if (fs) { opts = mnt_fs_strdup_options(fs); opts = mount_config_opts(spec, mount_point, opts); mnt_fs_set_options(fs, opts); } rc = mnt_context_prepare_mount(cxt); if (rc) { nfs_error(_("%s: failed to prepare mount: %s\n"), progname, strerror(-rc)); goto err; } rc = try_mount(cxt, FOREGROUND); if (rc == EX_BG) { printf(_("%s: backgrounding \"%s\"\n"), progname, mnt_context_get_source(cxt)); printf(_("%s: mount options: \"%s\"\n"), progname, opts); fflush(stdout); if (daemon(0, 0)) { nfs_error(_("%s: failed to start " "background process: %s\n"), progname, strerror(errno)); exit(EX_FAIL); } rc = try_mount(cxt, BACKGROUND); if (verbose && rc) printf(_("%s: giving up \"%s\"\n"), progname, mnt_context_get_source(cxt)); } mnt_context_set_syscall_status(cxt, rc == EX_SUCCESS ? 0 : -1); mnt_context_finalize_mount(cxt); /* mtab update */ return rc; err: return EX_FAIL; }