SmartOS isomerge

March 5 2013

This How-To covers extracting files from the SmartOS ISO
image and replacing them, which is automated with the
node.js script isomerge.

If you are trying to modify/change a device driver in a SmartOS image,
you are in the right place.

In this case I am updating the Areca ARC driver arcmsr
for the 1882 and 1880 RAID cards, including compiled
code/drivers not yet committed to the SmartOS image.

This How-To is written for vi imparied SmartOS noobs
who are trying to get some funky piece of bleeding edge
hardware working with a new device driver that some
nice person from the SmartOS/illumos dev community
patched up for you.

BONUS - isomerge doesn't make a bootable USB image,
but all the commands required are listed at the end.

Install SmartOS From the top.

You need a machine that actually boots
SmartOS (64 bit cpu, kvm not required).

See the SmartOS Install Wiki.

You will need access to the Joyent SmartOS
VM images (aka datasets),
BUT on a bare SmartOS install
is missing/empty,
so fill it with the images location as follows:

# cd /
# echo >> /var/db/imgadm/sources.list

For the vi handicapped like me,
you can quickly install pkgin,
and nano into the global zone

# curl -k | gzcat | tar -xf -

THIS puts everything onto the
global zone zfs volume in
These commands set up pkgin
and then use it to install nano

# pkg_admin rebuild
# pkgin -y up
# man pkgin
# pkgin help
# pkgin in nano

OK, now we can grab the appropriate
SmartOS Zone base64 image.

smartos-isomerge ZONE Setup. [Wiki]

# cd /var/db/imgadm
# imgadm
# imgadm update
# imgadm avail | grep base64

This lists the images, most recent at the bottom.
Using the following SmartOS base64 image:

fdea06b0-3f24-11e2-ac50-0b645575ce9d  base64         1.8.4    smartos  2012-12-05T21:59:37Z

# imgadm import fdea06b0-3f24-11e2-ac50-0b645575ce9d

Importing image fdea06b0-3f24-11e2-ac50-0b645575ce9d (base64 1.8.4) from ""
100% [=============================]  time 158.2s  eta 0.0s
Imported image fdea06b0-3f24-11e2-ac50-0b645575ce9d to "zones/fdea06b0-3f24-11e2-ac50-0b645575ce9d".

