Create custom FreeBSD .img from original FreeBSD-13.0-RELEASE-amd64-memstick.img

Okay, I took your suggestion and updated the base.txz file with my updated packages. That was fairly easy to accomplish... except I am not getting the attached error when during installation... I will start over and see if I can reproduce this...
 

Attachments

  • could_not_set_root_password.jpg
    could_not_set_root_password.jpg
    1.7 MB · Views: 80
No problem here. The installation image with additional binary packages in base.txz included, copied on a USB stick, does install without any errors.
 
Okay, I redid the steps and recreated the .img file. This time when I did the installation, I did not get that error... So that is fantastic! Not sure why it was messed up...

However, now I am stuck with another issue related to USB... I do not recall having this issue with the original memstick .img file. I will retry the installation with the original and see if I get the error...
 

Attachments

  • freebsd_usb_boot_error.jpg
    freebsd_usb_boot_error.jpg
    729.1 KB · Views: 66
Okay, after further research in the forums and installing from the original memstick .img file, the message still happens... The boot does eventually succeeds... which is good.

Anyways, I believe this solutions finally works and I have a custom installation .img file!

Thank you so much for the wonder help... it is much appreciated!
 
Okay, I am back...

I do have a custom .img being successfully created; however, I have now run into an issue when installing this .img to different hardware. Also, we decided to use 12.2 instead of 13.

We have two models of computers we install the .img onto each having slightly different CPU and RAM, but the same SSD and HDD configuration. System 1 has the SSD as ada0, while the HDD is ada1. System 2 has the SSD as ada1, while the HDD is ada0. This is causing major headaches since I have the installerconfig hardcoded to with

Bash:
DISTRIBUTIONS="kernel.txz base.txz lib32.txz"
export ZFSBOOT_VDEV_TYPE=stripe
export ZFSBOOT_DISKS=ada0
export ZFSBOOT_SWAP_SIZE=2g
export nonInteractive="YES"

So to combat this, I commented out the export nonInteractive="YES" statement. This allowed the installer to prompt the user to pick the installation drive. That all seemed to work as we were now able to pick the correct adaX; however, it does not seem to really work as the operating system is ALWAYS installed on ada0, I assuming because of the hardcoded export ZFSBOOT_DISKS=ada0.

So I thought, I will comment out the export ZFSBOOT_DISKS=ada0 statement, as that should take care of it... No dice, as I get an error when the installer tries to run...

Code:
No root partition was found. The root FreeBSD partition must have a mountpoint of '/'.

So, I am stuck. Any idea on how to get the installer to allow for the user to pick the installation drive and not run into this error?

Thanks,
 
export ZFSBOOT_DISKS=ada0
Remove export nonInteractive="YES", set to
Code:
export ZFSBOOT_DISKS="ada0 ada1"

In the "ZFS Configuration" menu choose "stripe", "ada1".

I don't know how useful this is. If the installation is interactive now you might as well skip automatic installation setup and let the normal FreeBSD installer run.

Another option would be to create two installer images, specifying different disks, one for each model of computers.

Also be advised, the above installerconfig setup in this form won't install a 13.0-RELEASE bootable system on UEFI because of missing efi boot loader.

I assume there are or will be in the original installerconfig additional bsdinstall(8) targets like rootpass for example, and time.

The normal FreeBSD Installer would make much less trouble. Can't be a step by step installation guide, hard copy booklet or PDF, with images, to be used by the end client an option?

Also, we decided to use 12.2 instead of 13.
12.2 will be EOL March 2022.

12.3-RELEASE + 3 months, 12.3-RELEASE available since December 2 2021.
 
Thanks for the heads-up about 12.2... We will go a head and update to 12.3...

You are 100% about not working with UEFI. I am not quite sure what I am missing. Here is my complete installerconfig file.

Bash:
DISTRIBUTIONS="kernel.txz base.txz lib32.txz"
export ZFSBOOT_VDEV_TYPE="stripe"
export ZFSBOOT_DISKS="ada0"
export ZFSBOOT_SWAP_SIZE="2g"
export nonInteractive="YES"

#!/bin/sh

bsdconfig hostname
bsdconfig timezone
bsdconfig password

# For details see bsdconfig(8)

sysrc ifconfig_DEFAULT=DHCP
sysrc sshd_enable=YES

touch /firstboot
cp /usr/custom-dist/firstboot /etc/rc.d

# To make it aesthetically pleasant clear the screen
clear

