Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
VERS?= 11
PKGVERS?= 11.0_2025Q3
UNAME_M!= uname -m
UNAME_S!= uname -s
# for an obscure reason, packages path use uname -m...
DIST?= https://nycdn.netbsd.org/pub/NetBSD-daily/netbsd-${VERS}/latest/${ARCH}/binary
.if !defined(ARCH)
Expand Down Expand Up @@ -31,9 +32,14 @@ EXTRAS+= -o

ENVVARS= SERVICE=${SERVICE} ARCH=${ARCH} PKGVERS=${PKGVERS} MOUNTRO=${MOUNTRO}
.if ${WHOAMI} != "root"
# macOS doesn't need sudo anymore (uses staging approach)
. if ${UNAME_S} == "Darwin"
SUDO= ${ENVVARS}
. else
SUDO!= command -v doas >/dev/null && \
echo '${ENVVARS} doas' || \
echo 'sudo -E ${ENVVARS}'
. endif
.else
SUDO= ${ENVVARS}
.endif
Expand Down Expand Up @@ -133,21 +139,28 @@ pkgfetch:
rescue:
${MAKE} setfetch SETS="${RESCUE}"
${SUDO} ./mkimg.sh -m 20 -x "${RESCUE}" ${EXTRAS}
.if ${UNAME_S} != "Darwin"
${SUDO} chown ${USER}:${GROUP} ${.TARGET}-${ARCH}.img
.endif

base:
$Q${MAKE} setfetch SETS="${BASE}"
$Qecho "${ARROW} creating root filesystem (${IMGSIZE}M)"
$Q${SUDO} ./mkimg.sh -i ${SERVICE}-${ARCH}.img -s ${SERVICE} \
-m ${IMGSIZE} -x "${BASE}" ${EXTRAS}
.if ${UNAME_S} != "Darwin"
$Q${SUDO} chown ${USER}:${GROUP} ${SERVICE}-${ARCH}.img
@${SUDO} chown ${USER}:${GROUP} ${SERVICE}-${ARCH}.img
.endif
$Qecho "${CHECK} image ready: ${SERVICE}-${ARCH}.img"

prof:
${MAKE} setfetch SETS="${PROF}"
${SUDO} ./mkimg.sh -i ${.TARGET}-${ARCH}.img -s ${.TARGET} -m 1024 -k kernels/${KERNEL} \
-x "${PROF}" ${EXTRAS}
.if ${UNAME_S} != "Darwin"
${SUDO} chown ${WHOAMI} ${.TARGET}-${ARCH}.img
.endif

# for use with sailor, needs rework
#imgbuilder:
Expand Down Expand Up @@ -198,4 +211,6 @@ build: kernfetch
$Qwhile [ -f tmp/build-${SERVICE} ]; do sleep 0.2; done
$Qecho "${ARROW} killing the builder microvm"
$Qkill $$(cat qemu-${.TARGET}.pid)
.if ${UNAME_S} != "Darwin"
$Q${SUDO} chown ${USER}:${GROUP} ${SERVICE}-${ARCH}.img
.endif
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
description = "smolBSD build environment";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};

outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
bmake
qemu_full
];
};
});
}
69 changes: 49 additions & 20 deletions mkimg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ usage()
{
cat 1>&2 << _USAGE_
Usage: $progname [-s service] [-m megabytes] [-i image] [-x set]
[-k kernel] [-o] [-c URL]
[-k kernel] [-o] [-c URL] [-d]
Create a root image
-s service service name, default "rescue"
-r rootdir hand crafted root directory to use
Expand All @@ -18,6 +18,7 @@ Usage: $progname [-s service] [-m megabytes] [-i image] [-x set]
-k kernel kernel to copy in the image
-c URL URL to a script to execute as finalizer
-o read-only root filesystem
-d enable debug mode (verbose output)
_USAGE_
exit 1
}
Expand All @@ -28,7 +29,7 @@ rsynclite()
(cd $1 && tar cfp - .)|(cd $2 && tar xfp -)
}

options="s:m:i:r:x:k:c:oh"
options="s:m:i:r:x:k:c:odh"

