summaryrefslogtreecommitdiffstats
path: root/libmount
diff options
context:
space:
mode:
authorKarel Zak2017-04-27 14:01:26 +0200
committerKarel Zak2017-04-27 14:10:23 +0200
commitea848180dd344ec2859b5ca329d9b1375ddde1ac (patch)
tree3891525fa351a694f83fc19d17c048d0771f0722 /libmount
parentlibmount: support MS_RDONLY on write-protected devices (diff)
downloadkernel-qcow2-util-linux-ea848180dd344ec2859b5ca329d9b1375ddde1ac.tar.gz
kernel-qcow2-util-linux-ea848180dd344ec2859b5ca329d9b1375ddde1ac.tar.xz
kernel-qcow2-util-linux-ea848180dd344ec2859b5ca329d9b1375ddde1ac.zip
libmount: add mnt_context_get_excode()
It's pretty complex task to make mount(8) and umount(8) return code and generate error message. It seems better to do that in the libmount rather than force all library users to duplicate mount(8) mk_exit_code() functions. It also means that all the messages will be translated only once. Changes: * all error messages are printed by warn() * no more multi-line messages * all messages prefixed by mount target (mountpoint) * library provides mount(8) compatible MNT_EX_* codes Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1429531 Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libmount')
-rw-r--r--libmount/docs/libmount-sections.txt16
-rw-r--r--libmount/src/context.c97
-rw-r--r--libmount/src/context_mount.c329
-rw-r--r--libmount/src/context_umount.c80
-rw-r--r--libmount/src/libmount.h.in73
-rw-r--r--libmount/src/libmount.sym1
-rw-r--r--libmount/src/mountP.h18
7 files changed, 609 insertions, 5 deletions
diff --git a/libmount/docs/libmount-sections.txt b/libmount/docs/libmount-sections.txt
index 1d21879a0..974b83b8f 100644
--- a/libmount/docs/libmount-sections.txt
+++ b/libmount/docs/libmount-sections.txt
@@ -35,11 +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_rwonly_mount
mnt_context_enable_sloppy
mnt_context_enable_verbose
-mnt_context_forced_rdonly;
+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
@@ -74,7 +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_rwonly_mount
mnt_context_is_sloppy
mnt_context_is_swapmatch
mnt_context_is_verbose
@@ -108,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>
diff --git a/libmount/src/context.c b/libmount/src/context.c
index 6a7c7d351..a370cea09 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -175,6 +175,7 @@ int mnt_reset_context(struct libmnt_context *cxt)
cxt->flags |= (fl & MNT_FL_RWONLY_MOUNT);
cxt->flags |= (fl & MNT_FL_NOSWAPMATCH);
cxt->flags |= (fl & MNT_FL_TABPATHS_CHECKED);
+
return 0;
}
@@ -2261,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.
*/
@@ -2273,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, "return code: %d [%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 1c8a62924..f2b42eb0b 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -1249,3 +1249,332 @@ 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.
+ */
+ 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 3f2da3230..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))
@@ -729,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 354332b43..ca16cafa1 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -320,4 +320,5 @@ 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 42957ecb9..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 */
@@ -410,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);