Skip Navigation

Assignment 9: Prepare to Install a GUI

For this assignment, you will perform preliminary steps for setting up a Graphical User Interface (GUI) on your Alpine Linux installation. These steps include installing documentation and useful tools, configuring system services that the GUI environment will need, and installing fonts.

Page Contents

Background

In our previous assignments, we’ve slowly but steadily set up various pieces of command line software in our Alpine Linux environment. On server systems, we normally only use the command line. However, most people these days like to have something a bit more graphical on their desktop systems. Over the course of this assignment and the next assignment, we’ll be setting up the part of the software stack that enables a graphical desktop (and installing a few other useful utilities along the way).

A Few Useful Things

Before we get too deep into the part of the software stack that directly supports our future desktop environment, there are still a few additional useful things applicable to both the command line and a graphical environment. Among the first of these things is to install some documentation, which provides helpful tools such as the man command for looking up help pages for system commands. For example, once the manual pages are installed, help for the apk command can be obtained by running:

man apk

In general, it is true that we can access manual pages on the Internet through a browser, as search engines will tend to find them. However, looking for manual pages this way may result in irrelevant results due to other uses of the word “man” in English. For example, I don’t recommend trying to find the man page for the man command itself in a search engine with Safe Search turned off.

Other useful things include the lspci and lsusb commands. These commands actually help us figure out what kind of hardware is attached to the system, which is useful when trying to figure out which graphics driver we need to configure, what kind of network card we have, etc. On the Raspberry Pi, most of these devices are well-known, since the Pi only comes configured with one set of hardware. However, it’s important to know about these commands for situations when you’re trying to use Linux on unknown hardware, such as a laptop you buy secondhand or literally anything you buy from Dell.

Another thing we need to install is a set of locale files for the musl C library, which will give us proper display of things like times and dates in our graphical programs. We’ll also install Lynx, which is a text mode Web browser that is functional enough to find documentation in a pinch. Our default installation of Alpine Linux already has a cron daemon for running scheduled tasks, but we need to turn it on before we start our desktop environment.

D-Bus

Technically, we already installed D-Bus when we installed NetworkManager in a previous assignment, since D-Bus is a dependency of NetworkManager. D-Bus is a message system that enables different programs to communicate with one another. On Linux systems, quite a few system services (including NetworkManager) listen on a D-Bus connection to receive messages from other programs. This connection is actually how the nmtui program communicates with the NetworkManager service to activate or deactivate a wireless connection, configure a new connection, and so forth.

While D-Bus has its criticisms, it is far smaller and less of a security concern than systemd. Its main fault is probably design by committee, as a result of which it can be cumbersome for developers to utilize. However, from the user and system administrator perspectives, it tends not to cause too many issues. The main concerns are that the system message bus (for systemwide services) gets started at boot time and that the session message bus (for each individual user) is started before starting a desktop environment that relies on it. We’ll take care of the first thing in this assignment and leave the session bus for the next assignment.

Seat Management

You’re probably aware that Linux systems use Discretionary Access Controls (DAC) that determine what a user can do based on things like file permissions, file ownership, and whether or not the user is the root user. Some of the things we need to do on a desktop system involve directly talking to the hardware. For example, rendering your screen to an output display requires sending data to the graphics card. In the case of the Linux console (the command line interface), it’s pretty easy to send data to the graphics card without needing direct access to the video memory or low-level graphics components, since we’re just sending a stream of text. Things change when we want to use high performance 3D graphics.

Of course, we could just give desktop users direct access to the video card. In fact, we did exactly that in a previous assignment when we added your regular user account to the “video” group. On a home desktop computer with only one human user, this approach is fine, since that user probably also has the root password and is the system administrator. However, Linux systems are fundamentally designed to support multiple users. Think of a shared workstation in an office. One user might be sitting at the keyboard, while another user could be logged into the same system over a Secure Shell (SSH) or other kind of remote connection. It makes sense for the user sitting at the keyboard to be able to send stuff directly to the graphics card. However, the user logged in remotely isn’t looking directly at the monitor attached to the computer anyway, so why do they need that permission? If their account gets hacked remotely, we really don’t want to give an attacker direct access to the hardware.

The standard solution to this problem is to use a seat manager, which is a layer of software that allows users to access hardware devices based on conditional rules. Instead of trying to speak to hardware devices directly, software applications that can use a seat manager instead send their data to the seat manager, which uses rules to determine whether or not the user running that program can send data to the requested hardware. There are two main seat managers in existence: logind, which is – surprise, surprise – part of systemd, and seatd. Of the two, seatd has the smaller code size and the smaller attack surface. Unfortunately, the big desktop environments (GNOME and KDE) have chosen to rely on logind. As a consequence, some developers have split the logind code out of systemd and have created Elogind, which is what we have available in Alpine Linux.

Elogind uses a separate component, officially called polkit but still often called its original name PolicyKit, for determining the rules governing access by different users. Users who are sitting at the physical seat (the keyboard plugged directly into the system) typically get more access than users who are logged into the system remotely.

PAM

On our system, we log in using a user name and a password. The user name and user information is stored in the /etc/passwd file, which is world-readable, while the hash of the password goes in the /etc/shadow file and is readable only by the root user. Out of the box, Alpine Linux uses BusyBox to manage its login process, and this version of BusyBox simply hashes the password you type at the login prompt, compares the hash to the /etc/shadow file, and then lets you log in if they match. Technically, the way this process works is that your login information is sent to the /bin/login command, which runs as root and checks that your hashed password matches the stored hash. If it matches, then the login program forks, or creates a copy of itself. After forking, the copy changes its running privileges to your user account, performs a few other cleanup tasks, and replaces itself with (or execs) your login shell set in /etc/passwd. We set our login shell to /bin/zsh.

This approach works quite well whenever user account information is stored locally in these two files. But, what happens if we want to have centralized user accounts using something like Microsoft Active Directory, which implements the Kerberos authentication mechanism and uses a Lightweight Directory Access Protocol (LDAP) server to get account information? Well, we have two choices. Either we need a login program that can also handle Kerberos+LDAP and fall back to the local files if the account isn’t found in the centralized server, or we need to add another software layer to do these sorts of operations for us.

Pluggable Authentication Modules (PAM) provide this layer. Instead of trying to figure out how to write a login program that can handle each and every different way of managing user accounts that someone might invent, PAM can centralize some of the common parts of this code and let plugins handle the details. PAM also provides mechanisms to set some security limits at login time, which makes it the favored approach when using seat management. PAM is optional on Alpine Linux, but we need to enable it on our system as part of our graphical desktop preparation.

Sound

In the prior section about seat management, I mentioned the video card is one of the devices that we need to access. The sound card is another one of these devices, and it’s a little bit trickier than the video card. Normally, we only have one process – either X11 or a Wayland compositor (which we’ll discuss in the next assignment) – that accesses the video card. However, multiple programs often want to play sound at the same time. At a low level, the sound card is just taking in a stream of bits and making noises based on that stream. If we throw a bunch of different bit streams at it, we would wind up with static if more than one program tries to play sound at once.

Thus, we first need to mix all our sounds together, which is the function of the mixer component. The Advanced Linux Sound Architecture (ALSA) system built into the Linux kernel has a mixer, but it has some serious limitations. Among these is that it is difficult to route audio to and from different devices. For example, if you’re using your desktop speakers but want to switch to a Bluetooth headset, changing the sound routing and mixing at the kernel level is quite tedious. In addition, keeping sound synchronized with video playback is yet another challenge.

For these reasons, we normally add a software layer to make managing our sound system a bit easier. Pipewire and its companion session and policy manager WirePlumber are the current recommendations. PipeWire replaces an older system called PulseAudio that was originally developed by the same person who created systemd. Although someone else took it over and rewrote a lot of the code (which was considered a mess at the time), it was still limited by original design decisions. PipeWire changed some of these decisions and added a compatibility layer for applications that expect a PulseAudio interface.

Bluetooth

You probably have one or more Bluetooth devices lying around, and the Raspberry Pi 5 includes a Bluetooth adapter on its board. Bluetooth is actually a stack of network protocols for wireless communication between devices, with a focus on Personal Area Networks (PANs), or short-range communication. On Linux, these protocols are split between kernel drivers and some userspace components provided by the BlueZ layer. We need to install this layer to be able to connect Bluetooth devices to the Pi.

Fonts

Our final task in preparing for a graphical environment will be to install some fonts. A good selection of system fonts makes graphical desktop environments and documents look better. Many of the fonts that you use on Windows are copyrighted and are not free to distribute. Therefore, we need to select some fonts that are freely available to install on our system.

Procedure

This section is structured as a tutorial. Please read slowly and carefully enter commands.

Step 0. Read the Background Section

If you skipped down to this point, go read the Background section above, and also read the pages linked from the background material. It’s important to understand why we’re making the choices we’re making in this assignment.

Step 1: Update the System

Log into your Pi as your regular user (not root). Update all the system packages first, since we’re going to be installing additional packages. The commands to update are:

doas apk update
doas apk upgrade

If you see the linux-rpi5-teal package get upgraded, then you also need to reboot onto the new kernel.

In the event that you get any errors at this step, run the nmtui command to troubleshoot your network connection. If you’re using a wired connection, be sure you plugged in the network cable.

Step 2: Install Documentation and Locale Data

Out of the box, a fresh installation of Alpine Linux keeps its disk/storage utilization down by leaving out all the documentation. It is often helpful to have a local copy of manual (man) pages available, along with local copies of documentation, whenever the space is available. Since we have plenty of space on our 64 GB MicroSD card, let’s go ahead and add these:

doas apk add mandoc mandoc-apropos docs musl-locales

We also added the musl-locales package, which provides both internationalization (i18n) and localization (l10n) support. We’ll need this package later in KDE Plasma to get time, date, and number formats localized to the United States, so we went ahead and added it now.

Step 3: Install PCI and USB Tools

Since the Raspberry Pi 5 has a PCIe interface available (if you get the additional hardware for it) plus 4 ready-to-use USB ports, let’s get some tools to make working with PCIe and USB devices easier:

doas apk add pciutils usbutils

These packages include both the lspci and lsusb commands, which allow you to see what devices are connected to the various buses on the Pi. Give them a test drive:

lspci
lsusb

You should see that the Raspberry Pi 5 has a PCIe bridge chip, and that its wired Ethernet controller is connected via PCIe. On the USB side, you should see the USB host controller, your keyboard, mouse, and anything else you have plugged into the USB ports.

Step 4: Start and Enable cron

The cron service allows periodic commands to be scheduled to run automatically. It’s disabled by default on Alpine Linux, but KDE Plasma has an interface to allow it to be configured graphically. That interface doesn’t report whether or not the cron daemon is actually running, so it could create an opportunity for a frustrating debug process later if we don’t enable it. Let’s go ahead and get it started and enabled:

doas rc-service crond start
doas rc-update add crond

Step 5: Install Lynx

For our class, we’ve relied on having a second computer or device available for reading the instructions while we work. In some situations (albeit rare ones these days, like working in a classified environment), the system under installation might be the only one you have. For this reason, it’s helpful to have a text mode Web browser on hand. Install Lynx as follows:

doas apk add lynx

Now let’s test Lynx by running:

lynx ww2.coastal.edu/mmurphy2

You should see my website appear, albeit in text mode. To use this browser, keep in mind that the left arrow key is the “back” button, while the right arrow key (or the Enter key) selects links. Navigate the page by moving up and down. Let’s navigate to this instruction page:

  1. Use the down arrow to pick Courses under Teaching.
  2. Use the right arrow key or the Enter key to go to my Courses page.
  3. Use the down arrow key to go down to the FIRST CSCI 311 entry (the one for THIS semester). Activate the link with the right arrow or Enter key.
  4. Navigate down to this assignment (Assignment 9).
  5. Press the down arrow key once to pick the Skip Navigation link, then activate it to drop down to the top of the assignment. Do you see why a “Skip Navigation” link that you might have learned about in CSCI 120 and/or may see in CSCI 303 is a good idea when making websites?
  6. Use the Page Contents to navigate to this step (Step 5).
  7. Read this sentence. Freaky, huh?

To exit Lynx, press the Q key. A confirmation message will appear in the blue status line at the bottom. Press the Y key to confirm.

Step 6: Install D-Bus

Note that the dbus package has already been installed and started by NetworkManager. For practice, let’s go ahead and be sure that both dbus and the dbus-x11 package (which contains a useful run script) are installed. We’ll also practice starting the service, and we’ll explicitly enable it.

doas apk add dbus dbus-x11
doas rc-service dbus start
doas rc-update add dbus

Note that you SHOULD see a warning that dbus has already been started when starting the service. NetworkManager already started it for us.

Step 7: Add Elogind and Polkit

Our future graphical environment depends upon both Elogind and PolicyKit to work properly. Let’s get those installed, started, and set to start at boot time:

doas apk add elogind polkit-elogind
doas rc-service elogind start
doas rc-service polkit start
doas rc-update add elogind
doas rc-update add polkit

Step 8: Enable PAM

To get seat management working properly with our future graphical environment, we need to switch to use a PAM login. Two packages are needed on Alpine Linux: one of these packages contains PAM itself, while the other one replaces the /bin/login command provided by BusyBox with the one from util-linux. The BusyBox login command doesn’t work with PAM, which is why we have to replace it. Run:

doas apk add linux-pam util-linux-login

Step 9: Install Pipewire

Any good graphical environment also needs to be able to support sound. These days, the recommended solution in Linux is to use the PipeWire engine. Let’s also add support for applications that expect PulseAudio, Jack Audio Connection Kit, or an old-school Advanced Linux Sound Architecture (ALSA) interface:

doas apk add pipewire wireplumber pipewire-pulse pipewire-jack pipewire-alsa

Step 10: Enable Bluetooth

Since our Raspberry Pi 5 supports Bluetooth, we might as well add the packages that enable us to use it. Also go ahead and add the PipeWire interface that allows us to use wireless headphones and headsets that speak the Bluetooth protocol. Run:

doas apk add bluez bluez-openrc pipewire-spa-bluez
doas rc-service bluetooth start
doas rc-update add bluetooth

Step 11: Install Fonts

Our penultimate step in getting ready for a graphical environment is to install some fonts. These packages will provide a decent selection:

doas apk add font-inconsolata font-dejavu font-noto font-noto-cjk
doas apk add font-awesome font-noto-extra font-croscore font-liberation

Step 12: Reboot

To get PAM and seat management working properly, the easiest and quickest thing to do is simply to reboot the system:

doas reboot

Submission Checklist

Once your Pi reboots, log in as your regular user and run the following commands:

hostname
date
PAGER= loginctl
which man
lspci
lsusb

Note that we’re reusing the trick of setting PAGER to an empty value when running the loginctl command. Otherwise, it would clobber the output of the other commands.

How to Check Your Work

To verify that you have everything working properly, look at the output of the above commands:

  1. Be sure that your CCU username is part of your hostname.
  2. Be sure that the date shows a time during the period for this assignment this semester.
  3. Be sure that your loginctl output shows a session. Since your account is the only user, the expected output would have a session named c1 on seat0 and tty1. If you get a message saying that there are no sessions, then elogind isn’t working properly. Did you remember to reboot in the last step? If so, then something went wrong with your setup. If not, rebooting should fix it.
  4. The output of which man should be /usr/bin/man, indicating that the man program is installed.
  5. Your lspci output should show the Raspberry Pi’s PCIe bridge and the Ethernet controller on its South Bridge. If you’re running your own Pi and added any PCIe devices (such as an SSD), those should show up here as well.
  6. Your lsusb output should show the host controllers, keyboard, and anything else you’ve plugged into the USB ports.

Final Steps

Use your phone to take a picture of the screen. Upload the picture to Moodle as the submission for this assignment.

ABET Assessment

Successful completion of this assignment satisfies the following performance indicator: