raspian-ua-netinst: jessie won’t boot after rpi-update?

Update: Raspbian now includes support for the Raspberry Pi 2; the linux-image-rpi2-rpfv metapackage installs the raspbian kernel for Raspberry Pi 2, and automatically creates an initramfs during installation.

TL;DR I learn that the linux kernel has never supported LABEL= or UUID= root devices, it was being done by initramfs all along.

My Raspberry Pi 2 is on its way! :D

The plan is to use the microSD card from my old Model B, just drop in the new hardware. However, the Raspberry Pi 2 requires the latest firmware.

The current OS is raspian jessie, installed using raspian-ua-netinst. It’s just using the default kernel (linux-image-3.12-1-rpi), with the default firmware (raspberrypi-bootloader-nokernel), both installed using apt-get. However, this won’t suport the Raspberry Pi 2.

I need to install the latest firmware using rpi-update:

apt-get install rpi-update
rpi-update

All successful; no errors.

After rpi-update completes, the /boot folder now contains a second kernel, kernel7.img, which will be used by the Raspberry Pi 2. However, the Raspberry Pi 2 hasn’t arraived yet, so I keep using kernel.img for the current Raspberry Pi.

I update /boot/config.txt, set kernel=kernel.img and remove the initramfs entry (since rpi-update doesn’t make one).

All good, right? Time to reboot.

Nothing.

No disk activity on the root device (an external USB HDD, one of many attached to the system via a powered USB hub).

Hmm. I pop out the SD card and revert back to vmlinuz-3.12-1.rpi (and initramfs). Works fine. Hmm. I switch back to the new kernel.img. Won’t boot. Hmm.

I change root=UUID= to root=/dev/mmcblk0p2. Works fine. With the new kernel.

I change it back to root=/dev/sda1. It doesn’t boot, still no activity on the root device. However, there is some activity on one of the other USB devices. Progress!

I boot using /dev/sda1 again, but this time I remove all the other USB devices first. Success! It boots fine!

Ok, so root=/dev/sda1 works fine, but root=UUID= does not. I have a booting system, but I have to remove all USB devices every time I reboot. But what if I’m not onsite? Or what if there’s a power outage? I need to be able to reboot the box without physical access. So why doesn’t root=UUID= work?

Apparently, UUID and LABEL aren’t supported by the linux kernel. They never have, not on your kernel or mine.

But I’ve been using root=LABEL=/ for years!

The kernel doesn’t support it. The initramfs is what allows UUID and LABEL.

And that explains why the rpi-update kernel can’t find the root device: it doesn’t create an initramfs!

Easy fix

sudo update-initramfs -c -k 3.18.5+

And then set initramfs initrd.img-3.18.5+ in /boot/config.txt

The initramfs will need to be updated every time the kernel is updated. To be on the safe side, I’ve renamed kernel.img; if I forget to update-initramfs before rebooting, at least it’ll still boot.

Other options:

  • If you only have one external USB device, then root=/dev/sda1 will work fine—just make sure you unplug other USB storage before rebooting!
  • If you’re booting from a GPT disk, then you might be able to use root=PARTUUID= instead. (This is supported by the kernel—it’s needed for native UEFI boot).

OS X Recovery shenanigans: sshd, ramdisks, and screenshots

The Problem:

You want to take screenshots during the OS X recovery process.

The Solution:

The screencapture command can be used to create screenshots from the Terminal.

(To launch the Terminal: hover the cursor at the top edge to show the menu bar, then select Utilities → Terminal).

Type the following:

screencapture -W /path/to/screenshot.png

then click the window you want to capture.

But wait— the recovery environment allows only one app to run at a time. If you want screenshots of Terminal, then this method works great. However, if you want screenshots of something else, you’re out of luck.

Fortunately, the recovery partition includes sshd. It’s not running by default, but starting it is easy:

/usr/sbin/sshd -o UsePAM=no

(The absolute path is required; if you leave it out, then sshd bails out with an error).

OK, but the root account has a random password. And you can’t reset it, since the filesystem is read-only.

New problem:

You want to ssh into recovery, but you can’t set the root account password.

The solution:

Pubkey authentication!

First, create a writeable ramdisk:

rdsize=$((16*1024*1024/512)) # 16 megabytes
dev=`hdik -drivekey system-image=yes -nomount "ram://$rdsize"`
echo $?; echo $dev # check for errors!
newfs_hfs "$dev"
eval `/usr/bin/stat -s /var/root` # store perms for old mountponit
mount -t hfs -o union -o nobrowse "$dev" /var/root # magic happens here
chown "$st_uid:$st_gid" /var/root
chmod "$st_mode" /var/root

