This commit is contained in:
2025-07-05 17:21:10 +09:00
parent 746fe4aa8c
commit 4e0f74a991
9 changed files with 1408 additions and 2 deletions

196
kernel/src/filesystem.rs Normal file
View File

@ -0,0 +1,196 @@
//! Simple File System for Aios
//!
//! Provides basic file operations for package installation and management
#![allow(dead_code)]
/// Simple file entry
#[derive(Debug, Clone, Copy)]
pub struct FileEntry {
pub name: [u8; 32],
pub size: usize,
pub file_type: FileType,
pub data_offset: usize,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FileType {
Regular,
Directory,
Executable,
}
/// Simple in-memory file system
pub struct SimpleFS {
files: [Option<FileEntry>; 64],
file_count: usize,
data_storage: [u8; 2048], // 2KB storage (reduced from 8KB)
data_used: usize,
}
impl SimpleFS {
pub fn new() -> Self {
SimpleFS {
files: [None; 64],
file_count: 0,
data_storage: [0; 2048],
data_used: 0,
}
}
/// Create a file
pub fn create_file(&mut self, name: &str, content: &[u8], file_type: FileType) -> Result<(), &'static str> {
if self.file_count >= 64 {
return Err("File system full");
}
if name.len() > 31 {
return Err("Filename too long");
}
if self.data_used + content.len() > self.data_storage.len() {
return Err("Not enough storage space");
}
// Check if file already exists
if self.find_file(name).is_some() {
return Err("File already exists");
}
// Create file entry
let mut file_name = [0u8; 32];
let name_bytes = name.as_bytes();
for i in 0..name_bytes.len() {
file_name[i] = name_bytes[i];
}
let file_entry = FileEntry {
name: file_name,
size: content.len(),
file_type,
data_offset: self.data_used,
};
// Store file data
for i in 0..content.len() {
self.data_storage[self.data_used + i] = content[i];
}
self.data_used += content.len();
// Add file entry
self.files[self.file_count] = Some(file_entry);
self.file_count += 1;
Ok(())
}
/// Find a file by name
pub fn find_file(&self, name: &str) -> Option<&FileEntry> {
for i in 0..self.file_count {
if let Some(file) = &self.files[i] {
if self.str_eq(&file.name, name) {
return Some(file);
}
}
}
None
}
/// List all files
pub fn list_files(&self) -> &[Option<FileEntry>] {
&self.files[..self.file_count]
}
/// Read file content
pub fn read_file(&self, name: &str) -> Option<&[u8]> {
if let Some(file) = self.find_file(name) {
let start = file.data_offset;
let end = start + file.size;
Some(&self.data_storage[start..end])
} else {
None
}
}
/// Delete a file
pub fn delete_file(&mut self, name: &str) -> Result<(), &'static str> {
let mut found_index = None;
for i in 0..self.file_count {
if let Some(file) = &self.files[i] {
if self.str_eq(&file.name, name) {
found_index = Some(i);
break;
}
}
}
if let Some(index) = found_index {
// Remove file by shifting array
for i in index..self.file_count.saturating_sub(1) {
self.files[i] = self.files[i + 1];
}
self.files[self.file_count - 1] = None;
self.file_count -= 1;
Ok(())
} else {
Err("File not found")
}
}
/// Get file count
pub fn file_count(&self) -> usize {
self.file_count
}
/// Helper function to compare string with byte array
fn str_eq(&self, arr: &[u8; 32], s: &str) -> bool {
let s_bytes = s.as_bytes();
if s_bytes.len() > 32 {
return false;
}
// Find the end of the string in the array (null terminator)
let mut arr_len = 0;
for i in 0..32 {
if arr[i] == 0 {
break;
}
arr_len += 1;
}
if arr_len != s_bytes.len() {
return false;
}
for i in 0..arr_len {
if arr[i] != s_bytes[i] {
return false;
}
}
true
}
/// Get filename as string
pub fn filename_str(file: &FileEntry) -> &str {
let mut len = 0;
for i in 0..32 {
if file.name[i] == 0 {
break;
}
len += 1;
}
core::str::from_utf8(&file.name[..len]).unwrap_or("")
}
}
impl FileType {
pub fn as_str(&self) -> &'static str {
match self {
FileType::Regular => "file",
FileType::Directory => "dir",
FileType::Executable => "exec",
}
}
}

