commit 685ae1e301d8d4901b9ed0ead7f72f7dfcbb1343
parent f0a5b424dffd7546818fa8729cb7e3f9a76bdf5a
Author: Jan Pobrislo <ccx@te2000.cz>
Date: Sat, 15 Nov 2025 01:43:42 +0000
WIP script generators with full paths
Diffstat:
6 files changed, 291 insertions(+), 0 deletions(-)
diff --git a/scripts/abspaths.awk b/scripts/abspaths.awk
@@ -0,0 +1,66 @@
+function die(msg) {
+ print msg >>"/dev/stderr"
+ exit 1
+}
+
+function s(re, t, str) {
+ gsub(re, t, str)
+ return str
+}
+
+function get(arg, m, fmt, exe, exe_path) {
+ # print "get(\""arg"\")" >>"/dev/stderr"
+ m = match(arg, ":")
+ if(!m) {
+ die("invalid token in " FILENAME ":" FNR)
+ }
+ fmt = substr(arg, 1, m-1)
+ exe = substr(arg, m+1)
+ # k = "prog_" exe
+ # print "exe=\""exe"\" -> \""k"\" -> \"" ENVIRON[k] "\"" >>"/dev/stderr"
+ exe_path = ENVIRON["prog_" exe]
+ if(!length(exe_path)) {
+ die("program '"exe"' wan't specified, used by " FILENAME ":" FNR)
+ }
+ if(fmt == "shebang") {
+ return exe_path
+ } else if(fmt == "shquote") {
+ if(exe_path !~ "[^-+,_./:@0-9A-Za-z]") {
+ return exe_path
+ }
+ return "'" s("'", "'\\''", exe_path) "'"
+ } else if(fmt == "elquote") {
+ if(exe_path !~ "[^][!%&'()*+,_./:;<=>?@^|0-9A-Za-z-]") {
+ return exe_path
+ }
+ return "\"" s("\"", "\\\"", s("\\", "\\\\", exe_path)) "\""
+ } else {
+ die("unknown format '"exe"', used by " FILENAME ":" FNR)
+ }
+}
+
+function parse_line(line, m, pre, tok) {
+ while(length(line)) {
+ m = match(line, /[ -~]*/)
+ if(!m) { break }
+ pre = substr(line, 1, m-1)
+ tok = substr(line, m+1, RLENGTH-2)
+ line = substr(line, m+RLENGTH)
+ printf("%s%s", pre, get(tok))
+ }
+ print line
+}
+{ parse_line($0) }
+
+# BEGIN {
+# for(k in ENVIRON) {
+# printf "%s=\"%s\"\n", k, ENVIRON[k]
+# }
+# print "--- begin ---"
+# }
+# END {
+# print "--- end ---"
+# for(k in ENVIRON) {
+# printf "%s=\"%s\"\n", k, ENVIRON[k]
+# }
+# }
diff --git a/scripts/abspaths2.awk b/scripts/abspaths2.awk
@@ -0,0 +1,92 @@
+#!/bin/awk -f
+
+function die(msg) {
+ print msg >>"/dev/stderr"
+ exit 1
+}
+
+function s(re, t, str) {
+ gsub(re, t, str)
+ return str
+}
+
+function set_prog(i, m, name, path) {
+ if(ARGV[i] == "no_paths") {
+ no_paths = 1
+ return
+ }
+ m = match(ARGV[i], "=")
+ if(!m) {
+ die("invalid argument: #"i" '"arg"'")
+ }
+ name = substr(ARGV[i], 1, m-1)
+ path = substr(ARGV[i], m+1)
+ paths[name] = path
+ # print "paths[\""name"\"] = \""path"\"" >>"/dev/stderr"
+}
+
+function get(arg, m, fmt, exe, exe_path) {
+ # print "get(\""arg"\")" >>"/dev/stderr"
+ m = match(arg, ":")
+ if(!m) {
+ die("invalid token in " FILENAME ":" FNR)
+ }
+ fmt = substr(arg, 1, m-1)
+ exe = substr(arg, m+1)
+ # print "exe=\""exe"\" -> \"" paths[exe] "\" " (exe in paths) >>"/dev/stderr"
+ if(!(exe in paths)) {
+ die("program '"exe"' wasn't specified, used by " FILENAME ":" FNR)
+ }
+ exe_path = paths[exe]
+ # print "length(\"" exe_path "\") = " length(exe_path) >>"/dev/stderr"
+ if(no_paths && fmt != "shebang") {
+ exe_path = s(".*/", "", length(exe_path) ? exe_path : exe)
+ }
+ if(!length(exe_path)) {
+ die("program '"exe"' wasn't found, used by " FILENAME ":" FNR)
+ }
+ if(fmt == "shebang") {
+ return exe_path
+ } else if(fmt == "shquote") {
+ if(exe_path !~ "[^-+,_./:@0-9A-Za-z]") {
+ return exe_path
+ }
+ return "'" s("'", "'\\''", exe_path) "'"
+ } else if(fmt == "elquote") {
+ if(exe_path !~ "[^][!%&'()*+,_./:;<=>?@^|0-9A-Za-z-]") {
+ return exe_path
+ }
+ return "\"" s("\"", "\\\"", s("\\", "\\\\", exe_path)) "\""
+ } else {
+ die("unknown format '"exe"', used by " FILENAME ":" FNR)
+ }
+}
+
+function parse_line(line, m, pre, tok) {
+ while(length(line)) {
+ m = match(line, /[ -~]*/)
+ if(!m) { break }
+ pre = substr(line, 1, m-1)
+ tok = substr(line, m+1, RLENGTH-2)
+ line = substr(line, m+RLENGTH)
+ printf("%s%s", pre, get(tok))
+ }
+ print line
+}
+
+BEGIN {
+ for(i=2; i<ARGC; i++) {
+ set_prog(i)
+ # ARGV[i] = ""
+ }
+ ARGC = 2
+}
+
+{ parse_line($0) }
+
+# BEGIN {
+# print "--- begin ---"
+# }
+# END {
+# print "--- end ---"
+# }
diff --git a/src/lns-mount-chroot.gen b/src/lns-mount-chroot.gen
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+exec awk -f "$(dirname "$0")/../scripts/abspaths2.awk" "${0%.gen}.in" \
+"execlineb=$(which 'execlineb' 2>/dev/null)" \
+"multisubstitute=$(which 'multisubstitute' 2>/dev/null)" \
+"importas=$(which 'importas' 2>/dev/null)" \
+"shift=$(which 'shift' 2>/dev/null)" \
+"if=$(which 'if' 2>/dev/null)" \
+"mount=$(which 'mount' 2>/dev/null)" \
+"mknod=$(which 'mknod' 2>/dev/null)" \
+"ln=$(which 'ln' 2>/dev/null)" \
+"mkdir=$(which 'mkdir' 2>/dev/null)" \
+"cd=$(which 'cd' 2>/dev/null)" \
+"runblock=$(which 'runblock' 2>/dev/null)" \
+"s6-mount=$(which 's6-mount' 2>/dev/null)" \
+"lns-mounts-to-env=$(which 'lns-mounts-to-env' 2>/dev/null)" \
+"$@"
diff --git a/src/lns-mount-chroot.in b/src/lns-mount-chroot.in
@@ -0,0 +1,66 @@
+#!shebang:execlineb -S1
+
+elquote:multisubstitute {
+ elquote:importas -i 1 1 # require first argument
+ elquote:importas -D /mnt/chroot LNS_ROOT LNS_ROOT
+}
+elquote:shift -n 1 # remove first argument so we don't have to deal with it with elquote:runblock
+
+elquote:lns-mounts-to-env
+
+elquote:if { elquote:mount -o rbind $1 $NS_ROOT }
+
+# /proc
+elquote:if { elquote:mount -t proc proc ${LNS_ROOT}/proc }
+
+# /dev
+elquote:if { elquote:s6-mount -nwt tmpfs -o nosuid,dev,mode=0755 dev ${LNS_ROOT}/dev }
+elquote:if { elquote:mknod -m 666 ${LNS_ROOT}/dev/null c 1 3 }
+elquote:if { elquote:mknod -m 666 ${LNS_ROOT}/dev/full c 1 7 }
+elquote:if { elquote:mknod -m 666 ${LNS_ROOT}/dev/ptmx c 5 2 }
+elquote:if { elquote:mknod -m 644 ${LNS_ROOT}/dev/random c 1 8 }
+elquote:if { elquote:mknod -m 644 ${LNS_ROOT}/dev/urandom c 1 9 }
+elquote:if { elquote:mknod -m 666 ${LNS_ROOT}/dev/zero c 1 5 }
+elquote:if { elquote:mknod -m 666 ${LNS_ROOT}/dev/tty c 5 0 }
+elquote:if { elquote:ln -sf /proc/self/fd ${LNS_ROOT}/dev/fd }
+elquote:if { elquote:ln -sf /proc/self/fd/0 ${LNS_ROOT}/dev/stdin }
+elquote:if { elquote:ln -sf /proc/self/fd/1 ${LNS_ROOT}/dev/stout }
+elquote:if { elquote:ln -sf /proc/self/fd/2 ${LNS_ROOT}/dev/stderr }
+# elquote:if { elquote:ln -sf ../run/shm ${LNS_ROOT}/dev/shm }
+
+# dev/shm is intentionally ommited to allow custom mount or symlink
+# pts and mqueue are provided below
+
+# Create top-level /dev directories. Many may be bind-mounted from host if neededx.
+elquote:if {
+ elquote:mkdir
+
+ ${LNS_ROOT}/dev/pts
+ ${LNS_ROOT}/dev/mqueue
+
+ ${LNS_ROOT}/dev/block
+ ${LNS_ROOT}/dev/bus
+ ${LNS_ROOT}/dev/bus/usb
+ ${LNS_ROOT}/dev/char
+ ${LNS_ROOT}/dev/dri
+ ${LNS_ROOT}/dev/input
+ ${LNS_ROOT}/dev/loop
+ ${LNS_ROOT}/dev/net
+ ${LNS_ROOT}/dev/snd
+ ${LNS_ROOT}/dev/usb
+
+}
+elquote:if { elquote:mount -t devpts devpts ${LNS_ROOT}/dev/pts }
+elquote:if { elquote:s6-mount -nwt mqueue -o nosuid,nodev,noexec mqueue ${LNS_ROOT}/dev/mqueue }
+
+# run
+elquote:if {
+ elquote:cd $NS_ROOT
+ elquote:runblock 1
+}
+
+# now we can make /dev immutable
+elquote:if { elquote:mount -o remount,ro ${LNS_ROOT}/dev }
+
+# chainload into the rest of the argv
+elquote:runblock -r 1
diff --git a/src/lns-mounts-to-env.gen b/src/lns-mounts-to-env.gen
@@ -0,0 +1,7 @@
+#!/bin/sh -e
+
+export prog_sh=${prog_sh:-"$(which sh)"}
+export prog_awk=${prog_awk:-"$(which awk)"}
+export prog_execlineb=${prog_execlineb:-"$(which execlineb)"}
+
+awk -f "$(dirname "$0")/../scripts/abspaths.awk" "${0%.gen}.in"
diff --git a/src/lns-mounts-to-env.in b/src/lns-mounts-to-env.in
@@ -0,0 +1,44 @@
+#!shebang:sh
+prog=$(shquote:awk '
+function el_quote(s) {
+ gsub(/\\/, "\\\\", s); # first double all backslashes
+ gsub(/"/, "\\\"", s); # then escape quote marks
+ return "\"" s "\"" # then surround with quote marks
+}
+
+BEGIN {
+ # mount IDs seem to be unsigned, so lets use -1 to signify not found
+ max_id = -1
+ root_id = -1
+ count = 0
+}
+
+# read in /proc/self/mountinfo
+$5 == "/" { root_id = $1 }
+{
+ max_id = max_id < $1 ? $1 : max_id
+ parents[$1] = $2
+ mountpoints[$1] = $5
+}
+
+function print_umount(mtp){
+ print "NS_MTP_" (++count) "=" el_quote(mtp)
+}
+
+function recursively_umount(mount_id, id) {
+ for(id=max_id; id>=0; id--){
+ if(parents[id] == mount_id){
+ recursively_umount(id)
+ }
+ }
+ print_umount(mountpoints[mount_id])
+}
+
+END{
+ if(root_id == -1) { exit 111 }
+ print "env"
+ recursively_umount(root_id)
+ print "NS_MTP_COUNT=" count
+}
+' /proc/self/mountinfo) || exit $?
+exec shquote:execlineb -s0 -c "$prog \$@" "$@"