Skip to content

Instantly share code, notes, and snippets.

@Daniel-Abrecht
Created January 28, 2018 21:56
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Daniel-Abrecht/b745fab790fc6354ce7267e58e91d579 to your computer and use it in GitHub Desktop.
Save Daniel-Abrecht/b745fab790fc6354ce7267e58e91d579 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!"
#!/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