CRUX : Home

Home :: Documentation :: Download :: Development :: Community :: Wiki :: Ports :: Bugs :: Links :: About

Handbook for CRUX 3.7

1. Preface
2. Introduction
2.1. What is CRUX?
2.2. Why use CRUX?
2.3. License
2.3.1. Packages
2.3.2. Build Scripts
2.3.3. NO WARRANTY
3. Installing CRUX
3.1. Supported Hardware / Requirements
3.2. Installing From Optical Medium or Removable Flash Drive
3.2.1. Installing a Bootloader
3.2.1.1. GRUB, in UEFI boot mode:
3.2.1.2. GRUB, in legacy (non-UEFI) boot mode:
3.2.1.3. SYSLINUX, in UEFI boot mode:
3.2.1.4. SYSLINUX, in legacy (non-UEFI) boot mode:
3.3. Upgrading From Optical Medium or Removable Flash Drive
4. Configuration
4.1. Initialization Scripts
4.1.1. Runlevels
4.1.2. Layout
4.1.3. Configuration Variables in /etc/rc.conf
4.2. Generating locales
4.3. Network Configuration
4.4. Passwords and User Environment
4.5. Upgrading the Kernel
5. The Package System
5.1. Introduction
5.2. Using the Package System
5.2.1. Installing a Package
5.2.2. Upgrading a Package
5.2.3. Removing a Package
5.2.4. Querying the Package Database
5.3. Package Management Frontend: prt-get
5.3.1. Functionality
5.3.2. Configuring prt-get
5.3.2.1. /etc/prt-get.conf
5.3.2.2. /etc/prt-get.aliases
5.4. Creating Packages
5.5. Adjusting/Configuring the Package Build Process
5.6. Package Guidelines
5.6.1. General
5.6.2. Directories
5.6.3. Remove Junk Files
5.6.4. Pkgfile Variables
5.6.5. Pkgfile Header
6. The Ports System
6.1. Introduction
6.1.1. What is a Port?
6.1.2. What is the Ports System?
6.1.3. Port collections
6.1.3.1. The official collections 'core', 'opt', 'xorg' and 'compat-32'
6.1.3.2. The user contributed collection 'contrib'
6.1.3.3. The individual collections from CRUX users
6.2. Using the Ports System
6.2.1. Synchronizing Your Local Ports Structure
6.2.2. Listing Local Ports
6.2.3. Listing Version Differences
6.2.4. Building and Installing Packages
6.2.5. Enabling the 'contrib' collection
6.2.6. Enabling the 'compat-32' collection
6.2.7. Additional tools
6.2.7.1. Building ports as unprivileged user
6.2.7.2. Useful scripts
7. Appendix
7.1. Troubleshooting
7.2. Writing a grub config file by hand
7.3. EFI Stub installation notes
7.4. Notes on Initramfs

1. Preface

Per Lidén wrote this handbook. RobertMcMeekin converted it to DocBook, the CRUX team made a Wiki version. Numerous others have given feedback and improvement suggestions.

2. Introduction

2.1. What is CRUX?

CRUX is a lightweight Linux distribution for the x86-64 architecture targeted at experienced Linux users. The primary focus of this distribution is "keep it simple", which it reflects in a simple tar.gz-based package system, BSD-style initscripts, and a relatively small collection of trimmed packages. The secondary focus is utilization of new Linux features and recent tools and libraries. CRUX also has a ports system which makes it easy to install and upgrade applications.

2.2. Why use CRUX?

There are many Linux distributions out there these days, so what makes CRUX such an appealing choice to its users? The choice of distribution is a matter of taste, really. Here are a few hints about the tastes and goals of the people behind CRUX. CRUX is made with simplicity in mind from beginning to end. Making it easy to create new and update old packages is essential; updating a package in CRUX is often just a matter of typing sudo prt-get update $MYPKG. The usage of ports helps keep your packages up to date; not the latest bleeding-edge-alpha version, but the latest stable version. Other features include creating packages optimized for your processor, eg. by compiling with -march=x86-64, and avoiding cluttering the filesystem with files you'll never use, eg. /usr/share/doc/*, etc. If you need more information about a specific program, other than information found in the man-page, Google usually knows all about it. Lastly, while the CRUX development team strives to introduce new features as soon as they reach stable status, such innovations are carefully screened to ensure that they work in CRUX without drastic changes to the upstream sources or to the rest of the CRUX system.

In short, CRUX might suit you very well if you are:

Note
If you are using CRUX, we highly recommend subscribing to our low-volume mailing list because security updates and updates that need user action are announced there.

2.3. License

2.3.1. Packages

Since CRUX is a Linux distribution, it contains software written by a lot of different people. Each software package comes with its own license, chosen by its author(s). To find out how a particular package is licensed, have a look at its source code.

2.3.2. Build Scripts

All package build scripts in CRUX (in package categories core, opt, xorg, and compat-32) are Copyright © 2000-2022 by Per Lidén and the CRUX development team and are released under the GNU General Public License.

2.3.3. NO WARRANTY

CRUX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Use it at YOUR OWN RISK.

3. Installing CRUX

3.1. Supported Hardware / Requirements

Packages on the official CRUX ISO image are compiled with optimization for x86-64 (AMD Athlon 64, Intel Core, Intel Atom) or newer processors. Do not try to install it on an i686 (Pentium-Pro, Celeron, Pentium-III) or lower processor, since it simply will not work.

A minimum of 2GB system memory is required to install CRUX from a DVD or removable flash drive. It is possible to perform a custom chroot installation with a smaller amount of RAM.

The kernel used during installation, i.e. when booting from the CRUX ISO image (El Torito), is compiled with support for most disk controllers. If your hard disk is not recognized after booting from the ISO image (i.e., the output of lsblk only shows the CRUX media), you might find a solution in the CRUX wiki, the mailing lists, or the bug tracker. You could also ask for help on the CRUX IRC channels. For example, the owner of a low-power machine that uses a board soldered memory card as its main disk was able to install CRUX successfully after building an ISO with kernel customized to enable CONFIG_X86_INTEL_LPSS.

3.2. Installing From Optical Medium or Removable Flash Drive

Download the CRUX ISO image (crux-3.7.iso). To ensure that the download was successful, examine its checksum.

 $ shasum -a 256 crux-3.7.iso

Compare the output with the file crux-3.7.sha256, which can be found in the same directory as the ISO image on the download site. If the checksums match, the download was successful and you can continue by burning the ISO image to a DVD or writing it to a removable flash drive.

 $ fdisk /dev/sd?
 $ mkfs.???? /dev/sd??
 $ mkswap /dev/sd??

Note

Please keep in mind that SATA harddisks are usually detected as SCSI devices. The first SATA disk is called /dev/sda instead of /dev/hda. For more information about harddisk naming conventions please refer to the Linux Partition HOWTO.

The amount of disk space required depends on how many packages are selected to install. It is recommended to have at least a 5G root partition (CRUX will use about 500MB-1GB, depending on whether you create separate partition for /usr, and other decisions you make in the setup process).

The amount of swap space required depends on several factors, including whether you intend to use hibernation or build new packages in RAM. For more information about how memory is handled by modern Linux kernels, please refer to In Defense of Swap.

Note: UEFI

For UEFI installation a GPT disklabel and an EFI system partition (ESP) are required in most cases. The ESP does not need to be very large (100MiB for example) and should be formatted with a FAT32 filesystem and flagged as bootable. When using UEFI the boot loader/manager will be installed in the ESP rather than the traditional method of installation into the Master Boot Record (MBR).

Note: MBR

If your BIOS does not support UEFI boot mode (or you have disabled it in favor of legacy MBR mode), then you do not need to create a separate small partition for EFI loaders or kernel images. One large partition for / is enough in such cases, and GRUB should be able to find a Linux kernel saved in the subdirectory /boot. But selecting SYSLINUX for your bootloader will require you to flag as bootable whichever partition contains syslinux.cfg. See Installing a Bootloader below for more details.

CRUX supports all the filesystems supported as root filesystems by the Linux kernel: btrfs, ext2, ext3, ext4, JFS, reiserfs and XFS. Further, it is highly recommended to separate the system data from user data, i.e. use a separate partition for /home (and possibly /var) since that will make your life a lot easier the day you want to upgrade, reinstall or remove your system.

Note

Make sure the appropriate userspace filesystem tools are installed. xfsprogs, btrfs-progs, jfsutils and reiserfsprogs can be found in the opt repository.

Note

Make sure that any BIOS Virus Protection option is DISABLED as this option may prevent fdisk from writing new partitions correctly.
 $ mount /dev/sd?? /mnt
 $ mkdir /mnt/var
 $ mount /dev/sd?? /mnt/var
 $ swapon /dev/sd??

Note: UEFI

If installing a UEFI system make sure to select the efibootmgr package from the opt collection during the package selection phase. efibootmgr would be installed automatically during dependency resolution if you chose grub2-efi as your boot loader, but it's a good idea to start your CRUX experience paying close attention to the administrative tools you'll be using.

Note: initramfs

If you plan to build a modular kernel, remember to select the dracut package from the opt collection.

After the packages have finished installing, the setup script will display an installation log. Make sure the last line in the log says “0 error(s)”.

If you missed or forgot to install certain packages, you can just mount the CRUX installation medium and use pkgadd to install them.

Screenshots of setup

Note

There is a shortcut command for creating the chroot environment: setup-chroot. This will execute all these steps at once.
 $ mount --bind /dev /mnt/dev
 $ mount --bind /tmp /mnt/tmp
 $ mount --bind /run /mnt/run
 $ mount -t proc proc /mnt/proc
 $ mount -t sysfs none /mnt/sys
 $ mount -t devpts -o noexec,nosuid,gid=tty,mode=0620 devpts /mnt/dev/pts
 (UEFI only) $ mount --bind /sys/firmware/efi/efivars /mnt/sys/firmware/efi/efivars
 $ chroot /mnt /bin/bash
 $ passwd

