Forked from Daniel-Abrecht/my_hello_world_distro.sh
Created
January 25, 2023 21:44
-
-
Save eramax/c48f8d4567fa65a9440b92e1aa407780 to your computer and use it in GitHub Desktop.
Shellscript to build the most minimalistic linux live CD which just starts /sbin/init from the CD root directory and outputs "Hello World!"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Vorhandensein der Programme prüfen | |
MKISOFS=( $(which genisoimage mkisofs) ) | |
if ! [ -x "$MKISOFS" ]; then echo "genisoimage aka mkisofs is missing"; exit 1; fi | |
if ! [ -x "$(which gcc)" ]; then echo "gcc is missing"; exit 1; fi | |
if ! [ -x "$(which nasm)" ]; then echo "nasm is missing"; exit 1; fi | |
if ! [ -x "$(which cpio)" ]; then echo "cpio is missing"; exit 1; fi | |
if ! [ -x "$(which tar)" ]; then echo "tar is missing"; exit 1; fi | |
set -xe # Befehle ausgeben und bei Fehler abbrechen | |
# Label der ISO zum finden des rootfs | |
LABEL="Hello World Distribution" | |
KERNEL="https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.15.tar.xz" | |
# Wichtigste Verzeichnisse anlegen | |
mkdir my_hello_world_distro | |
cd my_hello_world_distro | |
mkdir src initramfs bin/{,musl} rootfs/{,boot,sbin} | |
pushd src | |
# Kernel erstellen | |
wget "$KERNEL" | |
tar -xf "$(basename $KERNEL)" | |
pushd "$(basename $KERNEL .tar.xz)" | |
make olddefconfig # Kernel Config vom Hostsystem übernehmen | |
# make localyesconfig # Minimale Kernel Config für diesen PC | |
make -j 9 | |
# make INSTALL_PATH=../../rootfs/boot/ install # This line is commented because it calls /sbin/installkernel, which may do unwanted things | |
cp "$(make image_name)" ../../rootfs/boot/vmlinuz | |
make INSTALL_MOD_PATH=../../rootfs/ modules_install | |
popd | |
# Musl libc builden | |
git clone git://git.musl-libc.org/musl | |
pushd musl | |
./configure --prefix="$PWD/../../bin/musl" | |
make -j 9 | |
make install | |
popd | |
# Das init/Hello World Program erstellen | |
mkdir init | |
pushd init | |
cat > init.c <<EOF | |
#include <stdio.h> | |
#include <unistd.h> | |
int main(){ | |
sleep(1); | |
printf("\033[3J\033[H\033[2J"); // Clear screen | |
printf("Hello World!\n"); // Print Hello World | |
while(1) sleep(10); // Wait forever | |
} | |
EOF | |
../../bin/musl/bin/musl-gcc -static init.c -o ../../rootfs/sbin/init | |
popd | |
# initrd/initramfs erstellen (wird gebraucht um die CD zu suchen & module zu laden) | |
mkdir initramfs | |
# Kopieren aller Module, die zum Mounten von / benötigt werden könnten | |
MODDIR=( $(basename ../rootfs/lib/modules/*) ) | |
cat > ../initramfs/module_list <<EOF | |
kernel/lib/crc16.ko | |
kernel/crypto/xor.ko | |
kernel/crypto/crc32_generic.ko | |
kernel/crypto/crc32.ko | |
kernel/fs/mbcache.ko | |
kernel/fs/jbd2/jbd2.ko | |
kernel/drivers/cdrom/cdrom.ko | |
kernel/drivers/scsi/scsi_mod.ko | |
kernel/drivers/ata/libata.ko | |
kernel/drivers/usb/common/usb-common.ko | |
kernel/drivers/usb/core/usbcore.ko | |
kernel/drivers/usb/misc/ldusb.ko | |
kernel/drivers/usb/misc/ezusb.ko | |
kernel/drivers/ata/libahci.ko | |
kernel/drivers/scsi/sr_mod.ko | |
kernel/drivers/scsi/sd_mod.ko | |
kernel/drivers/scsi/sg.ko | |
kernel/drivers/scsi/scsi_transport_iscsi.ko | |
kernel/drivers/scsi/libiscsi.ko | |
kernel/drivers/scsi/scsi_transport_sas.ko | |
kernel/drivers/scsi/libsas/libsas.ko | |
kernel/drivers/scsi/isci/isci.ko | |
kernel/drivers/mmc/core/mmc_core.ko | |
kernel/drivers/mmc/card/mmc_block.ko | |
kernel/drivers/mmc/host/sdhci.ko | |
kernel/drivers/mmc/host/sdhci-pci.ko | |
kernel/drivers/mmc/host/sdhci-acpi.ko | |
kernel/drivers/memstick/core/memstick.ko | |
kernel/drivers/mfd/mfd-core.ko | |
kernel/drivers/mfd/rtsx_usb.ko | |
kernel/drivers/memstick/host/rtsx_usb_ms.ko | |
kernel/drivers/mmc/host/rtsx_usb_sdmmc.ko | |
kernel/drivers/usb/storage/usb-storage.ko | |
kernel/drivers/usb/storage/ums-alauda.ko | |
kernel/drivers/usb/storage/ums-freecom.ko | |
kernel/drivers/usb/storage/ums-onetouch.ko | |
kernel/drivers/usb/storage/ums-usbat.ko | |
kernel/drivers/usb/storage/ums-cypress.ko | |
kernel/drivers/usb/storage/ums-isd200.ko | |
kernel/drivers/usb/storage/ums-realtek.ko | |
kernel/drivers/usb/storage/ums-datafab.ko | |
kernel/drivers/usb/storage/ums-jumpshot.ko | |
kernel/drivers/usb/storage/ums-sddr09.ko | |
kernel/drivers/usb/storage/ums-eneub6250.ko | |
kernel/drivers/usb/storage/ums-karma.ko | |
kernel/drivers/usb/storage/ums-sddr55.ko | |
kernel/drivers/usb/host/ohci-hcd.ko | |
kernel/drivers/usb/host/xhci-hcd.ko | |
kernel/drivers/usb/host/uhci-hcd.ko | |
kernel/drivers/usb/host/ehci-hcd.ko | |
kernel/drivers/usb/host/ohci-pci.ko | |
kernel/drivers/usb/host/ehci-pci.ko | |
kernel/drivers/ata/pata_atiixp.ko | |
kernel/drivers/ata/pata_rdc.ko | |
kernel/drivers/ata/sata_via.ko | |
kernel/drivers/ata/pata_ninja32.ko | |
kernel/drivers/ata/sata_svw.ko | |
kernel/drivers/ata/pata_ns87415.ko | |
kernel/drivers/ata/pata_oldpiix.ko | |
kernel/drivers/ata/pata_hpt366.ko | |
kernel/drivers/ata/ata_piix.ko | |
kernel/drivers/ata/sata_promise.ko | |
kernel/drivers/ata/pata_triflex.ko | |
kernel/drivers/ata/pata_cmd64x.ko | |
kernel/drivers/ata/sata_qstor.ko | |
kernel/drivers/ata/pata_sil680.ko | |
kernel/drivers/ata/sata_uli.ko | |
kernel/drivers/ata/pata_artop.ko | |
kernel/drivers/ata/sata_sil24.ko | |
kernel/drivers/ata/pata_pdc2027x.ko | |
kernel/drivers/pcmcia/pcmcia_core.ko | |
kernel/drivers/pcmcia/pcmcia.ko | |
kernel/drivers/ata/pata_pcmcia.ko | |
kernel/drivers/ata/pata_jmicron.ko | |
kernel/drivers/ata/sata_sil.ko | |
kernel/drivers/ata/pata_it821x.ko | |
kernel/drivers/ata/pata_sis.ko | |
kernel/drivers/ata/pata_ali.ko | |
kernel/drivers/ata/pata_efar.ko | |
kernel/drivers/ata/pata_ns87410.ko | |
kernel/drivers/ata/pata_netcell.ko | |
kernel/drivers/ata/pata_amd.ko | |
kernel/drivers/ata/sata_sx4.ko | |
kernel/drivers/ata/sata_nv.ko | |
kernel/drivers/ata/pdc_adma.ko | |
kernel/drivers/ata/acard-ahci.ko | |
kernel/drivers/ata/pata_via.ko | |
kernel/drivers/ata/pata_piccolo.ko | |
kernel/drivers/ata/pata_rz1000.ko | |
kernel/drivers/ata/pata_it8213.ko | |
kernel/drivers/ata/ata_generic.ko | |
kernel/drivers/ata/ahci.ko | |
kernel/drivers/ata/pata_serverworks.ko | |
kernel/drivers/ata/pata_marvell.ko | |
kernel/drivers/ata/pata_mpiix.ko | |
kernel/drivers/ata/sata_mv.ko | |
kernel/drivers/ata/pata_sch.ko | |
kernel/drivers/ata/pata_hpt37x.ko | |
kernel/drivers/ata/sata_vsc.ko | |
kernel/drivers/ata/pata_pdc202xx_old.ko | |
kernel/drivers/ata/pata_atp867x.ko | |
kernel/drivers/ata/sata_sis.ko | |
kernel/fs/ext4/ext4.ko | |
kernel/fs/isofs/isofs.ko | |
EOF | |
while read mod | |
do | |
m="$MODDIR/$mod" | |
if [ ! -f "../rootfs/lib/modules/$m" ]; then continue; fi | |
mkdir -p $(dirname "../initramfs/lib/modules/$m") | |
cp "../rootfs/lib/modules/$m" "../initramfs/lib/modules/$m" | |
done < ../initramfs/module_list | |
# Init Program für initramfs zum laden der Module, mounten des echten root FS & strten des eigentlichen init | |
pushd initramfs | |
cat > init.c <<EOF | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/mount.h> | |
#include <sys/syscall.h> | |
#include <fcntl.h> | |
#include <stdbool.h> | |
#include <dirent.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
void exitfunc(void){ | |
sleep(10); | |
} | |
// search for a device containing an iso with the right label | |
char* find_root(void){ | |
char* root = 0; | |
char label[33] = LABEL; | |
label[32] = 0; | |
puts("Searching root FS"); | |
int dev = open("/dev/",O_DIRECTORY); | |
DIR* dir = fdopendir(dev); | |
struct dirent* entry; | |
while(entry=readdir(dir)){ | |
if( strncmp(entry->d_name,"sr",2) | |
&& strncmp(entry->d_name,"mmcblk",2) | |
&& strncmp(entry->d_name,"sd",2) | |
) continue; | |
printf("Checking /dev/%s\n",entry->d_name); | |
int fd = openat(dev,entry->d_name,O_RDONLY); | |
if( fd == -1 ) | |
continue; | |
if( lseek(fd, 33342, SEEK_SET) == -1 ) | |
goto next; | |
char result[33] = {0}; | |
if( read(fd,result,strlen(label)) != strlen(label) ) | |
goto next; | |
close(fd); | |
if( !strcmp(label, result) ){ | |
root = malloc(5+strlen(entry->d_name)+1); | |
memcpy(root,"/dev/",5); | |
strcpy(root+5, entry->d_name); | |
break; | |
} | |
continue; | |
next: | |
close(fd); | |
} | |
closedir(dir); | |
return root; | |
} | |
// Modul laden | |
bool load_module(int fd, const char* name){ | |
int init_module(void *module_image, unsigned long len, const char *param_values); | |
FILE* f = fdopen(fd, "r"); | |
if(!f){ | |
perror("load_module: fdopen failed"); | |
return false; | |
} | |
if( fseek(f, 0, SEEK_END) == -1 ){ | |
perror("load_module: fseek failed"); | |
goto failed_fdopen; | |
} | |
long l = ftell(f); | |
if( l < 0 ){ | |
perror("load_module: ftell failed"); | |
goto failed_fdopen; | |
} | |
if( fseek(f, 0, SEEK_SET) == -1 ){ | |
perror("load_module: fseek failed"); | |
goto failed_fdopen; | |
} | |
char* buf = malloc(l); | |
if(!buf){ | |
perror("load_module: malloc failed"); | |
goto failed_fdopen; | |
} | |
if( fread(buf,1,l,f) == -1 ){ | |
perror("load_module: fread failed"); | |
goto failed_malloc; | |
} | |
char* params = alloca(5+strlen(name)+1); | |
strcpy(params,"name="); | |
strcpy(params+5,name); | |
if( init_module(buf,l,params) == -1 ){ | |
perror("load_module: init_module failed"); | |
goto failed_malloc; | |
} | |
free(buf); | |
fclose(f); | |
return true; | |
failed_malloc: | |
free(buf); | |
failed_fdopen: | |
fclose(f); | |
return false; | |
} | |
int main(int argc, const char* argv[]){ | |
atexit(exitfunc); | |
// Mount /dev | |
if( mount("none","/dev","devtmpfs",0,"rw") == -1 ){ | |
perror("mounting devtmpfs failed\n"); | |
return 1; | |
} | |
int dir = open("/lib/modules/" MODDIR, O_DIRECTORY|O_RDONLY); | |
FILE* list = fopen("/module_list","r"); | |
if( dir != -1 && list ){ | |
char buf[257]; | |
while(fgets(buf,256,list)){ | |
unsigned long l = strlen(buf); | |
if(l && buf[l-1]=='\n') buf[l-1] = 0; | |
const char* s = strrchr(buf,'/'); | |
if(!s) continue; | |
int f = openat(dir,buf,O_RDONLY); | |
if(f == -1) continue; | |
printf("Loading module %s ",buf); | |
fflush(stdout); | |
bool res = load_module(f,s+1); | |
puts(res ? "OK" : ""); | |
close(f); | |
} | |
} | |
close(dir); | |
fclose(list); | |
char* root; | |
for( int i=0; !(root=find_root()) && i<3; i++) | |
sleep(i+1); | |
if(!root){ | |
fprintf(stderr,"Root FS not found\n"); | |
return 2; | |
}else | |
printf("Root found at %s\n",root); | |
// mount root & switch to real root & start real init | |
if( mount(root,"/root/","iso9660",MS_RDONLY,"") == -1 ){ | |
perror("mount failed"); | |
return 3; | |
} | |
free(root); | |
umount("/dev/"); | |
if( chroot("/root/") ){ | |
perror("chroot failed"); | |
return 4; | |
} | |
argv[0] = "/sbin/init"; | |
execv("/sbin/init",(void*)argv); | |
perror("execv /sbin/init failed"); | |
return 5; | |
} | |
EOF | |
../../bin/musl/bin/musl-gcc -D "LABEL=\"$LABEL\"" -D "MODDIR=\"$MODDIR\"" -static init.c -o ../../initramfs/init | |
pushd ../../initramfs/ | |
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs/boot/initramfs.cpio.gz | |
popd | |
popd | |
# Syslinux bootloader builden | |
wget https://www.kernel.org/pub/linux/utils/boot/syslinux/Testing/6.04/syslinux-6.04-pre1.tar.gz | |
tar -xf syslinux-6.04-pre1.tar.gz | |
pushd syslinux-6.04-pre1 | |
make | |
popd | |
popd | |
# Syslinux dateien kopieren | |
mkdir rootfs/efi/{,boot} | |
mkdir rootfs/syslinux | |
cp src/syslinux-6.04-pre1/efi64/efi/syslinux.efi rootfs/efi/boot/bootx64.efi | |
cp src/syslinux-6.04-pre1/bios/com32/elflink/ldlinux/ldlinux.c32 rootfs/syslinux/ | |
cp src/syslinux-6.04-pre1/bios/core/isolinux.bin rootfs/syslinux/ | |
cat > rootfs/syslinux/syslinux.cfg <<EOF | |
default linux | |
prompt 0 | |
timeout 0 | |
label linux | |
initrd /boot/initramfs.cpio.gz | |
kernel /boot/vmlinuz quiet | |
EOF | |
# ISO erstellen | |
rm -r rootfs/lib/ # Nicht benötigte Module löschen | |
"$MKISOFS" -r -l -o hello_world_distro.iso -b syslinux/isolinux.bin -c syslinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -A "$LABEL" -input-charset utf-8 rootfs | |
./src/syslinux-6.04-pre1/bios/utils/isohybrid hello_world_distro.iso |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment