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

View File

@ -4,6 +4,7 @@ members = [
"user",
"claude-service",
]
resolver = "2"
[workspace.package]
version = "2.0.0"

1
archiso Submodule

Submodule archiso added at 9089013c44

17
docker-build.sh Normal file
View File

@ -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."

293
docs/MINIMAL_OS_DESIGN.md Normal file
View File

@ -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 # 128MiBRedoxの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**を実現できます。

View File

@ -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<String>,
}
impl PackageBuilder {
pub async fn download_source(&self) -> Result<(), Box<dyn std::error::Error>> {
// 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<dyn std::error::Error>> {
Command::new("tar")
.arg("xzf")
.arg(format!("{}-{}.tar.gz", self.name, self.version))
.output()?;
Ok(())
}
pub fn build(&self) -> Result<(), Box<dyn std::error::Error>> {
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<String>,
pub build_steps: Vec<String>,
pub install_steps: Vec<String>,
}
#[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<dyn std::error::Error>> {
// レシピ読み込み
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<String>,
pub after: Vec<String>,
}
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<dyn std::error::Error>> {
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を構築できます。

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("")
}
}