Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
Merge pull request #172 from snapcore/mount-flag-decode
Browse files Browse the repository at this point in the history
Improve decoding of mount flags
  • Loading branch information
zyga authored Oct 19, 2016
2 parents 6044791 + 0c0667d commit c27d10a
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 48 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ src/snap-confine
src/snap-discard-ns
src/snap-confine-unit-tests
src/snap-confine.apparmor
src/decode-mount-opts
*~
*.o

Expand Down
13 changes: 11 additions & 2 deletions src/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
libexec_PROGRAMS = snap-confine snap-discard-ns
noinst_PROGRAMS = decode-mount-opts
if WITH_UNIT_TESTS
noinst_PROGRAMS = snap-confine-unit-tests
noinst_PROGRAMS += snap-confine-unit-tests
endif

decode_mount_opts_SOURCES = \
decode-mount-opts.c \
mount-opt.c \
mount-opt.h

snap_discard_ns_SOURCES = \
ns-support.c \
ns-support.h \
Expand Down Expand Up @@ -52,6 +58,8 @@ snap_confine_SOURCES = \
user-support.h \
quirks.c \
quirks.h \
mount-opt.c \
mount-opt.h \
mountinfo.c \
mountinfo.h \
ns-support.c \
Expand Down Expand Up @@ -97,7 +105,8 @@ snap_confine_unit_tests_SOURCES = \
mount-support-test.c \
verify-executable-name-test.c \
mountinfo-test.c \
ns-support-test.c
ns-support-test.c \
mount-opt-test.c
snap_confine_unit_tests_CFLAGS = $(snap_confine_CFLAGS) $(GLIB_CFLAGS)
snap_confine_unit_tests_LDADD = $(snap_confine_LDADD) $(GLIB_LIBS)
snap_confine_unit_tests_LDFLAGS = $(snap_confine_LDFLAGS)
Expand Down
37 changes: 37 additions & 0 deletions src/decode-mount-opts.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2016 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include <stdio.h>
#include <stdlib.h>

#include "mount-opt.h"

int main(int argc, char *argv[])
{
if (argc != 2) {
printf("usage: decode-mount-opts OPT\n");
return 0;
}
char *end;
unsigned long mountflags = strtoul(argv[1], &end, 0);
if (*end != '\0') {
fprintf(stderr, "cannot parse given argument as a number\n");
return 1;
}
printf("%#lx is %s\n", mountflags, sc_mount_opt2str(mountflags));
return 0;
}
66 changes: 66 additions & 0 deletions src/mount-opt-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2016 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include "mount-opt.h"
#include "mount-opt.c"

#include <sys/mount.h>
#include <glib.h>