Next, add your key to /var/root/.ssh/authorized_keys.

mkdir /var/root/.ssh
cat /Volumes/THUMBDRIVE/id_rsa.pub > /var/root/.ssh/authorized_keys

You can now use your private key to authenticate to sshd.

Quit Terminal, and the ssh sessions will remain connected. You can now use the screencapture command at any time!

A few notes:

You can create screenshots in /var/root, but the ramdisk is only 16 megabytes. If this is too small, increase the rdsize before creating the ramdisk.

Of course, since this is a ramdisk, all modifications will be lost upon reboot. You might want to save the screenshots to a USB device instead. (Or scp/sftp, etc).

Your ssh key should be located on the client machine at ~/.ssh/id_rsa.pub. If it’s not there, it can be created using ssh-keygen. (You might also see a file called id_rsa—that’s the private key; do not copy it).

I’m sure you can think of many other uses for ramdisks. :)

Sources:

Raspberry Pi won’t boot? Try this.

In /boot/config.txt:

initial_turbo=180

This disables dynamic overclocking for the first 180 seconds after boot. This should help devices to boot from a poor‑quality power supply.

My rasberry pi recently stopped booting after a (successful!) firmware update.

This fixed it.

math_is_hard.c

#include <stdio.h>
int main()
{
        printf("0.57 * 100 = %d\n", 0.57 * 100);
        printf("Math is hard!\n");
        return 0;
}

sshd: fatal: Access denied for user foo by PAM account configuration [preauth]

Symptoms:

  • cannot log in over ssh as user foo (not even using publickey!)
  • a valid entry for foo exists in /etc/passwd
  • entries in /var/log/auth.log:

Oct 13 06:27:07 dl sshd[44354]: fatal: Access denied for user foo by PAM account configuration [preauth]

Solution:

  • Check /etc/shadow contains entries for the user in question.
  • Check syntax, too!

If an entry is missing, you can create a new one using the passwd utility.

Alternatively, if no password is required, create a dummy entry like this:

foo:!:15991:0:99999:7:::

For more info:

man 5 shadow

Bash error: value too great for base

Consider the following:

#!/bin/bash
month='08'

for m in $( seq 1 $(( ${month} - 1 )) ); do
    rm "backupfile-${m}.tar.bz2"
done

When run, it produces the following error:

$ /bin/bash ./test.sh
test.sh: line 6: 08: value too great for base (error token is "08")

According to man 1 bash:

Constants with a leading 0 are interpreted as octal numbers.

Solution 1: force the number to be interpreted as decimal:

#!/bin/bash
month='08'

