Skip to content

Instantly share code, notes, and snippets.

@rma92
Last active November 13, 2025 20:05
Show Gist options
  • Select an option

  • Save rma92/5389a25458ac6760c3aa460b5c1cab6e to your computer and use it in GitHub Desktop.

Select an option

Save rma92/5389a25458ac6760c3aa460b5c1cab6e to your computer and use it in GitHub Desktop.

Building a small base for embedded systems on OpenBSD

The following will be removed

  • relinking sources
  • libs for X11 and base will be stripped. The following will be moved from base and X11 to comp
  • Clang (which is huge, and only present in the base image to help with the relinking)
  • All include files for X11 The following will be moved from base, and X11 to the man package
  • All man, info, and doc files

With these changes, the disk footprint becomes tiny while retaining nearly all practical system functionality. This is intended for embedded / appliance applications that might boot from a small read-only disk. Small systems are unable to perform the reliking anyway, or it takes excessively long.

With the new ISO file, we can choose to install just base or base + x servers and have minimal footprint. Or install man and comp as well, and the system is normal minus relinking.

Steps

  • Install OpenBSD normally. I put it in a single partition for processing. Only base.tgz install (and bsd/bsd.mp) are needed.
    • If this is a local VM, possibly enable root SSH so that commands can be pasted into terminal more easily.
  • Boot into the new system with the cd inserted, login as root
  • Notes:
    • Adjust the version if needed.
    • the p in tar xzpf is important to retain file permissions - setuid/setgid binaries, some special directories, and some files owned by daemon users are not owned by root.
  • The script will move all man pages to the man package, and all compiler related stuff to the compiler packages.
  • Kernel relink will be removed as it may not even run on an embedded system, and isn't a major impact to security in this situation.

Setup shrinking everything, and putting compilers into compiler folder.

mkdir -p /tmp/cdroot
mount -t cd9660 /dev/cd0a /mnt/cdrom
#umount /mnt/cdrom

