mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 23:58:12 +00:00
Kernel & Userland: Allow to mount image files formatted with Ext2FS
This commit is contained in:
parent
6b59311d4b
commit
a60ea79a41
8 changed files with 101 additions and 51 deletions
|
@ -5,6 +5,6 @@
|
||||||
/dev /dev bind bind,nosuid
|
/dev /dev bind bind,nosuid
|
||||||
/bin /bin bind bind,nodev
|
/bin /bin bind bind,nodev
|
||||||
|
|
||||||
proc /proc proc nosuid
|
none /proc proc nosuid
|
||||||
devpts /dev/pts devpts noexec,nosuid
|
none /dev/pts devpts noexec,nosuid
|
||||||
tmp /tmp tmp nodev,nosuid
|
none /tmp tmp nodev,nosuid
|
||||||
|
|
|
@ -7,12 +7,13 @@ mount - mount a filesystem
|
||||||
```**c++
|
```**c++
|
||||||
#include <unistd.h>
|
#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
|
## 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:
|
`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`).
|
* `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`.
|
* `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
|
For Ext2FS, `source_fd` must refer to an open file descriptor to a file containing
|
||||||
the other filesystems ignore the `source` argument (by convention, it should have the same
|
the filesystem image. This may be a device file or any other seekable file. All
|
||||||
value as `fs_type`).
|
the other filesystems ignore the `source_fd` — you can even pass an invalid file
|
||||||
|
descriptor such as -1.
|
||||||
|
|
||||||
The following `flags` are supported:
|
The following `flags` are supported:
|
||||||
|
|
||||||
|
@ -37,14 +39,22 @@ mounted file system.
|
||||||
|
|
||||||
### Bind mounts
|
### Bind mounts
|
||||||
|
|
||||||
If `MS_BIND` is specified in `flags`, `fs_type` is ignored and a bind mount is performed
|
If `MS_BIND` is specified in `flags`, `fs_type` is ignored and a bind mount is
|
||||||
instead. In this case `source` is treated as a path to a file or directory whose contents
|
performed instead. In this case, the file or directory specified by `source_fd`
|
||||||
are overlayed over `target`. This can be used as an alternative to symlinks or hardlinks.
|
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
|
## Errors
|
||||||
|
|
||||||
|
* `EFAULT`: The `fs_type` or `target` are invalid strings.
|
||||||
* `EPERM`: The current process does not have superuser privileges.
|
* `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.
|
All of the usual path resolution errors may also occur.
|
||||||
|
|
||||||
|
|
|
@ -12,18 +12,26 @@ $ mount
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
If invoked without any arguments, `mount` prints a list of all currently mounted filesystems.
|
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
|
If invoked as `mount -a`, `mount` mounts all the filesystems configured in
|
||||||
is normally done on system startup by [`SystemServer`(7)](../man7/SystemServer.md).
|
`/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
|
Otherwise, `mount` performs a single filesystem mount. Source should be a path
|
||||||
same meaning as in the [`mount`(2)](../man2/mount.md) syscall (if not specified, fstype
|
to a file containing the filesystem image. Target, and fstype have the same
|
||||||
defaults to `ext2`).
|
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
|
A special source value "none" is recognized, in which case
|
||||||
flag names (lowercase and without the `MS_` prefix). Additionally, the name `defaults` is
|
[`mount`(8)](mount.md) will not attempt to open the source as a file, and will
|
||||||
accepted and ignored.
|
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
|
## Files
|
||||||
|
|
||||||
|
|
|
@ -4011,14 +4011,18 @@ int Process::sys$mount(const Syscall::SC_mount_params* user_params)
|
||||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||||
return -EFAULT;
|
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 target = validate_and_copy_string_from_user(params.target);
|
||||||
auto fs_type = validate_and_copy_string_from_user(params.fs_type);
|
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;
|
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());
|
auto custody_or_error = VFS::the().resolve_path(target, current_directory());
|
||||||
if (custody_or_error.is_error())
|
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) {
|
if (params.flags & MS_BIND) {
|
||||||
// We're doing a bind mount.
|
// We're doing a bind mount.
|
||||||
auto source_or_error = VFS::the().resolve_path(source, current_directory());
|
if (description.is_null())
|
||||||
if (source_or_error.is_error())
|
return -EBADF;
|
||||||
return source_or_error.error();
|
ASSERT(description->custody());
|
||||||
auto& source_custody = source_or_error.value();
|
return VFS::the().bind_mount(*description->custody(), target_custody, params.flags);
|
||||||
return VFS::the().bind_mount(source_custody, target_custody, params.flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs_type == "ext2" || fs_type == "Ext2FS") {
|
if (fs_type == "ext2" || fs_type == "Ext2FS") {
|
||||||
auto source_or_error = VFS::the().open(source, O_RDWR, 0, current_directory());
|
if (description.is_null())
|
||||||
if (source_or_error.is_error())
|
return -EBADF;
|
||||||
return source_or_error.error();
|
ASSERT(description->custody());
|
||||||
|
if (!description->file().is_seekable()) {
|
||||||
auto* device = source_or_error.value()->device();
|
dbg() << "mount: this is not a seekable file";
|
||||||
if (!device || !device->is_block_device()) {
|
|
||||||
dbg() << "mount: this is not a BlockDevice";
|
|
||||||
return -ENODEV;
|
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") {
|
} else if (fs_type == "proc" || fs_type == "ProcFS") {
|
||||||
fs = ProcFS::create();
|
fs = ProcFS::create();
|
||||||
} else if (fs_type == "devpts" || fs_type == "DevPtsFS") {
|
} 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()) {
|
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;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = VFS::the().mount(fs.release_nonnull(), target_custody, params.flags);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -395,7 +395,7 @@ struct SC_rename_params {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_mount_params {
|
struct SC_mount_params {
|
||||||
StringArgument source;
|
int source_fd;
|
||||||
StringArgument target;
|
StringArgument target;
|
||||||
StringArgument fs_type;
|
StringArgument fs_type;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
|
@ -582,14 +582,15 @@ int reboot()
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__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;
|
errno = EFAULT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Syscall::SC_mount_params params {
|
Syscall::SC_mount_params params {
|
||||||
{ source, strlen(source) },
|
source_fd,
|
||||||
{ target, strlen(target) },
|
{ target, strlen(target) },
|
||||||
{ fs_type, strlen(fs_type) },
|
{ fs_type, strlen(fs_type) },
|
||||||
flags
|
flags
|
||||||
|
|
|
@ -129,7 +129,7 @@ int fchown(int fd, uid_t, gid_t);
|
||||||
int ftruncate(int fd, off_t length);
|
int ftruncate(int fd, off_t length);
|
||||||
int halt();
|
int halt();
|
||||||
int reboot();
|
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 umount(const char* mountpoint);
|
||||||
int pledge(const char* promises, const char* execpromises);
|
int pledge(const char* promises, const char* execpromises);
|
||||||
int unveil(const char* path, const char* permissions);
|
int unveil(const char* path, const char* permissions);
|
||||||
|
|
|
@ -27,8 +27,10 @@
|
||||||
#include <AK/JsonArray.h>
|
#include <AK/JsonArray.h>
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
#include <AK/JsonValue.h>
|
#include <AK/JsonValue.h>
|
||||||
|
#include <AK/Optional.h>
|
||||||
#include <LibCore/ArgsParser.h>
|
#include <LibCore/ArgsParser.h>
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -54,6 +56,27 @@ int parse_options(const StringView& options)
|
||||||
return flags;
|
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()
|
bool mount_all()
|
||||||
{
|
{
|
||||||
// Mount all filesystems listed in /etc/fstab.
|
// Mount all filesystems listed in /etc/fstab.
|
||||||
|
@ -86,7 +109,6 @@ bool mount_all()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* devname = parts[0].characters();
|
|
||||||
const char* mountpoint = parts[1].characters();
|
const char* mountpoint = parts[1].characters();
|
||||||
const char* fstype = parts[2].characters();
|
const char* fstype = parts[2].characters();
|
||||||
int flags = parts.size() >= 4 ? parse_options(parts[3]) : 0;
|
int flags = parts.size() >= 4 ? parse_options(parts[3]) : 0;
|
||||||
|
@ -96,11 +118,15 @@ bool mount_all()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg() << "Mounting " << devname << "(" << fstype << ")"
|
const char* filename = parts[0].characters();
|
||||||
|
|
||||||
|
int fd = get_source_fd(filename);
|
||||||
|
|
||||||
|
dbg() << "Mounting " << filename << "(" << fstype << ")"
|
||||||
<< " on " << mountpoint;
|
<< " on " << mountpoint;
|
||||||
int rc = mount(devname, mountpoint, fstype, flags);
|
int rc = mount(fd, mountpoint, fstype, flags);
|
||||||
if (rc != 0) {
|
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;
|
all_ok = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -179,7 +205,9 @@ int main(int argc, char** argv)
|
||||||
fs_type = "ext2";
|
fs_type = "ext2";
|
||||||
int flags = options ? parse_options(options) : 0;
|
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");
|
perror("mount");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue