File: lsb

package info (click to toggle)
unit-translator 0.8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 632 kB
  • sloc: sh: 909; makefile: 28
file content (304 lines) | stat: -rw-r--r-- 10,965 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# LSB output backend
# shellcheck shell=bash

gen_shebang() {
	# Shebang
	printf '%s\n' '#! /bin/sh'
}

gen_init_d_script() {
	printf '%s\n' '# kFreeBSD does not accept scripts as interpreters, using #!/bin/sh and sourcing.'
	printf '%s\n' 'if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then'
	printf '%s\n' '   set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script'
	printf '%s\n' 'fi'
}

gen_start() {
	case "${install[WantedBy]:-}" in
	    	'') ;;
		sysinit.target) printf 'S' ;;
		single.target|basic.target) printf '1' ;;
		*.target) printf '2 3 4 5' ;;
		*) echo "WARNING: unknown start target runlevel ${install[WantedBy]}" >&2 ;;
	esac
}

gen_stop() {
	case "${install[WantedBy]:-}" in
	    	'') ;;
		*.target) printf '0 1 6' ;;
		*) echo "WARNING: unknown stop target runlevel ${install[WantedBy]}" >&2 ;;
	esac
}

munge_deps() {
    # In normal usage insserv will be installed. However, to pass autopkgtests
    # on Debian infra the dependency on sysv-rc (pulling in insserv) has been
    # reduced to Recommends, so we need to handle missing /etc/insserv.conf gracefully.
    self=$(set +o noglob
	   { [ ! -f /etc/insserv.conf ] && [ ! -d /etc/insserv.conf.d ] ; } ||
	       find /etc/insserv.conf* -type f -exec  awk "/$(basename "$lsb_init_script")/ {print \$1}" '{}' ';')
    for key in Requires Wants After Before; do
	for dep in ${depends[$key]:-}; do
	    if [[ "$dep" == "$self" ]] ; then
		remove_depend "$dep" "$key"
	    fi
	done
    done
    add_depends Wants ${depends[After]:-}
    for dep in ${depends[Requires]:-}; do
	remove_depend "$dep" Wants
    done
    for dep in ${depends[Wants]:-}; do
	remove_depend "$dep" Before
    done
}

gen_lsb_header() {
    # Uncomment to show the data parsed by the frontend
    # declare -p unit  >&2
    # declare -p service >&2
    # declare -p depends >&2
    # declare -p install >&2

	munge_deps
	printf '%s\n' '### BEGIN INIT INFO'
	printf '%s %s\n' '# Provides:' "$(basename "${systemd_unit%.*}")${install[Alias]:+ ${install[Alias]%.*}}"
	printf '%s %s\n' '# Required-Start:' "${depends[Requires]:-}"
	printf '%s %s\n' '# Required-Stop:' "${depends[Requires]:-}"
	[[ "${depends[Wants]:-}" ]] && printf '%s %s\n' '# Should-Start:' "${depends[Wants]}"
	[[ "${depends[Wants]:-}" ]] && printf '%s %s\n' '# Should-Stop:' "${depends[Wants]}"
	printf '%s %s\n' '# Default-Start:' "$(gen_start)"
	printf '%s %s\n' '# Default-Stop:'  "$(gen_stop)"
	[[ "${depends[Before]:-}" ]] && printf '%s %s\n' '# X-Start-Before:' "${depends[Before]}"
	[[ "${depends[Before]:-}" ]] && printf '%s %s\n' '# X-Stop-After:'  "${depends[Before]}"
#	printf '%s %s\n' '# X-Interactive:' 'true'
	printf '%s %s\n' '# Description:' "${unit[Description]:-None provided}"
	printf '%s\n' '### END INIT INFO'
}

gen_lsb_environment() {
	gen_environment

	if [[ "${service[ExecStop]:-}${service[ExecReload]:-}" =~ '$MAINPID' ]]; then
		print_directive MAINPID '$([ ! -f "/run/${DAEMON}.pid" ] || cat "/run/${DAEMON}.pid")'
	fi
}