cd /tmp/cdroot
cp -r /mnt/cdrom/* /tmp/cdroot/
ARCH=amd64
VERSION=78
VERSIOND=7.8
CDPATH=/tmp/cdroot/$VERSIOND/$ARCH

mkdir -p "/tmp/base${VERSION}"
mkdir -p "/tmp/comp${VERSION}"
mkdir -p "/tmp/man${VERSION}"
mkdir -p "/tmp/xbase${VERSION}"
# mkdir -p "/tmp/xfont${VERSION}"
mkdir -p "/tmp/xserv${VERSION}"
mkdir -p "/tmp/xshare${VERSION}"


tar xzpf "${CDPATH}/base${VERSION}.tgz" -C "/tmp/base${VERSION}"
tar xzpf "${CDPATH}/comp${VERSION}.tgz" -C "/tmp/comp${VERSION}"
tar xzpf "${CDPATH}/man${VERSION}.tgz" -C "/tmp/man${VERSION}"
tar xzpf "${CDPATH}/xbase${VERSION}.tgz" -C "/tmp/xbase${VERSION}"
tar xzpf "${CDPATH}/xserv${VERSION}.tgz" -C "/tmp/xserv${VERSION}"
tar xzpf "${CDPATH}/xshare${VERSION}.tgz" -C "/tmp/xshare${VERSION}"

# base78.tgz
cd "/tmp/base${VERSION}"
du -sh .
touch etc/no_relink etc/no_reorder_kernel
rm -rf usr/share/relink
cp -r usr/share/man/* /tmp/man78/usr/share/man/
rm -rf usr/share/man/*
cp -r usr/share/info/* /tmp/man78/usr/share/info/
rm -rf usr/share/info
rm -rf usr/games/*
mv usr/share/doc/* /tmp/man78/usr/share/doc/

#perl - breaks pkg_add
# rm usr/bin/perl
# rm usr/libdata/perl*

#build
mv usr/bin/c++ /tmp/comp78/usr/bin
mv usr/bin/cc /tmp/comp78/usr/bin
mv usr/bin/clang /tmp/comp78/usr/bin
mv usr/bin/clang++ /tmp/comp78/usr/bin
mv usr/bin/clang-cpp /tmp/comp78/usr/bin
mv usr/bin/ld /tmp/comp78/usr/bin
mv usr/bin/ld.lld /tmp/comp78/usr/bin
mv usr/libexec/cpp /tmp/comp78/usr/bin
mv usr/lib/libLLVM* /tmp/comp78/usr/bin
mv usr/lib/*.a /tmp/comp78/usr/bin
mv usr/lib/*.o /tmp/comp78/usr/bin
cp -r usr/share/mk/ /tmp/comp78/usr/share/mk/
rm -rf usr/share/mk
# rm -rf etc/firmware
mv usr/share/misc /tmp/comp78/usr/share/misc
mkdir -p /tmp/man78/usr/bin
mv usr/bin/man /tmp/man78/usr/bin/man
mv usr/bin/mandoc /tmp/man78/usr/bin/mandoc
mkdir -p /tmp/man78/etc/examples/
mv etc/examples/man.conf /tmp/man78/etc/examples/man.conf

find usr/lib -type f -name 'lib*.so.*' -exec /usr/bin/strip -s {} +

du -sh .

# xbase
cd "/tmp/xbase${VERSION}"
du -sh .
find usr/X11R6/lib -type f -name 'lib*.so.*' -exec /usr/bin/strip -s {} +
mkdir -p /tmp/comp78/usr/X11R6/include/
cp -r usr/X11R6/include/ /tmp/comp78/usr/X11R6/include/
rm  -rf usr/X11R6/include/*
mkdir -p /tmp/man78/usr/X11R6/man/
cp -r usr/X11R6/man/ /tmp/man78/usr/X11R6/man/
rm  -rf usr/X11R6/man/*

find usr/X11R6/bin -type f -exec /usr/bin/strip -s {} +

du -sh .

# xserv
cd "/tmp/xserv${VERSION}"
du -sh .
find usr/X11R6/lib/modules -type f -name 'lib*.so' -exec /usr/bin/strip -s {} +
# Saves a couple hundred KB and messess symlinks
# find usr/X11R6/lib/modules/dri -type f -name '*.so' -exec /usr/bin/strip -s {} +
find usr/X11R6/lib/modules/drivers -type f -name '*.so' -exec /usr/bin/strip -s {} +
find usr/X11R6/lib/modules/extensions -type f -name 'lib*.so' -exec /usr/bin/strip -s {} +
find usr/X11R6/lib/modules/input -type f -name '*.so' -exec /usr/bin/strip -s {} +
mkdir -p /tmp/man78/usr/X11R6/man/
cp -r usr/X11R6/man/ /tmp/man78/usr/X11R6/man/
rm  -rf usr/X11R6/man/*
du -sh .

# xshare
cd "/tmp/xshare${VERSION}"
du -sh .
mkdir -p /tmp/man78/usr/X11R6/share/doc
cp -r usr/X11R6/share/doc/ /tmp/man78/usr/X11R6/share/doc
rm -rf usr/X11R6/share/doc/* 
mkdir -p /tmp/man78/usr/X11R6/man
cp -r usr/X11R6/man/ /tmp/man78/usr/X11R6/man
rm -rf usr/X11R6/man/* 
mkdir -p /tmp/comp78/usr/X11R6/include
cp -r usr/X11R6/include/ /tmp/comp78/usr/X11R6/include
rm -rf usr/X11R6/include/* 
du -sh .

# place cd stuff.
rm "${CDPATH}/base${VERSION}.tgz" 
tar czpf "${CDPATH}/base${VERSION}.tgz" -C "/tmp/base${VERSION}" .

rm "${CDPATH}/xbase${VERSION}.tgz" 
tar czpf "${CDPATH}/xbase${VERSION}.tgz" -C "/tmp/xbase${VERSION}" .

rm "${CDPATH}/xserv${VERSION}.tgz" 
tar czpf "${CDPATH}/xserv${VERSION}.tgz" -C "/tmp/xserv${VERSION}" .

rm "${CDPATH}/xshare${VERSION}.tgz" 
tar czpf "${CDPATH}/xshare${VERSION}.tgz" -C "/tmp/xshare${VERSION}" .

#rm "${CDPATH}/xfont${VERSION}.tgz" 
#tar czpf "${CDPATH}/xfont${VERSION}.tgz" -C "/tmp/xfont${VERSION}" .

rm "${CDPATH}/man${VERSION}.tgz" 
tar czpf "${CDPATH}/man${VERSION}.tgz" -C "/tmp/man${VERSION}" .

rm "${CDPATH}/comp${VERSION}.tgz" 
tar czpf "${CDPATH}/comp${VERSION}.tgz" -C "/tmp/comp${VERSION}" .

mkhybrid \
  -r -T -l \
  -A "OpenBSD #{VERSIOND} ${ARCH} small" \
  -V "OPENBSD_${VERSION}" \
  -b "${VERSIOND}/${ARCH}/cdbr" \
  -c boot.catalog \
  -o "/tmp/install${VERSION}-${ARCH}-custom.iso" \
  /tmp/cdroot

More compression - this didn't help, it made base78.tgz go from 50M to 49.6M and took MUCH longer:

GZIP=-9 tar czpf /tmp/cdroot/7.8/amd64/base78.tgz -C /tmp/base78 .

Results

The CD is 389MB if you include the now vastly larger (~180MB) compiler package. It's below 300MB with the original compiler package, but the actual compiler is missing.

The installed system with just base and the four X11 packages is 442MB on AMD64.

The install system with just base is 223MB (two kernels which are 31MB each but either the single processor or multiproccessor kernel could be deleted if needed). The disk image compressed with 7-zip to under 41MB.

Before compressing an image after deleting things:

dd if=/dev/zero of=/EMPTY bs=1M
rm /EMPTY

Perl is needed to install packages but can be removed if not needed after doing so. With perl and the single processor kernel removed, disk usage was 138MB. The disk compressed to 28.1MB with 7-zip.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment