Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
Already on GitHub? Sign in to your account
Improve decoding of mount flags #172
Merged
Commits
Jump to file or symbol
Failed to load files and symbols.
| @@ -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; | ||
| +} |
| @@ -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
src/mount-opt.c
| @@ -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; | ||
| +} |
| @@ -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
src/quirks.c