diff --git a/Cargo.toml b/Cargo.toml index 8ff1c35..b4b40be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "user", "claude-service", ] +resolver = "2" [workspace.package] version = "2.0.0" diff --git a/archiso b/archiso new file mode 160000 index 0000000..9089013 --- /dev/null +++ b/archiso @@ -0,0 +1 @@ +Subproject commit 9089013c44815fc133235bba83ebdd69d6ec56db diff --git a/docker-build.sh b/docker-build.sh new file mode 100644 index 0000000..d56c641 --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +echo "=== AIOS Docker Build Environment ===" + +# Build Docker image +echo "Building Docker image..." +docker build -t aios-dev . + +# Run test kernel build +echo "Testing simple kernel build..." +docker run --rm -v $(pwd):/aios aios-dev test-kernel + +# Run main kernel build +echo "Building main AIOS kernel..." +docker run --rm -v $(pwd):/aios aios-dev build-aios + +echo "Build complete. Check target/ directories for binaries." \ No newline at end of file diff --git a/docs/MINIMAL_OS_DESIGN.md b/docs/MINIMAL_OS_DESIGN.md new file mode 100644 index 0000000..c51e3e4 --- /dev/null +++ b/docs/MINIMAL_OS_DESIGN.md @@ -0,0 +1,293 @@ +# 最小限OS構成設計(Redox OSベース) + +## Redox OS分析結果 + +### 1. **最小構成の特定** + +#### コアコンポーネント(196MiB以下) +```toml +# config/minimal.toml から抽出 +[packages] +base = {} # 基本システム(~20MB) +base-initfs = {} # 初期ファイルシステム(~5MB) +bootloader = {} # ブートローダー(~2MB) +drivers = {} # 最小ドライバー(~15MB) +kernel = {} # マイクロカーネル(~5MB) +relibc = {} # C標準ライブラリ(~10MB) +coreutils = {} # 基本コマンド(~8MB) +ion = {} # シェル(~3MB) +``` + +#### 初期化プロセス +```bash +# 00_base: 基本システム初期化 +rm -r /tmp # 一時ディレクトリクリア +mkdir -m a=rwxt /tmp # 一時ディレクトリ作成 +ipcd # IPCデーモン +ptyd # PTYデーモン +sudo --daemon # Sudoデーモン + +# 00_drivers: ドライバー初期化 +pcid-spawner /etc/pcid.d/ # PCIドライバー +``` + +### 2. **AIOS向け最小構成実装** + +#### ディレクトリ構造 +``` +aios-minimal/ +├── kernel/ # Redoxカーネルベース +│ ├── Cargo.toml +│ ├── src/ +│ │ ├── main.rs # カーネルエントリーポイント +│ │ ├── memory/ # メモリ管理 +│ │ ├── syscall/ # システムコール +│ │ └── scheme/ # スキームベースFS +├── bootloader/ # ブートローダー +├── userspace/ # ユーザーランド +│ ├── init/ # 初期化プロセス +│ ├── shell/ # Rustシェル +│ └── coreutils/ # 基本コマンド +└── config/ + └── minimal.toml # 最小構成設定 +``` + +#### カーネル最小化(kernel/Cargo.toml) +```toml +[package] +name = "aios-kernel" +version = "0.1.0" +edition = "2021" + +[dependencies] +# 必要最小限の依存関係のみ +bitflags = "2" +spin = "0.9.8" +linked_list_allocator = "0.9.0" +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", default-features = false } + +[features] +default = [ + "serial_debug", # シリアルデバッグのみ +] +# 不要機能を削除 +# acpi = [] # ACPI無効化 +# multi_core = [] # シングルコアのみ +# graphical_debug = [] # グラフィカルデバッグ無効 +``` + +#### 最小カーネル実装(kernel/src/main.rs) +```rust +//! AIOS Minimal Kernel +#![no_std] +#![no_main] +#![feature(allocator_api)] + +use core::panic::PanicInfo; + +mod memory; +mod syscall; +mod scheme; + +/// カーネルエントリーポイント +#[no_mangle] +pub extern "C" fn kmain() -> ! { + // 基本初期化 + memory::init(); + scheme::init(); + syscall::init(); + + // 最初のユーザープロセス起動 + let init_pid = syscall::exec("/usr/bin/init", &[]).expect("Failed to start init"); + + // メインループ + loop { + syscall::sched_yield(); + } +} + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} +``` + +#### シンプルな初期化プロセス(userspace/init/src/main.rs) +```rust +//! AIOS Init Process +use std::process::Command; + +fn main() { + println!("AIOS Init Starting..."); + + // 基本デーモン起動 + spawn_daemon("ptyd"); // PTY管理 + spawn_daemon("sudo"); // 権限管理 + + // シェル起動 + Command::new("/usr/bin/shell") + .spawn() + .expect("Failed to start shell"); + + // プロセス管理ループ + loop { + // ゾンビプロセス回収 + std::thread::sleep(std::time::Duration::from_secs(1)); + } +} + +fn spawn_daemon(name: &str) { + Command::new(format!("/usr/bin/{}", name)) + .spawn() + .unwrap_or_else(|_| panic!("Failed to start {}", name)); +} +``` + +#### 軽量シェル実装(userspace/shell/src/main.rs) +```rust +//! AIOS Minimal Shell +use std::io::{self, Write}; +use std::process::Command; + +fn main() { + println!("AIOS Shell v0.1.0"); + + loop { + print!("aios> "); + io::stdout().flush().unwrap(); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + let input = input.trim(); + + match input { + "exit" => break, + "help" => show_help(), + cmd if !cmd.is_empty() => execute_command(cmd), + _ => {} + } + } +} + +fn execute_command(cmd: &str) { + let parts: Vec<&str> = cmd.split_whitespace().collect(); + if parts.is_empty() { return; } + + match Command::new(parts[0]) + .args(&parts[1..]) + .status() + { + Ok(status) => { + if !status.success() { + println!("Command failed with exit code: {:?}", status.code()); + } + } + Err(e) => println!("Failed to execute command: {}", e), + } +} + +fn show_help() { + println!("Available commands:"); + println!(" ls - List files"); + println!(" cat - Show file contents"); + println!(" echo - Print text"); + println!(" help - Show this help"); + println!(" exit - Exit shell"); +} +``` + +#### 構成ファイル(config/minimal.toml) +```toml +# AIOS Minimal Configuration +[general] +filesystem_size = 128 # 128MiB(Redoxの196MiBより小さく) +prompt = false + +[packages] +aios-kernel = {} +aios-init = {} +aios-shell = {} +aios-coreutils = {} + +# 最小ファイルシステム +[[files]] +path = "/usr/lib/init.d/00_base" +data = """ +mkdir -p /tmp /var/log +aios-init +""" + +[[files]] +path = "/etc/hostname" +data = "aios" + +# ユーザー設定 +[users.root] +password = "root" +uid = 0 +gid = 0 +shell = "/usr/bin/aios-shell" +``` + +### 3. **メモリ使用量最適化** + +#### カーネル最適化 +- **スタックサイズ**: 4KB(最小限) +- **ヒープサイズ**: 1MB(動的拡張) +- **バッファサイズ**: 512B(固定) + +#### ユーザーランド最適化 +```rust +// メモリ制限 +const MAX_PROCESSES: usize = 16; // 最大プロセス数 +const MAX_FILES: usize = 64; // 最大ファイル数 +const STACK_SIZE: usize = 8192; // プロセススタック8KB +``` + +### 4. **ビルドシステム** + +#### Makefile +```makefile +# AIOS Minimal Build System +TARGET = x86_64-unknown-none +ARCH = x86_64 +CONFIG = minimal + +.PHONY: all kernel userspace iso clean + +all: iso + +kernel: + cd kernel && cargo build --release --target $(TARGET) + +userspace: + cd userspace && cargo build --release + +iso: kernel userspace + mkdir -p build/iso + cp kernel/target/$(TARGET)/release/aios-kernel build/iso/ + cp userspace/target/release/* build/iso/ + grub-mkrescue -o aios-minimal.iso build/iso + +clean: + cargo clean + rm -rf build/ +``` + +### 5. **機能制限とトレードオフ** + +#### 削除される機能 +- マルチコア対応 +- ACPI高度機能 +- グラフィカルデバッグ +- 複雑なファイルシステム +- ネットワーク機能 + +#### 保持される機能 +- 基本的なプロセス管理 +- シンプルなファイルシステム +- 最低限のメモリ管理 +- シリアル出力 +- 基本的なシステムコール + +この設計により、**128MB以下の極小OS**を実現できます。 \ No newline at end of file diff --git a/docs/RUST_LINUX_IMPLEMENTATION.md b/docs/RUST_LINUX_IMPLEMENTATION.md new file mode 100644 index 0000000..46216fe --- /dev/null +++ b/docs/RUST_LINUX_IMPLEMENTATION.md @@ -0,0 +1,286 @@ +# Rust Linux OS実装戦略 + +## 1. アーキテクチャ選択 + +### Option A: Redox OSベースアプローチ +**優点:** +- 既にRustで書かれた完全なOS +- Unix-like POSIX互換 +- マイクロカーネル設計 +- パッケージ管理システム有り + +**実装方法:** +```bash +# Redox OSをベースに拡張 +git clone https://gitlab.redox-os.org/redox-os/redox +cd redox +# カスタムコンポーネント追加 +``` + +### Option B: Linux From Scratch + Rustアプローチ +**優点:** +- 既存Linuxエコシステム活用 +- systemd統合可能 +- 豊富なパッケージ + +**実装方法:** +```bash +# ALFS自動化ツール使用 +git clone https://git.linuxfromscratch.org/jhalfs.git +# Rustコンポーネント統合 +``` + +### Option C: Rust for Linuxアプローチ +**優点:** +- 既存Linuxカーネル利用 +- Rustドライバー開発可能 +- 段階的移行可能 + +## 2. パッケージビルドシステム設計 + +### Rustベースビルドツール実装 + +```rust +// src/package_builder.rs +use std::process::Command; +use std::fs; +use std::path::Path; + +pub struct PackageBuilder { + pub name: String, + pub version: String, + pub source_url: String, + pub build_deps: Vec, +} + +impl PackageBuilder { + pub async fn download_source(&self) -> Result<(), Box> { + // HTTP/Git ダウンロード実装 + let output = Command::new("wget") + .arg(&self.source_url) + .arg("-O") + .arg(format!("{}-{}.tar.gz", self.name, self.version)) + .output()?; + + if output.status.success() { + println!("Downloaded {}", self.name); + } + Ok(()) + } + + pub fn extract_source(&self) -> Result<(), Box> { + Command::new("tar") + .arg("xzf") + .arg(format!("{}-{}.tar.gz", self.name, self.version)) + .output()?; + Ok(()) + } + + pub fn build(&self) -> Result<(), Box> { + let build_dir = format!("{}-{}", self.name, self.version); + + // configure + Command::new("./configure") + .current_dir(&build_dir) + .arg("--prefix=/usr") + .output()?; + + // make + Command::new("make") + .current_dir(&build_dir) + .arg("-j") + .arg(num_cpus::get().to_string()) + .output()?; + + // make install + Command::new("make") + .current_dir(&build_dir) + .arg("install") + .output()?; + + println!("Built and installed {}", self.name); + Ok(()) + } +} + +// パッケージ定義 +pub fn create_zsh_package() -> PackageBuilder { + PackageBuilder { + name: "zsh".to_string(), + version: "5.9".to_string(), + source_url: "https://sourceforge.net/projects/zsh/files/zsh/5.9/zsh-5.9.tar.xz".to_string(), + build_deps: vec!["gcc".to_string(), "make".to_string(), "ncurses-dev".to_string()], + } +} +``` + +### 自動ビルドシステム + +```rust +// src/auto_builder.rs +use tokio::process::Command; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct BuildRecipe { + pub name: String, + pub version: String, + pub source: SourceConfig, + pub dependencies: Vec, + pub build_steps: Vec, + pub install_steps: Vec, +} + +#[derive(Serialize, Deserialize)] +pub struct SourceConfig { + pub url: String, + pub hash: String, + pub extract_cmd: String, +} + +pub struct AutoBuilder { + pub recipes_dir: String, + pub build_dir: String, + pub install_prefix: String, +} + +impl AutoBuilder { + pub async fn build_package(&self, package_name: &str) -> Result<(), Box> { + // レシピ読み込み + let recipe_path = format!("{}/{}.yaml", self.recipes_dir, package_name); + let recipe_content = fs::read_to_string(recipe_path)?; + let recipe: BuildRecipe = serde_yaml::from_str(&recipe_content)?; + + // 依存関係確認 + for dep in &recipe.dependencies { + self.ensure_dependency(dep).await?; + } + + // ソースダウンロード + self.download_source(&recipe).await?; + + // ビルド実行 + self.execute_build(&recipe).await?; + + Ok(()) + } + + async fn download_source(&self, recipe: &BuildRecipe) -> Result<(), Box> { + let output = Command::new("curl") + .arg("-L") + .arg(&recipe.source.url) + .arg("-o") + .arg(format!("{}.tar.gz", recipe.name)) + .output() + .await?; + + if !output.status.success() { + return Err("Download failed".into()); + } + + // ハッシュ検証 + self.verify_hash(&recipe).await?; + Ok(()) + } + + async fn execute_build(&self, recipe: &BuildRecipe) -> Result<(), Box> { + for step in &recipe.build_steps { + let output = Command::new("sh") + .arg("-c") + .arg(step) + .output() + .await?; + + if !output.status.success() { + return Err(format!("Build step failed: {}", step).into()); + } + } + Ok(()) + } +} +``` + +## 3. systemd統合戦略 + +### Rustサービス実装 + +```rust +// src/systemd_service.rs +use std::process::Command; + +pub struct SystemdService { + pub name: String, + pub description: String, + pub exec_start: String, + pub wants: Vec, + pub after: Vec, +} + +impl SystemdService { + pub fn create_unit_file(&self) -> String { + format!( + r#"[Unit] +Description={} +{} +{} + +[Service] +Type=simple +ExecStart={} +Restart=always + +[Install] +WantedBy=multi-user.target +"#, + self.description, + if self.wants.is_empty() { "".to_string() } else { format!("Wants={}", self.wants.join(" ")) }, + if self.after.is_empty() { "".to_string() } else { format!("After={}", self.after.join(" ")) }, + self.exec_start + ) + } + + pub fn install(&self) -> Result<(), Box> { + let unit_content = self.create_unit_file(); + let unit_path = format!("/etc/systemd/system/{}.service", self.name); + + std::fs::write(unit_path, unit_content)?; + + // systemd reload + Command::new("systemctl") + .arg("daemon-reload") + .output()?; + + // enable service + Command::new("systemctl") + .arg("enable") + .arg(format!("{}.service", self.name)) + .output()?; + + Ok(()) + } +} +``` + +## 4. 実装計画 + +### Phase 1: 基盤構築 +1. Redox OSをベースにしたカスタムOS +2. 基本的なビルドシステム +3. パッケージ管理インフラ + +### Phase 2: systemd統合 +1. systemdサービス管理 +2. D-Bus統合 +3. ネットワーク管理 + +### Phase 3: 本格的なパッケージビルド +1. ソースダウンロード +2. 依存関係解決 +3. 自動ビルド・インストール + +### Phase 4: AI統合 +1. LLM統合 +2. 自動設定 +3. インテリジェント管理 + +この戦略により、段階的に本格的なRust Linux OSを構築できます。 \ No newline at end of file diff --git a/kernel/src/filesystem.rs b/kernel/src/filesystem.rs new file mode 100644 index 0000000..937549e --- /dev/null +++ b/kernel/src/filesystem.rs @@ -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; 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] { + &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", + } + } +} \ No newline at end of file diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 4f045e3..aadf533 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -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); diff --git a/kernel/src/package.rs b/kernel/src/package.rs new file mode 100644 index 0000000..eaebd04 --- /dev/null +++ b/kernel/src/package.rs @@ -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; 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] { + &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(&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 { + 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] { + 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"), + } + } +} \ No newline at end of file diff --git a/kernel/src/simple_package.rs b/kernel/src/simple_package.rs new file mode 100644 index 0000000..09ead97 --- /dev/null +++ b/kernel/src/simple_package.rs @@ -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; 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] { + &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 { + 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(&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("") + } +} \ No newline at end of file