CS 326 Operating Systems

Raspberry Pi Setup

We’ll be using Arch Linux ARM (ALARM) in CS 326. Arch Linux is a simple distribution that gives us the opportunity to configure our Raspberry Pi exactly as we want. The Arch Linux Wiki has a wealth of information on configuring the system, swapping out components, and installing a wide variety of software. You may be wondering, “why not just use the existing OS I installed for another class?”, which is a great question. Since this is an OS class, we’ll be going much more in-depth with configuring and setting up the OS.

In this lab, you’ll learn:

Mac/Linux

Download the CS 326 Arch Linux ARM Disk Image to get started. Once this is downloaded, check to determine whether your browser automatically unzipped the file (if it did, the extension will just be .img; if not, then the extension is .img.gz). If your browser decides to automatically unzip the file, it will take some time.

Take note of where you downloaded the file. In the examples below, we’ll assume the file is in ~/Desktop.

Once you have the disk image, go ahead and insert your SD card into your computer and follow the directions below based on your operating system.

Mac

# Unzip the file (only if necessary)
gunzip ~/Desktop/alarm-cs326-fa18.img.gz

# Determine the device (on macOS) ----------------------------------------------
$ diskutil list
/dev/disk0 (internal):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                         500.3 GB   disk0
   1:                        EFI EFI                     314.6 MB   disk0s1
   2:                 Apple_APFS Container disk1         500.0 GB   disk0s2

/dev/disk1 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +500.0 GB   disk1
                                 Physical Store disk0s2
   1:                APFS Volume Macintosh HD            244.0 GB   disk1s1
   2:                APFS Volume Preboot                 21.2 MB    disk1s2
   3:                APFS Volume Recovery                506.6 MB   disk1s3
   4:                APFS Volume VM                      2.1 GB     disk1s4

/dev/disk2 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *31.9 GB    disk2
   1:             Windows_FAT_32 NO NAME                 104.9 MB   disk2s1
   2:                      Linux                         31.8 GB    disk2s2

# We want /dev/disk2 (will generally be the last disk, external, and have a size
# around your SD card's labeled size)

# Unmount the disk:
$ diskutil unmountDisk /dev/disk2

# Copy the disk image to the SD card (macOS):
$ sudo dd if=~/Desktop/alarm-cs326-fa18.img of=/dev/disk2 bs=1m
# (Press Ctrl+T to view progress info, it looks something like this):
# load: 1.59  cmd: dd 7487 running 0.00u 1.11s
# 176+0 records in
# 175+0 records out
# 175000000 bytes transferred in 16.679058 secs (10492199 bytes/sec)

# Unmount the disk again:
$ diskutil unmountDisk /dev/disk2

Once this is finished, you can insert the SD card into your Pi and head on down to Connecting via Serial Console.

Linux

# Unzip the file (only if necessary)
gunzip ~/Desktop/alarm-cs326-fa18.img.gz

# Determine the device
$ sudo fdisk -l
Disk /dev/sda: 64 GiB, 68719476736 bytes, 134217728 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x7758973f

Device     Boot     Start       End   Sectors  Size Id Type
/dev/sda1  *         2048 132120575 132118528   63G 83 Linux
/dev/sda2       132122622 134215679   2093058 1022M  5 Extended
/dev/sda5       132122624 134215679   2093056 1022M 82 Linux swap / Solaris

Partition 2 does not start on physical sector boundary.

Disk /dev/sdb: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x7d4b0f25

Device     Boot  Start      End  Sectors  Size Id Type
/dev/sdb1         2048   206847   204800  100M  c W95 FAT32 (LBA)
/dev/sdb2       206848 62333951 62127104 29.6G 83 Linux

# Here, we want /dev/sdb (note the similar size to my SD card)

# Unmount the disk -- note the * after device name:
$ umount /dev/sdb*

# Copy the disk image to the SD card:
$ sudo dd if=~/Desktop/alarm-cs326-fa18.img of=/dev/sdb bs=1M status=progress
# You'll see a progress display like:
# 98566144 bytes (99 MB, 94 MiB) copied, 8 s, 12.3 MB/s

# If your OS automatically detected the new filesystem(s) and mounted them, we
# need to unmount again. Both macOS and Ubuntu do this.

# Unmount the disk again -- note the * after device name:
$ umount /dev/sdb*

Once this is finished, you can insert the SD card into your Pi and head on down to Connecting via Serial Console.

Windows

As usual, Windows users have to do a bit more work to get up to speed (sorry…). To start out, install Cygwin. This will give you a UNIX-like environment on Windows. When installing Cygwin, the default set of packages are okay (in other words, hit ‘next’ until it’s done installing!)

Once Cygwin is installed, run the Cygwin terminal as Administrator (Right click, Run as Administrator). Download the CS 326 Arch Linux ARM Disk Image. You’re ready to go now.

# First, let's find out what drive our SD card is mapped to.
$ cat /proc/partitions
major minor  #blocks  name   win-mounts

    8     0 134217728 sda
    8     1    307200 sda1
    8     2    102400 sda2
    8     3    131072 sda3
    8     4 133675008 sda4   C:\
    8    16  31166976 sdb
    8    17  31162880 sdb1   F:\

# In this case, F:\ is my SD card, so I will write the disk image to sdb.
gunzip /cygdrive/c/users/matthew/desktop/alarm-cs326-fa18.img.gz
dd if=/cygdrive/c/users/matthew/desktop/alarm-cs326-fa18.img of=/dev/sdb bs=1024

After completing this step, exit cygwin and eject the disk using Windows explorer. You’ll notice that a small, 100 MB partition was mounted. This partition is the /boot partition on our Linux installation, and since it is formatted with the FAT file system Windows can read and mount it. On the other hand, the root partition / is ext4 format, which Windows can’t read natively, so you won’t see it in Explorer.

Go ahead and remove the SD card, and carry on…

Alternatives

Students have had success writing the disk image with Etcher instead of using dd from the terminal. This might be a good choice if you’re running into problems, especially on Windows.

Connecting via Serial Console

Insert your SD card into the Raspberry Pi, (don’t turn it on yet!) and install the drivers for the serial cable:

Note: you may need to restart your computer after installing the drivers.

Then connect the leads like so:

Don’t connect the red wire!

Once the drivers are installed and the cable is connected, you can launch the screen program to connect to the console, or use PuTTY on Windows.

# macOS
screen /dev/cu.usbserial 115200

# Linux
screen /dev/ttyUSB0 115200

Once this step is done, turn on your Pi and wait for text to begin scrolling (it may take up to 15 seconds to appear). If nothing appears, try hitting the enter key.

If you are unsure what device you should pass to screen, there are several commands you can use to find out. One of my favorite options is dmesg, which prints the kernel message buffer on UNIX machines. On Linux, you can also use lsusb or lsblk. Or, as Adafruit mentions, you can just view the devices in /dev and try them.

Troubleshooting: Unfortunately, getting the serial console to work can be buggy. Students have had to power cycle the Pi a few times to get it working, unplugged+replugged the serial cable, and rebooted their machines. You should also check to make sure your Pi is getting enough power; some laptops don’t provide enough power to run the Pi so it simply won’t boot. A good test is to try another student’s machine, or connect an HDMI monitor to see if anything displays.

The serial cables’ quality is often not great. Try a friend’s cable if yours refuses to work.

Resizing the Root Partition

When the Arch Linux image was created for class, it was set up with a 2 GB partition just to make sure it would fit on everybody’s SD cards. We’d probably like to use all the space we have, so let’s resize the root partition.

We’re about to modify the partition table of a running system and resize a file system on the fly, so buckle your seatbelts. For the rest of this lab, we’ll assume you are logged in as the root user (administrator). In general, this is a better approach than just prefixing everything with sudo, which doesn’t even come installed by default on Arch Linux.

# First log in as root (password is root)

# Let's see what filesystems are mounted
$ df
Filesystem      Size  Used Avail Use% Mounted on
dev             462M     0  462M   0% /dev
run             469M  312K  468M   1% /run
/dev/mmcblk0p2   30G  1.1G   27G   4% /
tmpfs           469M     0  469M   0% /dev/shm
tmpfs           469M     0  469M   0% /sys/fs/cgroup
tmpfs           469M     0  469M   0% /tmp
/dev/mmcblk0p1  100M   25M   76M  25% /boot
tmpfs            94M     0   94M   0% /run/user/1001

# We need to resize our root partition ('/'). The device name here is mmcblk0,
# with partitions p1 and p2 mounted at /boot and /, respectively.
# We will run fdisk on the *device*:
$ fdisk /dev/mmcblk0

# Enter the 'p' command to print the partition table
Command (m for help): p
Disk /dev/mmcblk0: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x7d4b0f25

Device         Boot  Start     End Sectors  Size Id Type
/dev/mmcblk0p1        2048  206847  204800  100M  c W95 FAT32 (LBA)
/dev/mmcblk0p2      206848 4401151 4194304    2G 83 Linux