for m in $( seq 1 $(( 10#${month} - 1 )) ); do
    rm "backupfile-${m}.tar.bz2"
done

Solution 2: strip the leading zero:

#!/bin/bash
month='08'

for m in $( seq 1 $(( ${month#0} - 1 )) ); do
    rm "backupfile-${m}.tar.bz2"
done

(or if there are multiple leading zeros:)

#!/bin/bash
month='08'

for m in $( seq 1 $(( $(echo "${month}" | sed 's/^0*//') - 1 )) ); do
    rm "backupfile-${m}.tar.bz2"
done

Source

More Netboot Shenanigans: Mac network boot without a netboot server

Sometimes you want to boot a Mac from the network without running a netboot server. You already have a TFTP server set up, and the root image is sitting on a HTTP server. The only missing piece of the puzzle is how to get the Mac to boot from the network.

One option is to deploy an Apple netboot server.

Another option is to fudge it using a Linux DHCP server.

However, if you can’t do either of those things (or if you just don’t want to), then you only other option is to inject it directly into the Mac’s firmware settings.

Fortunately, the bless command has some undocumented arguments to make this easier.

This document assumes you have a netboot bundle on a server somewhere, and HTTP and TFTP already configured.

Netboot bundles will typically contain the following components:

  • booter: i386/booter
  • kernel: i386/mach.macosx and/or i386/x86_64/mach.macosx
  • mkext: i386/mach.macosx.mkext and/or i386/x86_64/mach.macosx.mkext
  • kernelcache: i386/kernelcache and/or i386/x86_64/kernelcache
  • root filesystem image: NetInstall.sparseimage and/or NetRestore.sparseimage

OS X 10.6 bundles typically have a booter, a kernel, and a root filesystem image. The bless command looks like this:

sudo bless --netboot \
   --booter tftp://server/path/to/i386/booter \
   --kernel tftp://server/path/to/i386/mach.macosx \
   --options rp=http://server/path/to/NetInstall.sparseimage

The mkext doesn’t need to be specified; the firmware attempts to load it automatically.

This is explained in further detail in the Mactips article How to NetBoot Across Subnets.

Some time around 10.7 or 10.8, Apple removed the kernel and replaced it with the kernelcache:

sudo bless --netboot \
   --booter tftp://server/path/to/i386/booter \
   --kernelcache tftp://server/path/to/i386/x86_64/kernelcache \
   --options rp=http://server/path/to/NetInstall.sparseimage

However, what if you want to boot to a Mountain Lion netboot image from Snow Leopard? Unfortunately, the bless command in Snow Leopard does not support the --kernelcache option, and if you specify the kernelcache in the --kernel option, then the firmware treats it as a kernel, which fails.

To get kernelcache working from Snow Leopard, you need to get creative:

sudo bless --netboot \
   --booter tftp://server/path/to/i386/booter \
   --kernel tftp://server/path/to/i386/x86_64/kernelcache \
   --options rp=http://server/path/to/NetInstall.sparseimage
sudo nvram "$( sudo nvram efi-boot-file \
   | sed -E 's/^efi-boot-file[[:space:]]*/efi-boot-kernelcache=/' )"
sudo nvram -d efi-boot-file

This command uses bless to put the kernelcache into the wrong nvram variable. Next, it uses the nvram command to copy the kernelcache into the correct nvram variable. Finally, it uses the nvram command to delete the incorrect variable.

The end result is the same as if the --kernelcache option was used in Mountain Lion.

True Story

True story.
“Do these servers have sensors in them?”

Netboot Shenanigans: Mac network boot using ISC-DHCP as a BSDP server

This article by Pepijn Oomen describes how to get a netboot image to show up in the ⌥‑boot menu of the MacMini3,1, using nothing but the standard ISC‑DHCP server.

Why would you do this? Well, the ISC‑DHCP server is the standard DHCP server in many Linux distributions. :)

This method worked great until I updated the firmware on my iMac12,1. I could still boot the image, but it would not appear in the boot menu.

However, I was able to get it working by modifying the BSDP packet.

Pepijn’s configuration has the following characteristics:

  • When the Mac requests the image list, the DHCP server returns the list of images available on the server. In Pepijn’s case, one image is listed, with id “1” and name “netboot”:

option vendor-encapsulated-options
      01:01:01:               # bsdp_msgtype_list
      09:0c:81:00:00:01:07:6e:65:74:62:6f:6f:74; # netboot
  • Otherwise, it returns the select boot image (index 1):

option vendor-encapsulated-options
      01:01:02:               # bsdp_msgtype_select
      08:04:81:00:00:01;      # bsdptag_selected_boot_image

This worked fine with the new firmware when the Mac was booted holding ‘N’, but to get it to appear in the ⌥‑boot menu, I had to make the following modifications:

  • I modified the bsdp_msgtype_list so the id and name matched my image, and I added the server priority (BSDP option 4) and default image (BSDP option 7):

# bsdp image list message:
# one image, plus one default image (both are the same)
option vendor-encapsulated-options 
    01:01:01:                                 # bsdp_msgtype_list
    04:02:                                    # bsdp option code 4 (length 02) server priority
        80:00:                                #     Priority (32768)
    07:04:                                    # bsdp option code 7 (length 04) default image id
        81:00:00:89:                          #     Image ID (137)
    09:0e:                                    # bsdp option code 9 (length 0e) image list
        81:00:00:89:                          #     Image ID (137)
            09:54:68:65:2d:49:6d:61:67:65;    #         Name (length 09) 'The-Image'
  • I added the machine name to the bsdp_msgtype_select reply (and modified the index to match the change above).

# details about the selected image
# 
option vendor-encapsulated-options
    01:01:02:                          # bsdp_msgtype_select 
        08:04:                             # bsdptag_selected_boot_image
            81:00:00:89:                   #     Image ID (137)
        82:09:                             # Machine Name (length 09)
            54:68:65:2d:49:6d:61:67:65;    #     'The-Image'

… voilà! The image appears in the boot menu.

The following pages were extremely helpful when figuring out how to modify the bsdp packets:

Finally, I have included the entire dhcpd.conf below. It also includes a (commented) message list which contains multiple images. The two images appear separately in the boot menu, but I can’t figure out an easy way to differentiate between them during bsdp_msgtype_select.

#
# Apple BSDP server. Does NOT give out IP addresses
#

ddns-update-style none;
ddns-updates off;
ignore client-updates;
allow booting;
authoritative;
boot-unknown-clients on;
ping-check off;
one-lease-per-client on;
default-lease-time 7200;
max-lease-time 7200;
allow-unknown-clients;

subnet 0.0.0.0 netmask 0.0.0.0 { 
    pool {
        # DON'T supply an IP address!
        range 0.0.0.0 0.0.0.0;
        allow members of "netboot";
    }
}

class "netboot" {

    match if substring (option vendor-class-identifier, 0, 9) = "AAPLBSDPC";
    option dhcp-parameter-request-list 1,3,17,43,60;

    if (option dhcp-message-type = 1) {
        option vendor-class-identifier "AAPLBSDPC";
        option vendor-encapsulated-options
            08:04:81:00:00:89;    # bsdp option 8 (length 04) -- selected image id;
    } elsif (option dhcp-message-type = 8) {
        option vendor-class-identifier "AAPLBSDPC";
        if (substring(option vendor-encapsulated-options, 0, 3) = 01:01:01) {
            log(debug, "bsdp_msgtype_list");

            # bsdp image list message:
            # one image, plus one default image (both are the same)
            option vendor-encapsulated-options 
                01:01:01:                              # bsdp_msgtype_list
                04:02:                                 # bsdp option code 4 (length 02) server priority
                    80:00:                             #  Priority (32768)
                07:04:                                 # bsdp option code 7 (length 04) default image id
                    81:00:00:89:                       #  Image ID (137)
                09:0e:                                 # bsdp option code 9 (length 0e) image list
                    81:00:00:89:                       #  Image ID (137)
                        09:54:68:65:2d:49:6d:61:67:65; #   Name (length 09) 'The-Image'

            # bsdp image list message:
            # TWO images, plus one default image (both are the same)
            #option vendor-encapsulated-options 
            #    01:01:01:        # bsdp_msgtype_list
            #    04:02:           # bsdp option code 4 (length 02) -- server priority
            #        80:00:       #  Priority (32768)
            #    07:04:           # bsdp option code 7 (length 04) -- default image id
            #        81:00:00:89: #  Image ID (137)
            #    09:1b:           # bsdp option code 9 (length 1b) -- image list
            #        81:00:00:89: #  Image ID (137)
            #            09:54:68:65:2d:49:6d:61:67:65: # Name (length 09) 'The-Image'
            #        81:00:04:31: #  Image ID (1073)
            #            08:44:53:52:2d:31:30:37:33;    # Name (length 08) 'DSR-1073'
            #
            # option-boot lists both images, but the "root-path"
            # below is hardcoded! So it doesn't actually support
            # both images -- it'll always boot the first image. :(

        } else {
            log(debug, "bspd_msgtype_select");

            # details about the selected image
            # 
            option vendor-encapsulated-options
                01:01:02:                       # bsdp_msgtype_select 
                08:04:                          # bsdptag_selected_boot_image
                    81:00:00:89:                #  Image ID (137)
                82:09:                          # Machine Name (length 09)
                    54:68:65:2d:49:6d:61:67:65; #  'The-Image'

            if (substring(option vendor-class-identifier, 10, 4) = "i386") {
                filename "/osx/i386/booter";
                next-server 10.25.64.32;
                option root-path = "http://10.25.64.32/build.sparseimage";
            } elsif (substring(option vendor-class-identifier, 10, 3) = "ppc") {
                filename "nil";
            }
        }
    }
}

Update 06 Feb 2013: Brandon’s Tinkerings has a solution for handling multiple images correctly. Awesome! :)

Update 21 Feb 2013: The server priority is in fact BSDP option 4, not option 2.

Update 09 April 2014: Brandon’s Tinkerings appears to be offline. :( Mirror here.

Update: Brandon’s Tinkerings is back up again! :)

How to create a user account in lion from single user mode

Here’s how:

Boot into single user mode (⌘S), and run the following commands:

# Mount the filesystem; start opendirectoryd:
/sbin/fsck -fy && /sbin/mount -uw /
launchctl load /System/Library/LaunchDaemons/com.apple.opendirectoryd.plist

# Create the user account:
dscl . -create /Users/localadmin
dscl . -create /Users/localadmin UserShell /bin/bash
dscl . -create /Users/localadmin RealName "Local Admin"
dscl . -create /Users/localadmin UniqueID 502
dscl . -create /Users/localadmin PrimaryGroupID 20
dscl . -create /Users/localadmin NFSHomeDirectory /Users/localadmin

# Create the home directory:
cp -R "/System/Library/User Template/English.lproj" /Users/localadmin
chown -R localadmin:staff /Users/localadmin

# Set the password:
dscl . -passwd /Users/localadmin newPassword

# Grant admin access (optional):
dscl . -append /Groups/admin GroupMembership localadmin

Notes:

You may see this error message, but don’t worry, it can be safely ignored:

launchctl: Couldn't stat("/System/Library/LaunchDaemons/com.apple.DirectoryServicesLocal.plist"): No such file or directory
nothing found to load

To get the next unused UniqueID, run this command:

maxid=$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -ug | tail -1)
newid=$((maxid+1))
echo $newid

To get the group id for the staff group, run this command:

dscacheutil -q group -a name staff

(make a note of the uid — usually 20)

Sources:
http://support.apple.com/kb/HT4749
http://serverfault.com/questions/20702/how-do-i-create-user-accounts-from-the-terminal-in-mac-os-x-10-5

building cntlm from subversion using macports

Why do it the easy way?

Update: I originally wrote this post because of an overflow bug which caused files over 2GB to fail silently, and the fix hadn’t yet been released. Well, the fix has now been released, so it’s probably a better idea to use that version, since this portfile does not work properly with selfupdate.

Instructions

  1. Install and configure macports. Note that selfupdate doesn’t work from svn.

  2. Create a local repository:

    mkdir -p ~/ports/net/cntlm/files
    
  3. Copy the Portfile and patch to the repository (contents below):

    cp /path/to/Portfile ~/ports/net/cntlm
    cp /path/to/patch-trunk-Makefile.diff ~/ports/net/cntlm/files
    
  4. Configure the local repository. Add the following line to /opt/local/etc/macports/sources.conf, then sync the repository:

    file:///Users/localadmin/ports
    
    sudo port -d sync
    
  5. Install cntlm:

    sudo port -v install cntlm
    

Portfile

    # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
    # $Id$
    PortSystem              1.0
    name                    cntlm
    version                 HEAD
    license                 gpl
    categories              net
    platforms               darwin
    maintainers             xs4all.nl:hbruinsma
    homepage                http://cntlm.sourceforge.net/
    description             Cntlm is an NTLM / NTLM Session Response / NTLMv2 authenticating HTTP proxy
    svn.url                 https://cntlm.svn.sourceforge.net/svnroot/cntlm/cntlm/trunk
    svn.revision            HEAD
    fetch.type              svn
    worksrcdir              trunk
    patchfiles              patch-trunk-Makefile.diff
    depends_lib             port:coreutils
    build.target            {}
    build.args              SYSCONFDIR=/opt/local/etc BINDIR=/opt/local/sbin \
            MANDIR=/opt/local/man
    destroot.args           SYSCONFDIR=/opt/local/etc BINDIR=/opt/local/sbin \
            MANDIR=/opt/local/man
    
    startupitem.create      yes
    startupitem.name        cntlm
    startupitem.executable  "${prefix}/sbin/cntlm"

patch-trunk-Makefile.diff

    -- Makefile    2011-10-14 19:45:26.000000000 +0800
    +++ Makefile.old        2011-12-06 17:11:08.000000000 +0800
    @@ -44,10 +44,10 @@
                    install -M 644 -f $(MANDIR)/man1 doc/$(NAME).1; \
                    install -M 600 -c $(SYSCONFDIR) doc/$(NAME).conf; \
            else \
    -               install -D -m 755 -s $(NAME) $(BINDIR)/$(NAME); \
    -               install -D -m 644 doc/$(NAME).1 $(MANDIR)/man1/$(NAME).1; \
    +               install -m 755 -s $(NAME) $(BINDIR)/$(NAME); \
    +               install -m 644 doc/$(NAME).1 $(MANDIR)/man1/$(NAME).1; \
                    [ -f $(SYSCONFDIR)/$(NAME).conf -o -z "$(SYSCONFDIR)" ] \
    -                       || install -D -m 600 doc/$(NAME).conf $(SYSCONFDIR)/$(NAME).conf; \
    +                       || install -m 600 doc/$(NAME).conf $(SYSCONFDIR)/$(NAME).conf; \
            fi
            @echo; echo "Cntlm will look for configuration in $(SYSCONFDIR)/$(NAME).conf"

Note that macports does not recommend building from subversion, since the results will not be reproducible. However, for testing, it should work fine.