-
-
Notifications
You must be signed in to change notification settings - Fork 85
2. System Design
Athena OS is based on Arch Linux. At the beginning of the project, we started from an Arch Linux ISO and built Athena step by step, tailoring it with functional and non-functional requirements.
The steps involved for the creation of the base of Athena are shown. During the development phase, Athena has been built in two different ways:
- Direct: Arch Linux was used as base and built manually with only modules we need
- ISO: Arch Linux was used as base and built automatically with only modules we need. The automation has been reached by using Archiso
Create a Virtual Machine with at least 80 GB of disk space.
In case we are using VirtualBox, enable EFI by the Virtual Machine settings we create:
- Click on your Virtual Machine label of VirtualBox
- Click on Settings -> System -> Motherboard -> Enable EFI Don't enable 3D Acceleration on VirtualBox because bugged.
In case we are using VMware, create a new Virtual Machine by selecting I will install the operating system later
.
Go to the VMware Virtual Machine folder we just created, edit the .vmx
file by a text editor and add the following line on the 2nd row:
firmware = "efi"
Run the Virtual Machine and the screen will stop on some messages related EFI loading. Go above on Player menu -> Removable Devices -> CD/DVD (IDE) -> Settings -> Select the Arch Linux .iso
. Then again, Player menu -> Removable Devices -> CD/DVD (IDE) -> Connect and wait some minutes and we should get the access to the EFI Boot Manager. Choose the 2nd voice EFI VMWare Virtual IDE CDROM Drive (IDE 1:0)
and we get the Arch Boot Window for UEFI.
Furthermore, we can enable Accelerate 3D graphics
by the Virtual Machine settings.
Get the list of disks and their size:
$ fdisk -l
Let's guess we get /dev/sda
.
For setting the disk:
fdisk /dev/sda
Command (m for help): p
Command (m for help): g
Command (m for help): n
Partition number (1-128, default 1):
First sector (2048-xxxxxx, default 2048):
Last sector, +/- sectors or +/-size{K,M,G,T,P} (2048-xxxxx, default xxxxx): +500M
Command (m for help): t
Selected partition 1
Partition type or alias (type L to list all): 1
Changed type of partition 'Linux filesystem' to 'EFI System'.
Command (m for help): p
Command (m for help): n
Partition number (2-128, default 2):
First sector (xxx-xxxxxx, default xxx):
Last sector, +/- sectors or +/-size{K,M,G,T,P} (xxx-xxxxx, default xxxxx):
Command (m for help): t
Partition number (1-2, default 2):
Partition type or alias (type L to list all): 43
Changed type of partition 'Linux filesystem' to Linux LVM'.
Command (m for help): p
[Now we see two partitions: EFI System (/dev/sda1) and Linux LVM (/dev/sda2)]
Command (m for help): w
Now we wrote the changes. Here we will create two logical volumes: lv_root
and lv_home
but if you allocated not much space and want to avoid any disk space issues, create only one logical volume.
$ mkfs.fat -F32 /dev/sda1
$ pvcreate --dataalignment 1m /dev/sda2
$ vgcreate volgroup0 /dev/sda2
$ lvcreate -L 50GB volgroup0 -n lv_root
$ lvcreate -l 100%FREE volgroup0 -n lv_home
$ modprobe dm_mod
$ vgscan
$ vgchange -ay
$ mkfs.ext4 /dev/volgroup0/lv_root
$ mount /dev/volgroup0/lv_root /mnt
$ mkfs.ext4 /dev/volgroup0/lv_home
$ mkdir /mnt/home
$ mount /dev/volgroup0/lv_home /mnt/home
$ mkdir /mnt/etc
$ genfstab -U -p /mnt >> /mnt/etc/fstab
$ cat /mnt/etc/fstab #Check if there are no errors
We just set the partition. Now we must install Arch Linux that will be our base for Athena:
$ pacstrap -i /mnt base
$ arch-chroot /mnt
$ pacman -S linux linux-headers
OR
$ pacman -S linux-lts linux-lts-headers
OR install all of them. Let's guess to install linux and linux-headers:
$ pacman -S nano
$ pacman -S base-devel openssh
OpenSSH is optional. If you install it, be sure to run systemctl enable sshd
after the installation.
$ pacman -S networkmanager wpa_supplicant wireless_tools netctl inetutils
$ pacman -S dialog
$ systemctl enable NetworkManager
$ pacman -S lvm2
$ nano /etc/mkinitcpio.conf
Scroll until the first uncommented HOOKS=(base udev autodetect modconf block filesystems keyboard fsck)
and add lvm2
as:
HOOKS=(base udev autodetect modconf block lvm2 filesystems keyboard fsck)
. Note that, if btrfs
will be used as filesystem, fsck
hook can be removed because no needed (source: https://wiki.archlinux.org/title/Improving_performance/Boot_process#Filesystem_mounts).
$ mkinitcpio -p linux
If you installed linux-lts
instead of linux
, run mkinitcpio -p linux-lts
.
$ nano /etc/locale.gen
Uncomment en_US.UTF-8 UTF-8
.
$ nano /etc/locale.conf
Add LANG=en_US.UTF-8
.
$ locale-gen
$ passwd
Enter root password
$ useradd -m -g users -G wheel <your-username>
$ passwd <your-username>
Enter <your-username> password
$ pacman -S sudo
$ EDITOR=nano visudo
Scroll down and uncomment # %wheel ALL=(ALL) ALL
and save the file.
Let's install GRUB as bootloader of our OS:
$ pacman -S grub dosfstools os-prober mtools
$ pacman -S efibootmgr #If you are using UEFI partition
$ mkdir /boot/EFI
$ mount /dev/sda1 /boot/EFI
$ grub-install --target=x86_64-efi --bootloader-id=grub_uefi --recheck # It works in case of UEFI partition
$ ls -l /boot/grub
Check if "locale" folder exists. If does not, mkdir /boot/grub/locale
$ cp /usr/share/locale/en\@quot/LC_MESSAGES/grub.mo /boot/grub/locale/en.mo #en is related to language
$ pacman -S intel-ucode # if you have AMD, install amd-ucode
$ grub-mkconfig -o /boot/grub/grub.cfg
$ exit
$ umount -a
$ reboot
If you are on VirtualBox, save a snapshot of the Virtual Machine. If you are on VMware Workstation Player, make a backup of the folder containing your Virtual Machine files.
We proceed to install the Swap partition and some drivers (e.g., NVIDIA)
$ su
Enter root password
$ cd /root
$ dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress
$ chmod 600 /swapfile
$ mkswap /swapfile
$ cp /etc/fstab /etc/fstab.bak
$ echo '/swapfile none swap sw 0 0' | tee -a /etc/fstab
$ cat /etc/fstab
# Check if the line is inserted correctly
$ free -m
$ mount -a
$ free -m
$ swapon -a
$ free -m
$ timedatectl set-timezone Europe/Zurich
$ systemctl enable systemd-timesyncd
$ hostnamectl set-hostname <your-hostname>
$ nano /etc/hosts
# Add:
127.0.0.1 localhost
127.0.1.1 <your-hostname>
$ pacman -S xorg-server # I don't install it
$ pacman -S nvidia # if we installed linux-lts package at the beginning, install nvidia-lts. If you don't have NVIDIA, install mesa package
$ pacman -S wget which git man-db man-pages
$ mandb # command to generate the search database for manpage entries.
# Check if unset MANPATH so that mandb could use the man_db.conf (check also the content of man_db.conf for checking what it contains)
Note that generally NVIDIA drivers don't work in VirtualBox and VMware Workstation Player environment. You cannot install drivers for the Host's Graphics Adapter in a Virtual Machine because GPU passthrough is not available on VM softwares. So you are always using a virtual graphics adapter and not the one installed on your host OS. The Virtual Machine does not see your GPU and uses its own Drivers when VMware Tools or VirtualBox Guest Additions are installed.
Now, let's install Virtual Machine tools. If we are working on WMware, install:
$ pacman -S open-vm-tools
$ systemctl enable vmtoolsd.service
$ systemctl enable vmware-vmblock-fuse.service
If we are working on VirtualBox:
$ pacman -S virtualbox-guest-utils xf86-video-vmware # You need both of them if you are using VirtualBox
$ systemctl enable vboxservice
Athena is based on GNOME as Desktop Environment because of the usage of particular GNOME extensions. The GNOME package will install also GDM display manager. As display protocol, we will use Wayland:
$ pacman -S gnome
$ pacman -S gnome-tweaks wayland
$ systemctl enable gdm # Enabling this, it allows the login window to appear at startup. GDM is the display manager of GNOME
$ reboot
For native installation of Athena where you can use NVIDIA drivers, you can follow these links for better integrating NVIDIA with Wayland:
- https://www.youtube.com/watch?v=_YtgszmnfN8
- https://www.youtube.com/watch?v=qmvWQlsFc38&ab_channel=babyWOGUE
Source: https://www.youtube.com/watch?v=DPLnBPM4DhI&ab_channel=LearnLinuxTV
wget https://github.com/Schneegans/Fly-Pie/releases/latest/download/[email protected]
gnome-extensions install [email protected]
Logout / Login since we are on Wayland.
gnome-extensions enable [email protected]
Test it by pressing CTRL+SPACE
on the keyboard.
For accessing to the settings:
gnome-extensions prefs [email protected]
For exporting your custom settings, use:
dconf dump /org/gnome/shell/extensions/flypie/ > dconf-flypie.ini
For importing your custom settings, use:
dconf load /org/gnome/shell/extensions/flypie/ < dconf-flypie.ini
wget https://github.com/Schneegans/Burn-My-Windows/releases/latest/download/[email protected]
gnome-extensions install [email protected]
Logout / Login since we are on Wayland.
gnome-extensions enable [email protected]
Test it by opening and closing a window.
For accessing to the settings:
gnome-extensions prefs [email protected]
For exporting your custom settings, use:
dconf dump /org/gnome/shell/extensions/burn-my-windows/ > dconf-bmw.ini
For importing your custom settings, use:
dconf load /org/gnome/shell/extensions/burn-my-windows/ < dconf-bmw.ini
If you are using Kitty, set your preferred terminal as default terminal by editing your /etc/bash.bashrc
file and changing the line xterm*|rxvt*|Eterm|aterm|kterm|gnome*
to add kitty*
, so we should have xterm*|rxvt*|Eterm|kitty*|aterm|kterm|gnome*
.
Currently Athena uses mainly FISH shell but in the future users can choose among their favorite shells.
Setting immediately FISH as default shell is not good, because, since FISH and BASH have different parsing rules, if our default shell is FISH and we start a user session, /etc/profile
, /etc/profile.d/*.sh
and .bashrc
scripts cannot be sourced because falling in error since they are "sourced" by FISH rules and not BASH rules.
A solution is to have the user associated to BASH in /etc/passwd
and then calling FISH in .bashrc
file by adding at the end:
if [[ $(ps --no-header --pid=$PPID --format=comm) != "fish" && -z ${BASH_EXECUTION_STRING} ]]
then
exec fish
fi
The equivalent of FISH for .bashrc
is ~/.config/fish/config.fish
. Edit the file ~/.config/fish/config.fish
, creating it if it does not exist.
The main used font is JetBrains: https://www.jetbrains.com/lp/mono/#how-to-install
ISO approach consists of the creation of an ISO file we can use for installing the OS in a flexible manner. This method is based on the usage of Archiso. Please, read its documentation on how to set it. Refer to https://wiki.archlinux.org/title/archiso#Kernel for speeding up the build process.
Here we suppose we already set Archiso and we proceed to build our ISO.
We make our project folder by mkdir -p ~/athena-iso
and inside of it we put archiso content as explained in the official documentation. We should have a tree directory similar to this:
athena-iso
└── archlive
├── airootfs
│ ├── etc
│ │ ├── hostname
│ │ ├── locale.conf
│ │ ├── localtime -> /usr/share/zoneinfo/UTC
│ │ ├── mkinitcpio.conf
│ │ ├── mkinitcpio.d
│ │ │ └── linux.preset
│ │ ├── modprobe.d
│ │ │ └── broadcom-wl.conf
│ │ ├── motd
│ │ ├── pacman.d
│ │ │ └── hooks
│ │ │ ├── 40-locale-gen.hook
│ │ │ ├── uncomment-mirrors.hook
│ │ │ └── zzzz99-remove-custom-hooks-from-airootfs.hook
│ │ ├── passwd
│ │ ├── resolv.conf -> /run/systemd/resolve/stub-resolv.conf
│ │ ├── shadow
│ │ ├── ssh
│ │ │ └── sshd_config
│ │ ├── systemd
│ │ │ ├── journald.conf.d
│ │ │ │ └── volatile-storage.conf
│ │ │ ├── logind.conf.d
│ │ │ │ └── do-not-suspend.conf
│ │ │ ├── network
│ │ │ │ ├── 20-ethernet.network
│ │ │ │ ├── 20-wlan.network
│ │ │ │ └── 20-wwan.network
│ │ │ ├── system
│ │ │ │ ├── choose-mirror.service
│ │ │ │ ├── cloud-init.target.wants
│ │ │ │ │ ├── cloud-config.service -> /usr/lib/systemd/system/cloud-config.service
│ │ │ │ │ ├── cloud-final.service -> /usr/lib/systemd/system/cloud-final.service
│ │ │ │ │ ├── cloud-init-local.service -> /usr/lib/systemd/system/cloud-init-local.service
│ │ │ │ │ └── cloud-init.service -> /usr/lib/systemd/system/cloud-init.service
│ │ │ │ ├── dbus-org.freedesktop.ModemManager1.service -> /usr/lib/systemd/system/ModemManager.service
│ │ │ │ ├── dbus-org.freedesktop.network1.service -> /usr/lib/systemd/system/systemd-networkd.service
│ │ │ │ ├── dbus-org.freedesktop.resolve1.service -> /usr/lib/systemd/system/systemd-resolved.service
│ │ │ │ ├── etc-pacman.d-gnupg.mount
│ │ │ │ ├── [email protected]
│ │ │ │ │ └── autologin.conf
│ │ │ │ ├── livecd-alsa-unmuter.service
│ │ │ │ ├── livecd-talk.service
│ │ │ │ ├── multi-user.target.wants
│ │ │ │ │ ├── choose-mirror.service -> ../choose-mirror.service
│ │ │ │ │ ├── hv_fcopy_daemon.service -> /usr/lib/systemd/system/hv_fcopy_daemon.service
│ │ │ │ │ ├── hv_kvp_daemon.service -> /usr/lib/systemd/system/hv_kvp_daemon.service
│ │ │ │ │ ├── hv_vss_daemon.service -> /usr/lib/systemd/system/hv_vss_daemon.service
│ │ │ │ │ ├── iwd.service -> /usr/lib/systemd/system/iwd.service
│ │ │ │ │ ├── livecd-talk.service -> /etc/systemd/system/livecd-talk.service
│ │ │ │ │ ├── ModemManager.service -> /usr/lib/systemd/system/ModemManager.service
│ │ │ │ │ ├── pacman-init.service -> ../pacman-init.service
│ │ │ │ │ ├── qemu-guest-agent.service -> /usr/lib/systemd/system/qemu-guest-agent.service
│ │ │ │ │ ├── reflector.service -> /usr/lib/systemd/system/reflector.service
│ │ │ │ │ ├── sshd.service -> /usr/lib/systemd/system/sshd.service
│ │ │ │ │ ├── systemd-networkd.service -> /usr/lib/systemd/system/systemd-networkd.service
│ │ │ │ │ ├── systemd-resolved.service -> /usr/lib/systemd/system/systemd-resolved.service
│ │ │ │ │ ├── vboxservice.service -> /usr/lib/systemd/system/vboxservice.service
│ │ │ │ │ ├── vmtoolsd.service -> /usr/lib/systemd/system/vmtoolsd.service
│ │ │ │ │ └── vmware-vmblock-fuse.service -> /usr/lib/systemd/system/vmware-vmblock-fuse.service
│ │ │ │ ├── network-online.target.wants
│ │ │ │ │ └── systemd-networkd-wait-online.service -> /usr/lib/systemd/system/systemd-networkd-wait-online.service
│ │ │ │ ├── pacman-init.service
│ │ │ │ ├── reflector.service.d
│ │ │ │ │ └── archiso.conf
│ │ │ │ ├── sockets.target.wants
│ │ │ │ │ └── systemd-networkd.socket -> /usr/lib/systemd/system/systemd-networkd.socket
│ │ │ │ ├── sound.target.wants
│ │ │ │ │ └── livecd-alsa-unmuter.service -> ../livecd-alsa-unmuter.service
│ │ │ │ └── systemd-networkd-wait-online.service.d
│ │ │ │ └── wait-for-only-one-interface.conf
│ │ │ └── system-generators
│ │ │ └── systemd-gpt-auto-generator -> /dev/null
│ │ └── xdg
│ │ └── reflector
│ │ └── reflector.conf
│ ├── root
│ └── usr
│ └── local
│ ├── bin
│ │ ├── choose-mirror
│ │ ├── Installation_guide
│ │ └── livecd-sound
│ └── share
│ └── livecd-sound
│ └── asound.conf.in
├── bootstrap_packages.x86_64
├── efiboot
│ └── loader
│ ├── entries
│ │ ├── 01-archiso-x86_64-linux.conf
│ │ ├── 02-archiso-x86_64-speech-linux.conf
│ │ ├── 03-archiso-x86_64-ram-linux.conf
│ │ └── 04-archiso-x86_64-ram-speech-linux.conf
│ └── loader.conf
├── grub
│ └── grub.cfg
├── packages.x86_64
├── pacman.conf
├── profiledef.sh
└── syslinux
├── archiso_head.cfg
├── archiso_pxe.cfg
├── archiso_pxe-linux.cfg
├── archiso_sys.cfg
├── archiso_sys-linux.cfg
├── archiso_tail.cfg
├── splash.png
└── syslinux.cfg
The airootfs directory is used as the starting point for the root directory (/
) of the live system on the image. All its contents will be copied over to the working directory before packages are installed.
Place any custom files and/or directories in the desired location under airootfs/
. For example, if the user has a set of iptables scripts on its current system to be used on its live image, copy them over as such:
$ cp -r /etc/iptables archlive/airootfs/etc
Similarly, some care is required for special configuration files that reside somewhere down the hierarchy. Missing parts of the directory structure can be simply created with mkdir
.
To add a file to the root's home directory, place it in archlive/airootfs/root/
. To add a file to all other users' home directories, place it in archlive/airootfs/etc/skel/
.
Note: Custom files that conflict with those ones provided by packages will be overwritten or generate an error unless a package specifies them as backup files in its PKGBUILD
file.
By default, permissions will be set as 644
for files and 755
for directories. All of them will be owned by the root
user. To set different permissions or ownership for specific files and/or folders, use the file_permissions
associative array in profiledef.sh
.
Custom files can be added inside the ISO in two ways: by making a remote or local repository or putting them directly inside the airootfs
tree.
Summarizing, we can modify directly the files inside airootfs
directory that corresponds to our future system root, and we can add packages we would like to install on our Athena OS by specifying them inside athena-iso/archlive/packages.x86_64
file. Furthermore, if some of our files in airootfs
need particular permissions, we can add them inside athena-iso/archlive/profiledef.sh
file.
About systemd services, for enabling them after the installation, you can already insert them in the ISO in this way:
sudo rm -rf $ARCHLIVE/airootfs/etc/systemd/system/multi-user.target.wants/NetworkManager.service
sudo rm -rf $ARCHLIVE/airootfs/etc/systemd/system/systemd-timesyncd.service
sudo rm -rf $ARCHLIVE/airootfs/etc/systemd/system/display-manager.service
sudo ln -s /usr/lib/systemd/system/NetworkManager.service $ARCHLIVE/airootfs/etc/systemd/system/multi-user.target.wants/NetworkManager.service
sudo ln -s /usr/lib/systemd/system/systemd-timesyncd.service $ARCHLIVE/airootfs/etc/systemd/system/systemd-timesyncd.service
sudo ln -s /usr/lib/systemd/system/gdm.service $ARCHLIVE/airootfs/etc/systemd/system/display-manager.service
sudo ln -s /usr/lib/systemd/system/multi-user.target.wants/vboxservice.service $ARCHLIVE/airootfs/etc/systemd/system/vboxservice.service
sudo ln -s /usr/lib/systemd/system/multi-user.target.wants/vmtoolsd.service $ARCHLIVE/airootfs/etc/systemd/system/vmtoolsd.service
sudo ln -s /usr/lib/systemd/system/multi-user.target.wants/vmware-vmblock-fuse.service $ARCHLIVE/airootfs/etc/systemd/system/vmware-vmblock-fuse.service
Another important topic is related to Users and Groups as specified in https://wiki.archlinux.org/title/archiso#Installation
Note that in the guide, in etc/passwd
, /bin/zsh
is used as shell, and if ZSH is not installed because the user wants to use another shell, for example BASH, change it to /bin/bash
or other shells will be installed in the ISO, otherwise the user will get authentication failure. etc/passwd
must be like:
root:x:0:0:root:/root:/bin/bash
liveuser:x:1000:1000::/home/liveuser:/usr/bin/bash
On the ISO, if we are using GDM as Display Manager, for autologin it is important to create /path/to/airootfs/etc/gdm/custom.conf
file with the following content:
[daemon]
AutomaticLoginEnable=True
AutomaticLogin=liveuser
where liveuser
is our Live User account. For removing automatically that line after the installation of the target system (because the liveuser won't exist anymore), the command sed -i '/^AutomaticLogin=liveuser/d' /etc/gdm/custom.conf
has been implemented inside of shellprocess-before.conf
that will be executed by Calamares Installer.
Furthermore, there will be aspects the user wants to be run at the first login after the system installation. For example, since dconf
command cannot be run in chrooted environment, the user can create a run-once.sh
script placed in airootfs/etc/profile.d
folder. Then, give root executable permission on archiso/profiledef.sh
file.
In archiso/profiledef.sh
file important variables are defined, as iso_label
that defines the %ARCHISO_LABEL%
used in archiso/grub/grub.cfg
(UEFI mode) and archiso/syslinux/archiso_pxe-linux.cfg
and archiso/syslinux/archiso_sys-linux.cfg
files (BIOS/Legacy mode). In Athena the iso_label
is always defined by iso_label="ATHENA-OS"
string (Linux environment is case-sensitive) in order to be compliant with both ISO-9660 and FAT32 requirements (label shorter than 11 characters). Being compliant with FAT32 requirements will allow USB burning software as Rufus to work properly when burning the ISO and boot Athena by USB on the computer. Remember that RUFUS will convert labels as uppercase, for this reason our iso_label
value should be an uppercase string. If we use a label longer than 11 characters, it could happen that the label assigned by Rufus (or similar tools), that will be cut in 11 characters, won't match the label defined in %ARCHISO_LABEL%
variable, so the GRUB won't be able to find the USB device and will return an error like "error: no device found".
The content of run-once.sh
checks two flag files in the home folder of the current user: one for running offline commands at first boot; the other one for running online commands at first boot. If these flag files exist, then execute the customized commands and delete these flag files. In this way, the user executes these commands only at the first boot of a user. In case the network connection is not available at the first boot, the network flag file is kept until the session is logged in by keeping an Internet connection.
Remember to set always the repositories you need in the host environment, as BlackArch and Chaotic repositories. In this way, you can directly install keyrings and mirrorlist on the ISO by inserting in package.x86_64
the following packages: blackarch-keyring
, blackarch-mirrorlist
, chaotic-keyring
and chaotic-mirrorlist
.
When we finished to set everything, we can type mkarchiso ~/athena-iso/archlive
for making our ISO. This process will create the work
directory that contains all the temporary files needed for making our ISO, and out
directory that will contain our final ISO file.
At the end of the ISO creation, execute sudo pacman -Scc
in order to clean /var/cache/pkg
folder. Do the same process also on the target machine when the installation of the operating system ends.
All the third-party tools and environment customization manually implemented in the Direct Approach are automatically implemented in the ISO Approach.
The content of airootfs
and the other files mentioned here are stored in https://github.com/Athena-OS/athena-iso repository, so feel free to give a look on how they are built.