Skip to content
This repository has been archived by the owner on Sep 13, 2022. It is now read-only.

Custom OS

Frank Steiler edited this page Apr 28, 2017 · 2 revisions

This entry will explain the general approach for creating a custom OS, that can be provisioned using NOOBS4IoT. Since most Raspberry Pi OS are provided as images, which the user needs to dd onto the SD Card of the Raspberry Pi, it is not trivial to adopt them for the NOOBS4IoT layout.

We will show the process along the (tested) example of Ubuntu Mate using any Linux based PC to create the files, however the process should be adoptable to all Raspberry Pi image files (especially if they are Linux based and have only two partitions).

A list of predefined OS is available from the Raspberry Pi Foundation, an adopted list can be found in this wiki.

This article is based on an entry from the NOOBS Wiki.

Partition archives

  1. Get the image file for the Raspberry Pi and extract it, depending on its compression format:
# Downloading file
wget https://ubuntu-mate.org/raspberry-pi/ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz

# Extarction creates "ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img" file that we will work on
unxz ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz
  1. Mount the image file using kpartx, in order to access its content
# Create loopback device for mounting
sudo kpartx -av ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img
# The output will be something like:
# add map loop0p1 (254:0): 0 129024 linear 7:0 2048
# add map loop0p2 (254:1): 0 9633792 linear 7:0 131072
# where loop0p1 and loop0p2 are the partitions that we want to mount (make sure that the mountpoint directories exist):

sudo mount /dev/mapper/loop0p1 /mnt/boot
sudo mount /dev/mapper/loop0p2 /mnt/root
  1. Create tar files of both partitions, note the size of the uncompressed tarballs for later (ls command output)
# Processing boot archive
cd /mnt/boot 
tar -cpf /tmp/boot.tar
ls /tmp/boot.tar -l --block-size=1MB
xz -9 -e /tmp/boot.tar

# Processing root archive (tar must be executed as root)
cd /mnt/root
sudo tar -cpf /tmp/root.tar . --exclude=proc/* --exclude=sys/* --exclude=dev/pts/*
ls /tmp/root.tar -l --block-size=1MB
xz -9 -e /tmp/root.tar 
  1. Unmount and remove loopback device
umount /mnt/root
umount /mnt/boot

sudo kpartx -dv ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img
  1. Finally move the tar.xz files to the webserver path, where you want to provide them. We will asume the following root address where the tar files are direct accessible for the next steps: http://somehost.com/ubuntu_mate/

Meta-Data files

os.json

This file contains general information about the OS that will be installed. Most important is the supported_hex_revisions part. You need to make sure that one of the revision is mentioned in the /proc/device-tree/model of your target Pi (and make sure that the downloaded image is actually compatible with your Pi.

os.json
{
  "name": "Ubuntu_Mate",
  "version": "16.04.2 LTS",
  "release_date": "2015-02-17",
  "kernel": "4.8",
  "description": "Ubuntu MATE for the Raspberry Pi 2",
  "url": "https://ubuntu-mate.org/raspberry-pi/",
  "supported_hex_revisions": "1040,1041",
  "feature_level": 0
}

partitions.json

This file contains the list of partitions, that the OS needs, with their respective size and filesystem type.

First we need to gather the missing file sizes. uncompressed_tarball_size was the output of step three in "Partition archives". partition_size_nominal can be obtained throug the following command:

sudo parted -s ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img print

# The output will look like this
# Model:  (file)
# Disk /var/www/default/ubuntu_mate/ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img: 5000MB
# Sector size (logical/physical): 512B/512B
# Partition Table: msdos
# Disk Flags:
#
# Number  Start   End     Size    Type     File system  Flags
#  1      1049kB  67.1MB  66.1MB  primary  fat16        lba
#  2      67.1MB  5000MB  4933MB  primary  ext4

# We will use the rounded up "Size" column

Resulting in the following file:

partitions.json
{
  "partitions": [
    {
      "label": "boot",
      "filesystem_type": "FAT",
      "partition_size_nominal": 68,
      "want_maximised": false,
      "uncompressed_tarball_size": 22
    },
    {
      "label": "root",
      "filesystem_type": "ext4",
      "partition_size_nominal": 4933,
      "want_maximised": true,
      "mkfs_options": "-O ^huge_file",
      "uncompressed_tarball_size": 3458
    }
  ]
}

partition_setup.sh

Finally we need to add the post install script. This file will set the correct partitions after installation in the fstab and commandline.txt file, in order to properly boot. Depending on your OS and the amount of partitions, this file needs to be adopted. $part1, part2, ... contain the partition device NOOBS created and filed using the above created tarballs.

partition_setup.sh
#!/bin/sh

set -ex

if [ -z "$part1" ] || [ -z "$part2" ]; then
  printf "Error: missing environment variable part1 or part2\n" 1>&2
  exit 1
fi

mkdir -p /tmp/1 /tmp/2

mount "$part1" /tmp/1
mount "$part2" /tmp/2

sed /tmp/1/cmdline.txt -i -e "s|root=/dev/[^ ]*|root=${part2}|"
sed /tmp/2/etc/fstab -i -e "s|^.* / |${part2}  / |"
sed /tmp/2/etc/fstab -i -e "s|^.* /boot |${part1}  /boot |"

umount /tmp/1
umount /tmp/2

Request

Finally we need to specify the JSON request file. We will keep it simple:

 {
    "description": "Ubuntu MATE for the Raspberry Pi",
    "os_info": "http://somehost.com/ubuntu_mate/os.json",
    "os_name": "Ubuntu MATE 16.04.2 LTS",
    "partition_setup": "http://somehost.com/ubuntu_mate/partition_setup.sh",
    "partitions_info": "http://somehost.com/ubuntu_mate/partitions.json",
    "release_date": "2017-02-17",
    "supported_hex_revisions": "1040,1041",
    "supported_models": [
        "Pi 2",
        "Pi 3"
    ],
    "tarballs": [
        "http://somehost.com/ubuntu_mate/boot.tar.xz",
        "http://somehost.com/ubuntu_mate/root.tar.xz"
    ]
}