summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-05-03 22:59:58 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-05-03 22:59:58 +0200
commit8b249bd09bc63ad3a9aa99cc268299f0239b2f7d (patch)
tree345d460dd10fdbb34bc6e6cc283fe51a33095391
parentabb5c890e0960fa00cb566a9905e13cba078972b (diff)
downloadserenity-8b249bd09bc63ad3a9aa99cc268299f0239b2f7d.zip
Kernel+Userland: Implement mknod() syscall and add a /bin/mknod program.
-rw-r--r--Kernel/FileSystem/Ext2FileSystem.cpp9
-rw-r--r--Kernel/FileSystem/Ext2FileSystem.h2
-rw-r--r--Kernel/FileSystem/FileSystem.h2
-rw-r--r--Kernel/FileSystem/ProcFS.cpp2
-rw-r--r--Kernel/FileSystem/ProcFS.h2
-rw-r--r--Kernel/FileSystem/SyntheticFileSystem.cpp2
-rw-r--r--Kernel/FileSystem/SyntheticFileSystem.h2
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.cpp30
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.h1
-rw-r--r--Kernel/Process.cpp8
-rw-r--r--Kernel/Process.h2
-rw-r--r--Kernel/Syscall.cpp2
-rw-r--r--Kernel/Syscall.h1
-rw-r--r--LibC/unistd.cpp6
-rw-r--r--Userland/mknod.cpp50
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;
+}