diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-05-03 22:59:58 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-05-03 22:59:58 +0200 |
commit | 8b249bd09bc63ad3a9aa99cc268299f0239b2f7d (patch) | |
tree | 345d460dd10fdbb34bc6e6cc283fe51a33095391 | |
parent | abb5c890e0960fa00cb566a9905e13cba078972b (diff) | |
download | serenity-8b249bd09bc63ad3a9aa99cc268299f0239b2f7d.zip |
Kernel+Userland: Implement mknod() syscall and add a /bin/mknod program.
-rw-r--r-- | Kernel/FileSystem/Ext2FileSystem.cpp | 9 | ||||
-rw-r--r-- | Kernel/FileSystem/Ext2FileSystem.h | 2 | ||||
-rw-r--r-- | Kernel/FileSystem/FileSystem.h | 2 | ||||
-rw-r--r-- | Kernel/FileSystem/ProcFS.cpp | 2 | ||||
-rw-r--r-- | Kernel/FileSystem/ProcFS.h | 2 | ||||
-rw-r--r-- | Kernel/FileSystem/SyntheticFileSystem.cpp | 2 | ||||
-rw-r--r-- | Kernel/FileSystem/SyntheticFileSystem.h | 2 | ||||
-rw-r--r-- | Kernel/FileSystem/VirtualFileSystem.cpp | 30 | ||||
-rw-r--r-- | Kernel/FileSystem/VirtualFileSystem.h | 1 | ||||
-rw-r--r-- | Kernel/Process.cpp | 8 | ||||
-rw-r--r-- | Kernel/Process.h | 2 | ||||
-rw-r--r-- | Kernel/Syscall.cpp | 2 | ||||
-rw-r--r-- | Kernel/Syscall.h | 1 | ||||
-rw-r--r-- | LibC/unistd.cpp | 6 | ||||
-rw-r--r-- | Userland/mknod.cpp | 50 |
15 files changed, 107 insertions, 14 deletions
diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index 094e09414f..b5161b6773 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -1064,7 +1064,7 @@ RetainPtr<Inode> Ext2FS::create_directory(InodeIdentifier parent_id, const Strin // NOTE: When creating a new directory, make the size 1 block. // There's probably a better strategy here, but this works for now. - auto inode = create_inode(parent_id, name, mode, block_size(), error); + auto inode = create_inode(parent_id, name, mode, block_size(), 0, error); if (!inode) return nullptr; @@ -1092,7 +1092,7 @@ RetainPtr<Inode> Ext2FS::create_directory(InodeIdentifier parent_id, const Strin return inode; } -RetainPtr<Inode> Ext2FS::create_inode(InodeIdentifier parent_id, const String& name, mode_t mode, off_t size, int& error) +RetainPtr<Inode> Ext2FS::create_inode(InodeIdentifier parent_id, const String& name, mode_t mode, off_t size, dev_t dev, int& error) { LOCKER(m_lock); ASSERT(parent_id.fsid() == fsid()); @@ -1168,6 +1168,11 @@ RetainPtr<Inode> Ext2FS::create_inode(InodeIdentifier parent_id, const String& n e2inode.i_dtime = 0; e2inode.i_links_count = initial_links_count; + if (is_character_device(mode)) + e2inode.i_block[0] = dev; + else if (is_block_device(mode)) + e2inode.i_block[1] = dev; + success = write_block_list_for_inode(inode_id, e2inode, blocks); ASSERT(success); diff --git a/Kernel/FileSystem/Ext2FileSystem.h b/Kernel/FileSystem/Ext2FileSystem.h index 3443c77c9c..a9b5fd02b8 100644 --- a/Kernel/FileSystem/Ext2FileSystem.h +++ b/Kernel/FileSystem/Ext2FileSystem.h @@ -92,7 +92,7 @@ private: virtual const char* class_name() const override; virtual InodeIdentifier root_inode() const override; - virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, mode_t, off_t size, int& error) override; + virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, mode_t, off_t size, dev_t, int& error) override; virtual RetainPtr<Inode> create_directory(InodeIdentifier parentInode, const String& name, mode_t, int& error) override; virtual RetainPtr<Inode> get_inode(InodeIdentifier) const override; diff --git a/Kernel/FileSystem/FileSystem.h b/Kernel/FileSystem/FileSystem.h index 575b93b083..9ba5efddbf 100644 --- a/Kernel/FileSystem/FileSystem.h +++ b/Kernel/FileSystem/FileSystem.h @@ -52,7 +52,7 @@ public: byte file_type { 0 }; }; - virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, mode_t, off_t size, int& error) = 0; + virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, mode_t, off_t size, dev_t, int& error) = 0; virtual RetainPtr<Inode> create_directory(InodeIdentifier parentInode, const String& name, mode_t, int& error) = 0; virtual RetainPtr<Inode> get_inode(InodeIdentifier) const = 0; diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index a16965913c..c9de62f2d7 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -754,7 +754,7 @@ const char* ProcFS::class_name() const return "ProcFS"; } -RetainPtr<Inode> ProcFS::create_inode(InodeIdentifier, const String&, mode_t, off_t, int&) +RetainPtr<Inode> ProcFS::create_inode(InodeIdentifier, const String&, mode_t, off_t, dev_t, int&) { kprintf("FIXME: Implement ProcFS::create_inode()?\n"); return { }; diff --git a/Kernel/FileSystem/ProcFS.h b/Kernel/FileSystem/ProcFS.h index d08af28db7..97a1314ecb 100644 --- a/Kernel/FileSystem/ProcFS.h +++ b/Kernel/FileSystem/ProcFS.h @@ -22,7 +22,7 @@ public: virtual InodeIdentifier root_inode() const override; virtual RetainPtr<Inode> get_inode(InodeIdentifier) const override; - virtual RetainPtr<Inode> create_inode(InodeIdentifier parent_id, const String& name, mode_t, off_t size, int& error) override; + virtual RetainPtr<Inode> create_inode(InodeIdentifier parent_id, const String& name, mode_t, off_t size, dev_t, int& error) override; virtual RetainPtr<Inode> create_directory(InodeIdentifier parent_id, const String& name, mode_t, int& error) override; void add_sys_file(String&&, Function<ByteBuffer(ProcFSInode&)>&& read_callback, Function<ssize_t(ProcFSInode&, const ByteBuffer&)>&& write_callback); diff --git a/Kernel/FileSystem/SyntheticFileSystem.cpp b/Kernel/FileSystem/SyntheticFileSystem.cpp index 222c66a03b..b7d96c7b7b 100644 --- a/Kernel/FileSystem/SyntheticFileSystem.cpp +++ b/Kernel/FileSystem/SyntheticFileSystem.cpp @@ -138,7 +138,7 @@ InodeIdentifier SynthFS::root_inode() const return { fsid(), 1 }; } -RetainPtr<Inode> SynthFS::create_inode(InodeIdentifier parentInode, const String& name, mode_t mode, off_t size, int& error) +RetainPtr<Inode> SynthFS::create_inode(InodeIdentifier parentInode, const String& name, mode_t mode, off_t size, dev_t, int& error) { (void) parentInode; (void) name; diff --git a/Kernel/FileSystem/SyntheticFileSystem.h b/Kernel/FileSystem/SyntheticFileSystem.h index f3619a1b1e..be786c6b0c 100644 --- a/Kernel/FileSystem/SyntheticFileSystem.h +++ b/Kernel/FileSystem/SyntheticFileSystem.h @@ -14,7 +14,7 @@ public: virtual bool initialize() override; virtual const char* class_name() const override; virtual InodeIdentifier root_inode() const override; - virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, mode_t, off_t size, int& error) override; + virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, mode_t, off_t size, dev_t, int& error) override; virtual RetainPtr<Inode> create_directory(InodeIdentifier parentInode, const String& name, mode_t, int& error) override; virtual RetainPtr<Inode> get_inode(InodeIdentifier) const override; diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 7b1087c9ad..ec8b32ef15 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -195,6 +195,32 @@ KResultOr<Retained<FileDescriptor>> VFS::open(StringView path, int options, mode return FileDescriptor::create(*inode); } +KResult VFS::mknod(StringView path, mode_t mode, dev_t dev, Inode& base) +{ + if (!is_regular_file(mode) && !is_block_device(mode) && !is_character_device(mode) && !is_fifo(mode) && !is_socket(mode)) + return KResult(-EINVAL); + + RetainPtr<Inode> parent_inode; + auto existing_file_or_error = resolve_path_to_inode(path, base, &parent_inode); + if (!existing_file_or_error.is_error()) + return KResult(-EEXIST); + if (!parent_inode) + return KResult(-ENOENT); + if (existing_file_or_error.error() != -ENOENT) + return existing_file_or_error.error(); + if (!parent_inode->metadata().may_write(current->process())) + return KResult(-EACCES); + + FileSystemPath p(path); + dbgprintf("VFS::mknod: '%s' mode=%o dev=%u in %u:%u\n", p.basename().characters(), mode, dev, parent_inode->fsid(), parent_inode->index()); + int error; + auto new_file = parent_inode->fs().create_inode(parent_inode->identifier(), p.basename(), mode, 0, dev, error); + if (!new_file) + return KResult(error); + + return KSuccess; +} + KResultOr<Retained<FileDescriptor>> VFS::create(StringView path, int options, mode_t mode, Inode& base) { (void)options; @@ -218,7 +244,7 @@ KResultOr<Retained<FileDescriptor>> VFS::create(StringView path, int options, mo FileSystemPath p(path); dbgprintf("VFS::create_file: '%s' in %u:%u\n", p.basename().characters(), parent_inode->fsid(), parent_inode->index()); int error; - auto new_file = parent_inode->fs().create_inode(parent_inode->identifier(), p.basename(), mode, 0, error); + auto new_file = parent_inode->fs().create_inode(parent_inode->identifier(), p.basename(), mode, 0, 0, error); if (!new_file) return KResult(error); @@ -469,7 +495,7 @@ KResult VFS::symlink(StringView target, StringView linkpath, Inode& base) FileSystemPath p(linkpath); dbgprintf("VFS::symlink: '%s' (-> '%s') in %u:%u\n", p.basename().characters(), target.characters(), parent_inode->fsid(), parent_inode->index()); int error; - auto new_file = parent_inode->fs().create_inode(parent_inode->identifier(), p.basename(), 0120644, 0, error); + auto new_file = parent_inode->fs().create_inode(parent_inode->identifier(), p.basename(), 0120644, 0, 0, error); if (!new_file) return KResult(error); ssize_t nwritten = new_file->write_bytes(0, target.length(), (const byte*)target.characters(), nullptr); diff --git a/Kernel/FileSystem/VirtualFileSystem.h b/Kernel/FileSystem/VirtualFileSystem.h index cdc4c8d405..16b0dafbad 100644 --- a/Kernel/FileSystem/VirtualFileSystem.h +++ b/Kernel/FileSystem/VirtualFileSystem.h @@ -76,6 +76,7 @@ public: KResult stat(StringView path, int options, Inode& base, struct stat&); KResult utime(StringView path, Inode& base, time_t atime, time_t mtime); KResult rename(StringView oldpath, StringView newpath, Inode& base); + KResult mknod(StringView path, mode_t, dev_t, Inode& base); KResultOr<Retained<Inode>> open_directory(StringView path, Inode& base); void register_device(Device&); diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 20bd664292..69c3061de6 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2553,3 +2553,11 @@ void Process::FileDescriptorAndFlags::set(Retained<FileDescriptor>&& d, dword f) descriptor = move(d); flags = f; } + +int Process::sys$mknod(const char* pathname, mode_t mode, dev_t dev) +{ + if (!validate_read_str(pathname)) + return -EFAULT; + + return VFS::the().mknod(StringView(pathname), mode, dev, cwd_inode()); +} diff --git a/Kernel/Process.h b/Kernel/Process.h index 1461f8992e..75d398a040 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -178,7 +178,7 @@ public: void sys$exit_thread(int code); int sys$rename(const char* oldpath, const char* newpath); int sys$systrace(pid_t); - + int sys$mknod(const char* pathname, mode_t, dev_t); int sys$create_shared_buffer(pid_t peer_pid, int, void** buffer); void* sys$get_shared_buffer(int shared_buffer_id); int sys$release_shared_buffer(int shared_buffer_id); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 90fd031ed6..8594072026 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -265,6 +265,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2, return current->process().sys$ftruncate((int)arg1, (off_t)arg2); case Syscall::SC_systrace: return current->process().sys$systrace((pid_t)arg1); + case Syscall::SC_mknod: + return current->process().sys$mknod((const char*)arg1, (mode_t)arg2, (dev_t)arg3); default: kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3); break; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 6bd55ce560..b1168c777a 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -101,6 +101,7 @@ __ENUMERATE_SYSCALL(ftruncate) \ __ENUMERATE_SYSCALL(systrace) \ __ENUMERATE_SYSCALL(exit_thread) \ + __ENUMERATE_SYSCALL(mknod) \ namespace Syscall { diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp index 88f4bca542..e07463d9bf 100644 --- a/LibC/unistd.cpp +++ b/LibC/unistd.cpp @@ -364,10 +364,10 @@ int access(const char* pathname, int mode) __RETURN_WITH_ERRNO(rc, rc, -1); } -int mknod(const char* pathname, mode_t, dev_t) +int mknod(const char* pathname, mode_t mode, dev_t dev) { - (void) pathname; - ASSERT_NOT_REACHED(); + int rc = syscall(SC_mknod, pathname, mode, dev); + __RETURN_WITH_ERRNO(rc, rc, -1); } long fpathconf(int fd, int name) diff --git a/Userland/mknod.cpp b/Userland/mknod.cpp new file mode 100644 index 0000000000..dc1221b51d --- /dev/null +++ b/Userland/mknod.cpp @@ -0,0 +1,50 @@ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> + +inline constexpr unsigned encoded_device(unsigned major, unsigned minor) +{ + return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); +} + +static int usage() +{ + printf("usage: mknod <name> <c|b|p> <major> <minor>\n"); + return 0; +} + +int main(int argc, char** argv) +{ + // FIXME: When invoked with type "p", no need for major/minor numbers. + // FIXME: Add some kind of option for specifying the file permissions. + if (argc != 5) + return usage(); + + const char* name = argv[1]; + mode_t mode = 0666; + switch (argv[2][0]) { + case 'c': + case 'u': + mode |= S_IFCHR; + break; + case 'b': + mode |= S_IFBLK; + break; + case 'p': + mode |= S_IFIFO; + break; + default: + return usage(); + } + + int major = atoi(argv[3]); + int minor = atoi(argv[4]); + + int rc = mknod(name, mode, encoded_device(major, minor)); + if (rc < 0) { + perror("mknod"); + return 1; + } + return 0; +} |