systemd.eclass: add @SUPPORTED_EAPIS
[gentoo.git] / eclass / systemd.eclass
1 # Copyright 1999-2017 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 # @ECLASS: systemd.eclass
5 # @MAINTAINER:
6 # systemd@gentoo.org
7 # @SUPPORTED_EAPIS: 0 1 2 3 4 5 6 7
8 # @BLURB: helper functions to install systemd units
9 # @DESCRIPTION:
10 # This eclass provides a set of functions to install unit files for
11 # sys-apps/systemd within ebuilds.
12 # @EXAMPLE:
13 #
14 # @CODE
15 # inherit systemd
16 #
17 # src_configure() {
18 #       local myconf=(
19 #               --enable-foo
20 #               --with-systemdsystemunitdir="$(systemd_get_systemunitdir)"
21 #       )
22 #
23 #       econf "${myconf[@]}"
24 # }
25 # @CODE
26
27 inherit toolchain-funcs
28
29 case ${EAPI:-0} in
30         0|1|2|3|4|5|6|7) ;;
31         *) die "${ECLASS}.eclass API in EAPI ${EAPI} not yet established."
32 esac
33
34 if [[ ${EAPI:-0} == [0123456] ]]; then
35         DEPEND="virtual/pkgconfig"
36 else
37         BDEPEND="virtual/pkgconfig"
38 fi
39
40 # @FUNCTION: _systemd_get_dir
41 # @USAGE: <variable-name> <fallback-directory>
42 # @INTERNAL
43 # @DESCRIPTION:
44 # Try to obtain the <variable-name> variable from systemd.pc.
45 # If pkg-config or systemd is not installed, return <fallback-directory>
46 # instead.
47 _systemd_get_dir() {
48         [[ ${#} -eq 2 ]] || die "Usage: ${FUNCNAME} <variable-name> <fallback-directory>"
49         local variable=${1} fallback=${2} d
50
51         if $(tc-getPKG_CONFIG) --exists systemd; then
52                 d=$($(tc-getPKG_CONFIG) --variable="${variable}" systemd) || die
53                 d=${d#${EPREFIX}}
54         else
55                 d=${fallback}
56         fi
57
58         echo "${d}"
59 }
60
61 # @FUNCTION: _systemd_get_unitdir
62 # @INTERNAL
63 # @DESCRIPTION:
64 # Get unprefixed unitdir.
65 _systemd_get_systemunitdir() {
66         _systemd_get_dir systemdsystemunitdir /lib/systemd/system
67 }
68
69 # @FUNCTION: systemd_get_systemunitdir
70 # @DESCRIPTION:
71 # Output the path for the systemd system unit directory (not including
72 # ${D}).  This function always succeeds, even if systemd is not
73 # installed.
74 systemd_get_systemunitdir() {
75         has "${EAPI:-0}" 0 1 2 && ! use prefix && EPREFIX=
76         debug-print-function ${FUNCNAME} "${@}"
77
78         echo "${EPREFIX}$(_systemd_get_systemunitdir)"
79 }
80
81 # @FUNCTION: systemd_get_unitdir
82 # @DESCRIPTION:
83 # Deprecated alias for systemd_get_systemunitdir.
84 systemd_get_unitdir() {
85         [[ ${EAPI} == [012345] ]] || die "${FUNCNAME} is banned in EAPI 6, use systemd_get_systemunitdir instead"
86
87         systemd_get_systemunitdir
88 }
89
90 # @FUNCTION: _systemd_get_userunitdir
91 # @INTERNAL
92 # @DESCRIPTION:
93 # Get unprefixed userunitdir.
94 _systemd_get_userunitdir() {
95         _systemd_get_dir systemduserunitdir /usr/lib/systemd/user
96 }
97
98 # @FUNCTION: systemd_get_userunitdir
99 # @DESCRIPTION:
100 # Output the path for the systemd user unit directory (not including
101 # ${D}). This function always succeeds, even if systemd is not
102 # installed.
103 systemd_get_userunitdir() {
104         has "${EAPI:-0}" 0 1 2 && ! use prefix && EPREFIX=
105         debug-print-function ${FUNCNAME} "${@}"
106
107         echo "${EPREFIX}$(_systemd_get_userunitdir)"
108 }
109
110 # @FUNCTION: _systemd_get_utildir
111 # @INTERNAL
112 # @DESCRIPTION:
113 # Get unprefixed utildir.
114 _systemd_get_utildir() {
115         _systemd_get_dir systemdutildir /lib/systemd
116 }
117
118 # @FUNCTION: systemd_get_utildir
119 # @DESCRIPTION:
120 # Output the path for the systemd utility directory (not including
121 # ${D}). This function always succeeds, even if systemd is not
122 # installed.
123 systemd_get_utildir() {
124         has "${EAPI:-0}" 0 1 2 && ! use prefix && EPREFIX=
125         debug-print-function ${FUNCNAME} "${@}"
126
127         echo "${EPREFIX}$(_systemd_get_utildir)"
128 }
129
130 # @FUNCTION: _systemd_get_systemgeneratordir
131 # @INTERNAL
132 # @DESCRIPTION:
133 # Get unprefixed systemgeneratordir.
134 _systemd_get_systemgeneratordir() {
135         _systemd_get_dir systemdsystemgeneratordir /lib/systemd/system-generators
136 }
137
138 # @FUNCTION: systemd_get_systemgeneratordir
139 # @DESCRIPTION:
140 # Output the path for the systemd system generator directory (not including
141 # ${D}). This function always succeeds, even if systemd is not
142 # installed.
143 systemd_get_systemgeneratordir() {
144         has "${EAPI:-0}" 0 1 2 && ! use prefix && EPREFIX=
145         debug-print-function ${FUNCNAME} "${@}"
146
147         echo "${EPREFIX}$(_systemd_get_systemgeneratordir)"
148 }
149
150 # @FUNCTION: systemd_dounit
151 # @USAGE: <unit>...
152 # @DESCRIPTION:
153 # Install systemd unit(s). Uses doins, thus it is fatal in EAPI 4
154 # and non-fatal in earlier EAPIs.
155 systemd_dounit() {
156         debug-print-function ${FUNCNAME} "${@}"
157
158         (
159                 insopts -m 0644
160                 insinto "$(_systemd_get_systemunitdir)"
161                 doins "${@}"
162         )
163 }
164
165 # @FUNCTION: systemd_newunit
166 # @USAGE: <old-name> <new-name>
167 # @DESCRIPTION:
168 # Install systemd unit with a new name. Uses newins, thus it is fatal
169 # in EAPI 4 and non-fatal in earlier EAPIs.
170 systemd_newunit() {
171         debug-print-function ${FUNCNAME} "${@}"
172
173         (
174                 insopts -m 0644
175                 insinto "$(_systemd_get_systemunitdir)"
176                 newins "${@}"
177         )
178 }
179
180 # @FUNCTION: systemd_douserunit
181 # @USAGE: <unit>...
182 # @DESCRIPTION:
183 # Install systemd user unit(s). Uses doins, thus it is fatal in EAPI 4
184 # and non-fatal in earlier EAPIs.
185 systemd_douserunit() {
186         debug-print-function ${FUNCNAME} "${@}"
187
188         (
189                 insopts -m 0644
190                 insinto "$(_systemd_get_userunitdir)"
191                 doins "${@}"
192         )
193 }
194
195 # @FUNCTION: systemd_newuserunit
196 # @USAGE: <old-name> <new-name>
197 # @DESCRIPTION:
198 # Install systemd user unit with a new name. Uses newins, thus it
199 # is fatal in EAPI 4 and non-fatal in earlier EAPIs.
200 systemd_newuserunit() {
201         debug-print-function ${FUNCNAME} "${@}"
202
203         (
204                 insopts -m 0644
205                 insinto "$(_systemd_get_userunitdir)"
206                 newins "${@}"
207         )
208 }
209
210 # @FUNCTION: systemd_install_serviced
211 # @USAGE: <conf-file> [<service>]
212 # @DESCRIPTION:
213 # Install <conf-file> as the template <service>.d/00gentoo.conf.
214 # If <service> is not specified
215 # <conf-file> with the .conf suffix stripped is used
216 # (e.g. foo.service.conf -> foo.service.d/00gentoo.conf).
217 systemd_install_serviced() {
218         debug-print-function ${FUNCNAME} "${@}"
219
220         local src=${1}
221         local service=${2}
222
223         [[ ${src} ]] || die "No file specified"
224
225         if [[ ! ${service} ]]; then
226                 [[ ${src} == *.conf ]] || die "Source file needs .conf suffix"
227                 service=${src##*/}
228                 service=${service%.conf}
229         fi
230         # avoid potentially common mistake
231         [[ ${service} == *.d ]] && die "Service must not have .d suffix"
232
233         (
234                 insopts -m 0644
235                 insinto /etc/systemd/system/"${service}".d
236                 newins "${src}" 00gentoo.conf
237         )
238 }
239
240 # @FUNCTION: systemd_dotmpfilesd
241 # @USAGE: <tmpfilesd>...
242 # @DESCRIPTION:
243 # Install systemd tmpfiles.d files. Uses doins, thus it is fatal
244 # in EAPI 4 and non-fatal in earlier EAPIs.
245 systemd_dotmpfilesd() {
246         debug-print-function ${FUNCNAME} "${@}"
247
248         for f; do
249                 [[ ${f} == *.conf ]] \
250                         || die 'tmpfiles.d files need to have .conf suffix.'
251         done
252
253         (
254                 insopts -m 0644
255                 insinto /usr/lib/tmpfiles.d/
256                 doins "${@}"
257         )
258 }
259
260 # @FUNCTION: systemd_newtmpfilesd
261 # @USAGE: <old-name> <new-name>.conf
262 # @DESCRIPTION:
263 # Install systemd tmpfiles.d file under a new name. Uses newins, thus it
264 # is fatal in EAPI 4 and non-fatal in earlier EAPIs.
265 systemd_newtmpfilesd() {
266         debug-print-function ${FUNCNAME} "${@}"
267
268         [[ ${2} == *.conf ]] \
269                 || die 'tmpfiles.d files need to have .conf suffix.'
270
271         (
272                 insopts -m 0644
273                 insinto /usr/lib/tmpfiles.d/
274                 newins "${@}"
275         )
276 }
277
278 # @FUNCTION: systemd_enable_service
279 # @USAGE: <target> <service>
280 # @DESCRIPTION:
281 # Enable service in desired target, e.g. install a symlink for it.
282 # Uses dosym, thus it is fatal in EAPI 4 and non-fatal in earlier
283 # EAPIs.
284 systemd_enable_service() {
285         debug-print-function ${FUNCNAME} "${@}"
286
287         [[ ${#} -eq 2 ]] || die "Synopsis: systemd_enable_service target service"
288
289         local target=${1}
290         local service=${2}
291         local ud=$(_systemd_get_systemunitdir)
292         local destname=${service##*/}
293
294         dodir "${ud}"/"${target}".wants && \
295         dosym ../"${service}" "${ud}"/"${target}".wants/"${destname}"
296 }
297
298 # @FUNCTION: systemd_enable_ntpunit
299 # @USAGE: <NN-name> <service>...
300 # @DESCRIPTION:
301 # Add an NTP service provider to the list of implementations
302 # in timedated. <NN-name> defines the newly-created ntp-units.d priority
303 # and name, while the remaining arguments list service units that will
304 # be added to that file.
305 #
306 # Uses doins, thus it is fatal in EAPI 4 and non-fatal in earlier
307 # EAPIs.
308 #
309 # Doc: https://www.freedesktop.org/wiki/Software/systemd/timedated/
310 systemd_enable_ntpunit() {
311         debug-print-function ${FUNCNAME} "${@}"
312         if [[ ${#} -lt 2 ]]; then
313                 die "Usage: systemd_enable_ntpunit <NN-name> <service>..."
314         fi
315
316         local ntpunit_name=${1}
317         local services=( "${@:2}" )
318
319         if [[ ${ntpunit_name} != [0-9][0-9]-* ]]; then
320                 die "ntpunit.d file must be named NN-name where NN are digits."
321         elif [[ ${ntpunit_name} == *.list ]]; then
322                 die "The .list suffix is appended implicitly to ntpunit.d name."
323         fi
324
325         local unitdir=$(systemd_get_systemunitdir)
326         local s
327         for s in "${services[@]}"; do
328                 if [[ ! -f "${D}${unitdir}/${s}" ]]; then
329                         die "ntp-units.d provider ${s} not installed (yet?) in \${D}."
330                 fi
331                 echo "${s}" >> "${T}"/${ntpunit_name}.list || die
332         done
333
334         (
335                 insopts -m 0644
336                 insinto "$(_systemd_get_utildir)"/ntp-units.d
337                 doins "${T}"/${ntpunit_name}.list
338         )
339         local ret=${?}
340
341         rm "${T}"/${ntpunit_name}.list || die
342
343         return ${ret}
344 }
345
346 # @FUNCTION: systemd_with_unitdir
347 # @USAGE: [<configure-option-name>]
348 # @DESCRIPTION:
349 # Note: deprecated and banned in EAPI 6. Please use full --with-...=
350 # parameter for improved ebuild readability.
351 #
352 # Output '--with-systemdsystemunitdir' as expected by systemd-aware configure
353 # scripts. This function always succeeds. Its output may be quoted in order
354 # to preserve whitespace in paths. systemd_to_myeconfargs() is preferred over
355 # this function.
356 #
357 # If upstream does use invalid configure option to handle installing systemd
358 # units (e.g. `--with-systemdunitdir'), you can pass the 'suffix' as an optional
359 # argument to this function (`$(systemd_with_unitdir systemdunitdir)'). Please
360 # remember to report a bug upstream as well.
361 systemd_with_unitdir() {
362         [[ ${EAPI:-0} != [012345] ]] && die "${FUNCNAME} is banned in EAPI ${EAPI}, use --with-${1:-systemdsystemunitdir}=\"\$(systemd_get_systemunitdir)\" instead"
363
364         debug-print-function ${FUNCNAME} "${@}"
365         local optname=${1:-systemdsystemunitdir}
366
367         echo --with-${optname}="$(systemd_get_systemunitdir)"
368 }
369
370 # @FUNCTION: systemd_with_utildir
371 # @DESCRIPTION:
372 # Note: deprecated and banned in EAPI 6. Please use full --with-...=
373 # parameter for improved ebuild readability.
374 #
375 # Output '--with-systemdsystemutildir' as used by some packages to install
376 # systemd helpers. This function always succeeds. Its output may be quoted
377 # in order to preserve whitespace in paths.
378 systemd_with_utildir() {
379         [[ ${EAPI:-0} != [012345] ]] && die "${FUNCNAME} is banned in EAPI ${EAPI}, use --with-systemdutildir=\"\$(systemd_get_utildir)\" instead"
380
381         debug-print-function ${FUNCNAME} "${@}"
382
383         echo --with-systemdutildir="$(systemd_get_utildir)"
384 }
385
386 # @FUNCTION: systemd_update_catalog
387 # @DESCRIPTION:
388 # Update the journald catalog. This needs to be called after installing
389 # or removing catalog files. This must be called in pkg_post* phases.
390 #
391 # If systemd is not installed, no operation will be done. The catalog
392 # will be (re)built once systemd is installed.
393 #
394 # See: https://www.freedesktop.org/wiki/Software/systemd/catalog
395 systemd_update_catalog() {
396         debug-print-function ${FUNCNAME} "${@}"
397
398         [[ ${EBUILD_PHASE} == post* ]] \
399                 || die "${FUNCNAME} disallowed during ${EBUILD_PHASE_FUNC:-${EBUILD_PHASE}}"
400
401         # Make sure to work on the correct system.
402
403         local journalctl=${EPREFIX}/usr/bin/journalctl
404         if [[ -x ${journalctl} ]]; then
405                 ebegin "Updating systemd journal catalogs"
406                 journalctl --update-catalog
407                 eend $?
408         else
409                 debug-print "${FUNCNAME}: journalctl not found."
410         fi
411 }
412
413 # @FUNCTION: systemd_is_booted
414 # @DESCRIPTION:
415 # Check whether the system was booted using systemd.
416 #
417 # This should be used purely for informational purposes, e.g. warning
418 # user that he needs to use systemd. Installed files or application
419 # behavior *must not* rely on this. Please remember to check MERGE_TYPE
420 # to not trigger the check on binary package build hosts!
421 #
422 # Returns 0 if systemd is used to boot the system, 1 otherwise.
423 #
424 # See: man sd_booted
425 systemd_is_booted() {
426         debug-print-function ${FUNCNAME} "${@}"
427
428         [[ -d /run/systemd/system ]]
429         local ret=${?}
430
431         debug-print "${FUNCNAME}: [[ -d /run/systemd/system ]] -> ${ret}"
432         return ${ret}
433 }
434
435 # @FUNCTION: systemd_tmpfiles_create
436 # @USAGE: <tmpfilesd> ...
437 # @DESCRIPTION:
438 # Invokes systemd-tmpfiles --create with given arguments.
439 # Does nothing if ROOT != / or systemd-tmpfiles is not in PATH.
440 # This function should be called from pkg_postinst.
441 #
442 # Generally, this function should be called with the names of any tmpfiles
443 # fragments which have been installed, either by the build system or by a
444 # previous call to systemd_dotmpfilesd. This ensures that any tmpfiles are
445 # created without the need to reboot the system.
446 systemd_tmpfiles_create() {
447         debug-print-function ${FUNCNAME} "${@}"
448
449         [[ ${EBUILD_PHASE} == postinst ]] || die "${FUNCNAME}: Only valid in pkg_postinst"
450         [[ ${#} -gt 0 ]] || die "${FUNCNAME}: Must specify at least one filename"
451         [[ ${ROOT} == / ]] || return 0
452         type systemd-tmpfiles &> /dev/null || return 0
453         systemd-tmpfiles --create "${@}"
454 }
455
456 # @FUNCTION: systemd_reenable
457 # @USAGE: <unit> ...
458 # @DESCRIPTION:
459 # Re-enables units if they are currently enabled. This resets symlinks to the
460 # defaults specified in the [Install] section.
461 #
462 # This function is intended to fix broken symlinks that result from moving
463 # the systemd system unit directory. It should be called from pkg_postinst
464 # for system units that define the 'Alias' option in their [Install] section.
465 # It is not necessary to call this function to fix dependency symlinks
466 # generated by the 'WantedBy' and 'RequiredBy' options.
467 systemd_reenable() {
468         type systemctl &>/dev/null || return 0
469         local x
470         for x; do
471                 if systemctl --quiet --root="${ROOT}" is-enabled "${x}"; then
472                         systemctl --root="${ROOT}" reenable "${x}"
473                 fi
474         done
475 }