gen_directives() {
    if [[ "${unit[Description]:-}" ]]; then
	print_directive DESC "${unit[Description]}"
    fi
    print_directive umask "${service[UMask]:-}"
    if [[ -n "${service[ExecStart]:-}" ]]; then
	if [[ "${service[Type]}" == 'oneshot' ]] ; then
	    print_directive DAEMON none
	    print_directive NAME "$(basename "${systemd_unit%.*}")"
	    print_directive TYPE oneshot
	    gen_lsb_environment
	    for key in "${!lsb[@]}"; do
		# Skip directives just for s-s-d
		[[ "$key" != START_ARGS ]] || continue
		print_directive "$key" "${lsb[$key]}"
	    done
	    print_sh_function do_start_cmd_override "$(handle_exec_prefixes "${service[ExecStart]}" runas)"
	else
	    set -- ${service[ExecStart]}
	    if [[ "${service[Type]}" == 'socket' ]]; then
		print_directive NAME "$(basename "${systemd_unit%.*}")"
		print_directive COMMAND_NAME none
		print_directive DAEMON none
		lsb[START_ARGS]+=' --startas /usr/bin/socket-activate'
	    else
		case $1 in
		    /*) print_directive DAEMON "$1" ;;
		    -*) print_directive DAEMON "${1#-}"
			echo "TODO: ignore s-s-d exit status" >&2
			;;
		    @*|+*|!*) echo "WARNING: ignoring special exec prefix" >&2
			      print_directive DAEMON "${1##@|+|!|!!}"
			      ;;
		    *) print_directive DAEMON "$(PATH=/usr/sbin:/usr/bin:/sbin:/bin: which "$1")" ;;
		esac
	    fi
	    shift
	    gen_lsb_environment
	    print_directive DAEMON_ARGS "$*"
	    for key in "${!lsb[@]}"; do
		print_directive "$key" "${lsb[$key]}"
	    done
	fi
    fi
    while read -r ulimit ; do
    	    printf 'ulimit %s\n' "$ulimit"
    done < <(gen_ulimit_args)
}

# Based on backends/openrc but with /lib/lsb/init-functions functions
gen_pre_checks() {
	for constraint in Assert Condition; do
		for test in ACPower Architecture Capability ControlGroupController CPUFeature CPUs DirectoryNotEmpty Environment FileIsExecutable FileNotEmpty Firmware FirstBoot Group Host KernelCommandLine KernelVersion Memory NeedsUpdate OSRelease PathExists PathExistsGlob PathIsDirectory PathIsEncrypted PathIsMountPoint PathIsReadWrite PathIsSymbolicLink Security User Virtualization; do
		    while
			read -r trigger
			read -r pre
			read -r p; do
			t=$(gen_test_case "$test" "$pre" "$p")
			if [ "${t}" ]; then
					if [ "${trigger}" ] ; then
					    triggers+=$'\n'"( $t ) ||"
					else
					    [ $constraint = 'Assert' ] && fail="echo \"Prohibited by ${constraint}${test} ${pre}${p}\"; exit 1" ||
						    fail="do_start_cmd_override() { log_warning_msg \" .. Skipped due to ${constraint}${test} ${pre}${p}\" ; }"
					    echo "$t || $fail"
					fi
				else
					echo "WARNING: unsupported test: $constraint $test ${pre}${p}" >&2
					echo ": # WARNING: skipped unsupported ${constraint}${test} ${pre}${p}"
				fi
			done < <(split_constraint "${unit[${constraint}${test}]:-}")
		done
	done
	if [[ "${triggers:-}" ]] ; then
	    printf '( # Triggering conditions\n'
	    # Remove the final trailing '||'
	    print_lines "${triggers%||}" ' '
	    printf ') || do_start_cmd_override() { log_warning_msg " .. Skipped due to no Triggering Conditions" ; }'
	fi
}

gen_functions() {
	# Combine pre-checks and handling of special exec prefixes
	service[ExecStartPre]=$(cat<<EOF
$(gen_pre_checks)
$(handle_exec_prefixes "${service[ExecStartPre]:-}" runas)
EOF
	       )
	# This appears at odds with init-d-script(5) which states:-
	#
	#  Additionally, it is possible to change the behaviour of the resulting
	#  shell script by overriding some of the internal functions.  To do so,
	#  define function with an _override suffix.
	#
	# However, this naming doesn't seem to apply to functions that are no-op.
	print_sh_function do_start_prepare "${service[ExecStartPre]:-}"
	print_sh_function do_start_cleanup  "$(handle_exec_prefixes "${service[ExecStartPost]:-}" runas)"
	print_sh_function do_stop_prepare  "$(handle_exec_prefixes "${service[ExecStopPre]:-}" runas)"
	print_sh_function do_stop_cleanup  "$(handle_exec_prefixes "${service[ExecStopPost]:-}" runas)"
	print_sh_function do_stop_cmd_override  "$(handle_exec_prefixes "${service[ExecStop]:-}" runas)"
	print_sh_function do_reload "$(handle_exec_prefixes "${service[ExecReload]:-}" runas)"
}

export_service() {
	systemd_unit=$1
	base_dir=$2
	init_dir="${base_dir}/init.d"
	mkdir -p "${init_dir}"

	if [[ $(basename "${systemd_unit%/*}") == 'user' ]] ;  then
		echo "LSB backend is not compatible with user services, skipping" >&2
		exit 0
	fi

	lsb_init_script="${init_dir}/$(basename "${systemd_unit%.*}")"

	if [[ -z "${lsb_init_script##*@}" ]] ; then
		echo "LSB backend doesn't support instantiated services, skipping" >&2
		exit 0
	fi

	# array to hold directives
	declare -A lsb

	case "${service[Type]}" in
		oneshot) ;;
		simple|exec|idle|dbus|socket) lsb[PIDFILE]="/run/$(basename "${lsb_init_script}").pid"
			lsb[START_ARGS]="--background --make-pidfile";;
		notify|notify-reload) lsb[PIDFILE]="/run/$(basename "${lsb_init_script}").pid"
			 lsb[START_ARGS]="--background --make-pidfile --notify-await"
			 if [[ "${service[Type]}" == 'notify-reload' ]]; then
			     lsb[RELOAD_SIGNAL]=HUP
			 fi
			;;
		forking) lsb[PIDFILE]=none ;;
	esac

	# run as $user and $group if the systemd service provides one
	if [[ "${service[User]:-}" ]]; then
		local user="${service[User]}"
		if [[ "${service[Group]:-}" ]]; then
			local group="${service[Group]}"
		fi
		lsb[START_ARGS]+=" --chuid ${user}${group:+:"${group}"}"
	fi

	if [[ -n "${service[Nice]:-}" ]]; then
		lsb[START_ARGS]+=" --nicelevel ${service[Nice]}"
	fi
	if [[ -n "${service[IOSchedulingClass]:-}" || -n "${service[IOSchedulingPriority]:-}" ]]; then
		lsb[START_ARGS]+=" --iosched ${service[IOSchedulingClass]:-best-effort}:${service[IOSchedulingPriority]:-4}"
	fi
	if [[ -n "${service[UMask]:-}" ]]; then
		lsb[START_ARGS]+=" --umask ${service[UMask]:-}"
	fi
	if [[ -n "${service[WorkingDirectory]:-}" ]]; then
		lsb[START_ARGS]+=" --chdir ${service[WorkingDirectory]#-}"
	fi
	if [[ -n "${service[RootDirectory]:-}" ]]; then
		lsb[START_ARGS]+=" --chroot ${service[RootDirectory]}"
	fi
	if [[ "$(uname -s)" == 'Linux' ]]; then
		if [[ -n "${service[NoNewPrivileges]:-}" ]] && is_true "${service[NoNewPrivileges]}"; then
			lsb[SETPRIV_ARGS]+="--no-new-privs "
		fi

		if [[ -n "${service[SecureBits]:-}" ]]; then
			secbits=${service[SecureBits]/-/_}
			lsb[SETPRIV_ARGS]+="--securebits +${secbits//[$' \r\t\n']/,+} "
		fi

		if [[ "${service[CapabilityBoundingSet]+defined}" ]] ; then
			case "${service[CapabilityBoundingSet]}" in
			    # start-stop-daemon requires CAP_SETUID and CAP_SETGID for --chuid
			    '') lsb[SETPRIV_ARGS]+="--bounding-set -all${service[User]:+,+CAP_SETUID,+CAP_SETGID} " ;;
			    ~*) caps="${service[CapabilityBoundingSet]//CAP_/,-}"
				if [[ "${service[User]:-}" ]] ; then
			    caps="${caps//,-SET[UG]ID}"
				fi
				lsb[SETPRIV_ARGS]+="--bounding-set +all${caps//[$'~ \r\t\n']} "
				;;
			    *) caps="${service[CapabilityBoundingSet]//CAP_/,+}"
			       lsb[SETPRIV_ARGS]+="--bounding-set -all${caps//[$' \r\t\n']} "
			       ;;
			esac
		fi
		if [[ "${service[AmbientCapabilities]+defined}" ]] ; then
			case "${service[AmbientCapabilities]}" in
			    '') lsb[SETPRIV_ARGS]+="--ambient-caps -all ";;
			    ~*) caps="${service[AmbientCapabilities]//CAP_/,-}"
				lsb[SETPRIV_ARGS]+="--ambient-caps +all${caps//[$'~ \r\t\n']} "
				;;
			    *) caps="${service[AmbientCapabilities]//CAP_/,+}"
			       lsb[SETPRIV_ARGS]+="--ambient-caps -all${caps//[$' \r\t\n']} "
			       # TODO: does this require --secbits keep-cap? See
			       # https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#AmbientCapabilities=
			       ;;
			esac
		fi
	fi

	# shebang
	gen_shebang >"${lsb_init_script}"
	# embed source and sha256
	gen_origin >>"${lsb_init_script}"
	# source init-d-script
	gen_init_d_script >>"${lsb_init_script}"

	gen_lsb_header >>"${lsb_init_script}"

	gen_directives >>"${lsb_init_script}"

	gen_functions >>"${lsb_init_script}"

	chmod +x "${lsb_init_script}"
}