feature: login program
This commit is contained in:
parent
ed51f233ee
commit
a7a0c8bf2c
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -263,6 +263,7 @@ name = "user"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"libsys",
|
||||||
"libusr",
|
"libusr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
4
Makefile
4
Makefile
@ -92,11 +92,13 @@ initrd:
|
|||||||
--target=../etc/$(ARCH)-osdev5.json \
|
--target=../etc/$(ARCH)-osdev5.json \
|
||||||
-Z build-std=core,alloc,compiler_builtins \
|
-Z build-std=core,alloc,compiler_builtins \
|
||||||
$(CARGO_COMMON_OPTS)
|
$(CARGO_COMMON_OPTS)
|
||||||
mkdir -p $(O)/rootfs/bin
|
mkdir -p $(O)/rootfs/bin $(O)/rootfs/sbin $(O)/rootfs/dev
|
||||||
|
touch $(O)/rootfs/dev/.do_no_remove
|
||||||
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
|
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
|
||||||
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin
|
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin
|
||||||
cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin
|
cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin
|
||||||
cp target/$(ARCH)-osdev5/$(PROFILE)/ls $(O)/rootfs/bin
|
cp target/$(ARCH)-osdev5/$(PROFILE)/ls $(O)/rootfs/bin
|
||||||
|
cp target/$(ARCH)-osdev5/$(PROFILE)/login $(O)/rootfs/sbin
|
||||||
cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"`
|
cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"`
|
||||||
ifeq ($(MACH),orangepi3)
|
ifeq ($(MACH),orangepi3)
|
||||||
$(MKIMAGE) \
|
$(MKIMAGE) \
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::{FileRef, VnodeKind, VnodeRef};
|
use crate::{FileRef, VnodeKind, VnodeRef};
|
||||||
use libsys::{
|
use libsys::{
|
||||||
error::Errno,
|
error::Errno,
|
||||||
stat::{OpenFlags, FileMode},
|
|
||||||
path::{path_component_left, path_component_right},
|
path::{path_component_left, path_component_right},
|
||||||
|
stat::{FileMode, GroupId, OpenFlags, UserId},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// I/O context structure
|
/// I/O context structure
|
||||||
@ -10,13 +10,17 @@ use libsys::{
|
|||||||
pub struct Ioctx {
|
pub struct Ioctx {
|
||||||
root: VnodeRef,
|
root: VnodeRef,
|
||||||
cwd: VnodeRef,
|
cwd: VnodeRef,
|
||||||
|
pub uid: UserId,
|
||||||
|
pub gid: GroupId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ioctx {
|
impl Ioctx {
|
||||||
/// Creates a new I/O context with given root node
|
/// Creates a new I/O context with given root node
|
||||||
pub fn new(root: VnodeRef) -> Self {
|
pub fn new(root: VnodeRef, uid: UserId, gid: GroupId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cwd: root.clone(),
|
cwd: root.clone(),
|
||||||
|
uid,
|
||||||
|
gid,
|
||||||
root,
|
root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,6 +45,11 @@ impl Ioctx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while let Some(target) = at.target() {
|
||||||
|
assert!(at.kind() == VnodeKind::Directory);
|
||||||
|
at = target;
|
||||||
|
}
|
||||||
|
|
||||||
if element.is_empty() && rest.is_empty() {
|
if element.is_empty() && rest.is_empty() {
|
||||||
return Ok(at);
|
return Ok(at);
|
||||||
}
|
}
|
||||||
@ -113,6 +122,15 @@ impl Ioctx {
|
|||||||
|
|
||||||
node.open(opts)
|
node.open(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn chdir(&mut self, path: &str) -> Result<(), Errno> {
|
||||||
|
let node = self.find(None, path, true)?;
|
||||||
|
if !node.is_directory() {
|
||||||
|
return Err(Errno::NotADirectory);
|
||||||
|
}
|
||||||
|
self.cwd = node;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -105,6 +105,7 @@ impl Vnode {
|
|||||||
pub const SEEKABLE: u32 = 1 << 0;
|
pub const SEEKABLE: u32 = 1 << 0;
|
||||||
|
|
||||||
pub const CACHE_READDIR: u32 = 1 << 1;
|
pub const CACHE_READDIR: u32 = 1 << 1;
|
||||||
|
pub const CACHE_STAT: u32 = 1 << 2;
|
||||||
|
|
||||||
/// Constructs a new [Vnode], wrapping it in [Rc]. The resulting node
|
/// Constructs a new [Vnode], wrapping it in [Rc]. The resulting node
|
||||||
/// then needs to have [Vnode::set_data()] called on it to be usable.
|
/// then needs to have [Vnode::set_data()] called on it to be usable.
|
||||||
@ -452,7 +453,14 @@ impl Vnode {
|
|||||||
|
|
||||||
/// Reports file status
|
/// Reports file status
|
||||||
pub fn stat(self: &VnodeRef) -> Result<Stat, Errno> {
|
pub fn stat(self: &VnodeRef) -> Result<Stat, Errno> {
|
||||||
if let Some(ref mut data) = *self.data() {
|
if self.flags & Self::CACHE_STAT != 0 {
|
||||||
|
let props = self.props();
|
||||||
|
Ok(Stat {
|
||||||
|
blksize: 0,
|
||||||
|
size: 0,
|
||||||
|
mode: props.mode
|
||||||
|
})
|
||||||
|
} else if let Some(ref mut data) = *self.data() {
|
||||||
data.stat(self.clone())
|
data.stat(self.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(Errno::NotImplemented)
|
Err(Errno::NotImplemented)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use crate::util::InitOnce;
|
use crate::util::InitOnce;
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use libsys::error::Errno;
|
use libsys::{stat::FileMode, error::Errno};
|
||||||
use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeKind, VnodeRef};
|
use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeKind, VnodeRef};
|
||||||
|
|
||||||
/// Possible character device kinds
|
/// Possible character device kinds
|
||||||
@ -16,7 +16,9 @@ static DEVFS_ROOT: InitOnce<VnodeRef> = InitOnce::new();
|
|||||||
|
|
||||||
/// Initializes devfs
|
/// Initializes devfs
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
DEVFS_ROOT.init(Vnode::new("", VnodeKind::Directory, 0));
|
let node = Vnode::new("", VnodeKind::Directory, Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
|
||||||
|
node.props_mut().mode = FileMode::default_dir();
|
||||||
|
DEVFS_ROOT.init(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns devfs root node reference
|
/// Returns devfs root node reference
|
||||||
@ -27,7 +29,8 @@ pub fn root() -> &'static VnodeRef {
|
|||||||
fn _add_char_device(dev: &'static dyn CharDevice, name: &str) -> Result<(), Errno> {
|
fn _add_char_device(dev: &'static dyn CharDevice, name: &str) -> Result<(), Errno> {
|
||||||
infoln!("Add char device: {}", name);
|
infoln!("Add char device: {}", name);
|
||||||
|
|
||||||
let node = Vnode::new(name, VnodeKind::Char, 0);
|
let node = Vnode::new(name, VnodeKind::Char, Vnode::CACHE_STAT);
|
||||||
|
node.props_mut().mode = FileMode::from_bits(0o600).unwrap() | FileMode::S_IFCHR;
|
||||||
node.set_data(Box::new(CharDeviceWrapper::new(dev)));
|
node.set_data(Box::new(CharDeviceWrapper::new(dev)));
|
||||||
|
|
||||||
DEVFS_ROOT.get().attach(node);
|
DEVFS_ROOT.get().attach(node);
|
||||||
|
@ -3,6 +3,8 @@ use crate::mem::{
|
|||||||
self,
|
self,
|
||||||
phys::{self, PageUsage},
|
phys::{self, PageUsage},
|
||||||
};
|
};
|
||||||
|
use libsys::{error::Errno, stat::MountOptions};
|
||||||
|
use vfs::VnodeRef;
|
||||||
use memfs::BlockAllocator;
|
use memfs::BlockAllocator;
|
||||||
|
|
||||||
pub mod devfs;
|
pub mod devfs;
|
||||||
@ -25,3 +27,13 @@ unsafe impl BlockAllocator for MemfsBlockAlloc {
|
|||||||
phys::free_page(phys).unwrap();
|
phys::free_page(phys).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_filesystem(options: &MountOptions) -> Result<VnodeRef, Errno> {
|
||||||
|
let fs_name = options.fs.unwrap();
|
||||||
|
|
||||||
|
if fs_name == "devfs" {
|
||||||
|
Ok(devfs::root().clone())
|
||||||
|
} else {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::config::{ConfigKey, CONFIG};
|
|||||||
use crate::fs::{devfs, MemfsBlockAlloc};
|
use crate::fs::{devfs, MemfsBlockAlloc};
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::proc::{elf, Process};
|
use crate::proc::{elf, Process};
|
||||||
use libsys::stat::{FileDescriptor, OpenFlags};
|
use libsys::stat::{FileDescriptor, OpenFlags, UserId, GroupId};
|
||||||
use memfs::Ramfs;
|
use memfs::Ramfs;
|
||||||
use vfs::{Filesystem, Ioctx};
|
use vfs::{Filesystem, Ioctx};
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ pub extern "C" fn init_fn(_arg: usize) -> ! {
|
|||||||
unsafe { Ramfs::open(initrd_start as *mut u8, initrd_size, MemfsBlockAlloc {}).unwrap() };
|
unsafe { Ramfs::open(initrd_start as *mut u8, initrd_size, MemfsBlockAlloc {}).unwrap() };
|
||||||
let root = fs.root().unwrap();
|
let root = fs.root().unwrap();
|
||||||
|
|
||||||
let ioctx = Ioctx::new(root);
|
let ioctx = Ioctx::new(root, UserId::root(), GroupId::root());
|
||||||
|
|
||||||
let node = ioctx.find(None, "/init", true).unwrap();
|
let node = ioctx.find(None, "/init", true).unwrap();
|
||||||
let file = node.open(OpenFlags::O_RDONLY | OpenFlags::O_EXEC).unwrap();
|
let file = node.open(OpenFlags::O_RDONLY | OpenFlags::O_EXEC).unwrap();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Process file descriptors and I/O context
|
//! Process file descriptors and I/O context
|
||||||
use alloc::collections::BTreeMap;
|
use alloc::collections::BTreeMap;
|
||||||
use libsys::{error::Errno, stat::FileDescriptor};
|
use libsys::{error::Errno, stat::{FileDescriptor, UserId, GroupId}};
|
||||||
use vfs::{FileRef, Ioctx, VnodeRef, VnodeKind};
|
use vfs::{FileRef, Ioctx, VnodeRef, VnodeKind};
|
||||||
|
|
||||||
/// Process I/O context. Contains file tables, root/cwd info etc.
|
/// Process I/O context. Contains file tables, root/cwd info etc.
|
||||||
@ -31,6 +31,57 @@ impl ProcessIo {
|
|||||||
self.ctty.clone()
|
self.ctty.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn uid(&self) -> UserId {
|
||||||
|
self.ioctx.as_ref().unwrap().uid
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn gid(&self) -> GroupId {
|
||||||
|
self.ioctx.as_ref().unwrap().gid
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_uid(&mut self, uid: UserId) -> Result<(), Errno> {
|
||||||
|
let old_uid = self.uid();
|
||||||
|
if old_uid == uid {
|
||||||
|
Ok(())
|
||||||
|
} else if !old_uid.is_root() {
|
||||||
|
Err(Errno::PermissionDenied)
|
||||||
|
} else {
|
||||||
|
self.ioctx.as_mut().unwrap().uid = uid;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_gid(&mut self, gid: GroupId) -> Result<(), Errno> {
|
||||||
|
let old_gid = self.gid();
|
||||||
|
if old_gid == gid {
|
||||||
|
Ok(())
|
||||||
|
} else if !old_gid.is_root() {
|
||||||
|
Err(Errno::PermissionDenied)
|
||||||
|
} else {
|
||||||
|
self.ioctx.as_mut().unwrap().gid = gid;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn duplicate_file(&mut self, src: FileDescriptor, dst: Option<FileDescriptor>) -> Result<FileDescriptor, Errno> {
|
||||||
|
let file_ref = self.file(src)?;
|
||||||
|
if let Some(dst) = dst {
|
||||||
|
let idx = u32::from(dst);
|
||||||
|
if self.files.get(&idx).is_some() {
|
||||||
|
return Err(Errno::AlreadyExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.files.insert(idx, file_ref);
|
||||||
|
Ok(dst)
|
||||||
|
} else {
|
||||||
|
self.place_file(file_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns [File] struct referred to by file descriptor `idx`
|
/// Returns [File] struct referred to by file descriptor `idx`
|
||||||
pub fn file(&mut self, fd: FileDescriptor) -> Result<FileRef, Errno> {
|
pub fn file(&mut self, fd: FileDescriptor) -> Result<FileRef, Errno> {
|
||||||
self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile)
|
self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile)
|
||||||
|
@ -82,6 +82,10 @@ impl Process {
|
|||||||
self.inner.lock().pgid = pgid;
|
self.inner.lock().pgid = pgid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_sid(&self, sid: Pid) {
|
||||||
|
self.inner.lock().sid = sid;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current() -> ProcessRef {
|
pub fn current() -> ProcessRef {
|
||||||
Thread::current().owner().unwrap()
|
Thread::current().owner().unwrap()
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use crate::arch::{machine, platform::exception::ExceptionFrame};
|
use crate::arch::{machine, platform::exception::ExceptionFrame};
|
||||||
use crate::debug::Level;
|
use crate::debug::Level;
|
||||||
use crate::dev::timer::TimestampSource;
|
use crate::dev::timer::TimestampSource;
|
||||||
|
use crate::fs::create_filesystem;
|
||||||
use crate::proc::{self, elf, wait, Process, ProcessIo, Thread};
|
use crate::proc::{self, elf, wait, Process, ProcessIo, Thread};
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use core::ops::DerefMut;
|
use core::ops::DerefMut;
|
||||||
@ -15,7 +16,8 @@ use libsys::{
|
|||||||
proc::{ExitCode, Pid},
|
proc::{ExitCode, Pid},
|
||||||
signal::{Signal, SignalDestination},
|
signal::{Signal, SignalDestination},
|
||||||
stat::{
|
stat::{
|
||||||
AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH,
|
AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, GroupId, MountOptions,
|
||||||
|
OpenFlags, Stat, UserId, AT_EMPTY_PATH,
|
||||||
},
|
},
|
||||||
traits::{Read, Write},
|
traits::{Read, Write},
|
||||||
};
|
};
|
||||||
@ -107,7 +109,8 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
|||||||
|
|
||||||
let proc = Process::current();
|
let proc = Process::current();
|
||||||
let mut io = proc.io.lock();
|
let mut io = proc.io.lock();
|
||||||
let stat = find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat()?;
|
let stat =
|
||||||
|
find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat()?;
|
||||||
*buf = stat;
|
*buf = stat;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
@ -153,6 +156,48 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
|||||||
|
|
||||||
io.file(fd)?.borrow_mut().readdir(buf)
|
io.file(fd)?.borrow_mut().readdir(buf)
|
||||||
}
|
}
|
||||||
|
SystemCall::GetUserId => {
|
||||||
|
let proc = Process::current();
|
||||||
|
let uid = proc.io.lock().uid();
|
||||||
|
Ok(u32::from(uid) as usize)
|
||||||
|
}
|
||||||
|
SystemCall::GetGroupId => {
|
||||||
|
let proc = Process::current();
|
||||||
|
let gid = proc.io.lock().gid();
|
||||||
|
Ok(u32::from(gid) as usize)
|
||||||
|
}
|
||||||
|
SystemCall::DuplicateFd => {
|
||||||
|
let src = FileDescriptor::from(args[0] as u32);
|
||||||
|
let dst = FileDescriptor::from_i32(args[1] as i32)?;
|
||||||
|
|
||||||
|
let proc = Process::current();
|
||||||
|
let mut io = proc.io.lock();
|
||||||
|
|
||||||
|
let res = io.duplicate_file(src, dst)?;
|
||||||
|
|
||||||
|
Ok(u32::from(res) as usize)
|
||||||
|
}
|
||||||
|
SystemCall::SetUserId => {
|
||||||
|
let uid = UserId::from(args[0] as u32);
|
||||||
|
let proc = Process::current();
|
||||||
|
proc.io.lock().set_uid(uid)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
SystemCall::SetGroupId => {
|
||||||
|
let gid = GroupId::from(args[0] as u32);
|
||||||
|
let proc = Process::current();
|
||||||
|
proc.io.lock().set_gid(gid)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
SystemCall::SetCurrentDirectory => {
|
||||||
|
let path = arg::str_ref(args[0], args[1])?;
|
||||||
|
let proc = Process::current();
|
||||||
|
proc.io.lock().ioctx().chdir(path)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
SystemCall::GetCurrentDirectory => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
// Process
|
// Process
|
||||||
SystemCall::Clone => {
|
SystemCall::Clone => {
|
||||||
@ -294,7 +339,9 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
|||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!();
|
let id = proc.id();
|
||||||
|
proc.set_sid(id);
|
||||||
|
Ok(id.value() as usize)
|
||||||
}
|
}
|
||||||
SystemCall::SetPgid => {
|
SystemCall::SetPgid => {
|
||||||
let pid = args[0] as u32;
|
let pid = args[0] as u32;
|
||||||
@ -317,10 +364,28 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
|||||||
let time = machine::local_timer().timestamp()?;
|
let time = machine::local_timer().timestamp()?;
|
||||||
Ok(time.as_nanos() as usize)
|
Ok(time.as_nanos() as usize)
|
||||||
}
|
}
|
||||||
|
SystemCall::Mount => {
|
||||||
|
let target = arg::str_ref(args[0], args[1])?;
|
||||||
|
let options = arg::struct_ref::<MountOptions>(args[2])?;
|
||||||
|
|
||||||
|
let proc = Process::current();
|
||||||
|
let mut io = proc.io.lock();
|
||||||
|
|
||||||
|
debugln!("mount(target={:?}, options={:#x?})", target, options);
|
||||||
|
|
||||||
|
let target_node = io.ioctx().find(None, target, true)?;
|
||||||
|
let root = create_filesystem(options)?;
|
||||||
|
|
||||||
|
target_node.mount(root)?;
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
SystemCall::DebugTrace => {
|
SystemCall::DebugTrace => {
|
||||||
let level = TraceLevel::from_repr(args[0]).map(Level::from).ok_or(Errno::InvalidArgument)?;
|
let level = TraceLevel::from_repr(args[0])
|
||||||
|
.map(Level::from)
|
||||||
|
.ok_or(Errno::InvalidArgument)?;
|
||||||
let buf = arg::str_ref(args[1], args[2])?;
|
let buf = arg::str_ref(args[1], args[2])?;
|
||||||
let thread = Thread::current();
|
let thread = Thread::current();
|
||||||
let proc = thread.owner().unwrap();
|
let proc = thread.owner().unwrap();
|
||||||
|
@ -13,6 +13,13 @@ pub enum SystemCall {
|
|||||||
Select = 7,
|
Select = 7,
|
||||||
Access = 8,
|
Access = 8,
|
||||||
ReadDirectory = 9,
|
ReadDirectory = 9,
|
||||||
|
GetUserId = 10,
|
||||||
|
GetGroupId = 11,
|
||||||
|
DuplicateFd = 12,
|
||||||
|
SetUserId = 13,
|
||||||
|
SetGroupId = 14,
|
||||||
|
SetCurrentDirectory = 15,
|
||||||
|
GetCurrentDirectory = 16,
|
||||||
// Process manipulation
|
// Process manipulation
|
||||||
Fork = 32,
|
Fork = 32,
|
||||||
Clone = 33,
|
Clone = 33,
|
||||||
@ -34,6 +41,7 @@ pub enum SystemCall {
|
|||||||
SetPgid = 49,
|
SetPgid = 49,
|
||||||
// System
|
// System
|
||||||
GetCpuTime = 64,
|
GetCpuTime = 64,
|
||||||
|
Mount = 65,
|
||||||
// Debugging
|
// Debugging
|
||||||
DebugTrace = 128
|
DebugTrace = 128
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
use crate::abi::SystemCall;
|
use crate::abi::SystemCall;
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Errno,
|
|
||||||
debug::TraceLevel,
|
debug::TraceLevel,
|
||||||
|
error::Errno,
|
||||||
ioctl::IoctlCmd,
|
ioctl::IoctlCmd,
|
||||||
proc::{ExitCode, Pid},
|
proc::{ExitCode, Pid},
|
||||||
signal::{Signal, SignalDestination},
|
signal::{Signal, SignalDestination},
|
||||||
stat::{AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, OpenFlags, Stat},
|
stat::{
|
||||||
|
AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, GroupId, MountOptions,
|
||||||
|
OpenFlags, Stat, UserId,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
@ -387,3 +390,64 @@ pub fn sys_readdir(fd: FileDescriptor, buf: &mut [DirectoryEntry]) -> Result<usi
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_getuid() -> UserId {
|
||||||
|
UserId::from(unsafe { syscall!(SystemCall::GetUserId) as u32 })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_getgid() -> GroupId {
|
||||||
|
GroupId::from(unsafe { syscall!(SystemCall::GetGroupId) as u32 })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_setsid() -> Result<Pid, Errno> {
|
||||||
|
Errno::from_syscall(unsafe { syscall!(SystemCall::SetSid) })
|
||||||
|
.map(|e| unsafe { Pid::from_raw(e as u32) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_mount(target: &str, options: &MountOptions) -> Result<(), Errno> {
|
||||||
|
Errno::from_syscall_unit(unsafe {
|
||||||
|
syscall!(
|
||||||
|
SystemCall::Mount,
|
||||||
|
argp!(target.as_ptr()),
|
||||||
|
argn!(target.len()),
|
||||||
|
argp!(options as *const _)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_dup(src: FileDescriptor, dst: Option<FileDescriptor>) -> Result<FileDescriptor, Errno> {
|
||||||
|
Errno::from_syscall(unsafe {
|
||||||
|
syscall!(
|
||||||
|
SystemCall::DuplicateFd,
|
||||||
|
argn!(u32::from(src)),
|
||||||
|
argn!(FileDescriptor::into_i32(dst))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|e| FileDescriptor::from(e as u32))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_setuid(uid: UserId) -> Result<(), Errno> {
|
||||||
|
Errno::from_syscall_unit(unsafe { syscall!(SystemCall::SetUserId, u32::from(uid) as usize) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_setgid(gid: GroupId) -> Result<(), Errno> {
|
||||||
|
Errno::from_syscall_unit(unsafe { syscall!(SystemCall::SetGroupId, u32::from(gid) as usize) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_chdir(path: &str) -> Result<(), Errno> {
|
||||||
|
Errno::from_syscall_unit(unsafe {
|
||||||
|
syscall!(
|
||||||
|
SystemCall::SetCurrentDirectory,
|
||||||
|
argp!(path.as_ptr()),
|
||||||
|
argn!(path.len())
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// TODO split up this file
|
||||||
use crate::error::Errno;
|
use crate::error::Errno;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ bitflags! {
|
|||||||
const O_EXEC = 1 << 5;
|
const O_EXEC = 1 << 5;
|
||||||
const O_CLOEXEC = 1 << 6;
|
const O_CLOEXEC = 1 << 6;
|
||||||
const O_DIRECTORY = 1 << 7;
|
const O_DIRECTORY = 1 << 7;
|
||||||
|
const O_CTTY = 1 << 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,6 +25,7 @@ bitflags! {
|
|||||||
const FILE_TYPE = 0xF << 12;
|
const FILE_TYPE = 0xF << 12;
|
||||||
const S_IFREG = 0x8 << 12;
|
const S_IFREG = 0x8 << 12;
|
||||||
const S_IFDIR = 0x4 << 12;
|
const S_IFDIR = 0x4 << 12;
|
||||||
|
const S_IFCHR = 0x2 << 12;
|
||||||
|
|
||||||
const USER_READ = 1 << 8;
|
const USER_READ = 1 << 8;
|
||||||
const USER_WRITE = 1 << 7;
|
const USER_WRITE = 1 << 7;
|
||||||
@ -45,6 +48,69 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MountOptions<'a> {
|
||||||
|
pub device: Option<&'a str>,
|
||||||
|
pub fs: Option<&'a str>,
|
||||||
|
// TODO flags etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct UserId(u32);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct GroupId(u32);
|
||||||
|
|
||||||
|
impl UserId {
|
||||||
|
pub const fn root() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn is_root(self) -> bool {
|
||||||
|
self.0 == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for UserId {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(v: u32) -> Self {
|
||||||
|
Self(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UserId> for u32 {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(v: UserId) -> u32 {
|
||||||
|
v.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GroupId {
|
||||||
|
pub const fn root() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn is_root(self) -> bool {
|
||||||
|
self.0 == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for GroupId {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(v: u32) -> Self {
|
||||||
|
Self(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<GroupId> for u32 {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(v: GroupId) -> u32 {
|
||||||
|
v.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct FdSet {
|
pub struct FdSet {
|
||||||
bits: [u64; 2],
|
bits: [u64; 2],
|
||||||
@ -191,6 +257,7 @@ impl fmt::Display for FileMode {
|
|||||||
"{}{}{}{}{}{}{}{}{}{}",
|
"{}{}{}{}{}{}{}{}{}{}",
|
||||||
// File type
|
// File type
|
||||||
match *self & Self::FILE_TYPE {
|
match *self & Self::FILE_TYPE {
|
||||||
|
Self::S_IFCHR => 'c',
|
||||||
Self::S_IFDIR => 'd',
|
Self::S_IFDIR => 'd',
|
||||||
Self::S_IFREG => '-',
|
Self::S_IFREG => '-',
|
||||||
_ => '?'
|
_ => '?'
|
||||||
|
@ -21,6 +21,11 @@ path = "src/fuzzy/main.rs"
|
|||||||
name = "ls"
|
name = "ls"
|
||||||
path = "src/ls/main.rs"
|
path = "src/ls/main.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "login"
|
||||||
|
path = "src/login/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libusr = { path = "../libusr" }
|
libusr = { path = "../libusr" }
|
||||||
|
libsys = { path = "../libsys" }
|
||||||
lazy_static = { version = "*", features = ["spin_no_std"] }
|
lazy_static = { version = "*", features = ["spin_no_std"] }
|
||||||
|
@ -5,8 +5,19 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate libusr;
|
extern crate libusr;
|
||||||
|
|
||||||
|
use libusr::sys::{stat::MountOptions, sys_execve, sys_fork, sys_mount, sys_waitpid};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
|
sys_mount(
|
||||||
|
"/dev",
|
||||||
|
&MountOptions {
|
||||||
|
device: None,
|
||||||
|
fs: Some("devfs"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Failed to mount devfs");
|
||||||
|
|
||||||
let pid = unsafe { libusr::sys::sys_fork().unwrap() };
|
let pid = unsafe { libusr::sys::sys_fork().unwrap() };
|
||||||
|
|
||||||
if let Some(pid) = pid {
|
if let Some(pid) = pid {
|
||||||
@ -20,7 +31,7 @@ fn main() -> i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
libusr::sys::sys_execve("/bin/shell", &["/bin/shell"]).unwrap();
|
libusr::sys::sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap();
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
151
user/src/login/main.rs
Normal file
151
user/src/login/main.rs
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate libusr;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use libsys::{
|
||||||
|
calls::{
|
||||||
|
sys_close, sys_dup, sys_fork, sys_getgid, sys_getpgid, sys_getuid, sys_ioctl, sys_openat,
|
||||||
|
sys_read, sys_setgid, sys_setpgid, sys_setsid, sys_setuid, sys_waitpid, sys_execve
|
||||||
|
},
|
||||||
|
error::Errno,
|
||||||
|
ioctl::IoctlCmd,
|
||||||
|
proc::Pid,
|
||||||
|
stat::{FileDescriptor, FileMode, GroupId, OpenFlags, UserId},
|
||||||
|
termios::{Termios, TermiosLflag},
|
||||||
|
};
|
||||||
|
use libusr::{env, io};
|
||||||
|
|
||||||
|
struct HiddenInput {
|
||||||
|
fd: FileDescriptor,
|
||||||
|
termios: Termios,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HiddenInput {
|
||||||
|
fn open(fd: FileDescriptor) -> Result<Self, Errno> {
|
||||||
|
use core::mem::{size_of, MaybeUninit};
|
||||||
|
let mut termios: MaybeUninit<Termios> = MaybeUninit::uninit();
|
||||||
|
sys_ioctl(
|
||||||
|
fd,
|
||||||
|
IoctlCmd::TtyGetAttributes,
|
||||||
|
termios.as_mut_ptr() as usize,
|
||||||
|
size_of::<Termios>(),
|
||||||
|
)?;
|
||||||
|
let termios = unsafe { termios.assume_init() };
|
||||||
|
|
||||||
|
let mut new_termios = termios.clone();
|
||||||
|
new_termios.lflag &= !(TermiosLflag::ECHO | TermiosLflag::ECHOK | TermiosLflag::ECHOE);
|
||||||
|
sys_ioctl(
|
||||||
|
fd,
|
||||||
|
IoctlCmd::TtySetAttributes,
|
||||||
|
&new_termios as *const _ as usize,
|
||||||
|
size_of::<Termios>(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Self { fd, termios })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readline<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a str, Errno> {
|
||||||
|
readline(self.fd, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for HiddenInput {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
use core::mem::size_of;
|
||||||
|
sys_ioctl(
|
||||||
|
self.fd,
|
||||||
|
IoctlCmd::TtySetAttributes,
|
||||||
|
&self.termios as *const _ as usize,
|
||||||
|
size_of::<Termios>(),
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readline(fd: FileDescriptor, buf: &mut [u8]) -> Result<&str, Errno> {
|
||||||
|
let len = sys_read(fd, buf)?;
|
||||||
|
|
||||||
|
if len == 0 {
|
||||||
|
Ok("")
|
||||||
|
} else {
|
||||||
|
Ok(core::str::from_utf8(&buf[..len - 1]).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn login_as(uid: UserId, gid: GroupId, shell: &str) -> Result<(), Errno> {
|
||||||
|
if let Some(pid) = unsafe { sys_fork() }? {
|
||||||
|
let mut status = 0;
|
||||||
|
sys_waitpid(pid, &mut status).ok();
|
||||||
|
let pgid = sys_getpgid(unsafe { Pid::from_raw(0) }).unwrap();
|
||||||
|
io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap();
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
sys_setuid(uid).expect("setuid failed");
|
||||||
|
sys_setgid(gid).expect("setgid failed");
|
||||||
|
let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap();
|
||||||
|
io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap();
|
||||||
|
sys_execve(shell, &[shell]).expect("execve() failed");
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO baud rate and misc port settings
|
||||||
|
#[no_mangle]
|
||||||
|
fn main() -> i32 {
|
||||||
|
if !sys_getuid().is_root() {
|
||||||
|
panic!("This program must be run as root");
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = env::args();
|
||||||
|
if args.len() != 2 {
|
||||||
|
panic!("Usage: {} TTY", args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_setsid().expect("setsid() failed");
|
||||||
|
|
||||||
|
// Close controlling terminal
|
||||||
|
// NOTE this will invalidate rust-side Stdin, Stdout, Stderr
|
||||||
|
// until replacement is re-opened using the specified TTY
|
||||||
|
sys_close(FileDescriptor::STDERR).unwrap();
|
||||||
|
sys_close(FileDescriptor::STDOUT).unwrap();
|
||||||
|
sys_close(FileDescriptor::STDIN).unwrap();
|
||||||
|
|
||||||
|
sys_openat(
|
||||||
|
None,
|
||||||
|
args[1],
|
||||||
|
FileMode::default_reg(),
|
||||||
|
OpenFlags::O_RDONLY | OpenFlags::O_CTTY,
|
||||||
|
)
|
||||||
|
.expect("Failed to open stdin");
|
||||||
|
sys_openat(
|
||||||
|
None,
|
||||||
|
args[1],
|
||||||
|
FileMode::default_reg(),
|
||||||
|
OpenFlags::O_WRONLY | OpenFlags::O_CTTY,
|
||||||
|
)
|
||||||
|
.expect("Failed to open stdout");
|
||||||
|
sys_dup(FileDescriptor::STDOUT, Some(FileDescriptor::STDERR)).expect("Failed to open stderr");
|
||||||
|
|
||||||
|
let mut user_buf = [0; 128];
|
||||||
|
let mut password_buf = [0; 128];
|
||||||
|
loop {
|
||||||
|
print!("login: ");
|
||||||
|
let username = readline(FileDescriptor::STDIN, &mut user_buf).expect("Login read failed");
|
||||||
|
print!("password: ");
|
||||||
|
let password = {
|
||||||
|
let mut input = HiddenInput::open(FileDescriptor::STDIN).unwrap();
|
||||||
|
input.readline(&mut password_buf)
|
||||||
|
}
|
||||||
|
.expect("Password read failed");
|
||||||
|
|
||||||
|
if username == "root" && password == "toor" {
|
||||||
|
login_as(UserId::from(0), GroupId::from(0), "/bin/shell");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
@ -9,11 +9,34 @@ use alloc::{borrow::ToOwned, vec::Vec};
|
|||||||
use libusr::io::{self, Read};
|
use libusr::io::{self, Read};
|
||||||
use libusr::signal::{self, SignalHandler};
|
use libusr::signal::{self, SignalHandler};
|
||||||
use libusr::sys::{
|
use libusr::sys::{
|
||||||
proc::Pid, sys_execve, sys_setpgid, sys_exit, sys_fork, sys_getpgid, sys_waitpid, Errno, ExitCode,
|
proc::Pid, sys_chdir, sys_execve, sys_exit, sys_faccessat, sys_fork, sys_getpgid, sys_setpgid,
|
||||||
sys_faccessat, AccessMode,
|
sys_waitpid, AccessMode, Errno, ExitCode, FileDescriptor, Signal,
|
||||||
FileDescriptor, Signal,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Builtin {
|
||||||
|
func: fn(&[&str]) -> ExitCode,
|
||||||
|
name: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmd_cd(args: &[&str]) -> ExitCode {
|
||||||
|
if args.len() != 2 {
|
||||||
|
eprintln!("Usage: cd DIR");
|
||||||
|
ExitCode::from(-1)
|
||||||
|
} else {
|
||||||
|
if let Err(err) = sys_chdir(args[1]) {
|
||||||
|
eprintln!("{}: {:?}", args[1], err);
|
||||||
|
ExitCode::from(-1)
|
||||||
|
} else {
|
||||||
|
ExitCode::from(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BUILTINS: [Builtin; 1] = [Builtin {
|
||||||
|
name: "cd",
|
||||||
|
func: cmd_cd,
|
||||||
|
}];
|
||||||
|
|
||||||
fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result<Option<&'a str>, io::Error> {
|
fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result<Option<&'a str>, io::Error> {
|
||||||
let size = f.read(bytes)?;
|
let size = f.read(bytes)?;
|
||||||
Ok(if size == 0 {
|
Ok(if size == 0 {
|
||||||
@ -32,6 +55,12 @@ fn execute(line: &str) -> Result<ExitCode, Errno> {
|
|||||||
let args: Vec<&str> = line.split(' ').collect();
|
let args: Vec<&str> = line.split(' ').collect();
|
||||||
let cmd = args[0];
|
let cmd = args[0];
|
||||||
|
|
||||||
|
for item in BUILTINS.iter() {
|
||||||
|
if item.name == cmd {
|
||||||
|
return Ok((item.func)(&args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let filename = "/bin/".to_owned() + cmd;
|
let filename = "/bin/".to_owned() + cmd;
|
||||||
sys_faccessat(None, &filename, AccessMode::X_OK, 0)?;
|
sys_faccessat(None, &filename, AccessMode::X_OK, 0)?;
|
||||||
|
|
||||||
@ -73,12 +102,12 @@ fn main() -> i32 {
|
|||||||
if let Err(e) = execute(line) {
|
if let Err(e) = execute(line) {
|
||||||
eprintln!("{}: {:?}", line.split(' ').next().unwrap(), e);
|
eprintln!("{}: {:?}", line.split(' ').next().unwrap(), e);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("Interrupt!");
|
println!("Interrupt!");
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user