diff options
author | Liav A <liavalb@gmail.com> | 2020-03-26 02:51:16 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-02 12:03:08 +0200 |
commit | a60ea79a41845767ce40f225de20da7c99534ad1 (patch) | |
tree | 771b082c27a3cf8060fb23a8548be83ec8837677 | |
parent | 6b59311d4bdc1447e085573f9bd2c42819e264dd (diff) | |
download | serenity-a60ea79a41845767ce40f225de20da7c99534ad1.zip |
Kernel & Userland: Allow to mount image files formatted with Ext2FS
-rw-r--r-- | Base/etc/fstab | 6 | ||||
-rw-r--r-- | Base/usr/share/man/man2/mount.md | 28 | ||||
-rw-r--r-- | Base/usr/share/man/man8/mount.md | 32 | ||||
-rw-r--r-- | Kernel/Process.cpp | 43 | ||||
-rw-r--r-- | Kernel/Syscall.h | 2 | ||||
-rw-r--r-- | Libraries/LibC/unistd.cpp | 7 | ||||
-rw-r--r-- | Libraries/LibC/unistd.h | 2 | ||||
-rw-r--r-- | Userland/mount.cpp | 38 |
8 files changed, 104 insertions, 54 deletions
diff --git a/Base/etc/fstab b/Base/etc/fstab index 08b414ddec..a80aefc78a 100644 --- a/Base/etc/fstab +++ b/Base/etc/fstab @@ -5,6 +5,6 @@ /dev /dev bind bind,nosuid /bin /bin bind bind,nodev -proc /proc proc nosuid -devpts /dev/pts devpts noexec,nosuid -tmp /tmp tmp nodev,nosuid +none /proc proc nosuid +none /dev/pts devpts noexec,nosuid +none /tmp tmp nodev,nosuid diff --git a/Base/usr/share/man/man2/mount.md b/Base/usr/share/man/man2/mount.md index 1d54e6be2c..5f69543802 100644 --- a/Base/usr/share/man/man2/mount.md +++ b/Base/usr/share/man/man2/mount.md @@ -7,12 +7,13 @@ mount - mount a filesystem ```**c++ #include <unistd.h> -int mount(const char* source, const char* target, const char* fs_type, int flags); +int mount(int source_fd, const char* target, const char* fs_type, int flags); ``` ## Description -`mount()` mounts a filesystem stored at `source` by overlaying its contents over `target`. +`mount()` mounts a filesystem stored at `source_fd` by overlaying its contents +over `target`. `fs_type` must be one of the following supported filesystems: @@ -21,9 +22,10 @@ int mount(const char* source, const char* target, const char* fs_type, int flags * `DevPtsFS` (or `devpts`): The pseudoterminal pseudo-filesystem (normally mounted at `/dev/pts`). * `TmpFS` (or `tmp`): A non-persistent filesystem that stores all its data in RAM. An instance of this filesystem is normally mounted at `/tmp`. -For Ext2FS, `source` must be a path to a block device storing the filesystem contents. All -the other filesystems ignore the `source` argument (by convention, it should have the same -value as `fs_type`). +For Ext2FS, `source_fd` must refer to an open file descriptor to a file containing +the filesystem image. This may be a device file or any other seekable file. All +the other filesystems ignore the `source_fd` — you can even pass an invalid file +descriptor such as -1. The following `flags` are supported: @@ -37,14 +39,22 @@ mounted file system. ### Bind mounts -If `MS_BIND` is specified in `flags`, `fs_type` is ignored and a bind mount is performed -instead. In this case `source` is treated as a path to a file or directory whose contents -are overlayed over `target`. This can be used as an alternative to symlinks or hardlinks. +If `MS_BIND` is specified in `flags`, `fs_type` is ignored and a bind mount is +performed instead. In this case, the file or directory specified by `source_fd` +is overlayed over `target` — the target appears to be replaced by a copy of the +source. This can be used as an alternative to symlinks or hardlinks. ## Errors +* `EFAULT`: The `fs_type` or `target` are invalid strings. * `EPERM`: The current process does not have superuser privileges. -* `ENODEV`: The `fs_type` is unrecognized, or the device is not found, or the device doesn't contain a valid filesystem image. +* `ENODEV`: The `fs_type` is unrecognized, or the file descriptor to source is + not found, or the source doesn't contain a valid filesystem image. Also, this + error occurs if `fs_type` is valid, but the file descriptor from `source_fd` + is not seekable. +* `EBADF`: If the `source_fd` is not valid, and either `fs_type` specifies a + file-backed filesystem (and not a pseudo filesystem), or `MS_BIND` is + specified in flags. All of the usual path resolution errors may also occur. diff --git a/Base/usr/share/man/man8/mount.md b/Base/usr/share/man/man8/mount.md index 7f0b9c2c4b..f63d45cf23 100644 --- a/Base/usr/share/man/man8/mount.md +++ b/Base/usr/share/man/man8/mount.md @@ -12,18 +12,26 @@ $ mount ## Description -If invoked without any arguments, `mount` prints a list of all currently mounted filesystems. - -If invoked as `mount -a`, `mount` mounts all the filesystems configured in `/etc/fstab`. This -is normally done on system startup by [`SystemServer`(7)](../man7/SystemServer.md). - -Otherwise, `mount` performs a single filesystem mount. Source, target, and fstype have the -same meaning as in the [`mount`(2)](../man2/mount.md) syscall (if not specified, fstype -defaults to `ext2`). - -Options correspond to the mount flags, and should be specified as a comma-separated list of -flag names (lowercase and without the `MS_` prefix). Additionally, the name `defaults` is -accepted and ignored. +If invoked without any arguments, `mount` prints a list of all currently mounted +filesystems. + +If invoked as `mount -a`, `mount` mounts all the filesystems configured in +`/etc/fstab`. This is normally done on system startup by +[`SystemServer`(7)](../man7/SystemServer.md). + +Otherwise, `mount` performs a single filesystem mount. Source should be a path +to a file containing the filesystem image. Target, and fstype have the same +meaning as in the [`mount`(2)](../man2/mount.md) syscall (if not specified, +fstype defaults to `ext2`). + +A special source value "none" is recognized, in which case +[`mount`(8)](mount.md) will not attempt to open the source as a file, and will +pass an invalid file descriptor to [`mount`(2)](../man2/mount.md). This is +useful for mounting pseudo filesystems. + +Options correspond to the mount flags, and should be specified as a +comma-separated list of flag names (lowercase and without the `MS_` prefix). +Additionally, the name `defaults` is accepted and ignored. ## Files diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 054b987e50..28aca99bcb 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -4011,14 +4011,18 @@ int Process::sys$mount(const Syscall::SC_mount_params* user_params) if (!validate_read_and_copy_typed(¶ms, user_params)) return -EFAULT; - auto source = validate_and_copy_string_from_user(params.source); + auto source_fd = params.source_fd; auto target = validate_and_copy_string_from_user(params.target); auto fs_type = validate_and_copy_string_from_user(params.fs_type); - if (source.is_null() || target.is_null() || fs_type.is_null()) + if (target.is_null() || fs_type.is_null()) return -EFAULT; - dbg() << "mount " << fs_type << ": source " << source << " @ " << target; + auto description = file_description(source_fd); + if (!description.is_null()) + dbg() << "mount " << fs_type << ": source fd " << source_fd << " @ " << target; + else + dbg() << "mount " << fs_type << " @ " << target; auto custody_or_error = VFS::the().resolve_path(target, current_directory()); if (custody_or_error.is_error()) @@ -4030,28 +4034,24 @@ int Process::sys$mount(const Syscall::SC_mount_params* user_params) if (params.flags & MS_BIND) { // We're doing a bind mount. - auto source_or_error = VFS::the().resolve_path(source, current_directory()); - if (source_or_error.is_error()) - return source_or_error.error(); - auto& source_custody = source_or_error.value(); - return VFS::the().bind_mount(source_custody, target_custody, params.flags); + if (description.is_null()) + return -EBADF; + ASSERT(description->custody()); + return VFS::the().bind_mount(*description->custody(), target_custody, params.flags); } if (fs_type == "ext2" || fs_type == "Ext2FS") { - auto source_or_error = VFS::the().open(source, O_RDWR, 0, current_directory()); - if (source_or_error.is_error()) - return source_or_error.error(); - - auto* device = source_or_error.value()->device(); - if (!device || !device->is_block_device()) { - dbg() << "mount: this is not a BlockDevice"; + if (description.is_null()) + return -EBADF; + ASSERT(description->custody()); + if (!description->file().is_seekable()) { + dbg() << "mount: this is not a seekable file"; return -ENODEV; } - auto& block_device = static_cast<BlockDevice&>(*device); - dbg() << "mount: attempting to mount " << block_device.absolute_path() << " on " << target; + dbg() << "mount: attempting to mount " << description->absolute_path() << " on " << target; - fs = Ext2FS::create(block_device); + fs = Ext2FS::create(*description); } else if (fs_type == "proc" || fs_type == "ProcFS") { fs = ProcFS::create(); } else if (fs_type == "devpts" || fs_type == "DevPtsFS") { @@ -4063,12 +4063,15 @@ int Process::sys$mount(const Syscall::SC_mount_params* user_params) } if (!fs->initialize()) { - dbg() << "mount: failed to initialize " << fs_type << " filesystem on " << source; + dbg() << "mount: failed to initialize " << fs_type << " filesystem, fd - " << source_fd; return -ENODEV; } auto result = VFS::the().mount(fs.release_nonnull(), target_custody, params.flags); - dbg() << "mount: successfully mounted " << source << " on " << target; + if (!description.is_null()) + dbg() << "mount: successfully mounted " << description->absolute_path() << " on " << target; + else + dbg() << "mount: successfully mounted " << target; return result; } diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index cfb072c650..d3167bff87 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -395,7 +395,7 @@ struct SC_rename_params { }; struct SC_mount_params { - StringArgument source; + int source_fd; StringArgument target; StringArgument fs_type; int flags; diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index cd17c7ae83..10fffdd1a1 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -582,14 +582,15 @@ int reboot() __RETURN_WITH_ERRNO(rc, rc, -1); } -int mount(const char* source, const char* target, const char* fs_type, int flags) +int mount(int source_fd, const char* target, const char* fs_type, int flags) { - if (!source || !target || !fs_type) { + if (!target || !fs_type) { errno = EFAULT; return -1; } + Syscall::SC_mount_params params { - { source, strlen(source) }, + source_fd, { target, strlen(target) }, { fs_type, strlen(fs_type) }, flags diff --git a/Libraries/LibC/unistd.h b/Libraries/LibC/unistd.h index 2566abfdfd..bf8e80068c 100644 --- a/Libraries/LibC/unistd.h +++ b/Libraries/LibC/unistd.h @@ -129,7 +129,7 @@ int fchown(int fd, uid_t, gid_t); int ftruncate(int fd, off_t length); int halt(); int reboot(); -int mount(const char* source, const char* target, const char* fs_type, int flags); +int mount(int source_fd, const char* target, const char* fs_type, int flags); int umount(const char* mountpoint); int pledge(const char* promises, const char* execpromises); int unveil(const char* path, const char* permissions); diff --git a/Userland/mount.cpp b/Userland/mount.cpp index 314588a197..195d744056 100644 --- a/Userland/mount.cpp +++ b/Userland/mount.cpp @@ -27,8 +27,10 @@ #include <AK/JsonArray.h> #include <AK/JsonObject.h> #include <AK/JsonValue.h> +#include <AK/Optional.h> #include <LibCore/ArgsParser.h> #include <LibCore/File.h> +#include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> @@ -54,6 +56,27 @@ int parse_options(const StringView& options) return flags; } +bool is_source_none(const char* source) +{ + return !strcmp("none", source); +} + +int get_source_fd(const char* source) +{ + if (is_source_none(source)) + return -1; + int fd = open(source, O_RDWR); + if (fd < 0) + fd = open(source, O_RDONLY); + if (fd < 0) { + int saved_errno = errno; + auto message = String::format("Failed to open: %s\n", source); + errno = saved_errno; + perror(message.characters()); + } + return fd; +} + bool mount_all() { // Mount all filesystems listed in /etc/fstab. @@ -86,7 +109,6 @@ bool mount_all() continue; } - const char* devname = parts[0].characters(); const char* mountpoint = parts[1].characters(); const char* fstype = parts[2].characters(); int flags = parts.size() >= 4 ? parse_options(parts[3]) : 0; @@ -96,11 +118,15 @@ bool mount_all() continue; } - dbg() << "Mounting " << devname << "(" << fstype << ")" + const char* filename = parts[0].characters(); + + int fd = get_source_fd(filename); + + dbg() << "Mounting " << filename << "(" << fstype << ")" << " on " << mountpoint; - int rc = mount(devname, mountpoint, fstype, flags); + int rc = mount(fd, mountpoint, fstype, flags); if (rc != 0) { - fprintf(stderr, "Failed to mount %s (%s) on %s: %s\n", devname, fstype, mountpoint, strerror(errno)); + fprintf(stderr, "Failed to mount %s (FD: %d) (%s) on %s: %s\n", filename, fd, fstype, mountpoint, strerror(errno)); all_ok = false; continue; } @@ -179,7 +205,9 @@ int main(int argc, char** argv) fs_type = "ext2"; int flags = options ? parse_options(options) : 0; - if (mount(source, mountpoint, fs_type, flags) < 0) { + int fd = get_source_fd(source); + + if (mount(fd, mountpoint, fs_type, flags) < 0) { perror("mount"); return 1; } |