# I have a 32 GB card, so we're wasting a ton of valuable space! Ok, we will 
# delete the root partition and then put a new one in its place at exactly the
# same offset. If it sounds crazy, that's because it is! Here we go:
Command (m for help): d
Partition number (1,2, default 2): 2

Partition 2 has been deleted.

# Let's create the new partition ('n' command). We'll create a primary
# partition, and we can use the default values for the offsets (just press
# enter). Don't remove the ext4 signature.
Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 2
First sector (206848-62333951, default 206848):
Last sector, +sectors or +size{K,M,G,T,P} (206848-62333951, default 62333951):

Created a new partition 2 of type 'Linux' and of size 29.6 GiB.
Partition #2 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: n

# Print the new partition table:
Command (m for help): p

Disk /dev/mmcblk0: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x7d4b0f25

Device         Boot  Start      End  Sectors  Size Id Type
/dev/mmcblk0p1        2048   206847   204800  100M  c W95 FAT32 (LBA)
/dev/mmcblk0p2      206848 62333951 62127104 29.6G 83 Linux

# And finally, write the changes ('w' command).
Command (m for help): w
The partition table has been altered.
Syncing disks.

# Now we can resize the file system with resize2fs. Here we should give the
# partition name (p2), not just the device name:
$ resize2fs /dev/mmcblk0p2
resize2fs 1.43.7 (16-Oct-2017)
EXT4-fs (mmcblk0p2): resizing filesystem from 524288 to 7765888 blocks
The filesystem on /dev/mmcblk0p2 is now 7765888 (4k) blocks long.

# We should power cycle the Pi to make sure our changes worked.
shutdown -r now

Turn the Pi off and back on again. Your serial connection should show the Pi booting back up! Let’s take a look at our mounted file systems now:

$ df -H
Filesystem      Size  Used Avail Use% Mounted on
dev             484M     0  484M   0% /dev
run             491M  304k  491M   1% /run
/dev/mmcblk0p2   32G  806M   30G   3% /
tmpfs           491M     0  491M   0% /dev/shm
tmpfs           491M     0  491M   0% /sys/fs/cgroup
tmpfs           491M     0  491M   0% /tmp
/dev/mmcblk0p1  105M   26M   79M  25% /boot
tmpfs            99M     0   99M   0% /run/user/0

Great, we have a 32G file system (hopefully it’ll be around the size of your SD card. Mine is ~32 GB). We’re ready to get started with Linux!

Basic Configuration

# The default user on Arch Linux ARM is 'alarm,' so let's create our own user
# account with the useradd command. The -m flag creates a home directory for
# the user (/home/mmalensek in this case).
$ useradd -m mmalensek

# Set the password for our new user
$ passwd mmalensek

# We can now remove the alarm user. This is important, otherwise anybody can
# just log into your Pi. The -r flag deletes the user's home directory.
$ userdel -r alarm
userdel: alarm mail spool (/var/spool/mail/alarm) not found
# (Getting the warning above is fine)

# Let's test out the account. Since we're root, we can actually use the
# substitute user (su) command to switch over:
$ su - mmalensek
[mmalensek@alarm ~]$

# Great, it worked. Let's switch back to root.
$ exit

# Finally, you should set a root password. Root logins aren't allowed over SSH
# in the default configuration, but let's do it just to be safe:
$ passwd
# (in this case, not entering a username tells passwd to change the current
# user's password)

Network Configuration

# Generate a hashed password file for the CSLabs network:
$ wpa_passphrase CSLabs 1kudlick > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf

# Start WPA supplicant to initialize the wireless interface and associate with
# the network. Also start dhcpcd so the system will get an IP address from the
# CS DHCP server. The '@wlan0' tells WPA supplicant to use interface wlan0.
$ systemctl start wpa_supplicant@wlan0 dhcpcd

# Test to determine if we got an IP address
$ ip addr show wlan0
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
    link/ether b8:27:eb:75:b6:88 brd ff:ff:ff:ff:ff:ff
    inet 10.10.34.107/23 brd 10.10.35.255 scope global wlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::d9be:15bb:f9fd:8cfd/64 scope link 
       valid_lft forever preferred_lft forever
# In this case, I was assigned the IP 10.10.34.107

# ping a website to make sure DNS is working correctly (ctrl+C to stop)
$ ping google.com
PING google.com (172.217.5.110) 56(84) bytes of data.
64 bytes from sfo03s07-in-f110.1e100.net (172.217.5.110): icmp_seq=1 ttl=57
64 bytes from sfo03s07-in-f110.1e100.net (172.217.5.110): icmp_seq=2 ttl=57
^C

# If the above worked, enable wireless configuration and DHCP on bootup:
$ systemctl enable wpa_supplicant@wlan0 dhcpcd

# Let's give this Pi a hostname. You can go with something interesting,
# or if you can't think of anything you can be boring like me and use
# 'username-pi' (e.g., mmalensek-pi)
$ hostnamectl set-hostname magical-unicorn
$ hostnamectl
   Static hostname: magical-unicorn
         Icon name: computer
        Machine ID: 692b976ee401499b972528b814715e4d
           Boot ID: 836a9aeae8414fb4ab9a130d0feb9db6
  Operating System: Arch Linux ARM
            Kernel: Linux 4.18.0-1-ARCH
      Architecture: arm

# We should reboot the Pi to make sure our config worked. It should
# automatically get on the CSLabs network.
$ shutdown -r now

You may also want to add other networks to your Pi so you can connect at home. To do this, follow the same steps above but append (>>) the network information to your config file:

# Add another network. NOTE: you must append to the file with >>, otherwise
# the CSLabs setup will be overwritten!
# First, we will add an extra blank line to the file:
$ echo >> /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
# Next, add the password:
$ wpa_passphrase MatthewsWiFi super-secret-password >> \
    /etc/wpa_supplicant/wpa_supplicant-wlan0.conf

# Note: in your shell, the \ indicates a 'command continuation'
# (Multi-line command). The shell will interpret it as one big line.

# Edit the file to remove the comment with your plain text password,
# and check to make sure everything's formatted correctly:
$ vi /etc/wpa_supplicant/wpa_supplicant-wlan0.conf

Installing Software

# First, we need to update the package keyring:
$ pacman-key --init
$ pacman-key --populate archlinuxarm

# With that finished, our first order of business is getting our OS up to date.
# Arch uses a package manager called pacman:
pacman -Syu

# To search for packages use -Ss:
pacman -Ss some-package-name

# To install packages:
pacman -S vim

# Later on, the package database may be outdated. You can update with a usual
# 'pacman -Syu' as shown above, but if you just want to install one package use:
pacman -Sy vim

Making our Pi Discoverable: mDNS

$ pacman -S avahi nss-mdns

# Edit the nsswitch configuration to add 'mdns_minimal [NOTFOUND=return]'
# before the 'resolve' directive:
$ vi /etc/nsswitch.conf
hosts: files mymachines mdns_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname

# Let's start avahi:
$ systemctl start dbus
$ systemctl start avahi-daemon
# If this fails, try restarting dbus with systemctl restart, then try again.

# Enable the two services at boot:
$ systemctl enable dbus avahi-daemon

With this complete, you should now be able to reach your Pi via ssh and its hostname + ‘.local’ from your laptop (assuming you are on CSLabs WiFi). You can also use the serial cable to ascertain your IP address. In general, the Pi will try to re-use the last IP address it had.

$ ping -c4 yourpi.local
$ ssh username@yourpi.local
$ ssh username@10.10.34.107

Can’t reach your Pi? Make sure you are on CSLabs, not USF Wireless. (Check what WiFi network you’re connected to!)

Windows Users: Some versions of Windows do not come with support for resolving zeroconf addresses. Here’s some tips for getting this to work. The short version is: install Apple iTunes (yeah, seriously…) and you should be set.

Connectivity

In this setup, the Pi will work both on wired and wireless networks. You can ssh to your Pi via its hostname we set up above followed by .local (e.g., ‘yourpi.local’):

$ ssh username@hostname.local

One thing to note is that when 30+ students all connect to the same wireless access point with their Pi and laptop, you might experience some congestion. In this case, it may be better to use a USB to Ethernet adapter with your Pi and then share your laptop connection with it. As an added benefit, you won’t experience any lag over the ssh connection. On macOS, this is as simple as enabling connection sharing on your USB Ethernet adapter; for detailed instructions see:

Backing Up

Congratulations, you just configured and set up a Linux machine by hand. At this point, you’re almost ready for CS 326!

With the network setup, you can connect to WiFi or via Ethernet, ssh into your Pi, and you’re ready to go. So at this point, you only really need a power supply (and you can always use your serial cable to debug if the system doesn’t connect to the network for some reason).

An optional final step once you have your OS configured as you like is to make a backup of the SD card. This works similarly to writing the disk image:

# First, find the device name. Then use dd and gzip to back up. Here we are
# reading the raw block device (SD card), outputting the data to stdout, piping
# the output through gzip, which redirects its output to a file.
sudo dd if=/dev/disk2 | gzip > ~/Desktop/arch-cs326-backup.img.gz

Administration Tips

Once this guide is complete, head over to the Administration Tips guide.