/** * mnt_update_force_rdonly: * @upd: update * @rdonly: is read-only? * * Returns: 0 on success and negative number in case of error. */ int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly) { int rc = 0; if (!upd || !upd->fs) return -EINVAL; if (rdonly && (upd->mountflags & MS_RDONLY)) return 0; if (!rdonly && !(upd->mountflags & MS_RDONLY)) return 0; if (!upd->userspace_only) { /* /etc/mtab -- we care about VFS options there */ const char *o = mnt_fs_get_options(upd->fs); char *n = o ? strdup(o) : NULL; if (n) mnt_optstr_remove_option(&n, rdonly ? "rw" : "ro"); if (!mnt_optstr_prepend_option(&n, rdonly ? "ro" : "rw", NULL)) rc = mnt_fs_set_options(upd->fs, n); free(n); } if (rdonly) upd->mountflags &= ~MS_RDONLY; else upd->mountflags |= MS_RDONLY; return rc; }
/* * Parses one line from {fs,m}tab */ static int mnt_parse_table_line(struct libmnt_fs *fs, char *s) { int rc, n = 0; char *src, *fstype, *optstr; rc = sscanf(s, UL_SCNsA" " /* (1) source */ UL_SCNsA" " /* (2) target */ UL_SCNsA" " /* (3) FS type */ UL_SCNsA" " /* (4) options */ "%n", /* byte count */ &src, &fs->target, &fstype, &optstr, &n); if (rc == 4) { unmangle_string(src); unmangle_string(fs->target); unmangle_string(fstype); unmangle_string(optstr); rc = __mnt_fs_set_source_ptr(fs, src); if (!rc) rc = __mnt_fs_set_fstype_ptr(fs, fstype); if (!rc) rc = mnt_fs_set_options(fs, optstr); free(optstr); } else { DBG(TAB, mnt_debug("tab parse error: [sscanf rc=%d]: '%s'", rc, s)); rc = -EINVAL; } if (rc) return rc; /* error */ fs->passno = fs->freq = 0; s = skip_spaces(s + n); if (*s) { if (next_number(&s, &fs->freq) != 0) { if (*s) { DBG(TAB, mnt_debug("tab parse error: [freq]")); rc = -EINVAL; } } else if (next_number(&s, &fs->passno) != 0 && *s) { DBG(TAB, mnt_debug("tab parse error: [passno]")); rc = -EINVAL; } } return rc; }
/* * Store mount options to mtab (or /dev/.mount/utab), called from mount.nfs. * * Note that on systems without /etc/mtab the fs-specific options are not * managed by libmount at all. We have to use "mount attributes" that are * private for mount.<type> helpers. */ static void store_mount_options(struct libmnt_fs *fs, const char *nfs_opts) { char *o = NULL; mnt_fs_set_attributes(fs, nfs_opts); /* for non-mtab systems */ /* for mtab create a new options list */ mnt_optstr_append_option(&o, mnt_fs_get_vfs_options(fs), NULL); mnt_optstr_append_option(&o, nfs_opts, NULL); mnt_optstr_append_option(&o, mnt_fs_get_user_options(fs), NULL); mnt_fs_set_options(fs, o); free(o); }
static int test_remount(struct libmnt_test *ts, int argc, char *argv[]) { struct libmnt_fs *fs = mnt_new_fs(); int rc; if (argc < 3) return -1; mnt_fs_set_target(fs, argv[1]); mnt_fs_set_options(fs, argv[2]); rc = update(NULL, fs, MS_REMOUNT); mnt_free_fs(fs); return rc; }
static int test_add(struct libmnt_test *ts, int argc, char *argv[]) { struct libmnt_fs *fs = mnt_new_fs(); int rc; if (argc < 5 || !fs) return -1; mnt_fs_set_source(fs, argv[1]); mnt_fs_set_target(fs, argv[2]); mnt_fs_set_fstype(fs, argv[3]); mnt_fs_set_options(fs, argv[4]); rc = update(NULL, fs, 0); mnt_free_fs(fs); return rc; }
static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *lc) { struct libmnt_table *tb = NULL; int rc = 0; struct libmnt_fs *fs; assert(upd); assert(upd->fs); DBG(UPDATE, mnt_debug_h(upd, "%s: modify options", upd->filename)); fs = upd->fs; if (lc) rc = mnt_lock_file(lc); if (rc) return rc; tb = __mnt_new_table_from_file(upd->filename, upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB); if (tb) { struct libmnt_fs *cur = mnt_table_find_target(tb, mnt_fs_get_target(fs), MNT_ITER_BACKWARD); if (cur) { if (upd->userspace_only) rc = mnt_fs_set_attributes(cur, mnt_fs_get_attributes(fs)); if (!rc) rc = mnt_fs_set_options(cur, mnt_fs_get_options(fs)); if (!rc) rc = update_table(upd, tb); } } if (lc) mnt_unlock_file(lc); mnt_free_table(tb); return rc; }
/* * Parses one line from {fs,m}tab */ static int mnt_parse_table_line(struct libmnt_fs *fs, char *s) { int rc, n = 0, xrc; char *src = NULL, *fstype = NULL, *optstr = NULL; rc = sscanf(s, UL_SCNsA" " /* (1) source */ UL_SCNsA" " /* (2) target */ UL_SCNsA" " /* (3) FS type */ UL_SCNsA" " /* (4) options */ "%n", /* byte count */ &src, &fs->target, &fstype, &optstr, &n); xrc = rc; if (rc == 3 || rc == 4) { /* options are optional */ unmangle_string(src); unmangle_string(fs->target); unmangle_string(fstype); if (optstr && *optstr) unmangle_string(optstr); /* note that __foo functions does not reallocate the string */ rc = __mnt_fs_set_source_ptr(fs, src); if (!rc) { src = NULL; rc = __mnt_fs_set_fstype_ptr(fs, fstype); if (!rc) fstype = NULL; } if (!rc && optstr) rc = mnt_fs_set_options(fs, optstr); free(optstr); optstr = NULL; } else { DBG(TAB, mnt_debug("tab parse error: [sscanf rc=%d]: '%s'", rc, s)); rc = -EINVAL; } if (rc) { free(src); free(fstype); free(optstr); DBG(TAB, mnt_debug("tab parse error: [set vars, rc=%d]\n", rc)); return rc; /* error */ } fs->passno = fs->freq = 0; if (xrc == 4 && n) s = skip_spaces(s + n); if (xrc == 4 && *s) { if (next_number(&s, &fs->freq) != 0) { if (*s) { DBG(TAB, mnt_debug("tab parse error: [freq]")); rc = -EINVAL; } } else if (next_number(&s, &fs->passno) != 0 && *s) { DBG(TAB, mnt_debug("tab parse error: [passno]")); rc = -EINVAL; } } 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; }
/* * Allocates utab entry (upd->fs) for mount/remount. This function should be * called *before* mount(2) syscall. The @fs is used as a read-only template. * * Returns: 0 on success, negative number on error, 1 if utabs update is * unnecessary. */ static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs, unsigned long mountflags) { int rc = 0; const char *o = NULL, *a = NULL; char *u = NULL; assert(fs); assert(upd); assert(upd->fs == NULL); assert(!(mountflags & MS_MOVE)); DBG(UPDATE, mnt_debug("prepare utab entry")); o = mnt_fs_get_user_options(fs); a = mnt_fs_get_attributes(fs); upd->fs = NULL; if (o) { /* remove non-mtab options */ rc = mnt_optstr_get_options(o, &u, mnt_get_builtin_optmap(MNT_USERSPACE_MAP), MNT_NOMTAB); if (rc) goto err; } if (!u && !a) { DBG(UPDATE, mnt_debug("utab entry unnecessary (no options)")); return 1; } /* allocate the entry */ upd->fs = mnt_copy_fs(NULL, fs); if (!upd->fs) { rc = -ENOMEM; goto err; } rc = mnt_fs_set_options(upd->fs, u); if (rc) goto err; rc = mnt_fs_set_attributes(upd->fs, a); if (rc) goto err; if (!(mountflags & MS_REMOUNT)) { rc = set_fs_root(upd, fs, mountflags); if (rc) goto err; } free(u); DBG(UPDATE, mnt_debug("utab entry OK")); return 0; err: free(u); mnt_free_fs(upd->fs); upd->fs = NULL; return rc; }