cmd: add helpers for working with mount/umount commands #2814

Merged
merged 14 commits into from Feb 9, 2017
@@ -89,7 +89,123 @@ static void test_sc_mount_opt2str()
"ro,noexec,bind");
}
+static void test_sc_mount_cmd()
+{
+ char cmd[10000];
+
+ // Typical mount
+ sc_mount_cmd(cmd, sizeof cmd, "/dev/sda3", "/mnt", "ext4", MS_RDONLY,
+ NULL);
+ g_assert_cmpstr(cmd, ==, "mount -t ext4 -o ro /dev/sda3 /mnt");
+
+ // Bind mount
+ sc_mount_cmd(cmd, sizeof cmd, "/source", "/target", NULL, MS_BIND,
+ NULL);
+ g_assert_cmpstr(cmd, ==, "mount --bind /source /target");
+
+ // + recursive
+ sc_mount_cmd(cmd, sizeof cmd, "/source", "/target", NULL,
+ MS_BIND | MS_REC, NULL);
+ g_assert_cmpstr(cmd, ==, "mount --rbind /source /target");
+
+ // Shared subtree mount
+ sc_mount_cmd(cmd, sizeof cmd, "/place", "none", NULL, MS_SHARED, NULL);
+ g_assert_cmpstr(cmd, ==, "mount --make-shared /place");
+
+ sc_mount_cmd(cmd, sizeof cmd, "/place", "none", NULL, MS_SLAVE, NULL);
+ g_assert_cmpstr(cmd, ==, "mount --make-slave /place");
+
+ sc_mount_cmd(cmd, sizeof cmd, "/place", "none", NULL, MS_PRIVATE, NULL);
+ g_assert_cmpstr(cmd, ==, "mount --make-private /place");
+
+ sc_mount_cmd(cmd, sizeof cmd, "/place", "none", NULL, MS_UNBINDABLE,
+ NULL);
+ g_assert_cmpstr(cmd, ==, "mount --make-unbindable /place");
+
+ // + recursive
+ sc_mount_cmd(cmd, sizeof cmd, "/place", "none", NULL,
+ MS_SHARED | MS_REC, NULL);
+ g_assert_cmpstr(cmd, ==, "mount --make-rshared /place");
+
+ sc_mount_cmd(cmd, sizeof cmd, "/place", "none", NULL, MS_SLAVE | MS_REC,
+ NULL);
+ g_assert_cmpstr(cmd, ==, "mount --make-rslave /place");
+
+ sc_mount_cmd(cmd, sizeof cmd, "/place", "none", NULL,
+ MS_PRIVATE | MS_REC, NULL);
+ g_assert_cmpstr(cmd, ==, "mount --make-rprivate /place");
+
+ sc_mount_cmd(cmd, sizeof cmd, "/place", "none", NULL,
+ MS_UNBINDABLE | MS_REC, NULL);
+ g_assert_cmpstr(cmd, ==, "mount --make-runbindable /place");
+
+ // Move
+ sc_mount_cmd(cmd, sizeof cmd, "/from", "/to", NULL, MS_MOVE, NULL);
+ g_assert_cmpstr(cmd, ==, "mount --move /from /to");
+
+ // Monster (invalid but let's format it)
+ char from[PATH_MAX];
+ char to[PATH_MAX];
+ for (int i = 1; i < PATH_MAX - 1; ++i) {
+ from[i] = 'a';
+ to[i] = 'b';
+ }
+ from[0] = '/';
+ to[0] = '/';
+ from[PATH_MAX - 1] = 0;
+ to[PATH_MAX - 1] = 0;
+ int opts = MS_BIND | MS_MOVE | MS_SHARED | MS_SLAVE | MS_PRIVATE |
+ MS_UNBINDABLE | MS_REC | MS_RDONLY | MS_NOSUID | MS_NODEV |
+ MS_NOEXEC | MS_SYNCHRONOUS | MS_REMOUNT | MS_MANDLOCK | MS_DIRSYNC |
+ MS_NOATIME | MS_NODIRATIME | MS_BIND | MS_SILENT | MS_POSIXACL |
+ MS_RELATIME | MS_KERNMOUNT | MS_I_VERSION | MS_STRICTATIME |
+ MS_LAZYTIME;
+ const char *fstype = "fstype";
+ sc_mount_cmd(cmd, sizeof cmd, from, to, fstype, opts, NULL);
+ const char *expected =
+ "mount -t fstype "
+ "--rbind --move --make-rshared --make-rslave --make-rprivate --make-runbindable "
+ "-o ro,nosuid,nodev,noexec,sync,remount,mand,dirsync,noatime,nodiratime,silent,"
+ "acl,relatime,kernmount,iversion,strictatime,lazytime "
+ "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
+ "/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+ g_assert_cmpstr(cmd, ==, expected);
+}
+
+static void test_sc_umount_cmd()
+{
+ char cmd[1000];
+
+ // Typical umount
+ sc_umount_cmd(cmd, sizeof cmd, "/mnt/foo", 0);
+ g_assert_cmpstr(cmd, ==, "umount /mnt/foo");
+
+ // Force
+ sc_umount_cmd(cmd, sizeof cmd, "/mnt/foo", MNT_FORCE);
+ g_assert_cmpstr(cmd, ==, "umount --force /mnt/foo");
+
+ // Detach
+ sc_umount_cmd(cmd, sizeof cmd, "/mnt/foo", MNT_DETACH);
+ g_assert_cmpstr(cmd, ==, "umount --lazy /mnt/foo");
+
+ // Expire
+ sc_umount_cmd(cmd, sizeof cmd, "/mnt/foo", MNT_EXPIRE);
+ g_assert_cmpstr(cmd, ==, "umount --expire /mnt/foo");
+
+ // O_NOFOLLOW variant for umount
+ sc_umount_cmd(cmd, sizeof cmd, "/mnt/foo", UMOUNT_NOFOLLOW);
+ g_assert_cmpstr(cmd, ==, "umount --no-follow /mnt/foo");
+
+ // Everything at once
+ sc_umount_cmd(cmd, sizeof cmd, "/mnt/foo",
+ MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW);
+ g_assert_cmpstr(cmd, ==,
+ "umount --force --lazy --expire --no-follow /mnt/foo");
+}
+
static void __attribute__ ((constructor)) init()
{
g_test_add_func("/mount/sc_mount_opt2str", test_sc_mount_opt2str);
+ g_test_add_func("/mount/sc_mount_cmd", test_sc_mount_cmd);
+ g_test_add_func("/mount/sc_umount_cmd", test_sc_umount_cmd);
}
@@ -17,17 +17,19 @@
#include "mount-opt.h"
+#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
-#include "../libsnap-confine-private/utils.h"
-#include "../libsnap-confine-private/string-utils.h"
+#include "utils.h"
+#include "string-utils.h"
const char *sc_mount_opt2str(char *buf, size_t buf_size, unsigned long flags)
{
unsigned long used = 0;
- strcpy(buf, "");
+ sc_string_init(buf, buf_size);
#define F(FLAG, TEXT) do if (flags & (FLAG)) { sc_string_append(buf, buf_size, #TEXT ","); flags ^= (FLAG); } while (0)
F(MS_RDONLY, ro);
F(MS_NOSUID, nosuid);
@@ -115,3 +117,127 @@ const char *sc_mount_opt2str(char *buf, size_t buf_size, unsigned long flags)
}
return buf;
}
+
+const char *sc_mount_cmd(char *buf, size_t buf_size, const char *source, const char
+ *target, const char *fs_type, unsigned long mountflags, const
+ void *data)
+{
+ sc_string_init(buf, buf_size);
+ sc_string_append(buf, buf_size, "mount");
+
+ // Add filesysystem type if it's there and doesn't have the special value "none"
+ if (fs_type != NULL && strncmp(fs_type, "none", 5) != 0) {
+ sc_string_append(buf, buf_size, " -t ");
+ sc_string_append(buf, buf_size, fs_type);
+ }
+ // Check for some special, dedicated options, that aren't represented with
+ // the generic mount option argument (mount -o ...), by collecting those
+ // options that we will display as command line arguments in
+ // used_special_flags. This is used below to filter out these arguments
+ // from mount_flags when calling sc_mount_opt2str().
+ int used_special_flags = 0;
+
+ // Bind-ounts (bind)
+ if (mountflags & MS_BIND) {
+ if (mountflags & MS_REC) {
+ sc_string_append(buf, buf_size, " --rbind");
+ used_special_flags |= MS_REC;
+ } else {
+ sc_string_append(buf, buf_size, " --bind");
+ }
+ used_special_flags |= MS_BIND;
+ }
+ // Moving mount point location (move)
+ if (mountflags & MS_MOVE) {
+ sc_string_append(buf, buf_size, " --move");
+ used_special_flags |= MS_MOVE;
+ }
+ // Shared subtree operations (shared, slave, private, unbindable).
+ if (MS_SHARED & mountflags) {
+ if (mountflags & MS_REC) {
+ sc_string_append(buf, buf_size, " --make-rshared");
+ used_special_flags |= MS_REC;
+ } else {
+ sc_string_append(buf, buf_size, " --make-shared");
+ }
+ used_special_flags |= MS_SHARED;
+ }
+
+ if (MS_SLAVE & mountflags) {
+ if (mountflags & MS_REC) {
+ sc_string_append(buf, buf_size, " --make-rslave");
+ used_special_flags |= MS_REC;
+ } else {
+ sc_string_append(buf, buf_size, " --make-slave");
+ }
+ used_special_flags |= MS_SLAVE;
+ }
+
+ if (MS_PRIVATE & mountflags) {
+ if (mountflags & MS_REC) {
+ sc_string_append(buf, buf_size, " --make-rprivate");
+ used_special_flags |= MS_REC;
+ } else {
+ sc_string_append(buf, buf_size, " --make-private");
+ }
+ used_special_flags |= MS_PRIVATE;
+ }
+
+ if (MS_UNBINDABLE & mountflags) {
+ if (mountflags & MS_REC) {
+ sc_string_append(buf, buf_size, " --make-runbindable");
+ used_special_flags |= MS_REC;
+ } else {
+ sc_string_append(buf, buf_size, " --make-unbindable");
+ }
+ used_special_flags |= MS_UNBINDABLE;
+ }
+ // If regular option syntax exists then use it.
+ if (mountflags & ~used_special_flags) {
+ char opts_buf[1000];
+ sc_mount_opt2str(opts_buf, sizeof opts_buf, mountflags &
@jdstrand

jdstrand Feb 8, 2017

Contributor

Nitpick: sizeof(opts_buf) for style consistency.

@zyga

zyga Feb 9, 2017

Contributor

Aww, I really like the bare sizeof :-(

+ ~used_special_flags);
+ sc_string_append(buf, buf_size, " -o ");
+ sc_string_append(buf, buf_size, opts_buf);
+ }
+ // Add source and target locations
+ if (source != NULL && strncmp(source, "none", 5) != 0) {
+ sc_string_append(buf, buf_size, " ");
+ sc_string_append(buf, buf_size, source);
+ }
+ if (target != NULL && strncmp(target, "none", 5) != 0) {
+ sc_string_append(buf, buf_size, " ");
+ sc_string_append(buf, buf_size, target);
+ }
+
+ return buf;
+}
+
+const char *sc_umount_cmd(char *buf, size_t buf_size, const char *target,
+ int flags)
+{
+ sc_string_init(buf, buf_size);
+ sc_string_append(buf, buf_size, "umount");
+
+ if (flags & MNT_FORCE) {
+ sc_string_append(buf, buf_size, " --force");
+ }
+
+ if (flags & MNT_DETACH) {
+ sc_string_append(buf, buf_size, " --lazy");
+ }
+ if (flags & MNT_EXPIRE) {
+ // NOTE: there's no real command line option for MNT_EXPIRE
+ sc_string_append(buf, buf_size, " --expire");
+ }
+ if (flags & UMOUNT_NOFOLLOW) {
+ // NOTE: there's no real command line option for UMOUNT_NOFOLLOW
+ sc_string_append(buf, buf_size, " --no-follow");
+ }
+ if (target != NULL) {
+ sc_string_append(buf, buf_size, " ");
+ sc_string_append(buf, buf_size, target);
+ }
+
+ return buf;
+}
@@ -22,10 +22,42 @@
/**
* Convert flags for mount(2) system call to a string representation.
- *
- * The function uses an internal static buffer that is overwritten on each
- * request.
**/
const char *sc_mount_opt2str(char *buf, size_t buf_size, unsigned long flags);
+/**
+ * Compute an equivalent mount(8) command from mount(2) arguments.
+ *
+ * This function serves as a human-readable representation of the mount system
+ * call. The return value is a string that looks like a shell mount command.
+ *
+ * Note that the returned command is may not be a valid mount command. No
+ * sanity checking is performed on the mount flags, source or destination
+ * arguments.
+ *
+ * The returned value is always buf, it is provided as a convenience.
+ **/
+const char *sc_mount_cmd(char *buf, size_t buf_size, const char *source, const char
+ *target, const char *fs_type, unsigned long mountflags,
+ const void *data);
+
+/**
+ * Compute an equivalent umount(8) command from umount2(2) arguments.
+ *
+ * This function serves as a human-readable representation of the unmount
+ * system call. The return value is a string that looks like a shell unmount
+ * command.
+ *
+ * Note that some flags are not surfaced at umount command line level. For
+ * those flags a fake option is synthesized.
+ *
+ * Note that the returned command is may not be a valid umount command. No
+ * sanity checking is performed on the mount flags, source or destination
+ * arguments.
+ *
+ * The returned value is always buf, it is provided as a convenience.
+ **/
+const char *sc_umount_cmd(char *buf, size_t buf_size, const char *target,
+ int flags);
+
#endif // SNAP_CONFINE_MOUNT_OPT_H
Oops, something went wrong.