move the rpitools repo to boxtools/rpi
as we will need anyway boxtools also for rpis
This commit is contained in:
38
README.md
38
README.md
@ -201,3 +201,41 @@ Use (b) above to boot from the BOOT_TINY USB stick
|
||||
$ sh clone
|
||||
```
|
||||
You are asked to confirm or change the image name.
|
||||
|
||||
|
||||
## Installation of a Fresh Raspberry Pi
|
||||
|
||||
### install from cloned image (work currently from a Mac only)
|
||||
|
||||
Put compute module into PoE adapter, connect microUSB 'POWER' to
|
||||
a USB power supply, and connect micorUSB 'SLAVE' to your computer.
|
||||
|
||||
Go to the rpi subdir and then start
|
||||
```
|
||||
cd rpi
|
||||
`./write_to emmc
|
||||
```
|
||||
|
||||
You may test starting up the compute module in the PoE adapter, with a
|
||||
LAN cable attached, or directly in the iono pi max.
|
||||
|
||||
* on startup, the name will be boxaaaaaa with aaaaaa the last digits of the ethernet address
|
||||
* a new file should be created in the cfg sub directory
|
||||
|
||||
|
||||
### installing RPI tools from an fresh raspberry image (downloaded with Raspberry Pi Imager)
|
||||
|
||||
use the script install-ionopimax.sh or install-ionopi.sh
|
||||
(together with configsrtc.sh config-rtc-MCP79410.service)
|
||||
to add the needed items for iono pi and the run time clock
|
||||
|
||||
### create a clone image
|
||||
|
||||
In the rpi subdirectory, execute
|
||||
```
|
||||
./clone
|
||||
```
|
||||
An dated image will be created within about 10 min. and copied to the given directory.
|
||||
|
||||
|
||||
|
||||
|
40
rpi/clone
Executable file
40
rpi/clone
Executable file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import time
|
||||
|
||||
HOST = "l_samenv@samenv"
|
||||
SUBDIR = "boxes/rpi_images"
|
||||
DEFDEST = f"{HOST}:{SUBDIR}"
|
||||
file = f"{time.strftime('%Y-%m-%d')}.lz4"
|
||||
|
||||
|
||||
def prt(text):
|
||||
print(time.strftime('%H:%M:%S'), text)
|
||||
|
||||
|
||||
dest = input(f"destination directory for image [{DEFDEST}]: ") or DEFDEST
|
||||
|
||||
|
||||
host, _, subdir = dest.partition(':')
|
||||
if not subdir:
|
||||
if '@' in host:
|
||||
subdir = SUBDIR
|
||||
else:
|
||||
subdir, host = host, HOST
|
||||
|
||||
if os.system(f'ssh {host} cd {subdir}'):
|
||||
raise ValueError(f'{host}:{subdir} does not exist')
|
||||
if not os.system(f"bash -c 'ssh {host} ls {subdir}/{file} &> /dev/null'"):
|
||||
print(f'{host}:{subdir}/{file} already exists')
|
||||
|
||||
file = input(f"destination file name [{file}]: ") or file
|
||||
|
||||
prt('needs about 10 minutes')
|
||||
|
||||
pid = os.getpid()
|
||||
tmpfile = f"/media/rpi{pid}.img"
|
||||
os.system(f"sudo bash image-backup -i {tmpfile}")
|
||||
prt('pack and copy ... (3 minutes)')
|
||||
os.system(f"bash -c 'dd if={tmpfile} bs=512k | lz4 | ssh {host} dd of={subdir}/{file} bs=512k'")
|
||||
prt('cleanup ...')
|
||||
os.system(f"sudo rm -f {tmpfile}")
|
8
rpi/config-rtc-MCP79410.service
Normal file
8
rpi/config-rtc-MCP79410.service
Normal file
@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=RTC configuration for MCP79410
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/configrtc.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
7
rpi/configrtc.sh
Executable file
7
rpi/configrtc.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
modprobe i2c-dev
|
||||
# Calibrate the clock (default: 0x47). See datasheet for MCP7940N
|
||||
i2cset -y 1 0x6f 0x08 0x47
|
||||
modprobe i2c:mcp7941x
|
||||
echo mcp7941x 0x6f > /sys/class/i2c-dev/i2c-1/device/new_device
|
||||
hwclock -s
|
521
rpi/image-backup
Normal file
521
rpi/image-backup
Normal file
@ -0,0 +1,521 @@
|
||||
#!/bin/bash
|
||||
|
||||
trap '{ stty sane; echo ""; errexit "Aborted"; }' SIGINT SIGTERM
|
||||
|
||||
MNTPATH="/tmp/img-backup-mnt"
|
||||
|
||||
ONEMB=$((1024 * 1024))
|
||||
|
||||
errexit()
|
||||
{
|
||||
echo ""
|
||||
echo -e "$1"
|
||||
echo ""
|
||||
if [ "${MNTED}" = "TRUE" ]; then
|
||||
umount "${BOOTMNT}/" &> /dev/null
|
||||
umount "${MNTPATH}/" &> /dev/null
|
||||
fi
|
||||
rm -rf "${MNTPATH}/" &> /dev/null
|
||||
rmloop
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkloop()
|
||||
{
|
||||
LOOP="$(losetup -f --show -P "${IMGFILE}")"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to create loop device"
|
||||
fi
|
||||
}
|
||||
|
||||
rmloop()
|
||||
{
|
||||
if [ "${LOOP}" != "" ]; then
|
||||
losetup -d "${LOOP}"
|
||||
LOOP=""
|
||||
fi
|
||||
}
|
||||
|
||||
mntimg()
|
||||
{
|
||||
mkloop
|
||||
if [ ! -d "${MNTPATH}/" ]; then
|
||||
mkdir "${MNTPATH}/"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to make ROOT partition mount point"
|
||||
fi
|
||||
fi
|
||||
mount "${LOOP}p2" "${MNTPATH}/"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to mount image ROOT partition"
|
||||
fi
|
||||
MNTED=TRUE
|
||||
if [ ! -d "${BOOTMNT}/" ]; then
|
||||
mkdir -p "${BOOTMNT}/"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to make BOOT partition mount point"
|
||||
fi
|
||||
fi
|
||||
mount "${LOOP}p1" "${BOOTMNT}/"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to mount image BOOT partition"
|
||||
fi
|
||||
}
|
||||
|
||||
umntimg()
|
||||
{
|
||||
umount "${BOOTMNT}/"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to unmount image BOOT partition"
|
||||
fi
|
||||
umount "${MNTPATH}/"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to unmount image ROOT partition"
|
||||
fi
|
||||
MNTED=FALSE
|
||||
rmloop
|
||||
rm -r "${MNTPATH}/"
|
||||
}
|
||||
|
||||
fsckerr()
|
||||
{
|
||||
errexit "Filesystem appears corrupted "$1" resize2fs"
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
errexit "Usage: $0 [options] [pathto/imagefile for incremental backup]\n\
|
||||
-h,--help This usage description\n\
|
||||
-i,--initial pathto/filename of image file [,inital size MB [,added space for incremental MB]]\n\
|
||||
-n,--noexpand Do not expand filesystem on first run after restore\n\
|
||||
-o,--options Additional rsync options (comma separated)\n\
|
||||
-u,--ubuntu Ubuntu (Deprecated)\n\
|
||||
-x,--extract Extract image from NOOBS (force BOOT partition to -01 / ROOT partition to -02)"
|
||||
}
|
||||
|
||||
backup()
|
||||
{
|
||||
mntimg
|
||||
sync
|
||||
rsync -aDH --partial --numeric-ids --delete --force --exclude "${MNTPATH}" --exclude '/dev' --exclude '/lost+found' --exclude '/media' --exclude '/mnt' \
|
||||
--exclude '/proc' --exclude '/run' --exclude '/sys' --exclude '/tmp' --exclude '/var/swap' --exclude '/etc/udev/rules.d/70-persistent-net.rules' \
|
||||
--exclude '/var/lib/asterisk/astdb.sqlite3-journal' "${OPTIONS[@]}" / "${MNTPATH}/"
|
||||
if [[ $? -ne 0 && $? -ne 24 ]]; then
|
||||
errexit "Unable to create backup"
|
||||
fi
|
||||
mkdir -p "${MNTPATH}/dev/" "${MNTPATH}/lost+found/" "${MNTPATH}/media/" "${MNTPATH}/mnt/" "${MNTPATH}/proc/" "${MNTPATH}/run/" "${MNTPATH}/sys/" "${MNTPATH}/tmp/"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to create image directories"
|
||||
fi
|
||||
chmod a+rwxt "${MNTPATH}/tmp/"
|
||||
if [ "${EXTRACT}" = "TRUE" ]; then
|
||||
sed -i "/^[[:space:]]*#/!s|^\(.*root=\)\S\+\(\s\+.*\)$|\1PARTUUID=${PTUUID}-02\2|" "${BOOTMNT}/cmdline.txt"
|
||||
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/boot\S*\s\+vfat\s\+.*\)$|PARTUUID=${PTUUID}-01\1|" "${MNTPATH}/etc/fstab"
|
||||
sed -i "/^[[:space:]]*#/!s|^\S\+\(\s\+/\s\+.*\)$|PARTUUID=${PTUUID}-02\1|" "${MNTPATH}/etc/fstab"
|
||||
fi
|
||||
if [[ "${OSID}" != "ubuntu" && "${NOEXPAND}" = "FALSE" && "${ROOT_TYPE}" != "f2fs" && $(grep -v '^[[:space:]]*#' "${MNTPATH}/etc/rc.local" | grep -c 'resize-root-fs') -eq 0 ]]; then
|
||||
cat <<\EOF1 > "${MNTPATH}/etc/resize-root-fs"
|
||||
#!/bin/bash
|
||||
|
||||
ROOT_PART="$(mount | sed -n 's|^\(/dev/.*\) on / .*|\1|p')"
|
||||
ROOT_DEV="$(sed 's/[0-9]\+$//' <<< "${ROOT_PART}")"
|
||||
if [ "${ROOT_DEV}" = "/dev/mmcblk0p" ]; then
|
||||
ROOT_DEV="${ROOT_DEV:0:(${#ROOT_DEV} - 1)}"
|
||||
fi
|
||||
START=$(sfdisk -d "${ROOT_DEV}" | sed -n "s|^${ROOT_PART}\s\+:.*start=\s*\([0-9]\+\).*$|\1|p")
|
||||
PTTYPE="$(blkid "${ROOT_DEV}" | sed -n 's|^.*PTTYPE="\(\S\+\)".*|\1|p')"
|
||||
if [ "${PTTYPE}" = "dos" ]; then
|
||||
sfdisk --delete "${ROOT_DEV}" 2 > /dev/null
|
||||
echo "${START},+" | sfdisk --no-reread --no-tell-kernel -N2 "${ROOT_DEV}" &> /dev/null
|
||||
else
|
||||
PARTUUID="$(blkid "${ROOT_PART}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
|
||||
sgdisk -d 2 "${ROOT_DEV}" > /dev/null
|
||||
sgdisk -n 2:${START}:0 "${ROOT_DEV}" > /dev/null
|
||||
sgdisk -u 2:${PARTUUID} "${ROOT_DEV}" > /dev/null
|
||||
fi
|
||||
cat <<\EOF2 > /etc/init.d/resize_root_fs
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: resize_root_fs
|
||||
# Required-Start:
|
||||
# Required-Stop:
|
||||
# Default-Start: 3
|
||||
# Default-Stop:
|
||||
# Short-Description: Resize root filesystem
|
||||
# Description:
|
||||
### END INIT INFO
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
resize2fs "$(mount | sed -n 's|^\(/dev/.*\) on / .*|\1|p')"
|
||||
update-rc.d resize_root_fs remove
|
||||
rm /etc/init.d/resize_root_fs
|
||||
;;
|
||||
*)
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
EOF2
|
||||
chmod +x /etc/init.d/resize_root_fs
|
||||
update-rc.d resize_root_fs defaults
|
||||
sed -i '/resize-root-fs/d' /etc/rc.local
|
||||
rm /etc/resize-root-fs
|
||||
shutdown --no-wall -r now
|
||||
EOF1
|
||||
chmod +x "${MNTPATH}/etc/resize-root-fs"
|
||||
sed -i 's|^exit 0$|/etc/resize-root-fs\nexit 0|' "${MNTPATH}/etc/rc.local"
|
||||
fi
|
||||
sync
|
||||
umntimg
|
||||
mkloop
|
||||
fatlabel "${LOOP}p1" "$(fatlabel ${ROOT_DEV_P}1 | sed -n '$p')" &> /dev/null
|
||||
e2label "${LOOP}p2" "$(e2label ${ROOT_DEV_P}2)" &> /dev/null
|
||||
rmloop
|
||||
}
|
||||
|
||||
LOOP=""
|
||||
MNTED=FALSE
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
if [ $(id -u) -ne 0 ]; then
|
||||
errexit "$0 must be run as root user"
|
||||
fi
|
||||
PGMNAME="$(basename $0)"
|
||||
for PID in $(pidof -x -o %PPID "${PGMNAME}"); do
|
||||
if [ ${PID} -ne $$ ]; then
|
||||
errexit "${PGMNAME} is already running"
|
||||
fi
|
||||
done
|
||||
gdisk -l "${DEVICE}" &> /dev/null
|
||||
if [ $? -eq 127 ]; then
|
||||
echo ""
|
||||
echo "gdisk not installed"
|
||||
echo ""
|
||||
echo -n "Ok to install gdisk (y/n)? "
|
||||
while read -r -n 1 -s answer; do
|
||||
if [[ "${answer}" = [yYnN] ]]; then
|
||||
echo "${answer}"
|
||||
if [[ "${answer}" = [yY] ]]; then
|
||||
break
|
||||
else
|
||||
errexit "Aborted"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
echo "Installing gdisk"
|
||||
echo ""
|
||||
apt-get update
|
||||
apt-get install gdisk
|
||||
fi
|
||||
rsync --version &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "rsync not installed (run: apt-get install rsync)"
|
||||
fi
|
||||
OSID="$(sed -n 's|^ID=\(.*\)|\1|p' /etc/os-release)"
|
||||
BOOTMNT="${MNTPATH}$(sed -n 's|^\S\+\s\+\(/boot\S*\)\s\+vfat\s\+.*$|\1|p' /etc/fstab)"
|
||||
if [ "${BOOTMNT}" = "${MNTPATH}/boot/firmware" ]; then
|
||||
BOOTSIZE=512
|
||||
else
|
||||
BOOTSIZE=256
|
||||
fi
|
||||
ROOT_PART="$(mount | sed -n 's|^\(/dev/.*\) on / .*|\1|p')"
|
||||
ROOT_DEV_P="$(sed 's/[0-9]\+$//' <<< "${ROOT_PART}")"
|
||||
ROOT_DEV="${ROOT_DEV_P}"
|
||||
if [ "${ROOT_DEV}" = "/dev/mmcblk0p" ]; then
|
||||
ROOT_DEV="${ROOT_DEV:0:(${#ROOT_DEV} - 1)}"
|
||||
fi
|
||||
ROOT_TYPE=$(blkid "${ROOT_PART}" | sed -n 's|^.*TYPE="\(\S\+\)".*|\1|p')
|
||||
PTTYPE="$(blkid "${ROOT_DEV}" | sed -n 's|^.*PTTYPE="\(\S\+\)".*|\1|p')"
|
||||
if [[ "${PTTYPE}" != "dos" && "${PTTYPE}" != "gpt" ]]; then
|
||||
errexit "Unsupported partition table type: ${PTTYPE}"
|
||||
fi
|
||||
PARTUUID_B="$(blkid "${ROOT_DEV_P}1" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
|
||||
PARTUUID_R="$(blkid "${ROOT_PART}" | sed -n 's|^.*PARTUUID="\(\S\+\)".*|\1|p')"
|
||||
PTUUID="$(blkid "${ROOT_DEV}" | sed -n 's|^.*PTUUID="\(\S\+\)".*|\1|p')"
|
||||
DFKFREE=$(df | grep "% /$" | awk '{print $3}')
|
||||
INISIZE=$(((${DFKFREE} + (${DFKFREE} / 5)) / 1024))
|
||||
IMGNAME=""
|
||||
IMGSIZE=""
|
||||
IMGINCR=""
|
||||
IMGFILE=""
|
||||
OPTIONS=()
|
||||
EXTRACT=FALSE
|
||||
NOEXPAND=FALSE
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
|
||||
-i|--initial)
|
||||
OIFS=${IFS}
|
||||
IFS=','
|
||||
INITIAL=($2)
|
||||
IFS=${OIFS}
|
||||
IMGNAME=${INITIAL[0]}
|
||||
IMGSIZE=${INITIAL[1]}
|
||||
IMGINCR=${INITIAL[2]}
|
||||
shift 2
|
||||
;;
|
||||
|
||||
-n|--noexpand)
|
||||
NOEXPAND=TRUE
|
||||
shift
|
||||
;;
|
||||
|
||||
-o|--options)
|
||||
OIFS=${IFS}
|
||||
IFS=','
|
||||
OPTIONS=($2)
|
||||
IFS=${OIFS}
|
||||
shift 2
|
||||
;;
|
||||
|
||||
-u|--ubuntu)
|
||||
shift
|
||||
;;
|
||||
|
||||
-x|--extract)
|
||||
EXTRACT=TRUE
|
||||
shift
|
||||
;;
|
||||
|
||||
-*|--*)
|
||||
usage
|
||||
;;
|
||||
|
||||
*)
|
||||
IMGFILE="$1"
|
||||
shift
|
||||
;;
|
||||
|
||||
esac
|
||||
done
|
||||
if [ "${IMGFILE}" = "" ]; then
|
||||
if [ "${IMGNAME}" != "" ]; then
|
||||
IMGFILE="${IMGNAME}"
|
||||
if [[ ! "${IMGFILE}" =~ ^/mnt/.*$ && ! "${IMGFILE}" =~ ^/media/.*$ ]]; then
|
||||
errexit "${IMGFILE} does not begin with /mnt/ or /media/"
|
||||
fi
|
||||
if [ -d "${IMGFILE}" ]; then
|
||||
errexit "${IMGFILE} is a directory"
|
||||
fi
|
||||
if [ "${IMGSIZE}" = "" ]; then
|
||||
IMGSIZE=${INISIZE}
|
||||
fi
|
||||
IRFSSIZE=${IMGSIZE}
|
||||
if [ "${IMGINCR}" = "" ]; then
|
||||
IMGINCR=0
|
||||
fi
|
||||
ADDMB=${IMGINCR}
|
||||
else
|
||||
while :
|
||||
do
|
||||
echo ""
|
||||
read -r -e -i "${IMGFILE}" -p "Image file to create? " IMGFILE
|
||||
if [ "${IMGFILE}" = "" ]; then
|
||||
continue
|
||||
elif [[ ! "${IMGFILE}" =~ ^/mnt/.*$ && ! "${IMGFILE}" =~ ^/media/.*$ ]]; then
|
||||
echo ""
|
||||
echo "${IMGFILE} does not begin with /mnt/ or /media/"
|
||||
continue
|
||||
fi
|
||||
if [ -d "${IMGFILE}" ]; then
|
||||
echo ""
|
||||
echo "${IMGFILE} is a directory"
|
||||
elif [ -f "${IMGFILE}" ]; then
|
||||
echo ""
|
||||
echo -n "${IMGFILE} already exists, Ok to delete (y/n)? "
|
||||
while read -r -n 1 -s answer; do
|
||||
if [[ "${answer}" = [yYnN] ]]; then
|
||||
echo "${answer}"
|
||||
if [[ "${answer}" = [yY] ]]; then
|
||||
break 2
|
||||
else
|
||||
break 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
read -r -e -p "Initial image file ROOT filesystem size (MB) [${INISIZE}]? " IRFSSIZE
|
||||
if [ "${IRFSSIZE}" = "" ]; then
|
||||
IRFSSIZE=${INISIZE}
|
||||
fi
|
||||
if [ "${ROOT_TYPE}" != "f2fs" ]; then
|
||||
echo ""
|
||||
read -r -e -p "Added space for incremental updates after shrinking (MB) [0]? " ADDMB
|
||||
if [ "${ADDMB}" = "" ]; then
|
||||
ADDMB=0
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
echo -n "Create ${IMGFILE} (y/n)? "
|
||||
while read -r -n 1 -s answer; do
|
||||
if [[ "${answer}" = [yYnN] ]]; then
|
||||
echo "${answer}"
|
||||
if [[ "${answer}" = [yY] ]]; then
|
||||
break
|
||||
else
|
||||
errexit "Aborted"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [ -f "${IMGFILE}" ]; then
|
||||
rm "${IMGFILE}"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to delete existing image file"
|
||||
fi
|
||||
fi
|
||||
truncate -s $(((${IRFSSIZE} + ${BOOTSIZE}) * ${ONEMB})) "${IMGFILE}"
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to create image file"
|
||||
fi
|
||||
if [ "${PTTYPE}" = "dos" ]; then
|
||||
echo "label: dos" | sfdisk "${IMGFILE}" > /dev/null
|
||||
sfdisk "${IMGFILE}" <<EOF > /dev/null
|
||||
,${BOOTSIZE}MiB,c
|
||||
,+,83
|
||||
EOF
|
||||
else
|
||||
sgdisk -Z "${IMGFILE}" &> /dev/null
|
||||
sgdisk -n 1:0:+${BOOTSIZE}M "${IMGFILE}" &> /dev/null
|
||||
sgdisk -t 1:0700 "${IMGFILE}" > /dev/null
|
||||
sgdisk -n 2:0:0 "${IMGFILE}" &> /dev/null
|
||||
sgdisk -t 2:8300 "${IMGFILE}" > /dev/null
|
||||
gdisk "${IMGFILE}" <<EOF > /dev/null
|
||||
r
|
||||
h
|
||||
1
|
||||
n
|
||||
0c
|
||||
n
|
||||
n
|
||||
w
|
||||
y
|
||||
EOF
|
||||
fi
|
||||
mkloop
|
||||
mkfs.vfat -F 32 -n boot -s 4 "${LOOP}p1" &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to create image BOOT filesystem"
|
||||
fi
|
||||
dosfsck "${LOOP}p1" > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Image BOOT filesystem appears corrupted"
|
||||
fi
|
||||
if [ "${ROOT_TYPE}" = "f2fs" ]; then
|
||||
mkfs.f2fs "${LOOP}p2" > /dev/null
|
||||
else
|
||||
mkfs.ext4 -b 4096 -L rootfs -q "${LOOP}p2" > /dev/null
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
errexit "Unable to create image ROOT filesystem"
|
||||
fi
|
||||
rmloop
|
||||
echo ""
|
||||
echo "Starting full backup (for incremental backups, run: $0 ${IMGFILE})"
|
||||
backup
|
||||
if [ "${ROOT_TYPE}" != "f2fs" ]; then
|
||||
echo ""
|
||||
mkloop
|
||||
e2fsck -f -n "${LOOP}p2"
|
||||
if [ $? -ne 0 ]; then
|
||||
fsckerr "before"
|
||||
fi
|
||||
echo ""
|
||||
resize2fs -f -M "${LOOP}p2"
|
||||
resize2fs -f -M "${LOOP}p2"
|
||||
resize2fs -f -M "${LOOP}p2"
|
||||
e2fsck -f -n "${LOOP}p2"
|
||||
if [ $? -ne 0 ]; then
|
||||
fsckerr "after"
|
||||
fi
|
||||
INFO="$(tune2fs -l "${LOOP}p2" 2>/dev/null)"
|
||||
rmloop
|
||||
NEWSIZE=$(sed -n 's|^Block count:\s*\(.*\)|\1|p' <<< "${INFO}")
|
||||
BLKSIZE=$(sed -n 's|^Block size:\s*\(.*\)|\1|p' <<< "${INFO}")
|
||||
IMGFILE_P="${IMGFILE}"
|
||||
if [[ "${IMGFILE_P: -1}" =~ ^[[:digit:]]$ ]]; then
|
||||
IMGFILE_P+='p'
|
||||
fi
|
||||
START=$(sfdisk -d ${IMGFILE} | sed -n "s|^${IMGFILE_P}2\s\+:.*start=\s*\([0-9]\+\).*$|\1|p")
|
||||
NEWEND=$((${START} + (${NEWSIZE} * (${BLKSIZE} / 512)) + ((${ADDMB} * ${ONEMB}) / 512) - 1))
|
||||
if [ "${PTTYPE}" = "gpt" ]; then
|
||||
((NEWEND += 33))
|
||||
fi
|
||||
truncate -s $(((${NEWEND} + 1) * 512)) "${IMGFILE}"
|
||||
if [ "${PTTYPE}" = "dos" ]; then
|
||||
sfdisk --delete "${IMGFILE}" 2 > /dev/null
|
||||
echo "${START},+" | sfdisk -N2 "${IMGFILE}" &> /dev/null
|
||||
fdisk "${IMGFILE}" <<EOF > /dev/null
|
||||
x
|
||||
i
|
||||
0x${PTUUID}
|
||||
r
|
||||
w
|
||||
EOF
|
||||
else
|
||||
sgdisk -Z "${IMGFILE}" &> /dev/null
|
||||
sgdisk -n 1:0:+${BOOTSIZE}M "${IMGFILE}" &> /dev/null
|
||||
sgdisk -t 1:0700 "${IMGFILE}" > /dev/null
|
||||
sgdisk -n 2:0:0 "${IMGFILE}" &> /dev/null
|
||||
sgdisk -t 2:8300 "${IMGFILE}" > /dev/null
|
||||
sgdisk -u 1:"${PARTUUID_B}" "${IMGFILE}" > /dev/null
|
||||
sgdisk -u 2:"${PARTUUID_R}" "${IMGFILE}" > /dev/null
|
||||
sgdisk -U "${PTUUID}" "${IMGFILE}" > /dev/null
|
||||
gdisk "${IMGFILE}" <<EOF > /dev/null
|
||||
r
|
||||
h
|
||||
1
|
||||
n
|
||||
0c
|
||||
n
|
||||
n
|
||||
w
|
||||
y
|
||||
EOF
|
||||
fi
|
||||
if [ ${ADDMB} -ne 0 ]; then
|
||||
echo ""
|
||||
mkloop
|
||||
e2fsck -f -n "${LOOP}p2"
|
||||
if [ $? -ne 0 ]; then
|
||||
fsckerr "before"
|
||||
fi
|
||||
echo ""
|
||||
resize2fs -f "${LOOP}p2"
|
||||
e2fsck -f -n "${LOOP}p2"
|
||||
if [ $? -ne 0 ]; then
|
||||
fsckerr "after"
|
||||
fi
|
||||
rmloop
|
||||
fi
|
||||
fi
|
||||
mntimg
|
||||
while read DIR
|
||||
do
|
||||
touch -r "${DIR}" "${MNTPATH}${DIR}"
|
||||
done <<< "$(echo "$(rsync -aDH --dry-run --itemize-changes --partial --numeric-ids --delete --force --exclude "${MNTPATH}" --exclude '/dev' \
|
||||
--exclude '/lost+found' --exclude '/media' --exclude '/mnt' --exclude '/proc' --exclude '/run' --exclude '/sys' --exclude '/tmp' --exclude '/var/swap' \
|
||||
--exclude '/etc/udev/rules.d/70-persistent-net.rules' --exclude '/var/lib/asterisk/astdb.sqlite3-journal' "${OPTIONS[@]}" / "${MNTPATH}/")" | \
|
||||
sed -n "s|^\.d\.\.t\.\.\.\.\.\.\s\+\(.*$\)|/\1|p")"
|
||||
umntimg
|
||||
echo ""
|
||||
else
|
||||
if [[ ! "${IMGFILE}" =~ ^/mnt/.*$ && ! "${IMGFILE}" =~ ^/media/.*$ ]]; then
|
||||
errexit "${IMGFILE} does not begin with /mnt/ or /media/"
|
||||
fi
|
||||
if [ -d "${IMGFILE}" ]; then
|
||||
errexit "${IMGFILE} is a directory"
|
||||
elif [ ! -f "${IMGFILE}" ]; then
|
||||
errexit "${IMGFILE} not found"
|
||||
fi
|
||||
backup
|
||||
fi
|
||||
sync
|
37
rpi/install-ionopi.sh
Normal file
37
rpi/install-ionopi.sh
Normal file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
# script for iono-pi when starting from fresh rpi image
|
||||
sudo apt install -y git raspberrypi-kernel-headers
|
||||
git clone --depth 1 https://github.com/sfera-labs/iono-pi-kernel-module
|
||||
cd iono-pi-kernel-module
|
||||
make
|
||||
sudo make install
|
||||
dtc -@ -Hepapr -I dts -O dtb -o ionopi.dtbo ionopi.dts
|
||||
sudo cp ionopi.dtbo /boot/overlays/
|
||||
|
||||
sudo_append_to () {
|
||||
sudo bash -c "grep -qxF '$2' $1 || sudo echo '$2' >> $1"
|
||||
}
|
||||
sudo_append_to /boot/config.txt dtoverlay=ionopi
|
||||
sudo_append_to /boot/config.txt dtoverlay=i2c-rtc,mcp7941x
|
||||
sudo groupadd ionopi || true
|
||||
sudo cp 99-ionopi.rules /etc/udev/rules.d/
|
||||
sudo raspi-config nonint do_i2c 1
|
||||
sudo apt install -y i2c-tools
|
||||
sudo apt autoremove -y --purge fake-hwclock
|
||||
|
||||
# RTC clock
|
||||
sudo cp ../config-rtc-MCP79410.service /etc/systemd/system/
|
||||
sudo cp ../configrtc.sh /usr/local/bin/
|
||||
sudo chmod 744 /usr/local/bin/configrtc.sh
|
||||
sudo chown root:root /usr/local/bin/configrtc.sh
|
||||
sudo systemctl enable config-rtc-MCP79410.service
|
||||
sudo_append_to /etc/systemd/timesyncd.conf "NTP=pstime1.psi.ch pstime2.psi.ch pstime3.psi.ch"
|
||||
|
||||
echo "do the following:"
|
||||
echo ""
|
||||
echo "> sudo reboot now"
|
||||
echo ""
|
||||
echo "and, after reboot set RTC time and check it is working"
|
||||
echo ""
|
||||
echo "> sudo hwclock -w"
|
||||
echo "> timedatectl status"
|
37
rpi/install-ionopimax.sh
Normal file
37
rpi/install-ionopimax.sh
Normal file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
# script for iono-pi when starting from fresh rpi image
|
||||
sudo apt install -y git raspberrypi-kernel-headers
|
||||
git clone --depth 1 https://github.com/sfera-labs/iono-pi-max-kernel-module
|
||||
cd iono-pi-max-kernel-module
|
||||
make
|
||||
sudo make install
|
||||
dtc -@ -Hepapr -I dts -O dtb -o ionopimax.dtbo ionopimax.dts
|
||||
sudo cp ionopimax.dtbo /boot/overlays/
|
||||
|
||||
sudo_append_to () {
|
||||
sudo bash -c "grep -qxF '$2' $1 || sudo echo '$2' >> $1"
|
||||
}
|
||||
sudo_append_to /boot/config.txt dtoverlay=ionopimax
|
||||
sudo_append_to /boot/config.txt dtoverlay=i2c-rtc,mcp7941x
|
||||
sudo groupadd ionopimax || true
|
||||
sudo cp 99-ionopimax.rules /etc/udev/rules.d/
|
||||
sudo raspi-config nonint do_i2c 1
|
||||
sudo apt install -y i2c-tools
|
||||
sudo apt autoremove -y --purge fake-hwclock
|
||||
|
||||
# RTC clock
|
||||
sudo cp ../config-rtc-MCP79410.service /etc/systemd/system/
|
||||
sudo cp ../configrtc.sh /usr/local/bin/
|
||||
sudo chmod 744 /usr/local/bin/configrtc.sh
|
||||
sudo chown root:root /usr/local/bin/configrtc.sh
|
||||
sudo systemctl enable config-rtc-MCP79410.service
|
||||
sudo_append_to /etc/systemd/timesyncd.conf "NTP=pstime1.psi.ch pstime2.psi.ch pstime3.psi.ch"
|
||||
|
||||
echo "do the following:"
|
||||
echo ""
|
||||
echo "> sudo reboot now"
|
||||
echo ""
|
||||
echo "and, after reboot set RTC time and check it is working"
|
||||
echo ""
|
||||
echo "> sudo hwclock -w"
|
||||
echo "> timedatectl status"
|
161
rpi/write_to
Executable file
161
rpi/write_to
Executable file
@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
from select import select
|
||||
from glob import glob
|
||||
from subprocess import check_output, STDOUT, PIPE, Popen, TimeoutExpired
|
||||
|
||||
IMAGES_HOST = 'l_samenv@samenv'
|
||||
IMAGES_DIR = 'boxes/rpi_images'
|
||||
IMAGES_PAT = '*.lz4'
|
||||
|
||||
extdisks = {}
|
||||
|
||||
|
||||
def prt(text):
|
||||
print(time.strftime('%H:%M:%S'), text)
|
||||
|
||||
|
||||
def cmd(command, verbose=False):
|
||||
if verbose:
|
||||
print(f'> {command}')
|
||||
return check_output(command.split(), stderr=STDOUT).decode('latin-1')
|
||||
|
||||
|
||||
def find_raspi(kind):
|
||||
# collect info about disks
|
||||
dlist = '\n' + cmd('/usr/sbin/diskutil list')
|
||||
extdisks.clear()
|
||||
proposed = []
|
||||
noname = re.compile(r' +0: +\*\d+\.?\d* GB +disk')
|
||||
for dinfo in dlist.split('\n/dev/'):
|
||||
if not dinfo:
|
||||
continue
|
||||
disk, info = dinfo.split(maxsplit=1)
|
||||
if 'external' in info.split('\n')[0]:
|
||||
extdisks[disk] = info
|
||||
if kind == 'emmc':
|
||||
if 'Windows_FAT_32 bootfs' in info and 'Linux' in info:
|
||||
proposed.append(disk)
|
||||
elif noname.search(info):
|
||||
proposed.append(disk)
|
||||
elif kind == 'sd':
|
||||
if 'Apple' not in info:
|
||||
proposed.append(disk)
|
||||
return proposed
|
||||
|
||||
|
||||
def rpiboot():
|
||||
if os.path.exists('/Volumes/bootfs'):
|
||||
prt('unmount bootfs')
|
||||
os.system('diskutil unmount bootfs')
|
||||
lines = []
|
||||
with Popen(['rpiboot'], stdout=PIPE) as p:
|
||||
tmo = 1
|
||||
t = 0
|
||||
while select([p.stdout], [], [], tmo)[0]:
|
||||
rawline = p.stdout.readline()
|
||||
if not rawline:
|
||||
return tmo != 1
|
||||
line = rawline.decode('latin-1').strip()
|
||||
if lines is None:
|
||||
print(line)
|
||||
elif 'Waiting' in line:
|
||||
tmo = 2
|
||||
lines.append(line)
|
||||
t = time.time()
|
||||
elif tmo == 1:
|
||||
lines.append(line)
|
||||
else:
|
||||
print('\n'.join(lines))
|
||||
print(line)
|
||||
lines = None
|
||||
else:
|
||||
p.terminate()
|
||||
return False
|
||||
|
||||
|
||||
def list_external():
|
||||
print('--- external disks:')
|
||||
for disk, info in extdisks.items():
|
||||
print(disk, info)
|
||||
|
||||
|
||||
rescue = """
|
||||
Remark: not all cables might work.
|
||||
Example on Markus Mac:
|
||||
- does not work: black USB C to USB C cable
|
||||
- works: white USB A to USB C cable plugged into docking station.
|
||||
|
||||
Please unpower the box with compute module,
|
||||
start this script again and put power immediately."""
|
||||
|
||||
def write_image(kind):
|
||||
if kind == 'eemc':
|
||||
print("\nmake sure microUSB 'SLAVE' is connected to this computer")
|
||||
print("and microUSB 'POWER' is connected to a USB power supply\n")
|
||||
prt('try to find CM (compute module on PoE device) ...')
|
||||
else:
|
||||
pass
|
||||
proposed = find_raspi(kind)
|
||||
if not proposed and kind == 'emmc':
|
||||
# we may install rpiboot here if not available
|
||||
# git clone --depth=1 https://github.com/raspberrypi/usbboot
|
||||
# cd usbboot
|
||||
# make
|
||||
# ./rpiboot
|
||||
|
||||
print('not found - put rpi in bootloader mode')
|
||||
if not rpiboot() and not rpiboot():
|
||||
print(rescue)
|
||||
return
|
||||
for _ in range(10):
|
||||
proposed = find_raspi(kind)
|
||||
if proposed:
|
||||
break
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
list_external()
|
||||
print('can not find CM')
|
||||
return
|
||||
list_external()
|
||||
if len(proposed) > 1:
|
||||
if kind == 'emmc':
|
||||
print('several potential devices for CM:', proposed)
|
||||
return
|
||||
dev = input('select device to write to {" ".join(proposed)}: ')
|
||||
else:
|
||||
dev = proposed[0]
|
||||
images = check_output(['sudo', '-u', 'zolliker', 'ssh', IMAGES_HOST, f'cd {IMAGES_DIR} ; ls {IMAGES_PAT}']).decode('latin-1').split('\n')
|
||||
for file in sorted(images):
|
||||
print(file)
|
||||
print('')
|
||||
image = input(f'select image to write to {dev} [{file}]: ') or file
|
||||
prt(f'unmount {dev} ...')
|
||||
print('you may be prompted for your account password for sudo')
|
||||
os.system(f'sudo diskutil unmountDisk /dev/{dev}')
|
||||
print('')
|
||||
prt('get, uncompress and write... (takes about 15 min)')
|
||||
os.system(f'ssh {IMAGES_HOST} "dd if={IMAGES_DIR}/{image} bs=512k" | lz4 -d | sudo dd of=/dev/{dev} bs=512k')
|
||||
prt('unmount bootfs')
|
||||
for _ in range(3):
|
||||
if os.path.exists('/Volumes/bootfs'):
|
||||
prt('unmount bootfs')
|
||||
os.system('diskutil unmount bootfs')
|
||||
break
|
||||
time.sleep(1.0)
|
||||
prt('done')
|
||||
os.system(f'diskutil unmountDisk /dev/{dev}')
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
write_image(sys.argv[1])
|
||||
else:
|
||||
print("""
|
||||
Usage:
|
||||
|
||||
> write_to emmc # write to compute module using PoE board"
|
||||
> write_to sd # write to sd card
|
||||
|
||||
""")
|
Reference in New Issue
Block a user