====== Google Summer Of Code 2023: Integrate mfsBSD into the release building tools ======
* Student: [[/SoobinRho|SoobinRho]] (soobinrho@freebsd.org)
* Mentors: [[/JurajLutter|JurajLutter]] (otis@freebsd.org) and [[/JosephMingrone|JosephMingrone]] (jrm@freebsd.org)
===== Project description =====
mfsBSD is a toolset to create small-sized but full-featured mfsroot based distributions of FreeBSD that store all files in memory (MFS) [Memory File System] and load from hard drive, usb storage device or optical media.
It can be used for a variety of purposes, including diskless systems, recovery partitions and remotely overwriting other operating systems.
[[/MartinMatuska|MartinMatuska]] is the creator of mfsBSD, and he is also the author of the [[https://people.freebsd.org/~mm/mfsbsd/mfsbsd.pdf|original mfsBSD white paper]], which is where the excerpt above was taken from. The upstream mfsBSD is maintained at the [[https://github.com/mmatuska/mfsbsd|GitHub mfsBSD repository]].
This project integrates mfsBSD into the %%FreeBSD%% release tool set, creating an additional target of mfsBSD images (''%%.img%%'' for disc and ''%%.iso%%'' for optical images) into the ''%%/usr/src/release/Makefile%%''.
Until now, mfsBSD only existed outside the %%FreeBSD%% release tool chain, and only the -release versions have been produced.
With this project, mfsBSD images are now available at the official %%FreeBSD%% release page, and you can also build mfsBSD yourself by invoking ''%%cd /usr/src/release && make mfsbsd-se.img mfsbsd-se.iso%%'', which will then create ''%%mfsbsd-se.img%%'' and ''%%mfsbsd-se.iso%%'' at ''%%/usr/obj/usr/src/${ARCH}/release/%%''.
===== Project outcome =====
Two ways of building mfsBSD have been implemented.
The first use case is intended for most use cases, while the second is intended only for release engineering purposes -- e.g. creating all of the %%FreeBSD%%
installation media for distribution purposes.
#
# [Use Case 1] If you're a regular user, use this method.
#
# Build mfsBSD images.
cd /usr/src/release
make mfsbsd-se.img mfsbsd-se.iso
# The make process creates `mfsbsd-se.img` and `mfsbsd-se.iso` here:
ls -lh /usr/obj/usr/src/${ARCH}/release/
That's it!
Basically, it's very similar to mfsBSD's own make process with ''%%CUSTOM=1 BUILDWORLD=1 BUILDKERNEL=1%%'' flags.
In contrast, the second option shown below is different from the first option in that it invokes not only the mfsBSD image build process, but also all the rest of the %%FreeBSD%% release build processes.
The first use case only builds mfsBSD itself, and thus is intended for most use cases, while the second use case's purpose is to build all the release media.
#
# [Use Case 2] Build mfsBSD alongside all release artifacts.
#
# Build prerequisites.
cd /usr/src
make buildworld buildkernel
# Build mfsBSD images.
cd /usr/src/release
make release WITH_MFSBSD=1
# Copy the produced images to ${DESTDIR} and also prepend ${OSRELEASE} to the filenames.
make install WITH_MFSBSD=1 DESTDIR=/usr/src/release/images
ls -lh /usr/src/release/images
The mfsBSD build process is the same for both the first use case and the second use case.
However, the second use case also builds all the release artifacts and all of the %%FreeBSD%% installation media, such as cdrom, dvdrom, memstick, and mini-memstick.
Also, running ''%%make install WITH_MFSBSD=1 DESTDIR=/usr/src/release/images%%'' copies all of the built images to ''%%${DESTDIR}%%'' and appends a prefix to all of the image names ''%%${OSRELEASE}-mfsbsd-se.{img|iso}%%'' for distribution purposes.
===== Example usage of an mfsBSD image =====
A lot of the example in this section has been taken from the [[https://docs.freebsd.org/en/articles/remote-install/|documentation on FreeBSD remote install]].
This is just one among many possible uses of an mfsBSD image, but it shows you how to install %%FreeBSD%% on a system, where there's just a single drive.
Thanks to mfsBSD, you can install %%FreeBSD%% even without any external storage device, such as an USB, because mfsBSD - by its own definition - runs entirely on the memory file system, which means the original drive that the mfsBSD booted from can then be modified and even completely erased and overwritten with a new operating system.
First, boot into your existing operating system's recovery mode. Then, type the following:
# List all the disks and find the name of your target drive.
# The name can be different depending on the drive, but suppose we want ada0.
# Listing all the disks is `geom disk list` in FreeBSD, but is likely to be different in other systems.
geom disk list
# Write the mfsBSD image to your target drive.
dd if=./mfsbsd-se.img of=/dev/ada0 bs=1M
reboot
When rebooting, select the target drive as the booting device. For example, if you're using a Thinkpad, type F12 while booting.
# Prepare base.txz and kernel.txz for FreeBSD installation.
# Since the image we used (mfsbsd-se.img) is a special edition image, it comes packed with these two files, inside the third partition of mfsBSD.
mkdir /mnt/dist
mount /dev/ada0p3 /mnt/dist
# Later, we will be using bsdinstall for FreeBSD installation, and bsdinstall looks for the dist files in this specific folder.
mkdir /usr/freebsd-dist
cp /mnt/dist//*.txz /usr/freebsd-dist/
# Install FreeBSD.
bsdinstall
===== Milestones =====
* Week 1 - Week 7 (May 29, 2023 - July 16, 2023)
* Created a [[https://github.com/soobinrho/freebsd-src/tree/integrate-mfsBSD-building|fork]] of the [[https://github.com/freebsd/freebsd-src|-CURRENT branch]].
* Created [[/SoobinRho|SoobinRho]] page.
* Updated the [[SummerOfCode2023Projects/IntegrateMfsBSDIntoTheReleaseBuildingTools|project page]] based on [[SummerOfCode/ProjectTemplate|SummerOfCode/ProjectTemplate]].
* Scheduled weekly meetings on every Monday with my mentors.
* Completed reading [[https://man.freebsd.org/cgi/man.cgi?query=intro&sektion=9|INTRO(9)]], [[https://man.freebsd.org/cgi/man.cgi?make(1)|MAKE(1)]], [[https://docs-archive.freebsd.org/44doc/psd/12.make/paper.pdf|PMake — A Tutorial]], [[https://man.freebsd.org/cgi/man.cgi?build(7)|BUILD(7)]], [[https://man.freebsd.org/cgi/man.cgi?release(7)|RELEASE(7)]], [[https://man.freebsd.org/cgi/man.cgi?hier(7)|HIER(7)]], [[https://man.freebsd.org/cgi/man.cgi?query=tests&sektion=7&manpath=freebsd-release-ports|TESTS(7)]], [[https://man.freebsd.org/cgi/man.cgi?query=style&sektion=9|STYLE(9)]], [[https://man.freebsd.org/cgi/man.cgi?query=style.Makefile&sektion=5|STYLE.MAKEFILE(5)]], [[https://man.freebsd.org/cgi/man.cgi?query=development&sektion=7|DEVELOPMENT(7)]], [[https://svnweb.freebsd.org/base/user/gjb/thermite-git/|thermite.sh wrapper script around release.sh]], [[https://docs.freebsd.org/en/books/handbook/|FreeBSD Handbook]], [[https://docs.freebsd.org/en/books/developers-handbook/|Developer's Handbook]], [[https://docs.freebsd.org/en/articles/committers-guide|Committer's Guide]], [[https://docs.freebsd.org/en/articles/committers-guide/#vendor-import-git|Vendor Imports]], [[https://docs.freebsd.org/en/articles/freebsd-releng|Release Engineering]], [[/Phabricator]], [[https://man.freebsd.org/cgi/man.cgi?git-arc(1)|GIT-ARC(1)]], and [[https://freebsdfoundation.org/wp-content/uploads/2021/11/FreeBSD-Code-Review-with-git-arc.pdf|John Baldwin's article on GIT-ARC]].
* Improved some of the documentation along the way ([[https://github.com/freebsd/freebsd-doc/pull/201|#201]], [[https://github.com/freebsd/freebsd-doc/pull/232|#232]], [[https://github.com/freebsd/freebsd-doc/pull/246|#246]]).
* Started reviewing ''%%/usr/src/release/Makefile{.*}%%''
* Submitted a pull request for the [[https://github.com/freebsd/freebsd-doc/pull/192|2023 Q2 Status Report]] and merged to [[https://www.freebsd.org/status/report-2023-04-2023-06/#_integrate_mfsbsd_into_the_release_building_tools|main]].
* Week 8 - Week 15 (July 17, 2023 - September 4, 2023)
* Completed the integration of mfsBSD into the %%FreeBSD%% release tool set.
* [[https://github.com/soobinrho/freebsd-src/tree/integrate-mfsBSD-building|Source code on GitHub]] and [[https://reviews.freebsd.org/D41705|code review on Phabricator]].
* Done an [[https://freebsdfoundation.org/blog/meet-the-2023-freebsd-google-summer-of-code-students-soobin-rho/|interview with the FreeBSD Foundation]].
===== Development logs =====
This section explains three major problems encountered in the entirety of the project, and explains what kind of approaches were taken to solve them.
The first thing I did for this project was to import mfsBSD into ''%%/usr/src/contrib%%'' folder and try to build it:
git clone https://github.com/mmatuska/mfsbsd.git
cp -r ./mfsbsd /usr/src/contrib/
cd /use/src/contrib/mfsbsd
make BASE=/usr/obj/usr/src/${ARCH}/release
This, however, gave me an error
# First error
Installing configuration scripts and files ...install: /usr/home/fred/mfsbsd/tmp/mfs/etc/motd: No such file or directory.
Interestingly, this error would go away if I ''%%mv /usr/src/contrib/mfsbsd /mfsbsd%%'' and run from there.
The error would reappear if the folder is located at ''%%/usr/src/contrib/mfsbsd%%''.
So, in the middle of the Makefile, I ran ''%%pwd%%''. It showed me the current working directory as ''%%/usr/obj/usr/src/${ARCH}/contrib%%'', which it shouldn't be.
It was supposed to be pointing at where the ''%%mfsbsd%%'' folder was located at, which is ''%%/usr/src/contrib/mfsbsd%%'', but ''%%pwd%%'' was pointing to a non-existent, mysterious directory.
How was this problem resolved?
This [[https://stackoverflow.com/questions/45675365/make-starts-in-wrong-directory-under-freebsd|Stack Overflow answer]] helped me figure out what's happening here.
Basically, there's an internal mechanism in ''%%make%%'' that executes ''%%chdir%%'' if the directory is located in certain ways.
To solve this, I decided to add an extra flag that overrides this unexpected behavior.
Here's the code:
# MAKEOBJDIR flag solved the problem.
cd /usr/src/contrib/mfsBSD
env MAKEOBJDIR=${MFSBSD_DIR} make BASE=/usr/obj/usr/src/{ARCH}/release
The first problem was therefore solved.
The second unexpected behavior popped up right after that -- don't get me wrong, I was extremely happy to see this second error and not the first one for the 100th time:
# Second error
Installing pkgng ...pkg-static not found at: /usr/local/sbin/pkg-static.
Apparently, this is a much more well-known issue compared to the first.
There was only one query result on Google regarding the first, while there were dozens regarding this one.
''%%pkg-static%%'' is a program that is already included inside ''%%pkg%%''.
However, my machine was able to notice this instance of error because it was running a fresh install of %%FreeBSD%% for testing purposes and was never connected to the internet.
When you first run ''%%pkg%%'', it goes through an initialization process after asking the user to confirm it.
The problem here, however, was that this initialization process requires internet connection, and it is this exact initialization that installs ''%%pkg-static%%''.
Thus, without internet access, ''%%pkg-static%%'' doesn't exist, and this was why mfsBSD build process was exiting with an error.
The fix, of course, is unnecessary if the device has an internet connection, and this indeed is most often the case.
If you have downloaded the src tree, it most likely means you already have internet access.
So, I added a simple if statement in ''%%/usr/src/release/Makefile.mfsbsd%%'' to check if the ''%%pkg-static%%'' binary exists, and if not, just bypass that portion of the build program that requires ''%%pkg-static%%''.
If it does exist, which will be most of the time, proceed as normal.
. if !exists(${MFSBSD_PKGSTATIC})
# If pkg-static is not present at the device, mfsBSD build process
# cannot proceed further. Thus, creating .packages_done bypasses
# that specific part of the build process that requires pkg-static.
touch ${MFSBSD_DIR}/work/.packages_done
. endif
Finally, the last problem I encountered was:
# Last error
These libraries should be LIBADD+=foo rather than DPADD/LDADD+=-lfoo: ${_BADLDADD}
The solution was to add ''%%-m${MFSBSD_MKINCLUDEDIR}%%'' flag.
The build process was trying to find mk files from a wrong directory, such as ''%%/usr/src/share/mk%%'', so I had to override that with the correct directory ''%%/usr/share/mk%%''. The ''%%-m%%'' flag does exactly that.
What was the cause of this behavior?
According to [[https://man.freebsd.org/cgi/man.cgi?make|MAKE(1)]], "the search [for ''%%sys.mk%%'' and include makefiles] starts with the current directory of the ''%%Makefile%%'' and then works upward towards the root of the file system."
----
Update: One more major design decision I had to make was to ditch ''%%cd ${MFSBSD_DIR} && make CUSTOM=1 BUILDWORLD=1 BUILDKERNEL=1%%''.
It had two issues.
(a) Even though mfsBSD images can be built harmlessly at first glance, it actually fails to mount the memory disk when it boots in certain devices.
For example, this issue caused the mfsBSD to boot in one of my two amd64 devices, but wouldn't work on my newer amd64 machine.
(b) Also, the resultant image's size was considerably larger.
Its ''%%.img%%'' image was around 1.5GB, while its ''%%.iso%%'' image was around 1.3GB.
Ditching the original method and using a simple ''%%cd ${MFSBSD_SRCDIR} && ${IMAKE} buildworld buildkernel%%'' along with ''%%${IMAKE} -C ${.CURDIR} obj bootonly%%'' solved both of the issues.
The mfsBSD images boot correctly without any problem mounting its memory disks, and also the images themselves are around 300MB only.
[[https://summerofcode.withgoogle.com/programs/2023/projects/Pw6wO1Ng]]
Sponsored by: Google, Inc. (%%GSoC%% 2023)