View File

@ -2,6 +2,7 @@
#![no_std]
#![no_main]
#![allow(static_mut_refs)]
mod keyboard_basic;
@ -113,7 +114,7 @@ fn execute_command() {
}
// Clear input buffer
INPUT_BUFFER.fill(0);
core::ptr::write_bytes(INPUT_BUFFER.as_mut_ptr(), 0, INPUT_BUFFER.len());
INPUT_POS = 0;
new_line();
@ -196,7 +197,7 @@ pub extern "C" fn _start() -> ! {
// Panic handler
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
fn panic(_info: &PanicInfo) -> ! {
clear_screen();
print_str("!!! KERNEL PANIC !!!", 29, 12);
print_str("System halted.", 33, 13);

380
kernel/src/package.rs Normal file
View File

@ -0,0 +1,380 @@
//! Package Manager for Aios
//!
//! Simple package management system inspired by Redox pkgutils
//! Provides basic package operations: install, remove, list, update
#![allow(dead_code)]
use core::fmt;
use crate::filesystem::{SimpleFS, FileType};
/// Package metadata structure
#[derive(Debug, Clone, Copy)]
pub struct Package {
pub name: [u8; 32], // Fixed-size name
pub version: [u8; 16], // Fixed-size version
pub description: [u8; 64], // Fixed-size description
pub status: PackageStatus,
pub size: usize,
}
/// Package status
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PackageStatus {
Installed,
Available,
Broken,
}
/// Package manager error types
#[derive(Debug)]
pub enum PackageError {
NotFound,
AlreadyInstalled,
NotInstalled,
InvalidName,
IoError,
}
impl fmt::Display for PackageError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PackageError::NotFound => write!(f, "Package not found"),
PackageError::AlreadyInstalled => write!(f, "Package already installed"),
PackageError::NotInstalled => write!(f, "Package not installed"),
PackageError::InvalidName => write!(f, "Invalid package name"),
PackageError::IoError => write!(f, "I/O error"),
}
}
}
/// Package Manager
pub struct PackageManager {
installed_packages: [Option<Package>; 32], // Simple fixed-size array
package_count: usize,
filesystem: SimpleFS,
}
impl PackageManager {
/// Create new package manager
pub fn new() -> Self {
PackageManager {
installed_packages: [None; 32],
package_count: 0,
filesystem: SimpleFS::new(),
}
}
/// Install a package
pub fn install(&mut self, name: &str) -> Result<(), PackageError> {
// Check if package name is valid
if name.is_empty() || name.len() > 32 {
return Err(PackageError::InvalidName);
}
// Check if already installed
if self.is_installed(name) {
return Err(PackageError::AlreadyInstalled);
}
// Check if we have space
if self.package_count >= 32 {
return Err(PackageError::IoError);
}
// Create package from predefined list
let package = self.create_package(name)?;
// Install package files to filesystem
self.install_package_files(name)?;
// Add to installed packages
self.installed_packages[self.package_count] = Some(package);
self.package_count += 1;
Ok(())
}
/// Remove a package
pub fn remove(&mut self, name: &str) -> Result<(), PackageError> {
// Find package
let mut found_index = None;
for (i, pkg) in self.installed_packages.iter().enumerate() {
if let Some(package) = pkg {
if self.str_eq(&package.name, name) {
found_index = Some(i);
break;
}
}
}
match found_index {
Some(index) => {
// Remove package files from filesystem
let _ = self.remove_package_files(name);
// Remove package by shifting array
for i in index..self.package_count.saturating_sub(1) {
self.installed_packages[i] = self.installed_packages[i + 1].take();
}
self.package_count -= 1;
Ok(())
}
None => Err(PackageError::NotInstalled),
}
}
/// List installed packages
pub fn list(&self) -> &[Option<Package>] {
&self.installed_packages[..self.package_count]
}
/// Check if package is installed
pub fn is_installed(&self, name: &str) -> bool {
self.installed_packages[..self.package_count]
.iter()
.any(|pkg| {
if let Some(package) = pkg {
self.str_eq(&package.name, name)
} else {
false
}
})
}
/// Get package count
pub fn count(&self) -> usize {
self.package_count
}
/// Helper function to compare string with byte array
fn str_eq(&self, arr: &[u8; 32], s: &str) -> bool {
let s_bytes = s.as_bytes();
if s_bytes.len() > 32 {
return false;
}
// Find the end of the string in the array (null terminator)
let mut arr_len = 0;
for i in 0..32 {
if arr[i] == 0 {
break;
}
arr_len += 1;
}
if arr_len != s_bytes.len() {
return false;
}
for i in 0..arr_len {
if arr[i] != s_bytes[i] {
return false;
}
}
true
}
/// Copy string to byte array
fn copy_str_to_array<const N: usize>(&self, s: &str) -> [u8; N] {
let mut arr = [0u8; N];
let bytes = s.as_bytes();
let len = core::cmp::min(bytes.len(), N - 1); // Leave space for null terminator
for i in 0..len {
arr[i] = bytes[i];
}
arr
}
/// Create a package from predefined list
fn create_package(&self, name: &str) -> Result<Package, PackageError> {
match name {
"vim" => Ok(Package {
name: self.copy_str_to_array("vim"),
version: self.copy_str_to_array("8.2.0"),
description: self.copy_str_to_array("Vi IMproved text editor"),
status: PackageStatus::Installed,
size: 1024,
}),
"git" => Ok(Package {
name: self.copy_str_to_array("git"),
version: self.copy_str_to_array("2.39.0"),
description: self.copy_str_to_array("Git version control system"),
status: PackageStatus::Installed,
size: 2048,
}),
"curl" => Ok(Package {
name: self.copy_str_to_array("curl"),
version: self.copy_str_to_array("7.88.0"),
description: self.copy_str_to_array("Command line tool for transferring data"),
status: PackageStatus::Installed,
size: 512,
}),
"rust" => Ok(Package {
name: self.copy_str_to_array("rust"),
version: self.copy_str_to_array("1.75.0"),
description: self.copy_str_to_array("Rust programming language"),
status: PackageStatus::Installed,
size: 4096,
}),
"python" => Ok(Package {
name: self.copy_str_to_array("python"),
version: self.copy_str_to_array("3.11.0"),
description: self.copy_str_to_array("Python programming language"),
status: PackageStatus::Installed,
size: 3072,
}),
"claude" => Ok(Package {
name: self.copy_str_to_array("claude"),
version: self.copy_str_to_array("1.0.0"),
description: self.copy_str_to_array("Claude AI integration service"),
status: PackageStatus::Installed,
size: 1536,
}),
_ => Err(PackageError::NotFound),
}
}
/// Install package files to filesystem
fn install_package_files(&mut self, name: &str) -> Result<(), PackageError> {
match name {
"vim" => {
// Create vim executable
let vim_content = b"#!/bin/sh\necho 'Vi IMproved - text editor'\necho 'Usage: vim [file]'\n";
self.filesystem.create_file("/bin/vim", vim_content, FileType::Executable)
.map_err(|_| PackageError::IoError)?;
// Create vim config
let vimrc_content = b"\" Vim configuration\nset number\nset autoindent\nsyntax on\n";
self.filesystem.create_file("/etc/vimrc", vimrc_content, FileType::Regular)
.map_err(|_| PackageError::IoError)?;
}
"git" => {
let git_content = b"#!/bin/sh\necho 'Git - version control system'\necho 'Usage: git [command]'\n";
self.filesystem.create_file("/bin/git", git_content, FileType::Executable)
.map_err(|_| PackageError::IoError)?;
let gitconfig_content = b"[core]\n editor = vim\n[user]\n name = Aios User\n";
self.filesystem.create_file("/etc/gitconfig", gitconfig_content, FileType::Regular)
.map_err(|_| PackageError::IoError)?;
}
"curl" => {
let curl_content = b"#!/bin/sh\necho 'cURL - data transfer tool'\necho 'Usage: curl [URL]'\n";
self.filesystem.create_file("/bin/curl", curl_content, FileType::Executable)
.map_err(|_| PackageError::IoError)?;
}
"rust" => {
let rustc_content = b"#!/bin/sh\necho 'Rust Compiler'\necho 'Usage: rustc [file.rs]'\n";
self.filesystem.create_file("/bin/rustc", rustc_content, FileType::Executable)
.map_err(|_| PackageError::IoError)?;
let cargo_content = b"#!/bin/sh\necho 'Cargo - Rust package manager'\necho 'Usage: cargo [command]'\n";
self.filesystem.create_file("/bin/cargo", cargo_content, FileType::Executable)
.map_err(|_| PackageError::IoError)?;
}
"python" => {
let python_content = b"#!/bin/sh\necho 'Python interpreter'\necho 'Usage: python [script.py]'\n";
self.filesystem.create_file("/bin/python", python_content, FileType::Executable)
.map_err(|_| PackageError::IoError)?;
let pip_content = b"#!/bin/sh\necho 'pip - Python package installer'\necho 'Usage: pip install [package]'\n";
self.filesystem.create_file("/bin/pip", pip_content, FileType::Executable)
.map_err(|_| PackageError::IoError)?;
}
"claude" => {
let claude_content = b"#!/bin/sh\necho 'Claude AI Assistant'\necho 'Usage: claude [query]'\n";
self.filesystem.create_file("/bin/claude", claude_content, FileType::Executable)
.map_err(|_| PackageError::IoError)?;
let config_content = b"# Claude AI Configuration\napi_endpoint=https://api.anthropic.com\nmodel=claude-3-sonnet\n";
self.filesystem.create_file("/etc/claude.conf", config_content, FileType::Regular)
.map_err(|_| PackageError::IoError)?;
}
_ => return Err(PackageError::NotFound),
}
Ok(())
}
/// Remove package files from filesystem
fn remove_package_files(&mut self, name: &str) -> Result<(), PackageError> {
match name {
"vim" => {
let _ = self.filesystem.delete_file("/bin/vim");
let _ = self.filesystem.delete_file("/etc/vimrc");
}
"git" => {
let _ = self.filesystem.delete_file("/bin/git");
let _ = self.filesystem.delete_file("/etc/gitconfig");
}
"curl" => {
let _ = self.filesystem.delete_file("/bin/curl");
}
"rust" => {
let _ = self.filesystem.delete_file("/bin/rustc");
let _ = self.filesystem.delete_file("/bin/cargo");
}
"python" => {
let _ = self.filesystem.delete_file("/bin/python");
let _ = self.filesystem.delete_file("/bin/pip");
}
"claude" => {
let _ = self.filesystem.delete_file("/bin/claude");
let _ = self.filesystem.delete_file("/etc/claude.conf");
}
_ => return Err(PackageError::NotFound),
}
Ok(())
}
/// List installed files
pub fn list_files(&self) -> &[Option<crate::filesystem::FileEntry>] {
self.filesystem.list_files()
}
/// Get filesystem reference
pub fn filesystem(&self) -> &SimpleFS {
&self.filesystem
}
}
impl Package {
/// Get package name as string slice
pub fn name_str(&self) -> &str {
// Find null terminator
let mut len = 0;
for i in 0..32 {
if self.name[i] == 0 {
break;
}
len += 1;
}
// Safe to unwrap since we control the input
core::str::from_utf8(&self.name[..len]).unwrap_or("")
}
/// Get package version as string slice
pub fn version_str(&self) -> &str {
let mut len = 0;
for i in 0..16 {
if self.version[i] == 0 {
break;
}
len += 1;
}
core::str::from_utf8(&self.version[..len]).unwrap_or("")
}
}
impl fmt::Display for PackageStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PackageStatus::Installed => write!(f, "installed"),
PackageStatus::Available => write!(f, "available"),
PackageStatus::Broken => write!(f, "broken"),
}
}
}