printf  "#############################################################\n"
printf  "\n"
printf  "The custom FreeBSD has been installed.\n"
printf  "\n"
printf  "Please remove the installation media.\n"
printf  "\n"
printf  "Once the machine reboots, the firstboot process will\n"
printf  "automatically configure your installation.\n"
printf  "\n"
printf  "#############################################################\n"
printf  "\n"
printf  "Rebooting in...\n"
for i in $(/usr/bin/jot ${1:-10} ${1:-10} 1); do
    printf "\r%s " "$i"
    sleep 1
done

printf "\n"

reboot

# For details see  sysrc(8). For 'ifconfig_DEFAULT' see rc.conf(5).
 
Also be advised, the above installerconfig setup in this form won't install a 13.0-RELEASE bootable system on UEFI because of missing efi boot loader.
You are 100% about not working with UEFI. I am not quite sure what I am missing. Here is my complete installerconfig file.
I apologize not to elaborate the issue and express myself clearer .

You are missing nothing. It's a bug in 13.0-RELEASE, affecting automatic installation of ZFS on UEFI.

As said before, bsdinstall(8) does not install the efi boot loader (in the right place).

In detail, loader.efi (or bootx64.efi, same loader, different name) is installed in a automatic installation in the new system under /boot/efi/efi/boot/bootx64.efi and /boot/efi/efi/freebsd/loader.efi.

/boot/efi/ on the other hand is a directory under / of dataset zroot/ROOT/default, on partition ada0p4, the freebsd-zfs partiton.

The place where the efi loader should be installed is on a FAT formatted, separate partition, ada0p1, mounted under /boot/efi, but that partition remains empty after the installation finishes.

And second, bsdinstall(8) doesn't create a EFI boot variable in UEFI to boot the system from.

The new system boots fine after creating appropriate directories and copy /boot/loader.efi to /boot/efi/boot/bootx64.efi, and creating a boot variable with efibootmgr(8).

This could be done as a workaround in the setup shell script part of /etc/installerconfig.

I'm not sure if it's the same bug discussed and reported below or a new one. I haven't tested 13.0-STABEL:

- Unattended install on FreeBSD13 with zfs/efi
- PR 255824 - Unattended install with UEFI and ZFS fails

It doesn't help to replace directory /usr/libexec/bsdinstall on 13.0-RELEASE installer media with the one from 13.0-STABLE. The installation terminates with a error message window popping up, the new system remains mounted, no UEFI boot variable is created, system doesn't reboot automatically.

Conclusion, automatic installation of 13.0-RELEASE is buggy at the moment. Maybe it's corrected in 13.1-RELEASE, depending on if it's the the same bug mentioned earlier.
 
I now have UEFI working under 12.2 and 12.3. I have not delved into 13 yet.

We have now moved onto 12.3 and we ran into another issue which I seem to not be able to solve. But first a little background...

In the .img I have created, are the packages (.pkg) I want to have installed. Packages like tmux, tcpdump, sudo, etc., with all their dependencies. I put them in the .img because most of the time when doing an installation there is no Internet access... Also in the .img is a first_boot.sh script. This script is put onto the new installation and automatically ran on first boot. In this script I install the packages that were part of the .img I created. Herein lies the problem...

The problem is that since I am using pkg to install the various .pkg files, I need to have the pkg software installed on the installation. Seeing that pkg is already located in /usr/sbin, I though that I would simply perform

Bash:
/usr/sbin/pkg add -f /installation/packages/pkg-1.17.2.pkg

and the problem would be solved... But no, I get a message saying:

Code:
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]:

As mentioned before, most of the time there is no Internet access so all the packages are in the .img. Is there a way to get around this? Is there a way to use the built in /usr/sbin/pkg command to install the pkg-1.17.2.pkg that I already have without having to go out to the Internet? Hopefully this all makes sense...

Thanks,
 
/usr/sbin/pkg add -f /installation/packages/pkg-1.17.2.pkg
No problem here form command line.
As mentioned before, most of the time there is no Internet access so all the packages are in the .img. Is there a way to get around this? Is there a way to use the built in /usr/sbin/pkg command to install the pkg-1.17.2.pkg that I already have without having to go out to the Internet?
Yes it's possible. If you paste your firstboot.sh script it would be easier to suggest improvements, if necessary.

Below is a working example to bootstrap pkg and install extra packages on firstboot from a local repository (12.2-RELEASE):