JSON for the Zone (yes, this is where I need nano):

  "alias": "smartos-isomerge",
  "hostname": "smartos-isomerge",
  "brand": "joyent",
  "max_physical_memory": 32768,
  "tmpfs": 8192,
  "fs_allowed": "ufs,pcfs,tmpfs,hsfs",
  "image_uuid": "fdea06b0-3f24-11e2-ac50-0b645575ce9d",
  "quota": 15,
  "nics": [
      "nic_tag": "admin",
      "ip": "dhcp"

Save to the file

Create the Zone with vmadm

# vmadm create -f SmartOS_Isomerge.json
Successfully created 14a9d390-79bc-4331-8e33-d892295c150c

- will report the [uuid] of the new zone (not the same as the example above, a new uuid).

Tip: these long [uuid]s can be
tab-completed with
vmadm and zlogin commands,
just type a few chars!
# vmadm get [uuid]
--will report the JSON state of the zone.

# vmadm list
- will list the available VMs

# vmadm update [uuid] max_physical_memory=32768 -
- will update the max memory of the vm

# vmadm start [uuid]
-restarts a halted zone

Log in to the new zone as root

# zlogin [uuid]
- to get in..
- escape sequence to get out of the zone is:

# ~.

Looks like this:
[root@2c-27-d7-2e-93-55 /var/db/imgadm]# zlogin 14a9d390-79bc-4331-8e33-d892295c150c
[Connected to zone '14a9d390-79bc-4331-8e33-d892295c150c' pts/4]
   __        .                   .
 _|  |_      | .-. .  . .-. :--. |-
|_    _|     ;|   ||  |(.-' |  | |
  |__|   `--'  `-' `;-| `-' '  ' `-'
                   /  ; SmartMachine base64 1.8.4

[root@smartos-isomerge ~]#

Set up for isomerge within the
smartos-isomerge Zone

Grab a few packages: nano, wget and git wih pkgin.

[root@smartos-isomerge ~]# pkgin in nano
[root@smartos-isomerge ~]# pkgin in wget
[root@smartos-isomerge ~]# pkgin in scmgit-1

Git clone smartos-isomerge

[root@smartos-isomerge ~]# git clone
Cloning into 'smartos-isomerge'...
remote: Counting objects: 22, done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 22 (delta 5), reused 20 (delta 3)
Unpacking objects: 100% (22/22), done.

[root@smartos-isomerge ~]#

Locate the SmartOS Image you want to manipulate by version datestamp:

I will modify the 20130222 iso listed at the bottom of the listing (at time of writing).

smartos-20130222T000747Z-USB.img.bz2 22-Feb-2013 02:04 155179890
smartos-20130222T000747Z.iso 22-Feb-2013 02:03 268290048
smartos-20130222T000747Z.vmwarevm.tar.bz2 22-Feb-2013 02:06 155270475

Grab the SmartOS image with wget

[root@smartos-isomerge ~]# cd smartos-isomerge
[root@smartos-isomerge ~/smartos-isomerge]
# wget
--2013-03-05 05:23:50--
Resolving (
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 268290048 (256M) [application/octet-stream]
Saving to: `smartos-20130222T000747Z.iso'

100%[=============================================>] 268,290,048  524K/s   in 8m 30s 

2013-03-05 05:32:22 (513 KB/s) - `smartos-20130222T000747Z.iso' saved [268290048/268290048]

Gather The New Files for your Use Case

I am merging a new version of the Areca ARC 1882 device driver arcmsr provided by RM.

So I grab the device driver where he left it form me...
(which will go into /kernel/drv/amd64)

[root@smartos-isomerge ~/smartos-isomerge]# wget
--2013-03-05 05:50:24--
Resolving (, 2600:3c00::f03c:91ff:fe96:a264
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 77912 (76K) [text/plain]
Saving to: `arcmsr'

100%[=============================================>] 77,912      89.4K/s   in 0.9s   

2013-03-05 05:50:26 (89.4 KB/s) - `arcmsr' saved [77912/77912]]

I also need to update the /etc/driver_aliases file to include a line for 1882 support.
The file lives here on GitHub:

Use wget with the "raw" version of the file URL to grab the file:
[root@smartos-isomerge ~/smartos-isomerge]# wget
--2013-03-05 05:57:35--
Resolving (
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 23894 (23K) [text/plain]
Saving to: `driver_aliases'

100%[=============================================>] 23,894       105K/s   in 0.2s   

2013-03-05 05:57:37 (105 KB/s) - `driver_aliases' saved [23894/23894]

Now I have everything I need.
I will edit the local copy of driver_aliases
to add in the line for 1880 and 1882 arcmsr
support using nano and save it.

Set up the input JSON for isomerge
- modified from the sample provided.

[root@smartos-isomerge ~/smartos-isomerge]# cp sample-input.json arcmsr-isomerge.json
[root@smartos-isomerge ~/smartos-isomerge]# nano arcmsr-isomerge.json

This is the edited JSON I am using as input for isomerge.
Note the arcmsr driver gets 0755 permissions according to the directory contents
(-rwxr-xr-x ) and goes into the appropriate directory

  "workdir": "/var/tmp/ISOMERG",
  "inputiso": "smartos-20130222T000747Z.iso",
  "mergefiles": {
    "/etc/driver_aliases": { "owner": "root", "group": "sys", "perms": "0444",
                     "src": "driver_aliases" },
    "/kernel/drv/amd64/arcmsr": { "owner": "root", "group": "sys", "perms": "0755",
                     "src": "arcmsr" }

Tip: How did I known where to
put my file in the merge JSON?
What are the right permissions?

As root, from the global zone of my SmartOS box:
# cd /
# find . -name "driver.aliases" -print
# ls -al /etc/driver_aliases
-rw-r--r-- 1 root sys 23894 Feb 22 01:34 /etc/driver_aliases
# find . -name "arcmsr" -print
# ls -al /kernel/drv/amd64/arcmsr
-rWxr-xr-x 1 root sys 77912 Feb 22 01:34 /kernel/drv/amd64/arcmsr

NOW we are almost ready to run isomerge

isomerge is a node.js script that requires additional modules to be fetched with npm.

[root@smartos-isomerge ~/smartos-isomerge]# npm install async
[root@smartos-isomerge ~/smartos-isomerge]# npm install mkdirp
[root@smartos-isomerge ~/smartos-isomerge]# npm install colorize

isomerge also calls mkisofs, requiring the cdrtools package to be fetched with pkgin.

[root@smartos-isomerge ~/smartos-isomerge]# pkgin in cdrtools

Go forth and isomerge.
[root@smartos-isomerge ~/smartos-isomerge]# ./merge.js < arcmsr-isomerge.json
* mkdir /var/tmp/ISOMERG
path.exists is now called `fs.exists`.
 * lofi add smartos-20130222T000747Z.iso
    - device: /dev/lofi/2
 * fstyp /dev/lofi/2
    - type: hsfs
 * mkdir /var/tmp/ISOMERG/iso
 * mount hsfs /dev/lofi/2
       on /var/tmp/ISOMERG/iso
     opts ro
 * cp from /var/tmp/ISOMERG/iso
        to /var/tmp/ISOMERG/isounpack
 * umount /var/tmp/ISOMERG/iso
 * lofi remove /dev/lofi/2
 * lofi add /var/tmp/ISOMERG/isounpack/platform/i86pc/amd64/boot_archive
    - device: /dev/lofi/2
 * fstyp /dev/lofi/2
    - type: ufs
 * mkdir /var/tmp/ISOMERG/root
 * fsck /dev/lofi/2
 * mount ufs /dev/lofi/2
       on /var/tmp/ISOMERG/root
     opts rw nologging
 * mv from /var/tmp/ISOMERG/root/usr.lgz
        to /var/tmp/ISOMERG/tmpusr.lgz
 * lofi uncompress /var/tmp/ISOMERG/tmpusr.lgz
 * lofi add /var/tmp/ISOMERG/tmpusr.lgz
    - device: /dev/lofi/3
 * fstyp /dev/lofi/3
    - type: ufs
 * fsck /dev/lofi/3
 * mount ufs /dev/lofi/3
       on /var/tmp/ISOMERG/root/usr
     opts rw nologging
 * merging files...
 * cp from driver_aliases
        to /var/tmp/ISOMERG/root/etc/driver_aliases
 * chown root:sys /var/tmp/ISOMERG/root/etc/driver_aliases
 * chmod 0444 /var/tmp/ISOMERG/root/etc/driver_aliases
 * cp from arcmsr
        to /var/tmp/ISOMERG/root/kernel/drv/amd64/arcmsr
 * chown root:sys /var/tmp/ISOMERG/root/kernel/drv/amd64/arcmsr
 * chmod 0755 /var/tmp/ISOMERG/root/kernel/drv/amd64/arcmsr
 * ...done merging files
 * umount /var/tmp/ISOMERG/root/usr
 * fsck /dev/lofi/3
 * lofi remove /dev/lofi/3
 * lofi compress /var/tmp/ISOMERG/tmpusr.lgz
 * mv from /var/tmp/ISOMERG/tmpusr.lgz
        to /var/tmp/ISOMERG/root/usr.lgz
 * umount /var/tmp/ISOMERG/root
 * fsck /dev/lofi/2
 * lofi remove /dev/lofi/2
 * mkisofs /var/tmp/ISOMERG/output.iso
 * done

Congratulations, output.iso is the merged image.
But my server has no CD/DVD drive, so...

BONUS - Make the
bootable USB image!

# pkgin in pbzip
# cd /var/tmp/ISOMERG/
# mkfile -n 2000000000 output-USB.img
# ls
isounpack  output.iso  output.usb
# lofiadm -a output-USB.img
--Tip: Raw device here is /dev/rlofi/2 used for fdisk, mkfs
# wget
--2013-03-05 07:54:34--
Resolving (
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1232 (1.2K) [text/plain]
Saving to: `usb_fdisk_table'

100%[===============================================>] 1,232       --.-K/s   in 0s     

2013-03-05 07:54:36 (33.6 MB/s) - `usb_fdisk_table' saved [1232/1232]

# fdisk -F usb_fdisk_table /dev/rlofi/2
# mkfs -F pcfs -o fat=32 /dev/rlofi/2:c
Construct a new FAT file system on /dev/rlofi/2:c: (y/n)? y
# mkdir temp        
# mount -F pcfs /dev/lofi/2:c ./temp
# cp -r ./isounpack/boot ./temp
# cp -r ./isounpack/platform ./temp
# grub --batch
Probing devices to guess BIOS drives. This may take a long time.
    GNU GRUB  version 0.97  (640K lower / 65536K upper memory)
 [ Minimal BASH-like line editing is supported.  For the first word, TAB
   lists possible command completions.  Anywhere else TAB lists the possible
   completions of a device/filename. ]

grub> device (hd0) output-USB.img
device (hd0) output-USB.img
root (hd0,0)
root (hd0,0)
 Filesystem type is fat, partition type 0xc
setup (hd0)
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/fat_stage1_5" exists... no
 Running "install /boot/grub/stage1 (hd0) /boot/grub/stage2 p /boot/grub/menu.lst "... succeeded
# umount  -f /dev/lofi/2:c
# lofiadm -d /dev/lofi/2
# pbzip2 output-USB.img

The merged image output-USB.img.bz2 is
now in bootable USB form as per
the usual SmartOS image.