Saturday, 23 July 2016

"$@" is a shell idiom

TL;DR: Use "$@" when you want to pass arguments unchanged to a function or program.

When you read the shell documentation you will see that there are two main ways to refer to all the arguments for passing to a function or program: $* and "$@". What is the difference? This test script will demonstrate it:

#!/bin/sh

testargs() {
       echo testargs: $# arguments
       showargs $*
       showargs "$@"
}

showargs() {
       echo showargs: $# arguments
       for i
       do
               echo $i
       done
}

testargs 1 2 3
testargs word 'quoted phrase' word

The result should be:
testargs: 3 arguments
showargs: 3 arguments
1
2
3
showargs: 3 arguments
1
2
3
testargs: 3 arguments
showargs: 4 arguments
word
quoted
phrase
word
showargs: 3 arguments
word
quoted phrase
word
As you can see, the difference is manifest when an argument has whitespace. "$@" preserves the arguments, not parsing it again to break up at whitespace in arguments. Think if it as an idiom meaning pass arguments verbatim.

Why would you ever use $* though? Here's a place where you shouldn't use "$@".
su -c "$*" user
If you were to use "$@" and it contained multiple arguments, only the first argument would be used by -c and the others would follow, causing a syntax error. This however means that if you want to pass arguments with whitespace to -c, you have to quote them and escape the quotes too.

Saturday, 9 July 2016

Installing Linuxmint 18 on RAID 1

TL;DR: Can't be done easily.

I had a PC with dual disks that I was running under openSUSE Leap 42.1 in RAID 1. I wanted to install Linuxmint 18 on it before giving it away.

First problem I encountered was that the partitioner in the installer knows nothing about RAID.

After some reading I found that the solution is to use gparted to create the RAID partitions first. But gparted didn't know how to do this. I figured out that the mdadm tool was missing, so I did:

apt-get install mdadm

Note that this installs to RAM as it's a live filesystem so needs to be redone if the install is restarted. Also there are some post-install script errors but mdadm gets installed.

Now with gparted I could create the RAID partitions and assemble them. Alternatively it can be done from the command line:

mdadm --assemble --scan

Now md0 and md1 appeared on the list of "disks" in the partitioner and I could assign them to / and /home.

The system installation went fine until it was time to install GRUB. It failed when it couldn't do

grub-install /dev/sdb /dev/sda

Changing the target to just /dev/sda and clicking Continue did nothing. This seems to be an installer bug.

So I did this from the command line:

mount /dev/md0 /mnt
grub-install --root-directory=/mnt /dev/sda
umount /mnt

When I rebooted from disk it stopped at the GRUB prompt. So I tried to boot manually.

grub> linux /boot/vmlin.... --root=/dev/md0
grub> initrd /boot/initrd...
grub> boot

The ... are where you should use TAB completion to select the kernel and initramfs images respectively. Unfortunately this failed when systemd tried to mount the root partition. The reason is that the raid modules are not present in the stock initramfs file. This was built by the Linuxmint 18 distributors.

At this point I gave up. Obviously Linuxmint 18 isn't designed to support this kind of RAID installation. If you want to go further you should rebuild the initramfs with the RAID modules included. Do let us know if you overcome this next hurdle.

And remember if you get it to work, you should install the mdadm package permanently, as it's not part of the default package set.