summaryrefslogtreecommitdiffstats
path: root/libmount
diff options
context:
space:
mode:
Diffstat (limited to 'libmount')
-rw-r--r--libmount/docs/libmount-sections.txt14
-rw-r--r--libmount/src/context.c144
-rw-r--r--libmount/src/context_mount.c358
-rw-r--r--libmount/src/context_umount.c80
-rw-r--r--libmount/src/libmount.h.in78
-rw-r--r--libmount/src/libmount.sym7
-rw-r--r--libmount/src/mountP.h20
7 files changed, 698 insertions, 3 deletions
diff --git a/libmount/docs/libmount-sections.txt b/libmount/docs/libmount-sections.txt
index 78d89cae7..9c6ff2463 100644
--- a/libmount/docs/libmount-sections.txt
+++ b/libmount/docs/libmount-sections.txt
@@ -35,9 +35,12 @@ mnt_context_enable_fork
mnt_context_enable_lazy
mnt_context_enable_loopdel
mnt_context_enable_rdonly_umount
+mnt_context_enable_rwonly_mount
mnt_context_enable_sloppy
mnt_context_enable_verbose
+mnt_context_forced_rdonly
mnt_context_get_cache
+mnt_context_get_excode
mnt_context_get_fs
mnt_context_get_fstab
mnt_context_get_fstab_userdata
@@ -72,6 +75,7 @@ mnt_context_is_nomtab
mnt_context_is_parent
mnt_context_is_rdonly_umount
mnt_context_is_restricted
+mnt_context_is_rwonly_mount
mnt_context_is_sloppy
mnt_context_is_swapmatch
mnt_context_is_verbose
@@ -105,6 +109,15 @@ MNT_ERR_NOFSTAB
MNT_ERR_NOFSTYPE
MNT_ERR_NOSOURCE
MNT_ERR_LOOPOVERLAP
+<SUBSECTION>
+MNT_EX_SUCCESS
+MNT_EX_USAGE
+MNT_EX_SYSERR
+MNT_EX_SOFTWARE
+MNT_EX_USER
+MNT_EX_FILEIO
+MNT_EX_FAIL
+MNT_EX_SOMEOK
</SECTION>
<SECTION>
@@ -130,6 +143,7 @@ MNT_MS_UHELPER
MNT_MS_USER
MNT_MS_USERS
MNT_MS_XCOMMENT
+MNT_MS_XFSTABCOMM
<SUBSECTION>
MS_BIND
MS_DIRSYNC
diff --git a/libmount/src/context.c b/libmount/src/context.c
index e731749b4..38e036330 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -172,8 +172,10 @@ int mnt_reset_context(struct libmnt_context *cxt)
cxt->flags |= (fl & MNT_FL_FORCE);
cxt->flags |= (fl & MNT_FL_NOCANONICALIZE);
cxt->flags |= (fl & MNT_FL_RDONLY_UMOUNT);
+ cxt->flags |= (fl & MNT_FL_RWONLY_MOUNT);
cxt->flags |= (fl & MNT_FL_NOSWAPMATCH);
cxt->flags |= (fl & MNT_FL_TABPATHS_CHECKED);
+
return 0;
}
@@ -478,6 +480,48 @@ int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
}
/**
+ * mnt_context_enable_rwonly_mount:
+ * @cxt: mount context
+ * @enable: TRUE or FALSE
+ *
+ * Force read-write mount; if enabled libmount will never try MS_RDONLY
+ * after failed mount(2) EROFS. (See mount(8) man page, option -w).
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
+int mnt_context_enable_rwonly_mount(struct libmnt_context *cxt, int enable)
+{
+ return set_flag(cxt, MNT_FL_RWONLY_MOUNT, enable);
+}
+
+/**
+ * mnt_context_is_rwonly_mount
+ * @cxt: mount context
+ *
+ * See also mnt_context_enable_rwonly_mount() and mount(8) man page,
+ * option -w.
+ *
+ * Returns: 1 if only read-write mount is allowed.
+ */
+int mnt_context_is_rwonly_mount(struct libmnt_context *cxt)
+{
+ return cxt->flags & MNT_FL_RWONLY_MOUNT ? 1 : 0;
+}
+
+/**
+ * mnt_context_forced_rdonly:
+ * @cxt: mount context
+ *
+ * See also mnt_context_enable_rwonly_mount().
+ *
+ * Returns: 1 if mounted read-only on write-protected device.
+ */
+int mnt_context_forced_rdonly(struct libmnt_context *cxt)
+{
+ return cxt->flags & MNT_FL_FORCED_RDONLY ? 1 : 0;
+}
+
+/**
* mnt_context_disable_helpers:
* @cxt: mount context
* @disable: TRUE or FALSE
@@ -2002,8 +2046,10 @@ int mnt_context_apply_fstab(struct libmnt_context *cxt)
if (!cxt || !cxt->fs)
return -EINVAL;
- if (mnt_context_tab_applied(cxt)) /* already applied */
+ if (mnt_context_tab_applied(cxt)) { /* already applied */
+ DBG(CXT, ul_debugobj(cxt, "fstab already applied -- skip"));
return 0;
+ }
if (mnt_context_is_restricted(cxt)) {
DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
@@ -2216,7 +2262,7 @@ int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
* @buf: buffer
* @bufsiz: size of the buffer
*
- * Not implemented yet.
+ * Not implemented, deprecated in favor or mnt_context_get_excode().
*
* Returns: 0 or negative number in case of error.
*/
@@ -2228,6 +2274,100 @@ int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
return 0;
}
+
+int mnt_context_get_generic_excode(int rc, char *buf, size_t bufsz, char *fmt, ...)
+{
+ va_list va;
+
+ if (rc == 0)
+ return MNT_EX_SUCCESS;
+
+ va_start(va, fmt);
+
+ /* we need to support "%m" */
+ errno = rc < 0 ? -rc : rc;
+
+ if (buf)
+ vsnprintf(buf, bufsz, fmt, va);
+
+ switch (errno) {
+ case EINVAL:
+ case EPERM:
+ rc = MNT_EX_USAGE;
+ break;
+ case ENOMEM:
+ rc = MNT_EX_SYSERR;
+ break;
+ default:
+ rc = MNT_EX_FAIL;
+ break;
+ }
+ va_end(va);
+ return rc;
+}
+
+/**
+ * mnt_context_get_excode:
+ * @cxt: context
+ * @rc: return code of the previous operation
+ * @buf: buffer to print error message (optional)
+ * @bufsz: size of the buffer
+ *
+ * This function analyzes context, [u]mount syscall and external helper status
+ * and @mntrc and generates unified return code (see MNT_EX_*) as expected
+ * from mount(8) or umount(8).
+ *
+ * If the external helper (e.g. /sbin/mount.type) has been executed than it
+ * returns status from wait() of the helper. It's not libmount fail if helper
+ * returns some crazy undocumented codes... See mnt_context_helper_executed()
+ * and mnt_context_get_helper_status(). Note that mount(8) and umount(8) utils
+ * always return code from helper without extra care about it.
+ *
+ * If the argument @buf is not NULL then error message is generated (if
+ * anything failed).
+ *
+ * The @mntrc is usually return code from mnt_context_mount(),
+ * mnt_context_umount(), or 'mntrc' as returned by mnt_context_next_mount().
+ *
+ * Returns: MNT_EX_* codes.
+ */
+int mnt_context_get_excode(
+ struct libmnt_context *cxt,
+ int rc,
+ char *buf,
+ size_t bufsz)
+{
+ if (buf) {
+ *buf = '\0'; /* for sure */
+
+ if (!cxt->enabled_textdomain) {
+ bindtextdomain(LIBMOUNT_TEXTDOMAIN, LOCALEDIR);
+ cxt->enabled_textdomain = 1;
+ }
+ }
+
+ switch (cxt->action) {
+ case MNT_ACT_MOUNT:
+ rc = mnt_context_get_mount_excode(cxt, rc, buf, bufsz);
+ break;
+ case MNT_ACT_UMOUNT:
+ rc = mnt_context_get_umount_excode(cxt, rc, buf, bufsz);
+ break;
+ default:
+ if (rc)
+ rc = mnt_context_get_generic_excode(rc, buf, bufsz,
+ _("operation failed: %m"));
+ else
+ rc = MNT_EX_SUCCESS;
+ break;
+ }
+
+ DBG(CXT, ul_debugobj(cxt, "excode: rc=%d message=\"%s\"", rc,
+ buf ? buf : "<no-message>"));
+ return rc;
+}
+
+
/**
* mnt_context_init_helper
* @cxt: mount context
diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
index 6368e9ba8..9caee70e5 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -1083,6 +1083,7 @@ int mnt_context_mount(struct libmnt_context *cxt)
assert(cxt->helper_exec_status == 1);
assert(cxt->syscall_status == 1);
+again:
rc = mnt_context_prepare_mount(cxt);
if (!rc)
rc = mnt_context_prepare_update(cxt);
@@ -1090,6 +1091,32 @@ int mnt_context_mount(struct libmnt_context *cxt)
rc = mnt_context_do_mount(cxt);
if (!rc)
rc = mnt_context_update_tabs(cxt);
+
+ /*
+ * Read-only device; try mount filesystem read-only
+ */
+ if ((rc == -EROFS && !mnt_context_syscall_called(cxt)) /* before syscall; rdonly loopdev */
+ || mnt_context_get_syscall_errno(cxt) == EROFS /* syscall failed with EROFS */
+ || mnt_context_get_syscall_errno(cxt) == EACCES) /* syscall failed with EACCES */
+ {
+ unsigned long mflags = 0;
+
+ mnt_context_get_mflags(cxt, &mflags);
+
+ if (!(mflags & MS_RDONLY) /* not yet RDONLY */
+ && !(mflags & MS_REMOUNT) /* not remount */
+ && !(mflags & MS_BIND) /* not bin mount */
+ && !mnt_context_is_rwonly_mount(cxt)) { /* no explicit read-write */
+
+ assert(!(cxt->flags & MNT_FL_FORCED_RDONLY));
+ DBG(CXT, ul_debugobj(cxt, "write-protected source, trying RDONLY."));
+
+ mnt_context_reset_status(cxt);
+ mnt_context_set_mflags(cxt, mflags | MS_RDONLY);
+ cxt->flags |= MNT_FL_FORCED_RDONLY;
+ goto again;
+ }
+ }
return rc;
}
@@ -1222,3 +1249,334 @@ int mnt_context_next_mount(struct libmnt_context *cxt,
return 0;
}
+/*
+ * Returns 1 if @dir parent is shared
+ */
+static int is_shared_tree(struct libmnt_context *cxt, const char *dir)
+{
+ struct libmnt_table *tb = NULL;
+ struct libmnt_fs *fs;
+ unsigned long mflags = 0;
+ char *mnt = NULL, *p;
+ int rc = 0;
+
+ if (!dir)
+ return 0;
+ if (mnt_context_get_mtab(cxt, &tb) || !tb)
+ goto done;
+
+ mnt = strdup(dir);
+ if (!mnt)
+ goto done;
+ p = strrchr(mnt, '/');
+ if (!p)
+ goto done;
+ if (p > mnt)
+ *p = '\0';
+ fs = mnt_table_find_mountpoint(tb, mnt, MNT_ITER_BACKWARD);
+
+ rc = fs && mnt_fs_is_kernel(fs)
+ && mnt_fs_get_propagation(fs, &mflags) == 0
+ && (mflags & MS_SHARED);
+done:
+ free(mnt);
+ return rc;
+}
+
+int mnt_context_get_mount_excode(
+ struct libmnt_context *cxt,
+ int rc,
+ char *buf,
+ size_t bufsz)
+{
+ int syserr;
+ struct stat st;
+ unsigned long uflags = 0, mflags = 0;
+
+ int restricted = mnt_context_is_restricted(cxt);
+ const char *tgt = mnt_context_get_target(cxt);
+ const char *src = mnt_context_get_source(cxt);
+
+ if (mnt_context_helper_executed(cxt)) {
+ /*
+ * /sbin/mount.<type> called, return status
+ */
+ if (rc == -MNT_ERR_APPLYFLAGS && buf)
+ snprintf(buf, bufsz, _("WARNING: failed to apply propagation flags"));
+
+ return mnt_context_get_helper_status(cxt);
+ }
+
+ if (rc == 0 && mnt_context_get_status(cxt) == 1) {
+ /*
+ * Libmount success && syscall success.
+ */
+ if (buf && mnt_context_forced_rdonly(cxt))
+ snprintf(buf, bufsz, _("WARNING: device write-protected, mounted read-only"));
+ return MNT_EX_SUCCESS;
+ }
+
+ mnt_context_get_mflags(cxt, &mflags); /* mount(2) flags */
+ mnt_context_get_user_mflags(cxt, &uflags); /* userspace flags */
+
+ if (!mnt_context_syscall_called(cxt)) {
+ /*
+ * libmount errors (extra library checks)
+ */
+ switch (rc) {
+ case -EPERM:
+ if (buf)
+ snprintf(buf, bufsz, _("operation permitted for root only"));
+ return MNT_EX_USAGE;
+ case -EBUSY:
+ if (buf)
+ snprintf(buf, bufsz, _("%s is already mounted"), src);
+ return MNT_EX_USAGE;
+ case -MNT_ERR_NOFSTAB:
+ if (!buf)
+ return MNT_EX_USAGE;
+ if (mnt_context_is_swapmatch(cxt))
+ snprintf(buf, bufsz, _("can't find in %s"),
+ mnt_get_fstab_path());
+ else if (tgt)
+ snprintf(buf, bufsz, _("can't find mount point in %s"),
+ mnt_get_fstab_path());
+ else if (src)
+ snprintf(buf, bufsz, _("can't find mount source %s in %s"),
+ src, mnt_get_fstab_path());
+ return MNT_EX_USAGE;
+ case -MNT_ERR_AMBIFS:
+ if (buf)
+ snprintf(buf, bufsz, _("more filesystems detected on %s; use -t <type> or wipefs(8)"), src);
+ return MNT_EX_USAGE;
+ case -MNT_ERR_NOFSTYPE:
+ if (buf)
+ snprintf(buf, bufsz, restricted ?
+ _("failed to determine filesystem type") :
+ _("no filesystem type specified"));
+ return MNT_EX_USAGE;
+ case -MNT_ERR_NOSOURCE:
+ if (uflags & MNT_MS_NOFAIL)
+ return MNT_EX_SUCCESS;
+ if (buf) {
+ if (src)
+ snprintf(buf, bufsz, _("can't find %s"), src);
+ else
+ snprintf(buf, bufsz, _("no mount source specified"));
+ }
+ return MNT_EX_USAGE;
+ case -MNT_ERR_MOUNTOPT:
+ if (buf)
+ snprintf(buf, bufsz, errno ?
+ _("failed to parse mount options: %m") :
+ _("failed to parse mount options"));
+ return MNT_EX_USAGE;
+ case -MNT_ERR_LOOPDEV:
+ if (buf)
+ snprintf(buf, bufsz, _("failed to setup loop device for %s"), src);
+ return MNT_EX_FAIL;
+ case -MNT_ERR_LOOPOVERLAP:
+ if (buf)
+ snprintf(buf, bufsz, _("overlapping loop device exists for %s"), src);
+ return MNT_EX_FAIL;
+ default:
+ return mnt_context_get_generic_excode(rc, buf, bufsz, _("mount failed: %m"));
+ }
+
+ } else if (mnt_context_get_syscall_errno(cxt) == 0) {
+ /*
+ * mount(2) syscall success, but something else failed
+ * (probably error in mtab processing).
+ */
+ if (rc < 0)
+ return mnt_context_get_generic_excode(rc, buf, bufsz,
+ _("filesystem was mounted, but any subsequent operation failed: %m"));
+
+ return MNT_EX_SOFTWARE; /* internal error */
+
+ }
+
+ /*
+ * mount(2) errors
+ */
+ syserr = mnt_context_get_syscall_errno(cxt);
+
+
+ switch(syserr) {
+ case EPERM:
+ if (!buf)
+ break;
+ if (geteuid() == 0) {
+ if (stat(tgt, &st) || !S_ISDIR(st.st_mode))
+ snprintf(buf, bufsz, _("mount point is not a directory"));
+ else
+ snprintf(buf, bufsz, _("permission denied"));
+ } else
+ snprintf(buf, bufsz, _("must be superuser to use mount"));
+ break;
+
+ case EBUSY:
+ {
+ struct libmnt_table *tb;
+
+ if (!buf)
+ break;
+ if (mflags & MS_REMOUNT) {
+ snprintf(buf, bufsz, _("mount point is busy"));
+ break;
+ }
+ if (src && mnt_context_get_mtab(cxt, &tb) == 0) {
+ struct libmnt_iter itr;
+ struct libmnt_fs *fs;
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
+ const char *s = mnt_fs_get_srcpath(fs),
+ *t = mnt_fs_get_target(fs);
+
+ if (t && s && mnt_fs_streq_srcpath(fs, src)) {
+ snprintf(buf, bufsz, _("%s already mounted on %s"), s, t);
+ break;
+ }
+ }
+ }
+ if (!*buf)
+ snprintf(buf, bufsz, _("%s already mounted or mount point busy"), src);
+ break;
+ }
+ case ENOENT:
+ if (tgt && lstat(tgt, &st)) {
+ if (buf)
+ snprintf(buf, bufsz, _("mount point does not exist"));
+ } else if (tgt && stat(tgt, &st)) {
+ if (buf)
+ snprintf(buf, bufsz, _("mount point is a symbolic link to nowhere"));
+ } else if (src && stat(src, &st)) {
+ if (uflags & MNT_MS_NOFAIL)
+ return MNT_EX_SUCCESS;
+ if (buf)
+ snprintf(buf, bufsz, _("special device %s does not exist"), src);
+ } else if (buf) {
+ errno = syserr;
+ snprintf(buf, bufsz, _("mount(2) system call failed: %m"));
+ }
+ break;
+
+ case ENOTDIR:
+ if (stat(tgt, &st) || ! S_ISDIR(st.st_mode)) {
+ if (buf)
+ snprintf(buf, bufsz, _("mount point is not a directory"));
+ } else if (src && stat(src, &st) && errno == ENOTDIR) {
+ if (uflags & MNT_MS_NOFAIL)
+ return MNT_EX_SUCCESS;
+ if (buf)
+ snprintf(buf, bufsz, _("special device %s does not exist "
+ "(a path prefix is not a directory)"), src);
+ } else if (buf) {
+ errno = syserr;
+ snprintf(buf, bufsz, _("mount(2) system call failed: %m"));
+ }
+ break;
+
+ case EINVAL:
+ if (!buf)
+ break;
+ if (mflags & MS_REMOUNT)
+ snprintf(buf, bufsz, _("mount point not mounted or bad option"));
+ else if (rc == -MNT_ERR_APPLYFLAGS)
+ snprintf(buf, bufsz, _("not mount point or bad option"));
+ else if ((mflags & MS_MOVE) && is_shared_tree(cxt, src))
+ snprintf(buf, bufsz,
+ _("bad option; moving a mount "
+ "residing under a shared mount is unsupported"));
+ else if (mnt_fs_is_netfs(mnt_context_get_fs(cxt)))
+ snprintf(buf, bufsz,
+ _("bad option; for several filesystems (e.g. nfs, cifs) "
+ "you might need a /sbin/mount.<type> helper program"));
+ else
+ snprintf(buf, bufsz,
+ _("wrong fs type, bad option, bad superblock on %s, "
+ "missing codepage or helper program, or other error"),
+ src);
+ break;
+
+ case EMFILE:
+ if (buf)
+ snprintf(buf, bufsz, _("mount table full"));
+ break;
+
+ case EIO:
+ if (buf)
+ snprintf(buf, bufsz, _("can't read superblock on %s"), src);
+ break;
+
+ case ENODEV:
+ if (!buf)
+ break;
+ if (mnt_context_get_fstype(cxt))
+ snprintf(buf, bufsz, _("unknown filesystem type '%s'"),
+ mnt_context_get_fstype(cxt));
+ else
+ snprintf(buf, bufsz, _("unknown filesystem type"));
+ break;
+
+ case ENOTBLK:
+ if (uflags & MNT_MS_NOFAIL)
+ return MNT_EX_SUCCESS;
+ if (!buf)
+ break;
+ if (stat(src, &st))
+ snprintf(buf, bufsz, _("%s is not a block device, and stat(2) fails?"), src);
+ else if (S_ISBLK(st.st_mode))
+ snprintf(buf, bufsz,
+ _("the kernel does not recognize %s as a block device; "
+ "maybe \"modprobe driver\" is necessary"), src);
+ else if (S_ISREG(st.st_mode))
+ snprintf(buf, bufsz, _("%s is not a block device; try \"-o loop\""), src);
+ else
+ snprintf(buf, bufsz, _("%s is not a block device"), src);
+ break;
+
+ case ENXIO:
+ if (uflags & MNT_MS_NOFAIL)
+ return MNT_EX_SUCCESS;
+ if (buf)
+ snprintf(buf, bufsz, _("%s is not a valid block device"), src);
+ break;
+
+ case EACCES:
+ case EROFS:
+ if (!buf)
+ break;
+ if (mflags & MS_RDONLY)
+ snprintf(buf, bufsz, _("cannot mount %s read-only"), src);
+ else if (mnt_context_is_rwonly_mount(cxt))
+ snprintf(buf, bufsz, _("%s is write-protected but explicit read-write mode requested"), src);
+ else if (mflags & MS_REMOUNT)
+ snprintf(buf, bufsz, _("cannot remount %s read-write, is write-protected"), src);
+ else if (mflags & MS_BIND)
+ snprintf(buf, bufsz, _("bind %s failed"), src);
+ else {
+ errno = syserr;
+ snprintf(buf, bufsz, _("mount(2) system call failed: %m"));
+ }
+ break;
+
+ case ENOMEDIUM:
+ if (uflags & MNT_MS_NOFAIL)
+ return MNT_EX_SUCCESS;
+ if (buf)
+ snprintf(buf, bufsz, _("no medium found on %s"), src);
+ break;
+
+ default:
+ if (buf) {
+ errno = syserr;
+ snprintf(buf, bufsz, _("mount(2) system call failed: %m"));
+ }
+ break;
+ }
+
+ return MNT_EX_FAIL;
+}
+
diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c
index 28787dab1..a2bba8060 100644
--- a/libmount/src/context_umount.c
+++ b/libmount/src/context_umount.c
@@ -1016,3 +1016,83 @@ int mnt_context_next_umount(struct libmnt_context *cxt,
*mntrc = rc;
return 0;
}
+
+
+int mnt_context_get_umount_excode(
+ struct libmnt_context *cxt,
+ int rc,
+ char *buf,
+ size_t bufsz)
+{
+ if (mnt_context_helper_executed(cxt))
+ /*
+ * /sbin/umount.<type> called, return status
+ */
+ return mnt_context_get_helper_status(cxt);
+
+ if (rc == 0 && mnt_context_get_status(cxt) == 1)
+ /*
+ * Libmount success && syscall success.
+ */
+ return MNT_EX_SUCCESS;
+
+ if (!mnt_context_syscall_called(cxt)) {
+ /*
+ * libmount errors (extra library checks)
+ */
+ if (rc == -EPERM && !mnt_context_tab_applied(cxt)) {
+ /* failed to evaluate permissions because not found
+ * relevant entry in mtab */
+ if (buf)
+ snprintf(buf, bufsz, _("not mounted"));
+ return MNT_EX_USAGE;
+ }
+ return mnt_context_get_generic_excode(rc, buf, bufsz,
+ _("umount failed: %m"));
+
+ } else if (mnt_context_get_syscall_errno(cxt) == 0) {
+ /*
+ * umount(2) syscall success, but something else failed
+ * (probably error in mtab processing).
+ */
+ if (rc < 0)
+ return mnt_context_get_generic_excode(rc, buf, bufsz,
+ _("filesystem was unmounted, but any subsequent operation failed: %m"));
+
+ return MNT_EX_SOFTWARE; /* internal error */
+ }
+
+ /*
+ * umount(2) errors
+ */
+ if (buf) {
+ int syserr = mnt_context_get_syscall_errno(cxt);
+
+ switch (syserr) {
+ case ENXIO:
+ snprintf(buf, bufsz, _("invalid block device")); /* ??? */
+ break;
+ case EINVAL:
+ snprintf(buf, bufsz, _("not mounted"));
+ break;
+ case EIO:
+ snprintf(buf, bufsz, _("can't write superblock"));
+ break;
+ case EBUSY:
+ snprintf(buf, bufsz, _("target is busy"));
+ break;
+ case ENOENT:
+ snprintf(buf, bufsz, _("no mount point specified"));
+ break;
+ case EPERM:
+ snprintf(buf, bufsz, _("must be superuser to unmount"));
+ break;
+ case EACCES:
+ snprintf(buf, bufsz, _("block devices are not permitted on filesystem"));
+ break;
+ default:
+ return mnt_context_get_generic_excode(syserr, buf, bufsz,_("umount(2) system call failed: %m"));
+ }
+ }
+ return MNT_EX_FAIL;
+}
diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in
index f191a52fe..123145fc4 100644
--- a/libmount/src/libmount.h.in
+++ b/libmount/src/libmount.h.in
@@ -185,6 +185,72 @@ enum {
*/
#define MNT_ERR_LOOPOVERLAP 5007
+
+/*
+ * Overall return codes -- based on mount(8) and umount(8) return codes.
+ * See mnt_context_get_excode() for more details.
+ */
+
+/**
+ * MNT_EX_SUCCESS:
+ *
+ * [u]mount(8) exit code: no errors
+ */
+#define MNT_EX_SUCCESS 0
+
+/**
+ * MNT_EX_USAGE:
+ *
+ * [u]mount(8) exit code: incorrect invocation or permission
+ */
+#define MNT_EX_USAGE 1
+
+/**
+ * MNT_EX_SYSERR:
+ *
+ * [u]mount(8) exit code: out of memory, cannot fork, ...
+ */
+
+#define MNT_EX_SYSERR 2
+
+/**
+ * MNT_EX_SOFTWARE:
+ *
+ * [u]mount(8) exit code: internal mount bug or wrong version
+ */
+#define MNT_EX_SOFTWARE 4
+
+/**
+ * MNT_EX_USER:
+ *
+ * [u]mount(8) exit code: user interrupt
+ */
+#define MNT_EX_USER 8
+
+/**
+ * MNT_EX_FILEIO:
+ *
+ * [u]mount(8) exit code: problems writing, locking, ... mtab/fstab
+ */
+#define MNT_EX_FILEIO 16
+
+/**
+ * MNT_EX_FAIL:
+ *
+ * [u]mount(8) exit code: mount failure
+ */
+#define MNT_EX_FAIL 32
+
+/**
+ * MNT_EX_SOMEOK:
+ *
+ * [u]mount(8) exit code: some mount succeeded; usually when executed with
+ * --all options. Never returned by libmount.
+ */
+#define MNT_EX_SOMEOK 64
+
+
+
#ifndef __GNUC_PREREQ
# if defined __GNUC__ && defined __GNUC_MINOR__
# define __GNUC_PREREQ(maj, min) ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
@@ -610,6 +676,7 @@ extern int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode);
extern int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable);
extern int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable);
extern int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable);
+extern int mnt_context_enable_rwonly_mount(struct libmnt_context *cxt, int enable);
extern int mnt_context_disable_helpers(struct libmnt_context *cxt, int disable);
extern int mnt_context_enable_sloppy(struct libmnt_context *cxt, int enable);
extern int mnt_context_enable_fake(struct libmnt_context *cxt, int enable);
@@ -626,6 +693,8 @@ extern int mnt_context_is_lazy(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
extern int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
+extern int mnt_context_is_rwonly_mount(struct libmnt_context *cxt)
+ __ul_attribute__((nonnull));
extern int mnt_context_is_sloppy(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
extern int mnt_context_is_fake(struct libmnt_context *cxt)
@@ -644,6 +713,8 @@ extern int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
extern int mnt_context_is_swapmatch(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
+extern int mnt_context_forced_rdonly(struct libmnt_context *cxt)
+ __ul_attribute__((nonnull));
extern int mnt_context_is_fork(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
@@ -724,7 +795,12 @@ extern int mnt_context_syscall_called(struct libmnt_context *cxt);
extern int mnt_context_get_syscall_errno(struct libmnt_context *cxt);
extern int mnt_context_strerror(struct libmnt_context *cxt, char *buf,
- size_t bufsiz);
+ size_t bufsiz)
+ __ul_attribute__((deprecated));
+
+extern int mnt_context_get_excode(struct libmnt_context *cxt,
+ int rc, char *buf, size_t bufsz);
+
/* context_mount.c */
extern int mnt_context_mount(struct libmnt_context *cxt);
diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym
index f0210c240..ca16cafa1 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -315,3 +315,10 @@ MOUNT_2.28 {
mnt_table_find_target_with_option;
mnt_fs_set_priority;
} MOUNT_2.26;
+
+MOUNT_2.30 {
+ mnt_context_is_rwonly_mount;
+ mnt_context_forced_rdonly;
+ mnt_context_enable_rwonly_mount;
+ mnt_context_get_excode;
+} MOUNT_2.28;
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index 2baab55de..e01de337d 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -50,6 +50,18 @@ UL_DEBUG_DECLARE_MASK(libmount);
#define ON_DBG(m, x) __UL_DBG_CALL(libmount, MNT_DEBUG_, m, x)
#define DBG_FLUSH __UL_DBG_FLUSH(libmount, MNT_DEBUG_)
+/*
+ * NLS -- the library has to be independent on main program, so define
+ * UL_TEXTDOMAIN_EXPLICIT before you include nls.h.
+ *
+ * Now we use util-linux.po (=PACKAGE), rather than maintain the texts
+ * in the separate libmount.po file.
+ */
+#define LIBMOUNT_TEXTDOMAIN PACKAGE
+#define UL_TEXTDOMAIN_EXPLICIT LIBMOUNT_TEXTDOMAIN
+#include "nls.h"
+
+
/* extension for files in the directory */
#define MNT_MNTTABDIR_EXT ".fstab"
@@ -313,6 +325,8 @@ struct libmnt_context
int syscall_status; /* 1: not called yet, 0: success, <0: -errno */
+
+ unsigned int enabled_textdomain : 1; /* bindtextdomain() called */
};
/* flags */
@@ -328,6 +342,7 @@ struct libmnt_context
#define MNT_FL_RDONLY_UMOUNT (1 << 11) /* remount,ro after EBUSY umount(2) */
#define MNT_FL_FORK (1 << 12)
#define MNT_FL_NOSWAPMATCH (1 << 13)
+#define MNT_FL_RWONLY_MOUNT (1 << 14) /* explicit mount -w; never try read-only */
#define MNT_FL_MOUNTDATA (1 << 20)
#define MNT_FL_TAB_APPLIED (1 << 21) /* mtab/fstab merged to cxt->fs */
@@ -338,6 +353,7 @@ struct libmnt_context
#define MNT_FL_LOOPDEV_READY (1 << 26) /* /dev/loop<N> initialized by the library */
#define MNT_FL_MOUNTOPTS_FIXED (1 << 27)
#define MNT_FL_TABPATHS_CHECKED (1 << 28)
+#define MNT_FL_FORCED_RDONLY (1 << 29) /* mounted read-only on write-protected device */
/* default flags */
#define MNT_FL_DEFAULT 0
@@ -408,6 +424,10 @@ extern int mnt_context_set_tabfilter(struct libmnt_context *cxt,
int (*fltr)(struct libmnt_fs *, void *),
void *data);
+extern int mnt_context_get_generic_excode(int rc, char *buf, size_t bufsz, char *fmt, ...);
+extern int mnt_context_get_mount_excode(struct libmnt_context *cxt, int mntrc, char *buf, size_t bufsz);
+extern int mnt_context_get_umount_excode(struct libmnt_context *cxt, int mntrc, char *buf, size_t bufsz);
+
/* tab_update.c */
extern int mnt_update_set_filename(struct libmnt_update *upd,
const char *filename, int userspace_only);