static void test_sc_mount_opt2str()
{
g_assert_cmpstr(sc_mount_opt2str(0), ==, "");
g_assert_cmpstr(sc_mount_opt2str(MS_RDONLY), ==, "ro");
g_assert_cmpstr(sc_mount_opt2str(MS_NOSUID), ==, "nosuid");
g_assert_cmpstr(sc_mount_opt2str(MS_NODEV), ==, "nodev");
g_assert_cmpstr(sc_mount_opt2str(MS_NOEXEC), ==, "noexec");
g_assert_cmpstr(sc_mount_opt2str(MS_SYNCHRONOUS), ==, "sync");
g_assert_cmpstr(sc_mount_opt2str(MS_REMOUNT), ==, "remount");
g_assert_cmpstr(sc_mount_opt2str(MS_MANDLOCK), ==, "mand");
g_assert_cmpstr(sc_mount_opt2str(MS_DIRSYNC), ==, "dirsync");
g_assert_cmpstr(sc_mount_opt2str(MS_NOATIME), ==, "noatime");
g_assert_cmpstr(sc_mount_opt2str(MS_NODIRATIME), ==, "nodiratime");
g_assert_cmpstr(sc_mount_opt2str(MS_BIND), ==, "bind");
g_assert_cmpstr(sc_mount_opt2str(MS_REC | MS_BIND), ==, "rbind");
g_assert_cmpstr(sc_mount_opt2str(MS_MOVE), ==, "move");
g_assert_cmpstr(sc_mount_opt2str(MS_SILENT), ==, "silent");
g_assert_cmpstr(sc_mount_opt2str(MS_POSIXACL), ==, "acl");
g_assert_cmpstr(sc_mount_opt2str(MS_UNBINDABLE), ==, "unbindable");
g_assert_cmpstr(sc_mount_opt2str(MS_PRIVATE), ==, "private");
g_assert_cmpstr(sc_mount_opt2str(MS_REC | MS_PRIVATE), ==, "rprivate");
g_assert_cmpstr(sc_mount_opt2str(MS_SLAVE), ==, "slave");
g_assert_cmpstr(sc_mount_opt2str(MS_REC | MS_SLAVE), ==, "rslave");
g_assert_cmpstr(sc_mount_opt2str(MS_SHARED), ==, "shared");
g_assert_cmpstr(sc_mount_opt2str(MS_REC | MS_SHARED), ==, "rshared");
g_assert_cmpstr(sc_mount_opt2str(MS_RELATIME), ==, "relatime");
g_assert_cmpstr(sc_mount_opt2str(MS_KERNMOUNT), ==, "kernmount");
g_assert_cmpstr(sc_mount_opt2str(MS_I_VERSION), ==, "iversion");
g_assert_cmpstr(sc_mount_opt2str(MS_STRICTATIME), ==, "strictatime");
g_assert_cmpstr(sc_mount_opt2str(MS_LAZYTIME), ==, "lazytime");
// MS_NOSEC is not defined in userspace
// MS_BORN is not defined in userspace
g_assert_cmpstr(sc_mount_opt2str(MS_ACTIVE), ==, "active");
g_assert_cmpstr(sc_mount_opt2str(MS_NOUSER), ==, "nouser");
g_assert_cmpstr(sc_mount_opt2str(0x300), ==, "0x300");
// random compositions do work
g_assert_cmpstr(sc_mount_opt2str(MS_RDONLY | MS_NOEXEC | MS_BIND), ==, "ro,noexec,bind");
}

static void __attribute__ ((constructor)) init()
{
g_test_add_func("/mount/sc_mount_opt2str", test_sc_mount_opt2str);
}
112 changes: 112 additions & 0 deletions src/mount-opt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright (C) 2016 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include "mount-opt.h"

#include <stdio.h>
#include <string.h>
#include <sys/mount.h>

