2 * mount_libmount.c -- Linux NFS [u]mount based on libmount
4 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
33 #include <libmount/libmount.h>
36 #include "mount_config.h"
38 #include "nfs_mount.h"
39 #include "nfs4_mount.h"
48 int nfs_mount_data_version;
54 #define FOREGROUND (0)
55 #define BACKGROUND (1)
58 * Store mount options to mtab (or /dev/.mount/utab), called from mount.nfs.
60 * Note that on systems without /etc/mtab the fs-specific options are not
61 * managed by libmount at all. We have to use "mount attributes" that are
62 * private for mount.<type> helpers.
64 static void store_mount_options(struct libmnt_fs *fs, const char *nfs_opts)
68 mnt_fs_set_attributes(fs, nfs_opts); /* for non-mtab systems */
70 /* for mtab create a new options list */
71 mnt_optstr_append_option(&o, mnt_fs_get_vfs_options(fs), NULL);
72 mnt_optstr_append_option(&o, nfs_opts, NULL);
73 mnt_optstr_append_option(&o, mnt_fs_get_user_options(fs), NULL);
75 mnt_fs_set_options(fs, o);
80 * Retrieve mount options from mtab (or /dev/.mount/utab) called from umount.nfs.
82 * The result can passed to free().
84 char *retrieve_mount_options(struct libmnt_fs *fs)
91 opts = mnt_fs_get_attributes(fs); /* /dev/.mount/utab */
95 return mnt_fs_strdup_options(fs); /* /etc/mtab */
98 static int try_mount(struct libmnt_context *cxt, int bg)
100 struct libmnt_fs *fs;
102 char *src = NULL, *tgt = NULL, *type = NULL, *opts = NULL;
103 unsigned long flags = 0;
106 fs = mnt_context_get_fs(cxt);
108 /* libmount returns read-only pointers (const char)
109 * so, reallocate for nfsmount() functions.
111 if ((p = mnt_fs_get_source(fs))) /* spec */
113 if ((p = mnt_fs_get_target(fs))) /* mountpoint */
115 if ((p = mnt_fs_get_fstype(fs))) /* FS type */
117 if ((p = mnt_fs_get_fs_options(fs))) /* mount options */
120 mnt_context_get_mflags(cxt, &flags); /* mount(2) flags */
121 fake = mnt_context_is_fake(cxt);
124 ret = nfsmount_string(src, tgt, type, flags, &opts, fake, bg);
126 else if (strcmp(type, "nfs4") == 0)
127 ret = nfs4mount(src, tgt, flags, &opts, fake, bg);
129 ret = nfsmount(src, tgt, flags, &opts, fake, bg);
131 /* Store mount options if not called with mount --no-mtab */
132 if (!ret && !mnt_context_is_nomtab(cxt))
133 store_mount_options(fs, opts);
143 /* returns: error = -1, success = 1 , not vers4 == 0 */
144 static int is_vers4(struct libmnt_context *cxt)
146 struct libmnt_fs *fs = mnt_context_get_fs(cxt);
147 struct libmnt_table *tb = NULL;
148 const char *src = mnt_context_get_source(cxt),
149 *tgt = mnt_context_get_target(cxt);
155 if (!mnt_fs_is_kernel(fs)) {
156 struct libmnt_table *tb = mnt_new_table_from_file("/proc/mounts");
160 fs = mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD);
164 const char *type = mnt_fs_get_fstype(fs);
165 if (type && strcmp(type, "nfs4") == 0)
172 static int umount_main(struct libmnt_context *cxt, int argc, char **argv)
175 char *spec = NULL, *opts = NULL;
178 static const struct option longopts[] = {
179 { "force", 0, 0, 'f' },
180 { "help", 0, 0, 'h' },
181 { "no-mtab", 0, 0, 'n' },
182 { "verbose", 0, 0, 'v' },
183 { "read-only", 0, 0, 'r' },
184 { "lazy", 0, 0, 'l' },
185 { "types", 1, 0, 't' },
189 mnt_context_init_helper(cxt, MNT_ACT_UMOUNT, 0);
191 while ((c = getopt_long (argc, argv, "fvnrlh", longopts, NULL)) != -1) {
193 rc = mnt_context_helper_setopt(cxt, c, optarg);
194 if (rc == 0) /* valid option */
196 if (rc < 0) /* error (probably ENOMEM) */
198 /* rc==1 means unknow option */
204 spec = argv[optind++];
206 if (!spec || (*spec != '/' && strchr(spec,':') == NULL)) {
207 nfs_error(_("%s: no mount point provided"), progname);
211 if (mnt_context_set_target(cxt, spec))
214 /* read mtab/fstab, evaluate permissions, etc. */
215 rc = mnt_context_prepare_umount(cxt);
217 nfs_error(_("%s: failed to prepare umount: %s\n"),
218 progname, strerror(-rc));
222 if (mnt_context_get_fstype(cxt) &&
223 !mnt_match_fstype(mnt_context_get_fstype(cxt), "nfs,nfs4")) {
225 nfs_error(_("%s: %s: is not an NFS filesystem"), progname, spec);
230 opts = retrieve_mount_options(mnt_context_get_fs(cxt));
232 if (!mnt_context_is_lazy(cxt)) {
234 /* we have full FS description (e.g. from mtab or /proc) */
235 switch (is_vers4(cxt)) {
237 /* We ignore the error from nfs_umount23.
238 * If the actual umount succeeds (in del_mtab),
239 * we don't want to signal an error, as that
240 * could cause /sbin/mount to retry!
242 nfs_umount23(mnt_context_get_source(cxt), opts);
244 case 1: /* unknown */
250 /* strange, no entry in mtab or /proc not mounted */
251 nfs_umount23(spec, "tcp,v3");
255 rc = mnt_context_do_umount(cxt); /* call umount(2) syscall */
256 mnt_context_finalize_mount(cxt); /* mtab update */
258 if (rc && !mnt_context_get_status(cxt)) {
259 /* mnt_context_do_umount() returns errno if umount(2) failed */
260 umount_error(rc, spec);
269 static int mount_main(struct libmnt_context *cxt, int argc, char **argv)
272 struct libmnt_fs *fs;
273 char *spec = NULL, *mount_point = NULL, *opts = NULL;
275 static const struct option longopts[] = {
276 { "fake", 0, 0, 'f' },
277 { "help", 0, 0, 'h' },
278 { "no-mtab", 0, 0, 'n' },
279 { "read-only", 0, 0, 'r' },
281 { "verbose", 0, 0, 'v' },
282 { "version", 0, 0, 'V' },
283 { "read-write", 0, 0, 'w' },
285 { "options", 1, 0, 'o' },
286 { "sloppy", 0, 0, 's' },
290 mount_config_init(progname);
291 mnt_context_init_helper(cxt, MNT_ACT_MOUNT, 0);
293 while ((c = getopt_long(argc, argv, "fhnrVvwo:s", longopts, NULL)) != -1) {
295 rc = mnt_context_helper_setopt(cxt, c, optarg);
296 if (rc == 0) /* valid option */
298 if (rc < 0) /* error (probably ENOMEM) */
300 /* rc==1 means unknow option */
303 printf("%s: ("PACKAGE_STRING")\n", progname);
313 spec = argv[optind++];
315 mount_point = argv[optind++];
318 nfs_error(_("%s: no mount point provided"), progname);
322 nfs_error(_("%s: no mount spec provided"), progname);
326 if (geteuid() != 0) {
327 nfs_error(_("%s: not installed setuid - "
328 "\"user\" NFS mounts not supported."), progname);
332 verbose = mnt_context_is_verbose(cxt);
333 sloppy = mnt_context_is_sloppy(cxt);
334 nomtab = mnt_context_is_nomtab(cxt);
336 if (strcmp(progname, "mount.nfs4") == 0)
337 mnt_context_set_fstype(cxt, "nfs4");
339 mnt_context_set_fstype(cxt, "nfs"); /* default */
341 rc = mnt_context_set_source(cxt, spec);
343 mnt_context_set_target(cxt, mount_point);
345 nfs_error(_("%s: failed to set spec or mountpoint: %s"),
346 progname, strerror(errno));
350 mount_point = mnt_resolve_path(mount_point,
351 mnt_context_get_cache(cxt));
353 if (chk_mountpoint(mount_point))
357 * The libmount strictly uses only options from fstab if running in
358 * restricted mode (suid, non-root user). This is done in
359 * mnt_context_prepare_mount() by default.
361 * We have to read fstab before nfsmount.conf, otherwise the options
362 * from nfsmount.conf will be ignored (overwrited).
364 rc = mnt_context_apply_fstab(cxt);
366 nfs_error(_("%s: failed to apply fstab options\n"), progname);
371 * Concatenate mount options from the configuration file
373 fs = mnt_context_get_fs(cxt);
375 opts = mnt_fs_strdup_options(fs);
377 opts = mount_config_opts(spec, mount_point, opts);
378 mnt_fs_set_options(fs, opts);
381 rc = mnt_context_prepare_mount(cxt);
383 nfs_error(_("%s: failed to prepare mount: %s\n"),
384 progname, strerror(-rc));
388 rc = try_mount(cxt, FOREGROUND);
391 printf(_("%s: backgrounding \"%s\"\n"),
392 progname, mnt_context_get_source(cxt));
393 printf(_("%s: mount options: \"%s\"\n"),
399 nfs_error(_("%s: failed to start "
400 "background process: %s\n"),
401 progname, strerror(errno));
405 rc = try_mount(cxt, BACKGROUND);
408 printf(_("%s: giving up \"%s\"\n"),
409 progname, mnt_context_get_source(cxt));
412 mnt_context_set_syscall_status(cxt, rc == EX_SUCCESS ? 0 : -1);
413 mnt_context_finalize_mount(cxt); /* mtab update */
419 int main(int argc, char *argv[])
421 struct libmnt_context *cxt;
425 cxt = mnt_new_context();
427 nfs_error(_("Can't initilize libmount: %s"),
433 progname = basename(argv[0]);
434 nfs_mount_data_version = discover_nfs_mount_data_version(&string);
436 if(strncmp(progname, "umount", 6) == 0)
437 rc = umount_main(cxt, argc, argv);
439 rc = mount_main(cxt, argc, argv);
441 mnt_free_context(cxt);