195 lines
5.7 KiB
Rust
195 lines
5.7 KiB
Rust
use super::{download, run, run_chroot, tempfile, Image};
|
|
use crate::setup::Setup;
|
|
use anyhow::Context as _;
|
|
use std::{
|
|
fs::{self, File},
|
|
io::Write as _,
|
|
path::Path
|
|
};
|
|
|
|
pub fn init_os(setup: &Setup, img: &Image) -> anyhow::Result<()> {
|
|
eprintln!("Preparing operating system ...");
|
|
|
|
// write raspberry pi config
|
|
fs::write(img.boot.0.join("cmdline.txt"), &setup.os.rpi.cmdline)?;
|
|
let mut config = File::create(img.boot.0.join("config.txt"))?;
|
|
writeln!(
|
|
config,
|
|
r#"# Do not modify this file. Create and/or modify usercfg.txt instead.
|
|
[pi3]
|
|
kernel=vmlinuz-rpi
|
|
initramfs initramfs-rpi
|
|
[pi3+]
|
|
kernel=vmlinuz-rpi
|
|
initramfs initramfs-rpi
|
|
[pi4]
|
|
enable_gic=1
|
|
kernel=vmlinuz-rpi4
|
|
initramfs initramfs-rpi4
|
|
[all]"#
|
|
)?;
|
|
if setup.os.alpine.arch.is64bit() {
|
|
writeln!(config, "arm_64bit=1")?;
|
|
}
|
|
writeln!(config, "include usercfg.txt")?;
|
|
drop(config);
|
|
fs::write(img.boot.0.join("usercfg.txt"), &setup.os.rpi.usercfg)?;
|
|
|
|
// write initial apk config
|
|
let etc = img.root.0.join("etc");
|
|
let etc_apk = etc.join("apk");
|
|
let etc_apk_keys = etc_apk.join("keys");
|
|
fs::create_dir_all(&etc_apk_keys).context("Failed to create /etc/apk/keys directory")?;
|
|
let mut repositories = File::create(etc_apk.join("repositories"))?;
|
|
for repo in ["main", "community"] {
|
|
writeln!(repositories, "{}/{}/{repo}", setup.os.alpine.mirror, setup.os.alpine.branch)?;
|
|
}
|
|
for repo in &setup.os.alpine.extra_repos {
|
|
writeln!(repositories, "{repo}")?;
|
|
}
|
|
drop(repositories);
|
|
|
|
// download apk keys
|
|
let keys = tempfile()?;
|
|
download(
|
|
keys.path(),
|
|
&format!(
|
|
"https://gitlab.alpinelinux.org/alpine/aports/-/archive/{branch}/aports-{branch}.tar.bz2?path=main/alpine-keys",
|
|
branch = setup.os.alpine.branch.git_branch()
|
|
)
|
|
)?;
|
|
run(&[
|
|
"tar",
|
|
"xfj",
|
|
keys.path().to_str().unwrap(),
|
|
"-C",
|
|
etc_apk_keys.to_str().unwrap(),
|
|
"--strip-components=3",
|
|
"--wildcards",
|
|
"*/alpine-devel@lists.alpinelinux.org-*.rsa.pub"
|
|
])?;
|
|
drop(keys);
|
|
|
|
// copy additional keys
|
|
for key in &setup.os.alpine.extra_keys {
|
|
let key = Path::new(key);
|
|
let name = key.file_name().unwrap();
|
|
fs::copy(Path::new("setup").join(key), etc_apk_keys.join(name))?;
|
|
}
|
|
|
|
// bootstrap alpine
|
|
run(&[
|
|
"docker",
|
|
"run",
|
|
"--rm",
|
|
"-v",
|
|
&format!("{root}:{root}", root = &*img.root),
|
|
"alpine",
|
|
"apk",
|
|
"add",
|
|
"--root",
|
|
&img.root,
|
|
"--update-cache",
|
|
"--initdb",
|
|
"--arch",
|
|
setup.os.alpine.arch.to_str(),
|
|
"agetty",
|
|
"alpine-base",
|
|
"alpine-sdk",
|
|
"ca-certificates",
|
|
"elogind",
|
|
"eudev",
|
|
"haveged",
|
|
"linux-rpi",
|
|
"linux-rpi4",
|
|
"openssh",
|
|
"parted",
|
|
"raspberrypi-bootloader",
|
|
"sudo",
|
|
"tzdata",
|
|
"udev-init-scripts",
|
|
"util-linux-login",
|
|
"zram-init"
|
|
])?;
|
|
run(&[
|
|
"sed",
|
|
"-E",
|
|
"-e",
|
|
"s,getty(.*)$,agetty --noclear\\1 linux,",
|
|
"-i",
|
|
etc.join("inittab").to_str().unwrap()
|
|
])?;
|
|
for service in ["udev", "udev-postmount", "udev-settle", "udev-trigger"] {
|
|
run_chroot(img, "root", ["rc-update", "add", service, "sysinit"])?;
|
|
}
|
|
for service in ["modules", "syslog", "swclock"] {
|
|
run_chroot(img, "root", ["rc-update", "add", service, "boot"])?;
|
|
}
|
|
for service in ["elogind", "haveged", "ntpd", "sshd"] {
|
|
run_chroot(img, "root", ["rc-update", "add", service, "default"])?;
|
|
}
|
|
|
|
// configure fstab
|
|
fs::write(
|
|
etc.join("fstab"),
|
|
r#"# <device> <dir> <type> <options> <dump> <fsck>
|
|
/dev/mmcblk0p1 /boot vfat defaults 0 2
|
|
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
|
|
"#
|
|
)?;
|
|
|
|
// something is broken with abuild's functions.sh, so let's set CBUILD ourselves
|
|
let profile_d = etc.join("profile.d");
|
|
fs::create_dir_all(&profile_d)?;
|
|
fs::write(
|
|
profile_d.join("cbuild.sh"),
|
|
&format!("export CBUILD={}", setup.os.alpine.arch.cbuild())
|
|
)?;
|
|
|
|
// set up the locale
|
|
run_chroot(img, "root", ["setup-hostname", &setup.os.host.hostname])?;
|
|
run_chroot(img, "root", ["setup-timezone", "-z", &setup.os.host.timezone])?;
|
|
if let Some(variant) = setup.os.host.keymap_variant.as_deref() {
|
|
run_chroot(img, "root", ["setup-keymap", &setup.os.host.keymap, variant])?;
|
|
} else {
|
|
run_chroot(img, "root", ["setup-keymap", &setup.os.host.keymap])?;
|
|
}
|
|
|
|
// set up a user that we can use to install packages
|
|
run_chroot(img, "root", ["adduser", "-D", "mkalpiimg"])?;
|
|
run_chroot(img, "root", ["adduser", "mkalpiimg", "abuild"])?;
|
|
run_chroot(img, "root", "echo mkalpiimg:mkalpiimg | chpasswd")?;
|
|
fs::write(etc.join("sudoers.d").join("mkalpiimg"), "%abuild ALL=(ALL) NOPASSWD: ALL")?;
|
|
fs::create_dir_all(img.root.0.join("var").join("cache").join("distfiles"))?;
|
|
run_chroot(img, "root", "chgrp abuild /var/cache/distfiles; chmod 775 /var/cache/distfiles")?;
|
|
run_chroot(img, "mkalpiimg", ["abuild-keygen", "-a", "-n", "-b", "4096"])?;
|
|
run_chroot(img, "root", "cp /home/mkalpiimg/.abuild/*.rsa.pub /etc/apk/keys/")?;
|
|
|
|
// avoid a bug with cargo in qemu: https://github.com/rust-lang/cargo/issues/10583
|
|
let cargo = img.root.0.join("home").join("mkalpiimg").join(".cargo");
|
|
fs::create_dir_all(&cargo)?;
|
|
fs::write(cargo.join("config.toml"), "[net]\ngit-fetch-with-cli = true\n")?;
|
|
|
|
// set up the other users as requested
|
|
fs::write(etc.join("sudoers.d").join("wheel"), "%wheel ALL=(ALL:ALL) ALL")?;
|
|
for user in &setup.os.user {
|
|
run_chroot(img, "root", ["adduser", "-s", "/bin/ash", "-D", &user.name])?;
|
|
if user.sudo {
|
|
run_chroot(img, "root", ["adduser", &user.name, "wheel"])?;
|
|
}
|
|
for grp in &user.groups {
|
|
run_chroot(img, "root", ["adduser", &user.name, grp])?;
|
|
}
|
|
let ssh = img.root.0.join("home").join(&user.name).join(".ssh");
|
|
fs::create_dir_all(&ssh)?;
|
|
let mut keys = File::create(ssh.join("authorized_keys"))?;
|
|
for key in &user.authorized_keys {
|
|
writeln!(keys, "{key}")?;
|
|
}
|
|
drop(keys);
|
|
run_chroot(img, "root", ["chown", "-R", &user.name, &format!("/home/{}/.ssh", user.name)])?;
|
|
run_chroot(img, &user.name, "chmod 700 ~/.ssh; chmod 600 ~/.ssh/*")?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|