genact/modules/
kernel_compile.rs

1//! Pretend to build a Linux kernel
2use async_trait::async_trait;
3use rand::prelude::*;
4use regex::Regex;
5
6use crate::args::AppConfig;
7use crate::data::CFILES_LIST;
8use crate::io::{csleep, newline, print};
9use crate::modules::Module;
10
11/// Generate a build step for a header file
12fn gen_header(arch: &str, rng: &mut ThreadRng) -> String {
13    const RARE_CMDS: &[&str] = &["SYSTBL ", "SYSHDR "];
14
15    const CMDS: &[&str] = &["WRAP   ", "CHK    ", "UPD    "];
16
17    let cmd = if rng.gen_bool(1.0 / 15.0) {
18        RARE_CMDS.choose(rng).unwrap_or(&"")
19    } else {
20        CMDS.choose(rng).unwrap_or(&"")
21    };
22
23    let cfile = &CFILES_LIST.choose(rng).unwrap_or(&"");
24    let mut file = format!("{}h", &cfile[..cfile.len() - 1]);
25
26    if file.starts_with("arch") {
27        let re = Regex::new(r"arch/([a-z0-9_])+/").unwrap();
28        file = re
29            .replace(&file, format!("arch/{arch}/").as_str())
30            .into_owned();
31    }
32
33    format!("  {cmd} {file}")
34}
35
36/// Generate a build step for an object file
37fn gen_object(arch: &str, rng: &mut ThreadRng) -> String {
38    const RARE_CMDS: &[&str] = &["HOSTCC ", "AS     "];
39
40    let cmd = if rng.gen_bool(1.0 / 15.0) {
41        RARE_CMDS.choose(rng).unwrap_or(&"")
42    } else if rng.gen_bool(0.33) {
43        "AR     "
44    } else {
45        "CC     "
46    };
47
48    let cfile = &CFILES_LIST.choose(rng).unwrap_or(&"");
49    let mut file = format!("{}o", cfile[..cfile.len() - 1].to_owned());
50
51    if file.starts_with("arch") {
52        let re = Regex::new(r"arch/([a-z0-9_])+/").unwrap();
53        file = re
54            .replace(&file, format!("arch/{arch}/").as_str())
55            .into_owned();
56    }
57
58    format!("  {cmd} {file}")
59}
60
61/// Generate a 'special' build step
62fn gen_special(arch: &str, rng: &mut ThreadRng) -> String {
63    const SPECIALS: &[&str] = &[
64        "HOSTLD  arch/ARCH/tools/relocs",
65        "HOSTLD  scripts/mod/modpost",
66        "MKELF   scripts/mod/elfconfig.h",
67        "LDS     arch/ARCH/entry/vdso/vdso32/vdso32.lds",
68        "LDS     arch/ARCH/kernel/vmlinux.lds",
69        "LDS     arch/ARCH/realmode/rm/realmode.lds",
70        "LDS     arch/ARCH/boot/compressed/vmlinux.lds",
71        "EXPORTS arch/ARCH/lib/lib-ksyms.o",
72        "EXPORTS lib/lib-ksyms.o",
73        "MODPOST vmlinux.o",
74        "SORTEX  vmlinux",
75        "SYSMAP  System.map",
76        "VOFFSET arch/ARCH/boot/compressed/../voffset.h",
77        "OBJCOPY arch/ARCH/entry/vdso/vdso32.so",
78        "OBJCOPY arch/ARCH/realmode/rm/realmode.bin",
79        "OBJCOPY arch/ARCH/boot/compressed/vmlinux.bin",
80        "OBJCOPY arch/ARCH/boot/vmlinux.bin",
81        "VDSO2C  arch/ARCH/entry/vdso/vdso-image-32.c",
82        "VDSO    arch/ARCH/entry/vdso/vdso32.so.dbg",
83        "RELOCS  arch/ARCH/realmode/rm/realmode.relocs",
84        "PASYMS  arch/ARCH/realmode/rm/pasyms.h",
85        "XZKERN  arch/ARCH/boot/compressed/vmlinux.bin.xz",
86        "MKPIGGY arch/ARCH/boot/compressed/piggy.S",
87        "DATAREL arch/ARCH/boot/compressed/vmlinux",
88        "ZOFFSET arch/ARCH/boot/zoffset.h",
89    ];
90
91    let special = SPECIALS.choose(rng).unwrap_or(&"").to_string();
92    let special = special.replace("ARCH", arch);
93
94    format!("  {special}")
95}
96
97/// Generates a line from `make` output
98fn gen_line(arch: &str, rng: &mut ThreadRng) -> String {
99    if rng.gen_bool(1.0 / 50.0) {
100        gen_special(arch, rng)
101    } else if rng.gen_bool(0.1) {
102        gen_header(arch, rng)
103    } else {
104        gen_object(arch, rng)
105    }
106}
107
108pub struct KernelCompile;
109
110#[async_trait(?Send)]
111impl Module for KernelCompile {
112    fn name(&self) -> &'static str {
113        "kernel_compile"
114    }
115
116    fn signature(&self) -> String {
117        "sudo make install".to_string()
118    }
119
120    async fn run(&self, appconfig: &AppConfig) {
121        let mut rng = thread_rng();
122        let num_lines = rng.gen_range(50..500);
123
124        const ARCHES: &[&str] = &[
125            "alpha",
126            "arc",
127            "arm",
128            "arm64",
129            "blackfin",
130            "c6x",
131            "cris",
132            "frv",
133            "h8300",
134            "hexagon",
135            "ia64",
136            "m32r",
137            "m68k",
138            "metag",
139            "microblaze",
140            "mips",
141            "mn10300",
142            "nios2",
143            "openrisc",
144            "parisc",
145            "powerpc",
146            "s390",
147            "score",
148            "sh",
149            "sparc",
150            "tile",
151            "um",
152            "unicore32",
153            "x86",
154            "xtensa",
155        ];
156
157        let arch = ARCHES.choose(&mut rng).unwrap_or(&"x86");
158
159        for _ in 1..num_lines {
160            let line = gen_line(arch, &mut rng);
161            let sleep_length = rng.gen_range(10..1000);
162
163            print(line).await;
164            newline().await;
165            csleep(sleep_length).await;
166
167            if appconfig.should_exit() {
168                return;
169            }
170        }
171
172        print(format!("BUILD   arch/{arch}/boot/bzImage")).await;
173        newline().await;
174
175        newline().await;
176
177        let bytes: u32 = rng.gen_range(9000..1_000_000);
178        let padded_bytes: u32 = rng.gen_range(bytes..1_100_000);
179
180        print(format!(
181            "Setup is {bytes} bytes (padded to {padded_bytes} bytes)."
182        ))
183        .await;
184        newline().await;
185
186        let system: u32 = rng.gen_range(300..3000);
187        print(format!("System is {system} kB")).await;
188        newline().await;
189
190        let crc: u32 = rng.gen_range(0x1000_0000..0xffff_ffff);
191
192        print(format!("CRC {crc:x}")).await;
193        newline().await;
194
195        print(format!("Kernel: arch/{arch}/boot/bzImage is ready (#1)")).await;
196        newline().await;
197
198        newline().await;
199    }
200}