/installation/packages directory topography:
Code:
/installation/packages/All/<packages>
/installation/packages/Latest/pkg.pkg  # renamed pkg-1.7.2.pkg

Download https://cgit.freebsd.org/ports/plain/sysutils/firstboot-pkgs/files/firstboot_pkgs.in

Apply patch to firstboot_pkgs:
Code:
--- firstboot_pkgs.orig    2021-12-10 08:29:54.818825000 +0200
+++ firstboot_pkgs    2021-12-10 08:33:28.616402000 +0200
@@ -2,7 +2,6 @@
 
 # KEYWORD: firstboot
 # PROVIDE: firstboot_pkgs
-# REQUIRE: NETWORKING
 # BEFORE: LOGIN
 
 # Add the following lines to /etc/rc.conf.local or /etc/rc.conf (in the disk
@@ -29,13 +28,16 @@
     # Count rc.d scripts
     nscriptso=`ls /usr/local/etc/rc.d | wc -l`
 
-    # Bootstrap and update pkg to ensure synchronization with the repository
+    # See pkg.conf(5) for variables
+    export PACKAGESITE=file:///installation/packages
+    export SIGNATURE_TYPE=none
+
+    # Bootstrap pkg
     env ASSUME_ALWAYS_YES=YES pkg bootstrap -f | cat
-    env ASSUME_ALWAYS_YES=YES pkg update -f | cat
 
-    # Install requested packages, if any
+    # Install requested packages, if any, from local repository
     for package in ${firstboot_pkgs_list}; do
-        env ASSUME_ALWAYS_YES=YES pkg install ${package} </dev/null |
+    env ASSUME_ALWAYS_YES=YES pkg add /installation/packages/All/${package}* </dev/null |
             cat
     done

Code:
mkdir -p /usr/local/etc/rc.d
cp firstboot_pkgs /usr/local/etc/rc.d
chmod 555 /usr/local/etc/rc.d/firstboot_pkgs

sysrc firstboot_pkgs_enable=YES
sysrc firstboot_pkgs_list="sudo tmux"

touch /firstboot
 
Not sure if it matters or not, but we are now using 12.3-RELEASE, not 12.2-RELEASE...

Here is the information you asked for...

Our installerconfig automatically puts this script into /etc/rc.d.

Bash:
#!/bin/sh

# KEYWORD: firstboot
# PROVIDE: first_boot
# REQUIRE: NETWORKING
# BEFORE: login

. /etc/rc.subr

name="firstboot"
start_cmd="first_boot"
stop_cmd=":"

first_boot()
{
    /usr/custom-dist/first_boot.sh
}

load_rc_config $name
run_rc_command "$1"

Our installerconfig then does the following command to force a firstboot on the next reboot...

Bash:
touch /firstboot

Then, on firstboot, our first_boot.sh script runs.

Bash:
#!/bin/sh

# This script is run on first boot of the operating system.  After the first
# boot happens and the script is executed, the firstboot sentinel file located
# in /firstboot is automatically deleted by the operating system.  When this
# happens, the script is never run again.  If you need to rerun this script,
# create the firstboot sentinel file using the 'touch /furstboot' command to
# create the first boot sentinel file.  Once the file is created, reboot the
# system and this script will be run again.

#set -x

SIG_NONE=0
SIG_HUP=1
SIG_INT=2
SIG_QUIT=3
SIG_KILL=9
SIG_TERM=15

TIMEOUT=10

trap caught_signal $SIG_HUP $SIG_INT $SIG_QUIT $SIG_KILL $SIG_TERM

cleanup()
{
    if [ -e temp.txt ]; then
        rm -rf temp.txt
    fi

    # Restore the original configuration file.
    rm /etc/pkg/FreeBSD.conf
    mv /etc/pkg/FreeBSD.conf.ORIG /etc/pkg/FreeBSD.conf

    cd $_cwd

    exit 1
}

setup()
{
    _cwd=$PWD
    _pw=/usr/sbin/pw
    _shell=/bin/sh
    _uid="/usr/custom-dist"

    # Since we do not package signatures, we replace the original configuration
    # file with our configuration file so we do not need signatures.
    mv /etc/pkg/FreeBSD.conf /etc/pkg/FreeBSD.conf.ORIG
    cp $_uid/FreeBSD.conf /etc/pkg/FreeBSD.conf
}

caught_signal()
{
    logger "Caught Signal... Cleaning up."
    rmuser -y support
    cleanup
}