while getopts "$options" opt
do
Expand All @@ -41,11 +42,18 @@ do
k) kernel="$OPTARG";;
c) curlsh="$OPTARG";;
o) rofs=y;;
d) debug=y;;
h) usage;;
*) usage;;
esac
done

# Enable debug mode if requested
if [ -n "$debug" ]; then
set -x # Print commands as they execute
set -v # Print shell input lines as they are read
fi

export ARCH PKGVERS

arch=${ARCH:-"amd64"}
Expand Down Expand Up @@ -110,20 +118,21 @@ if [ -z "$is_netbsd" -a -f "service/${svc}/NETBSD_ONLY" ]; then
exit 1
fi

[ -n "$is_darwin" -o -n "$is_unknown" ] && \
[ -n "$is_unknown" ] && \
echo "${progname}: OS is not supported" && exit 1

if [ -n "$is_linux" ]; then
u=M
if [ -n "$is_darwin" ]; then
# Use temporary directory to stage files
stagedir=$(mktemp -d)
mnt=$stagedir
else
u=m
# Use platform-independent dd syntax that works with both GNU and BSD dd
# bs=1048576 (1MB in bytes) works on all platforms
dd if=/dev/zero of=./${img} bs=1048576 count=${megs}
mkdir -p mnt
mnt=$(pwd)/mnt
fi

dd if=/dev/zero of=./${img} bs=1${u} count=${megs}

mkdir -p mnt
mnt=$(pwd)/mnt

