├── .gitignore ├── LICENSE ├── README ├── build.sh ├── docker ├── Dockerfile ├── Dockerfile.aarch64 └── init.sh ├── files └── etc │ ├── board.d │ ├── 90-set_hostname │ └── 99-default_network │ ├── init.d │ └── container_init │ ├── inittab │ └── uci-defaults │ └── 70_fill-dhcp-checksum ├── patches ├── procd-lede-17.01 │ ├── 001_lxd_no_mounts.patch │ └── 002_lxd_signal_halt.patch ├── procd-master │ └── .gitkeep ├── procd-openwrt-18.06 │ ├── 0001-lxd-no-mounts.patch │ ├── 0002-lxd-shutdown-on-SIGPWR.patch │ └── 0003-docker-fix-problem-stopping-container.patch ├── procd-openwrt-19.07 └── procd-snapshot ├── scripts ├── build_rootfs.sh ├── sync_patches.sh └── upgrade.py └── templates └── hostname.tpl /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | build_dir/ 3 | dl/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mikael Magnusson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | lxd-openwrt 2 | =========== 3 | 4 | Scripts for building LXD images from OpenWrt rootfs tarballs. The OpenWrt SDK is used to build a patched procd package. 5 | 6 | Requirements 7 | ------------ 8 | It's recommended you use Debian or Ubuntu on the build system. The following additional packages are required on Ubuntu 18.04: 9 | 10 | * fakeroot 11 | 12 | Configuration 13 | ------------- 14 | Refer to the top of build.sh. 15 | 16 | Usage 17 | ----- 18 | ./build.sh [-a|--arch x86_64|i686|aarch64] [-v|--version ] [-p|--packages ] [-f|--files] [-t|--type lxd|plain] [-s|--super fakeroot|sudo] [-u|--upgrade] [--help] 19 | 20 | Example 21 | ------- 22 | ./build.sh 23 | lxc image import bin/openwrt-*-lxd.tar.gz --alias openwrt 24 | lxc launch openwrt router 25 | lxc exec router passwd root 26 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | arch_lxd=x86_64 6 | ver=22.03.5 7 | dist=openwrt 8 | type=lxd 9 | super=fakeroot 10 | # iptables-mod-checksum is required by the work-around inserted by files/etc/uci-defaults/70_fill-dhcp-checksum. 11 | packages=iptables-mod-checksum 12 | upgrade= 13 | 14 | # Workaround for Debian/Ubuntu systems which use C.UTF-8 which is unsupported by OpenWrt 15 | export LC_ALL=C 16 | 17 | usage() { 18 | echo "Usage: $0 [-a|--arch x86_64|i686|aarch64|aarch32] [-v|--version ] [-p|--packages ] [-f|--files] [-t|--type lxd|plain] [-s|--super fakeroot|sudo] [-u|--upgrade] [--help]" 19 | exit 1 20 | } 21 | 22 | temp=$(getopt -o "a:v:p:f:t:s:u" -l "arch:,version:,packages:,files:,type:,super:,upgrade,help" -- "$@") 23 | eval set -- "$temp" 24 | while true; do 25 | case "$1" in 26 | -a|--arch) 27 | arch_lxd="$2"; shift 2;; 28 | -v|--version) 29 | ver="$2"; shift 2;; 30 | -p|--packages) 31 | packages="$2"; shift 2;; 32 | -f|--files) 33 | files="$2"; shift 2;; 34 | -t|--type) 35 | type="$2" 36 | shift 2 37 | 38 | case "$type" in 39 | lxd|plain) 40 | ;; 41 | *) 42 | usage;; 43 | esac;; 44 | -s|--super) 45 | super="$2" 46 | shift 2 47 | 48 | case "$super" in 49 | fakeroot|sudo) 50 | ;; 51 | *) 52 | usage;; 53 | esac;; 54 | -u|--upgrade) 55 | upgrade="1" 56 | shift 1 57 | ;; 58 | --help) 59 | usage;; 60 | --) 61 | shift; break;; 62 | esac 63 | done 64 | 65 | if [ $# -ne 0 ]; then 66 | usage 67 | fi 68 | 69 | case "$arch_lxd" in 70 | i686) 71 | arch=x86 72 | subarch=generic 73 | arch_ipk=i386_pentium4 74 | ;; 75 | x86_64) 76 | arch=x86 77 | subarch=64 78 | arch_ipk=x86_64 79 | ;; 80 | aarch64) 81 | arch=armvirt 82 | subarch=64 83 | arch_ipk=aarch64_generic 84 | ;; 85 | aarch32) 86 | arch=armvirt 87 | subarch=32 88 | arch_ipk=aarch32_generic 89 | ;; 90 | *) 91 | usage 92 | ;; 93 | esac 94 | 95 | branch_ver=$(echo "${ver}"|cut -d- -f1|cut -d. -f1,2) 96 | 97 | if test $ver = snapshot; then 98 | openwrt_branch=snapshot 99 | procd_url=https://github.com/openwrt/openwrt/trunk/package/system/procd 100 | openwrt_url=https://downloads.openwrt.org/snapshots/targets/${arch}/${subarch} 101 | else 102 | openwrt_branch=${dist}-${branch_ver} 103 | procd_url=https://github.com/openwrt/openwrt/branches/${openwrt_branch}/package/system/procd 104 | openwrt_url=https://downloads.openwrt.org/releases/${ver}/targets/${arch}/${subarch} 105 | fi 106 | 107 | procd_extra_ver=lxd-3 108 | 109 | tarball=bin/${dist}-${ver}-${arch}-${subarch}-${type}.tar.gz 110 | metadata=bin/metadata.yaml 111 | pkgdir=bin/${ver}/packages/${arch}/${subarch} 112 | 113 | detect_url() { 114 | local pattern="$1" 115 | download_sums ${openwrt_url}/dummy 116 | local sums=$return 117 | return=$(cat $sums|grep "$pattern"|cut -d' ' -f2-|cut -c2-) 118 | if [ -z "$return" ]; then 119 | echo "URL autodetection failed: $pattern" 120 | exit 1 121 | fi 122 | } 123 | 124 | download_rootfs() { 125 | detect_url "rootfs\.tar" 126 | local rootfs_url=$openwrt_url/$return 127 | 128 | # global $rootfs 129 | rootfs=dl/$(basename $rootfs_url) 130 | 131 | download $rootfs_url $rootfs 132 | check $rootfs $rootfs_url 133 | } 134 | 135 | download_sdk() { 136 | detect_url "sdk" 137 | local sdk_url=$openwrt_url/$return 138 | local sdk_tar=dl/$(basename $sdk_url) 139 | 140 | download $sdk_url $sdk_tar 141 | check $sdk_tar $sdk_url 142 | 143 | # global $sdk 144 | sdk="build_dir/$(tar tf $sdk_tar|head -1)" 145 | 146 | if ! test -e $sdk; then 147 | test -e build_dir || mkdir build_dir 148 | tar xvf $sdk_tar -C build_dir 149 | fi 150 | } 151 | 152 | download() { 153 | url=$1 154 | dst=$2 155 | dir=$(dirname $dst) 156 | 157 | if ! test -e "$dst" ; then 158 | echo Downloading $url 159 | test -e $dir || mkdir $dir 160 | 161 | wget -O $dst "$url" 162 | fi 163 | } 164 | 165 | download_sums() { 166 | local url=$1 167 | 168 | local sums_url="$(dirname $url)/sha256sums" 169 | local sums_file="dl/sha256sums_$(echo $sums_url|md5sum|cut -d ' ' -f 1)" 170 | 171 | if ! test -e $sums_file; then 172 | test -e "dl" || mkdir "dl" 173 | wget -O $sums_file $sums_url 174 | fi 175 | 176 | return=$sums_file 177 | } 178 | 179 | check() { 180 | local dst=$1 181 | local dst_url=$2 182 | 183 | download_sums $dst_url 184 | local sums=$return 185 | 186 | local dst_sum="$(grep $(basename $dst_url) $sums|cut -d ' ' -f 1)" 187 | 188 | sum=$(sha256sum $dst| cut -d ' ' -f1) 189 | if test -z "$dst_sum" -o "$dst_sum" != $sum; then 190 | echo Bad checksum $sum of $dst 191 | exit 1 192 | fi 193 | } 194 | 195 | need_procd() { 196 | if ls patches/procd-${openwrt_branch}/*.patch 2>/dev/null >/dev/null; then 197 | return 0 198 | else 199 | return 1 200 | fi 201 | } 202 | 203 | download_procd() { 204 | if ! test -e dl/procd-${openwrt_branch}; then 205 | svn export $procd_url dl/procd-${openwrt_branch} 206 | sed -i -e "s/PKG_RELEASE:=\(\S\+\)/PKG_RELEASE:=\1-${procd_extra_ver}/" dl/procd-${openwrt_branch}/Makefile 207 | fi 208 | 209 | test -e dl/procd-${openwrt_branch}/patches || mkdir dl/procd-${openwrt_branch}/patches 210 | cp -a patches/procd-${openwrt_branch}/*.patch dl/procd-${openwrt_branch}/patches 211 | } 212 | 213 | build_procd() { 214 | rm $sdk/package/lxd-procd||true 215 | ln -sfT $(pwd)/dl/procd-${openwrt_branch} $sdk/package/lxd-procd 216 | 217 | local date=$(grep PKG_SOURCE_DATE:= dl/procd-${openwrt_branch}/Makefile | cut -d '=' -f 2) 218 | local version=$(grep PKG_SOURCE_VERSION:= dl/procd-${openwrt_branch}/Makefile | cut -d '=' -f 2 | cut -b '1-8') 219 | local release=$(grep PKG_RELEASE:= dl/procd-${openwrt_branch}/Makefile | cut -d '=' -f 2) 220 | local ipk_old=$sdk/bin/targets/${arch}/${subarch}/packages/procd_${date}-${version}-${release}_*.ipk 221 | local ipk_new=$sdk/bin/packages/${arch_ipk}/base/procd_${date}-${version}-${release}_*.ipk 222 | 223 | if test $ver \< 18; then 224 | local ipk=$ipk_old 225 | else 226 | local ipk=$ipk_new 227 | fi 228 | 229 | if ! test -s $ipk; then 230 | (cd $sdk && 231 | ./scripts/feeds update base && 232 | ./scripts/feeds install libubox && test -d package/feeds/base/libubox && 233 | ./scripts/feeds install ubus && test -d package/feeds/base/ubus && 234 | make defconfig && 235 | make package/lxd-procd/compile 236 | ) 237 | fi 238 | test -e ${pkgdir} || mkdir -p ${pkgdir} 239 | (cd ${pkgdir} && ln -sf ../../../../../$ipk .) 240 | } 241 | 242 | build_tarball() { 243 | export SDK="$(pwd)/${sdk}" 244 | local opts="" 245 | if test ${type} = lxd; then 246 | opts="$opts -m $metadata" 247 | fi 248 | if test "${upgrade}" = "1"; then 249 | opts="$opts --upgrade" 250 | fi 251 | local allpkgs="${packages}" 252 | test -d $pkgdir && for pkg in $pkgdir/*.ipk; do 253 | if [ -e "$pkg" ]; then 254 | allpkgs="${allpkgs} $pkg" 255 | fi 256 | done 257 | 258 | local cmd="scripts/build_rootfs.sh" 259 | if test `id -u` != 0; then 260 | case "$super" in 261 | sudo) 262 | cmd="sudo --preserve-env=SDK $cmd" 263 | ;; 264 | *) 265 | cmd="$super $cmd" 266 | ;; 267 | esac 268 | fi 269 | 270 | $cmd $rootfs $opts -o $tarball --disable-services="sysfixtime sysntpd led" --arch=${arch} --subarch=${subarch} --version=${ver} --packages="${allpkgs}" --files="${files}" 271 | } 272 | 273 | build_metadata() { 274 | local stat=`stat -c %Y $rootfs` 275 | local date="`date -d \"@${stat}\" +%F`" 276 | local desc="$(tar xf $rootfs ./etc/openwrt_release -O|grep DISTRIB_DESCRIPTION|sed -e "s/.*='\(.*\)'/\1/")" 277 | 278 | test -e bin || mkdir bin 279 | cat > $metadata <> /etc/uci-defaults/60_docker-network << EOF 11 | #!/bin/sh 12 | 13 | uci set network.lan.proto=static 14 | uci set network.lan.ipaddr=$ip4 15 | uci set network.lan.netmask=$mask4 16 | uci set network.lan.gateway=$gw4 17 | uci set network.lan.ip6addr=$ip6 18 | uci set network.lan.ip6gw=$gw6 19 | uci delete network.lan.type 20 | uci delete network.lan6 21 | uci commit network.lan 22 | exit 0 23 | EOF 24 | 25 | cat >> /etc/uci-defaults/50_passwd << EOF 26 | #!/bin/sh 27 | 28 | echo -e "openwrtpassword\nopenwrtpassword" | passwd 29 | exit 0 30 | EOF 31 | 32 | export container=lxc 33 | 34 | exec /sbin/init "$@" 35 | -------------------------------------------------------------------------------- /files/etc/board.d/90-set_hostname: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | 4 | . /lib/functions/uci-defaults.sh 5 | 6 | board_config_update 7 | 8 | json_is_a system object && exit 0 9 | 10 | ucidef_set_hostname "$(uname -n)" 11 | 12 | board_config_flush 13 | 14 | exit 0 15 | -------------------------------------------------------------------------------- /files/etc/board.d/99-default_network: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (C) 2013-2015 OpenWrt.org 4 | # 5 | 6 | . /lib/functions/uci-defaults.sh 7 | 8 | board_config_update 9 | 10 | json_is_a network object && exit 0 11 | 12 | ucidef_set_interface_lan 'eth0' dhcp 13 | [ -d /sys/class/net/eth1 ] && ucidef_set_interface_wan 'eth1' 14 | 15 | board_config_flush 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /files/etc/init.d/container_init: -------------------------------------------------------------------------------- 1 | #!/bin/sh /etc/rc.common 2 | # Copyright (C) 2018 Mikael Magnusson 3 | 4 | START=15 5 | 6 | log_output() { 7 | logger -t container_init "$@" 8 | } 9 | 10 | boot() { 11 | # Only execute for lxc containers 12 | if [ "$container" != "lxc" ]; then 13 | exit 0 14 | fi 15 | 16 | local disable_ipv6="$(uci_get firewall @defaults[0] disable_ipv6 false)" 17 | case "$disable_ipv6" in 18 | '0'|'no'|'off'|'false'|'disabled') disable_ipv6=false ;; 19 | '1'|'yes'|'on'|'true'|'enabled') disable_ipv6=true ;; 20 | esac 21 | 22 | tables='filter nat mangle raw' 23 | res=0 24 | for table in $tables; do 25 | iptables -n -t $table -L >/dev/null 2>/dev/null 26 | if ! grep $table /proc/net/ip_tables_names >/dev/null; then 27 | log_output -p daemon.crit "ip $table load failed" 28 | res=1 29 | fi 30 | 31 | if [ "$disable_ipv6" = "false" ]; then 32 | ip6tables -n -t $table -L >/dev/null 2>/dev/null 33 | if ! grep $table /proc/net/ip6_tables_names >/dev/null; then 34 | log_output -p daemon.crit "ip6 $table load failed" 35 | res=1 36 | fi 37 | fi 38 | done 39 | if [ "$res" == "0" ]; then 40 | if [ "$disable_ipv6" = "false" ]; then 41 | log_output -p daemon.info "ip and ip6 tables loaded successfully" 42 | else 43 | log_output -p daemon.info "ip tables loaded successfully" 44 | fi 45 | fi 46 | 47 | if [ ! -e /lib/modules/$(uname -r) ]; then 48 | local modulesdir=$(basename $(dirname $(opkg files kmod-ipt-core|grep "/lib/modules/[0-9].*"|head -1))) 49 | ln -s $modulesdir /lib/modules/$(uname -r) 50 | fi 51 | exit $res 52 | } 53 | -------------------------------------------------------------------------------- /files/etc/inittab: -------------------------------------------------------------------------------- 1 | ::sysinit:/etc/init.d/rcS S boot 2 | ::shutdown:/etc/init.d/rcS K shutdown 3 | console::askfirst:/usr/libexec/login.sh 4 | -------------------------------------------------------------------------------- /files/etc/uci-defaults/70_fill-dhcp-checksum: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cat >> /etc/firewall.user << EOF 4 | 5 | # Fill DHCP checksums, try to work-around broken DHCP clients (such as FreeBSD). 6 | # It requires iptables-mod-checksum which is installed by default in lxd-openwrt. 7 | if [ -e /usr/lib/iptables/libxt_CHECKSUM.so ]; then 8 | iptables -t mangle -A OUTPUT -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill 9 | fi 10 | 11 | EOF 12 | -------------------------------------------------------------------------------- /patches/procd-lede-17.01/001_lxd_no_mounts.patch: -------------------------------------------------------------------------------- 1 | diff --git a/initd/early.c b/initd/early.c 2 | index 7028ff8..115d8f8 100644 3 | --- a/initd/early.c 4 | +++ b/initd/early.c 5 | @@ -27,13 +27,6 @@ 6 | #include "../libc-compat.h" 7 | 8 | static void 9 | -early_dev(void) 10 | -{ 11 | - mkdev("*", 0600); 12 | - mknod("/dev/null", 0666, makedev(1, 3)); 13 | -} 14 | - 15 | -static void 16 | early_console(const char *dev) 17 | { 18 | struct stat s; 19 | @@ -56,15 +49,6 @@ early_mounts(void) 20 | { 21 | unsigned int oldumask = umask(0); 22 | 23 | - mount("proc", "/proc", "proc", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0); 24 | - mount("sysfs", "/sys", "sysfs", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0); 25 | - mount("cgroup", "/sys/fs/cgroup", "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID, 0); 26 | - mount("tmpfs", "/dev", "tmpfs", MS_NOATIME | MS_NOSUID, "mode=0755,size=512K"); 27 | - ignore(symlink("/tmp/shm", "/dev/shm")); 28 | - mkdir("/dev/pts", 0755); 29 | - mount("devpts", "/dev/pts", "devpts", MS_NOATIME | MS_NOEXEC | MS_NOSUID, "mode=600"); 30 | - early_dev(); 31 | - 32 | early_console("/dev/console"); 33 | if (mount_zram_on_tmp()) { 34 | mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOATIME, 0); 35 | diff --git a/initd/zram.c b/initd/zram.c 36 | index c730942..8eb38a6 100644 37 | --- a/initd/zram.c 38 | +++ b/initd/zram.c 39 | @@ -116,12 +116,6 @@ mount_zram_on_tmp(void) 40 | waitpid(pid, NULL, 0); 41 | } 42 | 43 | - ret = mount("/dev/zram0", "/tmp", "ext4", MS_NOSUID | MS_NODEV | MS_NOATIME, "errors=continue,noquota"); 44 | - if (ret < 0) { 45 | - ERROR("Can't mount /dev/zram0 on /tmp: %s\n", strerror(errno)); 46 | - return errno; 47 | - } 48 | - 49 | LOG("Using up to %ld kB of RAM as ZRAM storage on /mnt\n", zramsize); 50 | 51 | ret = chmod("/tmp", 01777); 52 | diff --git a/plug/coldplug.c b/plug/coldplug.c 53 | index 5fcb9a3..b846d7f 100644 54 | --- a/plug/coldplug.c 55 | +++ b/plug/coldplug.c 56 | @@ -43,13 +43,8 @@ void procd_coldplug(void) 57 | char *argv[] = { "udevtrigger", NULL }; 58 | unsigned int oldumask = umask(0); 59 | 60 | - umount2("/dev/pts", MNT_DETACH); 61 | - umount2("/dev/", MNT_DETACH); 62 | - mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755,size=512K"); 63 | ignore(symlink("/tmp/shm", "/dev/shm")); 64 | - mkdir("/dev/pts", 0755); 65 | umask(oldumask); 66 | - mount("devpts", "/dev/pts", "devpts", MS_NOEXEC | MS_NOSUID, 0); 67 | udevtrigger.cb = udevtrigger_complete; 68 | udevtrigger.pid = fork(); 69 | if (!udevtrigger.pid) { 70 | -------------------------------------------------------------------------------- /patches/procd-lede-17.01/002_lxd_signal_halt.patch: -------------------------------------------------------------------------------- 1 | --- a/initd/init.c.orig 2018-07-01 22:24:02.065349814 +0000 2 | +++ b/initd/init.c 2018-07-01 22:23:02.837917724 +0000 3 | @@ -77,6 +77,7 @@ 4 | sigaction(SIGTERM, &sa_shutdown, NULL); 5 | sigaction(SIGUSR1, &sa_shutdown, NULL); 6 | sigaction(SIGUSR2, &sa_shutdown, NULL); 7 | + sigaction(SIGPWR, &sa_shutdown, NULL); 8 | 9 | early(); 10 | cmdline(); 11 | --- a/signal.c.orig 2018-03-28 09:29:49.000000000 +0000 12 | +++ b/signal.c 2018-07-01 22:23:23.357720944 +0000 13 | @@ -44,6 +44,7 @@ 14 | break; 15 | case SIGUSR1: 16 | case SIGUSR2: 17 | + case SIGPWR: 18 | event = RB_POWER_OFF; 19 | msg = "poweroff"; 20 | break; 21 | @@ -90,6 +91,7 @@ 22 | sigaction(SIGINT, &sa_shutdown, NULL); 23 | sigaction(SIGUSR1, &sa_shutdown, NULL); 24 | sigaction(SIGUSR2, &sa_shutdown, NULL); 25 | + sigaction(SIGPWR, &sa_shutdown, NULL); 26 | sigaction(SIGSEGV, &sa_crash, NULL); 27 | sigaction(SIGBUS, &sa_crash, NULL); 28 | sigaction(SIGHUP, &sa_dummy, NULL); 29 | -------------------------------------------------------------------------------- /patches/procd-master/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikma/lxd-openwrt/28e0c7f0cb1e37d3762e219ac927b677d4e0def8/patches/procd-master/.gitkeep -------------------------------------------------------------------------------- /patches/procd-openwrt-18.06/0001-lxd-no-mounts.patch: -------------------------------------------------------------------------------- 1 | From 991241149ad50b0ef5e221fe34d993ad67cb4174 Mon Sep 17 00:00:00 2001 2 | From: Mikael Magnusson 3 | Date: Fri, 24 Aug 2018 13:55:42 +0000 4 | Subject: [PATCH 1/3] lxd: no mounts 5 | 6 | --- 7 | initd/early.c | 16 ---------------- 8 | initd/zram.c | 6 ------ 9 | plug/coldplug.c | 5 ----- 10 | 3 files changed, 27 deletions(-) 11 | 12 | diff --git a/initd/early.c b/initd/early.c 13 | index 00fd946..dac07b9 100644 14 | --- a/initd/early.c 15 | +++ b/initd/early.c 16 | @@ -26,13 +26,6 @@ 17 | #include "init.h" 18 | #include "../libc-compat.h" 19 | 20 | -static void 21 | -early_dev(void) 22 | -{ 23 | - mkdev("*", 0600); 24 | - mknod("/dev/null", 0666, makedev(1, 3)); 25 | -} 26 | - 27 | static void 28 | early_console(const char *dev) 29 | { 30 | @@ -56,15 +49,6 @@ early_mounts(void) 31 | { 32 | unsigned int oldumask = umask(0); 33 | 34 | - mount("proc", "/proc", "proc", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0); 35 | - mount("sysfs", "/sys", "sysfs", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0); 36 | - mount("cgroup", "/sys/fs/cgroup", "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID, 0); 37 | - mount("tmpfs", "/dev", "tmpfs", MS_NOATIME | MS_NOSUID, "mode=0755,size=512K"); 38 | - ignore(symlink("/tmp/shm", "/dev/shm")); 39 | - mkdir("/dev/pts", 0755); 40 | - mount("devpts", "/dev/pts", "devpts", MS_NOATIME | MS_NOEXEC | MS_NOSUID, "mode=600"); 41 | - early_dev(); 42 | - 43 | early_console("/dev/console"); 44 | if (mount_zram_on_tmp()) { 45 | mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOATIME, 0); 46 | diff --git a/initd/zram.c b/initd/zram.c 47 | index b41bfd9..70049e6 100644 48 | --- a/initd/zram.c 49 | +++ b/initd/zram.c 50 | @@ -116,12 +116,6 @@ mount_zram_on_tmp(void) 51 | waitpid(pid, NULL, 0); 52 | } 53 | 54 | - ret = mount("/dev/zram0", "/tmp", "ext4", MS_NOSUID | MS_NODEV | MS_NOATIME, "errors=continue,noquota"); 55 | - if (ret < 0) { 56 | - ERROR("Can't mount /dev/zram0 on /tmp: %m\n"); 57 | - return errno; 58 | - } 59 | - 60 | LOG("Using up to %ld kB of RAM as ZRAM storage on /mnt\n", zramsize); 61 | 62 | ret = chmod("/tmp", 01777); 63 | diff --git a/plug/coldplug.c b/plug/coldplug.c 64 | index c6a89c3..72554c3 100644 65 | --- a/plug/coldplug.c 66 | +++ b/plug/coldplug.c 67 | @@ -43,13 +43,8 @@ void procd_coldplug(void) 68 | char *argv[] = { "udevtrigger", NULL }; 69 | unsigned int oldumask = umask(0); 70 | 71 | - umount2("/dev/pts", MNT_DETACH); 72 | - umount2("/dev/", MNT_DETACH); 73 | - mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755,size=512K"); 74 | ignore(symlink("/tmp/shm", "/dev/shm")); 75 | - mkdir("/dev/pts", 0755); 76 | umask(oldumask); 77 | - mount("devpts", "/dev/pts", "devpts", MS_NOEXEC | MS_NOSUID, 0); 78 | udevtrigger.cb = udevtrigger_complete; 79 | udevtrigger.pid = fork(); 80 | if (!udevtrigger.pid) { 81 | -- 82 | 2.17.1 83 | 84 | -------------------------------------------------------------------------------- /patches/procd-openwrt-18.06/0002-lxd-shutdown-on-SIGPWR.patch: -------------------------------------------------------------------------------- 1 | From 9c252ff0b3fec05f3757362ca044440bfdfa16f4 Mon Sep 17 00:00:00 2001 2 | From: Mikael Magnusson 3 | Date: Fri, 24 Aug 2018 13:56:12 +0000 4 | Subject: [PATCH 2/3] lxd: shutdown on SIGPWR 5 | 6 | --- 7 | initd/init.c | 1 + 8 | signal.c | 2 ++ 9 | 2 files changed, 3 insertions(+) 10 | 11 | diff --git a/initd/init.c b/initd/init.c 12 | index 0349e6e..29eee50 100644 13 | --- a/initd/init.c 14 | +++ b/initd/init.c 15 | @@ -77,6 +77,7 @@ main(int argc, char **argv) 16 | sigaction(SIGTERM, &sa_shutdown, NULL); 17 | sigaction(SIGUSR1, &sa_shutdown, NULL); 18 | sigaction(SIGUSR2, &sa_shutdown, NULL); 19 | + sigaction(SIGPWR, &sa_shutdown, NULL); 20 | 21 | early(); 22 | cmdline(); 23 | diff --git a/signal.c b/signal.c 24 | index 07dda9a..9974153 100644 25 | --- a/signal.c 26 | +++ b/signal.c 27 | @@ -44,6 +44,7 @@ static void signal_shutdown(int signal, siginfo_t *siginfo, void *data) 28 | break; 29 | case SIGUSR1: 30 | case SIGUSR2: 31 | + case SIGPWR: 32 | event = RB_POWER_OFF; 33 | msg = "poweroff"; 34 | break; 35 | @@ -90,6 +91,7 @@ void procd_signal(void) 36 | sigaction(SIGINT, &sa_shutdown, NULL); 37 | sigaction(SIGUSR1, &sa_shutdown, NULL); 38 | sigaction(SIGUSR2, &sa_shutdown, NULL); 39 | + sigaction(SIGPWR, &sa_shutdown, NULL); 40 | sigaction(SIGSEGV, &sa_crash, NULL); 41 | sigaction(SIGBUS, &sa_crash, NULL); 42 | sigaction(SIGHUP, &sa_dummy, NULL); 43 | -- 44 | 2.17.1 45 | 46 | -------------------------------------------------------------------------------- /patches/procd-openwrt-18.06/0003-docker-fix-problem-stopping-container.patch: -------------------------------------------------------------------------------- 1 | From 0aacf0e59985185e7d4a88e3dd72aed62ad87926 Mon Sep 17 00:00:00 2001 2 | From: Mikael Magnusson 3 | Date: Thu, 29 Nov 2018 22:10:42 +0000 4 | Subject: [PATCH 3/3] docker: fix problem stopping container 5 | 6 | --- 7 | state.c | 13 +------------ 8 | 1 file changed, 1 insertion(+), 12 deletions(-) 9 | 10 | diff --git a/state.c b/state.c 11 | index ccf4104..bd59d7e 100644 12 | --- a/state.c 13 | +++ b/state.c 14 | @@ -157,18 +157,8 @@ static void state_enter(void) 15 | else 16 | LOG("- reboot -\n"); 17 | 18 | - /* Allow time for last message to reach serial console, etc */ 19 | - sleep(1); 20 | - 21 | - /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) 22 | - * in linux/kernel/sys.c, which can cause the machine to panic when 23 | - * the init process exits... */ 24 | - if (!vfork( )) { /* child */ 25 | - reboot(reboot_event); 26 | - _exit(EXIT_SUCCESS); 27 | - } 28 | - while (1) 29 | - sleep(1); 30 | + reboot(reboot_event); 31 | + exit(0); 32 | #else 33 | exit(0); 34 | #endif 35 | -- 36 | 2.17.1 37 | 38 | -------------------------------------------------------------------------------- /patches/procd-openwrt-19.07: -------------------------------------------------------------------------------- 1 | procd-master -------------------------------------------------------------------------------- /patches/procd-snapshot: -------------------------------------------------------------------------------- 1 | procd-master -------------------------------------------------------------------------------- /scripts/build_rootfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | usage() { 6 | echo "Usage: $0 [-a|--arch ] [-v|--version ] [-d|--disable-services ] [-s|--subarch ] [-o|--output ] [-p|--packages ] [-f|--files ] [-m|--metadata ] [-u|--upgrade] " 7 | exit 1 8 | } 9 | 10 | arch=x86 11 | subarch=64 12 | version= 13 | packages= 14 | dst_file=/dev/stdout 15 | files= 16 | services= 17 | metadata= 18 | metadata_dir= 19 | upgrade= 20 | 21 | temp=$(getopt -o "a:d:o:p:s:f:m:u:v:" -l "arch:,disable-services:,output:,packages:,subarch:,files:,metadata:,upgrade,version:,help" -- "$@") 22 | eval set -- "$temp" 23 | while true; do 24 | case "$1" in 25 | -a|--arch) 26 | arch="$2"; shift 2;; 27 | -v|--version) 28 | version="$2"; shift 2;; 29 | -d|--disable-services) 30 | services="$2"; shift 2;; 31 | -s|--subarch) 32 | subarch="$2"; shift 2;; 33 | -p|--packages) 34 | packages="$2"; shift 2;; 35 | -o|--output) 36 | dst_file="$2"; shift 2;; 37 | -f|--files) 38 | files="$2"; shift 2;; 39 | -m|--metadata) 40 | metadata=`basename $2` 41 | metadata_dir=`dirname $2` 42 | shift 2;; 43 | -u|--upgrade) 44 | upgrade=1; shift 1;; 45 | --help) 46 | usage;; 47 | --) 48 | shift; break;; 49 | esac 50 | done 51 | 52 | if [ $# -ne 1 -o -z "$version" ]; then 53 | usage 54 | fi 55 | 56 | src_tar=$1 57 | base=`basename $src_tar` 58 | dir=/tmp/build.$$ 59 | files_dir=files/ 60 | instroot=$dir/rootfs 61 | cache=dl/packages/$version/$arch/$subarch 62 | 63 | test -e $cache || mkdir -p $cache 64 | OPKG="env LD_PRELOAD= IPKG_NO_SCRIPT=1 IPKG_INSTROOT=$instroot $SDK/staging_dir/host/bin/opkg -o $instroot --cache $cache" 65 | 66 | unpack() { 67 | mkdir -p $instroot 68 | cat $src_tar | (cd $instroot && tar -xz) 69 | mkdir -p $instroot/var/lock/ 70 | } 71 | 72 | pack() { 73 | echo Pack rootfs 74 | (cd $instroot && rm -rf var/lock/) 75 | if test -n "$metadata"; then 76 | (cd $dir && tar -cz *) > $dst_file 77 | else 78 | (cd $dir/rootfs && tar -cz *) > $dst_file 79 | fi 80 | } 81 | 82 | pack_squashfs() { 83 | echo Pack rootfs squashfs 84 | mksquashfs $dir $dst_file 85 | } 86 | 87 | disable_root() { 88 | sed -i -e 's/^root::/root:*:/' $instroot/etc/shadow 89 | } 90 | 91 | add_file() { 92 | file=$1 93 | src_dir=$2 94 | dst_dir=$3 95 | 96 | src=$src_dir/$file 97 | dst=$dst_dir/$file 98 | 99 | if test -d $src; then 100 | test -d $dst || mkdir -p $dst 101 | elif test -f $src; then 102 | cp $src $dst 103 | foo=$(dirname $file) 104 | if [ "$foo" = "./etc/init.d" ]; then 105 | echo Enabling $file 106 | set +e 107 | env IPKG_INSTROOT=$instroot sh $instroot/etc/rc.common $dst enable 108 | set -e 109 | fi 110 | fi 111 | } 112 | 113 | add_files() { 114 | src_dir=$1 115 | dst_dir=$2 116 | 117 | for f in $(cd $src_dir && find); do 118 | add_file $f $src_dir $dst_dir 119 | done 120 | } 121 | 122 | add_package() { 123 | local ipkg=$1 124 | $OPKG install --force-downgrade $ipkg 125 | } 126 | 127 | add_packages() { 128 | local dir=$1 129 | for f in $dir/*.ipk; do 130 | add_package $f 131 | done 132 | } 133 | 134 | opkg_update() { 135 | $OPKG update 136 | } 137 | 138 | update_packages() { 139 | local upgradable="$($OPKG list-upgradable|grep -e '^.* - .* - .*'|cut -d ' ' -f 1)" 140 | for pkg in $upgradable; do 141 | echo Upgrading $pkg 142 | $OPKG upgrade $pkg 143 | done 144 | } 145 | 146 | install_packages() { 147 | local packages="$1" 148 | for pkg in $packages; do 149 | echo Install $pkg 150 | $OPKG install --force-downgrade $pkg 151 | done 152 | } 153 | 154 | disable_services() { 155 | local services="$1" 156 | for service in $services; do 157 | echo Disabling $service 158 | env IPKG_INSTROOT=$instroot sh $instroot/etc/rc.common $instroot/etc/init.d/$service disable 159 | done 160 | } 161 | 162 | create_manifest() { 163 | $OPKG list-installed > $instroot/etc/openwrt_manifest 164 | } 165 | 166 | unpack 167 | disable_root 168 | if test -n "$metadata"; then 169 | add_file $metadata $metadata_dir $dir 170 | fi 171 | add_files templates/ $dir/templates/ 172 | opkg_update 173 | if test -n "$upgrade"; then 174 | update_packages 175 | fi 176 | install_packages "$packages" 177 | disable_services "$services" 178 | add_files $files_dir $instroot 179 | if test -n "$files"; then 180 | add_files $files $instroot 181 | fi 182 | create_manifest 183 | pack 184 | #pack_squashfs 185 | -------------------------------------------------------------------------------- /scripts/sync_patches.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | usage() { 6 | echo "Usage: $0 " 7 | exit 1 8 | } 9 | 10 | if [ $# -ne 1 ]; then 11 | usage 12 | fi 13 | 14 | repo=$1 15 | tmpdir=/tmp/procd.$$ 16 | 17 | git clone $repo $tmpdir 18 | 19 | for ver in openwrt-18.06 master; do 20 | outdir=$(pwd)/patches/procd-$ver 21 | git rm $outdir/00* 22 | (cd $tmpdir && git format-patch --output-directory $outdir origin/$ver...origin/lxd/$ver) 23 | git add $outdir/00* 24 | done 25 | -------------------------------------------------------------------------------- /scripts/upgrade.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import re 4 | import sys 5 | import time 6 | import pylxd 7 | from pylxd import Client 8 | 9 | class ExecuteError(RuntimeError): 10 | def __init__(self, command, exit_code): 11 | self.command = command 12 | self.exit_code = exit_code 13 | 14 | def __str__(self): 15 | return 'Command "%s" exit code %d' % (' '.join(self.command), self.exit_code) 16 | 17 | def find_source_image(client, image): 18 | try: 19 | client.images.get_by_alias(image) 20 | return {'type': 'image', 'alias': image} 21 | except pylxd.exceptions.NotFound as e: 22 | if len(image) >= 12: 23 | client.images.get(image) 24 | return {'type': 'image', 'fingerprint': image} 25 | else: 26 | raise 27 | 28 | def copy_config(old, new): 29 | new.devices = old.devices 30 | new.description = old.description 31 | new_config = new.config 32 | 33 | for key, value in old.config.items(): 34 | if key.endswith("hwaddr"): 35 | new_config[key] = value 36 | 37 | # for key, value in new_config.items(): 38 | # print("%s %s" % (key, value)) 39 | 40 | new.config = new_config 41 | 42 | def log_stdout(message): 43 | print(message, end='', flush=True) 44 | 45 | def log_stderr(message): 46 | print(message, end='', file=sys.stderr, flush=True) 47 | 48 | class Container: 49 | def __init__(self, container): 50 | self.container = container 51 | 52 | def __getattr__(self, name): 53 | return self.container.__getattribute__(name) 54 | 55 | def __setattr__(self, name, value): 56 | if name not in ('container'): 57 | self.container.__setattr__(name, value) 58 | else: 59 | super(Container, self).__setattr__(name, value) 60 | 61 | def execute_with_output(self, command, *args, **kwargs): 62 | extra_args={} 63 | if 'stderr_handler' not in kwargs: 64 | extra_args['stderr_handler'] = log_stderr 65 | (exit_code, stdout, stderr) = self.container.execute(command, *args, **kwargs, **extra_args) 66 | if exit_code != 0: 67 | raise ExecuteError(command, exit_code) 68 | return stdout 69 | 70 | def execute(self, command, *args, **kwargs): 71 | extra_args={} 72 | if 'stdout_handler' not in kwargs: 73 | extra_args['stdout_handler'] = log_stdout 74 | self.execute_with_output(command, *args, **kwargs, **extra_args) 75 | 76 | def execute_retry(self, command, retries, *args, **kwargs): 77 | for i in range(retries + 1): 78 | try: 79 | self.execute(command, *args, **kwargs) 80 | except ExecuteError as e: 81 | if i == retries: 82 | raise 83 | continue 84 | return 85 | raise NotImplementedError() 86 | 87 | def ping(self, dest): 88 | self.execute_retry(['ping', '-c', '1', '-q', dest], 2, 89 | stdout_handler=None) 90 | 91 | def sysupgrade_backup(self, ): 92 | return self.execute_with_output(['sysupgrade', '-b', '-'], 93 | encoding='raw', decode=False) 94 | 95 | def sysupgrade_restore(self, data): 96 | backup_file = '/tmp/lxd-upgrade.tar.gz' 97 | self.files.put(backup_file, data) 98 | self.execute(['sysupgrade', '-r', backup_file]) 99 | 100 | def opkg_list_installed(self, ): 101 | return self.execute_with_output(['opkg', 'list-installed']) 102 | 103 | def opkg_update(self): 104 | print("Update") 105 | self.execute(['opkg', 'update']) 106 | 107 | def opkg_install(self, packages): 108 | print("Installing %s" % packages) 109 | self.execute(['opkg', 'install'] + packages) 110 | 111 | def opkg_remove(self, packages): 112 | print("Removing %s" % packages) 113 | self.execute(['opkg', 'remove'] + packages) 114 | 115 | def _package_set_from_str(self, s): 116 | print("_package_set_from_str ", type(s)) 117 | old_list = s.split('\n') 118 | old_packages = [] 119 | pat = re.compile(r'([\w\.\-]*?)[0-9][0-9a-f\.\-]*') 120 | i = 1 121 | for l in old_list: 122 | i = i + 1 123 | res = l.split(' ') 124 | if len(res) == 3: 125 | (name, _, version) = res 126 | if name.startswith('lib'): 127 | m = pat.match(name) 128 | if m: 129 | name = m[1] 130 | old_packages.append(name) 131 | return frozenset(old_packages) 132 | 133 | def package_set(self): 134 | return self._package_set_from_str(self.opkg_list_installed()) 135 | 136 | def orig_package_set(self): 137 | return self._package_set_from_str(self.container.files.get('/etc/openwrt_manifest').decode('ascii')) 138 | 139 | def save_orig_package_set(self): 140 | self.execute(['sh', '-c', 'opkg list-installed > tee /etc/openwrt_manifest']) 141 | 142 | 143 | def usage(argv): 144 | print("Usage:", argv[0], " ") 145 | exit(1) 146 | 147 | def main(argv): 148 | is_allow_existing = False 149 | 150 | if len(argv) == 4: 151 | pos = 1 152 | else: 153 | usage(argv) 154 | 155 | old_name = argv[pos]; pos=pos+1 156 | new_name = argv[pos]; pos=pos+1 157 | new_image = argv[pos]; pos=pos+1 158 | client = Client() 159 | 160 | old = Container(client.containers.get(old_name)) 161 | 162 | if old.status == 'Stopped': 163 | print("Start", old_name) 164 | old.start(wait=True) 165 | 166 | new_source = find_source_image(client, new_image) 167 | new_config = {'name': new_name, 'source': new_source, 'profiles': old.profiles} 168 | 169 | if is_allow_existing and client.containers.exists(new_name): 170 | new = Container(client.containers.get(new_name)) 171 | else: 172 | print("Create", new_name, new_config) 173 | new = Container(client.containers.create(new_config, wait=True)) 174 | 175 | if new.status == 'Stopped': 176 | print("Start", new_name) 177 | new.start(wait=True) 178 | 179 | # Can't use ujail on LXD instances 180 | new.opkg_remove(['procd-ujail']) 181 | print("Ping downloads.openwrt.org") 182 | new.ping('downloads.openwrt.org') 183 | 184 | print("Update package list") 185 | new.opkg_update() 186 | 187 | print("Build /etc/openwrt_manifest") 188 | new.save_orig_package_set() 189 | 190 | orig_set = old.orig_package_set() 191 | old_set = old.package_set() 192 | new_set = new.package_set() 193 | del_set = orig_set.difference(old_set) 194 | add_set = old_set.difference(orig_set) 195 | del_packages = list(del_set) 196 | del_packages.append('procd-ujail') 197 | add_packages = list(add_set.difference(['iw'])) 198 | 199 | if len(del_packages) > 0: 200 | print("Remove", del_packages) 201 | new.opkg_remove(del_packages) 202 | else: 203 | print("No packages uninstalled") 204 | 205 | if len(add_packages) > 0: 206 | print("Install", add_packages) 207 | new.opkg_install(add_packages) 208 | else: 209 | print("No packages installed") 210 | 211 | print("Backup", old_name) 212 | backup_data = old.sysupgrade_backup() 213 | 214 | print("Restore", new_name) 215 | new.sysupgrade_restore(backup_data) 216 | 217 | print("Stop", old_name) 218 | old.stop(wait=True) 219 | 220 | print("Stop", new_name) 221 | new.stop(wait=True) 222 | 223 | print("Copy config") 224 | copy_config(old, new) 225 | new.save() 226 | 227 | print("Wait 2s") 228 | time.sleep(2) 229 | 230 | print("Start", new_name) 231 | new.start(wait=True) 232 | print("Finished") 233 | 234 | if __name__ == '__main__': 235 | main(sys.argv) 236 | -------------------------------------------------------------------------------- /templates/hostname.tpl: -------------------------------------------------------------------------------- 1 | {{ container.name }} 2 | --------------------------------------------------------------------------------