install_standard_packages()
{
    logger "Install standard packages..."

    # Install the package program.
    /usr/sbin/pkg add -f $_uid/packages/pkg-1.17.2.pkg
    result_code=$?
    if [ $result_code -eq 0 ]; then
        logger "pkg has been installed successfully."
    fi
    
    # Install the Unix bash shell and command language.
    pkg add -f $_uid/packages/bash-5.1.8.pkg
    result_code=$?
    if [ $result_code -eq 0 ]; then
        logger "bash has been installed successfully."
    fi
    
    # Install htop.  htop is an interactive system-monitor, process-viewer, and
    # process-manager.
    pkg add -f $_uid/packages/htop-3.0.5.pkg
    result_code=$?
    if [ $result_code -eq 0 ]; then
        logger "htop has been installed successfully."
    fi
    
    # Install lnav.  lnav is an advanced log file viewer.
    pkg add -f $_uid/packages/lnav-0.9.0.pkg
    result_code=$?
    if [ $result_code -eq 0 ]; then
        logger "lnav has been installed successfully."
    fi
    
    # Install 7zip.  7zip is an advanced file compression utility.
    pkg add -f $_uid/packages/p7zip-16.02_3.pkg
    result_code=$?
    if [ $result_code -eq 0 ]; then
        logger "7zip has been installed successfully."
    fi
    
    # Install sudo. The sudo command allows users who are part of the wheel and
    # operator groups to run command as root with actually logging in as root.
    pkg add -f $_uid/packages/sudo-1.9.8p2.pkg
    result_code=$?
    if [ $result_code -eq 0 ]; then
        logger "sudo has been installed successfully."
    fi
    
    # Install tcpdump.  tcpdump is a data-network packer analyer similar to Wire
    # Shark.
    pkg add -f $_uid/packages/tcpdump-4.99.0.pkg
    result_code=$?
    if [ $result_code -eq 0 ]; then
        logger "tcpdump has been installed successfully."
    fi
    
    # Install tmux.  tmux is a terminal multiplexer for Unix-like operating
    # systems.  It allows multiple terminal sessions to be accessed simultaneously
    # in a single window. 
    pkg add -f $_uid/packages/tmux-3.2a.pkg
    result_code=$?
    if [ $result_code -eq 0 ]; then
        logger "tmux has been installed successfully."
    fi

    logger "Installing standard packages... Complete."
}

setup
install_standard_packages

echo ""
echo "**********************************************************************"
echo "Congratulations!"
echo "The final setup of the Custom FreeBSD installation is complete."
echo "**********************************************************************"
logger "Congratulations! The final setup of the Custom FreeBSD installation is complete."

cleanup

# shutdown -r now
 
Not sure if it matters or not, but we are now using 12.3-RELEASE, not 12.2-RELEASE...
It doesn't matter.

Our installerconfig automatically puts this script into /etc/rc.d.
Base systems rc scripts shouldn't be mixed with custom rc script in /etc/rc.d/. All ports/packages install their scripts under /usr/local/etc/rc.d/ and custom scripts should go there also.

# REQUIRE: NETWORKING
Why require NETWORKING when the installation of packages are offline from a local repository?


Tried out on a test system, your first_boot.sh works just fine, with some modifications.

Precondition is:

- a local package repository (/installation/packages)

The repository needs a topography pkg expects as shown below.
Code:
/installation/packages/All/<packages>
/installation/packages/Latest/pkg.pkg # renamed pkg-1.7.2.pkg
After all packages are in place, execute pkg-repo(8) on /installation/packages, which creates below files:
Code:
/installation/packages/{meta.conf, meta.pkg, meta.txz, packagesite.txz, packagesite.pkg}

- a package repository configuration file (i.e. local.conf)

I would put that file under /usr/local/etc/pkg/repos/ and disable /etc/pkg/FreeBSD.conf there and let it be removed after firstboot from fist_boot.sh, instead of moving/removing/copying the original and custom repository configuration files:
Code:
FreeBSD: { enabled: no }

local: {
    url: "file:///installation/packages"
    enabled: yes
}


In first_boot.sh set for all package installations global environment ASSUME_ALWAYS_YES=yes

With the repsitory configuration in effect, instead of
Code:
/usr/sbin/pkg add -f $_uid/packages/pkg-1.17.2.pkg
just
pkg bootstrap -f

and for all other packages, instead of
Code:
pkg add -f $_uid/packages/bash-5.1.8.pkg

pkg install bash
 
Back
Top