if [ -n "$is_linux" ]; then
mke2fs -O none $img
mount -o loop $img $mnt
Expand All @@ -133,6 +142,8 @@ elif [ -n "$is_freebsd" ]; then
newfs -o time -O2 /dev/${vnd}
mount -o noatime /dev/${vnd} $mnt
mountfs="ffs"
elif [ -n "$is_darwin" ]; then
mountfs="staged" # Special flag for macOS staging mode
else # NetBSD (and probably OpenBSD)
vnd=$(vndconfig -l|grep -m1 'not'|cut -f1 -d:)
vndconfig $vnd $img
Expand All @@ -155,7 +166,7 @@ else
do
# don't prepend sets path if this is a full path
case $s in */*) ;; *) s="sets/${arch}/${s}" ;; esac
echo -n "extracting ${s}.. "
printf "extracting ${s}.. "
$TAR xfp ${s} -C ${mnt}/ || exit 1
echo done
done
Expand All @@ -164,7 +175,7 @@ fi
# additional packages
[ -n "$ADDPKGS" ] && for pkg in ${ADDPKGS}; do
eval $($TAR xfp $pkg -O +BUILD_INFO|grep ^LOCALBASE)
echo -n "extracting $pkg to ${LOCALBASE}.. "
printf "extracting $pkg to ${LOCALBASE}.. "
mkdir -p ${mnt}/${LOCALBASE}
$TAR xfp ${pkg} -C ${mnt}/${LOCALBASE} || exit 1
echo done
Expand All @@ -181,6 +192,7 @@ rsynclite service/common/ ${mnt}/etc/include/

[ -n "$kernel" ] && cp -f $kernel ${mnt}/

BACK=$PWD
cd $mnt

if [ "$svc" = "rescue" ]; then
Expand All @@ -207,20 +219,37 @@ fi

# newer NetBSD versions use tmpfs for /dev, sailor copies MAKEDEV from /dev
# backup MAKEDEV so imgbuilder rc can copy it
cp dev/MAKEDEV etc/
# unionfs with ext2 leads to i/o error
sed -ie 's/-o union//g' dev/MAKEDEV
if [ -f dev/MAKEDEV ]; then
cp -f dev/MAKEDEV etc/
# unionfs with ext2 leads to i/o error
# Use portable sed approach that works with both GNU and BSD sed
sed 's/-o union//g' dev/MAKEDEV > dev/MAKEDEV.tmp && rm -f dev/MAKEDEV && mv dev/MAKEDEV.tmp dev/MAKEDEV
fi
# record wanted pkgsrc version
echo "PKGVERS=$PKGVERS" > etc/pkgvers

# proceed with caution
[ -n "$curlsh" ] && curl -sSL "$CURLSH" | /bin/sh

cd ..
cd $BACK

if [ -n "$is_darwin" ]; then
# macOS: Convert staged files to qemu image
(cd $mnt && $TAR cf - .) > ${img}.tar
echo "Created ${img}.tar"

umount $mnt
# Clean up staging directory
rm -rf $mnt

[ -n "$is_freebsd" ] && mdconfig -d -u $vnd
[ -z "$is_linux" ] && [ -z "$is_freebsd" ] && vndconfig -u $vnd
echo "macOS build complete!"
if [ -f "$qcow_img" ]; then
echo "Created qemu image: $qcow_img"
fi
else
umount $mnt
[ -z "$is_linux" ] && vndconfig -u $vnd
[ -n "$is_freebsd" ] && mdconfig -d -u $vnd
[ -z "$is_linux" ] && [ -z "$is_freebsd" ] && vndconfig -u $vnd
fi

exit 0
61 changes: 54 additions & 7 deletions startnb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,39 @@ if [ -z "$kernel" -o -z "$img" ]; then
usage
fi

# Handle tar files created by macOS staging approach
# Check if img ends with .tar or if a .tar file exists for the specified .img
tarfile=""
tar_extracted_dir=""
if [ "${img%.tar}" != "$img" ]; then
# User specified a .tar file directly
tarfile="$img"
img="${img%.tar}"
elif [ -f "${img%.img}.tar" -a ! -f "$img" ]; then
# Found corresponding .tar file for .img
tarfile="${img%.img}.tar"
fi

if [ -n "$tarfile" -a -f "$tarfile" ]; then
echo "* Found tar archive $tarfile, extracting to directory..."

# Create extraction directory based on image name
tar_extracted_dir="${img%.img}.d"

# Extract if not already extracted
if [ ! -d "$tar_extracted_dir" ]; then
mkdir -p "$tar_extracted_dir"
tar -xf "$tarfile" -C "$tar_extracted_dir"
echo "* Extracted to: $tar_extracted_dir"
else
echo "* Using existing directory: $tar_extracted_dir"
fi

# Use the directory path as the root filesystem via 9p
img="$tar_extracted_dir"
use_9p_root=yes
fi

[ -n "$hostfwd" ] && network="\
-device virtio-net-device,netdev=net${uuid}0 \
-netdev user,id=net${uuid}0,ipv6=off,$(echo "$hostfwd"|sed -E 's/(udp|tcp)?::/hostfwd=\1::/g')"
Expand Down Expand Up @@ -209,13 +242,27 @@ fi
# QMP is available
[ -n "${qmp_port}" ] && extra="$extra -qmp tcp:localhost:${qmp_port},server,wait=off"

cmd="${QEMU} -smp $cores \
$mflags -m $mem $cpuflags \
-kernel $kernel -append \"console=${console} root=${root} ${append}\" \
-global virtio-mmio.force-legacy=false ${share} \
-device virtio-blk-device,drive=hd${uuid}0${sharerw} \
-drive if=none,file=${img},format=raw,id=hd${uuid}0 \
${drive2} ${network} ${d} ${viosock} ${extra}"
# Build the command differently if using 9p root from tar extraction
if [ -n "$use_9p_root" ]; then
echo "* Using 9p filesystem for root from directory: $img"
# Use 9p virtio filesystem as root
cmd="${QEMU} -smp $cores \
$mflags -m $mem $cpuflags \
-kernel $kernel -append \"console=${console} root=9p:root ${append}\" \
-global virtio-mmio.force-legacy=false \
-fsdev local,path=${img},security_model=none,id=root \
-device virtio-9p-device,fsdev=root,mount_tag=root \
${share} ${drive2} ${network} ${d} ${viosock} ${extra}"
else
# Normal block device root
cmd="${QEMU} -smp $cores \
$mflags -m $mem $cpuflags \
-kernel $kernel -append \"console=${console} root=${root} ${append}\" \
-global virtio-mmio.force-legacy=false ${share} \
-device virtio-blk-device,drive=hd${uuid}0${sharerw} \
-drive if=none,file=${img},format=raw,id=hd${uuid}0 \
${drive2} ${network} ${d} ${viosock} ${extra}"
fi

[ -n "$VERBOSE" ] && echo "$cmd" && exit

Expand Down