const char *sc_mount_opt2str(unsigned long flags)
{
static char buf[1000];
unsigned long used = 0;
strcpy(buf, "");
#define F(FLAG, TEXT) do if (flags & (FLAG)) { strcat(buf, #TEXT ","); flags ^= (FLAG); } while (0)
F(MS_RDONLY, ro);
F(MS_NOSUID, nosuid);
F(MS_NODEV, nodev);
F(MS_NOEXEC, noexec);
F(MS_SYNCHRONOUS, sync);
F(MS_REMOUNT, remount);
F(MS_MANDLOCK, mand);
F(MS_DIRSYNC, dirsync);
F(MS_NOATIME, noatime);
F(MS_NODIRATIME, nodiratime);
if (flags & MS_BIND) {
if (flags & MS_REC) {
strcat(buf, "rbind,");
used |= MS_REC;
} else {
strcat(buf, "bind,");
}
flags ^= MS_BIND;
}
F(MS_MOVE, move);
// The MS_REC flag handled separately by affected flags (MS_BIND,
// MS_PRIVATE, MS_SLAVE, MS_SHARED)
// XXX: kernel has MS_VERBOSE, glibc has MS_SILENT, both use the same constant
F(MS_SILENT, silent);
F(MS_POSIXACL, acl);
F(MS_UNBINDABLE, unbindable);
if (flags & MS_PRIVATE) {
if (flags & MS_REC) {
strcat(buf, "rprivate,");
used |= MS_REC;
} else {
strcat(buf, "private,");
}
flags ^= MS_PRIVATE;
}
if (flags & MS_SLAVE) {
if (flags & MS_REC) {
strcat(buf, "rslave,");
used |= MS_REC;
} else {
strcat(buf, "slave,");
}
flags ^= MS_SLAVE;
}
if (flags & MS_SHARED) {
if (flags & MS_REC) {
strcat(buf, "rshared,");
used |= MS_REC;
} else {
strcat(buf, "shared,");
}
flags ^= MS_SHARED;
}
flags ^= used; // this is just for MS_REC
F(MS_RELATIME, relatime);
F(MS_KERNMOUNT, kernmount);
F(MS_I_VERSION, iversion);
F(MS_STRICTATIME, strictatime);
F(MS_LAZYTIME, lazytime);
#ifndef MS_NOSEC
#define MS_NOSEC (1 << 28)
#endif
F(MS_NOSEC, nosec);
#ifndef MS_BORN
#define MS_BORN (1 << 29)
#endif
F(MS_BORN, born);
F(MS_ACTIVE, active);
F(MS_NOUSER, nouser);
#undef F
// Render any flags that are unaccounted for.
if (flags) {
char of[128];
sprintf(of, "%#lx", flags);
strcat(buf, of);
}
// Chop the excess comma from the end.
size_t len = strlen(buf);
if (len > 0 && buf[len - 1] == ',') {
buf[len - 1] = 0;
}
return buf;
}
29 changes: 29 additions & 0 deletions src/mount-opt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2016 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef SNAP_CONFINE_MOUNT_OPT_H
#define SNAP_CONFINE_MOUNT_OPT_H

/**
* 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(unsigned long flags);

#endif // SNAP_CONFINE_MOUNT_OPT_H
48 changes: 2 additions & 46 deletions src/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "utils.h"
#include "cleanup-funcs.h"
#include "classic.h"
#include "mount-opt.h"
// XXX: for smaller patch, this should be in utils.h later
#include "user-support.h"

Expand Down Expand Up @@ -73,51 +74,6 @@ static void sc_quirk_setup_tmpfs(const char *dirname)
};
}

const char *mount_flags_to_string(unsigned flags)
{
static char buf[1000];
strcpy(buf, "");
if (flags & MS_BIND) {
if (flags & MS_REC) {
strcat(buf, "rbind,");
} else {
strcat(buf, "bind,");
}
}
if (flags & MS_PRIVATE) {
if (flags & MS_REC) {
strcat(buf, "rprivate,");
} else {
strcat(buf, "private,");
}
}
if (flags & MS_SLAVE) {
if (flags & MS_REC) {
strcat(buf, "rslave,");
} else {
strcat(buf, "slave,");
}
}
if (flags & MS_SHARED) {
if (flags & MS_REC) {
strcat(buf, "rshared,");
} else {
strcat(buf, "shared,");
}
}
if (flags & MS_MOVE) {
strcat(buf, "move,");
}
if (flags & MS_UNBINDABLE) {
strcat(buf, "unbindable,");
}
size_t len = strlen(buf);
if (len > 0 && buf[len - 1] == ',') {
buf[len - 1] = 0;
}
return buf;
}

/**
* Create an empty directory and bind mount something there.
*
Expand All @@ -131,7 +87,7 @@ static void sc_quirk_mkdir_bind(const char *src_dir, const char *dest_dir,
flags |= MS_BIND;
debug("creating empty directory at %s", dest_dir);
mkpath(dest_dir);
const char *flags_str = mount_flags_to_string(flags);
const char *flags_str = sc_mount_opt2str(flags);
debug("performing operation: mount %s %s -o %s", src_dir, dest_dir,
flags_str);
if (mount(src_dir, dest_dir, NULL, flags, NULL) != 0) {
Expand Down

0 comments on commit c27d10a

Please sign in to comment.