diff options
-rw-r--r-- | include/exitcodes.h | 10 | ||||
-rw-r--r-- | lib/timer.c | 29 | ||||
-rw-r--r-- | libmount/docs/libmount-sections.txt | 14 | ||||
-rw-r--r-- | libmount/src/context.c | 144 | ||||
-rw-r--r-- | libmount/src/context_mount.c | 358 | ||||
-rw-r--r-- | libmount/src/context_umount.c | 80 | ||||
-rw-r--r-- | libmount/src/libmount.h.in | 78 | ||||
-rw-r--r-- | libmount/src/libmount.sym | 7 | ||||
-rw-r--r-- | libmount/src/mountP.h | 20 | ||||
-rw-r--r-- | sys-utils/fstrim.c | 8 | ||||
-rw-r--r-- | sys-utils/mount.8 | 6 | ||||
-rw-r--r-- | sys-utils/mount.c | 435 | ||||
-rw-r--r-- | sys-utils/umount.c | 180 | ||||
-rw-r--r-- | tests/expected/libmount/loop-conflict | 2 | ||||
-rw-r--r-- | tests/expected/libmount/loop-o-loop-val-conflict | 2 | ||||
-rw-r--r-- | tests/expected/libmount/loop-o-loop-val-initialized | 2 | ||||
-rw-r--r-- | tests/expected/libmount/loop-overlay | 6 | ||||
-rwxr-xr-x | tests/ts/libmount/loop | 9 | ||||
-rwxr-xr-x | tests/ts/libmount/loop-overlay | 10 |
19 files changed, 831 insertions, 569 deletions
diff --git a/include/exitcodes.h b/include/exitcodes.h index 24ee12364..f28f68e45 100644 --- a/include/exitcodes.h +++ b/include/exitcodes.h @@ -22,14 +22,4 @@ #define FSCK_EX_USAGE 16 /* Usage or syntax error */ #define FSCK_EX_LIBRARY 128 /* Shared library error */ -/* Exit codes used by mount-line programs */ -#define MOUNT_EX_SUCCESS 0 /* No errors */ -#define MOUNT_EX_USAGE 1 /* incorrect invocation or permission */ -#define MOUNT_EX_SYSERR 2 /* out of memory, cannot fork, ... */ -#define MOUNT_EX_SOFTWARE 4 /* internal mount bug or wrong version */ -#define MOUNT_EX_USER 8 /* user interrupt */ -#define MOUNT_EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */ -#define MOUNT_EX_FAIL 32 /* mount failure */ -#define MOUNT_EX_SOMEOK 64 /* some mount succeeded */ - #endif /* UTIL_LINUX_EXITCODES_H */ diff --git a/lib/timer.c b/lib/timer.c index 05fbd92f5..210c726cb 100644 --- a/lib/timer.c +++ b/lib/timer.c @@ -10,19 +10,38 @@ #include "c.h" #include "timer.h" +/* + * Note the timeout is used for the first signal, then the signal is send + * repeatedly in interval ~1% of the original timeout to avoid race in signal + * handling -- for example you want to use timer to define timeout for a + * syscall: + * + * setup_timer() + * syscall() + * cancel_timer() + * + * if the timeout is too short than it's possible that the signal is delivered + * before application enter the syscall function. For this reason timer send + * the signal repeatedly. + * + * The applications need to ensure that they can tolerate multiple signal + * deliveries. + */ int setup_timer(timer_t * t_id, struct itimerval *timeout, void (*timeout_handler)(int, siginfo_t *, void *)) { + time_t sec = timeout->it_value.tv_sec; + long usec = timeout->it_value.tv_usec; struct sigaction sig_a; static struct sigevent sig_e = { .sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGALRM }; struct itimerspec val = { - .it_value.tv_sec = timeout->it_value.tv_sec, - .it_value.tv_nsec = timeout->it_value.tv_usec * 1000, - .it_interval.tv_sec = 0, - .it_interval.tv_nsec = 0 + .it_value.tv_sec = sec, + .it_value.tv_nsec = usec * 1000, + .it_interval.tv_sec = sec / 100, + .it_interval.tv_nsec = (sec ? sec % 100 : 1) * 10*1000*1000 }; if (sigemptyset(&sig_a.sa_mask)) @@ -35,7 +54,7 @@ int setup_timer(timer_t * t_id, struct itimerval *timeout, return 1; if (timer_create(CLOCK_MONOTONIC, &sig_e, t_id)) return 1; - if (timer_settime(*t_id, SA_SIGINFO, &val, NULL)) + if (timer_settime(*t_id, 0, &val, NULL)) return 1; return 0; } 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); diff --git a/sys-utils/fstrim.c b/sys-utils/fstrim.c index f42ebe77a..b884af6d0 100644 --- a/sys-utils/fstrim.c +++ b/sys-utils/fstrim.c @@ -184,11 +184,11 @@ static int fstrim_all(struct fstrim_range *rangetpl, int verbose) itr = mnt_new_iter(MNT_ITER_BACKWARD); if (!itr) - err(MOUNT_EX_FAIL, _("failed to initialize libmount iterator")); + err(MNT_EX_FAIL, _("failed to initialize libmount iterator")); tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO); if (!tab) - err(MOUNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO); + err(MNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO); /* de-duplicate by mountpoints */ mnt_table_uniq_fs(tab, 0, uniq_fs_target_cmp); @@ -237,9 +237,9 @@ static int fstrim_all(struct fstrim_range *rangetpl, int verbose) mnt_free_iter(itr); if (cnt && cnt == cnt_err) - return MOUNT_EX_FAIL; /* all failed */ + return MNT_EX_FAIL; /* all failed */ if (cnt && cnt_err) - return MOUNT_EX_SOMEOK; /* some ok */ + return MNT_EX_SOMEOK; /* some ok */ return EXIT_SUCCESS; } diff --git a/sys-utils/mount.8 b/sys-utils/mount.8 index 56ccbbd35..bbfe71b75 100644 --- a/sys-utils/mount.8 +++ b/sys-utils/mount.8 @@ -807,8 +807,12 @@ Mount the partition that has the specified Verbose mode. .TP .BR \-w , " \-\-rw" , " \-\-read\-write" -Mount the filesystem read/write. This is the default. A synonym is +Mount the filesystem read/write. The read-write is kernel default. A synonym is .BR "\-o rw" . + +Note that specify \fB\-w\fR on command line forces \fBmount\fR command +to never try read-only mount on write-protected devices. The default is +try read-only if the previous mount syscall with read-write flags failed. .TP .BR \-V , " \-\-version" Display version information and exit. diff --git a/sys-utils/mount.c b/sys-utils/mount.c index b09e77616..4d7a5fc73 100644 --- a/sys-utils/mount.c +++ b/sys-utils/mount.c @@ -36,12 +36,11 @@ #include "c.h" #include "env.h" #include "strutils.h" -#include "exitcodes.h" #include "xalloc.h" #include "closestream.h" #include "canonicalize.h" -#define OPTUTILS_EXIT_CODE MOUNT_EX_USAGE +#define OPTUTILS_EXIT_CODE MNT_EX_USAGE #include "optutils.h" /*** TODO: DOCS: @@ -51,8 +50,6 @@ * --options-source-force MNT_OMODE_FORCE */ -static int readwrite; - static int mk_exit_code(struct libmnt_context *cxt, int rc); static void __attribute__((__noreturn__)) exit_non_root(const char *option) @@ -63,15 +60,15 @@ static void __attribute__((__noreturn__)) exit_non_root(const char *option) if (ruid == 0 && euid != 0) { /* user is root, but setuid to non-root */ if (option) - errx(MOUNT_EX_USAGE, _("only root can use \"--%s\" option " + errx(MNT_EX_USAGE, _("only root can use \"--%s\" option " "(effective UID is %u)"), option, euid); - errx(MOUNT_EX_USAGE, _("only root can do that " + errx(MNT_EX_USAGE, _("only root can do that " "(effective UID is %u)"), euid); } if (option) - errx(MOUNT_EX_USAGE, _("only root can use \"--%s\" option"), option); - errx(MOUNT_EX_USAGE, _("only root can do that")); + errx(MNT_EX_USAGE, _("only root can use \"--%s\" option"), option); + errx(MNT_EX_USAGE, _("only root can do that")); } static void __attribute__((__noreturn__)) print_version(void) @@ -92,7 +89,7 @@ static void __attribute__((__noreturn__)) print_version(void) fputs(*p++, stdout); } fputs(")\n", stdout); - exit(MOUNT_EX_SUCCESS); + exit(MNT_EX_SUCCESS); } static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)), @@ -127,11 +124,11 @@ static void print_all(struct libmnt_context *cxt, char *pattern, int show_label) struct libmnt_cache *cache = NULL; if (mnt_context_get_mtab(cxt, &tb)) - err(MOUNT_EX_SYSERR, _("failed to read mtab")); + err(MNT_EX_SYSERR, _("failed to read mtab")); itr = mnt_new_iter(MNT_ITER_FORWARD); if (!itr) - err(MOUNT_EX_SYSERR, _("failed to initialize libmount iterator")); + err(MNT_EX_SYSERR, _("failed to initialize libmount iterator")); if (show_label) cache = mnt_new_cache(); @@ -173,14 +170,14 @@ static int mount_all(struct libmnt_context *cxt) { struct libmnt_iter *itr; struct libmnt_fs *fs; - int mntrc, ignored, rc = MOUNT_EX_SUCCESS; + int mntrc, ignored, rc = MNT_EX_SUCCESS; int nsucc = 0, nerrs = 0; itr = mnt_new_iter(MNT_ITER_FORWARD); if (!itr) { warn(_("failed to initialize libmount iterator")); - return MOUNT_EX_SYSERR; + return MNT_EX_SYSERR; } while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) { @@ -196,10 +193,10 @@ static int mount_all(struct libmnt_context *cxt) if (mnt_context_is_verbose(cxt)) printf("%-25s: mount successfully forked\n", tgt); } else { - if (mk_exit_code(cxt, mntrc) == MOUNT_EX_SUCCESS) { + if (mk_exit_code(cxt, mntrc) == MNT_EX_SUCCESS) { nsucc++; - /* Note that MOUNT_EX_SUCCESS return code does + /* Note that MNT_EX_SUCCESS return code does * not mean that FS has been really mounted * (e.g. nofail option) */ if (mnt_context_get_status(cxt) @@ -222,11 +219,11 @@ static int mount_all(struct libmnt_context *cxt) } if (nerrs == 0) - rc = MOUNT_EX_SUCCESS; /* all success */ + rc = MNT_EX_SUCCESS; /* all success */ else if (nsucc == 0) - rc = MOUNT_EX_FAIL; /* all failed */ + rc = MNT_EX_FAIL; /* all failed */ else - rc = MOUNT_EX_SOMEOK; /* some success, some failed */ + rc = MNT_EX_SOMEOK; /* some success, some failed */ mnt_free_iter(itr); return rc; @@ -258,40 +255,6 @@ static void success_message(struct libmnt_context *cxt) printf(_("%s: %s mounted on %s.\n"), pr, src, tgt); } -/* - * Handles generic errors like ENOMEM, ... - * - * rc = 0 success - * <0 error (usually -errno) - * - * Returns exit status (MOUNT_EX_*) and prints error message. - */ -static int handle_generic_errors(int rc, const char *msg, ...) -{ - va_list va; - - va_start(va, msg); - errno = -rc; - - switch(errno) { - case EINVAL: - case EPERM: - vwarn(msg, va); - rc = MOUNT_EX_USAGE; - break; - case ENOMEM: - vwarn(msg, va); - rc = MOUNT_EX_SYSERR; - break; - default: - vwarn(msg, va); - rc = MOUNT_EX_FAIL; - break; - } - va_end(va); - return rc; -} - #if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT) #include <selinux/selinux.h> #include <selinux/context.h> @@ -323,339 +286,29 @@ static void selinux_warning(struct libmnt_context *cxt, const char *tgt) #endif /* - * 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 = xstrdup(dir); - 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; -} - -/* - * rc = 0 success - * <0 error (usually -errno or -1) - * - * Returns exit status (MOUNT_EX_*) and/or prints error message. + * Returns exit status (MNT_EX_*) and/or prints error message. */ static int mk_exit_code(struct libmnt_context *cxt, int rc) { - int syserr; - struct stat st; - unsigned long uflags = 0, mflags = 0; + const char *tgt; + char buf[BUFSIZ] = { 0 }; - int restricted = mnt_context_is_restricted(cxt); - const char *tgt = mnt_context_get_target(cxt); - const char *src = mnt_context_get_source(cxt); + rc = mnt_context_get_excode(cxt, rc, buf, sizeof(buf)); + tgt = mnt_context_get_target(cxt); -try_readonly: - if (mnt_context_helper_executed(cxt)) { - /* - * /sbin/mount.<type> called, return status - */ - if (rc == -MNT_ERR_APPLYFLAGS) - warnx(_("WARNING: failed to apply propagation flags")); - return mnt_context_get_helper_status(cxt); + if (*buf) { + const char *spec = tgt; + if (!spec) + spec = mnt_context_get_source(cxt); + if (!spec) + spec = "???"; + warnx(_("%s: %s."), spec, buf); } - if (rc == 0 && mnt_context_get_status(cxt) == 1) { - /* - * Libmount success && syscall success. - */ + if (rc == MNT_EX_SUCCESS && mnt_context_get_status(cxt) == 1) { selinux_warning(cxt, tgt); - - return MOUNT_EX_SUCCESS; /* mount(2) 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: - warnx(_("only root can mount %s on %s"), src, tgt); - return MOUNT_EX_USAGE; - case -EBUSY: - warnx(_("%s is already mounted"), src); - return MOUNT_EX_USAGE; - /* -EROFS before syscall can happen only for loop mount */ - case -EROFS: - warnx(_("%s is used as read only loop, mounting read-only"), src); - mnt_context_reset_status(cxt); - mnt_context_set_mflags(cxt, mflags | MS_RDONLY); - rc = mnt_context_mount(cxt); - if (!rc) - rc = mnt_context_finalize_mount(cxt); - goto try_readonly; - case -MNT_ERR_NOFSTAB: - if (mnt_context_is_swapmatch(cxt)) { - warnx(_("can't find %s in %s"), - src ? src : tgt, - mnt_get_fstab_path()); - return MOUNT_EX_USAGE; - } - /* source/target explicitly defined */ - if (tgt) - warnx(_("can't find mountpoint %s in %s"), - tgt, mnt_get_fstab_path()); - else - warnx(_("can't find mount source %s in %s"), - src, mnt_get_fstab_path()); - return MOUNT_EX_USAGE; - case -MNT_ERR_AMBIFS: - warnx(_("%s: more filesystems detected. This should not happen,\n" - " use -t <type> to explicitly specify the filesystem type or\n" - " use wipefs(8) to clean up the device."), src); - return MOUNT_EX_USAGE; - case -MNT_ERR_NOFSTYPE: - if (restricted) - warnx(_("I could not determine the filesystem type, " - "and none was specified")); - else - warnx(_("you must specify the filesystem type")); - return MOUNT_EX_USAGE; - case -MNT_ERR_NOSOURCE: - if (uflags & MNT_MS_NOFAIL) - return MOUNT_EX_SUCCESS; - if (src) - warnx(_("can't find %s"), src); - else - warnx(_("mount source not defined")); - return MOUNT_EX_USAGE; - case -MNT_ERR_MOUNTOPT: - if (errno) - warn(_("failed to parse mount options")); - else - warnx(_("failed to parse mount options")); - return MOUNT_EX_USAGE; - case -MNT_ERR_LOOPDEV: - warn(_("%s: failed to setup loop device"), src); - return MOUNT_EX_FAIL; - case -MNT_ERR_LOOPOVERLAP: - warnx(_("%s: overlapping loop device exists"), src); - return MOUNT_EX_FAIL; - default: - return handle_generic_errors(rc, _("%s: mount failed"), - tgt ? tgt : src); - } - } 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 handle_generic_errors(rc, - _("%s: filesystem mounted, but mount(8) failed"), - tgt ? tgt : src); - - return MOUNT_EX_SOFTWARE; /* internal error */ - - } - - /* - * mount(2) errors - */ - syserr = mnt_context_get_syscall_errno(cxt); - - - switch(syserr) { - case EPERM: - if (geteuid() == 0) { - if (stat(tgt, &st) || !S_ISDIR(st.st_mode)) - warnx(_("mount point %s is not a directory"), tgt); - else - warnx(_("permission denied")); - } else - warnx(_("must be superuser to use mount")); - break; - - case EBUSY: - { - struct libmnt_table *tb; - - if (mflags & MS_REMOUNT) { - warnx(_("%s is busy"), tgt); - break; - } - - warnx(_("%s is already mounted or %s busy"), src, tgt); - - if (src && mnt_context_get_mtab(cxt, &tb) == 0) { - struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD); - struct libmnt_fs *fs; - - 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)) - fprintf(stderr, _( - " %s is already mounted on %s\n"), s, t); - } - mnt_free_iter(itr); - } - break; - } - case ENOENT: - if (tgt && lstat(tgt, &st)) - warnx(_("mount point %s does not exist"), tgt); - else if (tgt && stat(tgt, &st)) - warnx(_("mount point %s is a symbolic link to nowhere"), tgt); - else if (src && stat(src, &st)) { - if (uflags & MNT_MS_NOFAIL) - return MOUNT_EX_SUCCESS; - - warnx(_("special device %s does not exist"), src); - } else { - errno = syserr; - if (tgt) - warn("%s: %s", _("mount(2) failed"), tgt); - else if (src) - warn("%s: %s", _("mount(2) failed"), src); - else - warn(_("mount(2) failed")); - } - break; - - case ENOTDIR: - if (stat(tgt, &st) || ! S_ISDIR(st.st_mode)) - warnx(_("mount point %s is not a directory"), tgt); - else if (src && stat(src, &st) && errno == ENOTDIR) { - if (uflags & MNT_MS_NOFAIL) - return MOUNT_EX_SUCCESS; - - warnx(_("special device %s does not exist " - "(a path prefix is not a directory)"), src); - } else { - errno = syserr; - warn("%s: %s", _("mount(2) failed"), tgt); - } - break; - - case EINVAL: - if (mflags & MS_REMOUNT) - warnx(_("%s not mounted or bad option"), tgt); - else if (rc == -MNT_ERR_APPLYFLAGS) - warnx(_("%s is not mountpoint or bad option"), tgt); - else if ((mflags & MS_MOVE) && is_shared_tree(cxt, src)) - warnx(_("bad option. Note that moving a mount residing under a shared\n" - " mount is unsupported.")); - else - warnx(_("wrong fs type, bad option, bad superblock on %s,\n" - " missing codepage or helper program, or other error"), - src); - - if (mnt_fs_is_netfs(mnt_context_get_fs(cxt))) - fprintf(stderr, _( - " (for several filesystems (e.g. nfs, cifs) you might\n" - " need a /sbin/mount.<type> helper program)\n")); - - fprintf(stderr, _("\n" - " In some cases useful info is found in syslog - try\n" - " dmesg | tail or so.\n")); - break; - - case EMFILE: - warnx(_("mount table full")); - break; - - case EIO: - warnx(_("%s: can't read superblock"), src); - break; - - case ENODEV: - if (mnt_context_get_fstype(cxt)) - warnx(_("unknown filesystem type '%s'"), mnt_context_get_fstype(cxt)); - else - warnx(_("unknown filesystem type")); - break; - - case ENOTBLK: - if (uflags & MNT_MS_NOFAIL) - return MOUNT_EX_SUCCESS; - - if (stat(src, &st)) - warnx(_("%s is not a block device, and stat(2) fails?"), src); - else if (S_ISBLK(st.st_mode)) - warnx(_("the kernel does not recognize %s as a block device\n" - " (maybe `modprobe driver'?)"), src); - else if (S_ISREG(st.st_mode)) - warnx(_("%s is not a block device (maybe try `-o loop'?)"), src); - else - warnx(_(" %s is not a block device"), src); - break; - - case ENXIO: - if (uflags & MNT_MS_NOFAIL) - return MOUNT_EX_SUCCESS; - - warnx(_("%s is not a valid block device"), src); - break; - - case EACCES: - case EROFS: - if (mflags & MS_RDONLY) - warnx(_("cannot mount %s read-only"), src); - - else if (readwrite) - warnx(_("%s is write-protected but explicit `-w' flag given"), src); - - else if (mflags & MS_REMOUNT) - warnx(_("cannot remount %s read-write, is write-protected"), src); - - else if (mflags & MS_BIND) - warn(_("mount %s on %s failed"), src, tgt); - - else { - warnx(_("%s is write-protected, mounting read-only"), src); - - mnt_context_reset_status(cxt); - mnt_context_set_mflags(cxt, mflags | MS_RDONLY); - rc = mnt_context_do_mount(cxt); - if (!rc) - rc = mnt_context_finalize_mount(cxt); - - goto try_readonly; - } - break; - - case ENOMEDIUM: - if (uflags & MNT_MS_NOFAIL) - return MOUNT_EX_SUCCESS; - - warnx(_("no medium found on %s"), src); - break; - - default: - warn(_("mount %s on %s failed"), src, tgt); - break; } - - return MOUNT_EX_FAIL; + return rc; } static struct libmnt_table *append_fstab(struct libmnt_context *cxt, @@ -666,7 +319,7 @@ static struct libmnt_table *append_fstab(struct libmnt_context *cxt, if (!fstab) { fstab = mnt_new_table(); if (!fstab) - err(MOUNT_EX_SYSERR, _("failed to initialize libmount table")); + err(MNT_EX_SYSERR, _("failed to initialize libmount table")); mnt_table_set_parser_errcb(fstab, table_parser_errcb); mnt_context_set_fstab(cxt, fstab); @@ -675,7 +328,7 @@ static struct libmnt_table *append_fstab(struct libmnt_context *cxt, } if (mnt_table_parse_fstab(fstab, path)) - errx(MOUNT_EX_USAGE,_("%s: failed to parse"), path); + errx(MNT_EX_USAGE,_("%s: failed to parse"), path); return fstab; } @@ -696,7 +349,7 @@ static void sanitize_paths(struct libmnt_context *cxt) if (p) { char *np = canonicalize_path_restricted(p); if (!np) - err(MOUNT_EX_USAGE, "%s", p); + err(MNT_EX_USAGE, "%s", p); mnt_fs_set_target(fs, np); free(np); } @@ -705,7 +358,7 @@ static void sanitize_paths(struct libmnt_context *cxt) if (p) { char *np = canonicalize_path_restricted(p); if (!np) - err(MOUNT_EX_USAGE, "%s", p); + err(MNT_EX_USAGE, "%s", p); mnt_fs_set_source(fs, np); free(np); } @@ -714,9 +367,9 @@ static void sanitize_paths(struct libmnt_context *cxt) static void append_option(struct libmnt_context *cxt, const char *opt) { if (opt && (*opt == '=' || *opt == '\'' || *opt == '\"' || isblank(*opt))) - errx(MOUNT_EX_USAGE, _("unsupported option format: %s"), opt); + errx(MNT_EX_USAGE, _("unsupported option format: %s"), opt); if (mnt_context_append_options(cxt, opt)) - err(MOUNT_EX_SYSERR, _("failed to append option '%s'"), opt); + err(MNT_EX_SYSERR, _("failed to append option '%s'"), opt); } static int has_remount_flag(struct libmnt_context *cxt) @@ -805,12 +458,12 @@ static void __attribute__((__noreturn__)) usage(FILE *out) fprintf(out, USAGE_MAN_TAIL("mount(8)")); - exit(out == stderr ? MOUNT_EX_USAGE : MOUNT_EX_SUCCESS); + exit(out == stderr ? MNT_EX_USAGE : MNT_EX_SUCCESS); } int main(int argc, char **argv) { - int c, rc = MOUNT_EX_SUCCESS, all = 0, show_labels = 0; + int c, rc = MNT_EX_SUCCESS, all = 0, show_labels = 0; struct libmnt_context *cxt; struct libmnt_table *fstab = NULL; char *srcbuf = NULL; @@ -884,7 +537,7 @@ int main(int argc, char **argv) mnt_init_debug(0); cxt = mnt_new_context(); if (!cxt) - err(MOUNT_EX_SYSERR, _("libmount context allocation failed")); + err(MNT_EX_SYSERR, _("libmount context allocation failed")); mnt_context_set_tables_errcb(cxt, table_parser_errcb); @@ -924,7 +577,7 @@ int main(int argc, char **argv) break; case 'r': append_option(cxt, "ro"); - readwrite = 0; + mnt_context_enable_rwonly_mount(cxt, FALSE); break; case 'v': mnt_context_enable_verbose(cxt, TRUE); @@ -934,14 +587,14 @@ int main(int argc, char **argv) break; case 'w': append_option(cxt, "rw"); - readwrite = 1; + mnt_context_enable_rwonly_mount(cxt, TRUE); break; case 'o': append_option(cxt, optarg); break; case 'O': if (mnt_context_set_options_pattern(cxt, optarg)) - err(MOUNT_EX_SYSERR, _("failed to set options pattern")); + err(MNT_EX_SYSERR, _("failed to set options pattern")); break; case 'L': xasprintf(&srcbuf, "LABEL=\"%s\"", optarg); @@ -1017,7 +670,7 @@ int main(int argc, char **argv) mnt_context_set_source(cxt, optarg); break; default: - errtryhelp(MOUNT_EX_USAGE); + errtryhelp(MNT_EX_USAGE); } } @@ -1093,7 +746,7 @@ int main(int argc, char **argv) if (istag && mnt_context_get_source(cxt)) /* -L, -U or --source together with LABEL= or UUID= */ - errx(MOUNT_EX_USAGE, _("source specified more than once")); + errx(MNT_EX_USAGE, _("source specified more than once")); else if (istag || mnt_context_get_target(cxt)) mnt_context_set_source(cxt, argv[0]); else @@ -1132,7 +785,7 @@ int main(int argc, char **argv) rc = mnt_context_mount(cxt); rc = mk_exit_code(cxt, rc); - if (rc == MOUNT_EX_SUCCESS && mnt_context_is_verbose(cxt)) + if (rc == MNT_EX_SUCCESS && mnt_context_is_verbose(cxt)) success_message(cxt); done: mnt_free_context(cxt); diff --git a/sys-utils/umount.c b/sys-utils/umount.c index 21f7edfed..ed8fd4fe2 100644 --- a/sys-utils/umount.c +++ b/sys-utils/umount.c @@ -33,7 +33,6 @@ #include "c.h" #include "env.h" #include "optutils.h" -#include "exitcodes.h" #include "closestream.h" #include "pathnames.h" #include "canonicalize.h" @@ -66,7 +65,7 @@ static void __attribute__((__noreturn__)) print_version(void) fputs(*p++, stdout); } fputs(")\n", stdout); - exit(MOUNT_EX_SUCCESS); + exit(MNT_EX_SUCCESS); } static void __attribute__((__noreturn__)) usage(FILE *out) { @@ -102,7 +101,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out) fputs(USAGE_VERSION, out); fprintf(out, USAGE_MAN_TAIL("umount(8)")); - exit(out == stderr ? MOUNT_EX_USAGE : MOUNT_EX_SUCCESS); + exit(out == stderr ? MNT_EX_USAGE : MNT_EX_SUCCESS); } static void __attribute__((__noreturn__)) exit_non_root(const char *option) @@ -113,16 +112,16 @@ static void __attribute__((__noreturn__)) exit_non_root(const char *option) if (ruid == 0 && euid != 0) { /* user is root, but setuid to non-root */ if (option) - errx(MOUNT_EX_USAGE, + errx(MNT_EX_USAGE, _("only root can use \"--%s\" option " "(effective UID is %u)"), option, euid); - errx(MOUNT_EX_USAGE, _("only root can do that " + errx(MNT_EX_USAGE, _("only root can do that " "(effective UID is %u)"), euid); } if (option) - errx(MOUNT_EX_USAGE, _("only root can use \"--%s\" option"), option); - errx(MOUNT_EX_USAGE, _("only root can do that")); + errx(MNT_EX_USAGE, _("only root can use \"--%s\" option"), option); + errx(MNT_EX_USAGE, _("only root can do that")); } static void success_message(struct libmnt_context *cxt) @@ -144,123 +143,20 @@ static void success_message(struct libmnt_context *cxt) warnx(_("%s unmounted"), tgt); } -/* - * Handles generic errors like ENOMEM, ... - * - * rc = 0 success - * <0 error (usually -errno) - * - * Returns exit status (MOUNT_EX_*) and prints error message. - */ -static int handle_generic_errors(int rc, const char *msg, ...) -{ - va_list va; - - va_start(va, msg); - errno = -rc; - - switch(errno) { - case EINVAL: - case EPERM: - vwarn(msg, va); - rc = MOUNT_EX_USAGE; - break; - case ENOMEM: - vwarn(msg, va); - rc = MOUNT_EX_SYSERR; - break; - default: - vwarn(msg, va); - rc = MOUNT_EX_FAIL; - break; - } - va_end(va); - return rc; -} - static int mk_exit_code(struct libmnt_context *cxt, int rc) { - int syserr; - const char *tgt = mnt_context_get_target(cxt); - - 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 MOUNT_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 */ - warnx(_("%s: not mounted"), tgt); - return MOUNT_EX_USAGE; - } - return handle_generic_errors(rc, _("%s: umount failed"), tgt); - - } 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 handle_generic_errors(rc, - _("%s: filesystem was unmounted, but mount(8) failed"), - tgt); - - return MOUNT_EX_SOFTWARE; /* internal error */ - + char buf[BUFSIZ] = { 0 }; + + rc = mnt_context_get_excode(cxt, rc, buf, sizeof(buf)); + if (*buf) { + const char *spec = mnt_context_get_target(cxt); + if (!spec) + spec = mnt_context_get_source(cxt); + if (!spec) + spec = "???"; + warnx(_("%s: %s."), spec, buf); } - - /* - * umount(2) errors - */ - syserr = mnt_context_get_syscall_errno(cxt); - - switch(syserr) { - case ENXIO: - warnx(_("%s: invalid block device"), tgt); /* ??? */ - break; - case EINVAL: - warnx(_("%s: not mounted"), tgt); - break; - case EIO: - warnx(_("%s: can't write superblock"), tgt); - break; - case EBUSY: - warnx(_("%s: target is busy\n" - " (In some cases useful info about processes that\n" - " use the device is found by lsof(8) or fuser(1).)"), - tgt); - break; - case ENOENT: - if (tgt && *tgt) - warnx(_("%s: mountpoint not found"), tgt); - else - warnx(_("undefined mountpoint")); - break; - case EPERM: - warnx(_("%s: must be superuser to unmount"), tgt); - break; - case EACCES: - warnx(_("%s: block devices are not permitted on filesystem"), tgt); - break; - default: - errno = syserr; - warn("%s", tgt); - break; - } - return MOUNT_EX_FAIL; + return rc; } static int umount_all(struct libmnt_context *cxt) @@ -272,7 +168,7 @@ static int umount_all(struct libmnt_context *cxt) itr = mnt_new_iter(MNT_ITER_BACKWARD); if (!itr) { warn(_("failed to initialize libmount iterator")); - return MOUNT_EX_SYSERR; + return MNT_EX_SYSERR; } while (mnt_context_next_umount(cxt, itr, &fs, &mntrc, &ignored) == 0) { @@ -285,7 +181,7 @@ static int umount_all(struct libmnt_context *cxt) } else { int xrc = mk_exit_code(cxt, mntrc); - if (xrc == MOUNT_EX_SUCCESS + if (xrc == MNT_EX_SUCCESS && mnt_context_is_verbose(cxt)) printf("%-25s: successfully unmounted\n", tgt); rc |= xrc; @@ -301,15 +197,15 @@ static int umount_one(struct libmnt_context *cxt, const char *spec) int rc; if (!spec) - return MOUNT_EX_SOFTWARE; + return MNT_EX_SOFTWARE; if (mnt_context_set_target(cxt, spec)) - err(MOUNT_EX_SYSERR, _("failed to set umount target")); + err(MNT_EX_SYSERR, _("failed to set umount target")); rc = mnt_context_umount(cxt); rc = mk_exit_code(cxt, rc); - if (rc == MOUNT_EX_SUCCESS && mnt_context_is_verbose(cxt)) + if (rc == MNT_EX_SUCCESS && mnt_context_is_verbose(cxt)) success_message(cxt); mnt_reset_context(cxt); @@ -320,7 +216,7 @@ static struct libmnt_table *new_mountinfo(struct libmnt_context *cxt) { struct libmnt_table *tb = mnt_new_table(); if (!tb) - err(MOUNT_EX_SYSERR, _("libmount table allocation failed")); + err(MNT_EX_SYSERR, _("libmount table allocation failed")); mnt_table_set_parser_errcb(tb, table_parser_errcb); mnt_table_set_cache(tb, mnt_context_get_cache(cxt)); @@ -344,7 +240,7 @@ static int umount_one_if_mounted(struct libmnt_context *cxt, const char *spec) rc = mnt_context_find_umount_fs(cxt, spec, &fs); if (rc == 1) { - rc = MOUNT_EX_SUCCESS; /* already unmounted */ + rc = MNT_EX_SUCCESS; /* already unmounted */ mnt_reset_context(cxt); } else if (rc < 0) { rc = mk_exit_code(cxt, rc); /* error */ @@ -363,7 +259,7 @@ static int umount_do_recurse(struct libmnt_context *cxt, int rc; if (!itr) - err(MOUNT_EX_SYSERR, _("libmount iterator allocation failed")); + err(MNT_EX_SYSERR, _("libmount iterator allocation failed")); /* umount all children */ for (;;) { @@ -371,13 +267,13 @@ static int umount_do_recurse(struct libmnt_context *cxt, if (rc < 0) { warnx(_("failed to get child fs of %s"), mnt_fs_get_target(fs)); - rc = MOUNT_EX_SOFTWARE; + rc = MNT_EX_SOFTWARE; goto done; } else if (rc == 1) break; /* no more children */ rc = umount_do_recurse(cxt, tb, child); - if (rc != MOUNT_EX_SUCCESS) + if (rc != MNT_EX_SUCCESS) goto done; } @@ -395,7 +291,7 @@ static int umount_recursive(struct libmnt_context *cxt, const char *spec) tb = new_mountinfo(cxt); if (!tb) - return MOUNT_EX_SOFTWARE; + return MNT_EX_SOFTWARE; /* it's always real mountpoint, don't assume that the target maybe a device */ mnt_context_disable_swapmatch(cxt, 1); @@ -404,7 +300,7 @@ static int umount_recursive(struct libmnt_context *cxt, const char *spec) if (fs) rc = umount_do_recurse(cxt, tb, fs); else { - rc = MOUNT_EX_USAGE; + rc = MNT_EX_USAGE; warnx(access(spec, F_OK) == 0 ? _("%s: not mounted") : _("%s: not found"), spec); @@ -427,7 +323,7 @@ static int umount_alltargets(struct libmnt_context *cxt, const char *spec, int r */ rc = mnt_context_find_umount_fs(cxt, spec, &fs); if (rc == 1) { - rc = MOUNT_EX_USAGE; + rc = MNT_EX_USAGE; warnx(access(spec, F_OK) == 0 ? _("%s: not mounted") : _("%s: not found"), spec); @@ -437,18 +333,18 @@ static int umount_alltargets(struct libmnt_context *cxt, const char *spec, int r return mk_exit_code(cxt, rc); /* error */ if (!mnt_fs_get_srcpath(fs) || !mnt_fs_get_devno(fs)) - errx(MOUNT_EX_USAGE, _("%s: failed to determine source " + errx(MNT_EX_USAGE, _("%s: failed to determine source " "(--all-targets is unsupported on systems with " "regular mtab file)."), spec); itr = mnt_new_iter(MNT_ITER_BACKWARD); if (!itr) - err(MOUNT_EX_SYSERR, _("libmount iterator allocation failed")); + err(MNT_EX_SYSERR, _("libmount iterator allocation failed")); /* get on @cxt independent mountinfo */ tb = new_mountinfo(cxt); if (!tb) { - rc = MOUNT_EX_SOFTWARE; + rc = MNT_EX_SOFTWARE; goto done; } @@ -468,7 +364,7 @@ static int umount_alltargets(struct libmnt_context *cxt, const char *spec, int r else rc = umount_one_if_mounted(cxt, mnt_fs_get_target(fs)); - if (rc != MOUNT_EX_SUCCESS) + if (rc != MNT_EX_SUCCESS) break; } @@ -492,7 +388,7 @@ static char *sanitize_path(const char *path) p = canonicalize_path_restricted(path); if (!p) - err(MOUNT_EX_USAGE, "%s", path); + err(MNT_EX_USAGE, "%s", path); return p; } @@ -545,7 +441,7 @@ int main(int argc, char **argv) mnt_init_debug(0); cxt = mnt_new_context(); if (!cxt) - err(MOUNT_EX_SYSERR, _("libmount context allocation failed")); + err(MNT_EX_SYSERR, _("libmount context allocation failed")); mnt_context_set_tables_errcb(cxt, table_parser_errcb); @@ -598,7 +494,7 @@ int main(int argc, char **argv) break; case 'O': if (mnt_context_set_options_pattern(cxt, optarg)) - err(MOUNT_EX_SYSERR, _("failed to set options pattern")); + err(MNT_EX_SYSERR, _("failed to set options pattern")); break; case 't': types = optarg; @@ -610,7 +506,7 @@ int main(int argc, char **argv) print_version(); break; default: - errtryhelp(MOUNT_EX_USAGE); + errtryhelp(MNT_EX_USAGE); } } diff --git a/tests/expected/libmount/loop-conflict b/tests/expected/libmount/loop-conflict index e26f99a4f..1686021f0 100644 --- a/tests/expected/libmount/loop-conflict +++ b/tests/expected/libmount/loop-conflict @@ -1,2 +1,2 @@ -: overlapping loop device exists +mount: <target> overlapping loop device exists for <source> Success diff --git a/tests/expected/libmount/loop-o-loop-val-conflict b/tests/expected/libmount/loop-o-loop-val-conflict index 043847449..0eb732214 100644 --- a/tests/expected/libmount/loop-o-loop-val-conflict +++ b/tests/expected/libmount/loop-o-loop-val-conflict @@ -1,2 +1,2 @@ -: failed to setup loop device: Device or resource busy +mount: <target> failed to setup loop device for <source> Success diff --git a/tests/expected/libmount/loop-o-loop-val-initialized b/tests/expected/libmount/loop-o-loop-val-initialized index e26f99a4f..1686021f0 100644 --- a/tests/expected/libmount/loop-o-loop-val-initialized +++ b/tests/expected/libmount/loop-o-loop-val-initialized @@ -1,2 +1,2 @@ -: overlapping loop device exists +mount: <target> overlapping loop device exists for <source> Success diff --git a/tests/expected/libmount/loop-overlay b/tests/expected/libmount/loop-overlay index ab6c68beb..399024471 100644 --- a/tests/expected/libmount/loop-overlay +++ b/tests/expected/libmount/loop-overlay @@ -1,7 +1,7 @@ second should fail - overlapping loop device exists +mount: <target> overlapping loop device exists for <source> should succeed both should fail - overlapping loop device exists - overlapping loop device exists +mount: <target> overlapping loop device exists for <source> +mount: <target> overlapping loop device exists for <source> Success diff --git a/tests/ts/libmount/loop b/tests/ts/libmount/loop index 1589af1ed..ec22c9a2c 100755 --- a/tests/ts/libmount/loop +++ b/tests/ts/libmount/loop @@ -104,7 +104,8 @@ ts_finalize_subtest ts_init_subtest "conflict" [ -d "$TS_MOUNTPOINT" ] || mkdir -p $TS_MOUNTPOINT LODEV=$( $TS_CMD_LOSETUP --find --nooverlap --show --offset=1000 "$BACKFILE" 2>> $TS_OUTPUT ) -$TS_CMD_MOUNT "$BACKFILE" "$TS_MOUNTPOINT" 2>&1 | sed 's/^.*\.img//' > $TS_OUTPUT +$TS_CMD_MOUNT "$BACKFILE" "$TS_MOUNTPOINT" 2>&1 \ + | sed 's/:.*:/: <target>/; s/for .*/for <source>/' > $TS_OUTPUT $TS_CMD_LOSETUP --detach $LODEV >> $TS_OUTPUT 2>&1 udevadm settle ts_log "Success" @@ -114,7 +115,8 @@ ts_init_subtest "o-loop-val-initialized" [ -d "$TS_MOUNTPOINT" ] || mkdir -p $TS_MOUNTPOINT LODEV=$( $TS_CMD_LOSETUP --find 2>> $TS_OUTPUT ) $TS_CMD_LOSETUP $LODEV "$BACKFILE" >> $TS_OUTPUT 2>&1 -$TS_CMD_MOUNT -oloop=$LODEV "$BACKFILE" "$TS_MOUNTPOINT" 2>&1 | sed 's/^.*\.img//' > $TS_OUTPUT +$TS_CMD_MOUNT -oloop=$LODEV "$BACKFILE" "$TS_MOUNTPOINT" 2>&1 \ + | sed 's/:.*:/: <target>/; s/for .*/for <source>/' > $TS_OUTPUT $TS_CMD_LOSETUP --detach $LODEV >> $TS_OUTPUT 2>&1 udevadm settle ts_log "Success" @@ -125,7 +127,8 @@ ts_init_subtest "o-loop-val-conflict" cp "$BACKFILE" "$BACKFILE"-2 LODEV=$( $TS_CMD_LOSETUP --find 2>> $TS_OUTPUT ) $TS_CMD_LOSETUP $LODEV "$BACKFILE"-2 >> $TS_OUTPUT 2>&1 -$TS_CMD_MOUNT -oloop=$LODEV "$BACKFILE" "$TS_MOUNTPOINT" 2>&1 | sed 's/^.*\.img//' > $TS_OUTPUT +$TS_CMD_MOUNT -oloop=$LODEV "$BACKFILE" "$TS_MOUNTPOINT" 2>&1 \ + | sed 's/:.*:/: <target>/; s/for .*/for <source>/' > $TS_OUTPUT $TS_CMD_LOSETUP --detach $LODEV >> $TS_OUTPUT 2>&1 rm "$BACKFILE"-2 udevadm settle diff --git a/tests/ts/libmount/loop-overlay b/tests/ts/libmount/loop-overlay index 97eb32118..dc9b73d6b 100755 --- a/tests/ts/libmount/loop-overlay +++ b/tests/ts/libmount/loop-overlay @@ -43,8 +43,8 @@ dd if="$IMG" of="$IMG" oflag=append bs=5MiB count=1 conv=notrunc &>/dev/null echo "second should fail" >>$TS_OUTPUT $TS_CMD_MOUNT -oloop "$IMG" "$TS_MOUNTPOINT-1" >> $TS_OUTPUT 2>&1 -$TS_CMD_MOUNT -oloop,offset=$OFFSET "$IMG" "$TS_MOUNTPOINT-2" 2>&1 | sed 's/.*://' >>$TS_OUTPUT - +$TS_CMD_MOUNT -oloop,offset=$OFFSET "$IMG" "$TS_MOUNTPOINT-2" 2>&1 \ + | sed 's/:.*:/: <target>/; s/for .*/for <source>/' >> $TS_OUTPUT $TS_CMD_UMOUNT "$TS_MOUNTPOINT-1" >> $TS_OUTPUT 2>&1 echo "should succeed" >>$TS_OUTPUT @@ -56,8 +56,10 @@ $TS_CMD_UMOUNT "$TS_MOUNTPOINT-2" >> $TS_OUTPUT 2>&1 echo "both should fail" >>$TS_OUTPUT LOOPDEV=$($TS_CMD_LOSETUP --find) $TS_CMD_LOSETUP --offset 1 --sizelimit $OFFSET $LOOPDEV "$IMG" -$TS_CMD_MOUNT -oloop,sizelimit=$OFFSET "$IMG" "$TS_MOUNTPOINT-1" 2>&1 | sed 's/.*://' >>$TS_OUTPUT -$TS_CMD_MOUNT -oloop,offset=$OFFSET "$IMG" "$TS_MOUNTPOINT-2" 2>&1 | sed 's/.*://' >>$TS_OUTPUT +$TS_CMD_MOUNT -oloop,sizelimit=$OFFSET "$IMG" "$TS_MOUNTPOINT-1" 2>&1 \ + | sed 's/:.*:/: <target>/; s/for .*/for <source>/' >> $TS_OUTPUT +$TS_CMD_MOUNT -oloop,offset=$OFFSET "$IMG" "$TS_MOUNTPOINT-2" 2>&1 \ + | sed 's/:.*:/: <target>/; s/for .*/for <source>/' >> $TS_OUTPUT $TS_CMD_LOSETUP --detach $LOOPDEV ts_log "Success" |