udev reads files in /sys/* and /proc/*. Make sure that those pseudo filesystems are enabled in your kernel configuration and available during system-startup. Also note that udev doesn't automatically mount /dev/pts. Terminal applications such as xterm(1) will not work if you forget to mount it. We highly recommend you check that your fstab contains the following line:
# dev> mountpoint>         type> options> dump> pass>
[..]
devpts  /dev/pts      devpts noexec,nosuid,gid=tty,mode=0620  0      0

Note

Make sure to include drivers needed to bring up your root filesystem! Unless you also create an initramfs with dracut, these drivers must be built-in and not kernel modules. Look for sections titled "SCSI disk support", "partition types", and "disk controller" when configuring your kernel. For example:

Note: UEFI

If you disable your motherboard's CSM (compatibility support mode) and use anything other than GRUB as your bootloader, you must include an EFI stub in your compiled kernel. Check that .config has the line CONFIG_EFI_STUB = y before running make.

Note

The setup program installs a configuration file /usr/src/linux-5.15.55/.config which is a good starting point for a custom kernel, because all needed options, like CONFIG_DEVTMPFS, are enabled.
 $ cd /usr/src/linux-5.15.55
 $ make menuconfig
 $ make all
 $ make modules_install
 $ cp arch/x86/boot/bzImage /boot/vmlinuz-5.15.55
 $ cp System.map /boot

Note

The location /boot is the default path that GRUB will search for kernel images. If you use the kernel's EFI stub as your bootloader, then modify the cp commands to copy the kernel into a more appropriate location, e.g., the subdirectory EFI/BOOT under the mountpoint of the EFI system partition. The SYSLINUX bootloader on UEFI systems will also require a different location for the saved kernel; see SYSLINUX, in UEFI boot mode for the proper cp commands.

Note

A user-contributed example of a modular kernel configuration has been provided, if you want to boot a kernel that can tell you the exact set of modules needed for your particular hardware, or if you find it too daunting to navigate through the interface of the make menuconfig step. You can find this file, config-5.15.55-modular, under /crux/kernel/contrib on the installation media.

3.2.1. Installing a Bootloader

Unless you compiled your kernel to provide an EFI stub and have UEFI boot mode enabled in your BIOS, you will want to install a bootloader on your hard disk. Simple instructions are provided below for four distinct combinations of bootloader and BIOS setting. You are advised to choose one of the following options based on how your BIOS is configured and on how much you value “do-it-yourself” config files. The EFI stub option is presented in the Appendix, if you find it simpler to modify EFI variables rather than configuration files.

Note

LILO is no longer maintained in the official ports collections. If you were using LILO to boot CRUX 3.6 or earlier, you are advised to replace the boot sector with GRUB or SYSLINUX when upgrading to CRUX 3.7.

Note

Dual-booting with another operating system is not covered in this handbook. There are more extensive resources for such installations on the SYSLINUX wiki or the GRUB manual.

3.2.1.1. GRUB, in UEFI boot mode:

3.2.1.2. GRUB, in legacy (non-UEFI) boot mode:

3.2.1.3. SYSLINUX, in UEFI boot mode:

Note

This configuration requires your kernel to be built with an EFI stub (see this developer's terse reply on the mailing list for more context). Double-check that .config contains the line CONFIG_EFI_STUB = y before proceeding.
 $ mkdir -p /boot/efi/EFI/BOOT
 $ cd /boot/efi/EFI/BOOT
 $ cp /usr/src/linux-5.15.55/arch/x86/boot/bzImage vmlinuz-5.15.55
 $ cp /usr/share/syslinux/efi64/ldlinux.e64 .
 $ cp /usr/share/syslinux/efi64/syslinux.efi BOOTX64.EFI
 $ cat <<EOF > syslinux.cfg
DEFAULT CRUX-3.7
PROMPT 1
TIMEOUT 10

LABEL CRUX-3.7
  SAY "Now booting into CRUX"
  KERNEL vmlinuz-5.15.55
  APPEND root=/dev/sda2 rw quiet

# End of config file
EOF

3.2.1.4. SYSLINUX, in legacy (non-UEFI) boot mode:

 $ mkdir /boot/syslinux
 $ cd /boot/syslinux
 $ cp /usr/share/syslinux/ldlinux.c32 .
 $ extlinux --install /boot/syslinux
 $ [ -e ../vmlinuz-5.15.55 ] || cp /usr/src/linux-5.15.55/arch/x86/boot/bzImage ../vmlinuz-5.15.55
 $ cat <<EOF > syslinux.cfg
DEFAULT CRUX-3.7
PROMPT 1
TIMEOUT 10

LABEL CRUX-3.7
  SAY "Now booting into CRUX"
  KERNEL ../vmlinuz-5.15.55
  APPEND root=/dev/sda2 rw quiet

# End of config file
EOF
 $ PTYPE=$(fdisk -l /dev/sda | grep "^Disklabel type" | cut -d " " -f3)
 $ [ "$PTYPE" = "gpt" ] && BINBLOB=gptmbr.bin || BINBLOB=mbr.bin
 $ dd bs=440 count=1 conv=notrunc if=/usr/share/syslinux/$BINBLOB of=/dev/sda

More information about UEFI and other boot loader/manager options can be found in the CRUX wiki at https://crux.nu/Wiki/UEFI.

Remove the CRUX installation media from your computer and reboot from harddisk.

3.3. Upgrading From Optical Medium or Removable Flash Drive

Download the CRUX ISO image (crux-3.7.iso). To ensure that the download was successful, examine its checksum.

 $ shasum -a 256 crux-3.7.iso

Compare the output with the file crux-3.7.sha256, which can be found in the same directory as the ISO image on the download site. If the checksums match, the download was successful and you can continue by burning the ISO image to a DVD or writing it to a removable flash drive.

 $ mount /dev/sd?? /mnt
 $ mount /dev/sd?? /mnt/var
 $ swapon /dev/sd??

Note

The setup script uses the /etc/pkgadd.conf of the target system to determine which files to upgrade, and which files not to upgrade. The files that are not upgraded are put in /var/lib/pkg/rejected/ (see the section "Upgrading a Package" for advice on how to resolve such file conflicts).

When the setup script has upgraded the selected packages an upgrade log will be displayed. Make sure the last line in the log says “0 error(s)”. If you missed/forgot to install certain packages, you can just mount the CRUX installation media and use pkgadd to install them (e.g. pkgadd /mnt/crux/opt/package#1.0-1.pkg.tar.gz).

Note

There is a shortcut command for creating the chroot environment: setup-chroot. This will execute all these steps at once.
 $ mount --bind /dev /mnt/dev
 $ mount --bind /tmp /mnt/tmp
 $ mount --bind /run /mnt/run
 $ mount -t proc proc /mnt/proc
 $ mount -t sysfs none /mnt/sys
 $ mount -t devpts -o noexec,nosuid,gid=tty,mode=0620 devpts /mnt/dev/pts
 (UEFI only) $ mount --bind /sys/firmware/efi/efivars /mnt/sys/firmware/efi/efivars
 $ chroot /mnt /bin/bash

Finish the upgrade by Installing a Bootloader, and then you should be able to login to your upgraded CRUX system after rebooting.

4. Configuration

4.1. Initialization Scripts

4.1.1. Runlevels

The following runlevels are used in CRUX (defined in /etc/inittab).

RunlevelDescription
0Halt
1 (S)Single-user Mode
2Multi-user Mode
3-5(Not used)
6Reboot

4.1.2. Layout

The initialization scripts used in CRUX follow the BSD-style (as opposed to the SysV-style) and have the following layout.

FileDescription
/etc/rcSystem boot script
/etc/rc.singleSingle-user startup script
/etc/rc.modulesModule initialization script
/etc/rc.multiMulti-user startup script
/etc/rc.localLocal multi-user startup script (empty by default)
/etc/rc.shutdownSystem shutdown script
/etc/rc.confSystem configuration
/etc/rc.d/Service start/stop script directory

Modify /etc/rc.modules, /etc/rc.local and /etc/rc.conf according to your needs.

4.1.3. Configuration Variables in /etc/rc.conf

The following configuration variables are found in /etc/rc.conf.

Variable Description
FONT

Specifies which console font to load at system startup. The contents of this variable will be passed as argument to setfont(1). The available fonts are located in /usr/share/kbd/consolefonts/.

Example: FONT=default

KEYMAP

Specifies which console keyboard map to load at system startup. The contents of this variable will be passed as argument to loadkeys(1). The available keyboard maps are located in /usr/share/kbd/keymaps/.

Example: KEYMAP=sv-latin1

TIMEZONE

Specifies the timezone used by the system. The available zone description files are located in /usr/share/zoneinfo/.

Example: TIMEZONE=Europe/Stockholm

HOSTNAME

Specifies the hostname.

Example: HOSTNAME=pluto

SYSLOG

Specifies the system logging daemon(s) to run at startup.

Example: SYSLOG=sysklogd

SERVICES

Specifies which services to start at system startup. The services specified in this array must have a matching start/stop script in /etc/rc.d/. When entering multi-user mode the specified scripts will be called in the specified order with the argument start. At system shutdown or when entering single-user mode these scripts will be called in the reverse order with the argument stop.

Example: SERVICES=(crond lo net sshd)

4.2. Generating locales

Starting with CRUX 2.5, glibc does not contain all possible locales anymore, thus you'll have to generate the locales you need/use. To ensure proper operation of pkgmk, the locale C.UTF-8 is generated as part of the CRUX installation. Any other desired locales must be created by the administrator.

The core port glibc provides a script to generate the desired locales based on the configuration file /etc/locale.gen, so you no longer need to run localedef manually. Just open /etc/locale.gen in an editor and uncomment the desired locales, then run /usr/sbin/locale-gen. With the appropriate UPGRADE directives in /etc/pkgadd.conf, you can safely upgrade glibc at a later date without losing your chosen locales; just make sure that the file /etc/locale.gen is protected from being overwritten when performing pkgadd -u.

4.3. Network Configuration

The network configuration is found in the service script /etc/rc.d/net. To enable this service you need to add net to the SERVICES array in /etc/rc.conf. By default this service script configures a dynamic IP address.
Example:

#!/bin/sh
#
# /etc/rc.d/net: start/stop network interface
#

# Connection type: "DHCP" or "static"
TYPE="DHCP"

# For "static" connections, specify your settings here:
# To see your available devices run "ip link".
DEV=enp11s0
ADDR=192.168.1.100
MASK=24
GW=192.168.1.1

# Optional settings:
DHCPOPTS="-h `/bin/hostname` -t 10"

case $1 in
        start)
                if [ "${TYPE}" = "DHCP" ]; then
                        /sbin/dhcpcd ${DHCPOPTS}
                else
                        /sbin/ip addr add ${ADDR}/${MASK} dev ${DEV} broadcast +
                        /sbin/ip link set ${DEV} up
                        /sbin/ip route add default via ${GW}
                fi
                ;;
        stop)
                if [ "${TYPE}" = "DHCP" ]; then
                        /sbin/dhcpcd -x
                else
                        /sbin/ip route del default
                        /sbin/ip link set ${DEV} down
                        /sbin/ip addr del ${ADDR}/${MASK} dev ${DEV}
                fi
                ;;
        restart)
                $0 stop
                $0 start
                ;;
        *)
                echo "Usage: $0 [start|stop|restart]"
                ;;
esac

# End of file

If you want to configure your system to use a static IP address, specify TYPE=static and the correct interface. You will also need to configure DNS settings in /etc/resolv.conf.
Example:

#!/bin/sh
#
# /etc/rc.d/net: start/stop network interface
#

# Connection type: "DHCP" or "static"
TYPE="static"

# For "static" connections, specify your settings here:
# To see your available devices run "ip link".
DEV=enp11s0
ADDR=192.168.1.100
MASK=24
GW=192.168.1.1

# Optional settings:
DHCPOPTS="-h `/bin/hostname` -t 10"

case $1 in
        start)
                if [ "${TYPE}" == "DHCP" ]; then
                        /sbin/dhcpcd ${DHCPOPTS}
                else
                        /sbin/ip addr add ${ADDR}/${MASK} dev ${DEV} broadcast +
                        /sbin/ip link set ${DEV} up
                        /sbin/ip route add default via ${GW}
                fi
                ;;
        stop)
                if [ "${TYPE}" == "DHCP" ]; then
                        /sbin/dhcpcd -x
                else
                        /sbin/ip route del default
                        /sbin/ip link set ${DEV} down
                        /sbin/ip addr del ${ADDR}/${MASK} dev ${DEV}
                fi
                ;;
        restart)
                $0 stop
                $0 start
                ;;
        *)
                echo "Usage: $0 [start|stop|restart]"
                ;;
esac

# End of file
#
# /etc/resolv.conf: resolver configuration file
#

search your internal domain>
nameserver your DNS server>

# End of file

To associate with a WPA2-protected wireless network, you should first create a configuration file for wpa_supplicant to use, then launch wpa_supplicant on that interface.

 $ wpa_passphrase MYNETWORK MYPASS > /etc/wpa_supplicant-wlan0.conf
 $ wpa_supplicant -i wlan0 -c /etc/wpa_supplicant-wlan0.conf
Replace MYNETWORK with the ssid of your network, MYPASS with its passphrase, and wlan0 with the name of your actual network interface. Run ip link to see the list of all available interfaces.

If the wpa_supplicant output indicates a successful authentication, you can background the process and run dhcpcd wlan0 to request an address from the DHCP server.

The wpa_supplicant package provides two startup scripts in /etc/rc.d. You might choose to put wlan in the SERVICES array of /etc/rc.conf (replacing net), which will let wpa_supplicant manage all your network interfaces. Another option is to let the net startup script call wpa_supplicant as needed, by copying into /lib/dhcpcd/dhcpcd-hooks/ the example file /usr/share/dhcpcd/hooks/10-wpa_supplicant.

4.4. Passwords and User Environment

CRUX uses SHA512 passwords by default. To change the password encryption method set the ENCRYPT_METHOD variable in /etc/login.defs to DES, MD5 or SHA256.

Furthermore, when compiling programs that use the crypt(3) function to authenticate users you should make sure that these programs are linked against the libcrypt library (i.e. use -lcrypt when linking) which contains the SHA512 version of the crypt function (this version is backwards compatible and understands DES passwords as well).

Also configurable in /etc/login.defs are the settings that govern how useradd(8) behaves when you create a new non-root user, such as CREATE_HOME and USERGROUPS_ENAB. First-time CRUX administrators might be surprised to learn that creating a new user via useradd -m will not automatically populate the home directory with a basic shell startup file, as happens on other Linux distributions whose /etc/skel/ contains their idea of an initial home directory.

A new default in CRUX 3.7 is that the value of PATH, for shells that rely on /etc/profile to set this variable, will be the same regardless of UID. This change allows non-root users easy access to any administrative command without having to type its full path (provided they use bash as their shell and are given the appropriate doas/sudo permissions). Users are always free to choose a different shell and manage PATH themselves, but the default behaviour is now less likely to cause confusion.

The core packages linux-pam and dumb_runtime_dir, and the contrib package pam_xdg, provide a variety of modules that can be loaded upon logging in. The files in /etc/pam.d govern the association between the type of login (eg., tty, SSH, su, X Display Manager) and the modules that get loaded (eg., pam_env, pam_exec, pam_limits). Some typical situations that can be handled cleanly with PAM modules are listed in the table below.

file in /etc/pam.d Typical usage
pam_dumb_runtime_dir.so

create an XDG_RUNTIME_DIR for applications that conform to the freedesktop.org specification

pam_env.so

export some common environment variables, no matter what login shell the user has chosen

pam_xdg.so

export the XDG environment variables defined in the freedesktop.org specification

pam_limits.so

increase the allowed number of opened files, to ensure proper operation of some games

pam_xauth.so

grant another user access to the X display of the logged-in user, so that programs invoked with su can work properly

pam_mount.so

automatically mount a LUKS-encrypted home partition after successful authentication

Note

The existence of a writable XDG_RUNTIME_DIR is required for proper operation of many desktop applications. A clean CRUX 3.7 installation will place a line in /etc/pam.d/common-session that loads the module pam_dumb_runtime_dir.so to satisfy this requirement. An upgrade to CRUX 3.7 might not do so, depending on your UPGRADE directives in /etc/pkgadd.conf. But any configuration that allows desktop applications to run smoothly on CRUX 3.6 will probably continue working after an upgrade to 3.7.
While pam_dumb_runtime_dir has a simple design and restricts itself to the creation of the runtime dir, the 'contrib' collection offers an alternative, pam_xdg, which exports all the environment variables defined in the freedesktop.org specification. You should choose ONE of these two options and edit /etc/pam.d/common-session accordingly.

If you find yourself in one of the other situations in the table above, read the man page for the corresponding PAM module to learn how to accomplish the desired configuration.

4.5. Upgrading the Kernel

The kernel source, which is found in /usr/src/linux-5.15.x/ is not installed using pkgadd. If you decide to upgrade your kernel you can safely do so by manually replacing the kernel source with a newer version (or unpack the newer source tree somewhere else). This will not make the package database inconsistent (since it's not installed with pkgadd) nor will it affect the kernel headers found in /usr/include/linux and /usr/include/asm since these are not symlinks to the kernel source, but instead contain copies of the headers.

5. The Package System

5.1. Introduction

The package system (pkgutils) is made with simplicity in mind, where all packages are plain tar.gz files (i.e. without any kind of meta data).

Packages follow the naming convention <name>#<version>-<release>.pkg.tar.gz, where <name> is the name of the program, <version> is the version number of the program, and <release> is the version number of the package.
The pkg.tar.gz extension is used (instead of just tar.gz) to indicate that this is not just any tar.gz file, but a tar.gz that is meant to be installed using pkgadd. This helps distinguish packages from other tar.gz files. Note that pkgmk nowadays supports additional compression schemes like bzip2 with the tar.bz2 extension or XZ ending with tar.xz.

pkgadd(8), pkgrm(8), pkginfo(8), and pkgmk(8) are the package management utilities. With these utilities you can install, uninstall, inspect, make packages, or query the package database.

When a package is installed using pkgadd a new record is added to the package database (stored in /var/lib/pkg/db). The basic package system does not have any kind of dependency checking, thus it will not warn you if you try to build a package that requires libraries or headers from other packages. Your mistake will only be revealed when the pkgmk build function exits with errors. The included prt-get tool, however, can be told to resolve dependencies, if called with prt-get depinst rather than simply prt-get install.

The following sections will in describe in short how to use the package utilities. Additional information about these utilities can be found on their respective man pages.

5.2. Using the Package System

5.2.1. Installing a Package

Installing a package is done by using pkgadd. This utility requires at least one argument, the package you want to install. Example:

 $ pkgadd bash#5.0.18-1.pkg.tar.gz

When installing a package the package manager will ensure that no existing files are overwritten. If conflicts are found, an error message will be printed and pkgadd will abort without installing the package. The error message will contain the names of the conflicting files. Example:

 $ pkgadd bash#5.0.18-1.pkg.tar.gz
 bin/sh
 usr/man/man1/sh.1.gz
 pkgadd error: listed file(s) already installed (use -f to ignore and overwrite)
No such error message is issued for already-existing directories, since the package database allows a directory to be associated with more than one package. However, the owner/group and permissions of an existing directory will not be changed to match those of the requested package.

To force the installation when conflicting files are reported, you can use the option -f (or --force). Example:

 $ pkgadd -f bash#5.0.18-1.pkg.tar.gz

The package system allows a file to be owned by exactly one package. When forcing an installation the ownership of the conflicting files will be transferred to the package that is currently being installed.

Warning

It is often not a good idea to force the installation unless you really know what you are doing. If a package conflicts with already installed files it could be a sign that the package is broken and installs unexpected files. Use this option with extreme care, preferably not at all.

As earlier, the package file itself does not contain any meta data. Instead, the package manager uses the package filename to determine the package name and version. Thus, when installing a package file named bash#5.0.18-1.pkg.tar.gz, the package manager will interpret this as a package named bash at version 5.0.18-1. If pkgadd is unable to interpret the filename (e.g. # is missing or the filename does not end with .pkg.tar.gz) an error message will be printed and pkgadd will abort without installing the package.

5.2.2. Upgrading a Package

Upgrading a package is done using pkgadd with the -u option. Example:

 $ pkgadd -u bash#5.0.18-1.pkg.tar.gz

This will replace the previously installed bash package with the new one. If you have not previously installed bash, pkgadd will print an error message. The package system does not care about the version number of the package in that you can “upgrade” version 5.0.18-1 with version 5.0.16-1 (or even with version 5.0.18-1 itself). The installed package will be replaced with the specified package.

Upgrading a package is not simply a wrapper for pkgrm followed by pkgadd, because you usually want to preserve your customizations of the config and log files that are owned by the already-installed package. Therefore, pkgadd -u conducts some upgrade-specific checks of the filesystem and the package database to construct what is called a “keep list” (in addition to the “non-install list” which is initialized for every pkgadd transaction). The construction of both lists is governed by the file /etc/pkgadd.conf.

/etc/pkgadd.conf can contain rules describing how pkgadd should behave when installing or upgrading any package. A rule is built out of three fragments; event, pattern and action. The event names the kind of operation (INSTALL or UPGRADE) to which this rule will be applied. The pattern is a filename pattern expressed as a regular expression and the action applicable to the INSTALL or UPGRADE event is YES or NO. More than one rule of the same event type is allowed, in which case the first rule will have the lowest priority and the last rule will have the highest priority.
Example:

 # 
 # /etc/pkgadd.conf: pkgadd(8) configuration
 #

 UPGRADE         ^etc/.*$                NO
 UPGRADE         ^var/log/.*$            NO
 UPGRADE         ^etc/X11/.*$            YES
 UPGRADE         ^etc/X11/xorg.conf$     NO

 # End of file

The above example will cause pkgadd to never upgrade anything in /etc/ or /var/log/ (subdirectories included), except files in /etc/X11/ (subdirectories included), unless it is the file /etc/X11/xorg.conf. The default rule is to upgrade everything, rules in this file are exceptions to that rule.

Note

A pattern should never contain an initial “/” since you are referring to the files in the package, not the files on the disk.

If pkgadd finds that a specific file should not be upgraded, it will install it under /var/lib/pkg/rejected/. Files in this directory are never added to the package database. The user is then free to examine, use and/or remove that file manually. Another option is to use rejmerge. For each rejected file found in /var/lib/pkg/rejected/, rejmerge will display the difference between the installed version and the rejected version. The user can then choose to keep the installed version, upgrade to the rejected version or perform a merge of the two. Example (using the above /etc/pkgadd.conf):

 $ pkgadd -u ports#1.6-3.pkg.tar.gz
 pkgadd: rejecting etc/ports/compat-32.pub, keeping existing version
 pkgadd: rejecting etc/ports/compat-32.rsync.inactive, keeping existing version
 pkgadd: rejecting etc/ports/contrib.pub, keeping existing version
 pkgadd: rejecting etc/ports/contrib.rsync.inactive, keeping existing version
 pkgadd: rejecting etc/ports/core.pub, keeping existing version
 pkgadd: rejecting etc/ports/core.rsync, keeping existing version
 pkgadd: rejecting etc/ports/opt.pub, keeping existing version
 pkgadd: rejecting etc/ports/opt.rsync, keeping existing version
 pkgadd: rejecting etc/ports/xorg.pub, keeping existing version
 pkgadd: rejecting etc/ports/xorg.rsync, keeping existing version

 $ tree -L 3 /var/lib/pkg/rejected/
 /var/lib/pkg/rejected
   etc
      ports
         compat-32.pub
         compat-32.rsync.inactive
         contrib.pub
         contrib.rsync.inactive
         core.pub
         core.rsync
         drivers
         opt.pub
         opt.rsync
         xorg.pub
         xorg.rsync

If this pkgadd.conf had been in place during an upgrade from CRUX 3.6 to 3.7, and you neglected to check the contents of /var/lib/pkg/rejected/ (either manually or by running rejmerge), then ports -u would synchronize your ports tree with the older branch! Hence you should always pay attention to warnings and errors reported by pkgadd.

5.2.3. Removing a Package

Removing a package is done by using pkgrm. This utility requires one argument, the name of the package you want to remove. Example:

 $ pkgrm bash

Warning

This will remove all files owned by the package, no questions asked. Think twice before doing it and make sure that you did not misspell the package name since that could remove something completely different (e.g. think about what could happen if you misspelled glib as glibc).

5.2.4. Querying the Package Database

Querying the package database is done using pkginfo. This utility has a few options to answer different queries.

OptionDescription
-i, --installedList installed packages and their version.
-l, --list package|fileList files owned by the specified package or contained in file
-o, --owner patternList owner(s) of file(s) matching pattern.

Examples:

 $ pkginfo -i
 acl 2.3.1-1
 alsa-lib 1.2.7.2-1
 alsa-utils 1.2.7-1
 ...>
 yasm 1.3.0-2
 zip 3.0-2
 zlib 1.2.12-1
 zstd 1.5.2-1
 $ pkginfo -l bash
 bin/
 bin/bash
 bin/sh
 etc/
 etc/profile
 usr/
 usr/man/
 usr/man/man1/
 usr/man/man1/bash.1.gz
 usr/man/man1/sh.1.gz
 $ pkginfo -l grep#3.7-1.pkg.tar.gz
 usr/
 usr/bin/
 usr/bin/egrep
 usr/bin/fgrep
 usr/bin/grep
 usr/man/
 usr/man/man1/
 usr/man/man1/egrep.1.gz
 usr/man/man1/fgrep.1.gz
 usr/man/man1/grep.1.gz
 $ pkginfo -o bin/ls
 e2fsprogs  usr/bin/lsattr
 fileutils  bin/ls
 modutils   sbin/lsmod

5.3. Package Management Frontend: prt-get

In its current form pkgutils does not have a concept of dependency handling. To address this a frontend utility called prt-get was created. It supports dependency handling (with the caveat mentioned below) as well as some overlap with pkgutils features and has been an official part of CRUX for some time.

5.3.1. Functionality

Some examples of prt-get's functionality and use are as follows:

Listing installed ports:

$ prt-get listinst
acl
alsa-lib
alsa-utils
[...]

$ prt-get listinst -v
acl 2.3.1-1
alsa-lib 1.2.7.2-1
alsa-utils 1.2.7-1
[...]

Querying information about a port:

$ prt-get info acl
Name:         acl
Path:         /usr/ports/core
Version:      2.3.1
Release:      1
Description:  Access Control Lists library
URL:          http://savannah.nongnu.org/projects/acl
Maintainer:   CRUX System Team, core-ports at crux dot nu
Dependencies: attr

Searching for ports by name:

$ prt-get search glibc
glibc
glibc-32

$ prt-get search --regex '(ba|z)sh$'
bash
zsh

Searching for ports by installed file:

$ prt-get fsearch gconv
Found in /usr/ports/core/glibc:
  /usr/lib/gconv/

Found in /usr/ports/core/glibc-32:
  /usr/lib32/gconv/

Searching for ports by words in their descriptions:

$ prt-get dsearch shell
dash
dialog
dsh
[...]
zsh

Viewing dependency lists:

$ prt-get depends bash
-- dependencies ([i] = installed)
[i] ncurses
[i] readline
[i] bash

$ prt-get quickdep bash
ncurses readline bash

$ prt-get deptree bash
-- dependencies ([i] = installed, '-->' = seen before)
[i] bash
[i]   readline
[i]     ncurses

Installing ports:

$ prt-get install xterm

Note

The 'install' command does NOT process dependencies and it is usually recommended to use 'depinst' (next) instead!
$ prt-get depinst xterm

Viewing and updating outdated ports (generally after 'ports -u'):

Listing installed ports which are out of date:

$prt-get diff
Differences between installed packages and ports tree:

Port                Installed           Available in the ports tree

inkscape            1.2-1            1.2.1-1

Updating an individual port:

$ prt-get update inkscape

Updating all installed ports:

$ prt-get sysup

Note

Currently 'update' and 'sysup' do not process new dependencies introduced after the initial installation of a port. To show such additions to the dependency lists of installed ports, you can chain together several invocations of prt-get with one invocation of awk as follows.
$ prt-get isinst $(prt-get quickdep $(prt-get quickdiff)) | awk '/not installed/ {print $2}'

5.3.2. Configuring prt-get

5.3.2.1. /etc/prt-get.conf

prt-get's main configuration file, '/etc/prt-get.conf', contains options that can be used to change prt-get's behavior. Notably in this file the following options can be configured:

prtdir - This option can occur multiple times and specifies a directory with a 'collection' that prt-get should search for ports. By default the 'core', 'opt', and 'xorg' collections are enabled. The 'compat-32' and 'contrib' collections are disabled by default, see sections "Enabling the 'contrib' collection" and "Enabling the 'compat-32' collection".

logfile - This option configures a file for prt-get to log its operation if desired.

runscripts - This option configures prt-get to run pre-/post-install scripts if they exist in ports being installed or updated. It is recommended that this be enabled as in many cases if a pre- or post-install script exists in a port, it is required to be run for proper operation.

5.3.2.2. /etc/prt-get.aliases

prt-get has a concept of aliases which can be used in a fashion similar to the concept of 'provides' in some other Linux distributions. This file is /etc/prt-get.aliases and contains lines in the following format:

postfix: sendmail
exim: sendmail
qmail: sendmail
masqmail: sendmail

The above set of aliases indicates that postfix, exim, qmail, and masqmail are all considered sufficient to satisfy a dependency on 'sendmail' in a port.

Sometimes the port maintainer will list among the required dependencies a lightweight library, to save on compilation time for the majority of users. If you already have the more powerful library installed, you can use prt-get.aliases to avoid automatic installation of the lightweight alternative. For example, on a system with mozjs91 already built, you would not want prt-get depinst polkit to build duktape as well. This can be accomplished with the following line in prt-get.aliases:

mozjs91: duktape

Another situation that can be handled with prt-get aliases is when you have a fork of port X in your personal overlay, renamed to describe how it differs from the original port, and port X appears somewhere in the dependency tree of port Y. For example, suppose the Pkgfile for foo explicitly disables qt and hard depends on Xorg, so that prt-get depinst foo on a Wayland-only system would bring in all of Xorg. If you create a custom port of foo that disables Xorg in favor of qt, calling it foo-qt, then by appending foo-qt: foo to /etc/prt-get.aliases you can ensure that prt-get does not try to build all of Xorg when foo shows up in some other port's dependency tree.

Note

prt-get's alias function does NOT automatically replace ports during an install or depinst operation. If a port depends on 'duktape' and neither 'duktape' nor 'mozjs91' are installed, prt-get will install 'duktape' as listed in the port's dependencies. If 'mozjs91' was installed before the depending port's install or depinst operation, on the other hand, prt-get will consider the dependency satisfied.

This is NOT an exhaustive list of all of prt-get's commands, features, and configuration options, merely a starting point. More information can be found in the manual and quick start documentation.

5.4. Creating Packages

Creating a package is done using pkgmk. This utility uses a file called Pkgfile, which contains information about the package (such as name, version, etc) and the commands that should be executed in order to compile the package in question.

To be more specific, the Pkgfile file is actually a bash(1) script, which defines a number of variables (name, version, release and source) and a function (build). Below is an example of what a Pkgfile file might look like. The example shows how to package the grep(1) utility. Some comments are inserted for explanation.

# Specify the name of the package.
name=grep

# Specify the version of the package.
version=3.7

# Specify the package release.
release=1

# The source(s) used to build this package.
source=(ftp://ftp.ibiblio.org/pub/gnu/$name/$name-$version.tar.gz)

# The build() function below will be called by pkgmk when
# the listed source files have been unpacked.
build() {
   # The first thing we do is to cd into the source directory.
   cd $name-$version

   # Run the configure script with desired arguments.
   # In this case we want to put grep under /usr/bin and
   # disable national language support.
   ./configure --prefix=/usr --disable-nls

   # Compile.
   make

   # Install the files, BUT do not install it under /usr, instead
   # we redirect all the files to $PKG/usr by setting the DESTDIR
   # variable. The $PKG variable points to a temporary directory
   # which will later be made into a tar.gz-file. Note that the
   # DESTDIR variable is not used by all Makefiles, some use prefix
   # and others use ROOT, etc. You have to inspect the Makefile in
   # question to find out. Some Makefiles do not support redirection
   # at all. In those cases you will have to create a patch for it.
   make DESTDIR=$PKG install

   # Remove unwanted files, in this case the info-pages.
   rm -rf $PKG/usr/info
}

In reality you do not include all those comments, thus the real Pkgfile for grep(1) looks like this:

# Description: GNU grep, egrep and fgrep
# URL:         http://www.gnu.org/software/grep/grep.html
# Maintainer:  Per Lid&#65533;n, per at fukt dot bth dot se

name=grep
version=3.7
release=1
source=(ftp://ftp.ibiblio.org/pub/gnu/$name/$name-$version.tar.gz)

build() {
  cd $name-$version
  ./configure --prefix=/usr --disable-nls
  make
  make DESTDIR=$PKG install
  rm -rf $PKG/usr/info
}

Note

The build() function in the example above is just an example of how grep is built. The contents of the function can differ significantly if the program is built in some other way, e.g. does not use autoconf.

When the build() function has been executed, the $PKG directory will be made into a package named <name>#<version>-<release>.pkg.tar.gz. Before the package creation is completed, pkgmk will check the contents of the package against the .footprint file. If this file does not exist, it will be created and the test will be skipped. The .footprint file will contain a list of all files that should be in the package if the build was successful or a list of all the files that were installed in $PKG (if the .footprint did not already exist). If there is a mismatch the test will fail and an error message will be printed. You should not write the .footprint file by hand. Instead, when a package has been upgraded and you need to update the contents of the .footprint file you simply do pkgmk -uf. This test ensures that a rebuild of the package turned out as expected.

If the package built without errors it's time to install it by using pkgadd and try it out. I highly recommend looking at the Pkgfile in another package(s), since looking at examples is a great way to learn.

Note

Please see the Package Guidelines for additional recommendations regarding Pkgfile variables (name, version, release, build) and the footprint.

5.5. Adjusting/Configuring the Package Build Process

Many settings pertaining to the package build process can be adjusted by editing the pkgmk(8) configuration file /etc/pkgmk.conf. Some of these configurable settings include:

Here are some examples:

PKGMK_SOURCE_MIRRORS=(http://fileserver.intranet/crux/sources/)

This setting instructs pkgmk to attempt to fetch all source archives from http://fileserver.intranet/crux/sources/ before falling back to the source URL specified in the Pkgfile. Multiple URLS can be separated by spaces.

PKGMK_SOURCE_DIR="/usr/ports/srcfiles"

This example instructs pkgmk to store and find source archives in /usr/ports/srcfiles. An example benefit of this setup would be the ability to store /usr/ports/srcfiles on an NFS server on your local network for use by multiple crux installations. (PKGMK_PACKAGE_DIR can be set and used the same way. But if NFS is too challenging to set up on your local network and you find it easier to configure an http server instead, pkg-get from the opt collection gives you an alternative mechanism for sharing built packages.)

PKGMK_WORK_DIR="/usr/ports/work/$name"

This example instructs pkgmk to use /usr/ports/work/$name as a work area for building the specified package. Building the grep package would result in the work area being /usr/ports/work/grep. An alternative would be to use a tmpfs as your work directory.

There are a few more settings which can be found in the pkgmk.conf man page.

5.6. Package Guidelines

5.6.1. General

5.6.2. Directories

DirectoryDescription
/usr/bin/User command/application binaries
/usr/sbin/System binaries (e.g. daemons)
/usr/lib/Libraries
/usr/include/Header files
/usr/lib/<prog>/Plug-ins, addons, etc
/usr/share/man/Man pages
/usr/share/<prog>/Data files
/usr/etc/<prog>/Configuration files
/etc/Configuration files for system software (daemons, etc)

5.6.3. Remove Junk Files

5.6.4. Pkgfile Variables

5.6.5. Pkgfile Header

The commented lines at the beginning of a Pkgfile do not affect the operation of pkgmk, but prt-get and other CRUX tools will make use of the information provided there. Four headers of utmost importance are:

NameMeaning
DescriptionA short description of the package; keep it factual
MaintainerYour full name and e-mail address, obfuscated if you want
URLA webpage with more information on this software package
Depends onA list of dependencies, separated either by spaces or commas

Depends on can be omitted if there are no dependencies. To keep this line short, runtime dependencies in the 'core' collection are omitted, unless they provide a library that is dynamically linked to the built program. See the Pkgfile man page for more details.

Two other headers you will often encounter when inspecting Pkgfiles are Optional and Nice to have. None of the official CRUX tools will be affected by the contents of these lines, but maintainers find it helpful to store in Optional the list of “soft” dependencies (libraries that will be linked to the built program, if present during compilation). This header then serves as a reminder of tests that might need to be included in the build() function in order to set the appropriate configure flags. As an end user of official ports, you might find in these headers some clues about:

Example header

# Description: CUPS - Common UNIX Printing System
# URL: https://openprinting.github.io/cups/
# Maintainer: Juergen Daubert, jue at crux dot nu
# Depends on: acl libusb zlib linux-pam
# Optional: dbus gnutls

6. The Ports System

6.1. Introduction

6.1.1. What is a Port?

A port is a directory containing the files needed for building a package using pkgmk. This means that this directory at least has the files Pkgfile (which is the package build description) and .footprint (which is used for regression testing and contains a list of files this package is expected to contain once it is built). Further, a port directory can contain patches and/or other files needed for building the package. It is important to understand that the actual source code for the package is not necessarily present in port directory. Instead the Pkgfile contains an URL which points to a location where the source can be downloaded.

The use of the word port in this context is borrowed from the BSD world, where a port refers to a program that has been ported to a system or platform. The word can sometimes be a bit misleading since most programs require no actual porting to run on CRUX (or on Linux in general).

6.1.2. What is the Ports System?

The term Ports System refers to a remote repository containing ports and a client program capable of downloading ports from that repository. The administrator of a CRUX system runs the ports(8) bash script to download ports from the remote repository and place them in /usr/ports/. The ports script uses rsync(1) or httpup(1) or git(1) to do the actual downloading/synchronization.

6.1.3. Port collections

CRUX ports are organized in so-called 'collections'. There are three different layers of ports:

6.1.3.1. The official collections 'core', 'opt', 'xorg' and 'compat-32'

core, opt, xorg and compat-32 are the four primary collections of CRUX. They're maintained by the CRUX development team which ensures that they're consistent and working well together. The first three are enabled by default. The compat-32 collection is disabled by default and contains 32-bit compatibility ports.

6.1.3.2. The user contributed collection 'contrib'

The contrib collection is a collection which is provided by experienced port maintainers: some are part of the CRUX development team, while others are regular users. Its goal is to reduce the number of duplicate ports provided in the individual collections. If you're a seasoned port maintainer, you might even want to join the contrib team.

As those ports are not provided officially by the CRUX development team, this collection is disabled by default.

6.1.3.3. The individual collections from CRUX users

Using HttpUp or git, every user can publish his or her own ports easily; the only requirement for that is some webspace to upload the ports. Maintaining an HttpUp repository of ports, which you've tested and gotten successfully running, is a simple way to contribute back to the CRUX community.

6.2. Using the Ports System

6.2.1. Synchronizing Your Local Ports Structure

When CRUX is installed for the first time the local ports structure (/usr/ports/) is empty. To bring your local ports structure up to date you use the ports utility with the -u option. Example:

 $ ports -u

The -u option means update, and tells ports to contact the ports repository and download new and updated ports. The output from this execution is something like this:

 Updating file list from crux.nu::ports/crux-3.7/core/
 Updating collection ports/crux-3.7/core/
 ...
 Updating file list from crux.nu::ports/crux-3.7/opt/
 Updating collection ports/crux-3.7/opt/
 ...
 Updating file list from crux.nu::ports/crux-3.7/xorg/
 Updating collection ports/crux-3.7/xorg/
 ...
 Finished successfully

The output reveals which files are downloaded, updated and deleted.

6.2.2. Listing Local Ports

When the local ports structure has been updated the directory /usr/ports/ will contain at least two collections, core and opt. Under each of these directories you will find ports. You can simply browse around in the directory structure to find out which ports are available.

 $ cd /usr/ports/core/
 $ ls

 acl/			httpup/			nftables/
 attr/			iana-etc/		ninja/
 autoconf/		inetutils/		openssh/
 automake/		iproute2/		openssl/
 bash/			iptables/		patch/
 bc/			jansson/		pciutils/
 binutils/		jsoncpp/		perl/
 bison/			kbd/			pkgconf/
 bzip2/			kmod/			pkgutils/
 ca-certificates/	less/			ports/
 cmake/			libarchive/		procps/
 coreutils/		libcap/			prt-get/
 cpio/			libdevmapper/		psmisc/
 curl/			libedit/		python3/
 dash/			libffi/			python3-setuptools/
 db/			libgmp/			rc/
 dcron/			libmnl/			rdate/
 dhcpcd/		libmpc/			readline/
 diffutils/		libmpfr/		rhash/
 dumb_runtime_dir/	libnftnl/		rsync/
 e2fsprogs/		libnghttp2/		sed/
 ed/			libnsl/			shadow/
 elfutils/		libpcre/		signify/
 eudev/			libpcre2/		sqlite3/
 exim/			libpipeline/		start-stop-daemon/
 expat/			libtirpc/		sudo/
 file/			libtool/		sysfsutils/
 filesystem/		libusb/			sysklogd/
 findutils/		libuv/			sysvinit/
 flex/			linux-pam/		tar/
 gawk/			lzlib/			time/
 gcc/			lzo/			tzdata/
 gdbm/			m4/			usbutils/
 gettext/		make/			util-linux/
 glibc/			man-db/			vim/
 glibc-32/		man-pages/		which/
 gperf/			meson/			xz/
 grep/			mlocate/		zlib/
 groff/			mpdecimal/		zstd/
 gzip/			nasm/
 hdparm/		ncurses/

You can also use ports with the -l option to list all local ports. Example:

 $ ports -l
 core/acl
 core/attr
 core/autoconf
 core/automake
 core/bash
 core/bc
 ...

If you are looking for a specific package, a command like ports -l | grep sendmail provides a straightforward way to find out if the package is available and if so in which collection it is located. More complicated searches (eg., based on footprint, description, or maintainer) can be performed using prt-get.

6.2.3. Listing Version Differences

To find out if the ports structure carries ports that are different (likely newer) compared to the versions currently installed, you can use the option -d. If differences are found (in either 'version' or 'release'), the output from the above command could look something like this:

 $ ports -d
 Collection  Name     Port      Installed
 contrib     pipewire 0.3.56-1  0.3.55-1
 xorg        mesa     22.1.5-1  22.1.4-1

If no version differences were found, i.e. the system is in sync with the ports structure, the output will simply be:

 $ ports -d
 No differences found

6.2.4. Building and Installing Packages

Once you have found a port that you want to build and install you simply go into the desired port directory and use pkgmk to build it. Example:

 $ cd /usr/ports/core/gawk
 $ pkgmk -d

The -d option means download missing source files and tells pkgmk to download the source(s) specified in the Pkgfile (in case the source is already downloaded, this option is ignored). When the download is completed the package will be built. If the package was built successfully you can use pkgadd to install or upgrade it. Example:

 $ pkgadd gawk#3.1.5-3.pkg.tar.gz

To make life a bit easier these two steps can be made into one by using the options -i (for install) or -u (for upgrade). Example:

 $ pkgmk -d -i

or

 $ pkgmk -d -u

This will download, build and then install/upgrade the package. Note that the package will only be installed/upgraded if the build is successful.

Note

If you enable building ports as an unprivileged user and give that user write permissions on the directories for pkgmk {sources, work, packages}, the unprivileged user will be able to create a package but not to exercise the -i and -u options of pkgmk. There are forks of pkgmk that automatically invoke sudo or doas when performing the pkgadd step, but these forks are not part of the official CRUX utilities at this time.

6.2.5. Enabling the 'contrib' collection

As previously mentioned, the 'contrib' collection contains useful ports of experienced port maintainers. Since they are not provided by the CRUX development team, you should be slightly more critical with respect to quality and security. However, members with write permissions for 'contrib' are usually well-known and active in the CRUX community.

To enable the 'contrib' collection so that ports -u will bring it up to date, just rename its rsync file.

$ cd /etc/ports
$ mv contrib.rsync.inactive contrib.rsync

You will probably also want to let prt-get know about the newly-enabled 'contrib' tree. This can be done by editing /etc/prt-get.conf and uncommenting the line prtdir /usr/ports/contrib (i.e. remove the hashmark in the beginning of the line). After that, it should look like this:

###
### prt-get conf
###

# note: the order matters: the package found first is used
prtdir /usr/ports/core
prtdir /usr/ports/opt

# the following line enables the user maintained contrib collection
prtdir /usr/ports/contrib

Now, run ports -u and you're ready to use the ports from contrib.

6.2.6. Enabling the 'compat-32' collection

The 'compat-32' collection contains compatibility ports needed for 32-bit support (32-bit applications running on a 64-bit multilib system).

To enable it for ports, do

$ cd /etc/ports
$ mv compat-32.rsync.inactive compat-32.rsync

The 'compat-32' collection is enabled in the same way as the 'contrib' collection (described previously) for usage with prt-get.

As with 'contrib', run ports -u and you're ready to use the ports from compat-32.

6.2.7. Additional tools

6.2.7.1. Building ports as unprivileged user

Building packages requires root privileges in order to create files with the correct owner and group. This is a security concern because a malicious or badly designed port can run arbitrary commands when its Pkgfile is sourced by the shell. The fakeroot command provides a way to build ports as normal user. Particularly when you build packages from user contributed repositories you are advised to use fakeroot:

$ fakeroot pkgmk -d

6.2.7.2. Useful scripts

Regarding package and ports management there are many tasks which can be done in several steps with the CRUX standard tools introduced above. The opt repository contains a port called prt-utils with many such scripts. Other combinations of low-level tools, using UNIX pipes, command substitution, and text processing utilities, can be found in the bug tracker, the mailing list, and IRC logs. Efforts are underway to bring this diaspora of institutional knowledge into a central place, such as the EXAMPLES section of the most relevant man page.

7. Appendix

7.1. Troubleshooting

Many common problems are answered in the FAQ document, so if you experience problems please check whether the CRUX FAQ contains answers to your questions already.

If you have further questions, there's a dedicated mailing list for CRUX, and an IRC channel. Actual information about these can be found on the Community page.

7.2. Writing a grub config file by hand

If grub-mkconfig does not work (eg., because you saved the kernel image under a non-standard name), a grub.cfg file can be created manually. For more information see the GRUB manual at http://www.gnu.org/software/grub/manual/. A simple example configuration might look like the following:

# Display the menu for 10 seconds
set timeout=10

# Boot the first entry by default
set default=0

# Boot entries follow

# Default CRUX boot entry
menuentry "CRUX 3.7" {
	linux (hd0,msdos2)/boot/vmlinuz-5.15.55 root=/dev/sda2 quiet
}

# Single-user recovery entry
menuentry "CRUX 3.7 single-user mode" {
	linux (hd0,msdos2)/boot/vmlinuz-5.15.55 root=/dev/sda2 quiet single
}

# Memory test entry
menuentry "MemTest86+ 4.20" {
	linux16 (hd0,msdos2)/boot/memtest86+-4.20.bin
}

Save the manual configuration file as /boot/grub/grub.cfg.

7.3. EFI Stub installation notes

GRUB and SYSLINUX offer the most familiar experience for users coming from LILO. After a one-time interaction with the BIOS and the Master Boot Record, all subsequent updates to the GRUB or SYSLINUX configuration only involve editing a flat-text file. Although with LILO you had to run /sbin/lilo after editing its flat-text config, for GRUB and SYSLINUX you never have to touch the contents of the bootsector or the NVRAM after the initial installation; changes to their flat-text config files are automatically detected.

A third way to boot into your CRUX system involves direct interaction with the EFI variables, letting the Linux kernel image provide the required EFI bootloader code. This option has a workflow that might remind you of running /sbin/lilo after building and installing each new kernel.

Note: this type of booting only works in UEFI mode, and when your kernel has been built with CONFIG_EFI_STUB=y. Legacy MBR booting is not supported with this method.

As with GRUB and SYSLINUX, the kernel has to be told which device to use as a root filesystem. Most modern BIOSes allow you to append options like root=/dev/sda2 to the line that boots the kernel, but some buggy UEFI implementations do not honor such appended options. To be safe, you can customize the boot options during the kernel configuration process (the make menuconfig step), at the expense of making it harder to put the disk in an external enclosure and boot from USB (when you want to travel lightly). If you leave the boot options empty during kernel configuration, and the BIOS does not honor your appended options, you might have to boot from a rescue disk to get back into your system and fix things.

$ mkdir -p /boot/efi/BOOT
$ cd /boot/efi/BOOT
$ cp /usr/src/linux-5.15.55/arch/x86/boot/bzImage vmlinuz-5.15.55.efi
 $ efibootmgr -c -d /dev/sda -L 'Linux 5.15.55' -l '\BOOT\vmlinuz-5.15.55.efi' -u 'root=/dev/sda2'
$ efibootmgr
BootCurrent: 0000
Timeout: 1 seconds
BootOrder: 0000,0001
Boot0000* Linux 5.15.26	 HD(1,GPT,d5a44413-...,0x800,0x64000)/File(\BOOT\vmlinuz-5.15.26.efi)72006f006f0074...
Boot0001* Linux 5.15.55	 HD(1,GPT,d5a44413-...,0x800,0x64000)/File(\BOOT\vmlinuz-5.15.55.efi)72006f006f0074...

$ efibootmgr -o 0001,0000
As in the UEFI installation of SYSLINUX, the subdirectory EFI/BOOT of the EFI system partition is the default path where the BIOS expects to find a bootloader. This location is more obvious in the efibootmgr commands, since efibootmgr is agnostic about the mountpoint of your EFI system partition. The two most common ways to shorten what looks like an overly-verbose path to the kernel are:
  • mount your EFI system partition somewhere else (and adjust the mkdir and cd commands as needed).
  • save your kernel closer to the root of the EFI system partition (and change the efibootmgr invocation as needed).

7.4. Notes on Initramfs

A common scenario that prevents the usual practice of booting a slimmed-down kernel containing only the drivers for the root filesystem (and then loading modules to initialize other hardware) is that the root filesystem is not a physical volume, but rather a logical volume inside an encryption layer like LUKS. To handle this situation, you will need to go beyond the kernel building process outlined above, and also create a compressed filesystem image (called an initramfs) that contains the lvm2 and cryptsetup packages (and the drivers for usb input devices, if you chose not to compile them into the kernel). Creating such an initramfs was once an intricate procedure, but tools like dracut make it much simpler these days.

If running dracut, and saving the initramfs alongside the kernel in the EFI system partition, had been the only deviations from the usual CRUX installation procedure, then one section of the appendix would suffice to explain how to do full-disk encryption in CRUX. But preparation for this setup begins at the partitioning stage, when you need to call commands from the lvm2 and cryptsetup packages before creating and mounting your filesystems. So this section of the appendix just points to a separate document, where an outline for installing CRUX with full-disk encryption is given from beginning to end. Even if full-disk encryption is not your desired endpoint and you just want to learn more about highly-modular kernel configs, the need for an initramfs is easier to motivate by considering a specific use case like full-disk encryption. Studying the upstream documentation for any unfamiliar command in the linked outline (eg., cryptsetup, pvcreate, or dracut) is an excellent way to distinguish the functions performed at each step of the process.