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"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libsys",
|
||||
"libusr",
|
||||
]
|
||||
|
||||
|
4
Makefile
4
Makefile
@ -92,11 +92,13 @@ initrd:
|
||||
--target=../etc/$(ARCH)-osdev5.json \
|
||||
-Z build-std=core,alloc,compiler_builtins \
|
||||
$(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)/shell $(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)/login $(O)/rootfs/sbin
|
||||
cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"`
|
||||
ifeq ($(MACH),orangepi3)
|
||||
$(MKIMAGE) \
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{FileRef, VnodeKind, VnodeRef};
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
stat::{OpenFlags, FileMode},
|
||||
path::{path_component_left, path_component_right},
|
||||
stat::{FileMode, GroupId, OpenFlags, UserId},
|
||||
};
|
||||
|
||||
/// I/O context structure
|
||||
@ -10,13 +10,17 @@ use libsys::{
|
||||
pub struct Ioctx {
|
||||
root: VnodeRef,
|
||||
cwd: VnodeRef,
|
||||
pub uid: UserId,
|
||||
pub gid: GroupId,
|
||||
}
|
||||
|
||||
impl Ioctx {
|
||||
/// 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 {
|
||||
cwd: root.clone(),
|
||||
uid,
|
||||
gid,
|
||||
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() {
|
||||
return Ok(at);
|
||||
}
|
||||
@ -113,6 +122,15 @@ impl Ioctx {
|
||||
|
||||
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)]
|
||||
|
@ -105,6 +105,7 @@ impl Vnode {
|
||||
pub const SEEKABLE: u32 = 1 << 0;
|
||||
|
||||
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
|
||||
/// then needs to have [Vnode::set_data()] called on it to be usable.
|
||||
@ -452,7 +453,14 @@ impl Vnode {
|
||||
|
||||
/// Reports file status
|
||||
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())
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
|
@ -2,7 +2,7 @@
|
||||
use crate::util::InitOnce;
|
||||
use alloc::boxed::Box;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use libsys::error::Errno;
|
||||
use libsys::{stat::FileMode, error::Errno};
|
||||
use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeKind, VnodeRef};
|
||||
|
||||
/// Possible character device kinds
|
||||
@ -16,7 +16,9 @@ static DEVFS_ROOT: InitOnce<VnodeRef> = InitOnce::new();
|
||||
|
||||
/// Initializes devfs
|
||||
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
|
||||
@ -27,7 +29,8 @@ pub fn root() -> &'static VnodeRef {
|
||||
fn _add_char_device(dev: &'static dyn CharDevice, name: &str) -> Result<(), Errno> {
|
||||
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)));
|
||||
|
||||
DEVFS_ROOT.get().attach(node);
|
||||
|
@ -3,6 +3,8 @@ use crate::mem::{
|
||||
self,
|
||||
phys::{self, PageUsage},
|
||||
};
|
||||
use libsys::{error::Errno, stat::MountOptions};
|
||||
use vfs::VnodeRef;
|
||||
use memfs::BlockAllocator;
|
||||
|
||||
pub mod devfs;
|
||||
@ -25,3 +27,13 @@ unsafe impl BlockAllocator for MemfsBlockAlloc {
|
||||
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::mem;
|
||||
use crate::proc::{elf, Process};
|
||||
use libsys::stat::{FileDescriptor, OpenFlags};
|
||||
use libsys::stat::{FileDescriptor, OpenFlags, UserId, GroupId};
|
||||
use memfs::Ramfs;
|
||||
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() };
|
||||
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 file = node.open(OpenFlags::O_RDONLY | OpenFlags::O_EXEC).unwrap();
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Process file descriptors and I/O context
|
||||
use alloc::collections::BTreeMap;
|
||||
use libsys::{error::Errno, stat::FileDescriptor};
|
||||
use libsys::{error::Errno, stat::{FileDescriptor, UserId, GroupId}};
|
||||
use vfs::{FileRef, Ioctx, VnodeRef, VnodeKind};
|
||||
|
||||
/// Process I/O context. Contains file tables, root/cwd info etc.
|
||||
@ -31,6 +31,57 @@ impl ProcessIo {
|
||||
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`
|
||||
pub fn file(&mut self, fd: FileDescriptor) -> Result<FileRef, Errno> {
|
||||
self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile)
|
||||
|
@ -82,6 +82,10 @@ impl Process {
|
||||
self.inner.lock().pgid = pgid;
|
||||
}
|
||||
|
||||
pub fn set_sid(&self, sid: Pid) {
|
||||
self.inner.lock().sid = sid;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn current() -> ProcessRef {
|
||||
Thread::current().owner().unwrap()
|
||||
|
@ -3,6 +3,7 @@
|
||||
use crate::arch::{machine, platform::exception::ExceptionFrame};
|
||||
use crate::debug::Level;
|
||||
use crate::dev::timer::TimestampSource;
|
||||
use crate::fs::create_filesystem;
|
||||
use crate::proc::{self, elf, wait, Process, ProcessIo, Thread};
|
||||
use core::mem::size_of;
|
||||
use core::ops::DerefMut;
|
||||
@ -15,7 +16,8 @@ use libsys::{
|
||||
proc::{ExitCode, Pid},
|
||||
signal::{Signal, SignalDestination},
|
||||
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},
|
||||
};
|
||||
@ -107,7 +109,8 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||
|
||||
let proc = Process::current();
|
||||
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;
|
||||
Ok(0)
|
||||
}
|
||||
@ -153,6 +156,48 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||
|
||||
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
|
||||
SystemCall::Clone => {
|
||||
@ -294,7 +339,9 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||
todo!();
|
||||
}
|
||||
|
||||
todo!();
|
||||
let id = proc.id();
|
||||
proc.set_sid(id);
|
||||
Ok(id.value() as usize)
|
||||
}
|
||||
SystemCall::SetPgid => {
|
||||
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()?;
|
||||
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
|
||||
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 thread = Thread::current();
|
||||
let proc = thread.owner().unwrap();
|
||||
|
@ -13,6 +13,13 @@ pub enum SystemCall {
|
||||
Select = 7,
|
||||
Access = 8,
|
||||
ReadDirectory = 9,
|
||||
GetUserId = 10,
|
||||
GetGroupId = 11,
|
||||
DuplicateFd = 12,
|
||||
SetUserId = 13,
|
||||
SetGroupId = 14,
|
||||
SetCurrentDirectory = 15,
|
||||
GetCurrentDirectory = 16,
|
||||
// Process manipulation
|
||||
Fork = 32,
|
||||
Clone = 33,
|
||||
@ -34,6 +41,7 @@ pub enum SystemCall {
|
||||
SetPgid = 49,
|
||||
// System
|
||||
GetCpuTime = 64,
|
||||
Mount = 65,
|
||||
// Debugging
|
||||
DebugTrace = 128
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
use crate::abi::SystemCall;
|
||||
use crate::{
|
||||
error::Errno,
|
||||
debug::TraceLevel,
|
||||
error::Errno,
|
||||
ioctl::IoctlCmd,
|
||||
proc::{ExitCode, Pid},
|
||||
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;
|
||||
|
||||
@ -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 core::fmt;
|
||||
|
||||
@ -15,6 +16,7 @@ bitflags! {
|
||||
const O_EXEC = 1 << 5;
|
||||
const O_CLOEXEC = 1 << 6;
|
||||
const O_DIRECTORY = 1 << 7;
|
||||
const O_CTTY = 1 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +25,7 @@ bitflags! {
|
||||
const FILE_TYPE = 0xF << 12;
|
||||
const S_IFREG = 0x8 << 12;
|
||||
const S_IFDIR = 0x4 << 12;
|
||||
const S_IFCHR = 0x2 << 12;
|
||||
|
||||
const USER_READ = 1 << 8;
|
||||
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)]
|
||||
pub struct FdSet {
|
||||
bits: [u64; 2],
|
||||
@ -191,6 +257,7 @@ impl fmt::Display for FileMode {
|
||||
"{}{}{}{}{}{}{}{}{}{}",
|
||||
// File type
|
||||
match *self & Self::FILE_TYPE {
|
||||
Self::S_IFCHR => 'c',
|
||||
Self::S_IFDIR => 'd',
|
||||
Self::S_IFREG => '-',
|
||||
_ => '?'
|
||||
|
@ -21,6 +21,11 @@ path = "src/fuzzy/main.rs"
|
||||
name = "ls"
|
||||
path = "src/ls/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "login"
|
||||
path = "src/login/main.rs"
|
||||
|
||||
[dependencies]
|
||||
libusr = { path = "../libusr" }
|
||||
libsys = { path = "../libsys" }
|
||||
lazy_static = { version = "*", features = ["spin_no_std"] }
|
||||
|
@ -5,8 +5,19 @@
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
|
||||
use libusr::sys::{stat::MountOptions, sys_execve, sys_fork, sys_mount, sys_waitpid};
|
||||
|
||||
#[no_mangle]
|
||||
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() };
|
||||
|
||||
if let Some(pid) = pid {
|
||||
@ -20,7 +31,7 @@ fn main() -> i32 {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
libusr::sys::sys_execve("/bin/shell", &["/bin/shell"]).unwrap();
|
||||
libusr::sys::sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap();
|
||||
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::signal::{self, SignalHandler};
|
||||
use libusr::sys::{
|
||||
proc::Pid, sys_execve, sys_setpgid, sys_exit, sys_fork, sys_getpgid, sys_waitpid, Errno, ExitCode,
|
||||
sys_faccessat, AccessMode,
|
||||
FileDescriptor, Signal,
|
||||
proc::Pid, sys_chdir, sys_execve, sys_exit, sys_faccessat, sys_fork, sys_getpgid, sys_setpgid,
|
||||
sys_waitpid, AccessMode, Errno, ExitCode, 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> {
|
||||
let size = f.read(bytes)?;
|
||||
Ok(if size == 0 {
|
||||
@ -32,6 +55,12 @@ fn execute(line: &str) -> Result<ExitCode, Errno> {
|
||||
let args: Vec<&str> = line.split(' ').collect();
|
||||
let cmd = args[0];
|
||||
|
||||
for item in BUILTINS.iter() {
|
||||
if item.name == cmd {
|
||||
return Ok((item.func)(&args));
|
||||
}
|
||||
}
|
||||
|
||||
let filename = "/bin/".to_owned() + cmd;
|
||||
sys_faccessat(None, &filename, AccessMode::X_OK, 0)?;
|
||||
|
||||
@ -73,12 +102,12 @@ fn main() -> i32 {
|
||||
if let Err(e) = execute(line) {
|
||||
eprintln!("{}: {:?}", line.split(' ').next().unwrap(), e);
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Interrupt!");
|
||||
continue;
|
||||
},
|
||||
_ => panic!()
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
0
|
||||
|
Loading…
x
Reference in New Issue
Block a user