Last active
August 29, 2015 14:19
-
-
Save pipcet/8a6fc304e66a83ff2b03 to your computer and use it in GitHub Desktop.
Debian root-on-diod-over-IPv6 scripts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
These are scripts for setting up a Debian (sid) root file system on a diod (http://github.com/chaos/diod) server using IPv6 only—no IPv4 IP required. This requires some minor modifications, but with one exception, the initramfs-tools(8) toolchain that ships with Debian works. | |
The main work is done in the kernel command line (which is actually parsed by the initramfs's init script). It should look like this: | |
[ 0.000000] Kernel command line: boot=9p ip=dhcpv6 rootfstype=diod root=server:/path | |
boot=9p includes the right script for dealing with 9p-specific boot setup; ip=dhcpv6 runs dhclient -6 rather than ipconfig to configure our network interface; rootfstype=diod runs the right fs helper, and root=server:/path is the path specification for diod. (You can use a DNS name, but you cannot currently use an IPv6 IP without modifying diodmount. Currently, you have to use an absolute path.). | |
Modifications necessary: | |
--- .../usr/share/initramfs-tools/scripts/functions 2015-04-12 23:56:58.000000000 +0000 | |
+++ .../usr/share/initramfs-tools/scripts/functions 2015-04-17 12:11:29.758149255 +0000 | |
@@ -106,6 +106,9 @@ | |
/*) | |
return | |
;; | |
+ *:/*) | |
+ return | |
+ ;; | |
[0-9]*:[0-9]*) | |
minor=$(( ${1#*:} )) | |
major=$(( ${1%:*} )) | |
@@ -222,6 +225,12 @@ | |
dhcp|bootp|rarp|both) | |
ipconfig -t ${ROUNDTTT} -c ${IP} -d "${DEVICE}" | |
;; | |
+ dhcpv6) | |
+ mkdir -p /var/lib/dhcp | |
+ sleep 1 | |
+ dhclient -6 -v "eth0" # XXX don't hardcode eth0 | |
+ [ -e "/etc/resolv.conf" ] && touch /run/net-"eth0".conf | |
+ ;; | |
*) | |
ipconfig -t ${ROUNDTTT} -d $IP | |
The first modification avoids parsing server:/path as a numeric device ID. (It's actually only necessary if you use a server name that starts with a hexadecimal digit.) The second modification runs dhclient in lieu of ipconfig to set up an IPv6 IP, and DNS resolution, for interface eth0. | |
I'm using these scripts with qemu virtual machines, but there is no reason I can think of they shouldn't work with physical machines as well. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# this file is supposed to be named /etc/initramfs-tools/hooks/9p | |
PREREQ="" | |
prereqs() | |
{ | |
echo "$PREREQ" | |
} | |
case $1 in | |
prereqs) | |
prereqs | |
exit 0 | |
;; | |
esac | |
. /usr/share/initramfs-tools/scripts/functions | |
. /usr/share/initramfs-tools/hook-functions | |
copy_exec /sbin/mount.diod | |
copy_exec /usr/sbin/diodmount | |
copy_exec /sbin/dhclient | |
copy_exec /sbin/dhclient-script | |
copy_exec /lib/x86_64-linux-gnu/libnss_compat.so.2 | |
copy_exec /lib/x86_64-linux-gnu/libnss_dns.so.2 | |
copy_exec /lib/x86_64-linux-gnu/libnss_files.so.2 | |
copy_exec /lib/x86_64-linux-gnu/libnss_nis.so.2 | |
copy_exec /lib/x86_64-linux-gnu/libpam.so.0 | |
copy_exec /lib/x86_64-linux-gnu/libresolv.so.2 | |
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 9P filesystem mounting -*- shell-script -*- | |
# this file is supposed to be named /etc/initramfs-tools/scripts/9p | |
v9p_top() | |
{ | |
if [ "${v9p_top_used}" != "yes" ]; then | |
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/9p-top" | |
run_scripts /scripts/9p-top | |
[ "$quiet" != "y" ] && log_end_msg | |
fi | |
v9p_top_used=yes | |
} | |
v9p_premount() | |
{ | |
if [ "${v9p_premount_used}" != "yes" ]; then | |
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/9p-premount" | |
run_scripts /scripts/9p-premount | |
[ "$quiet" != "y" ] && log_end_msg | |
fi | |
v9p_premount_used=yes | |
} | |
v9p_bottom() | |
{ | |
if [ "${v9p_premount_used}" = "yes" ] || [ "${v9p_top_used}" = "yes" ]; then | |
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/9p-bottom" | |
run_scripts /scripts/9p-bottom | |
[ "$quiet" != "y" ] && log_end_msg | |
fi | |
v9p_premount_used=no | |
v9p_top_used=no | |
} | |
# parse v9p bootargs and mount v9p | |
v9p_mount_root_impl() | |
{ | |
configure_networking | |
if [ ${readonly} = y ]; then | |
roflag="-o ro" | |
else | |
roflag="-o rw" | |
fi | |
echo root:x:0:0:root:/root:/bin/bash > /etc/passwd | |
mount -n -t diod ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt} | |
} | |
# V9P root mounting | |
v9p_mount_root() | |
{ | |
v9p_top | |
modprobe 9p | |
# For DHCP | |
modprobe af_packet | |
wait_for_udev 10 | |
# Default delay is around 180s | |
delay=${ROOTDELAY:-180} | |
# loop until v9pmount succeeds | |
v9p_mount_root_impl | |
v9p_retry_count=0 | |
while [ ${v9p_retry_count} -lt ${delay} ] \ | |
&& ! chroot "${rootmnt}" test -x "${init}" ; do | |
[ "$quiet" != "y" ] && log_begin_msg "Retrying 9p mount" | |
/bin/sleep 1 | |
v9p_mount_root_impl | |
v9p_retry_count=$(( ${v9p_retry_count} + 1 )) | |
[ "$quiet" != "y" ] && log_end_msg | |
done | |
} | |
mountroot() | |
{ | |
v9p_mount_root | |
} | |
mount_top() | |
{ | |
# Note, also called directly in case it's overridden. | |
v9p_top | |
} | |
mount_premount() | |
{ | |
# Note, also called directly in case it's overridden. | |
v9p_premount | |
} | |
mount_bottom() | |
{ | |
# Note, also called directly in case it's overridden. | |
v9p_bottom | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- shell-script -*- | |
# this file is supposed to be named /usr/share/initramfs-tools/scripts/functions, replacing the Debian-provided version | |
_log_msg() | |
{ | |
if [ "$quiet" = "y" ]; then return; fi | |
printf "$@" | |
} | |
log_success_msg() | |
{ | |
_log_msg "Success: $@\n" | |
} | |
log_failure_msg() | |
{ | |
_log_msg "Failure: $@\n" | |
} | |
log_warning_msg() | |
{ | |
_log_msg "Warning: $@\n" | |
} | |
log_begin_msg() | |
{ | |
_log_msg "Begin: $@ ... " | |
} | |
log_end_msg() | |
{ | |
_log_msg "done.\n" | |
} | |
panic() | |
{ | |
if command -v chvt >/dev/null 2>&1; then | |
chvt 1 | |
fi | |
echo "$@" | |
# Disallow console access | |
if [ -n "${panic}" ]; then | |
echo "Rebooting automatically due to panic= boot argument" | |
sleep ${panic} | |
reboot | |
exit # in case reboot fails, force kernel panic | |
fi | |
modprobe -v i8042 || true | |
modprobe -v atkbd || true | |
modprobe -v ehci-pci || true | |
modprobe -v ehci-orion || true | |
modprobe -v ehci-hcd || true | |
modprobe -v uhci-hcd || true | |
modprobe -v ohci-hcd || true | |
modprobe -v usbhid || true | |
REASON="$@" PS1='(initramfs) ' /bin/sh -i </dev/console >/dev/console 2>&1 | |
} | |
maybe_break() | |
{ | |
if [ "${break:-}" = "$1" ]; then | |
panic "Spawning shell within the initramfs" | |
fi | |
} | |
render() | |
{ | |
eval "echo -n \${$@}" | |
} | |
# For boot time only; this is overridden at build time in hook-functions | |
run_scripts() | |
{ | |
initdir=${1} | |
[ ! -d ${initdir} ] && return | |
shift | |
. ${initdir}/ORDER | |
} | |
# Load custom modules first | |
load_modules() | |
{ | |
if [ -e /conf/modules ]; then | |
cat /conf/modules | while read m; do | |
# Skip empty lines | |
if [ -z "$m" ]; then | |
continue | |
fi | |
# Skip comments - d?ash removes whitespace prefix | |
com=$(printf "%.1s" "${m}") | |
if [ "$com" = "#" ]; then | |
continue | |
fi | |
modprobe $m | |
done | |
fi | |
} | |
# lilo compatibility | |
parse_numeric() { | |
case $1 in | |
"") | |
return | |
;; | |
/*) | |
return | |
;; | |
*:/*) | |
return | |
;; | |
[0-9]*:[0-9]*) | |
minor=$(( ${1#*:} )) | |
major=$(( ${1%:*} )) | |
;; | |
[A-Fa-f0-9]*) | |
value=$(( 0x${1} )) | |
minor=$(( ${value} % 256 )) | |
major=$(( ${value} / 256 )) | |
;; | |
*) | |
return | |
;; | |
esac | |
if command -v udevd >/dev/null 2>&1; then | |
ROOT=/dev/block/${major}:${minor} | |
else | |
mknod -m 600 /dev/root b ${major} ${minor} | |
ROOT=/dev/root | |
fi | |
} | |
# Parameter: device node to check | |
# Echos fstype to stdout | |
# Return value: indicates if an fs could be recognized | |
get_fstype () | |
{ | |
local FS FSTYPE FSSIZE RET | |
FS="${1}" | |
# blkid has a more complete list of file systems, | |
# but fstype is more robust | |
FSTYPE="unknown" | |
eval $(fstype "${FS}" 2> /dev/null) | |
if [ "$FSTYPE" = "unknown" ] && command -v blkid >/dev/null 2>&1 ; then | |
FSTYPE=$(blkid -o value -s TYPE "${FS}") | |
elif [ "$FSTYPE" = "unknown" ] && [ -x /lib/udev/vol_id ]; then | |
FSTYPE=$(/lib/udev/vol_id -t "${FS}" 2> /dev/null) | |
fi | |
RET=$? | |
if [ -z "${FSTYPE}" ]; then | |
FSTYPE="unknown" | |
fi | |
echo "${FSTYPE}" | |
return ${RET} | |
} | |
configure_networking() | |
{ | |
if [ -n "${BOOTIF}" ]; then | |
# pxelinux sets BOOTIF to a value based on the mac address of the | |
# network card used to PXE boot, so use this value for DEVICE rather | |
# than a hard-coded device name from initramfs.conf. this facilitates | |
# network booting when machines may have multiple network cards. | |
# pxelinux sets BOOTIF to 01-$mac_address | |
# strip off the leading "01-", which isn't part of the mac | |
# address | |
temp_mac=${BOOTIF#*-} | |
# convert to typical mac address format by replacing "-" with ":" | |
bootif_mac="" | |
IFS='-' | |
for x in $temp_mac ; do | |
if [ -z "$bootif_mac" ]; then | |
bootif_mac="$x" | |
else | |
bootif_mac="$bootif_mac:$x" | |
fi | |
done | |
unset IFS | |
# look for devices with matching mac address, and set DEVICE to | |
# appropriate value if match is found. | |
for device in /sys/class/net/* ; do | |
if [ -f "$device/address" ]; then | |
current_mac=$(cat "$device/address") | |
if [ "$bootif_mac" = "$current_mac" ]; then | |
DEVICE=${device##*/} | |
break | |
fi | |
fi | |
done | |
fi | |
# networking already configured thus bail out | |
[ -n "${DEVICE}" ] && [ -e /run/net-"${DEVICE}".conf ] && return 0 | |
wait_for_udev 10 | |
# support ip options see linux sources | |
# Documentation/filesystems/nfs/nfsroot.txt | |
# Documentation/frv/booting.txt | |
for ROUNDTTT in 2 3 4 6 9 16 25 36 64 100; do | |
# The NIC is to be configured if this file does not exist. | |
# Ip-Config tries to create this file and when it succeds | |
# creating the file, ipconfig is not run again. | |
for x in /run/net-"${DEVICE}".conf /run/net-*.conf ; do | |
[ -e "$x" ] && break 2 | |
done | |
case ${IP} in | |
none|off) | |
# Do nothing | |
;; | |
""|on|any) | |
# Bring up device | |
ipconfig -t ${ROUNDTTT} "${DEVICE}" | |
;; | |
dhcp|bootp|rarp|both) | |
ipconfig -t ${ROUNDTTT} -c ${IP} -d "${DEVICE}" | |
;; | |
dhcpv6) | |
mkdir -p /var/lib/dhcp | |
sleep 1 | |
dhclient -6 -v "eth0" # XXX don't hardcode eth0 | |
[ -e "/etc/resolv.conf" ] && touch /run/net-"eth0".conf | |
;; | |
*) | |
ipconfig -t ${ROUNDTTT} -d $IP | |
# grab device entry from ip option | |
NEW_DEVICE=${IP#*:*:*:*:*:*} | |
if [ "${NEW_DEVICE}" != "${IP}" ]; then | |
NEW_DEVICE=${NEW_DEVICE%%:*} | |
else | |
# wrong parse, possibly only a partial string | |
NEW_DEVICE= | |
fi | |
if [ -n "${NEW_DEVICE}" ]; then | |
DEVICE="${NEW_DEVICE}" | |
fi | |
;; | |
esac | |
done | |
# source ipconfig output | |
if [ -n "${DEVICE}" ]; then | |
# source specific bootdevice | |
. /run/net-${DEVICE}.conf | |
else | |
# source any interface... | |
# ipconfig should have quit after first response | |
. /run/net-*.conf | |
fi | |
} | |
# Wait for queued kernel/udev events | |
wait_for_udev() | |
{ | |
command -v udevadm >/dev/null 2>&1 || return 0 | |
udevadm settle ${1:+--timeout=$1} | |
} | |
# Find a specific fstab entry | |
# $1=mountpoint | |
# $2=fstype (optional) | |
# returns 0 on success, 1 on failure (not found or no fstab) | |
read_fstab_entry() { | |
# Not found by default. | |
found=1 | |
for file in ${rootmnt}/etc/fstab; do | |
if [ -f "$file" ]; then | |
while read MNT_FSNAME MNT_DIR MNT_TYPE MNT_OPTS MNT_FREQ MNT_PASS MNT_JUNK; do | |
case "$MNT_FSNAME" in | |
""|\#*) | |
continue; | |
;; | |
esac | |
if [ "$MNT_DIR" = "$1" ]; then | |
if [ -n "$2" ]; then | |
[ "$MNT_TYPE" = "$2" ] || continue; | |
fi | |
found=0 | |
break 2 | |
fi | |
done < "$file" | |
fi | |
done | |
return $found | |
} | |
# Resolve device node from a name. This expands any LABEL or UUID. | |
# $1=name | |
# Resolved name is echoed. | |
resolve_device() { | |
DEV="$1" | |
case $DEV in | |
LABEL=*) | |
DEV="${DEV#LABEL=}" | |
# support any / in LABEL= path (escape to \x2f) | |
case "${DEV}" in | |
*/*) | |
if command -v sed >/dev/null 2>&1; then | |
DEV="$(echo ${DEV} | sed 's,/,\\x2f,g')" | |
else | |
if [ "${DEV}" != "${DEV#/}" ]; then | |
DEV="\x2f${DEV#/}" | |
fi | |
if [ "${DEV}" != "${DEV%/}" ]; then | |
DEV="${DEV%/}\x2f" | |
fi | |
IFS='/' | |
newroot= | |
for s in $DEV; do | |
newroot="${newroot:+${newroot}\\x2f}${s}" | |
done | |
unset IFS | |
DEV="${newroot}" | |
fi | |
esac | |
DEV="/dev/disk/by-label/${DEV}" | |
;; | |
UUID=*) | |
DEV="/dev/disk/by-uuid/${DEV#UUID=}" | |
;; | |
esac | |
# Only canonicalise if a valid file, in case $DEV isn't a filename | |
[ -e "$DEV" ] && DEV=$(readlink -f "$DEV") | |
echo "$DEV" | |
} | |
# Check a file system. | |
# $1=device | |
# $2=mountpoint (for diagnostics only) | |
_checkfs_once() | |
{ | |
DEV="$1" | |
NAME="$2" | |
if [ "$NAME" = "/" ] ; then | |
NAME="root" | |
fi | |
FSCK_LOGFILE=/run/initramfs/fsck.log | |
FSCK_STAMPFILE=/run/initramfs/fsck-${NAME#/} | |
TYPE=$(get_fstype "$1") | |
FSCKCODE=0 | |
if [ "$fastboot" = "y" ] ; then | |
log_warning_msg "Fast boot enabled, so skipping $NAME file system check." | |
return | |
fi | |
if [ "$forcefsck" = "y" ] | |
then | |
force="-f" | |
else | |
force="" | |
fi | |
if [ "$fsckfix" = yes ] | |
then | |
fix="-y" | |
else | |
fix="-a" | |
fi | |
# spinner="-C" -- only if on an interactive terminal | |
spinner="" | |
if [ "$VERBOSE" = no ] | |
then | |
log_begin_msg "Will now check $NAME file system" | |
logsave -a -s $FSCK_LOGFILE fsck $spinner $force $fix -V -t $TYPE $DEV | |
FSCKCODE=$? | |
log_end_msg | |
else | |
log_begin_msg "Checking $NAME file system" | |
logsave -a -s $FSCK_LOGFILE fsck $spinner $force $fix -t $TYPE $DEV | |
FSCKCODE=$? | |
log_end_msg | |
fi | |
# NOTE: "failure" is defined as exiting with a return code of | |
# 4, possibly or-ed with other flags. A return code of 1 | |
# indicates that file system errors were corrected but that | |
# the boot may proceed. | |
# | |
if [ "$FSCKCODE" -eq 32 ] | |
then | |
log_warning_msg "File system check was interrupted by user" | |
elif [ $((FSCKCODE & 4)) -eq 4 ] | |
then | |
log_failure_msg "File system check of the $NAME filesystem failed" | |
return 1 | |
elif [ "$FSCKCODE" -gt 1 ] | |
then | |
log_warning_msg "File system check failed but did not detect errors" | |
sleep 5 | |
else | |
touch $FSCK_STAMPFILE | |
fi | |
return 0 | |
} | |
checkfs() | |
{ | |
while ! _checkfs_once "$@"; do | |
panic "The $2 filesystem on $1 requires a manual fsck" | |
done | |
} | |
# Mount a file system. We parse the information from the fstab. This | |
# should be overridden by any boot script which can mount arbitrary | |
# filesystems such as /usr. This default implementation delegates to | |
# local or nfs based upon the filesystem type. | |
# $1=mountpoint mount location | |
mountfs() | |
{ | |
type=local | |
read_fstab_entry "$1" | |
if [ "${MNT_TYPE}" = "nfs" ] || [ "${MNT_TYPE}" = "nfs4" ]; then | |
type=nfs | |
fi | |
${type}_mount_fs "$1" | |
} | |
# Mount the root file system. It should be overridden by all | |
# boot scripts. | |
mountroot() | |
{ | |
: | |
} | |
# Run /scripts/${boot}-top. This should be overridden by all boot | |
# scripts. | |
mount_top() | |
{ | |
: | |
} | |
# Run /scripts/${boot}-premount. This should be overridden by all boot | |
# scripts. | |
mount_premount() | |
{ | |
: | |
} | |
# Run /scripts/${boot}-bottom. This should be overridden by all boot | |
# scripts. | |
mount_bottom() | |
{ | |
: | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment