mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 04:32:44 +00:00 
			
		
		
		
	Add a /dev/pts filesystem and make PTY allocation dynamic.
You can now open as many PTY pairs as you like. Well, it's actually capped at 8 for now, but it's just a constant and trivial to change. Unregistering a PTY pair is untested because I didn't want to start mucking with that in Terminal right now.
This commit is contained in:
		
							parent
							
								
									c30e2c8d44
								
							
						
					
					
						commit
						e9b948103d
					
				
					 12 changed files with 124 additions and 20 deletions
				
			
		
							
								
								
									
										67
									
								
								Kernel/DevPtsFS.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								Kernel/DevPtsFS.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,67 @@ | ||||||
|  | #include "DevPtsFS.h" | ||||||
|  | #include <Kernel/VirtualFileSystem.h> | ||||||
|  | #include <AK/StringBuilder.h> | ||||||
|  | 
 | ||||||
|  | static DevPtsFS* s_the; | ||||||
|  | 
 | ||||||
|  | DevPtsFS& DevPtsFS::the() | ||||||
|  | { | ||||||
|  |     ASSERT(s_the); | ||||||
|  |     return *s_the; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | RetainPtr<DevPtsFS> DevPtsFS::create() | ||||||
|  | { | ||||||
|  |     return adopt(*new DevPtsFS); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DevPtsFS::DevPtsFS() | ||||||
|  | { | ||||||
|  |     s_the = this; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DevPtsFS::~DevPtsFS() | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool DevPtsFS::initialize() | ||||||
|  | { | ||||||
|  |     SynthFS::initialize(); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* DevPtsFS::class_name() const | ||||||
|  | { | ||||||
|  |     return "DevPtsFS"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | RetainPtr<SynthFSInode> DevPtsFS::create_slave_pty_device_file(unsigned index) | ||||||
|  | { | ||||||
|  |     auto file = adopt(*new SynthFSInode(*this, generate_inode_index())); | ||||||
|  | 
 | ||||||
|  |     StringBuilder builder; | ||||||
|  |     builder.appendf("%u", index); | ||||||
|  |     file->m_name = builder.build(); | ||||||
|  | 
 | ||||||
|  |     file->m_metadata.size = 0; | ||||||
|  |     file->m_metadata.uid = 0; | ||||||
|  |     file->m_metadata.gid = 0; | ||||||
|  |     file->m_metadata.mode = 0020666; | ||||||
|  |     file->m_metadata.majorDevice = 11; | ||||||
|  |     file->m_metadata.minorDevice = index; | ||||||
|  |     file->m_metadata.mtime = mepoch; | ||||||
|  |     return file; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DevPtsFS::register_slave_pty(SlavePTY& slave_pty) | ||||||
|  | { | ||||||
|  |     InterruptDisabler disabler; | ||||||
|  |     auto inode_id = add_file(create_slave_pty_device_file(slave_pty.index())); | ||||||
|  |     slave_pty.set_devpts_inode_id(inode_id); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DevPtsFS::unregister_slave_pty(SlavePTY& slave_pty) | ||||||
|  | { | ||||||
|  |     InterruptDisabler disabler; | ||||||
|  |     remove_file(slave_pty.devpts_inode_id().index()); | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								Kernel/DevPtsFS.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Kernel/DevPtsFS.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "SlavePTY.h" | ||||||
|  | #include <AK/Types.h> | ||||||
|  | #include <Kernel/SyntheticFileSystem.h> | ||||||
|  | 
 | ||||||
|  | class Process; | ||||||
|  | 
 | ||||||
|  | class DevPtsFS final : public SynthFS { | ||||||
|  | public: | ||||||
|  |     static DevPtsFS& the() PURE; | ||||||
|  | 
 | ||||||
|  |     virtual ~DevPtsFS() override; | ||||||
|  |     static RetainPtr<DevPtsFS> create(); | ||||||
|  | 
 | ||||||
|  |     virtual bool initialize() override; | ||||||
|  |     virtual const char* class_name() const override; | ||||||
|  | 
 | ||||||
|  |     void register_slave_pty(SlavePTY&); | ||||||
|  |     void unregister_slave_pty(SlavePTY&); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     DevPtsFS(); | ||||||
|  | 
 | ||||||
|  |     RetainPtr<SynthFSInode> create_slave_pty_device_file(unsigned index); | ||||||
|  | 
 | ||||||
|  |     HashTable<SlavePTY*> m_slave_ptys; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | @ -29,6 +29,7 @@ KERNEL_OBJS = \ | ||||||
|        ELFImage.o \
 |        ELFImage.o \
 | ||||||
|        ELFLoader.o \
 |        ELFLoader.o \
 | ||||||
|        KSyms.o \
 |        KSyms.o \
 | ||||||
|  |        DevPtsFS.o \
 | ||||||
|        PS2MouseDevice.o \
 |        PS2MouseDevice.o \
 | ||||||
|        GUIEventDevice.o |        GUIEventDevice.o | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,6 @@ MasterPTY::MasterPTY(unsigned index) | ||||||
|     , m_slave(*new SlavePTY(*this, index)) |     , m_slave(*new SlavePTY(*this, index)) | ||||||
|     , m_index(index) |     , m_index(index) | ||||||
| { | { | ||||||
|     VFS::the().register_character_device(m_slave); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MasterPTY::~MasterPTY() | MasterPTY::~MasterPTY() | ||||||
|  | @ -16,7 +15,7 @@ MasterPTY::~MasterPTY() | ||||||
| String MasterPTY::pts_name() const | String MasterPTY::pts_name() const | ||||||
| { | { | ||||||
|     char buffer[32]; |     char buffer[32]; | ||||||
|     ksprintf(buffer, "/dev/pts%u", m_index); |     ksprintf(buffer, "/dev/pts/%u", m_index); | ||||||
|     return buffer; |     return buffer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,12 +2,14 @@ | ||||||
| #include "MasterPTY.h" | #include "MasterPTY.h" | ||||||
| #include <LibC/errno_numbers.h> | #include <LibC/errno_numbers.h> | ||||||
| 
 | 
 | ||||||
|  | static const unsigned s_max_pty_pairs = 8; | ||||||
|  | 
 | ||||||
| PTYMultiplexer::PTYMultiplexer() | PTYMultiplexer::PTYMultiplexer() | ||||||
|     : CharacterDevice(5, 2) |     : CharacterDevice(5, 2) | ||||||
| { | { | ||||||
|     m_freelist.ensure_capacity(4); |     m_freelist.ensure_capacity(s_max_pty_pairs); | ||||||
|     for (int i = 4; i > 0; --i) |     for (int i = s_max_pty_pairs; i > 0; --i) | ||||||
|         m_freelist.unchecked_append(adopt(*new MasterPTY(i - 1))); |         m_freelist.unchecked_append(i - 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| PTYMultiplexer::~PTYMultiplexer() | PTYMultiplexer::~PTYMultiplexer() | ||||||
|  | @ -21,7 +23,8 @@ RetainPtr<FileDescriptor> PTYMultiplexer::open(int& error, int options) | ||||||
|         error = -EBUSY; |         error = -EBUSY; | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|     auto master = m_freelist.take_last(); |     auto master_index = m_freelist.take_last(); | ||||||
|  |     auto master = adopt(*new MasterPTY(master_index)); | ||||||
|     dbgprintf("PTYMultiplexer::open: Vending master %u\n", master->index()); |     dbgprintf("PTYMultiplexer::open: Vending master %u\n", master->index()); | ||||||
|     return VFS::the().open(move(master), error, options); |     return VFS::the().open(move(master), error, options); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -23,5 +23,5 @@ private: | ||||||
|     virtual const char* class_name() const override { return "PTYMultiplexer"; } |     virtual const char* class_name() const override { return "PTYMultiplexer"; } | ||||||
| 
 | 
 | ||||||
|     Lock m_lock; |     Lock m_lock; | ||||||
|     Vector<RetainPtr<MasterPTY>> m_freelist; |     Vector<unsigned> m_freelist; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,22 +1,26 @@ | ||||||
| #include "SlavePTY.h" | #include "SlavePTY.h" | ||||||
| #include "MasterPTY.h" | #include "MasterPTY.h" | ||||||
|  | #include "DevPtsFS.h" | ||||||
| 
 | 
 | ||||||
| SlavePTY::SlavePTY(MasterPTY& master, unsigned index) | SlavePTY::SlavePTY(MasterPTY& master, unsigned index) | ||||||
|     : TTY(11, index) |     : TTY(11, index) | ||||||
|     , m_master(master) |     , m_master(master) | ||||||
|     , m_index(index) |     , m_index(index) | ||||||
| { | { | ||||||
|  |     VFS::the().register_character_device(*this); | ||||||
|  |     DevPtsFS::the().register_slave_pty(*this); | ||||||
|     set_size(80, 25); |     set_size(80, 25); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SlavePTY::~SlavePTY() | SlavePTY::~SlavePTY() | ||||||
| { | { | ||||||
|  |     DevPtsFS::the().unregister_slave_pty(*this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String SlavePTY::tty_name() const | String SlavePTY::tty_name() const | ||||||
| { | { | ||||||
|     char buffer[32]; |     char buffer[32]; | ||||||
|     ksprintf(buffer, "/dev/pts%u", m_index); |     ksprintf(buffer, "/dev/pts/%u", m_index); | ||||||
|     return buffer; |     return buffer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,9 @@ public: | ||||||
|     void on_master_write(const byte*, size_t); |     void on_master_write(const byte*, size_t); | ||||||
|     unsigned index() const { return m_index; } |     unsigned index() const { return m_index; } | ||||||
| 
 | 
 | ||||||
|  |     InodeIdentifier devpts_inode_id() const { return m_devpts_inode_id; } | ||||||
|  |     void set_devpts_inode_id(InodeIdentifier inode_id) { m_devpts_inode_id = inode_id; } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     // ^TTY
 |     // ^TTY
 | ||||||
|     virtual String tty_name() const override; |     virtual String tty_name() const override; | ||||||
|  | @ -25,5 +28,6 @@ private: | ||||||
| 
 | 
 | ||||||
|     MasterPTY& m_master; |     MasterPTY& m_master; | ||||||
|     unsigned m_index; |     unsigned m_index; | ||||||
|  |     InodeIdentifier m_devpts_inode_id; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -45,6 +45,7 @@ struct SynthFSInodeCustomData { | ||||||
| 
 | 
 | ||||||
| class SynthFSInode final : public Inode { | class SynthFSInode final : public Inode { | ||||||
|     friend class SynthFS; |     friend class SynthFS; | ||||||
|  |     friend class DevPtsFS; | ||||||
| public: | public: | ||||||
|     virtual ~SynthFSInode() override; |     virtual ~SynthFSInode() override; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ | ||||||
| #include "Scheduler.h" | #include "Scheduler.h" | ||||||
| #include "PS2MouseDevice.h" | #include "PS2MouseDevice.h" | ||||||
| #include "PTYMultiplexer.h" | #include "PTYMultiplexer.h" | ||||||
|  | #include "DevPtsFS.h" | ||||||
| 
 | 
 | ||||||
| //#define SPAWN_GUITEST
 | //#define SPAWN_GUITEST
 | ||||||
| #define SPAWN_GUITEST2 | #define SPAWN_GUITEST2 | ||||||
|  | @ -95,6 +96,7 @@ static void init_stage2() | ||||||
|     load_ksyms(); |     load_ksyms(); | ||||||
| 
 | 
 | ||||||
|     vfs->mount(ProcFS::the(), "/proc"); |     vfs->mount(ProcFS::the(), "/proc"); | ||||||
|  |     vfs->mount(DevPtsFS::the(), "/dev/pts"); | ||||||
| 
 | 
 | ||||||
|     Vector<String> environment; |     Vector<String> environment; | ||||||
|     environment.append("TERM=ansi"); |     environment.append("TERM=ansi"); | ||||||
|  | @ -167,6 +169,9 @@ void init() | ||||||
|     auto procfs = ProcFS::create(); |     auto procfs = ProcFS::create(); | ||||||
|     procfs->initialize(); |     procfs->initialize(); | ||||||
| 
 | 
 | ||||||
|  |     auto devptsfs = DevPtsFS::create(); | ||||||
|  |     devptsfs->initialize(); | ||||||
|  | 
 | ||||||
|     Process::initialize(); |     Process::initialize(); | ||||||
|     Process::create_kernel_process("init_stage2", init_stage2); |     Process::create_kernel_process("init_stage2", init_stage2); | ||||||
|     Process::create_kernel_process("syncd", [] { |     Process::create_kernel_process("syncd", [] { | ||||||
|  |  | ||||||
|  | @ -11,14 +11,7 @@ mknod mnt/dev/tty3 c 4 3 | ||||||
| mknod mnt/dev/keyboard c 85 1 | mknod mnt/dev/keyboard c 85 1 | ||||||
| mknod mnt/dev/psaux c 10 1 | mknod mnt/dev/psaux c 10 1 | ||||||
| mknod mnt/dev/ptmx c 5 2 | mknod mnt/dev/ptmx c 5 2 | ||||||
| mknod mnt/dev/ptm0 c 10 0 | mkdir mnt/dev/pts | ||||||
| mknod mnt/dev/ptm1 c 10 1 |  | ||||||
| mknod mnt/dev/ptm2 c 10 2 |  | ||||||
| mknod mnt/dev/ptm3 c 10 3 |  | ||||||
| mknod mnt/dev/pts0 c 11 0 |  | ||||||
| mknod mnt/dev/pts1 c 11 1 |  | ||||||
| mknod mnt/dev/pts2 c 11 2 |  | ||||||
| mknod mnt/dev/pts3 c 11 3 |  | ||||||
| mknod mnt/dev/gui_events c 66 1 | mknod mnt/dev/gui_events c 66 1 | ||||||
| cp -R ../Base/* mnt/ | cp -R ../Base/* mnt/ | ||||||
| cp -v ../Userland/sh mnt/bin/sh | cp -v ../Userland/sh mnt/bin/sh | ||||||
|  |  | ||||||
|  | @ -14,7 +14,6 @@ | ||||||
| struct GlobalState { | struct GlobalState { | ||||||
|     String cwd; |     String cwd; | ||||||
|     String username; |     String username; | ||||||
|     const char* ttyname_short { nullptr }; |  | ||||||
|     char ttyname[32]; |     char ttyname[32]; | ||||||
|     char hostname[32]; |     char hostname[32]; | ||||||
|     pid_t sid; |     pid_t sid; | ||||||
|  | @ -356,7 +355,7 @@ static void greeting() | ||||||
|         perror("uname"); |         perror("uname"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     printf("\n%s/%s on %s\n\n", uts.sysname, uts.machine, g->ttyname_short); |     printf("\n%s/%s on %s\n\n", uts.sysname, uts.machine, g->ttyname); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int main(int, char**) | int main(int, char**) | ||||||
|  | @ -384,8 +383,7 @@ int main(int, char**) | ||||||
|     rc = ttyname_r(0, g->ttyname, sizeof(g->ttyname)); |     rc = ttyname_r(0, g->ttyname, sizeof(g->ttyname)); | ||||||
|     if (rc < 0) |     if (rc < 0) | ||||||
|         perror("ttyname_r"); |         perror("ttyname_r"); | ||||||
|     else | 
 | ||||||
|         g->ttyname_short = strrchr(g->ttyname, '/') + 1; |  | ||||||
|     { |     { | ||||||
|         auto* pw = getpwuid(getuid()); |         auto* pw = getpwuid(getuid()); | ||||||
|         if (pw) |         if (pw) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling