1use crate::api::console::Style;
2use crate::api::fs;
3use crate::api::io;
4use crate::api::process::ExitCode;
5use crate::api::syscall;
6use crate::{api, sys, usr};
7
8use alloc::format;
9use alloc::string::String;
10
11macro_rules! copy_file {
12 ($path:expr, $verbose:expr) => ({
13 copy_file($path, include_bytes!(concat!("../../dsk", $path)), $verbose);
14 });
15}
16
17pub fn copy_files(verbose: bool) {
18 create_dir("/bin", verbose); create_dir("/dev", verbose); create_dir("/ini", verbose); create_dir("/lib", verbose); create_dir("/net", verbose); create_dir("/src", verbose); create_dir("/tmp", verbose); create_dir("/usr", verbose); create_dir("/var", verbose); copy_file!("/bin/clear", verbose);
34 copy_file!("/bin/halt", verbose);
39 copy_file!("/bin/ntp", verbose);
42 copy_file!("/bin/pkg", verbose);
43 copy_file!("/bin/print", verbose);
44 copy_file!("/bin/reboot", verbose);
45 copy_file!("/bin/sleep", verbose);
46
47 create_dir("/dev/ata", verbose); create_dir("/dev/ata/0", verbose);
49 create_dir("/dev/ata/1", verbose);
50 create_dir("/dev/clk", verbose); create_dir("/dev/net", verbose); create_dir("/dev/vga", verbose);
53
54 create_dev("/dev/ata/0/0", "ata-0-0", verbose);
55 create_dev("/dev/ata/0/1", "ata-0-1", verbose);
56 create_dev("/dev/ata/1/0", "ata-1-0", verbose);
57 create_dev("/dev/ata/1/1", "ata-1-1", verbose);
58 create_dev("/dev/clk/boot", "clk-boot", verbose);
59 create_dev("/dev/clk/epoch", "clk-epoch", verbose);
60 create_dev("/dev/clk/rtc", "clk-rtc", verbose);
61 create_dev("/dev/console", "console", verbose);
62 create_dev("/dev/net/tcp", "net-tcp", verbose);
63 create_dev("/dev/net/udp", "net-udp", verbose);
64 create_dev("/dev/net/gw", "net-gw", verbose);
65 create_dev("/dev/net/ip", "net-ip", verbose);
66 create_dev("/dev/net/mac", "net-mac", verbose);
67 create_dev("/dev/net/usage", "net-usage", verbose);
68 create_dev("/dev/null", "null", verbose);
69 create_dev("/dev/random", "random", verbose);
70 create_dev("/dev/speaker", "speaker", verbose);
71 create_dev("/dev/vga/buffer", "vga-buffer", verbose);
72 create_dev("/dev/vga/font", "vga-font", verbose);
73 create_dev("/dev/vga/mode", "vga-mode", verbose);
74 create_dev("/dev/vga/palette", "vga-palette", verbose);
75
76 copy_file!("/ini/banner.txt", verbose);
77 copy_file!("/ini/boot.sh", verbose);
78 copy_file!("/ini/lisp.lsp", verbose);
79 copy_file!("/ini/shell.sh", verbose);
80 copy_file!("/ini/version.txt", verbose);
81
82 create_dir("/ini/palettes", verbose);
83 copy_file!("/ini/palettes/default.sh", verbose);
84 copy_file!("/ini/palettes/gruvbox-dark.sh", verbose);
85 copy_file!("/ini/palettes/gruvbox-light.sh", verbose);
86
87 create_dir("/ini/fonts", verbose);
88 copy_file!("/ini/fonts/zap-light-8x16.psf", verbose);
90 create_dir("/lib/lisp", verbose);
93 copy_file!("/lib/lisp/alias.lsp", verbose);
94 copy_file!("/lib/lisp/core.lsp", verbose);
95 copy_file!("/lib/lisp/file.lsp", verbose);
96 copy_file!("/lib/lisp/ini.lsp", verbose);
97 copy_file!("/lib/lisp/math.lsp", verbose);
99
100 copy_file!("/tmp/alice.txt", verbose);
101 create_dir("/var/log", verbose);
137
138 create_dir("/var/www", verbose);
139 copy_file!("/var/www/index.html", verbose);
140 copy_file!("/var/www/moros.css", verbose);
141 copy_file!("/var/www/moros.png", verbose);
142
143 create_dir("/var/pkg", verbose);
144}
145
146pub fn main(args: &[&str]) -> Result<(), ExitCode> {
147 let csi_color = Style::color("yellow");
148 let csi_reset = Style::reset();
149 println!(
150 "{}Welcome to MOROS v{} installation program!{}",
151 csi_color,
152 env!("CARGO_PKG_VERSION"),
153 csi_reset
154 );
155 println!();
156
157 let mut has_confirmed = false;
158 for &arg in args {
159 match arg {
160 "-y" | "--yes" => has_confirmed = true,
161 _ => continue,
162 }
163 }
164 if !has_confirmed {
165 print!("Proceed? [y/N] ");
166 has_confirmed = io::stdin().read_line().trim() == "y";
167 println!();
168 }
169
170 if has_confirmed {
171 if !sys::fs::is_mounted() {
172 println!("{}Listing disks ...{}", csi_color, csi_reset);
173 usr::shell::exec("disk list").ok();
174 println!("/dev/mem RAM DISK");
175 println!();
176
177 println!("{}Formatting disk ...{}", csi_color, csi_reset);
178 print!("Enter path of disk to format: ");
179 let path = io::stdin().read_line();
180 if path.trim_end() == "/dev/mem" {
181 usr::shell::exec(&format!("memory format"))?;
182 } else {
183 usr::shell::exec(&format!("disk format {}", path.trim_end()))?;
184 }
185 println!();
186 }
187
188 println!("{}Populating filesystem...{}", csi_color, csi_reset);
189 let verbose = true;
190 copy_files(verbose);
191
192 if sys::process::user().is_none() {
193 println!();
194 println!("{}Creating user...{}", csi_color, csi_reset);
195 let res = usr::user::main(&["user", "create"]);
196 if res == Err(ExitCode::Failure) {
197 return res;
198 }
199 }
200
201 println!();
202 println!("{}Installation successful!{}", csi_color, csi_reset);
203 println!();
204 println!("Quit the console or reboot to apply changes");
205 }
206
207 Ok(())
208}
209
210fn create_dir(path: &str, verbose: bool) {
211 if fs::exists(path) {
212 return;
213 }
214 if verbose {
215 println!("Creating '{}'", path);
216 }
217 if let Some(handle) = api::fs::create_dir(path) {
218 syscall::close(handle);
219 }
220}
221
222fn create_dev(path: &str, name: &str, verbose: bool) {
223 if fs::exists(path) {
224 return;
225 }
226 if verbose {
227 println!("Creating '{}'", path);
228 }
229 if let Some(handle) = fs::create_device(path, name) {
230 syscall::close(handle);
231 }
232}
233
234fn copy_file(path: &str, buf: &[u8], verbose: bool) {
235 if fs::exists(path) {
236 return;
237 }
238 if verbose {
239 println!("Fetching '{}'", path);
240 }
241 if path.ends_with(".txt") {
242 if let Ok(text) = String::from_utf8(buf.to_vec()) {
243 let text = text.replace("{x.x.x}", env!("CARGO_PKG_VERSION"));
244 fs::write(path, text.as_bytes()).ok();
245 } else {
246 fs::write(path, buf).ok();
247 }
248 } else {
249 fs::write(path, buf).ok();
250 }
251}