diff --git a/contrib/TODO b/contrib/TODO deleted file mode 100644 index 6ec1312..0000000 --- a/contrib/TODO +++ /dev/null @@ -1,16 +0,0 @@ - -There are several things on the wishlist. See also the "wishlist" bugs filed -against sysvinit in the debian bugs system (http://www.debian.org/Bugs/). - -1. A special target for kbrequest, so that extra CHILDs are - created (each one needs its own utmp/wtmp bookkeeping) -2. Extend the initreq.h interface? -3. Add GNU last long options to last - -4. Write all boot messages to a logfile - Problem: TIOCCONS ioctl redirects console output, it doesn't copy it. - I think this is not easily possible without kernel support. - I do not like the idea of booting with a pseudo tty as console and - a redirect process behind it writing to both the real console and a - logfile - too fragile. - diff --git a/contrib/sysd2v.sh b/contrib/sysd2v.sh new file mode 100755 index 0000000..7c8d798 --- /dev/null +++ b/contrib/sysd2v.sh @@ -0,0 +1,482 @@ +#!/bin/sh +# sysd2v v0.2 -- systemd unit to sysvinit script converter +# Copyright (C) 2019 Trek http://www.trek.eu.org/devel/sysd2v +# distributed under the terms of the GNU General Public License 3 + + +nl=" +" + +# read a systemd unit file and set variables named ini_{section}_{key} +# usage: read_unit filename instance +# filename service unit configuration file, '-' to read from stdin +# instance instance name for template units +read_unit() +{ + filename=$1 + instance=$2 + + if [ "$filename" != - ] + then + inifile_unit_name=${filename##*/} + inifile_unit_name=${inifile_unit_name%.*} + fi + + rm_comm='/^[#;]/d' + concat=':l; /\\$/ { N; s/[[:space:]]*\\\n/ /; tl }' + subst_inst="s/%[Ii]/$instance/g" + unit=$( + cat "$filename" | + sed "$rm_comm" | + sed "$concat;$subst_inst" + ) + section_list=$( + printf %s "$unit" | + sed -n 's/^\[\([[:alnum:]]\+\)\].*/\1/p' + ) + oldifs=$IFS + IFS=$nl + + for section in $section_list + do + get_sect='/^\['"$section"'\]/,/^\[.\+\]/' + key_list=$( + printf %s "$unit" | + sed -n "$get_sect"'s/^\([[:alnum:]]\+\)[[:space:]]*=.*/\1/p' | + sort -u + ) + + for key in $key_list + do + val=$( + printf %s "$unit" | + sed -n "$get_sect"'s/^'"$key"'[[:space:]]*=[[:space:]]*\(.*\)/\1/p' + ) + var=$( + echo "${section}_$key" | + tr '[:upper:]' '[:lower:]' + ) + eval ini_$var=\$val + # FIXME: only to debug + echo "ini_$var=$val" >&2 + done + done + + IFS=$oldifs +} + + +# read a systemd configuration value and write its prefix to stdout +# usage: get_prefix val +# val systemd configuration value +get_prefix () { printf %s "$1" | sed -n 's/^\([-@:+!|]*\).*/\1/p'; } + + +# read a boolean value and returns true or false +# usage: is_true val +# val boolean value +is_true () { case "$1" in 1|[Oo][Nn]|[Tt]*|[Yy]*) true;; *) false; esac } + + +# read systemd services list and write LSB facilities to stdout +# usage: get_provides services +# services list of service units +get_provides () +{ + lst= + for dep in $1 + do + lst=${lst:+$lst }${dep%.service} + done + printf %s "$lst" +} + + +# read systemd units list and write LSB facilities to stdout +# usage: get_depends dependencies [ignores] +# dependencies list of required units +# ignores units to ignore +get_depends () +{ + lst= + for dep in $1 + do + d= + case $dep in + local-fs-pre.target) d=mountkernfs;; + time-sync.target) d=\$time;; + systemd-modules-load.service) d=kmod;; + local-fs.target|network-pre.target) d=\$local_fs;; + systemd-sysctl.service) d=procps;; + network.target|network-online.target|systemd-networkd.service) + d=\$network;; + nss-lookup.target) d=\$named;; + rpcbind.target|remote-fs-pre.target) d=\$portmap;; + remote-fs.target|sysinit.target|basic.target) d=\$remote_fs;; + syslog.service) d=\$syslog;; + boot-complete.target|multi-user.target|default.target) d=\$all;; + *.service) d=${dep%.service};; + *) echo "WARNING: unsupported target '$dep'" >&2 + esac + + ign=${2:+$2 }$lst + [ -z "$ign" -o -n "${ign%%*"$d"*}" ] && + lst=${lst:+$lst }$d + done + + printf %s "$lst" +} + + +# read LSB facilities list and write runlevel to stdout +# usage: get_runlevel facilities +# facilities list of required facilities +get_runlevel () +{ + case $1 in + *\$remote_fs*) echo 2 3 4 5;; + *) echo S + esac +} + + +# write a list of environment files to be executed +# usage: write_env list +# list files separated by newlines, with prefix (-) +write_env () +{ + oldifs=$IFS + IFS=$nl + + for env in $1 + do + pre=$(get_prefix "$env") + noerr= + + [ -n "$pre" -a -z "${pre%%*-*}" ] && noerr="[ -r ${env#$pre} ] && " + + printf '%s\n' "$noerr. ${env#$pre}" + done + + IFS=$oldifs + [ -n "$env" ] && echo +} + + +# write a list of commands applying systemd executable prefixes +# usage: write_commands list [run [runpriv]] +# list commands separated by newlines, with prefixes (-@:+!) +# run command line to run each command (nice, chrt, ...) +# runpriv command line to set privileges (runuser, ...) +write_commands () +{ + oldifs=$IFS + IFS=$nl + + for cmd in $1 + do + pre=$(get_prefix "$cmd") + beg=$3 + end=' || return 2' + + if [ -n "$pre" ] + then + [ -z "${pre%%*-*}" ] && end= + [ -z "${pre%%*[+!]*}" ] && beg= + [ -z "${pre%%*[@:]*}" ] && + echo "WARNING: unsupported exec prefix '$pre'" >&2 + fi + + printf ' %s\n' "$2$beg${cmd#$pre}$end" + done + + IFS=$oldifs +} + + +# read a list of commands separated by newlines and write an override function +# usage: write_function name [commands] +# name function name (start_cmd, stop_cmd, ...) +# commands list of commands, read from stdin if omitted +write_function () +{ + lst=${2-$(cat)} + + [ -n "$lst" ] || return + [ "$lst" = : ] && printf "do_${1}_override () :\n\n" && return + + end=' true\n' + [ -z "${lst%%*|| return [0-9]}" -o -z "${lst%%*|| return \$?}" ] && end= + printf "do_${1}_override ()\n{\n%s\n$end}\n\n" "$lst" +} + + +# write an init-d-script file starting from the ini_* vars (see read_unit) +# usage: write_init servicename instance +# servicename name of the service provided +# instance instance name for template units +write_init () +{ + name=$1 + instance=$2 + + if [ "${name%@}" != "$name" ] + then + name=$name$instance + fi + + daemon_pre=$(get_prefix "$ini_service_execstart") + daemon=${ini_service_execstart#$daemon_pre} + + if [ "${daemon%%[[:space:]]*}" != "$daemon" ] + then + daemon_args=${daemon#*[[:space:]]} + daemon=${daemon%%[[:space:]]*} + fi + + pidfile=$ini_service_pidfile + + if [ -n "$ini_service_user" ] + then + start_args="--user $ini_service_user" + [ -n "$daemon_pre" -a -z "${daemon_pre%%*[+!]*}" ] || + start_args="$start_args --chuid $ini_service_user" + stop_args="--user $ini_service_user" + runprivstart="runuser -u $ini_service_user -- " + is_true "$ini_service_permissionsstartonly" || runpriv=$runprivstart + fi + + cls=$ini_service_ioschedulingclass + pri=$ini_service_ioschedulingpriority + [ -n "$cls$pri" ] && + start_args="$start_args --iosched ${cls:-best-effort}${pri:+:$pri}" && + run="ionice ${cls:+-c $cls }${pri:+-n $pri }" + + pol=$ini_service_cpuschedulingpolicy + pri=$ini_service_cpuschedulingpriority + [ -n "$pol$pri" ] && + start_args="$start_args --procsched ${pol:-other}${pri:+:$pri}" && + run="${run}chrt ${pol:+--$pol }${pri:-0} " + + [ -n "$ini_service_nice" ] && + start_args="$start_args --nicelevel $ini_service_nice" && + run="${run}nice -n $ini_service_nice " + + pre=$(get_prefix "$ini_service_workingdirectory") + workdir=${ini_service_workingdirectory#$pre} + [ "$workdir" = '~' ] && workdir=\~$ini_service_user + [ -n "$workdir" ] && + start_args="$start_args --chdir $workdir" && + chdir="${pre}cd $workdir" + + if [ -z "${service_type:=$ini_service_type}" ] + then + if [ -n "$ini_service_busname" ] + then + service_type=dbus + elif [ -n "$ini_service_execstart" ] + then + service_type=simple + else + service_type=oneshot + fi + fi + + if [ "$service_type" != forking ] + then + start_args="$start_args --background" + [ -z "$pidfile" -a "$ini_service_killmode" != none ] && + start_args="$start_args --make-pidfile" && + pidfile="/run/$name-sysd2v.pid" + fi + + if [ "$service_type" = notify ] + then + start_args="$start_args --notify-await" + timeout=${ini_service_timeoutstartsec:-$ini_service_timeoutsec} + timeout=${timeout%s} + [ -n "${timeout#60}" ] && + start_args="$start_args --notify-timeout $timeout" + [ -n "$timeout" -a -z "${timeout%%*[^0-9]*}" ] && + echo "WARNING: unsupported timeout '$timeout'" >&2 + elif [ "$service_type" = dbus ] + then + : TODO + fi + + signal=${ini_service_killsignal#SIG} + timeout=${ini_service_timeoutstopsec:-$ini_service_timeoutsec} + timeout=${timeout%s} + [ -n "${signal#TERM}" -o -n "${timeout#90}" ] && + stop_args="$stop_args --retry=${signal:-TERM}/${timeout:-90}/KILL/5" + + limitnofile=$ini_service_limitnofile + [ "$limitnofile" = infinity ] && limitnofile=unlimited + + execstop=$ini_service_execstop + + if [ "$service_type" != oneshot ] + then + [ "$pidfile" = "/var/run/${daemon##*/}.pid" ] && unset pidfile + [ "$name" = "${daemon##*/}" ] && unset name + + [ -n "$daemon_args" -a -z "${daemon_args%%*[\"\\]*}" ] && + echo "WARNING: DAEMON_ARGS needs to be escaped" >&2 + errcheck=' || return $?' + + if [ -n "$daemon_pre" ] + then + [ -z "${daemon_pre%%*-*}" ] && errcheck= + [ -z "${daemon_pre%%*[@:]*}" ] && + echo "WARNING: unsupported exec prefix '$daemon_pre'" >&2 + fi + + # TODO: test if already running before start (pretest="+do_status_cmd") + [ -n "$ini_service_execstartpre$ini_service_execstartpost" -o \ + -z "$errcheck" ] && + execstart="-+do_start_cmd$errcheck" + + errcheck=' || return $?' + [ -n "$execstop" ] && errcheck= + [ -n "$execstop$ini_service_execstoppost" -a \ + "$ini_service_killmode" != none ] && + killstop="-do_stop_cmd$errcheck" + + [ -n "$timeout" -a -z "${timeout%%*[^0-9]*}" ] && + echo "WARNING: unsupported timeout '$timeout'" >&2 + else + daemon=none + pidfile=none + : ${name:=SERVICE_NAME} + unset daemon_args start_args stop_args + execstart=$ini_service_execstart + runstart=$run + fi + + start_args=${start_args# } + stop_args=${stop_args# } + + aliases=$(get_provides "$ini_install_alias") + + [ -z "$ini_unit_defaultdependencies" ] || + is_true "$ini_unit_defaultdependencies" && + defdep=sysinit.target + + req_start=$(get_depends "$ini_unit_requires $defdep") + should_start=$(get_depends "$ini_unit_wants $ini_unit_after" "$req_start") + + default_start=$(get_runlevel "$req_start $should_start") + [ "$default_start" = S ] && default_stop='0 6' || default_stop='0 1 6' + [ -z "$execstop$ini_service_execstoppost" ] && + [ "$service_type" = oneshot -o "$ini_service_killmode" = none ] && + default_stop= + + [ "$default_start" = S ] && ignore=\$remote_fs + start_before=$(get_depends "$ini_unit_requiredby $ini_install_wantedby + $ini_unit_before" "$req_start $should_start \$all $ignore") + + cat <