View File

@ -0,0 +1,231 @@
//! Lightweight Package Manager for Aios
//!
//! Memory-safe package management system with minimal memory footprint
#![allow(dead_code)]
/// Lightweight package entry
#[derive(Debug, Clone, Copy)]
pub struct LightPackage {
pub name: [u8; 16], // Reduced from 32 to 16 bytes
pub version: [u8; 8], // Reduced from 16 to 8 bytes
pub status: PackageStatus,
}
/// Package status
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PackageStatus {
Installed,
Available,
}
/// Lightweight Package Manager
pub struct LightPackageManager {
packages: [Option<LightPackage>; 8], // Reduced from 32 to 8 packages
count: usize,
}
impl LightPackageManager {
pub fn new() -> Self {
LightPackageManager {
packages: [None; 8],
count: 0,
}
}
/// Install a package (lightweight - no actual files)
pub fn install(&mut self, name: &str) -> Result<(), &'static str> {
if name.len() > 15 {
return Err("Package name too long");
}
if self.count >= 8 {
return Err("Package manager full");
}
// Check if already installed
if self.is_installed(name) {
return Err("Already installed");
}
// Create package entry
let package = self.create_package(name)?;
self.packages[self.count] = Some(package);
self.count += 1;
Ok(())
}
/// Remove a package
pub fn remove(&mut self, name: &str) -> Result<(), &'static str> {
let mut found_index = None;
for (i, pkg) in self.packages.iter().enumerate() {
if let Some(package) = pkg {
if self.str_eq(&package.name, name) {
found_index = Some(i);
break;
}
}
}
match found_index {
Some(index) => {
// Remove package by shifting array
for i in index..self.count.saturating_sub(1) {
self.packages[i] = self.packages[i + 1];
}
self.packages[self.count - 1] = None;
self.count -= 1;
Ok(())
}
None => Err("Package not installed"),
}
}
/// List installed packages
pub fn list(&self) -> &[Option<LightPackage>] {
&self.packages[..self.count]
}
/// Check if package is installed
pub fn is_installed(&self, name: &str) -> bool {
self.packages[..self.count]
.iter()
.any(|pkg| {
if let Some(package) = pkg {
self.str_eq(&package.name, name)
} else {
false
}
})
}
/// Get package count
pub fn count(&self) -> usize {
self.count
}
/// Create a package from predefined list
fn create_package(&self, name: &str) -> Result<LightPackage, &'static str> {
match name {
"vim" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("vim"),
version: self.copy_str_to_array::<8>("8.2"),
status: PackageStatus::Installed,
}),
"git" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("git"),
version: self.copy_str_to_array::<8>("2.39"),
status: PackageStatus::Installed,
}),
"curl" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("curl"),
version: self.copy_str_to_array::<8>("7.88"),
status: PackageStatus::Installed,
}),
"rust" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("rust"),
version: self.copy_str_to_array::<8>("1.75"),
status: PackageStatus::Installed,
}),
"python" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("python"),
version: self.copy_str_to_array::<8>("3.11"),
status: PackageStatus::Installed,
}),
"claude" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("claude"),
version: self.copy_str_to_array::<8>("1.0"),
status: PackageStatus::Installed,
}),
"zsh" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("zsh"),
version: self.copy_str_to_array::<8>("5.9"),
status: PackageStatus::Installed,
}),
"bash" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("bash"),
version: self.copy_str_to_array::<8>("5.2"),
status: PackageStatus::Installed,
}),
"fish" => Ok(LightPackage {
name: self.copy_str_to_array::<16>("fish"),
version: self.copy_str_to_array::<8>("3.6"),
status: PackageStatus::Installed,
}),
_ => Err("Package not found"),
}
}
/// Helper function to compare string with byte array
fn str_eq(&self, arr: &[u8; 16], s: &str) -> bool {
let s_bytes = s.as_bytes();
if s_bytes.len() > 16 {
return false;
}
// Find the end of the string in the array (null terminator)
let mut arr_len = 0;
for i in 0..16 {
if arr[i] == 0 {
break;
}
arr_len += 1;
}
if arr_len != s_bytes.len() {
return false;
}
for i in 0..arr_len {
if arr[i] != s_bytes[i] {
return false;
}
}
true
}
/// Copy string to byte array
fn copy_str_to_array<const N: usize>(&self, s: &str) -> [u8; N] {
let mut arr = [0u8; N];
let bytes = s.as_bytes();
let len = core::cmp::min(bytes.len(), N - 1); // Leave space for null terminator
for i in 0..len {
arr[i] = bytes[i];
}
arr
}
}
impl LightPackage {
/// Get package name as string slice
pub fn name_str(&self) -> &str {
// Find null terminator
let mut len = 0;
for i in 0..16 {
if self.name[i] == 0 {
break;
}
len += 1;
}
// Safe to unwrap since we control the input
core::str::from_utf8(&self.name[..len]).unwrap_or("")
}
/// Get package version as string slice
pub fn version_str(&self) -> &str {
let mut len = 0;
for i in 0..8 {
if self.version[i] == 0 {
break;
}
len += 1;
}
core::str::from_utf8(&self.version[..len]).unwrap_or("")
}
}