Index: bin/Makefile =================================================================== --- bin/Makefile +++ bin/Makefile @@ -29,6 +29,7 @@ ps \ pwait \ pwd \ + rc-status \ realpath \ rm \ rmdir \ Index: bin/rc-status/Makefile =================================================================== --- /dev/null +++ bin/rc-status/Makefile @@ -0,0 +1,26 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= rc-status + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= rc-status.c \ + rc-misc.c \ + _usage.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 +MAN= ${.CURDIR}/../../contrib/openrc/man/rc-status.8 + +LIBADD= einfo rc + +.include Index: bin/rc-status/Makefile.depend =================================================================== --- /dev/null +++ bin/rc-status/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/librc \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: contrib/openrc/AUTHORS =================================================================== --- /dev/null +++ contrib/openrc/AUTHORS @@ -0,0 +1,99 @@ +Alessio Ababilov +Alexander Berntsen +Alexander Mezin +Alexander Tsoy +Alexander Vershilov +Alexander Vershilov +Alexander V Vershilov +Alexey Shvetsov +Alon Bar-Lev +Amadeusz Żołnowski +Andrew Gregory +Anthony Donnelly +Anthony G. Basile +Anthony G. Basile +Austin S. Hemmelgarn +Benda Xu +Björn Baumbach +Charlie +Chris Richards +Christian +Christian Ruppert +Christian Wetzig +Christopher Head +Consus +Daniel Mierswa +Daniel Robbins +Diego Elio Pettenò +Diego Elio Pettenò +Diego +Dirk Sondermann +Doug Freed +Doug Goldstein +Ed Wildgoose +Eray Aslan +Eugeny Shkrigunov +Fedja Beader +Flex +Gabriele Giacone <1o5g4r8o@gmail.com> +Gary +Gilles Oivier +Hank Leininger +Ian Stakenvicius +Jakob Drexel +James Le Cuirot +Jan Psota +Jason Zaman +Joe Harvell +Joe M +Johan Bergström +Jory A. Pratt +Juan RP +Kaarle Ritvanen +Kfir Lavi +Kirill Elagin +Lars Wendler +Lorand Kelemen +Marc Joliet +Marien Zwart +Michal Gorny +Mihai Moldovan +Mike Frysinger +Mike Gilbert +Nao Nakashima +Natanael Copa +Nathan Phillip Brink +Ned Ludd +Olivier Huber +Patrick Lauer +Petre Rodan +Piotr Karbowski +Ralph Sennhauser +Richard Yao +Rick Farina (ZeroChaos) +Rick Farina (Zero_Chaos) +Robin H. Johnson +Robin H. Johnson +Robin Johnson +Roy Marples +Salah Coronya +Sebastian Thorarensen +Semen Maryasin +Sergei Trofimovich +Seth Robertson +S. Gilles +Stefan Knoblich +Stef Simoens +Steve L +Steven Chamberlain +Svante Signell +Sven Vermeulen +Thomas D +Thomas Pfaff +Trevor Summers Smith +Walter +William Hubbs +William Hubbs +Will Miles +Yun Zheng Hu +Yuta SATOH Index: contrib/openrc/BUSYBOX.md =================================================================== --- /dev/null +++ contrib/openrc/BUSYBOX.md @@ -0,0 +1,30 @@ +Using Busybox as your Default Shell with OpenRC +=============================================== + +If you have/bin/sh linked to busybox, you need to be aware of several +incompatibilities between busybox's applets and the standalone +counterparts. Since it is possible to configure busybox to not include +these applets or to prefer the standalone counterparts, OpenRC does not +attempt to support the busybox applets. + +For now, it is recommended that you disable the following busybox +configuration settings for best results with OpenRC. + +CONFIG_START_STOP_DAEMON -- The start-stop-daemon applet is not compatible with +start-stop-daemon in OpenRC. + +CONFIG_MOUNT -- The mount applet does not support the -O [no]_netdev options to +skip over or include network file systems when the -a option is present. + +CONFIG_UMOUNT -- The umount applet does not support the -O option along with -a. + +CONFIG_SWAPONOFF -- The swapon applet does not support the -e option +or recognize the nofail option in fstab. + +CONFIG_SETFONT -- The setfont applet does not support the -u option from kbd. + +CONFIG_BB_SYSCTL -- The sysctl applet does not support the --system command +line switch. + +There is work to get most of these supported by busybox, so this file +will be updated as things change. Index: contrib/openrc/ChangeLog =================================================================== --- /dev/null +++ contrib/openrc/ChangeLog @@ -0,0 +1,1474 @@ +commit f5acc66db7d1a0bfad6a40eefc0240b80f52df94 +Author: William Hubbs +Commit: William Hubbs + + rc_find_pids: ignore pids that are not in our pid namespace + + X-Gentoo-Bug: 634634 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=634634 + +commit fdce4769f2e0f4175163ffa181c7b3b2192f7b22 +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: multiple fixes + + - Harden against dying by handling all signals that would terminate the + program and adding --reexec support + - factor the supervisor into its own function + - fix test for whether we are already running + +commit 35b1996704f6635bb29ea3604410e133209e6432 +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: elevate some log messages to warnings + + Prior to this change, we were logging unexpected terminations of daemons + we were supervising at the info level. This change moves the logs to + warnings. + +commit 3c8e7ed255edb8df0d548d6ce514544d5422cbf0 +Author: William Hubbs +Commit: William Hubbs + + version 0.34 + +commit acaed1f910a2a00fdd5b6aeab752c552075a7292 +Author: William Hubbs +Commit: William Hubbs + + Update ChangeLog + +commit 91109e31d81ecd48f5690ad6f63103fca545dec7 +Author: William Hubbs +Commit: William Hubbs + + update news + +commit 2b6eeea01d1c64d58929788f4bfa0758393885bf +Author: William Hubbs +Commit: William Hubbs + + man: remove service(8) man page + +commit a15de23e5713d840d871c526b46050983dc6ea1e +Author: William Hubbs +Commit: William Hubbs + + typo fix + +commit efa9ba485d9328f780f3e60dc18339c75974c6c6 +Author: William Hubbs +Commit: William Hubbs + + init.d/sysfs.in: fix reference to RC_LIBEXECDIR + + The sysfs init script referred to @LIBEXECDIR@ before this change, but + it is better to refer to RC_LIBEXECDIR so that we get rid of a sed + substitution. + +commit d4ddd72701ff5533a1ba07b1da60806859c63d88 +Author: Chris Cromer +Commit: William Hubbs + + add option to make agetty startup quiet + + This fixes #150 + +commit 1e9af2cd421423404ffe1491bd35af76c2885f1f +Author: William Hubbs +Commit: William Hubbs + + fix compiler warning + +commit 3c05db74f6e733890e9035c183a774db3d512512 +Author: William Hubbs +Commit: William Hubbs + + remove service binary + + The service binary was just a synonym for rc-service, so use rc-service + instead of service. If you want a "service" binary, it should be + something that can determine which service manager you are running and + run the appropriate service manager commands. + +commit edc54b03770d5f58d1a4969d06c28660003dfb04 +Author: William Hubbs +Commit: William Hubbs + + version 0.33 + +commit 8e53a3fa8a33fb714064ddbe38bff2213fcf6837 +Author: William Hubbs +Commit: William Hubbs + + Update ChangeLog + +commit 7f3b41311119e3a96a15b0fb473b44f422e903e9 +Author: William Hubbs +Commit: William Hubbs + + use printf consistently in cgroups handling + + This makes the cgroups handling consistent between cgroups v1 and v2. + Also, it fixes #167. + +commit 1ccba056584ee1a8e09fb1d5eebd988b47912c06 +Author: William Hubbs +Commit: William Hubbs + + sh/rc-functions.sh: add need_if_exists convenience function + +commit c46adf14343df3a74aef7e4ae5be175ae5fa7a01 +Author: William Hubbs +Commit: William Hubbs + + man/openrc-run.8: Clarify the explanation of the need dependency + +commit 1cac8b080c16f9aab19c7a3ae1ca155c20dfa14d +Author: William Hubbs +Commit: William Hubbs + + ignore sigchld when shutting down the supervised process + + We need to do this to skip the zombie state for the child process since + we are not easily able to wait() for it. + +commit b58194ef63ec8c0a7e0ea3c291da9c19aa83cb1a +Author: William Hubbs +Commit: William Hubbs + + typo fix + +commit b28c0d6f66e42b1e6d2a39c286a18c8d92881790 +Author: William Hubbs +Commit: William Hubbs + + typo fix + +commit 3cf19b0f30a90157d23d09ded304439f1eb42d4a +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: code cleanup + + Clean up the process for killing an active supervisor when stopping. + +commit 0eb47b9af340dd07209a3920944ed085fe7bd359 +Author: William Hubbs +Commit: William Hubbs + + initialize the stop schedule + +commit 4ab60ff10935122277bbaed437f82a765279cd19 +Author: William Hubbs +Commit: William Hubbs + + rc-schedules.c: pass the correct pid to rc_find_pids + + This is for #163. + +commit db4a578273dbfa15b8b96686391bcc9ecc04b646 +Author: Jason Zaman +Commit: William Hubbs + + selinux: fix const qualifier warning + + rc-selinux.c: In function ‘selinux_setup’: + rc-selinux.c:361:9: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] + curr_t = context_type_get(curr_con); + ^ + +commit b1c3422f453921e838d419640fe39144dbf8d13d +Author: Jason Zaman +Commit: William Hubbs + + selinux: use openrc contexts path to get contexts + + The minimum requirement for libselinux is now >=2.6 + The refpolicy and the gentoo policy contain the + contexts since version 2.20170204-r4 + +commit 3fafd7a76e6adf15ec72a7ba5f44583eff8fab7a +Author: William Hubbs +Commit: William Hubbs + + sysfs: fix cgroup hybrid mode + + In hybrid mode, we should not try to mount cgroup2 if it is not + available in the kernel. + + This fixes #164. + +commit cd5722aca50f0eaddde7ce04ee00da53c313ba7d +Author: William Hubbs +Commit: William Hubbs + + cgroup2_find_path: use legacy mode if cgroup2 is not in the kernel + + This is related to #164. + +commit dcb4a4d2613a1fdf85651b32e5b7a87528f487bc +Author: William Hubbs +Commit: William Hubbs + + version 0.32 + +commit e312e569970c74cf52e255da67034391b68dafac +Author: William Hubbs +Commit: William Hubbs + + Update ChangeLog + +commit 2f60a959b442866b0e879d83f2732c4fa3ed3f7d +Author: William Hubbs +Commit: William Hubbs + + update news file + +commit 25b45a5a239318fb57c405c3fe64e53b0738ad68 +Author: William Hubbs +Commit: William Hubbs + + cgroup_cleanup: try to remove the cgroup version 2 cgroup + + If we were able to kill all the processes in the cgroup, it should be + removed. + +commit 4651b8c7e9e2ef9c1ea1fb8d174d1ca4693627af +Author: William Hubbs +Commit: William Hubbs + + rc-cgroup.sh: cgroup_cleanup fix error handling + + cgroup_cleanup should warn if it is unable to clean up all processes in + the control group, but it will always return success. + +commit 50608b54ed98acb54fec5fe3323909ea684d3af9 +Author: William Hubbs +Commit: William Hubbs + + rc-cgroup.sh: fix signal names + + The "SIG" prefix on signal names passed to kill -s isn't portable. + +commit b0a077a35f85e266fdb82a245dcbda18664a8567 +Author: William Hubbs +Commit: William Hubbs + + add quiet switch to do_stop in src-schedules.c + + This allows supervise-daemon to run this code without attempting to + print some status messages used by start-stop-daemon. + +commit 6a5ca2ab368d0a85f51bb559672dba2e3ffcc6be +Author: William Hubbs +Commit: William Hubbs + + make the procedure for killing child processes of services configurable + +commit 2b0345165e5af57ca61a4000c3671bbe6d677cf9 +Author: William Hubbs +Commit: William Hubbs + + Make cgroup_cleanup send only one sigterm and sigkill + + Instead of looping and sending multiple signals to child processes in + cgroup_cleanup, we send sigterm followed by sleeping one second then + sigkill. + + This brings us more in line with systemd's "control group" killmode + setting. + + Also, this commit includes several shellcheck cleanups. + +commit 8885580986ab8adc951fe32b9323c8b16130fb4f +Author: William Hubbs +Commit: William Hubbs + + rc-cgroup.sh: move cgroup_cleanup to the end of the file + +commit 6d7713a758b7e78f05e6a3cc101f862d28d778ab +Author: William Hubbs +Commit: William Hubbs + + guide.md: clarify cgroups documentation + + Update the documentation to reflect cgroups version 2 support. + Also, add a section on dealing with orphaned service processes. + + This fixes #94. + +commit 457f928e793cb1f6ef254935ad07f58b8762c72f +Author: William Hubbs +Commit: William Hubbs + + add support for control groups version 2 + + This is for #94. + +commit a71a461e452a98554346c47411e9c9012023c201 +Author: William Hubbs +Commit: William Hubbs + + version 0.31 + +commit a09b8af3f98c0700a9b838b7f3683ee58eecc912 +Author: William Hubbs +Commit: William Hubbs + + Update ChangeLog + +commit 382efdbfcb99703d03211efacd800c9575e64230 +Author: William Hubbs +Commit: William Hubbs + + add quiet parameter to run_stop_schedule + +commit 17b5cc78d35dc5fe4904e5951715c3e0d07d6343 +Author: William Hubbs +Commit: William Hubbs + + add retry option to supervise-daemon + + The --retry option for supervise-daemon defines how the supervisor will + attempt to stop the child process it is monitoring. It is defined when + the supervisor is started since stopping the supervisor just sends a + signal to the active supervisor. + + This fixes #160. + +commit 36a0ab9054512ade413226fb8e8b28060045e9a4 +Author: William Hubbs +Commit: William Hubbs + + make run_stop_schedule accept a pid instead of a pid file + +commit 27c2bd997d5173aa30844a16bc22dc8caab09f8c +Author: William Hubbs +Commit: William Hubbs + + version 0.30 + +commit d7938f54f29193251e083ad35a7d464949829096 +Author: William Hubbs +Commit: William Hubbs + + start-stop-daemon: move --retry processing code to a shared module + + This was part of start-stop-daemon; however, it needs to be shared in + order to be used by supervise-daemon. + +commit cfbe9c2ede24dac530ef58e5c35bd57f22a788a3 +Author: William Hubbs +Commit: William Hubbs + + move get_pid function to a shared file + +commit df28002b728b033c00c2da64dedf2bcd4ab5e11b +Author: William Hubbs +Commit: William Hubbs + + Update ChangeLog + +commit 66ed8082d0c865a0b4f4cc436cf9e13351e3d6fe +Author: William Hubbs +Commit: William Hubbs + + sh/openrc-run: source service script before ulimit is processed + + This is needed to allow the service script author to set a default for + rc_ulimit inside the service script. + +commit c2d256bafb9d1dfafbfd0846c035c5d26f7449c8 +Author: William Hubbs +Commit: William Hubbs + + man/openrc-run.8: document fstabinfo and mountinfo + + X-Gentoo-Bug: 592374 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=592374 + +commit f48d9c33a5c708c871d6657a39485d1c0c735548 +Author: William Hubbs +Commit: William Hubbs + + man/openrc-run.8: document _pre and _post functions + + Fixes https://github.com/openrc/openrc/issues/155. + +commit 6d4e8433974fd8567885635ae0454031290f96b1 +Author: Jason Graham +Commit: William Hubbs + + fix ENT macro usage + + X-Gentoo-Bug: 624796 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=624796 + +commit 0513cd3964a9564e0ba39b50aa8ebd3d7e9a3920 +Author: William Hubbs +Commit: William Hubbs + + version 0.29 + +commit 72bb2e57de935ab46ad000f97a5720265bed9342 +Author: John R. Graham +Commit: William Hubbs + + Typo fix + + X-Gentoo-Bug: 624908 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=624908 + +commit 84c5da30695db89d686d3c28c7cacdf172cbf429 +Author: William Hubbs +Commit: William Hubbs + + Update ChangeLog + +commit b35099cb707e333b6b8d30d956ffa93bcd2da0ab +Author: William Hubbs +Commit: William Hubbs + + Add comment about overriding the default efivars mount in fstab to news + +commit 3fd3bfc76dccc3752f4af949ad4076dab26357fb +Author: William Hubbs +Commit: William Hubbs + + add link to efivars issue to news file + +commit 492a6303cb8314263bfd3631e3b0de5a9df178da +Author: William Hubbs +Commit: William Hubbs + + Update ChangeLog + +commit e7807b3136d8993805082320784460f5059e6275 +Author: William Hubbs +Commit: William Hubbs + + fix sysvinit compatibility for shutdown wrapper + +commit 03a461ac0ee34b7900868cdea624c6fd868b1656 +Author: William Hubbs +Commit: William Hubbs + + fix sysvinit compatibility for reboot wrapper + +commit 7e0f76e0adc545c74a8332a6ef0811d2aa62cb81 +Author: William Hubbs +Commit: William Hubbs + + fix sysvinit compatibility for poweroff wrapper + +commit 9812ce5b8dc22fe36cc7bf75cf6e62db204ece3d +Author: William Hubbs +Commit: William Hubbs + + fix halt wrapper so it is sysvinit compatible + + This makes the halt wrapper sysvinit compatible. It ignores several + command line switches which are not currently implemented; however, + those can be implemented if we need to do so. + + This fixes https://github.com/openrc/openrc/issues/146. + +commit 12f75e4167f84a9a85f69924ebdb28ad36c085cb +Author: Adam Borowski +Commit: William Hubbs + + man: fix an unclosed .Bl/.El warning + + This fixes #151. + +commit 260368e0103e95625c29760f2c2ec89143e5a233 +Author: Adam Borowski +Commit: William Hubbs + + man: fix missing .Pp warnings + + This fixes #151. + +commit f87a9eec3d23ea01578500972f1df993d5d24fba +Author: William Hubbs +Commit: William Hubbs + + init.d/sysfs: mount efivars read only + + This fixes #134. + +commit 1e837d596e483ceb5cec177a6c7faff24a42384b +Author: William Hubbs +Commit: William Hubbs + + fix argument parsing for the sysvinit shutdown wrapper + + This fixes #140. + +commit dcc686e42b406d63d52ef75de9a326f67d0a06c9 +Author: William Hubbs +Commit: William Hubbs + + scripts/shutdown: fix arguments to be sysvinit shutdown compatible + + This fixes #140. + +commit 2f81c100afdf45ebf787dfc5d3261aa6055640e4 +Author: William Hubbs +Commit: William Hubbs + + Fix link to shutdown for MKSYSVINIT=yes + +commit a511a48d77b1dcb8a3fb0dd1abddb750a152869b +Author: Nuno Silva +Commit: William Hubbs + + init.d/hostname: fix default parameter syntax + + The syntax for expanding a variable with a default value is + ${parameter:-word} + not + ${parameter-word} + although the latter still works for a reason I could not explain. + + This fixes #143. + +commit 1e5322e5c55ec744a2cdcc3342ef6547eab7c46f +Author: Nuno Silva +Commit: William Hubbs + + init.d/hostname: fix indentation + + This is for #143. + +commit 199a210d2fbc524c9c400a06f832dabffd7ed1b3 +Author: udeved +Commit: William Hubbs + + scripts/Makefile: make symlinks absolute instead of relative + + This closes #142. + +commit 5b7667af32effddf867a5d021c66d43f0645d374 +Author: udeved +Commit: William Hubbs + + scripts/Makefile: respect SBINDIR with MKSYSVINIT + + This is for #142. + +commit 11243f85b67e5f450ddf50346ffd4a1b2c6faeb5 +Author: Jory A. Pratt +Commit: William Hubbs + + kill_all: include limits.h for PATH_MAX + +commit 3c40826d3466cdda1a46abcd5c86b661b8185f46 +Author: William Hubbs +Commit: William Hubbs + + version 0.28 + +commit 560d874d2fee63bf7ca11f17cf9933021b639a1d +Author: William Hubbs +Commit: William Hubbs + + fix compile issue for musl + +commit e84366fd232a41c3ba79ed351e93c74cef8d7c8d +Author: William Hubbs +Commit: William Hubbs + + Update ChangeLog + +commit caacedc0a82285fb2d25c6d3473f154044c7ad66 +Author: William Hubbs +Commit: William Hubbs + + man: update openrc-shutdown man page + + Add the new wtmp options and fix some cross references. + +commit 84d140a1f6abf95a4170d13527152d3ab14e6613 +Author: William Hubbs +Commit: William Hubbs + + scripts/shutdown: pass --single to openrc-shutdown + + Sysvinit shutdown has a default of single user mode, but openrc-shutdown + makes you choose a default action. Because of this, the shutdown wrapper + needs to pass --single to openrc-shutdown. + +commit ee886c44824b1dd892eaff2c6da666286e61bc73 +Author: William Hubbs +Commit: William Hubbs + + openrc-shutdown: add --single option and clean up option processing + +commit 1801561c2d36c330df7fd02c7508f503a61ff5ba +Author: William Hubbs +Commit: William Hubbs + + init.d/bootmisc: use openrc-shutdown instead of halt to write halt record + + This fixes #139 and fixes #128. + and fixes #124. + +commit 7689106aa10f7852b707b4c21ec080ccb2767280 +Author: William Hubbs +Commit: William Hubbs + + add support for writing reboot and shutdown records to wtmp + +commit 1564e155b726308200ecd5df315c002bd8b16952 +Author: William Hubbs +Commit: William Hubbs + + openrc-init: add optional sysvinit compatibility + +commit 44bac3c3798f7eb9186c3ea8774552aa191bfae7 +Author: William Hubbs +Commit: William Hubbs + + Change killprocs to use kill_all instead of killall5 + + X-Gentoo-Bug:376977 + X-Gentoo-Bug-URL:https://bugs.gentoo.org/show_bug.cgi?id=376977 + +commit 0ddee9b7d2b8dea810e252ca6a95c457876df120 +Author: Sergei Trofimovich +Commit: William Hubbs + + openrc-init: fix buffer overflow in init.ctl + + How to reproduce 1-byte overflow: + + ``` + $ FEATURES=-test CFLAGS="-fsanitize=address -O0 -ggdb3" emerge -1 openrc + + ================================================================= + ==1==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff0efd8710 + at pc 0x000000402076 bp 0x7fff0efd7d50 sp 0x7fff0efd7d40 + WRITE of size 1 at 0x7fff0efd8710 thread T0 + #0 0x402075 (/sbin/openrc-init+0x402075) + #1 0x3cf6e2070f in __libc_start_main (/lib64/libc.so.6+0x3cf6e2070f) + #2 0x4013b8 (/sbin/openrc-init+0x4013b8) + + Address 0x7fff0efd8710 is located in stack of thread T0 at offset 2432 in frame + #0 0x401cfb (/sbin/openrc-init+0x401cfb) + + This frame has 3 object(s): + [32, 160) 'signals' + [192, 344) 'sa' + [384, 2432) 'buf' <== Memory access at offset 2432 overflows this variable + HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext + (longjmp and C++ exceptions *are* supported) + SUMMARY: AddressSanitizer: stack-buffer-overflow ??:0 ?? + ``` + + The problem here is in the code handling reads from 'init.ctl': + + ``` + int main(int argc, char **argv) { + ... + char buf[2048]; + for (;;) { + /* This will block until a command is sent down the pipe... */ + fifo = fopen(RC_INIT_FIFO, "r"); + count = fread(buf, 1, 2048, fifo); + buf[count] = 0; + ... + } + ``` + + `buf[count] = 0;` writes outside the buffer when `fread()` returns non-truncated read. + + This fixes #138. + +commit 688566c535111a141f77caf88db12a4338544f7b +Author: Sergei Trofimovich +Commit: Doug Freed + + mk/cc.mk: make implicit function declarations fatal (#136) + + Avoids issues with missing prototypes causing truncation of pointers. + + Signed-off-by: Sergei Trofimovich + +commit 7185e242ffaa8cd1b672fe4726502a196fd779c2 +Author: Sergei Trofimovich +Commit: Doug Freed + + rc-logger.c: fix crash on fclose(NULL) (#137) + + Only close the log if we successfully opened it. + + Reported-by: Brian Evans + Tested-by: Brian Evans + Signed-off-by: Sergei Trofimovich + +commit ec27299f4b88daa80261298fafea76ae634744d9 +Author: William Hubbs +Commit: William Hubbs + + typo fix + + X-Gentoo-Bug: 618888 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=618888 + +commit 1ece16bfcd0ab71d2f9fe17a75ee6184e0fa4828 +Author: William Hubbs +Commit: William Hubbs + + openrc-shutdown: add dry-run option + +commit 0cfd0dd9ef580ed9dc563ccc164d70efe8f299db +Author: William Hubbs +Commit: William Hubbs + + openrc-shutdown: move to single user mode by default + + To be more compatible with sysvinit, move to single user mode if no + options are specified on the command line. + +commit a77ee2e94191ba1a286b8a6835f76556481566ba +Author: William Hubbs +Commit: William Hubbs + + init: add ability to switch to single user mode + +commit 49b8a573a195f4b2cee992cd10678694da0a6f4f +Author: William Hubbs +Commit: William Hubbs + + add kill_all helper + + This is similar to the sysvinit killall5 utility. It should only be used + in service scripts, so it will not be installed in the path. + + This closes #129. + +commit a2055af90054f5125cc07d4851b1dc9d16815e7c +Author: William Hubbs +Commit: William Hubbs + + rc_status: calculate time differences in time_t and display seconds in uptime + +commit cbf96967f1b6dc72ae16203dfbbb844bd08e8b6b +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: save start time and respawn count before dropping privs + +commit f1013037b47cdd6344f1b3ed92b7f84d7fcca01f +Author: William Hubbs +Commit: William Hubbs + + version 0.27 + +commit e4bfb4530a86a4ccdff312c857df37fa0da36fd6 +Author: William Hubbs +Commit: William Hubbs + + update ChangeLog + +commit 78e0042eccaf5a5554b195ad391b3ab0b8974cf6 +Author: William Hubbs +Commit: William Hubbs + + man/rc-status: document changes for supervised daemons + + rc-status now shows the amount of time a supervised daemon has been + active as well as the number of times it has been respawned during the + current respawn period. + +commit 82e12e309247bc84abf29aca04b3a2dd845fa11b +Author: William Hubbs +Commit: William Hubbs + + rc-status: show uptimes and respawn counts for supervised daemons + +commit 1ebef0d7a38ec0a9635418b75c3aabb564c1577e +Author: William Hubbs +Commit: William Hubbs + + fix to_time_t to honor dst + +commit 6b4050ab9cf9d678a1d6b7af7af7494f8533dbca +Author: William Hubbs +Commit: William Hubbs + + fix from_time_t function + +commit cf5e9aa2bbcdf1783fadeab26586c1134929d928 +Author: William Hubbs +Commit: William Hubbs + + Move time_t conversions to rc-misc.c so they can be shared + +commit a3250e77d412f2290e381b9e7569930d95e4fc5b +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: save start time and respawn count + + This will allow rc-status to display an uptime and restart count for + supervised processes. + +commit df027ca4722c8755b23a65db75728b835ccca807 +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: fix our status when we give up on the child process + +commit 4c89e3f5fa1c65ccd0c843f98e4013c2085f243f +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon:create multiple options from --respawn-limit + + This creates --respawn-delay, --respawn-max and --respawn-period. It was + suggested that it would be easier to follow if the options were + separated. + + This is for #126. + +commit 3673040722b75c0a4d06fbeb272f917c7d1ea7c4 +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: add a --respawn-limit option + + Allow limiting the number of times supervise-daemon will attempt to respawn a + daemon once it has died to prevent infinite respawning. Also, set a + reasonable default limit (10 times in a 5 second period). + + This is for issue #126. + +commit 96c8ba2fb5f91a711ef5bfcfd8affe0b74ad18fe +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: mark all open file descriptors FD_CLOEXEC + +commit 47cf1d0c707dc88d216bebc15be3f39d5eb47fa9 +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon:remove the controlling tty in the supervisor + +commit 06a6a27e441372164872c7712b80728527a6ec05 +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: fix access to tty_fd and devnull_fd + + Both the child and supervisor need access to these file descriptors. + +commit 5de3798afc55ce147e65926f863ec9c9cef60e79 +Author: William Hubbs +Commit: William Hubbs + + supervise-daemon: mark the service started when the supervisor is active + +commit 6ac094a59cf7b51d8527af15b07feca707a635c8 +Author: William Hubbs +Commit: William Hubbs + + version 0.26 + +commit 84c81ca02d7077a619dc704ff654385846fcd2b4 +Author: William Hubbs +Commit: William Hubbs + + update ChangeLog + +commit 0e3f8720984d7d5752a78a4135cd268e4f83b3d7 +Author: William Hubbs +Commit: William Hubbs + + init: send term/kill signals as final step of shutdown + +commit 5fd3747b190887d094225547f23007d25e2d9592 +Author: William Hubbs +Commit: William Hubbs + + reword the bugs section of the openrc-init man page + +commit 4694900190a9078397bb9083328b68b489af92f4 +Author: William Hubbs +Commit: William Hubbs + + init: fix signal handling + + The only signals we handle are SIGINT and SIGCHLD, so block all others + and unblock them in the child process before we start a rurnlevel. + +commit 05738bfce120114037d4f02c67ec740813f94b89 +Author: William Hubbs +Commit: William Hubbs + + init: add re-exec capability + + This will allow the re-execution of the init process after upgrading + OpenRC. + +commit 6f88ee4ec6f59e545346a7422facc3e5b6adac04 +Author: i.Dark_Templar +Commit: William Hubbs + + bootmisc: do not remove ld-elf32.so.hints + + File /var/run/ld-elf32.so.hints is used on FreeBSD 64bit multilib + This fixes #125. + +commit cc51bdca3bac963878141da047e92f125772e14f +Author: William Hubbs +Commit: William Hubbs + + Add attribution to openrc-init.c and openrc-shutdown.c + +commit 13ca79856e5836117e469c3edbcfd4bf47b6bab0 +Author: William Hubbs +Commit: William Hubbs + + add init process + + openrc-init.c and openrc-shutdown.c are based on code which was written by + James Hammons , so I would like to publically + thank him for his work. + +commit 79a9edc73068244ad843f2edbe4206ce696c91c8 +Author: i.Dark_Templar +Commit: i.Dark_Templar + + Fix make install on FreeBSD: don't try to install /etc/init.d/modules twice + +commit 9eb669591e16c5ee0ca07babe058d0b7b2396077 +Author: Austin English +Commit: William Hubbs + + start-stop-daemon: warn if calling --start with --retry or --stop with --wait + + This fixes #122 + +commit 55a87a30ec845eb725e8a923c8f8eb7aa75baa72 +Author: William Hubbs +Commit: William Hubbs + + init.d/agetty.in: add -prefix keyword + +commit a912029462ae988ab4e2a96a0958e54a3c2e822f +Author: William Hubbs +Commit: William Hubbs + + init.d/mount-ro: change dependency on killprocs and savecache to after + + killprocs always succeeds and savecache is not required by mount-ro, so + we can just start after both of these have run. + +commit 1e9078279709df2a3617bf1460890ceb1ddfcf59 +Author: William Hubbs +Commit: William Hubbs + + agetty-guide: typo fix + +commit 51a292e09b9362f13d5747d4eedaa521ddf9ce72 +Author: William Hubbs +Commit: William Hubbs + + init.d: add agetty to ignore patterns + +commit 50fccf47d4bd2ed6e7ea6ff7f72577c8e7b95d0d +Author: William Hubbs +Commit: William Hubbs + + sh/gendepends.sh.in: fix detection of service scripts + + We do not need to care about the path on the shebang line of a service + script as long as the shebang line ends with "openrc-run". + This fixes #119 and #120. + +commit 9bd63b5d4a16601712a65eb8962214cdd4d26ce5 +Author: William Hubbs +Commit: William Hubbs + + update dependencies for clock service + + The clock services had a very long list of "before" dependencies that + referred to other services within OpenRC. For ease of maintenance, + convert these to "after clock" dependencies in the individual services. + +commit 48db17a93f5e60c0d241f8fb06bfbdd01206fb9c +Author: William Hubbs +Commit: William Hubbs + + update news file + +commit c333707cba356f4cacfd58a6fcc78f7c073dddcd +Author: William Hubbs +Commit: William Hubbs + + Remove all occurances of 'before *' from dependencies + + Using wildcards in dependencies causes issues when rc_parallel is set to + yes because it can lead to deadlocks. + All dependencies need to be explicit rather than implicit. + + This is the first stage of moving this direction. + +commit 5f5b1f7cbefd0bc14352e86a9c33260266f98d9b +Author: William Hubbs +Commit: William Hubbs + + init.d/sysfs.in: efivarfs tweaks + + Since we check for /sys/firmware/efi/efivars, we do not need to check + for /sys/firmware/efi + + Since Failing to mount efivarfs is not critical, we silence the error + message from mount. + +commit cfdf56475e600f79a433cd721cadf39114c6c58d +Author: William Hubbs +Commit: William Hubbs + + version 0.25 + +commit fde3902d069dfdce9c59555186a5541d6d99c8aa +Author: William Hubbs +Commit: William Hubbs + + update ChangeLog + +commit d7bbb0f5830e1ec4df1ec52714d70ac6b0a81878 +Author: William Hubbs +Commit: William Hubbs + + add agetty service + + The agetty service is an alternate way to manage gettys with agetty + under Linux which is separate from an external init system. + +commit 21ca2b746cce67e2b3578fb7015c9d4c243e3a0c +Author: William Hubbs +Commit: William Hubbs + + init.d/sysfs: drop modules completely from the dependencies + + This is for #112. + +commit 6a79aef0159d7035778fd852b26ecfac903cd029 +Author: William Hubbs +Commit: William Hubbs + + init.d/sysfs: Do not load efivarfs module + + My understanding is that the kernel can autoload this module. If it + doesn't, the module should be built in or loaded from an initramfs. + + This fixes https://github.com/openrc/openrc/pulls/112. + +commit 4a269674b765e5267f024fa55c8644480a7304ea +Author: William Hubbs +Commit: William Hubbs + + make sure netmount and localmount start after root + +commit eea4decdd1c84e4b8775a255d8ed85bce5eb40a5 +Author: William Hubbs +Commit: William Hubbs + + net-online: typo fix + +commit d4d0f25a4844ecaed43de913e8b729e7a2e894db +Author: William Hubbs +Commit: William Hubbs + + net-online: updates to make the service more usable + + - switch from attempting to ping the default gateway to a host outside + the local network, defaulting to google.com. + - along with this, change the name of the variable that requests a ping + test to include_ping_test so the meaning is more clear. + +commit 1cb44092fce298004ab4c4547c6fbcac29c5997f +Author: William Hubbs +Commit: William Hubbs + + sh/rc-functions.sh.in: add get_bootparam_value function + +commit 4207e46622f584eb5f0cc10bbfd36f92f001a2e2 +Author: William Hubbs +Commit: William Hubbs + + move init.d examples under support and install them + +commit f6ea16159ec8583a6f2182578334aa00578cb080 +Author: William Hubbs +Commit: William Hubbs + + scripts: make sure the rc-sstat symlink is always replaced + +commit 9047ea4cb0d0e5e27704369380e128d26c3e86b2 +Author: William Hubbs +Commit: William Hubbs + + install support files + + These files have been in the distribution for some time but haven't been + installed. They are good examples of how to do things, so we should + install them. + +commit d7f5a696c173e7af67dd4b3f90744e0a056441e1 +Author: William Hubbs +Commit: William Hubbs + + support: rename all README files to README.md + +commit 6f614cd3f33dbdea3a67ac2fb414b1130674ee04 +Author: William Hubbs +Commit: William Hubbs + + Move deptree2dot to the support folder + + Since deptree2dot and the perl requirement are completely optional, we + can move this tool to the support folder. This gives the user the option + of using it if they have perl installed, and means we do not have an + optional runtime dependency on perl. + + Documentation for this tool has also been added to the support folder. + + X-Gentoo-Bug: 600742 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=600742 + +commit 85c1930acf15b0c9d3c5537fb2b0409c6a11c982 +Author: William Pitcock +Commit: William Hubbs + + test/setup_env: ensure that eval_ecolors is available on the path. + + The test environment previously used the system default paths instead of installing the necessary $PATH environment + variable to make finding eval_ecolors work. + This closes #117. + + X-Gentoo-Bug: 374191. + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=374191. + +commit 96bd0c004c9549e5a2ef64277216a15da6f96a8e +Author: Nicolas Porcel +Commit: William Hubbs + + Fix typo in guide.md + + This fixes #115. + +commit b693af90556ac9b055ba5c6e589066c1e08b2146 +Author: William Hubbs +Commit: William Hubbs + + Revert "scripts: do not substitute for @SHELL@ in rc-sstat" + + This reverts commit e2e652e469efa5f3ebcd69828ff16d8f5ad3f1b8. + +commit 6dcb6929869c2f81c1f8d0930191f74fc6dfaa3e +Author: Doug Freed +Commit: William Hubbs + + start-stop-daemon: allow all standard signals + + Also we define the signalpair_item macro. + This fixes #113. + + X-Gentoo-Bug: 604986 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=604986 + +commit e2e652e469efa5f3ebcd69828ff16d8f5ad3f1b8 +Author: William Hubbs +Commit: William Hubbs + + scripts: do not substitute for @SHELL@ in rc-sstat + +commit b73941f0c3020e3dbd1684d09685e114c678b520 +Author: William Hubbs +Commit: William Hubbs + + mountinfo: make the path to /proc/mounts a constant + + This path should not be hard coded in the open call. + Linux prior to 2.4.19 did not have /proc/self/mounts, so for now I'm + making this value /proc/mounts everywhere, but that may change to + /proc/self/mounts on linux; I'm not sure we should care about <2.4.19. + + X-Gentoo-Bug: 604646 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=604646 + +commit c304522131a795cf882444b5f94e81db4baf65b3 +Author: Benda Xu +Commit: William Hubbs + + Clean up warnings that can use the _unused macro + + X-Gentoo-Bug: 604666 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=604666 + +commit 92325b44ba58a7ca04d88ae8ca202b402b032b43 +Author: Benda Xu +Commit: William Hubbs + + Indentation fixes + + X-Gentoo-Bug: 604666 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=604666 + +commit 074d90f5a4e3b66e532a0becde372acf38346397 +Author: Benda Xu +Commit: William Hubbs + + Drop the use of the _BSD_SOURCE macro on Linux + + X-Gentoo-Bug: 604666 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=604666 + +commit 7056b56b3ccc9cbde4ef8297b923919c49c7c242 +Author: Benda Xu +Commit: William Hubbs + + Drop the use of the _BSD_SOURCE macro on GNU/Hurd + + X-Gentoo-Bug: 604666 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=604666 + +commit d5c3b85e3fbddbba149687244d607fcdae222f95 +Author: Doug Freed +Commit: Doug Freed + + loopback: drop explicit route for BSD too + +commit 1ab2249448ba24a591b561f53aa64ff3df1e41f6 +Author: William Hubbs +Commit: William Hubbs + + version 0.24 + +commit a15cff21c63f2ad951af1c59a74fc7d37f78e91b +Author: William Hubbs +Commit: William Hubbs + + update ChangeLog + +commit 45aa36cc623eeeb15fb6827b57e0c07a37cdef41 +Author: Doug Freed +Commit: William Hubbs + + librc: detect loops in stacked runlevels and abort + + This fixes #109. + X-Gentoo-Bug: 558700 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=558700 + +commit d3f833179b39368442221c448f90b87f76d28ee8 +Author: William Hubbs +Commit: William Hubbs + + sh/init.sh.Linux.in: remove unused check for Gnu/KFreeBSD + + This script only runs on Linux, so the check will always be false. + +commit abe552b969b6601f47ba0474f683d8cd80d53c9d +Author: William Hubbs +Commit: William Hubbs + + modules: get rid of printing each module on Linux + + Now that we respect the module blacklists, don't print every module we + try to load, because it might not end up loaded due to the blacklist, + and modprobe doesn't consider that a failure. + +commit 856eafb006655b7dda630a94cbd16f5db9f781be +Author: Doug Freed +Commit: Doug Freed + + sh/init.sh.Linux.in: skip /proc test if no md5sum + + This will also warn users if md5sum is missing, which serves as a pretty + good indicator that /usr is not mounted. + +commit f27d60add9ee1ef8a90ea0034edf6f4e4e6d0ed8 +Author: Robin H. Johnson +Commit: Robin H. Johnson + + sh/openrc-run.sh: expose default start/stop/status + + Supervisor setups break easily when start/stop/status functions are not + default. + + Applications that write multiple PIDs to a pidfile (eg HAProxy as + described in bug 601540), can also benefit from being able to call the + default start/stop/status with modified environment variables. + + Expose the default start/stop/status functions as + default_start/stop/status, and use them for the defaults + start/stop/status. + + Trivial usage example: + ``` + stop() + { + t=$(mktemp) + for pid in $(cat $pidfile) ; do + echo $pid >$t + pidfile=$t default_stop + done + rm -f $t + } + ``` + + X-Gentoo-Bug: 601540 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/601540 + Signed-off-by: Robin H. Johnson + +commit 8ad460c54ce66aa0900cf872d9ebfacf0c03f9da +Author: Doug Freed +Commit: Doug Freed + + Fix typos + + Fixes #99 + +commit 72c0824961fc257b634a9439496e04d1b3392ef1 +Author: Doug Freed +Commit: Doug Freed + + localmount: add comment about types variable + +commit 5b7e3490ef2ce96c35e6c18b4c64e8c61586bb7a +Author: Alan Somers +Commit: Doug Freed + + Localmount shouldn't mount remote filesystems + + The /etc/init.d/localmount script has a syntax error that causes it to + attempt to mount remote filesystems, causing the boot to fail. The + script appends a "no" to each remote filesystem type, but it should only + be append the "no" to the beginning of the list. This patch fixes + localmount on FreeBSD 12.0. A review of the mount(8) manpage on Ubuntu + 12.04 suggests that this patch is correct for Linux, too. + +commit dd61e6bfc3fc1da011b01f4f6cf3e45e26c59dc1 +Author: William Hubbs +Commit: William Hubbs + + rc.conf: fix the commented default setting for rc_logger + + X-Gentoo-Bug: 601480 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=601480 + +commit 204971c6e2ea1e37fa037e09bff02eea3a07f843 +Author: Doug Freed +Commit: GitHub + + runlevels: remove bad trailing backslash + +commit 3552f0ae548d68effd4411ad4080e7b13fe627c5 +Author: William Hubbs +Commit: William Hubbs + + man/start-stop-daemon.8: clarify documentation about --pidfile option + + The documentation implied that if you stop a daemon we handle multiple + pids in a pid file. This is not correct. We only handle the first pid. + + X-Gentoo-Bug: https://bugs.gentoo.org/show_bug.cgi?id=601540 + +commit 42cb84882918a0c9dd93a89d92b0b4818dfb44b8 +Author: AndCycle +Commit: William Hubbs + + fix manual typo + + This fixes #105. + +commit e0ac661419042cb39c1ccf93df2981504d1e6339 +Author: William Hubbs +Commit: William Hubbs + + split tmpfiles processing into opentmpfiles + + The openntmpfiles package is designed so that it can be used on systems + independently of whether openrc is used. + +commit 6414c3bc394f86a5d6a5f02c934469e21bbbc923 +Author: Jason Zaman +Commit: William Hubbs + + selinux: fix SIGSEGV with invalid contexts + + Fixes: https://github.com/openrc/openrc/issues/104 + +commit 4f9bd7e4db185ce6debbebb5242344d8ffadc3ae +Author: William Hubbs +Commit: William Hubbs + + init.d/loopback.in: drop the route to the loopback interface on Linux + + This is related to #103. + +commit bf539f2196290864ce5c5fd0d679b74ee016e2da +Author: William Hubbs +Commit: William Hubbs + + init.d/mount-ro: do not remount /usr read only if it is premounted + + X-Gentoo-Bug: 573760 + X-Gentoo-Bug: https://bugs.gentoo.org/show_bug.cgi?id=573760 + +commit 20b60ea904612669dfb744beffcd8e7e447f69ef +Author: William Hubbs +Commit: William Hubbs + + conf.d/net-online: clarify comment about interfaces setting + + This setting refers to all interfaces that support ethernet + +commit f53c8baef3a6215077c00901759cbbcbe8f10e9b +Author: William Hubbs +Commit: William Hubbs + + init.d/net-online: remove interfaces and timeout from local declarations + + X-Gentoo-Bug: 598621 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=598621 + +commit be06cd250e12e63b8eb704bb2508e06fb9791251 +Author: William Hubbs +Commit: William Hubbs + + src/rc/rc: do not try to start services if fork fails + +commit 003657c973ea338a19f2b7294190af9d76cf5cea +Author: Robin H. Johnson +Commit: William Hubbs + + init.d/loopback: drop scope on loopback + + Busybox does not support the 'scope' argument on 'ip address add' or 'ip + route add', this is documented in BUSYBOX.md, but is no longer actually + needed, as the kernel does get it right without manual specification, + and the ifconfig variant already relies on the kernel to get it right. + This is part of #103. + + X-Gentoo-Bug: 487208 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=487208 + +commit 4fd144c0a6526963c70f18cb34a65354c2f0a48c +Author: William Hubbs +Commit: William Hubbs + + src/rc/rc-misc.c: report error if call to flock() fails + + X-Gentoo-Bug: 597390 + X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=597390 Index: contrib/openrc/FEATURE-REMOVAL-SCHEDULE.md =================================================================== --- /dev/null +++ contrib/openrc/FEATURE-REMOVAL-SCHEDULE.md @@ -0,0 +1,79 @@ +Features Scheduled for Removal +============================== + +The following is a list of files and features that are going to be removed in +the source tree. Every entry should contain what exactly is going away, why it +is happening, and who is going to be doing the work. When the feature is +removed, it should also be removed from this file. + +# Service pause action + +When: 1.0 + +Why: The same affect can be obtained with the --nodeps option to stop. + +Who: + +# start-stop-daemon options --startas, --chuid , --oknodo + +When: 1.0 + +Why: Obsolete or replaced by other options. + +* --startas => use --name or --exec +* --chuid => use --user +* --oknodo => ignore return code instead + +Who: + +# runscript and rc symbolic links + +When: 1.0 + +Why: Deprecated in favor of openrc-run and openrc due to naming + conflicts with other software. + +Who: + +# support for the opts variable in service scripts + +When: 1.0 + +Why: Deprecated in favor of extra_commands, extra_started_commands + and extra_stopped_commands. + +Who: + +# support for local_start and local_stop + +When: 1.0 + +Why: Deprecated in favor of executable scripts in @SYSCONFDIR@/local.d + +Who: + +# the mtab service script + +When: force /etc/mtab to link to /proc/self/mounts in 1.0, remove + service in 2.0 + +Why: /etc/mtab should be a symbolic link to /proc/self/mounts on modern + Linux systems + +Who: + +# C API Functions in rc.h + +If you have a c program that links to librc and uses functions from +there, this section will list API functions which are deprecated and +will be removed along with the reason they are being removed. + +## rc_getline() + +When: 1.0 + +Why: The getline() function was standardized in POSIX.1-2008, so it + should be available on POSIX systems. + +Who: + Index: contrib/openrc/HISTORY.md =================================================================== --- /dev/null +++ contrib/openrc/HISTORY.md @@ -0,0 +1,63 @@ +OpenRC History +============== + +This history of OpenRC was written by Daniel Robbins, Roy Marples, William +Hubbs and others. + +The Gentoo modular init scripts were developed by Daniel Robbins for Gentoo +Linux 1.0_rc6 during most of 2001 and released in September 2001. After their +development, the dependency-based init script system was maintained by a +number of senior developers, starting with Azarah (Martin Schlemmer), with +migration to the new init system assisted by Woodchip (Donnie Davies) who +converted all ebuild init scripts to work with the new system. As Grant +Goodyear notes: + +"My recollection is that one of woodchip's more impressive early feats +was the complete replacement of all of the init scripts in Portage +for Gentoo Linux 1.0_rc6. Through 1.0_rc5 Gentoo had used fairly +standard rc scripts modified from Stampede Linux, but for 1.0_rc6 Daniel +Robbins (drobbins) and Martin Schlemmer (azarah) had created a new +dependency-based init script system that is still used today. Within a +span of days Donny rewrote every single init script in the Portage tree +and committed new masked packages to await the release of 1.0_rc6. Thanks to +woodchip (and drobbins and azarah, of course) the +transition to the new init scripts was nearly painless." [1] + +Roy Marples became a Gentoo/Linux developer in 2004 and wrote the modular +network scripts for the Gentoo baselayout package. Towards the end of 2005, +he became the primary maintainer for baselayout and the init scripts. + +At the start of 2007, He announced the ongoing development of +baselayout-2, containing a rewritten core coded in C and allowing POSIX sh +init scripts instead of forcing the use of bash. By mid 2007, He had +re-implemented the Gentoo init script design created by Daniel Robbins, +using an entirely new code base. Alpha and pre-release baselayout-2 +snapshots were added to Gentoo's Portage tree as an optional component. + +Toward the end of 2007, Roy retired as a Gentoo developer. +Baselayout-2 was still in the pre stage, and aside from the gentoo-fbsd +users, it was masked. However, He desired to keep the baselayout-2 +project moving forward as an independent project. The Gentoo Council +permitted Him to release OpenRC under the 2-clause BSD license, +managed by him as an external project. + +Around mid-2010, Roy decided to no longer maintain OpenRC. At this +point, he transferred development back to Gentoo. + +William Hubbs, and several other Gentoo developers, started working on +OpenRC around this point and brought OpenRC-0.8.x to Gentoo Linux's stable +tree in 2011. + +In 2013 the OpenRC team became independent from Gentoo again and moved primary +development to github. + +Daniel Robbins continues to maintain an independent, forked +version of OpenRC for Funtoo Linux, which includes a Funtoo-specific network +configuration system. + +On 17-Dec-2015 utc, Roy gave the OpenRC developers permission to replace his +copyrights in all source files with a generic Copyright assertion for +the OpenRC developers as long as we keep the original copyright in the +binaries and LICENSE file. + +[1] http://www.gentoo.org/news/en/gwn/20040426-newsletter.xml Index: contrib/openrc/LICENSE =================================================================== --- /dev/null +++ contrib/openrc/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2007-2008, Roy Marples +Copyright (c) 2007-2015, the OpenRC authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. Index: contrib/openrc/Makefile =================================================================== --- /dev/null +++ contrib/openrc/Makefile @@ -0,0 +1,54 @@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +TOP:= ${dir ${realpath ${firstword ${MAKEFILE_LIST}}}} +MK= ${TOP}/mk + +include ${TOP}/Makefile.inc + +SUBDIR= conf.d etc init.d local.d man scripts sh src support sysctl.d + +# Build bash completion or not +MKBASHCOMP?= no +ifeq (${MKBASHCOMP},yes) +SUBDIR+= bash-completion +endif + +# Build pkgconfig or not +MKPKGCONFIG?= yes +ifeq (${MKPKGCONFIG},yes) +SUBDIR+= pkgconfig +endif + +# Build zsh completion or not +MKZSHCOMP?= no +ifeq (${MKZSHCOMP},yes) +SUBDIR+= zsh-completion +endif + +# We need to ensure that runlevels is done last +SUBDIR+= runlevels + +INSTALLAFTER= _installafter + +include ${MK}/sys.mk +include ${MK}/os.mk +include ${MK}/subdir.mk +include ${MK}/dist.mk +include ${MK}/gitver.mk + +_installafter: +ifeq (${MKPREFIX},yes) + ${INSTALL} -d ${DESTDIR}/${LIBEXECDIR}/init.d +else ifneq (${OS},Linux) + ${INSTALL} -d ${DESTDIR}/${LIBEXECDIR}/init.d +endif + ${INSTALL} -d ${DESTDIR}/${LIBEXECDIR}/tmp + ${ECHO} "${VERSION}${GITVER}" > ${DESTDIR}/${LIBEXECDIR}/version Index: contrib/openrc/Makefile.inc =================================================================== --- /dev/null +++ contrib/openrc/Makefile.inc @@ -0,0 +1,3 @@ +NAME= openrc +VERSION= 0.35 +PKG= ${NAME}-${VERSION} Index: contrib/openrc/NEWS.md =================================================================== --- /dev/null +++ contrib/openrc/NEWS.md @@ -0,0 +1,248 @@ +OpenRC NEWS +=========== + +This file will contain a list of notable changes for each release. Note +the information in this file is in reverse order. + +## OpenRC 0.35 + +In this version, the cgroups mounting logic has been moved from the +sysfs service to the cgroups service. This was done so cgroups can be +mounted inside an lxc/lxd container without using the other parts of the +sysfs service. + +?As a result of this change, if you are upgrading, you need to add +cgroups to your sysinit runlevel by running the following command as +root: + +``` +# rc-update add cgroups sysinit +``` + +For more information, see the following issue: + +https://github.com/openrc/openrc/issues/187 + +Consider this your second notification with regard to /etc/mtab being a +file instead of a symbolic link. + +In this version, the mtab service will complain loudly if you have +mtab_is_file set to yes and recommend that you change this to no and +restart the mtab service to migrate /etc/mtab to a symbolic link. + +If there is a valid technical reason to keep /etc/mtab as a flat file +instead of a symbolic link to /proc/self/mounts, we are interested and +we will keep the support in that case. Please open an issue and let us +know however. Otherwise, consider this your final notice that the mtab +service will be removed in the future. + +## OpenRC 0.33 + +This version removes the "service" binary which was just a copy of +"rc-service" provided for compatibility. + +If you still need the "service" binary, as opposed to "rc-service", it is +recommended that you use something like Debian's init-system-helpers. +Otherwise, just use "rc-service" in place of "service". + +## OpenRC 0.31 + +This version adds support for Control Groups version 2, which is +considered stable as of Linux-4.13. Please see /etc/rc.conf for +documentation on how to configure control groups. + +## OpenRC-0.28 + +This version mounts efivars read only due to concerns about changes in +this file system making systems unbootable. If you need to change something +in this path, you will need to re-mount it read-write, make the change +and re-mount it read-only. + +Also, you can override this behavior by adding a line for efivars to +fstab if you want efivars mounted read-write. + +For more information on this issue, see the following url: + +https://github.com/openrc/openrc/issues/134 + +## OpenRC-0.25 + +This version contains an OpenRC-specific implementation of init for +Linux which can be used in place of sysvinit or any other init process. +For information on its usage, see the man pages for openrc-init (8) and +openrc-shutdown (8). + +## OpenRC-0.24.1 + +This version starts cleaning up the dependencies so that rc_parallel +will work correctly. + +The first step in this process is to remove the 'before *' from the +depend functions in the clock services. This means some services not +controlled by OpenRC may now start before instead of after the clock +service. If it is important for these services to start after the clock +service, they need to have 'after clock' added to their depend +functions. + +## OpenRC-0.24 + +Since the deptree2dot tool and the perl requirement are completely +optional, the deptree2dot tool has been moved to the support directory. +As a result, the MKTOOLS=yes/no switch has been removed from the makefiles. + +This version adds the agetty service which can be used to spawn +agetty on a specific terminal. This is currently documented in the +agetty-guide.md file at the top level of this distribution. + +## OpenRC-0.23 + +The tmpfiles.d processing code, which was part of previous versions of +OpenRC, has been separated into its own package [1]. If you need to +process systemd style tmpfiles.d files, please install this package. + +[1] https://github.com/openrc/opentmpfiles + +## OpenRC-0.22 + +In previous versions of OpenRC, configuration information was processed +so that service-specific configuration stored in /etc/conf.d/* was +overridden by global configuration stored in /etc/rc.conf. This release +reverses that. Global configuration is now overridden by +service-specific configuration. + +The swapfiles service, which was basically a copy of the swap service, +has been removed. If you are only using swap partitions, this change +will not affect you. If you are using swap files, please adjust the +dependencies of the swap service as shown in /etc/conf.d/swap. + +## OpenRC-0.21 + +This version adds a daemon supervisor which can start daemons and +restart them if they crash. See supervise-daemon-guide.md in the +distribution for details on its use. + +It is now possible to mark certain mount points as critical. If these +mount points are unable to be mounted, localmount or netmount will fail. +This is handled in /etc/conf.d/localmount and /etc/conf.d/netmount. See +these files for the setup. + +The deprecation messages in 0.13.x for runscript and rc are now +made visible in preparation for the removal of these binaries in 1.0. + +The steps you should take to get rid of these warnings is to run openrc +in initialization steps instead of rc and change the shebang lines in +service scripts to refer to "openrc-run" instead of "runscript". + +In 0.21.4, a modules-load service was added. This works like the +equivalent service in systemd. It looks for files named *.conf first in +/usr/lib/modules-load.d, then /run/modules-load.d, then +/etc/modules-load.d. These files contain a list of modules, one per +line, which should be loaded into the kernel. If a file name appears in +/run/modules-load.d, it overrides a file of the same name in +/usr/lib/modules-load.d. A file appearing in /etc/modules-load.d +overrides a file of the same name in both previous directories. + +## OpenRC-0.19 + +This version adds a net-online service. By default, this +service will check all known network interfaces for a configured +interface or a carrier. It will register as started only when all +interfaces are configured and there is at least a carrier on one +interface. The behaviour of this service can be modified in +/etc/conf.d/net-online. + +Currently, this only works on Linux, but if anyone wants to port to +*bsd, that would be welcomed. + +## OpenRC-0.18.3 + +Modern Linux systems expect /etc/mtab to be a symbolic link to +/proc/self/mounts. Reasons for this change include support for mount +namespaces, which will not work if /etc/mtab is a file. +By default, the mtab service enforces this on each reboot. + +If you find that this breaks your system in some way, please do the +following: + +- Set mtab_is_file=yes in /etc/conf.d/mtab. + +- Restart mtab. This will recreate the /etc/mtab file. + +- Check for an issue on https://github.com/openrc/openrc/issues + explaining why you need /etc/mtab to be a file. If there isn't one, + please open one and explain in detail why you need this to be a file. + If there is one, please add your comments to it. Please give concrete + examples of why it is important that /etc/mtab be a file instead of a + symbolic link. Those comments will be taken into consideration for how + long to keep supporting mtab as a file or when the support can be + removed. + +## OpenRC-0.18 + +The behaviour of localmount and netmount in this version is changing. In +the past, these services always started successfully. In this version, +they will be able to fail if file systems they mount fail to mount. If +you have file systems listed in fstab which should not be mounted at +boot time, make sure to add noauto to the mount options. If you have +file systems that you want to attempt to mount at boot time but failure +should be allowed, add nofail to the mount options for these file +systems in fstab. + +## OpenRC-0.14 + +The binfmt service, which registers misc binary formats with the Linux +kernel, has been separated from the procfs service. This service will be +automatically added to the boot runlevel for new Linux installs. When +you upgrade, you will need to use rc-update to add it to your boot +runlevel. + +The procfs service no longer automounts the deprecated usbfs and +usbdevfs file systems. Nothing should be using usbdevfs any longer, and +if you still need usbfs it can be added to fstab. + +Related to the above change, the procfs service no longer attempts to +modprobe the usbcore module. If your device manager does not load it, +you will need to configure the modules service to do so. + +The override order of binfmt.d and tmpfiles.d directories has been +changed to match systemd. Files in /run/binfmt.d and /run/tmpfiles.d +override their /usr/lib counterparts, and files in the /etc counterparts +override both /usr/lib and /run. + +## OpenRC-0.13.2 + +A chroot variable has been added to the service script variables. +This fixes the support for running a service in a chroot. +This is documented in man 8 openrc-run. + +The netmount service now mounts nfs file systems. +This change was made to correct a fix for an earlier bug. + +## OpenRC-0.13 + +/sbin/rc was renamed to /sbin/openrc and /sbin/runscript was renamed to +/sbin/openrc-run due to naming conflicts with other software. + +Backward compatible symbolic links are currently in place so your +system will keep working if you are using the old names; however, it is +strongly advised that you migrate to the new names because the symbolic +links will be removed in the future. +Warnings have been added to assist with this migration; however, due to the +level of noise they produce, they only appear in verbose mode in this release. + +The devfs script now handles the initial mounting and setup of the +/dev directory. If /dev has already been mounted by the kernel or an +initramfs, devfs will remount /dev with the correct mount options +instead of mounting a second /dev over the existing mount point. + +It attempts to mount /dev from fstab first if an entry exists there. If +it doesn't it attempts to mount devtmpfs if it is configured in the +kernel. If not, it attempts to mount tmpfs. +If none of these is available, an error message is displayed and static +/dev is assumed. + +## OpenRC-0.12 + +The net.* scripts, originally from Gentoo Linux, have +been removed. If you need these scripts, look for a package called +netifrc, which is maintained by them. Index: contrib/openrc/README.newnet =================================================================== --- /dev/null +++ contrib/openrc/README.newnet @@ -0,0 +1,36 @@ +OpenRC Network Ideals +--------------------- + +The new style networking for OpenRC is very simplistic - provide a basic means +of configuring static interface address and routes whilst allowing the +possibility to run any command at any point. + +In a nutshell, init.d/network is a wrapper around ifconfig(8) and +init.d/staticroute is wrapper around route(8). + +In the Perfect World (TM) ifconfig should be able to configure everything +about the interface easily * . The BSD family almost get this right and Linux +epically fails. + +* Only static configuration, including link setup. +For dynamic, static, IPv4LL, arping and per ssid IPv4 setup dhcpcd-5.x +provides your needs. + +It fails because there are many tools to do the same job and often have +vastly different syntax where they could be similar. In other words, there +is no coherence. + +OpenRC-0.4.x and older (inc Gentoo baselayout-1) had a collection of scripts +for each tool and allowed a script per interface. Over the years, this design +has proven very hard to maintain as each user has their own idea of how +things should work. Also, there were (and still are) race conditions. + +So where do we go from here? +Well, it's possible to use the new network scripts using the tools +currently available. It's just harder as you have to know them and their +documentation can be lacking at times. +The correct end goal is a BSD style ifconfig tool. +I've started work on it, but the project has stalled somewhat. +It's display only right now and the source is not yet publicly available. +If you have the skills and share the vision then contact me privately and +we'll take it from there. Index: contrib/openrc/STYLE-GUIDE.md =================================================================== --- /dev/null +++ contrib/openrc/STYLE-GUIDE.md @@ -0,0 +1,85 @@ +OpenRC Coding Style Guide +========================= + +This is the openrc style manual. It governs the coding style of all code +in this repository. Follow it. Contact openrc@gentoo.org for any questions +or fixes you might notice. + +## C CODE + +The BSD Kernel Normal Form (KNF) style is used [1]. Basically, it is like +K&R/LKML, but wrapped lines that are indented use 4 spaces. Here are the +highlights. + +- no trailing whitespace +- indented code use tabs (not line wrapped) +- cuddle the braces (except for functions) +- space after native statements and before paren (for/if/while/...) +- no space between function and paren +- pointer asterisk cuddles the variable, not the type + +``` +void foo(int c) +{ + int ret = 0; + + if (c > 1000) + return; + + while (c--) { + bar(c); + ret++; + } + + return ret; +} +``` + +## COMMIT MESSAGES + +The following is an example of a correctly formatted git commit message +for this repository. Most of this information came from this blog post +[2], so I would like to thank the author. + +``` +Capitalized, short (50 chars or less) summary + +More detailed explanatory text, if necessary. Wrap it to about 72 +characters or so. In some contexts, the first line is treated as the +subject of an email and the rest of the text as the body. The blank +line separating the summary from the body is critical (unless you omit +the body entirely); tools like rebase can get confused if you run the +two together. + +Write your commit message in the imperative: "Fix bug" and not "Fixed +bug." This convention matches up with commit messages generated by +commands like git merge and git revert. + +Further paragraphs come after blank lines. + +- Bullet points are okay, too + +- Typically a hyphen or asterisk is used for the bullet, preceded by a + single space, with blank lines in between, but conventions vary here + +- Use a hanging indent + +Reported-by: User Name +X-[Distro]-Bug: BugID +X-[Distro]-Bug-URL: URL for the bug (on the distribution's web site typically) +``` + +If you did not write the code and the patch does not include authorship +information in a format git can use, please use the --author option of the +git commit command to make the authorship correct. + +The Reported-by tag is required if the person who reported the bug is +different from the author and committer. + + The X-[Distro]-Bug/Bug-URL tags are required if this commit is related + to a bug reported to us by a specific distribution of linux or a + *BSD. Also, [Distro] should be replaced with the name of the + distribution, e.g. X-Gentoo-Bug. + +[1] http://en.wikipedia.org/wiki/Indent_style#BSD_KNF_style +[2] http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html Index: contrib/openrc/TODO =================================================================== --- /dev/null +++ contrib/openrc/TODO @@ -0,0 +1,21 @@ +- ensure all forks block, restore and unblock signals. needs review + +- add support somehow for optional translations + +- oldnet[bridging]: Review setting of bridge configuration on dynamic interface add + +- Document rc-depend binary. + +- _ifindex is not a reliable means of calculating metrics: + _ifindex is used for calculating metrics for new devices but has a major + problem: Since it's only the nth entry in /proc/net/dev + And devices may be removed from that file, and reordered, you won't always + get the same result. + If you do: + - add eth0 - _ifindex (eth0=0) + - add vlan1 - _ifindex (eth0=0,vlan1=1) + - add vlan2 - _ifindex (eth0=0,vlan1=1,vlan2=2) + - rem vlan1 - _ifindex (eth0=0,vlan2=1) + - add vlan3 - _ifindex (eth0=0,vlan2=1,vlan3=2) + Now your routing table has entries for both vlan2 and vlan3 with a metric of 2. + Index: contrib/openrc/agetty-guide.md =================================================================== --- /dev/null +++ contrib/openrc/agetty-guide.md @@ -0,0 +1,19 @@ +Setting up the agetty service in OpenRC +=================================xxxxxx + +The agetty service is an OpenRC specific way to monitor and respawn a +getty, using agetty, on Linux. To use this method, make sure you aren't +spawning a getty manager for this port some other way (such as through +sysvinit/inittab), then run the following commands as root. + +Note that [port] refers to the port you are spawning the getty on, for +example, tty1 or ttyS0. The full path to it, for example, /dev/tty1 +should not be used. + +``` +# cd /etc/init.d +# ln -s agetty agetty.[port] +# cd /etc/conf.d +# cp agetty agetty.[port] +#rc-update add agetty.[port] [runlevel] +``` Index: contrib/openrc/bash-completion/Makefile =================================================================== --- /dev/null +++ contrib/openrc/bash-completion/Makefile @@ -0,0 +1,11 @@ +DIR= ${BASHCOMPDIR} +CONF= openrc \ + openrc-service-script \ + rc-service \ + rc-status \ + rc-update \ + +MK= ../mk +include ${MK}/os.mk + +include ${MK}/scripts.mk Index: contrib/openrc/bash-completion/openrc =================================================================== --- /dev/null +++ contrib/openrc/bash-completion/openrc @@ -0,0 +1,24 @@ +# Copyright (c) 2017 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# +# openrc completion command +# +_openrc() +{ + local cur + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ ${#COMP_WORDS[*]} -le 2 ]]; then + COMPREPLY=($(compgen -W "$(rc-status --list)" -- $cur)) + fi + return 0 +} && +complete -F _openrc openrc Index: contrib/openrc/bash-completion/openrc-service-script =================================================================== --- /dev/null +++ contrib/openrc/bash-completion/openrc-service-script @@ -0,0 +1,29 @@ +# Copyright (c) 2017 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +_openrc_service_script() +{ + local script="${COMP_WORDS[0]}" + local cur="${COMP_WORDS[$COMP_CWORD]}" + + if [[ ( -f "${script}" || -h "${script}" ) && -r "${script}" ]] \ + && [[ "$(head -n 1 "${script}")" =~ \#\!.*/openrc-run ]] + then + [[ $COMP_CWORD -gt 1 ]] && return 1 + COMPREPLY=($(opts="start stop status restart pause zap ineed needsme iuse usesme broken"; \ + eval "$(grep '^opts=' "${script}")"; echo "${opts}")) + [[ -n "$COMPREPLY" ]] || COMPREPLY=(start stop restart zap) + COMPREPLY=($(compgen -W "${COMPREPLY[*]}" -- "${cur}")) + else + COMPREPLY=($(compgen -o default -- "${cur}")) + fi + return 0 +} +complete -F _openrc_service_script */etc/init.d/* Index: contrib/openrc/bash-completion/rc-service =================================================================== --- /dev/null +++ contrib/openrc/bash-completion/rc-service @@ -0,0 +1,113 @@ +# Copyright (c) 2017 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# +# rc-service completion command +# +_rc_service() +{ + local cur prev numwords opts + local words i x filename + local action actionpos + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + numwords=${#COMP_WORDS[*]} + + if [[ ${prev} == '>' || ${prev} == '<' ]] ; then + COMPREPLY=($(compgen -f -- ${cur})) + return 0 + fi + + # find action + for x in ${COMP_LINE} ; do + if [[ ${x} =~ --(list|exists|resolve) ]] || [[ ${x} =~ -(l|e|r) ]] + then + action=${x} + break + fi + done + if [[ -n ${action} ]]; then + for ((i = 0; i < ${numwords}; i++ )); do + if [[ ${COMP_WORDS[${i}]} == "${action}" ]]; then + actionpos=${i} + break + fi + done + + for ((i = 1; i < ${numwords}; i++ )); do + if [[ ! ${COMP_WORDS[$i]} == -* ]]; then + break + fi + done + fi + + if [[ ${COMP_CWORD} -eq 3 ]]; then + return 1 + fi + + # check if an option was typed + if [[ ${cur} == -* ]]; then + if [[ ${cur} == --* ]]; then + opts="--list --exists --resolve" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + elif [[ ${cur} == -* ]]; then + opts="-l -e -r" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + # NOTE: This slows things down! + # (Adapted from bash_completion by Ian Macdonald ) + # This removes any options from the list of completions that have + # already been specified on the command line. + COMPREPLY=($(echo "${COMP_WORDS[@]}" | \ + (while read -d ' ' i; do + [[ -z ${i} ]] && continue + # flatten array with spaces on either side, + # otherwise we cannot grep on word boundaries of + # first and last word + COMPREPLY=" ${COMPREPLY[@]} " + # remove word from list of completions + COMPREPLY=(${COMPREPLY/ ${i%% *} / }) + done + echo ${COMPREPLY[@]}))) + + return 0 + else + # no option was typed + if [[ ${COMP_CWORD} -eq 1 ]]; then # if first word typed + words="$(rc-service --list | grep ^${cur})" # complete for init scripts + COMPREPLY=($(for i in ${words} ; do \ + [[ ${i} == ${cur}* ]] && echo ${i} ; \ + done)) + return 0 + elif [[ ${COMP_CWORD} -eq 2 ]] && [[ ${prev} != -* ]]; then # if second word typed and we didn't type in a function + filename=$(rc-service --resolve ${prev}) + opts=$(cat ${filename} | grep "^\w*()" | sed "s/().*$//") # Greps the functions included in the init script + if [[ "x${opts}" == "x" ]] ; then # if no options found loosen the grep algorhythm + opts=$(cat ${filename} | grep "\w*()" | sed "s/().*$//") + fi + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + fi + if [[ ${action} == '--exists' ]] || [[ ${action} == '-e' ]] || \ + [[ ${action} == '--resolve' ]] || [[ ${action} == '-r' ]]; then + words="$(rc-service --list | grep ^${cur})" + COMPREPLY=($(for i in ${words} ; do \ + [[ ${i} == ${cur}* ]] && echo ${i} ; \ + done)) + return 0 + fi + return 0 +} && +complete -F _rc_service rc-service Index: contrib/openrc/bash-completion/rc-status =================================================================== --- /dev/null +++ contrib/openrc/bash-completion/rc-status @@ -0,0 +1,31 @@ +# Copyright (c) 2017 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# +# rc-status completion command +# +_rcstatus() +{ + local cur + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ $COMP_CWORD -eq 1 ]]; then + if [[ "${cur}" == --* ]]; then + COMPREPLY=($(compgen -W '--all --list --unused' -- ${cur})) + elif [[ "${cur}" == -* ]]; then + COMPREPLY=($(compgen -W '-a -l -u' -- ${cur})) + else + COMPREPLY=($(compgen -W "$(rc-status --list)" -- ${cur})) + fi + else + unset COMPREPLY + fi + return 0 +} && +complete -F _rcstatus rc-status Index: contrib/openrc/bash-completion/rc-update =================================================================== --- /dev/null +++ contrib/openrc/bash-completion/rc-update @@ -0,0 +1,42 @@ +# Copyright (c) 2017 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# +# rc-update completion command +# +_rc_update() +{ + local cur show + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ $COMP_CWORD -eq 1 ]]; then + if [[ "${cur}" == -* ]]; then + COMPREPLY=($(compgen -W '-a -d -s' -- ${cur})) + else + COMPREPLY=($(compgen -W 'add del show' ${cur})) + fi + else + if [[ "${COMP_WORDS[1]}" == "show" ]] || [[ "${COMP_WORDS[1]}" == "-s" ]]; then + show="TRUE" + fi + if ([[ $COMP_CWORD -eq 3 ]] && [[ -z "$show" ]]) || \ + ([[ $COMP_CWORD -eq 2 ]] && [[ -n "$show" ]]); then + COMPREPLY=($(compgen -W "$(rc-status --list)" -- $cur)) + elif [[ $COMP_CWORD -eq 2 ]]; then + COMPREPLY=($(compgen -W "$(rc-service --list)" $cur)) + elif [[ ${#COMP_WORDS[*]} -gt 2 ]] ; then + COMPREPLY=($(compgen -W "$(rc-status --list)" -- $cur)) + else + unset COMPREPLY + fi + fi + return 0 +} && +complete -F _rc_update rc-update Index: contrib/openrc/conf.d/Makefile =================================================================== --- /dev/null +++ contrib/openrc/conf.d/Makefile @@ -0,0 +1,20 @@ +include ../mk/net.mk + +DIR= ${CONFDIR} +CONF= bootmisc fsck hostname localmount netmount swap urandom ${CONF-${OS}} + +ifeq (${MKNET},yes) +CONF+= network staticroute +endif + +MK= ../mk +include ${MK}/os.mk + +CONF-FreeBSD= ipfw modules moused powerd rarpd savecore syscons + +CONF-Linux= agetty consolefont devfs dmesg hwclock keymaps killprocs modules \ + mtab net-online + +CONF-NetBSD= moused rarpd savecore + +include ${MK}/scripts.mk Index: contrib/openrc/conf.d/adjkerntz =================================================================== --- /dev/null +++ contrib/openrc/conf.d/adjkerntz @@ -0,0 +1,10 @@ +# Set CLOCK to "UTC" if your system clock is set to UTC (also known as +# Greenwich Mean Time). If your clock is set to the local time, then +# set CLOCK to "local". Note that if you dual boot with Windows, then +# you should set it to "local". +clock="UTC" + +# If you want to set the Hardware Clock to the current System Time +# during shutdown, then say "YES" here. +# You normally don't need to do this if you run a ntp daemon. +clock_systohc="NO" Index: contrib/openrc/conf.d/agetty =================================================================== --- /dev/null +++ contrib/openrc/conf.d/agetty @@ -0,0 +1,11 @@ +# make agetty quiet +#quiet="yes" + +# Set the baud rate of the terminal line +#baud="" + +# set the terminal type +#term_type="linux" + +# extra options to pass to agetty for this port +#agetty_options="" Index: contrib/openrc/conf.d/bootmisc =================================================================== --- /dev/null +++ contrib/openrc/conf.d/bootmisc @@ -0,0 +1,15 @@ +# List of /tmp directories we should clean up +clean_tmp_dirs="/tmp" + +# Should we wipe the tmp paths completely or just selectively remove known +# locks / files / etc... ? +wipe_tmp="YES" + +# Write the initial dmesg log into /var/log/dmesg after boot +# This may be useful if you need the kernel boot log afterwards +log_dmesg="YES" + +# Save the previous dmesg log to dmesg.old +# This may be useful if you need to compare the current boot to the +# previous one. +#previous_dmesg=no Index: contrib/openrc/conf.d/consolefont =================================================================== --- /dev/null +++ contrib/openrc/conf.d/consolefont @@ -0,0 +1,18 @@ +# The consolefont service is not activated by default. If you need to +# use it, you should run "rc-update add consolefont boot" as root. +# +# consolefont specifies the default font that you'd like Linux to use on the +# console. You can find a good selection of fonts in /usr/share/consolefonts; +# you shouldn't specify the trailing ".psf.gz", just the font name below. +# To use the default console font, comment out the CONSOLEFONT setting below. +consolefont="default8x16" + +# consoletranslation is the charset map file to use. Leave commented to use +# the default one. Have a look in /usr/share/consoletrans for a selection of +# map files you can use. +#consoletranslation="8859-1_to_uni" + +# unicodemap is the unicode map file to use. Leave commented to use the +# default one. Have a look in /usr/share/unimaps for a selection of map files +# you can use. +#unicodemap="iso01" Index: contrib/openrc/conf.d/devfs =================================================================== --- /dev/null +++ contrib/openrc/conf.d/devfs @@ -0,0 +1,8 @@ +# OpenRC will attempt each of the following in succession to mount /dev. +# +# 1. If there is an entry for /dev in fstab, it will be used. +# 2. If devtmpfs is defined in the kernel, it will be used. +# 3. If tmpfs is defined in the kernel, it will be used. +# +# Set this to yes if you do not want OpenRC to attempt to mount /dev. +# skip_mount_dev="NO" Index: contrib/openrc/conf.d/dmesg =================================================================== --- /dev/null +++ contrib/openrc/conf.d/dmesg @@ -0,0 +1,3 @@ +# Sets the level at which logging of messages is done to the +# console. See dmesg(1) for more info. +dmesg_level="1" Index: contrib/openrc/conf.d/fsck =================================================================== --- /dev/null +++ contrib/openrc/conf.d/fsck @@ -0,0 +1,40 @@ +# Pass any arguments to fsck. +# By default we preen. +# Linux systems also force -C0 and -T. +# If fsck_args is not specified then Linux systems also use -A +# (and -R if / is rw) +#fsck_args="-p" + +# We can also specify the passno in /etc/fstab to check +# If you multiplex fsck (ie ln -s fsck /etc/init.d/fsck.late) then you can +# do an fsck outside of the normal scope, say for /home. +# Here are some exampes:- +#fsck_passno="=1 =2" +#fsck_passno=">1" +#fsck_passno="<2" + +# If passno is not enough granularity, you can also specify mountpoints to +# check. This should NOT be used for the default non-multiplexed fsck, or your +# system might not be checked. Additionally, it is mutually exclusive with +# the fsck_passno setting. +#fsck_mnt="" +#fsck_mnt="/home" + +# Most modern fs's don't require a full fsck on boot, but for those that do +# it may be advisable to skip this when running on battery. +# WARNING: Do not turn this off if you have any JFS partitions. +fsck_on_battery="YES" + +# fsck_shutdown causes fsck to trigger during shutdown as well as startup. +# The end result of this is that if any periodic non-root filesystem checks are +# scheduled, under normal circumstances the actual check will happen during +# shutdown rather than at next boot. +# This is useful when periodic filesystem checks are causing undesirable +# delays at startup, but such delays at shutdown are acceptable. +fsck_shutdown="NO" + +# fsck_abort_on_errors can be set to no to cause fsck to not abort on +# errors. +# This is useful when periodic filesystem checks are causing undesirable +# aborts. +fsck_abort_on_errors="YES" Index: contrib/openrc/conf.d/hostname =================================================================== --- /dev/null +++ contrib/openrc/conf.d/hostname @@ -0,0 +1,2 @@ +# Set to the hostname of this machine +hostname="localhost" Index: contrib/openrc/conf.d/hwclock =================================================================== --- /dev/null +++ contrib/openrc/conf.d/hwclock @@ -0,0 +1,20 @@ +# Set CLOCK to "UTC" if your Hardware Clock is set to UTC (also known as +# Greenwich Mean Time). If that clock is set to the local time, then +# set CLOCK to "local". Note that if you dual boot with Windows, then +# you should set it to "local". +clock="UTC" + +# If you want the hwclock script to set the system time (software clock) +# to match the current hardware clock during bootup, leave this +# commented out. +# However, you can set this to "NO" if you are running a modern kernel +# and using NTP to synchronize your system clock. +#clock_hctosys="YES" + +# If you do not want to set the hardware clock to the current system +# time (software clock) during shutdown, set this to no. +#clock_systohc="YES" + +# If you wish to pass any other arguments to hwclock during bootup, +# you may do so here. Alpha users may wish to use --arc or --srm here. +clock_args="" Index: contrib/openrc/conf.d/ipfw =================================================================== --- /dev/null +++ contrib/openrc/conf.d/ipfw @@ -0,0 +1,14 @@ +# ipfw provides a stateful firewall. +# This means we allow everything out, and if we have a connection we allow it +# back in. This is very flexable and quite secure. + +# For ease of use, we allow auth and ssh ports through as well. +# To override the list of allowed ports +#ipfw_ports_in="auth ssh" + +# You may want to enable logging of denied connections +#ipfw_log_deny="YES" + +# This ports not logged +#ipfw_ports_nolog="135-139,445 1026,1027 1433,1434" + Index: contrib/openrc/conf.d/keymaps =================================================================== --- /dev/null +++ contrib/openrc/conf.d/keymaps @@ -0,0 +1,23 @@ +# Use keymap to specify the default console keymap. There is a complete tree +# of keymaps in /usr/share/keymaps to choose from. +keymap="us" + +# Should we first load the 'windowkeys' console keymap? Most x86 users will +# say "yes" here. Note that non-x86 users should leave it as "no". +# Loading this keymap will enable VT switching (like ALT+Left/Right) +# using the special windows keys on the linux console. +windowkeys="NO" + +# The maps to load for extended keyboards. Most users will leave this as is. +extended_keymaps="" +#extended_keymaps="backspace keypad euro2" + +# Tell dumpkeys(1) to interpret character action codes to be +# from the specified character set. +# This only matters if you set unicode="yes" in /etc/rc.conf. +# For a list of valid sets, run `dumpkeys --help` +dumpkeys_charset="" + +# Some fonts map AltGr-E to the currency symbol instead of the Euro. +# To fix this, set to "yes" +fix_euro="NO" Index: contrib/openrc/conf.d/killprocs =================================================================== --- /dev/null +++ contrib/openrc/conf.d/killprocs @@ -0,0 +1,6 @@ +# If you wish to pass any options to kill_all during shutdown, +# you should do so here. +# +# The setting is called killall5_opts because the options here are meant +# to be identical to those you could pass to killall5. +killall5_opts="" Index: contrib/openrc/conf.d/localmount =================================================================== --- /dev/null +++ contrib/openrc/conf.d/localmount @@ -0,0 +1,10 @@ +# Stop the unmounting of certain points. +# This could be useful for some NFS related work. +#no_umounts="/dir1:/var/dir2" +# +# Mark certain mount points as critical. +# This contains a space separated list of mount points which should be +# considered critical. If one of these mount points cannot be mounted, +# localmount will fail. +# By default, this is empty. +#critical_mounts="/home /var" Index: contrib/openrc/conf.d/modules =================================================================== --- /dev/null +++ contrib/openrc/conf.d/modules @@ -0,0 +1,27 @@ +# Linux users can define a list of modules for a specific kernel version, +# a released kernel version, a main kernel version or all kernel versions. +# The most specific versioned variable will take precedence. +# FreeBSD users can only use the modules="foo bar" setting. +#modules_2_6_23_gentoo_r5="ieee1394 ohci1394" +#modules_2_6_23="tun ieee1394" +#modules_2_6="tun" +#modules_2="ipv6" +#modules="ohci1394" + +# Linux users can give modules a different name when they load - the new name +# will also be used to pick arguments below. +# This is not supported on FreeBSD. +#modules="dummy:dummy1" + +# Linux users can give the modules some arguments if needed, per version +# if necessary. +# Again, the most specific versioned variable will take precedence. +# This is not supported on FreeBSD. +#module_ieee1394_args="debug" +#module_ieee1394_args_2_6_23_gentoo_r5="debug2" +#module_ieee1394_args_2_6_23="debug3" +#module_ieee1394_args_2_6="debug4" +#module_ieee1394_args_2="debug5" + +# You should consult your kernel documentation and configuration +# for a list of modules and their options. Index: contrib/openrc/conf.d/moused =================================================================== --- /dev/null +++ contrib/openrc/conf.d/moused @@ -0,0 +1,16 @@ +# See the moused man page for available settings. + +# Set to your mouse device psm[0-9] for PS/2 ports, ums[0-9] for USB ports +# Leave blank to try to autodetect it +#moused_device="/dev/psm0" + +# Any additional arguments required for a specific port +#moused_args_psm0="" +# or for all mice +#moused_args="" + +# You can also multiplex the init script for each device like so +# ln -s moused /etc/init.d/moused.ums0 +# This enables you to have a config file per mouse (forces moused_device +# to ums0 in this case) and control each mouse. +# devd can also start and stop these mice, which laptop users will find handy. Index: contrib/openrc/conf.d/mtab =================================================================== --- /dev/null +++ contrib/openrc/conf.d/mtab @@ -0,0 +1,13 @@ +# As far as we are aware, there are no modern linux tools or use cases +# which require /etc/mtab to be a separate file from /proc/self/mounts, +# so this setting should be commented out. +# If it is set to yes, please comment it out and run this command: +# # rc-service mtab restart +# In the future, the mtab service will be removed since we are not aware +# of any need to manipulate /etc/mtab as a separate file from +# /proc/self/mounts. +# If you have a technical reason we should keep this support, please +# open an issue at https://github.com/openrc/openrc/issues and let us +# know about your situation. +# This setting controls whether /etc/mtab is a file or symbolic link. +# mtab_is_file=no Index: contrib/openrc/conf.d/net-online =================================================================== --- /dev/null +++ contrib/openrc/conf.d/net-online @@ -0,0 +1,18 @@ +# The interfaces setting controls which interfaces the net-online +# service considers in deciding whether the network is active. The +# default is all interfaces that support ethernet. +#interfaces="" + +# This setting controls whether a ping test is included in the test for +# network connectivity after all interfaces are active. +#include_ping_test=no + +# This setting is the host to attempt to ping if the above is yes. +# The default is google.com. +#ping_test_host=some.host.name + +# The timeout setting controls how long the net-online service waits +# for the network to be configured. +# The default is 120 seconds. +# if this is set to 0, the wait is infinite. +#timeout=120 Index: contrib/openrc/conf.d/netmount =================================================================== --- /dev/null +++ contrib/openrc/conf.d/netmount @@ -0,0 +1,47 @@ +# You will need to set the dependencies in the netmount script to match +# the network configuration tools you are using. This should be done in +# this file by following the examples below, and not by changing the +# service script itself. +# +# Each of these examples is meant to be used separately. So, for +# example, do not set rc_need to something like "net.eth0 dhcpcd". +# +# If you are using newnet and configuring your interfaces with static +# addresses with the network script, you should use this setting. +# +#rc_need="network" +# +# If you are using oldnet, you must list the specific net.* services you +# need. +# +# This example assumes all of your netmounts can be reached on +# eth0. +# +#rc_need="net.eth0" +# +# This example assumes some of your netmounts are on eth1 and some +# are on eth2. +# +#rc_need="net.eth1 net.eth2" +# +# If you are using a dynamic network management tool like +# NetworkManager, dhcpcd in standalone mode, wicd, badvpn-ncd, etc, to +# manage the network interfaces with the routes to your netmounts, you +# should list that tool. +# +#rc_need="NetworkManager" +#rc_need="dhcpcd" +#rc_need="wicd" +# +# The default setting is designed to be backward compatible with our +# current setup, but you are highly discouraged from using this. In +# other words, please change it to be more suited to your system. +# +rc_need="net" +# +# Mark certain mount points as critical. +# This contains aspace separated list of mount points which should be +# considered critical. If one of these mount points cannot be mounted, +# netmount will fail. +# By default, this is empty. +#critical_mounts="/home /var" Index: contrib/openrc/conf.d/network =================================================================== --- /dev/null +++ contrib/openrc/conf.d/network @@ -0,0 +1,80 @@ +# Assign static IP addresses and run custom scripts per interface. +# Seperate commands with ; +# Prefix with ! to run a shell script. +# Use \$int to represent the interface +#ifconfig_eth0="192.168.0.10 netmask 255.255.255.0" + +# You also have ifup_eth0 and ifdown_eth0 to run other commands when +# eth0 is started and stopped. +# You should note that we don't stop the network at system shutdown by default. +# If you really need this, then set keep_network=NO + +# Lastly, the interfaces variable pulls in virtual interfaces that cannot +# be automatically detected. +#interfaces="br0 bond0 vlan0" + +# You can also use files instead of variables here if you like: +# /etc/ifconfig.eth0 is equivalent to ifconfig_eth0 +# /etc/ip.eth0 is equivalent to ifconfig_eth0 +# /etc/ifup.eth0 is equivalent to ifup_eth0 +# /etc/ifdown.eth0 is equivalent to ifdown_eth0 +# Any files found will automatically be put into the interfaces variable. +# You don't need to escape variables in files, so use $int instead of \$int. + +# If you require DHCP, you should install dhcpcd and add it to the boot or +# default runlevel. + +# NIS users can set the domain name here +#domainname="foobar" + +# You can add a default route. +# The way this is done is slightly different depending on the operating system. +# +# *BSD: +#defaultroute="192.168.0.1" +#defaultroute6="2001:a:b:c" +#Hurd/Linux (ifconfig): +#defaultroute="gw 192.168.0.1" +#defaultroute6="gw 2001:a:b:c" + +# The remainder of this file applies to Linux only and shows how +# iproute2 is supported along with other examples. + +# ifconfig under Linux is not that powerful and doesn't easily handle +# multiple addresses +# On the other hand, iproute2 is quite powerful and is also supported +#ip_eth0="192.168.0.10/24; 192.168.10.10/24" + +# You can also use iproute2 to add the default route. +#defaultiproute="via 192.168.0.1" +#defaultiproute6="via 2001:a:b:c" + +# ip doesn't handle MTU like ifconfig, but we can do it like so +#ifup_eth0="ip link set \$int mtu 1500" + +# Create a bonded interface +#interfaces="bond0" +#ifup_bond0="modprobe bonding; ifconfig \$int up; ifenslave \$int bge0" +#ifconfig_bond0="192.168.0.10 netmask 255.255.255.0" +#ifdown_bond0="rmmod bonding" + +# Create tap interface and a bridge interface. +# We add the tap to the bridge. +# An external program, like dhcpcd, will configure the IP on the bridge +#interfaces="tun0 br0" +#ifup_tun0="tunctl -t \$int" +#ifdown_tun0="tunctl -d \$int" +#ifup_br0="brctl addbr \$int; brctl add \$int eth1; brtctl add \$int eth2" +#ifdown_br0="ifconfig \$int down; btctl delbr \$int" + +# Create VLAN +#interfaces="eth0_2 eth0_3 eth0_4" +#ifup_eth0="vconfig add \$int 2; vconfig add \$int 3; vconfig add \$int 4" +#ifconfig_eth0_2="192.168.2.10 netmask 255.255.255.0" +#ifconfig_eth0_3="192.168.3.10 netmask 255.255.255.0" +#ifconfig_eth0_4="192.168.4.10 netmask 255.255.255.0" +#ifdown_eth0="vconfig rem \$int.2; vconfig rem \$int.3; vconfig rem \$int.4" + +# Normally you would use wpa_supplicant to configure wireless, but you can +# use iwconfig also +#ifup_wlan0="iwconfig \$int key s:secretkey enc open essid foobar" Index: contrib/openrc/conf.d/powerd =================================================================== --- /dev/null +++ contrib/openrc/conf.d/powerd @@ -0,0 +1,7 @@ +# Mode allowed: maximum, minimum, adaptive +# Default unless specified is adaptive +powerd_ac_mode="maximum" +#powerd_battery_mode="minimum" + +# Addiditonal arguments for powerd - see the man page for details +powerd_args="" Index: contrib/openrc/conf.d/rarpd =================================================================== --- /dev/null +++ contrib/openrc/conf.d/rarpd @@ -0,0 +1,3 @@ +# To start rarpd only for a given interface, set the +# following variable. Otherwise we listen on all interfaces. +#rarpd_interface="rl0" Index: contrib/openrc/conf.d/savecore =================================================================== --- /dev/null +++ contrib/openrc/conf.d/savecore @@ -0,0 +1,25 @@ +# Unless you're a kernel developer or driver writer then this won't +# be of any interest to you at all. +# The following options allow to configure the kernel's core dump +# facilities. + +# The dump_device variable is used to specify which device will be +# used by the kernel to write the dump down. This has to be a swap +# partition, and has to be at least big enough to contain the whole +# physical memory (see hw.physmem sysctl(8) variable). +# When the variable is commented out, no core dump will be enabled for +# the kernel. +#dump_device=/dev/ad0s1b + +# The dump_dir variable is used to tell savecore(8) utility where +# to save the kernel core dump once it's restored from the dump +# device. If unset, /var/crash will be used, as the default of +# FreeBSD. +#dump_dir=/var/crash + +# The dump_compress variable decide whether to compress with +# gzip(1) the dump or leave it of its original size (the size of the +# physical memory present on the system). If set to yes, the -z option +# will be passed to savecore(8) that will proceed on compressing the +# dump. +#dump_compress=NO Index: contrib/openrc/conf.d/staticroute =================================================================== --- /dev/null +++ contrib/openrc/conf.d/staticroute @@ -0,0 +1,26 @@ +# Static routes are defined differently depending on your operating +# system, so please be sure to use the correct syntax. +# Do not use this file to define the default route. +# In all settings, multiple routes should be separated using ; or new lines. + +# Define static routes on Linux using route. See route(8) for syntax. +#staticroute="net 192.168.0.0 netmask 255.255.255.0 gw 10.73.1.1 +#net 192.168.1.0 netmask 255.255.255.0 gw 10.73.1.1" + +# Define static routes on Linux using iproute2. See ip(8) for syntax. +#staticiproute="192.168.0.0/24 via 10.73.1.1; 192.168.1.0/24 via 10.73.1.1" + +# Define static routes on GNU/Hurd. See route(8) for syntax. +# /etc/route.conf(5) takes precedence over this configuration. +# FIXME: "net ..." not supported +#staticroute="net 192.168.0.0 -netmask 255.255.255.0 --address 10.73.1.1 +#net 192.168.1.0 -netmask 255.255.255.0 --address 10.73.1.1" + +# Define static routes on GNU/KFreeBSD. See route(8) for syntax. +#staticroute="net 192.168.0.0 10.73.1.1 netmask 255.255.255.0 +#net 192.168.1.0 10.73.1.1 netmask 255.255.255.0" + +# Define static routes on other BSD systems. See route(8) for syntax. +# /etc/route.conf(5) takes precedence over this configuration. +#staticroute="net 192.168.0.0 -netmask 255.255.255.0 10.73.1.1 +#net 192.168.1.0 -netmask 255.255.255.0 10.73.1.1" Index: contrib/openrc/conf.d/swap =================================================================== --- /dev/null +++ contrib/openrc/conf.d/swap @@ -0,0 +1,13 @@ +# If you are only using local swap partitions, you should not change +# this file. Otherwise, you need to uncomment the below rc_before line +# followed by the appropriate rc_need line. +#rc_before="!localmount" +# +# If you are using swap files stored on local file systems, uncomment +# this line. +#rc_need="localmount" +# +# If you are using swap files stored on network file systems or swap +# partitions stored on network block devices such as iSCSI, uncomment +# this line. +#rc_need="netmount" Index: contrib/openrc/conf.d/syscons =================================================================== --- /dev/null +++ contrib/openrc/conf.d/syscons @@ -0,0 +1,19 @@ +# Example syscons config file. This is the place to set things like keymap, etc. + +# Set the video mode - you should check the vidcontrol man page for valid modes +# NOTE:- This will blank the screen after this command is run +# NOTE:- You can get more modes if you load the vesa kernel module, but this +# may require the SC_PIXEL_MODE kernel option +#allscreen_flags="VGA_80x30" + +# Set the keymap to "uk.iso". +#keymap="uk.iso" + +# Set the keyboard rate to 250ms delay, and 34 repeat rate. +#keyrate="250.34" + +# Change the behaviour of F-unction keys (see kbdcontrol(1)). +#keychange="10 'ssh myhost'" + +# See vidcontrol(1) -t +#blanktime="off" Index: contrib/openrc/conf.d/urandom =================================================================== --- /dev/null +++ contrib/openrc/conf.d/urandom @@ -0,0 +1,5 @@ +# Sometimes you want to have urandom start before "localmount" +# (say for crypt swap), so you will need to customize this +# behavior. If you have /var on a separate partition, then +# make sure this path lives on your root device somewhere. +urandom_seed="/var/lib/misc/random-seed" Index: contrib/openrc/etc/Makefile =================================================================== --- /dev/null +++ contrib/openrc/etc/Makefile @@ -0,0 +1,23 @@ +DIR= ${SYSCONFDIR} +SRCS= rc.in rc.shutdown.in +BIN= ${BIN-${OS}} +CONF= rc.conf ${BIN-${OS}} + +MK= ../mk +include ${MK}/os.mk + +SED_EXTRA-FreeBSD= -e 's:@TERM@:cons25:g' +BIN-FreeBSD= rc rc.shutdown rc.devd +CONF-FreeBSD= devd.conf + +SED_EXTRA-Linux= -e 's:@TERM@:wsvt25:g' +BIN-Linux= +CONF-Linux= + +SED_EXTRA-NetBSD= -e 's:@TERM@:wsvt25:g' +BIN-NetBSD= rc rc.shutdown +CONF-NetBSD= + +SED_EXTRA= ${SED_EXTRA-${OS}} + +include ${MK}/scripts.mk Index: contrib/openrc/etc/devd.conf =================================================================== --- /dev/null +++ contrib/openrc/etc/devd.conf @@ -0,0 +1,315 @@ +# $FreeBSD$ +# +# Refer to devd.conf(5) and devd(8) man pages for the details on how to +# run and configure devd. +# + +# NB: All regular expressions have an implicit ^$ around them. +# NB: device-name is shorthand for 'match device-name' + +options { + # Each directory directive adds a directory the list of directories + # that we scan for files. Files are read-in in the order that they + # are returned from readdir(3). The rule-sets are combined to + # create a DFA that's used to match events to actions. + directory "/etc/devd"; + directory "/usr/local/etc/devd"; + pid-file "/var/run/devd.pid"; + + # Setup some shorthand for regex that we use later in the file. + #XXX Yes, these are gross -- imp + set scsi-controller-regex + "(aac|adv|adw|aha|ahb|ahc|ahd|aic|amd|amr|asr|bt|ciss|ct|dpt|\ + esp|ida|iir|ips|isp|mlx|mly|mpt|ncr|ncv|nsp|stg|sym|trm|wds)\ + [0-9]+"; +}; + +# Note that the attach/detach with the highest value wins, so that one can +# override these general rules. + +# +# Configure the interface on attach. Due to a historical accident, this +# script is called pccard_ether. +# +notify 0 { + match "system" "IFNET"; + match "type" "ATTACH"; + action "/etc/rc.devd net.$subsystem start"; +}; + +notify 0 { + match "system" "IFNET"; + match "type" "DETACH"; + action "/etc/rc.devd net.$subsystem stop"; +}; + +# +# Try to configure the interface when the network comes up and deconfigure +# when it goes down +# +notify 0 { + match "system" "IFNET"; + match "type" "LINK_UP"; + media-type "ethernet"; + action "/etc/rc.devd net.$subsystem start"; +}; + +notify 0 { + match "system" "IFNET"; + match "type" "LINK_DOWN"; + media-type "ethernet"; + action "/etc/rc.devd net.$subsystem stop"; +}; +# +# Like Ethernet devices, but separate because +# they have a different media type. We may want +# to exploit this later. +# +detach 0 { + media-type "802.11"; + action "/etc/rc.devd net.$device-name stop"; +}; +attach 0 { + media-type "802.11"; + action "/etc/rc.devd net.$device-name start"; +}; +notify 0 { + match "system" "IFNET"; + match "type" "LINK_UP"; + media-type "802.11"; + action "/etc/rc.devd net.$subsystem start"; +}; +notify 0 { + match "system" "IFNET"; + match "type" "LINK_DOWN"; + media-type "802.11"; + action "/etc/rc.devd net.$subsystem stop"; +}; + +# An entry like this might be in a different file, but is included here +# as an example of how to override things. Normally 'ed50' would match +# the above attach/detach stuff, but the value of 100 makes it +# hard wired to 1.2.3.4. +attach 100 { + device-name "ed50"; + action "ifconfig $device-name inet 1.2.3.4 netmask 0xffff0000"; +}; +detach 100 { + device-name "ed50"; +}; + +# When a USB Bluetooth dongle appears activate it +attach 100 { + device-name "ubt[0-9]+"; + action "/etc/rc.d/bluetooth start $device-name"; +}; +detach 100 { + device-name "ubt[0-9]+"; + action "/etc/rc.d/bluetooth stop $device-name"; +}; + +# When a USB keyboard arrives, attach it as the console keyboard. +attach 100 { + device-name "ukbd0"; + action "/etc/rc.d/syscons setkeyboard /dev/ukbd0"; +}; +detach 100 { + device-name "ukbd0"; + action "/etc/rc.d/syscons setkeyboard /dev/kbd0"; +}; + +# The entry below starts moused when a mouse is plugged in. Moused +# stops automatically (actually it bombs :) when the device disappears. +attach 100 { + device-name "ums[0-9]+"; + action "/etc/rc.devd moused.$device-name start"; +}; + +# Firmware download into the ActiveWire board. After the firmware download is +# done the device detaches and reappears as something new and shiny +# automatically. +attach 100 { + match "vendor" "0x0854"; + match "product" "0x0100"; + match "release" "0x0000"; + action "/usr/local/bin/ezdownload -f /usr/local/share/usb/firmware/0854.0100.0_01.hex $device-name"; +}; + +# Firmware download for Entrega Serial DB25 adapter. +attach 100 { + match "vendor" "0x1645"; + match "product" "0x8001"; + match "release" "0x0101"; + action "if ! kldstat -n usio > /dev/null 2>&1 ; then kldload usio; fi /usr/sbin/ezdownload -v -f /usr/share/usb/firmware/1645.8001.0101 /dev/$device-name"; +}; + +# This entry starts the ColdSync tool in daemon mode. Make sure you have an up +# to date /usr/local/etc/palms. We override the 'listen' settings for port and +# type in /usr/local/etc/coldsync.conf. +attach 100 { + device-name "ugen[0-9]+"; + match "vendor" "0x082d"; + match "product" "0x0100"; + match "release" "0x0100"; + action "/usr/local/bin/coldsync -md -p /dev/$device-name -t usb"; +}; + +# +# Rescan scsi device-names on attach, but not detach. However, it is +# disabled by default due to reports of problems. +# +attach 0 { + device-name "$scsi-controller-regex"; +// action "camcontrol rescan all"; +}; + +# Don't even try to second guess what to do about drivers that don't +# match here. Instead, pass it off to syslog. Commented out for the +# moment, as the pnpinfo variable isn't set in devd yet. Individual +# variables within the bus supplied pnpinfo are set. +nomatch 0 { +# action "logger Unknown device: $pnpinfo $location $bus"; +}; + +# Various logging of unknown devices. +nomatch 10 { + match "bus" "uhub[0-9]+"; + action "logger Unknown USB device: vendor $vendor product $product \ + bus $bus"; +}; + +# Some PC-CARDs don't offer numerical manufacturer/product IDs, just +# show the CIS info there. +nomatch 20 { + match "bus" "pccard[0-9]+"; + match "manufacturer" "0xffffffff"; + match "product" "0xffffffff"; + action "logger Unknown PCCARD device: CISproduct $cisproduct \ + CIS-vendor $cisvendor bus $bus"; +}; + +nomatch 10 { + match "bus" "pccard[0-9]+"; + action "logger Unknown PCCARD device: manufacturer $manufacturer \ + product $product CISproduct $cisproduct CIS-vendor \ + $cisvendor bus $bus"; +}; + +nomatch 10 { + match "bus" "cardbus[0-9]+"; + action "logger Unknown Cardbus device: device $device class $class \ + vendor $vendor bus $bus"; +}; + +# Switch power profiles when the AC line state changes. +notify 10 { + match "system" "ACPI"; + match "subsystem" "ACAD"; + action "/etc/rc.d/power_profile $notify"; +}; + +# Notify all users before beginning emergency shutdown when we get +# a _CRT or _HOT thermal event and we're going to power down the system +# very soon. +notify 10 { + match "system" "ACPI"; + match "subsystem" "Thermal"; + match "notify" "0xcc"; + action "logger -p kern.emerg 'WARNING: system temperature too high, shutting down soon!'"; +}; + +# Sample ZFS problem reports handling. +notify 10 { + match "system" "ZFS"; + match "type" "zpool"; + action "logger -p kern.err 'ZFS: failed to load zpool $pool'"; +}; + +notify 10 { + match "system" "ZFS"; + match "type" "vdev"; + action "logger -p kern.err 'ZFS: vdev failure, zpool=$pool type=$type'"; +}; + +notify 10 { + match "system" "ZFS"; + match "type" "data"; + action "logger -p kern.warn 'ZFS: zpool I/O failure, zpool=$pool error=$zio_err'"; +}; + +notify 10 { + match "system" "ZFS"; + match "type" "io"; + action "logger -p kern.warn 'ZFS: vdev I/O failure, zpool=$pool path=$vdev_path offset=$zio_offset size=$zio_size error=$zio_err'"; +}; + +notify 10 { + match "system" "ZFS"; + match "type" "checksum"; + action "logger -p kern.warn 'ZFS: checksum mismatch, zpool=$pool path=$vdev_path offset=$zio_offset size=$zio_size'"; +}; + +# User requested suspend, so perform preparation steps and then execute +# the actual suspend process. +notify 10 { + match "system" "ACPI"; + match "subsystem" "Suspend"; + action "/etc/rc.suspend acpi $notify"; +}; +notify 10 { + match "system" "ACPI"; + match "subsystem" "Resume"; + action "/etc/rc.resume acpi $notify"; +}; + +/* EXAMPLES TO END OF FILE + +# The following might be an example of something that a vendor might +# install if you were to add their device. This might reside in +# /usr/local/etc/devd/deqna.conf. A deqna is, in this hypothetical +# example, a pccard ethernet-like device. Students of history may +# know other devices by this name, and will get the in-jokes in this +# entry. +nomatch 10 { + match "bus" "pccard[0-9]+"; + match "manufacturer" "0x1234"; + match "product" "0x2323"; + action "kldload if_deqna"; +}; +attach 10 { + device-name "deqna[0-9]+"; + action "/etc/pccard_ether $device-name start"; +}; +detach 10 { + device-name "deqna[0-9]+"; + action "/etc/pccard_ether $device-name stop"; +}; + +# Examples of notify hooks. A notify is a generic way for a kernel +# subsystem to send event notification to userland. +# +# Here are some examples of ACPI notify handlers. ACPI subsystems that +# generate notifies include the AC adapter, power/sleep buttons, +# control method batteries, lid switch, and thermal zones. +# +# Information returned is not always the same as the ACPI notify +# events. See the ACPI specification for more information about +# notifies. Here is the information returned for each subsystem: +# +# ACAD: AC line state (0 is offline, 1 is online) +# Button: Button pressed (0 for power, 1 for sleep) +# CMBAT: ACPI battery events +# Lid: Lid state (0 is closed, 1 is open) +# Suspend, Resume: Suspend and resume notification +# Thermal: ACPI thermal zone events +# +# This example calls a script when the AC state changes, passing the +# notify value as the first argument. If the state is 0x00, it might +# call some sysctls to implement economy mode. If 0x01, it might set +# the mode to performance. +notify 10 { + match "system" "ACPI"; + match "subsystem" "ACAD"; + action "/etc/acpi_ac $notify"; +}; +*/ Index: contrib/openrc/etc/rc.conf =================================================================== --- /dev/null +++ contrib/openrc/etc/rc.conf @@ -0,0 +1,309 @@ +# Global OpenRC configuration settings + +# Set to "YES" if you want the rc system to try and start services +# in parallel for a slight speed improvement. When running in parallel we +# prefix the service output with its name as the output will get +# jumbled up. +# WARNING: whilst we have improved parallel, it can still potentially lock +# the boot process. Don't file bugs about this unless you can supply +# patches that fix it without breaking other things! +#rc_parallel="NO" + +# Set rc_interactive to "YES" and you'll be able to press the I key during +# boot so you can choose to start specific services. Set to "NO" to disable +# this feature. This feature is automatically disabled if rc_parallel is +# set to YES. +#rc_interactive="YES" + +# If we need to drop to a shell, you can specify it here. +# If not specified we use $SHELL, otherwise the one specified in /etc/passwd, +# otherwise /bin/sh +# Linux users could specify /sbin/sulogin +#rc_shell=/bin/sh + +# Do we allow any started service in the runlevel to satisfy the dependency +# or do we want all of them regardless of state? For example, if net.eth0 +# and net.eth1 are in the default runlevel then with rc_depend_strict="NO" +# both will be started, but services that depend on 'net' will work if either +# one comes up. With rc_depend_strict="YES" we would require them both to +# come up. +#rc_depend_strict="YES" + +# rc_hotplug controls which services we allow to be hotplugged. +# A hotplugged service is one started by a dynamic dev manager when a matching +# hardware device is found. +# Hotplugged services appear in the "hotplugged" runlevel. +# If rc_hotplug is set to any value, we compare the name of this service +# to every pattern in the value, from left to right, and we allow the +# service to be hotplugged if it matches a pattern, or if it matches no +# patterns. Patterns can include shell wildcards. +# To disable services from being hotplugged, prefix patterns with "!". +#If rc_hotplug is not set or is empty, all hotplugging is disabled. +# Example - rc_hotplug="net.wlan !net.*" +# This allows net.wlan and any service not matching net.* to be hotplugged. +# Example - rc_hotplug="!net.*" +# This allows services that do not match "net.*" to be hotplugged. + +# rc_logger launches a logging daemon to log the entire rc process to +# /var/log/rc.log +# NOTE: Linux systems require the devfs service to be started before +# logging can take place and as such cannot log the sysinit runlevel. +#rc_logger="NO" + +# Through rc_log_path you can specify a custom log file. +# The default value is: /var/log/rc.log +#rc_log_path="/var/log/rc.log" + +# If you want verbose output for OpenRC, set this to yes. If you want +# verbose output for service foo only, set it to yes in /etc/conf.d/foo. +#rc_verbose=no + +# By default we filter the environment for our running scripts. To allow other +# variables through, add them here. Use a * to allow all variables through. +#rc_env_allow="VAR1 VAR2" + +# By default we assume that all daemons will start correctly. +# However, some do not - a classic example is that they fork and return 0 AND +# then child barfs on a configuration error. Or the daemon has a bug and the +# child crashes. You can set the number of milliseconds start-stop-daemon +# waits to check that the daemon is still running after starting here. +# The default is 0 - no checking. +#rc_start_wait=100 + +# rc_nostop is a list of services which will not stop when changing runlevels. +# This still allows the service itself to be stopped when called directly. +#rc_nostop="" + +# rc will attempt to start crashed services by default. +# However, it will not stop them by default as that could bring down other +# critical services. +#rc_crashed_stop=NO +#rc_crashed_start=YES + +# Set rc_nocolor to yes if you do not want colors displayed in OpenRC +# output. +#rc_nocolor=NO + +############################################################################## +# MISC CONFIGURATION VARIABLES +# There variables are shared between many init scripts + +# Set unicode to YES to turn on unicode support for keyboards and screens. +#unicode="NO" + +# This is how long fuser should wait for a remote server to respond. The +# default is 60 seconds, but it can be adjusted here. +#rc_fuser_timeout=60 + +# Below is the default list of network fstypes. +# +# afs ceph cifs coda davfs fuse fuse.sshfs gfs glusterfs lustre ncpfs +# nfs nfs4 ocfs2 shfs smbfs +# +# If you would like to add to this list, you can do so by adding your +# own fstypes to the following variable. +#extra_net_fs_list="" + +############################################################################## +# SERVICE CONFIGURATION VARIABLES +# These variables are documented here, but should be configured in +# /etc/conf.d/foo for service foo and NOT enabled here unless you +# really want them to work on a global basis. +# If your service has characters in its name which are not legal in +# shell variable names and you configure the variables for it in this +# file, those characters should be replaced with underscores in the +# variable names as shown below. + +# Some daemons are started and stopped via start-stop-daemon. +# We can set some things on a per service basis, like the nicelevel. +#SSD_NICELEVEL="-19" +# Or the ionice level. The format is class[:data] , just like the +# --ionice start-stop-daemon parameter. +#SSD_IONICELEVEL="2:2" + +# Pass ulimit parameters +# If you are using bash in POSIX mode for your shell, note that the +# ulimit command uses a block size of 512 bytes for the -c and -f +# options +#rc_ulimit="-u 30" + +# It's possible to define extra dependencies for services like so +#rc_config="/etc/foo" +#rc_need="openvpn" +#rc_use="net.eth0" +#rc_after="clock" +#rc_before="local" +#rc_provide="!net" + +# You can also enable the above commands here for each service. Below is an +# example for service foo. +#rc_foo_config="/etc/foo" +#rc_foo_need="openvpn" +#rc_foo_after="clock" + +# Below is an example for service foo-bar. Note that the '-' is illegal +# in a shell variable name, so we convert it to an underscore. +# example for service foo-bar. +#rc_foo_bar_config="/etc/foo-bar" +#rc_foo_bar_need="openvpn" +#rc_foo_bar_after="clock" + +# You can also remove dependencies. +# This is mainly used for saying which services do NOT provide net. +#rc_net_tap0_provide="!net" + +# This is the subsystem type. +# It is used to match against keywords set by the keyword call in the +# depend function of service scripts. +# +# It should be set to the value representing the environment this file is +# PRESENTLY in, not the virtualization the environment is capable of. +# If it is commented out, automatic detection will be used. +# +# The list below shows all possible settings as well as the host +# operating systems where they can be used and autodetected. +# +# "" - nothing special +# "docker" - Docker container manager (Linux) +# "jail" - Jail (DragonflyBSD or FreeBSD) +# "lxc" - Linux Containers +# "openvz" - Linux OpenVZ +# "prefix" - Prefix +# "rkt" - CoreOS container management system (Linux) +# "subhurd" - Hurd subhurds (to be checked) +# "systemd-nspawn" - Container created by systemd-nspawn (Linux) +# "uml" - Usermode Linux +# "vserver" - Linux vserver +# "xen0" - Xen0 Domain (Linux and NetBSD) +# "xenU" - XenU Domain (Linux and NetBSD) +#rc_sys="" + +# if you use openrc-init, which is currently only available on Linux, +# this is the default runlevel to activate after "sysinit" and "boot" +# when booting. +#rc_default_runlevel="default" + +# on Linux and Hurd, this is the number of ttys allocated for logins +# It is used in the consolefont, keymaps, numlock and termencoding +# service scripts. +rc_tty_number=12 + +############################################################################## +# LINUX CGROUPS RESOURCE MANAGEMENT + +# This sets the mode used to mount cgroups. +# "hybrid" mounts cgroups version 2 on /sys/fs/cgroup/unified and +# cgroups version 1 on /sys/fs/cgroup. +# "legacy" mounts cgroups version 1 on /sys/fs/cgroup +# "unified" mounts cgroups version 2 on /sys/fs/cgroup +#rc_cgroup_mode="hybrid" + +# This is a list of controllers which should be enabled for cgroups version 2. +# If hybrid mode is being used, controllers listed here will not be +# available for cgroups version 1. +# This is a global setting. +#rc_cgroup_controllers="" + +# This variable contains the cgroups version 2 settings for your services. +# If this is set in this file, the settings will apply to all services. +# If you want different settings for each service, place the settings in +# /etc/conf.d/foo for service foo. +# The format is to specify the setting and value followed by a newline. +# Multiple settings and values can be specified. +# For example, you would use this to set the maximum memory and maximum +# number of pids for a service. +#rc_cgroup_settings=" +#memory.max 10485760 +#pids.max max +#" +# +# For more information about the adjustments that can be made with +# cgroups version 2, see Documentation/cgroups-v2.txt in the linux kernel +# source tree. +#rc_cgroup_settings="" + +# This switch controls whether or not cgroups version 1 controllers are +# individually mounted under +# /sys/fs/cgroup in hybrid or legacy mode. +#rc_controller_cgroups="YES" + +# The following settings allow you to set up values for the cgroups version 1 +# controllers for your services. +# They can be set in this file;, however, if you do this, the settings +# will apply to all of your services. +# If you want different settings for each service, place the settings in +# /etc/conf.d/foo for service foo. +# The format is to specify the names of the settings followed by their +# values. Each variable can hold multiple settings. +# For example, you would use this to set the cpu.shares setting in the +# cpu controller to 512 for your service. +# rc_cgroup_cpu=" +# cpu.shares 512 +# " +# +# For more information about the adjustments that can be made with +# cgroups version 1, see Documentation/cgroups-v1/* in the linux kernel +# source tree. + +# Set the blkio controller settings for this service. +#rc_cgroup_blkio="" + +# Set the cpu controller settings for this service. +#rc_cgroup_cpu="" + +# Add this service to the cpuacct controller (any value means yes). +#rc_cgroup_cpuacct="" + +# Set the cpuset controller settings for this service. +#rc_cgroup_cpuset="" + +# Set the devices controller settings for this service. +#rc_cgroup_devices="" + +# Set the hugetlb controller settings for this service. +#rc_cgroup_hugetlb="" + +# Set the memory controller settings for this service. +#rc_cgroup_memory="" + +# Set the net_cls controller settings for this service. +#rc_cgroup_net_cls="" + +# Set the net_prio controller settings for this service. +#rc_cgroup_net_prio="" + +# Set the pids controller settings for this service. +#rc_cgroup_pids="" + +# Set this to YES if you want all of the processes in a service's cgroup +# killed when the service is stopped or restarted. +# Be aware that setting this to yes means all of a service's +# child processes will be killed. Keep this in mind if you set this to +# yes here instead of for the individual services in +# /etc/conf.d/. +# To perform this cleanup manually for a stopped service, you can +# execute cgroup_cleanup with /etc/init.d/ cgroup_cleanup or +# rc-service cgroup_cleanup. +# The process followed in this cleanup is the following: +# 1. send stopsig (sigterm if it isn't set) to all processes left in the +# cgroup immediately followed by sigcont. +# 2. Send sighup to all processes in the cgroup if rc_send_sighup is +# yes. +# 3. delay for rc_timeout_stopsec seconds. +# 4. send sigkill to all processes in the cgroup unless disabled by +# setting rc_send_sigkill to no. +# rc_cgroup_cleanup="NO" + +# If this is yes, we will send sighup to the processes in the cgroup +# immediately after stopsig and sigcont. +#rc_send_sighup="NO" + +# This is the amount of time in seconds that we delay after sending sigcont +# and optionally sighup, before we optionally send sigkill to all +# processes in the # cgroup. +# The default is 90 seconds. +#rc_timeout_stopsec="90" + +# If this is set to no, we do not send sigkill to all processes in the +# cgroup. +#rc_send_sigkill="YES" Index: contrib/openrc/etc/rc.devd =================================================================== --- /dev/null +++ contrib/openrc/etc/rc.devd @@ -0,0 +1,39 @@ +#!/bin/sh +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Inform RC that we are in the background and hotplugged +IN_BACKGROUND=yes +IN_HOTPLUG=yes +export IN_BACKGROUND IN_HOTPLUG + +getmedia() { + ifconfig "$1" | while read line; do + case "${line}" in + media:" "*) echo "${line}"; return;; + esac + done +} + +# Try and create an init script for network interfaces +if [ ! -e /etc/init.d/"$1" -a ! -e /usr/local/init.d/"$1" ]; then + base=${1%%.*} + if [ "${base}" = "net" ]; then + # We only create links for pyhsical interfaces + [ -n "$(getmedia ${1#*.})" ] || exit 1 + base="net.lo0" + fi + if [ -e /etc/init.d/"${base}" -a "${base}" != "$1" ]; then + ln -s "${base}" /etc/init.d/"$1" + fi +fi + +# Run the init script +exec /etc/init.d/"$1" "$2" Index: contrib/openrc/etc/rc.in =================================================================== --- /dev/null +++ contrib/openrc/etc/rc.in @@ -0,0 +1,26 @@ +#!@SHELL@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# If $TERM is not set then assume default of @TERM@ +# This gives us a nice colour boot :) +[ -z "$TERM" -o "$TERM" = "dumb" ] && TERM="@TERM@" && export TERM + +# Handle interrupts +trap : SIGINT +trap "echo 'Boot interrupted'; exit 1" SIGQUIT + +/sbin/openrc sysinit || exit 1 +/sbin/openrc boot || exit 1 +/sbin/openrc default + +# We don't actually care if rc default worked or not, we should exit 0 +# to allow logins +exit 0 Index: contrib/openrc/etc/rc.shutdown.in =================================================================== --- /dev/null +++ contrib/openrc/etc/rc.shutdown.in @@ -0,0 +1,24 @@ +#!@SHELL@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Handle interrupts +trap : SIGINT SIGQUIT + +# Try and use stuff in /lib over anywhere else so we can shutdown +# local mounts correctly. +LD_LIBRARY_PATH="/lib${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}" ; export LD_LIBRARY_PATH + +# If $TERM is not set then assume default of @TERM@ +# This gives us a nice colour boot :) +[ -z "$TERM" -o "$TERM" = "dumb" ] && TERM="@TERM@" && export TERM + +action=${1:-shutdown} +exec /sbin/openrc "${action}" Index: contrib/openrc/guide.md =================================================================== --- /dev/null +++ contrib/openrc/guide.md @@ -0,0 +1,269 @@ +# Purpose and description + +OpenRC is an init system for Unixoid operating systems. It takes care of +startup and shutdown of the whole system, including services. + +It evolved out of the Gentoo "Baselayout" package which was a custom pure-shell +startup solution. (This was both hard to maintain and debug, and not very +performant) + +Most of the core parts are written in C99 for performance and flexibility +reasons, while everything else is posix sh. +The License is 2-clause BSD + +Current size is about 10k LoC C, and about 4k LoC shell. + +OpenRC is known to work on Linux, many BSDs (FreeBSD, OpenBSD, DragonFlyBSD at +least) and HURD. + +Services are stateful (i.e. `start`; `start` will lead to "it's already started") + +# Startup + +Usually PID1 (aka. `init`) calls the OpenRC binary (`/sbin/openrc` by default). +(The default setup assumes sysvinit for this) + +openrc scans the runlevels (default: `/etc/runlevels`) and builds a dependency +graph, then starts the needed service scripts, either serialized (default) or in +parallel. + +When all the init scripts are started openrc terminates. There is no persistent +daemon. (Integration with tools like monit, runit or s6 can be done) + +# Shutdown + +On change to runlevel 0/6 or running `reboot`, `halt` etc., openrc stops all +services that are started and runs the services in the `shutdown` runlevel. + +# Modifying Service Scripts + +Any service can, at any time, be started/stopped/restarted by executing +`rc-service someservice start`, `rc-service someservice stop`, etc. +Another, less preferred method, is to run the service script directly, +e.g. `/etc/init.d/service start`, `/etc/init.d/service stop`, etc. + +OpenRC will take care of dependencies, e.g starting apache will start network +first, and stopping network will stop apache first. + +There is a special command `zap` that makes OpenRC 'forget' that a service is +started; this is mostly useful to reset a crashed service to stopped state +without invoking the (possibly broken) stop function of the service script. + +Calling `openrc` without any arguments will try to reset all services so +that the current runlevel is satisfied; if you manually started apache it will be +stopped, and if squid died but is in the current runlevel it'll be restarted. + +There is a `service` helper that emulates the syntax seen on e.g. older Redhat +and Ubuntu (`service nginx start` etc.) + +# Runlevels + +OpenRC has a concept of runlevels, similar to what sysvinit historically +offered. A runlevel is basically a collection of services that needs to be +started. Instead of random numbers they are named, and users can create their +own if needed. This allows, for example, to have a default runlevel with +"everything" enabled, and a "powersaving" runlevel where some services are +disabled. + +The `rc-status` helper will print all currently active runlevels and the state +of init scripts in them: + +``` +# rc-status + * Caching service dependencies ... [ ok ] +Runlevel: default + modules [ started ] + lvm [ started ] +``` + +All runlevels are represented as folders in `/etc/runlevels/` with symlinks to +the actual init scripts. + +Calling openrc with an argument (`openrc default`) will switch to that +runlevel; this will start and stop services as needed. + +Managing runlevels is usually done through the `rc-update` helper, but could of +course be done by hand if desired. +e.g. `rc-update add nginx default` - add nginx to the default runlevel +Note: This will not auto-start nginx! You'd still have to trigger `rc` or run +the initscript by hand. + +FIXME: Document stacked runlevels + +The default startup uses the runlevels `boot`, `sysinit` and `default`, in that +order. Shutdown uses the `shutdown` runlevel. + + +# Syntax of Service Scripts + +Service scripts are shell scripts. OpenRC aims at using only the standardized +POSIX sh subset for portability reasons. The default interpreter (build-time +toggle) is `/bin/sh`, so using for example mksh is not a problem. + +OpenRC has been tested with busybox sh, ash, dash, bash, mksh, zsh and possibly +others. Using busybox sh has been difficult as it replaces commands with +builtins that don't offer the expected features. + +The interpreter for initscripts is `#!/sbin/openrc-run`. +Not using this interpreter will break the use of dependencies and is not +supported. (iow: if you insist on using `#!/bin/sh` you're on your own) + +A `depend` function declares the dependencies of this service script. +All scripts must have start/stop/status functions, but defaults are provided. +Extra functions can be added easily: + +``` +extra_commands="checkconfig" +checkconfig() { + doSomething +} +``` + +This exports the checkconfig function so that `/etc/init.d/someservice +checkconfig` will be available, and it "just" runs this function. + +While commands defined in `extra_commands` are always available, commands +defined in `extra_started_commands` will only work when the service is started +and those defined in `extra_stopped_commands` will only work when the service is +stopped. This can be used for implementing graceful reload and similar +behaviour. + +Adding a restart function will not work, this is a design decision within +OpenRC. Since there may be dependencies involved (e.g. network -> apache) a +restart function is in general not going to work. +restart is internally mapped to `stop()` + `start()` (plus handling dependencies). +If a service needs to behave differently when it is being restarted vs +started or stopped, it should test the `$RC_CMD` variable, for example: + +``` +[ "$RC_CMD" = restart ] && do_something +``` + +# The Depend Function + +This function declares the dependencies for a service script. This +determines the order the service scripts start. + +``` +depend() { + need net + use dns logger netmount + want coolservice +} +``` + +`need` declares a hard dependency - net always needs to be started before this + service does + +`use` is a soft dependency - if dns, logger or netmount is in this runlevel + start it before, but we don't care if it's not in this runlevel. + `want` is between need and use - try to start coolservice if it is + installed on the system, regardless of whether it is in the + runlevel, but we don't care if it starts. + +`before` declares that we need to be started before another service + +`after` declares that we need to be started after another service, without + creating a dependency (so on calling stop the two are independent) + +`provide` allows multiple implementations to provide one service type, e.g.: + `provide cron` is set in all cron-daemons, so any one of them started + satisfies a cron dependency + +`keyword` allows platform-specific overrides, e.g. `keyword -lxc` makes this + service script a noop in lxc containers. Useful for things like keymaps, + module loading etc. that are either platform-specific or not available + in containers/virtualization/... + +FIXME: Anything missing in this list? + +# The Default Functions + +All service scripts are assumed to have the following functions: + +``` +start() +stop() +status() +``` + +There are default implementations in `lib/rc/sh/openrc-run.sh` - this allows very +compact service scripts. These functions can be overridden per service script as +needed. + +The default functions assume the following variables to be set in the service +script: + +``` +command= +command_args= +pidfile= +``` + +Thus the 'smallest' service scripts can be half a dozen lines long + +# The Magic of `conf.d` + +Most service scripts need default values. It would be fragile to +explicitly source some arbitrary files. By convention `openrc-run` will source +the matching file in `/etc/conf.d/` for any script in `/etc/init.d/` + +This allows you to set random startup-related things easily. Example: + +``` +conf.d/foo: +START_OPTS="--extraparameter sausage" + +init.d/foo: +start() { + /usr/sbin/foo-daemon ${STARTOPTS} +} +``` + +The big advantage of this split is that most of the time editing of the init +script can be avoided. + +# Start-Stop-Daemon + +OpenRC has its own modified version of s-s-d, which is historically related and +mostly syntax-compatible to Debian's s-s-d, but has been rewritten from scratch. + +It helps with starting daemons, backgrounding, creating PID files and many +other convenience functions related to managing daemons. + +# `/etc/rc.conf` + +This file manages the default configuration for OpenRC, and it has examples of +per-service-script variables. + +Among these are `rc_parallel` (for parallelized startup), `rc_log` (logs all boot +messages to a file), and a few others. + +# ulimit and CGroups + +Setting `ulimit` and `nice` values per service can be done through the `rc_ulimit` +variable. + +Under Linux, OpenRC can optionally use CGroups for process management. +By default each service script's processes are migrated to their own CGroup. + +By changing certain values in the `conf.d` file limits can be enforced per +service. It is easy to find orphan processes of a service that persist after +`stop()`, but by default these will NOT be terminated. +To change this add `rc_cgroup_cleanup="yes"` in the `conf.d` files for services +where you desire this functionality. + +# Caching + +For performance reasons OpenRC keeps a cache of pre-parsed initscript metadata +(e.g. `depend`). The default location for this is `/${RC_SVCDIR}/cache`. + +The cache uses `mtime` to check for file staleness. Should any service script +change it'll re-source the relevant files and update the cache + +# Convenience functions + +OpenRC has wrappers for many common output tasks in libeinfo. +This allows to print colour-coded status notices and other things. +To make the output consistent the bundled initscripts all use ebegin/eend to +print nice messages. Index: contrib/openrc/init.d/Makefile =================================================================== --- /dev/null +++ contrib/openrc/init.d/Makefile @@ -0,0 +1,37 @@ +include ../mk/net.mk + +DIR= ${INITDIR} +SRCS= bootmisc.in fsck.in hostname.in local.in localmount.in loopback.in \ + netmount.in osclock.in root.in savecache.in swap.in swclock.in \ + sysctl.in runsvdir.in urandom.in s6-svscan.in ${SRCS-${OS}} +BIN= ${OBJS} + +# Are we installing our network scripts? +ifeq (${MKNET},yes) +SRCS+= network.in staticroute.in +endif + +MK= ../mk +include ${MK}/os.mk + +# Generic BSD scripts +SRCS-FreeBSD= hostid.in modules.in moused.in newsyslog.in pf.in rarpd.in \ + rc-enabled.in rpcbind.in savecore.in syslogd.in +# These are FreeBSD specific +SRCS-FreeBSD+= adjkerntz.in devd.in dumpon.in encswap.in ipfw.in \ + modules-load.in mixer.in nscd.in powerd.in syscons.in + +SRCS-Linux= agetty.in binfmt.in devfs.in cgroups.in dmesg.in hwclock.in \ + consolefont.in keymaps.in killprocs.in modules.in modules-load.in \ + mount-ro.in mtab.in numlock.in procfs.in net-online.in sysfs.in \ +termencoding.in + +# Generic BSD scripts +SRCS-NetBSD= hostid.in moused.in newsyslog.in pf.in rarpd.in rc-enabled.in \ + rpcbind.in savecore.in syslogd.in +# These are NetBSD specific +SRCS-NetBSD+= devdb.in swap-blk.in ttys.in wscons.in + +include ${MK}/scripts.mk + +_installafter_: realinstall Index: contrib/openrc/init.d/adjkerntz.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/adjkerntz.in @@ -0,0 +1,70 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +extra_commands="save" + +description="Sets the local clock to UTC or Local Time." +description_save="Saves the current time in the BIOS." + +: ${clock:=${CLOCK:-UTC}} +if [ "$clock" = "UTC" ]; then + utc="UTC" +else + utc="Local Time" +fi + +depend() +{ + after swclock + provide clock + # BSD adjkerntz needs to be able to write to /etc + if [ "$clock" = "UTC" -a -e /etc/wall_cmos_clock ] || + [ "$clock" != "UTC" -a ! -e /etc/wall_cmos_clock ]; then + need root + fi + keyword -jail -prefix +} + +start() +{ + ebegin "Starting the System Clock Adjuster [${utc}]" + if [ "$clock" != "UTC" ]; then + echo >/etc/wall_cmos_clock + start-stop-daemon --start --exec /sbin/adjkerntz -- -i + else + rm -f /etc/wall_cmos_clock + /sbin/adjkerntz -i + fi + eend $? +} + +save() +{ + ebegin "Setting hardware clock using the system clock [${utc}]" + adjkerntz -a + eend $? +} + +stop() +{ + # Don't tweak the hardware clock on LiveCD halt. + if yesno "${clock_systohc:-$CLOCK_SYSTOHC}"; then + [ -z "$CDBOOT" ] && save + fi + + ebegin "Stopping the System Clock Adjuster" + if start-stop-daemon --test --quiet --stop --exec /sbin/adjkerntz; then + start-stop-daemon --stop --exec /sbin/adjkerntz + eend $? + else + eend 0 + fi +} Index: contrib/openrc/init.d/agetty.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/agetty.in @@ -0,0 +1,33 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2017 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="start agetty on a terminal line" +supervisor=supervise-daemon +port="${RC_SVCNAME#*.}" +term_type="${term_type:-linux}" +command=/sbin/agetty +command_args_foreground="${agetty_options} ${port} ${baud} ${term_type}" +pidfile="/run/${RC_SVCNAME}.pid" +export EINFO_QUIET="${quiet:-yes}" + +depend() { + after local + keyword -prefix +} + +start_pre() { + if [ -z "$port" ]; then + eerror "${RC_SVCNAME} cannot be started directly. You must create" + eerror "symbolic links to it for the ports you want to start" + eerror "agetty on and add those to the appropriate runlevels." + return 1 + fi +} Index: contrib/openrc/init.d/binfmt.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/binfmt.in @@ -0,0 +1,27 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Register misc binary format handlers" + +depend() +{ + after clock procfs + use modules devfs + keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver +} + +start() +{ + ebegin "Loading custom binary format handlers" + "$RC_LIBEXECDIR"/sh/binfmt.sh + eend $? + return 0 +} Index: contrib/openrc/init.d/bootmisc.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/bootmisc.in @@ -0,0 +1,253 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() +{ + need localmount + before logger + after clock root sysctl + keyword -prefix -timeout +} + +: ${wipe_tmp:=${WIPE_TMP:-yes}} +: ${log_dmesg:=${LOG_DMESG:-yes}} + +cleanup_tmp_dir() +{ + local dir="$1" + + if ! [ -d "$dir" ]; then + mkdir -p "$dir" || return $? + fi + checkpath -W "$dir" || return 1 + chmod a+rwt "$dir" 2> /dev/null + cd "$dir" || return 1 + if yesno $wipe_tmp; then + ebegin "Wiping $dir directory" + + # Faster than raw find + if ! rm -rf -- [!ajlq\.]* 2>/dev/null ; then + # Blah, too many files + find . -maxdepth 1 -name '[!ajlq\.]*' -exec rm -rf -- {} + + fi + + # pam_mktemp creates a .private directory within which + # each user gets a private directory with immutable + # bit set; remove the immutable bit before trying to + # remove it. + [ -d /tmp/.private ] && chattr -R -a /tmp/.private 2> /dev/null + + # Prune the paths that are left + find . -maxdepth 1 \ + ! -name . \ + ! -name lost+found \ + ! -name quota.user \ + ! -name aquota.user \ + ! -name quota.group \ + ! -name aquota.group \ + ! -name journal \ + -exec rm -rf -- {} + + eend 0 + else + ebegin "Cleaning $dir directory" + rm -rf -- .X*-lock esrv* kio* \ + jpsock.* .fam* .esd* \ + orbit-* ssh-* ksocket-* \ + .*-unix + eend 0 + fi +} + +cleanup_var_run_dir() +{ + ebegin "Cleaning /var/run" + for x in $(find /var/run ! -type d ! -name utmp \ + ! -name random-seed ! -name dev.db \ + ! -name ld-elf.so.hints ! -name ld-elf32.so.hints \ + ! -name ld.so.hints); + do + # Clean stale sockets + if [ -S "$x" ]; then + if command -v fuser >/dev/null 2>&1; then + fuser "$x" >/dev/null 2>&1 || rm -- "$x" + else + rm -- "$x" + fi + fi + [ ! -f "$x" ] && continue + # Do not remove pidfiles of already running daemons + case "$x" in + *.pid) + start-stop-daemon --test --quiet \ + --stop --pidfile "$x" && continue + ;; + esac + rm -f -- "$x" + done + eend 0 +} + +mkutmp() +{ + : >"$1" + # Not all systems have the utmp group + chgrp utmp "$1" 2>/dev/null + chmod 0664 "$1" +} + +migrate_to_run() +{ + src="$1" + dst="$2" + if [ -L $src -a "$(readlink -f $src)" != $dst ]; then + ewarn "$src does not point to $dst." + ewarn "Setting $src to point to $dst." + rm $src + elif [ ! -L $src -a -d $src ]; then + ebegin "Migrating $src to $dst" + cp -a $src/* $dst/ + rm -rf $src + eend $? + fi + # If $src doesn't exist at all, just run this + if [ ! -e $src ]; then + ln -s $dst $src + fi +} + +clean_run() +{ + [ "$RC_SYS" = VSERVER -o "$RC_SYS" = LXC ] && return 0 + local dir + # If / is still read-only due to a problem, this will fail! + if ! checkpath -W /; then + ewarn "/ is not writable; unable to clean up underlying /run" + return 1 + fi + if ! checkpath -W /tmp; then + ewarn "/tmp is not writable; unable to clean up underlying /run" + return 1 + fi + # Now we know that we can modify /tmp and / + # if mktemp -d fails, it returns an EMPTY string + # STDERR: mktemp: failed to create directory via template ‘/tmp/tmp.XXXXXXXXXX’: Read-only file system + # STDOUT: '' + rc=0 + dir=$(mktemp -d) + if [ -n "$dir" -a -d $dir -a -w $dir ]; then + mount --bind / $dir && rm -rf $dir/run/* || rc=1 + umount $dir && rmdir $dir + else + rc=1 + fi + if [ $rc -ne 0 ]; then + ewarn "Could not clean up underlying /run on /" + return 1 + fi +} + +start() +{ + # Remove any added console dirs + if checkpath -W "$RC_LIBEXECDIR"; then + rm -rf "$RC_LIBEXECDIR"/console/* + fi + + local logw=false runw=false extra= + # Ensure that our basic dirs exist + if [ "$RC_UNAME" = Linux ]; then + # Satisfy Linux FHS + extra=/var/lib/misc + if [ ! -d /run ]; then + extra="/var/run $extra" + fi + else + extra=/var/run + fi + for x in /var/log /tmp $extra; do + if ! [ -d $x ]; then + if ! mkdir -p $x; then + eend 1 "failed to create needed directory $x" + return 1 + fi + fi + done + + if [ "$RC_UNAME" = Linux -a -d /run ]; then + migrate_to_run /var/lock /run/lock + migrate_to_run /var/run /run + clean_run + fi + + if checkpath -W /var/run; then + ebegin "Creating user login records" + local xtra= + [ "$RC_UNAME" = NetBSD ] && xtra=x + for x in "" $xtra; do + mkutmp /var/run/utmp$x + done + [ -e /var/log/wtmp ] || mkutmp /var/log/wtmp + eend 0 + + mountinfo -q -f tmpfs /var/run || cleanup_var_run_dir + fi + + # Clean up /tmp directories + local tmp= + for tmp in ${clean_tmp_dirs:-${wipe_tmp_dirs-/tmp}}; do + mountinfo -q -f tmpfs "$tmp" || cleanup_tmp_dir "$tmp" + done + + if checkpath -W /tmp; then + # Make sure our X11 stuff have the correct permissions + # Omit the chown as bootmisc is run before network is up + # and users may be using lame LDAP auth #139411 + rm -rf /tmp/.ICE-unix /tmp/.X11-unix + mkdir -p /tmp/.ICE-unix /tmp/.X11-unix + chmod 1777 /tmp/.ICE-unix /tmp/.X11-unix + if [ -x /sbin/restorecon ]; then + restorecon /tmp/.ICE-unix /tmp/.X11-unix + fi + fi + + if yesno $log_dmesg; then + if $logw || checkpath -W /var/log; then + # Create an 'after-boot' dmesg log + case "$RC_SYS" in + VSERVER|OPENVZ|LXC|SYSTEMD-NSPAWN) ;; + *) + if yesno ${previous_dmesg:-no}; then + mv /var/log/dmesg /var/log/dmesg.old + fi + dmesg > /var/log/dmesg + chmod 640 /var/log/dmesg + ;; + esac + fi + fi + + return 0 +} + +stop() +{ + # Write a halt record if we're shutting down + if [ "$RC_RUNLEVEL" = shutdown ]; then + [ "$RC_UNAME" = Linux ] && openrc-shutdown -w + if [ "$RC_SYS" = OPENVZ ]; then + yesno $RC_REBOOT && printf "" >/reboot + fi + fi + + return 0 +} + +# vim: ft=sh Index: contrib/openrc/init.d/cgroups.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/cgroups.in @@ -0,0 +1,146 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2017 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mount the control groups." + +cgroup_opts=nodev,noexec,nosuid + +depend() +{ + keyword -docker -prefix -systemd-nspawn -vserver + after sysfs +} + +cgroup1_base() +{ + grep -qw cgroup /proc/filesystems || return 0 + if ! mountinfo -q /sys/fs/cgroup; then + ebegin "Mounting cgroup filesystem" + local opts="${cgroup_opts},mode=755,size=${rc_cgroupsize:-10m}" + mount -n -t tmpfs -o "${opts}" cgroup_root /sys/fs/cgroup + eend $? + fi + + if ! mountinfo -q /sys/fs/cgroup/openrc; then + local agent="${RC_LIBEXECDIR}/sh/cgroup-release-agent.sh" + mkdir /sys/fs/cgroup/openrc + mount -n -t cgroup \ + -o none,${cgroup_opts},name=openrc,release_agent="$agent" \ + openrc /sys/fs/cgroup/openrc + printf 1 > /sys/fs/cgroup/openrc/notify_on_release + fi + return 0 +} + +cgroup1_controllers() +{ + yesno "${rc_controller_cgroups:-YES}" && [ -e /proc/cgroups ] && + grep -qw cgroup /proc/filesystems || return 0 + while read -r name _ _ enabled _; do + case "${enabled}" in + 1) mountinfo -q "/sys/fs/cgroup/${name}" && continue + local x + for x in $rc_cgroup_controllers; do + [ "${name}" = "blkio" ] && [ "${x}" = "io" ] && + continue 2 + [ "${name}" = "${x}" ] && + continue 2 + done + mkdir "/sys/fs/cgroup/${name}" + mount -n -t cgroup -o "${cgroup_opts},${name}" \ + "${name}" "/sys/fs/cgroup/${name}" + ;; + esac + done < /proc/cgroups + return 0 +} + +cgroup2_base() +{ + grep -qw cgroup2 /proc/filesystems || return 0 + local base + base="$(cgroup2_find_path)" + mkdir -p "${base}" + mount -t cgroup2 none -o "${cgroup_opts},nsdelegate" "${base}" 2> /dev/null || + mount -t cgroup2 none -o "${cgroup_opts}" "${base}" + return 0 +} + +cgroup2_controllers() +{ + grep -qw cgroup2 /proc/filesystems || return 0 + local active cgroup_path x y + cgroup_path="$(cgroup2_find_path)" + [ -z "${cgroup_path}" ] && return 0 + [ -e "${cgroup_path}/cgroup.controllers" ] && + read -r active < "${cgroup_path}/cgroup.controllers" + for x in ${rc_cgroup_controllers}; do + for y in ${active}; do + [ "$x" = "$y" ] && + [ -e "${cgroup_path}/cgroup.subtree_control" ]&& + echo "+${x}" > "${cgroup_path}/cgroup.subtree_control" + done + done + return 0 +} + +cgroups_hybrid() +{ + cgroup1_base + cgroup2_base + cgroup2_controllers + cgroup1_controllers + return 0 +} + +cgroups_legacy() +{ + cgroup1_base + cgroup1_controllers + return 0 +} + +cgroups_unified() +{ + cgroup2_base + cgroup2_controllers + return 0 +} + +mount_cgroups() +{ + case "${rc_cgroup_mode:-hybrid}" in + hybrid) cgroups_hybrid ;; + legacy) cgroups_legacy ;; + unified) cgroups_unified ;; + esac + return 0 +} + +restorecon_cgroups() +{ + if [ -x /sbin/restorecon ]; then + ebegin "Restoring SELinux contexts in /sys/fs/cgroup" + restorecon -rF /sys/fs/cgroup >/dev/null 2>&1 + eend $? + fi + return 0 +} + +start() +{ + # set up kernel support for cgroups + if [ -d /sys/fs/cgroup ]; then + mount_cgroups + restorecon_cgroups + fi + return 0 +} Index: contrib/openrc/init.d/consolefont.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/consolefont.in @@ -0,0 +1,70 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Sets a font for the consoles." + +depend() +{ + need localmount termencoding + after hotplug bootmisc modules + keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu +} + +start() +{ + ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}} + consolefont=${consolefont:-${CONSOLEFONT}} + unicodemap=${unicodemap:-${UNICODEMAP}} + consoletranslation=${consoletranslation:-${CONSOLETRANSLATION}} + + if [ -z "$consolefont" ]; then + ebegin "Using the default console font" + eend 0 + return 0 + fi + + if [ "$ttyn" = 0 ]; then + ebegin "Skipping font setup (rc_tty_number == 0)" + eend 0 + return 0 + fi + + local x= param= sf_param= retval=0 ttydev=/dev/tty + + # Get additional parameters + if [ -n "$consoletranslation" ]; then + param="$param -m $consoletranslation" + fi + if [ -n "${unicodemap}" ]; then + param="$param -u $unicodemap" + fi + + # Set the console font + ebegin "Setting console font [$consolefont]" + [ -d /dev/vc ] && ttydev=/dev/vc/ + x=1 + while [ $x -le $ttyn ]; do + if ! setfont $consolefont $param -C $ttydev$x >/dev/null; then + retval=1 + break + fi + : $(( x += 1 )) + done + eend $retval + + # Store the font so we can use it ASAP on boot + if [ $retval -eq 0 ] && checkpath -W "$RC_LIBEXECDIR"; then + mkdir -p "$RC_LIBEXECDIR"/console + setfont -O "$RC_LIBEXECDIR"/console/font + fi + + return $retval +} Index: contrib/openrc/init.d/devd.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/devd.in @@ -0,0 +1,29 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/sbin/devd +command_args=$devd_args +name="Device State Change Daemon" + +depend() { + need localmount + after bootmisc + before net.lo0 + keyword -jail -prefix +} + +start_pre() { + sysctl hw.bus.devctl_disable=0 >/dev/null +} + +stop_post() { + sysctl hw.bus.devctl_disable=1 >/dev/null +} Index: contrib/openrc/init.d/devdb.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/devdb.in @@ -0,0 +1,29 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Creates the dev database" + +depend() +{ + after clock + need localmount +} + +start() +{ + ebegin "Building the dev database" + if [ /var/run/dev.db -nt /dev ]; then + : + else + dev_mkdb + fi + eend $? +} Index: contrib/openrc/init.d/devfs.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/devfs.in @@ -0,0 +1,131 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Set up the /dev directory" + +depend() +{ + provide dev-mount + before dev + keyword -docker -lxc -prefix -systemd-nspawn -vserver +} + +mount_dev() +{ + local action conf_d_dir devfstype msg mountopts + action=--mount + conf_d_dir="${RC_SERVICE%/*/*}/conf.d" + msg=Mounting + # Some devices require exec, Bug #92921 + mountopts="exec,nosuid,mode=0755" + if yesno ${skip_mount_dev:-no} ; then + einfo "/dev will not be mounted due to user request" + return 0 + fi + if mountinfo -q /dev; then + action=--remount + mountopts="remount,$mountopts" + msg=Remounting + fi + if fstabinfo -q /dev; then + ebegin "$msg /dev according to fstab" + fstabinfo -q $action /dev + eend $? + return 0 + fi + if grep -q devtmpfs /proc/filesystems; then + devfstype=devtmpfs + mountopts="$mountopts,size=10M" + elif grep -q tmpfs /proc/filesystems; then + devfstype=tmpfs + mountopts="$mountopts,size=10M" + fi + if [ -n "$devfstype" ]; then + ebegin "$msg $devfstype on /dev" + mount -n -t $devfstype -o $mountopts dev /dev + eend $? + else + ewarn "This kernel does not have devtmpfs or tmpfs support, and there" + ewarn "is no entry for /dev in fstab." + ewarn "This means /dev will not be mounted." + ewarn "To avoid this message, set CONFIG_DEVTMPFS or CONFIG_TMPFS to y" + ewarn "in your kernel configuration or see ${conf_d_dir}/${RC_SVCNAME}" + fi + return 0 +} + +seed_dev() +{ + # Seed /dev with some things that we know we need + + # creating /dev/console, /dev/tty and /dev/tty1 to be able to write + # to $CONSOLE with/without bootsplash before udevd creates it + [ -c /dev/console ] || mknod -m 600 /dev/console c 5 1 + [ -c /dev/tty1 ] || mknod -m 620 /dev/tty1 c 4 1 + [ -c /dev/tty ] || mknod -m 666 /dev/tty c 5 0 + + # udevd will dup its stdin/stdout/stderr to /dev/null + # and we do not want a file which gets buffered in ram + [ -c /dev/null ] || mknod -m 666 /dev/null c 1 3 + + # so udev can add its start-message to dmesg + [ -c /dev/kmsg ] || mknod -m 660 /dev/kmsg c 1 11 + + # extra symbolic links not provided by default + [ -e /dev/fd ] || ln -snf /proc/self/fd /dev/fd + [ -e /dev/stdin ] || ln -snf /proc/self/fd/0 /dev/stdin + [ -e /dev/stdout ] || ln -snf /proc/self/fd/1 /dev/stdout + [ -e /dev/stderr ] || ln -snf /proc/self/fd/2 /dev/stderr + [ -e /proc/kcore ] && ln -snf /proc/kcore /dev/core + + # Mount required directories as user may not have them in /etc/fstab + for x in \ + "mqueue /dev/mqueue 1777 ,nodev mqueue" \ + "devpts /dev/pts 0755 ,gid=5,mode=0620 devpts" \ + "tmpfs /dev/shm 1777 ,nodev,mode=1777 shm" \ + ; do + set -- $x + grep -Eq "[[:space:]]+$1$" /proc/filesystems || continue + mountinfo -q $2 && continue + + if [ ! -d $2 ]; then + mkdir -m $3 -p $2 >/dev/null 2>&1 || \ + ewarn "Could not create $2!" + fi + + if [ -d $2 ]; then + ebegin "Mounting $2" + if ! fstabinfo --mount $2; then + mount -n -t $1 -o noexec,nosuid$4 $5 $2 + fi + eend $? + fi + done +} + +restorecon_dev() +{ + if [ -x /sbin/restorecon ]; then + ebegin "Restoring SELinux contexts in /dev" + restorecon -rF /dev >/dev/null 2>&1 + eend $? + fi + + return 0 +} + +start() +{ + mount_dev + seed_dev + restorecon_dev + return 0 +} Index: contrib/openrc/init.d/dmesg.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/dmesg.in @@ -0,0 +1,25 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Set the dmesg level for a cleaner boot" + +depend() +{ + before dev modules + keyword -docker -lxc -prefix -systemd-nspawn -vserver +} + +start() +{ + if [ -n "$dmesg_level" ]; then + dmesg -n$dmesg_level + fi +} Index: contrib/openrc/init.d/dumpon.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/dumpon.in @@ -0,0 +1,33 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Configures a specific kernel dump device." + +depend() { + after clock + need swap + keyword -jail -prefix +} + +start() { + # Setup any user requested dump device + if [ -n "$dump_device" ]; then + ebegin "Activating kernel core dump device ($dump_device)" + dumpon ${dump_device} + eend $? + fi +} + +stop() { + ebegin "Deactivating kernel core dump device" + dumpon off + eend $? +} Index: contrib/openrc/init.d/encswap.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/encswap.in @@ -0,0 +1,43 @@ +#!@SBINDIR@/openrc-run +# Copyright 1992-2012 FreeBSD Project +# Released under the 2-clause BSD license + +depend() { + before swap +} + +start() { + while read device mountpoint type options rest ; do + case ":${device}:${type}:${options}" in + :#*) + ;; + *.bde:swap:sw) + passphrase=$(dd if=/dev/random count=1 2>/dev/null | md5 -q) + device="${device%.bde}" + gbde init "${device}" -P "${passphrase}" || return 1 + gbde attach "${device}" -p "${passphrase}" || return 1 + ;; + *.eli:swap:sw) + device="${device%.eli}" + geli onetime ${geli_swap_flags} "${device}" || return 1 + ;; + esac + done < /etc/fstab +} + +stop() { + while read device mountpoint type options rest ; do + case ":${device}:${type}:${options}" in + :#*) + ;; + *.bde:swap:sw) + device="${device%.bde}" + gbde detach "${device}" + ;; + *.eli:swap:sw) + # Nothing here, because geli swap devices should be + # created with the auto-detach-on-last-close option. + ;; + esac + done < /etc/fstab +} Index: contrib/openrc/init.d/fsck.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/fsck.in @@ -0,0 +1,131 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Check and repair filesystems according to /etc/fstab" +_IFS=" +" + +depend() +{ + after clock + use dev clock modules + keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -timeout -vserver -uml +} + +_abort() { + yesno ${fsck_abort_on_errors:-yes} && rc-abort + return 1 +} + +# We should only reboot when first booting +_reboot() { + if [ "$RC_RUNLEVEL" = "$RC_BOOTLEVEL" ]; then + reboot "$@" + _abort || return 1 + fi +} + +_forcefsck() +{ + [ -e /forcefsck ] || get_bootparam forcefsck +} + +start() +{ + local fsck_opts= p= check_extra= + + if [ -e /fastboot ]; then + ewarn "Skipping fsck due to /fastboot" + return 0 + fi + if _forcefsck; then + fsck_opts="$fsck_opts -f" + check_extra="(check forced)" + elif ! yesno ${fsck_on_battery:-YES} && ! on_ac_power; then + ewarn "Skipping fsck due to not being on AC power" + return 0 + fi + + if [ -n "$fsck_passno" ]; then + check_extra="[passno $fsck_passno] $check_extra" + if [ -n "$fsck_mnt" ]; then + eerror "Only 1 of fsck_passno and fsck_mnt must be set!" + return 1 + fi + fi + ebegin "Checking local filesystems $check_extra" + # Append passno mounts + for p in $fsck_passno; do + local IFS="$_IFS" + case "$p" in + [0-9]*) p="=$p";; + esac + set -- "$@" $(fstabinfo --passno "$p") + unset IFS + done + # Append custom mounts + for m in $fsck_mnt ; do + local IFS="$_IFS" + set -- "$@" "$m" + unset IFS + done + + if [ "$RC_UNAME" = Linux ]; then + local skiptypes + skiptypes=$(printf 'no%s,' ${net_fs_list} ${extra_net_fs_list}) + [ "${skiptypes}" = "no," ] && skiptypes="" + fsck_opts="$fsck_opts -C0 -T -t ${skiptypes}noopts=_netdev" + if [ -z "$fsck_passno" -a -z "$fsck_mnt" ]; then + fsck_args=${fsck_args:--A -p} + if echo 2>/dev/null >/.test.$$; then + rm -f /.test.$$ + fsck_opts="$fsck_opts -R" + fi + fi + fi + + trap : INT QUIT + fsck ${fsck_args:--p} $fsck_opts "$@" + case $? in + 0) eend 0; return 0;; + 1) ewend 1 "Filesystems repaired"; return 0;; + 2|3) if [ "$RC_UNAME" = Linux ]; then + ewend 1 "Filesystems repaired, but reboot needed" + _reboot -f + else + ewend 1 "Filesystems still have errors;" \ + "manual fsck required" + _abort + fi;; + 4) if [ "$RC_UNAME" = Linux ]; then + ewend 1 "Fileystem errors left uncorrected, aborting" + _abort + else + ewend 1 "Filesystems repaired, but reboot needed" + _reboot + fi;; + 8) ewend 1 "Operational error"; return 0;; + 12) ewend 1 "fsck interrupted";; + *) eend 2 "Filesystems couldn't be fixed";; + esac + _abort || return 1 +} + +stop() +{ + # Fake function so we always shutdown correctly. + _abort() { return 0; } + _reboot() { return 0; } + _forcefsck() { return 1; } + + yesno $fsck_shutdown && start + return 0 +} Index: contrib/openrc/init.d/hostid.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/hostid.in @@ -0,0 +1,88 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +extra_commands="reset" +: ${hostid_file:=/etc/hostid} + +depend() +{ + use root + after clock + before devd net + keyword -jail -prefix +} + +_set() +{ + local id=0 + + if [ -n "$1" ]; then + id=$(echo "$1" | md5) + id="0x${id%????????????????????????}" + fi + ebegin "Setting Host ID: $id" + sysctl -w kern.hostid="$id" >/dev/null + eend $? || return 1 + + if sysctl -n kern.hostuuid >/dev/null 2>&1; then + [ -n "$1" ] && id=$1 + ebegin "Setting Host UUID: $id" + sysctl kern.hostuuid="$id" >/dev/null + eend $? || return 1 + fi + +} + +# First we check to see if there is a system UUID +# If so then we use that and erase the hostid file, +# otherwise we generate a random UUID. +reset() +{ + local uuid= x="[0-9a-f]" y="$x$x$x$x" + + if command -v kenv >/dev/null 2>&1; then + uuid=$(kenv smbios.system.uuid 2>/dev/null) + fi + case "$uuid" in + $y$y-$y-$y-$y-$y$y$y);; + *) uuid=;; + esac + + if [ -n "$uuid" ]; then + rm -f "$hostid_file" + else + uuid=$(uuidgen) + if [ -z "$uuid" ]; then + eerror "Unable to generate a UUID" + return 1 + fi + if ! echo "$uuid" >"$hostid_file"; then + eerror "Failed to store UUID in \`$hostid_file'" + return 1 + fi + fi + + _set "$uuid" +} + +start() +{ + if [ -r "$hostid_file" ]; then + _set $(cat "$hostid_file") + else + reset + fi +} + +stop() +{ + _set +} Index: contrib/openrc/init.d/hostname.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/hostname.in @@ -0,0 +1,38 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Sets the hostname of the machine." + +depend() +{ + after clock + keyword -docker -lxc -prefix -systemd-nspawn +} + +start() +{ + local h source x + if [ -s /etc/hostname ] && [ -r /etc/hostname ]; then + read h x &1 >/dev/null)" + + [ -z "$err" ] && return 0 + echo "${err}" >&2 + return 1 +} + +get_noadjfile() +{ + if ! yesno $clock_adjfile; then + # Some implementations don't handle adjustments + if LC_ALL=C hwclock --help 2>&1 | grep -q "\-\-noadjfile"; then + echo --noadjfile + fi + fi +} + +rtc_exists() +{ + local rtc= + for rtc in /dev/rtc /dev/rtc[0-9]*; do + [ -e "$rtc" ] && break + done + [ -e "$rtc" ] +} + +start() +{ + local retval=0 errstr="" modname + setupopts + + if [ -z "$utc_cmd" ]; then + ewarn "Not setting clock for $utc system" + return 0 + fi + + ebegin "Setting system clock using the hardware clock [$utc]" + if [ -e /proc/modules ]; then + if ! rtc_exists; then + for x in rtc-cmos rtc genrtc; do + modprobe -q $x && rtc_exists && modname="$x" && break + done + [ -n "$modname" ] && + ewarn "The $modname module needs to be configured in" \ + "${RC_SERVICE%/*/*}/conf.d/modules or built in." + fi + fi + + # Always set the kernel's time zone. + _hwclock --systz $utc_cmd $(get_noadjfile) $clock_args + : $(( retval += $? )) + + if [ -e /etc/adjtime ] && yesno $clock_adjfile; then + _hwclock --adjust $utc_cmd $(get_noadjfile) + : $(( retval += $? )) + fi + + if yesno ${clock_hctosys:-YES}; then + _hwclock --hctosys $utc_cmd $(get_noadjfile) $clock_args + : $(( retval += $? )) + fi + + eend $retval "Failed to set the system clock" + + return 0 +} + +stop() +{ + # Don't tweak the hardware clock on LiveCD halt. + [ -n "$CDBOOT" ] && return 0 + yesno ${clock_systohc:-YES} || return 0 + + local retval=0 errstr="" + setupopts + + [ -z "$utc_cmd" ] && return 0 + + ebegin "Setting hardware clock using the system clock" "[$utc]" + + _hwclock --systohc $utc_cmd $(get_noadjfile) $clock_args + retval=$? + + eend $retval "Failed to sync clocks" +} + +save() +{ + clock_systohc=yes + stop +} + +show() +{ + setupopts + hwclock --show "$utc_cmd" $(get_noadjfile) $clock_args +} Index: contrib/openrc/init.d/ipfw.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/ipfw.in @@ -0,0 +1,166 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# This is based on /etc/rc.firewall and /etc/rc.firewall6 from FreeBSD + +ipfw_ip_in=${ipfw_ip_in-any} +ipfw_ports_in=${ipfw_ports_in-auth ssh} +ipfw_ports_nolog=${ipfw_ports_nolog-135-139,445 1026,1027 1433,1434} + +extra_commands="panic showstatus" + +depend() { + before net + provide firewall + keyword -jail +} + +ipfw() { + /sbin/ipfw -f -q "$@" +} + +have_ip6() { + sysctl net.ipv6 2>/dev/null +} + +init() { + # Load the kernel module + if ! sysctl net.inet.ip.fw.enable=1 >/dev/null 2>&1; then + if ! kldload ipfw; then + eend 1 "Unable to load firewall module" + return 1 + fi + fi + + # Now all rules and give a good base + ipfw flush + + ipfw add pass all from any to any via lo0 + ipfw add deny all from any to 127.0.0.0/8 + ipfw add deny ip from 127.0.0.0/8 to any + + if have_ip6; then + ipfw add pass ip6 from any to any via lo0 + ipfw add deny ip6 from any to ::1 + ipfw add deny ip6 from ::1 to any + + ipfw add pass ip6 from :: to ff02::/16 proto ipv6-icmp + ipfw add pass ip6 from fe80::/10 to fe80::/10 proto ipv6-icmp + ipfw add pass ip6 from fe80::/10 to ff02::/16 proto ipv6-icmp + fi +} + +start() { + local i= p= log= + ebegin "Starting firewall rules" + if ! init; then + eend 1 "Failed to flush firewall ruleset" + return 1 + fi + + # Use a stateful firewall + ipfw add check-state + ipfw add pass tcp from me to any established + + # Allow any connection out, adding state for each. + ipfw add pass tcp from me to any setup keep-state + ipfw add pass udp from me to any keep-state + ipfw add pass icmp from me to any keep-state + + if have_ip6; then + ipfw add pass tcp from me6 to any setup keep-state + ipfw add pass udp from me6 to any keep-state + ipfw add pass icmp from me6 to any keep-state + fi + + # Allow DHCP. + ipfw add pass udp from 0.0.0.0 68 to 255.255.255.255 67 out + ipfw add pass udp from any 67 to me 68 in + ipfw add pass udp from any 67 to 255.255.255.255 68 in + # Some servers will ping the IP while trying to decide if it's + # still in use. + ipfw add pass icmp from any to any icmptype 8 + + # Allow "mandatory" ICMP in. + ipfw add pass icmp from any to any icmptype 3,4,11 + + if have_ip6; then + # Allow ICMPv6 destination unreach + ipfw add pass ip6 from any to any icmp6types 1 proto ipv6-icmp + + # Allow NS/NA/toobig (don't filter it out) + ipfw add pass ip6 from any to any icmp6types 2,135,136 proto ipv6-icmp + fi + + # Add permits for this workstations published services below + # Only IPs and nets in firewall_allowservices is allowed in. + for i in $ipfw_ip_in; do + for p in $ipfw_ports_in; do + ipfw add pass tcp from $i to me $p + done + done + + # Allow all connections from trusted IPs. + # Playing with the content of firewall_trusted could seriously + # degrade the level of protection provided by the firewall. + for i in $ipfw_ip_trust; do + ipfw add pass ip from $i to me + done + + ipfw add 65000 count ip from any to any + + # Drop packets to ports where we don't want logging + for p in $ipfw_ports_nolog; do + ipfw add deny { tcp or udp } from any to any $p in + done + + # Broadcasts and muticasts + ipfw add deny ip from any to 255.255.255.255 + ipfw add deny ip from any to 224.0.0.0/24 + + # Noise from routers + ipfw add deny udp from any to any 520 in + + # Noise from webbrowsing. + # The stateful filter is a bit aggressive, and will cause some + # connection teardowns to be logged. + ipfw add deny tcp from any 80,443 to any 1024-65535 in + + # Deny and (if wanted) log the rest unconditionally. + if yesno ${ipfw_log_deny:-no}; then + log=log + sysctl net.inet.ip.fw.verbose=1 >/dev/null + fi + ipfw add deny $log ip from any to any + + eend 0 +} + +stop() { + ebegin "Stopping firewall rules" + # We don't unload the kernel module as that action + # can cause memory leaks as of FreeBSD 6.x + sysctl net.inet.ip.fw.enable=0 >/dev/null + eend $? +} + +panic() { + ebegin "Stopping firewall rules - hard" + if ! init; then + eend 1 "Failed to flush firewall ruleset" + return 1 + fi + eend 0 +} + +showstatus() { + ipfw show +} Index: contrib/openrc/init.d/keymaps.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/keymaps.in @@ -0,0 +1,77 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Applies a keymap for the consoles." + +depend() +{ + need localmount termencoding + after bootmisc clock + keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu +} + +start() +{ + ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}} + : ${unicode:=$UNICODE} + : ${keymap:=$KEYMAP} + : ${extended_keymaps:=$EXTENDED_KEYMAPS} + : ${windowkeys:=$SET_WINDOWSKEYS} + : ${fix_euro:=$FIX_EURO} + : ${dumpkeys_charset:=${DUMPKEYS_CHARSET}} + + if [ -z "$keymap" ]; then + eerror "You need to setup keymap in /etc/conf.d/keymaps first" + return 1 + fi + + local ttydev=/dev/tty n= + [ -d /dev/vc ] && ttydev=/dev/vc/ + + # Force linux keycodes for PPC. + if [ -f /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes ]; then + echo 1 > /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes + fi + + local wkeys= kmode="-a" msg="ASCII" + if yesno $unicode; then + kmode="-u" + msg="UTF-8" + fi + yesno $windowkeys && wkeys="windowkeys" + + # Set terminal encoding to either ASCII or UNICODE. + # See utf-8(7) for more information. + ebegin "Setting keyboard mode [$msg]" + n=1 + while [ $n -le $ttyn ]; do + kbd_mode $kmode -C $ttydev$n + : $(( n += 1 )) + done + eend 0 + + ebegin "Loading key mappings [$keymap]" + loadkeys -q $wkeys $keymap $extended_keymaps + eend $? "Error loading key mappings" || return $? + + if yesno $fix_euro; then + ebegin "Fixing font for euro symbol" + # Fix some fonts displaying the Euro, #173528. + echo "altgr keycode 18 = U+20AC" | loadkeys -q - + eend $? + fi + + # Save the keymapping for use immediately at boot + if checkpath -W "$RC_LIBEXECDIR"; then + mkdir -p "$RC_LIBEXECDIR"/console + dumpkeys >"$RC_LIBEXECDIR"/console/keymap + fi +} Index: contrib/openrc/init.d/killprocs.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/killprocs.in @@ -0,0 +1,27 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Kill all processes so we can unmount disks cleanly." + +depend() +{ + keyword -prefix +} + +start() +{ + ebegin "Terminating remaining processes" + kill_all 15 ${killall5_opts} + eend 0 + ebegin "Killing remaining processes" + kill_all 9 ${killall5_opts} + eend 0 +} Index: contrib/openrc/init.d/local.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/local.in @@ -0,0 +1,96 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +conf_d_dir="${RC_SERVICE%/*/*}/conf.d" +local_d_dir="${RC_SERVICE%/*/*}/local.d" + +description="Executes user programs in ${local_d_dir}" + +depend() +{ + after * + keyword -timeout +} + +start() +{ + local file has_errors redirect retval + has_errors=0 + yesno $rc_verbose || redirect='> /dev/null 2>&1' + ebegin "Starting local" + eindent + for file in "${local_d_dir}"/*.start; do + if [ -x "${file}" ]; then + vebegin "Executing \"${file}\"" + eval "${file}" $redirect + retval=$? + if [ ${retval} -ne 0 ]; then + has_errors=1 + fi + veend ${retval} "Execution of \"${file}\" failed." + fi + done + eoutdent + + if command -v local_start >/dev/null 2>&1; then + ewarn "\"${conf_d_dir}/local\" should be removed." + ewarn "Please move the code from the local_start function" + ewarn "to executable scripts with an .start extension" + ewarn "in \"${local_d_dir}\"" + local_start + fi + + eend ${has_errors} + + # We have to end with a zero exit code, because a failed execution + # of an executable ${local_d_dir}/*.start file shouldn't result in + # marking the local service as failed. Otherwise we are unable to + # execute any executable ${local_d_dir}/*.stop file, because a failed + # marked service cannot be stopped (and the stop function would + # actually call the executable ${local_d_dir}/*.stop file(s)). + return 0 +} + +stop() +{ + local file has_errors redirect retval + has_errors=0 + yesno $rc_verbose || redirect='> /dev/null 2>&1' + ebegin "Stopping local" + eindent + for file in "${local_d_dir}"/*.stop; do + if [ -x "${file}" ]; then + vebegin "Executing \"${file}\"" + eval "${file}" $redirect + retval=$? + if [ ${retval} -ne 0 ]; then + has_errors=1 + fi + veend ${retval} "Execution of \"${file}\" failed." + fi + done + eoutdent + + if command -v local_stop >/dev/null 2>&1; then + ewarn "\"${conf_d_dir}/local\" should be removed." + ewarn "Please move the code from the local_stop function" + ewarn "to executable scripts with an .stop extension" + ewarn "in \"${local_d_dir}\"" + local_stop + fi + + eend ${has_errors} + + # An executable ${local_d_dir}/*.stop file which failed with a + # non-zero exit status is not a reason to mark this service + # as failed, therefore we have to end with a zero exit code. + return 0 +} Index: contrib/openrc/init.d/localmount.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/localmount.in @@ -0,0 +1,133 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mounts disks and swap according to /etc/fstab." + +depend() +{ + need fsck + use lvm modules root + after clock lvm modules root + keyword -docker -jail -lxc -prefix -systemd-nspawn -vserver +} + +start() +{ + # Mount local filesystems in /etc/fstab. + # The types variable must start with no, and must be a type + local critical= types="noproc" x= no_netdev= rc= + for x in $net_fs_list $extra_net_fs_list; do + types="${types},${x}" + done + + if [ "$RC_UNAME" = Linux ]; then + no_netdev="-O no_netdev" + if mountinfo -q /usr; then + touch "$RC_SVCDIR"/usr_premounted + fi + fi + ebegin "Mounting local filesystems" + mount -at "$types" $no_netdev + eend $? "Some local filesystem failed to mount" + rc=$? + if [ -z "$critical_mounts" ]; then + rc=0 + else + for x in ${critical_mounts}; do + fstabinfo -q $x || continue + if ! mountinfo -q $x; then + critical=x + eerror "Failed to mount $x" + fi + done + [ -z "$critical" ] && rc=0 + fi + return $rc +} + +stop() +{ + yesno $RC_GOINGDOWN || return 0 + # We never unmount / or /dev or $RC_SVCDIR + + # Bug 381783 + local rc_svcdir=$(printf '%s\n' "$RC_SVCDIR" | sed 's:/lib\(32\|64\)\?/:/lib(32|64)?/:g') + + local x= no_umounts_r="/|/dev|/dev/.*|${rc_svcdir}" + no_umounts_r="${no_umounts_r}|/bin|/sbin|/lib(32|64)?|/libexec" + # RC_NO_UMOUNTS is an env var that can be set by plugins + local IFS="$IFS:" + for x in $no_umounts $RC_NO_UMOUNTS; do + no_umounts_r="$no_umounts_r|$x" + done + + if [ "$RC_UNAME" = Linux ]; then + no_umounts_r="$no_umounts_r|/proc|/proc/.*|/run|/sys|/sys/.*" + if [ -e "$rc_svcdir"/usr_premounted ]; then + no_umounts_r="$no_umounts_r|/usr" + fi + fi + no_umounts_r="^($no_umounts_r)$" + + # Flush all pending disk writes now + sync + + . "$RC_LIBEXECDIR"/sh/rc-mount.sh + + if [ "$RC_UNAME" = Linux ] && [ -d /sys/fs/aufs ] ; then + #if / is aufs we remount it noxino during shutdown + if mountinfo -q -f '^aufs$' / ; then + mount -o remount,noxino,rw / + sync + fi + + local aufs_branch aufs_mount_point aufs_si_id aufs_br_id branches + for aufs_si_dir in /sys/fs/aufs/si*; do + [ -d "${aufs_si_dir}" ] || continue + aufs_si_id="si=${aufs_si_dir#/sys/fs/aufs/si_}" + aufs_mount_point="$(mountinfo -o ${aufs_si_id})" + branches="$aufs_si_dir/br[0-9] $aufs_si_dir/br[0-9][0-9] $aufs_si_dir/br[0-9][0-9][0-9]" + for x in $branches; do + [ -e "${x}" ] || continue + aufs_branch=$(sed 's/=.*//g' $x) + eindent + if ! mount -o "remount,del:$aufs_branch" "$aufs_mount_point" > /dev/null 2>&1; then + ewarn "Failed to remove branch $aufs_branch from aufs" \ + "$aufs_mount_point" + fi + eoutdent + sync + done + done + fi + + # Umount loop devices + einfo "Unmounting loop devices" + eindent + do_unmount "umount -d" --skip-point-regex "$no_umounts_r" \ + --node-regex "^/dev/loop" + eoutdent + + # Now everything else, except network filesystems as the + # network should be down by this point. + einfo "Unmounting filesystems" + eindent + local fs= + for x in $net_fs_list $extra_net_fs_list; do + fs="$fs${fs:+|}$x" + done + [ -n "$fs" ] && fs="^($fs)$" + do_unmount umount --skip-point-regex "$no_umounts_r" \ + "${fs:+--skip-fstype-regex}" $fs --nonetdev + eoutdent + + return 0 +} Index: contrib/openrc/init.d/loopback.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/loopback.in @@ -0,0 +1,35 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2013-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Configures the loopback interface." + +depend() +{ + after clock + keyword -jail -prefix -systemd-nspawn -vserver +} + +start() +{ + if [ "$RC_UNAME" = Linux ]; then + ebegin "Bringing up network interface lo" + if command -v ip > /dev/null 2>&1; then + ip addr add 127.0.0.1/8 dev lo brd + + ip link set lo up + else + ifconfig lo 127.0.0.1 netmask 255.0.0.0 + fi + else + ebegin "Bringing up network interface lo0" + ifconfig lo0 127.0.0.1 netmask 255.0.0.0 + fi + eend $? +} Index: contrib/openrc/init.d/mixer.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/mixer.in @@ -0,0 +1,54 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +extra_commands="restore" + +depend() +{ + need localmount + keyword -jail -prefix +} + +restore() +{ + local mixer= retval=0 + ebegin "Restoring mixer settings" + eindent + for mixer in /dev/mixer*; do + if [ -r "/var/db/${mixer#/dev/}-state" ]; then + vebegin "$mixer" + mixer -f "$mixer" \ + $(cat "/var/db/${mixer#/dev/}-state") >/dev/null + veend $? + : $(( retval += $? )) + fi + done +} + +start() +{ + restore +} + +stop() +{ + local mixer= retval=0 + ebegin "Saving mixer settings" + eindent + for mixer in /dev/mixer*; do + vebegin "$mixer" + mixer -f "$mixer" -s >/var/db/"${mixer#/dev/}"-state + veend $? + : $(( retval += $? )) + done + eoutdent + eend $retval +} Index: contrib/openrc/init.d/modules-load.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/modules-load.in @@ -0,0 +1,72 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2016 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Loads a list of modules from systemd-compatible locations." + +depend() +{ + keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver +} + +find_modfiles() +{ + local dirs="/usr/lib/modules-load.d /run/modules-load.d /etc/modules-load.d" + local basenames files fn x y + for x in $dirs; do + [ ! -d $x ] && continue + for y in $x/*.conf; do + [ -f $y ] && basenames="${basenames}\n${y##*/}" + done + done + basenames=$(printf "$basenames" | sort -u) + for x in $basenames; do + for y in $dirs; do + [ -r $y/$x ] && + fn=$y/$x + done + files="$files $fn" + done + echo $files +} + +load_modules() +{ + local file m modules rc x + file=$1 + [ -z "$file" ] && return 0 + while read m x; do + case $m in + \;*) continue ;; + \#*) continue ;; + *) modules="$modules $m" + ;; + esac + done < $file + for x in $modules; do + ebegin "Loading module $x" + case "$RC_UNAME" in + FreeBSD) kldload "$x"; rc=$? ;; + Linux) modprobe --use-blacklist -q "$x"; rc=$? ;; + *) ;; + esac + eend $rc "Failed to load $x" + done +} + +start() +{ + local x + files=$(find_modfiles) + for x in $files; do + load_modules $x + done + return 0 +} Index: contrib/openrc/init.d/modules.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/modules.in @@ -0,0 +1,89 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Loads a user defined list of kernel modules." + +depend() +{ + use isapnp + want modules-load + keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver +} + +FreeBSD_modules() +{ + local cnt=0 x + for x in $modules; do + ebegin "Loading module $x" + kldload "$x" + eend $? "Failed to load $x" && : $(( cnt += 1 )) + done + einfo "Autoloaded $cnt module(s)" +} + +Linux_modules() +{ + # Should not fail if kernel does not have module + # support compiled in ... + [ ! -f /proc/modules ] && return 0 + + local KV x y kv_variant_list + KV=$(uname -r) + # full $KV + kv_variant_list="${KV}" + # remove any KV_EXTRA options to just get the full version + x=${KV%%-*} + # now slowly strip them + while [ -n "$x" ] && [ "$x" != "$y" ]; do + kv_variant_list="${kv_variant_list} $x" + y=$x + x=${x%.*} + done + + local list= x= xx= y= args= mpargs= a= + for x in $kv_variant_list ; do + eval list=\$modules_$(shell_var "$x") + [ -n "$list" ] && break + done + [ -z "$list" ] && list=$modules + + [ -n "$list" ] && ebegin "Loading kernel modules" + for x in $list; do + a=${x#*:} + if [ "$a" = "$x" ]; then + unset mpargs + else + x=${x%%:*} + mpargs="-o $a" + fi + aa=$(shell_var "$a") + xx=$(shell_var "$x") + for y in $kv_variant_list ; do + eval args=\$module_${aa}_args_$(shell_var "$y") + [ -n "${args}" ] && break + eval args=\$module_${xx}_args_$(shell_var "$y") + [ -n "${args}" ] && break + done + [ -z "$args" ] && eval args=\$module_${aa}_args + [ -z "$args" ] && eval args=\$module_${xx}_args + eval modprobe --use-blacklist --verbose "$mpargs" "$x" "$args" + done + [ -n "$list" ] && eend +} + +start() +{ + case "$RC_UNAME" in + FreeBSD|Linux) ${RC_UNAME}_modules ;; + *) ;; + esac + return 0 +} Index: contrib/openrc/init.d/mount-ro.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/mount-ro.in @@ -0,0 +1,59 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Re-mount filesytems read-only for a clean reboot." + +depend() +{ + after killprocs savecache + keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver +} + +start() +{ + local ret=0 + + # Flush all pending disk writes now + sync + + ebegin "Remounting remaining filesystems read-only" + # We need the do_unmount function + . "$RC_LIBEXECDIR"/sh/rc-mount.sh + eindent + + # Bug 381783 + local rc_svcdir=$(echo $RC_SVCDIR | sed 's:/lib\(32\|64\)\?/:/lib(32|64)?/:g') + + local m="/dev|/dev/.*|/proc|/proc.*|/sys|/sys/.*|/run|${rc_svcdir}" x= fs= + m="$m|/bin|/sbin|/lib(32|64)?|/libexec" + if [ -e "$rc_svcdir"/usr_premounted ]; then + m="$m|/usr" + fi + # RC_NO_UMOUNTS is an env var that can be set by plugins + local IFS="$IFS:" + for x in $no_umounts $RC_NO_UMOUNTS; do + m="$m|$x" + done + m="^($m)$" + fs= + for x in $net_fs_list $extra_net_fs_list; do + fs="$fs${fs:+|}$x" + done + [ -n "$fs" ] && fs="^($fs)$" + do_unmount "umount -r" \ + --skip-point-regex "$m" \ + "${fs:+--skip-fstype-regex}" $fs --nonetdev + ret=$? + + eoutdent + + eend $ret +} Index: contrib/openrc/init.d/moused.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/moused.in @@ -0,0 +1,69 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +mouse=${RC_SVCNAME##*.} +if [ -n "$mouse" -a "$mouse" != "moused" ]; then + moused_device=/dev/"$mouse" + pidfile=/var/run/moused-"$mouse".pid +else + pidfile=/var/run/moused.pid +fi +name="Console Mouse Daemon" +[ -n "$moused_device" ] && name="$name ($moused_device)" + +depend() +{ + need localmount + after bootmisc + keyword -jail -prefix +} + +start() +{ + ebegin "Starting $name" + + if [ -z "$moused_device" ]; then + local dev= + for dev in /dev/psm[0-9]* /dev/ums[0-9]*; do + [ -c "$dev" ] || continue + [ -e /var/run/moused-"${dev##*/}".pid ] && continue + moused_device=$dev + eindent + einfo "Using mouse on $moused_device" + eoutdent + break + done + fi + + if [ -z "$moused_device" ]; then + eend 1 "No mouse device found" + return 1 + fi + + local args= + eval args=\$moused_args_${moused_device##*/} + [ -z "$args" ] && args=$moused_args + + start-stop-daemon --start --exec /usr/sbin/moused \ + --pidfile "$pidfile" \ + -- $args -p "$moused_device" -I "$pidfile" + local retval=$? + + if [ $retval = 0 ]; then + local ttyv= + for ttyv in /dev/ttyv*; do + vidcontrol < "$ttyv" -m on + : $(( retval += $? )) + done + fi + + eend $retval "Failed to start moused" +} Index: contrib/openrc/init.d/mtab.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/mtab.in @@ -0,0 +1,52 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Update /etc/mtab to match what the kernel knows about" + +depend() +{ + after clock + before localmount + need root + keyword -prefix -systemd-nspawn +} + +start() +{ + local rc=0 + ebegin "Updating /etc/mtab" + if ! checkpath -W /etc; then + rc=1 + elif ! yesno ${mtab_is_file:-no}; then + [ ! -L /etc/mtab ] && [ -f /etc/mtab ] && + ewarn "Removing /etc/mtab file" + einfo "Creating mtab symbolic link" + ln -snf /proc/self/mounts /etc/mtab + else + ewarn "The ${RC_SVCNAME} service will be removed in the future." + ewarn "Please change the mtab_is_file setting to no and run" + ewarn "# rc-service mtab restart" + ewarn "to create the mtab symbolic link." + [ -L /etc/mtab ] && ewarn "Removing /etc/mtab symbolic link" + rm -f /etc/mtab + einfo "Creating mtab file" + # With / as tmpfs we cannot umount -at tmpfs in localmount as that + # makes / readonly and dismounts all tmpfs even if in use which is + # not good. Luckily, umount uses /etc/mtab instead of /proc/mounts + # which allows this hack to work. + grep -v "^[! ]* / tmpfs " /proc/mounts > /etc/mtab + + # Remove stale backups + rm -f /etc/mtab~ /etc/mtab~~ + fi + eend $rc "/etc is not writable; unable to create /etc/mtab" + return 0 +} Index: contrib/openrc/init.d/net-online.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/net-online.in @@ -0,0 +1,76 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Delays until the network is online or a specific timeout" + +depend() +{ + after modules + need sysfs + provide network-online + keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -uml -vserver +} + +get_interfaces() +{ + local ifname iftype + for ifname in /sys/class/net/*; do + [ -h "${ifname}" ] && continue + read iftype < ${ifname}/type + [ "$iftype" = "1" ] && printf "%s " ${ifname##*/} + done +} + +start () +{ + local carriers configured dev gateway ifcount infinite + local carrier operstate rc + + ebegin "Checking to see if the network is online" + rc=0 + interfaces=${interfaces:-$(get_interfaces)} + timeout=${timeout:-120} + [ $timeout -eq 0 ] && infinite=true || infinite=false + while $infinite || [ $timeout -gt 0 ]; do + carriers=0 + configured=0 + ifcount=0 + for dev in ${interfaces}; do + : $((ifcount += 1)) + read carrier < /sys/class/net/$dev/carrier 2> /dev/null || + carrier= + [ "$carrier" = 1 ] && : $((carriers += 1)) + read operstate < /sys/class/net/$dev/operstate 2> /dev/null || + operstate= + [ "$operstate" = up ] && : $((configured += 1)) + done + [ $configured -eq $ifcount ] && [ $carriers -ge 1 ] && break + sleep 1 + : $((timeout -= 1)) + done + ! $infinite && [ $timeout -eq 0 ] && rc=1 + include_ping_test=${include_ping_test:-${ping_default_gateway}} + if [ -n "${ping_default_gateway}" ]; then + ewarn "ping_default_gateway is deprecated, please use include_ping_test" + fi + if [ $rc -eq 0 ] && yesno ${include_ping_test:-no}; then + ping_test_host="${ping_test_host:-google.com}" + if [ -n "$ping_test_host" ]; then + while $infinite || [ $timeout -gt 0 ]; do + ping -c 1 $ping_test_host > /dev/null 2>&1 + rc=$? + [ $rc -eq 0 ] && break + : $((timeout -= 1)) + done + fi + fi + eend $rc "The network is offline" +} Index: contrib/openrc/init.d/netmount.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/netmount.in @@ -0,0 +1,91 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mounts network shares according to /etc/fstab." + +depend() +{ + local opts mywant="" + for opts in $(fstabinfo -o -t nfs,nfs4); do + case $opts in + noauto) ;; + *) mywant="$mywant nfsclient"; break ;; + esac + done + after root + config /etc/fstab + want $mywant + use afc-client amd openvpn + use dns + use root + keyword -docker -jail -lxc -prefix -systemd-nspawn -vserver +} + +start() +{ + local x= fs= rc= + for x in $net_fs_list $extra_net_fs_list; do + fs="$fs${fs:+,}$x" + done + + ebegin "Mounting network filesystems" + mount -at $fs + rc=$? + if [ "$RC_UNAME" = Linux ] && [ $rc = 0 ]; then + mount -a -O _netdev + rc=$? + fi + ewend $rc "Could not mount all network filesystems" + if [ -z "$critical_mounts" ]; then + rc=0 + else + for x in ${critical_mounts}; do + fstabinfo -q $x || continue + if ! mountinfo -q $x; then + critical=x + eerror "Failed to mount $x" + fi + done + [ -z "$critical" ] && rc=0 + fi + return $rc +} + +stop() +{ + local x= fs= + + ebegin "Unmounting network filesystems" + . "$RC_LIBEXECDIR"/sh/rc-mount.sh + + for x in $net_fs_list $extra_net_fs_list; do + fs="$fs${fs:+,}$x" + done + if [ -n "$fs" ]; then + umount -at $fs || eerror "Failed to simply unmount filesystems" + fi + + eindent + fs= + for x in $net_fs_list $extra_net_fs_list; do + fs="$fs${fs:+|}$x" + done + [ -n "$fs" ] && fs="^($fs)$" + do_unmount umount ${fs:+--fstype-regex} $fs --netdev + retval=$? + + eoutdent + if [ "$RC_UNAME" = Linux ] && [ $retval = 0 ]; then + umount -a -O _netdev + retval=$? + fi + eend $retval "Failed to unmount network filesystems" +} Index: contrib/openrc/init.d/network.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/network.in @@ -0,0 +1,360 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2009-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# This script was inspired by the equivalent rc.d network from NetBSD. + +description="Configures network interfaces." +__nl=" +" + +depend() +{ + need localmount + after bootmisc clock + if [ -n "$(interfaces)" ]; then + provide net + fi + keyword -jail -prefix -vserver +} + +uniqify() +{ + local result= i= + for i; do + case " $result " in + *" $i "*);; + *) result="$result $i";; + esac + done + echo "${result# *}" +} + +reverse() +{ + local result= i= + for i; do + result="$i $result" + done + echo "${result# *}" +} + +sys_interfaces() +{ + case "$RC_UNAME" in + Linux) + local w= rest= i= cmd=$1 + while read w rest; do + i=${w%%:*} + case "$i" in + "$w") continue ;; + lo|lo0) continue ;; + *) ;; + esac + if [ "$cmd" = u ]; then + ifconfig "$i" | grep -q "[ ]*UP" || continue + fi + printf "%s " "$i" + done /dev/null); do + for f in /etc/ifconfig.${c}[0-9]*; do + [ -f "$f" ] && printf "%s" "$f{##*.} " + done + done + ;; + *) + for f in /etc/ifconfig.*; do + [ -f "$f" ] && printf "%s" "${f##*.} " + done + for f in /etc/ip.*; do + [ -f "$f" ] && printf "%s" "${f##*.} " + done + ;; + esac + echo +} + +interfaces() +{ + uniqify $(sys_interfaces "$@") $interfaces $(auto_interfaces) +} + +dumpargs() +{ + local f="$1" + + shift + case "$@" in + '') [ -f "$f" ] && cat "$f";; + *"$__nl"*) echo "$@";; + *) + ( + set -o noglob + IFS=';'; set -- $@ + IFS="$__nl"; echo "$*" + );; + esac +} + +intup=false +runip() +{ + local int="$1" err= + shift + + # Ensure we have a valid broadcast address + case "$@" in + *" broadcast "*|*" brd "*) ;; + *:*) ;; # Ignore IPv6 + *) set -- "$@" brd +;; + esac + + err=$(LC_ALL=C ip address add "$@" dev "$int" 2>&1) + if [ -z "$err" ]; then + # ip does not bring up the interface when adding addresses + if ! $intup; then + ip link set "$int" up + intup=true + fi + return 0 + fi + if [ "$err" = "RTNETLINK answers: File exists" ]; then + ip address del "$@" dev "$int" 2>/dev/null + fi + # Localise the error + ip address add "$@" dev "$int" +} + +routeflush() +{ + if [ "$RC_UNAME" = Linux ]; then + if [ -n "$(command -v ip)" ]; then + ip route flush scope global + ip route delete default 2>/dev/null + else + # Sadly we also delete some link routes, but + # this cannot be helped + local dest= gate= net= flags= rest= + route -n | while read dest gate net flags rest; do + [ -z "$net" ] && continue + case "$dest" in + [0-9]*) ;; + *) continue;; + esac + local xtra= netmask="netmask $net" + case "$flags" in + U) continue;; + *H*) flags=-host; netmask=;; + *!*) flags=-net; xtra=reject;; + *) flags=-net;; + esac + route del $flags $dest $netmask $xtra + done + # Erase any default dev eth0 routes + route del default 2>/dev/null + fi + else + route -qn flush + fi +} + +runargs() +{ + dumpargs "$@" | while read -r args; do + case "$args" in + ''|"#"*) ;; + *) + ( + eval vebegin "${args#*!}" + eval "${args#*!}" + veend $? + );; + esac + done +} + +start() +{ + local cr=0 r= int= intv= cmd= args= upcmd= + + if [ -z "$domainname" -a -s /etc/defaultdomain ]; then + domainname=$(cat /etc/defaultdomain) + fi + if [ -n "$domainname" ]; then + ebegin "Setting NIS domainname: $domainname" + domainname "$domainname" + eend $? + fi + + einfo "Starting network" + routeflush + eindent + for int in $(interfaces); do + local func= cf= + intv=$(shell_var "$int") + eval upcmd=\$ifup_$intv + for func in ip ifconfig; do + eval cmd=\$${func}_$intv + if [ -n "$cmd" -o -f /etc/"$func.$int" ]; then + cf=/etc/"$func.$int" + break + fi + done + [ -n "$cf" -o -n "$upcmd" -o \ + -f /etc/ifup."$int" -o -f "$cf" ] || continue + veinfo "$int" + case "$func" in + ip) func=runip; intup=false;; + esac + eindent + runargs /etc/ifup."$int" "$upcmd" + r=0 + dumpargs "$cf" "$cmd" | while read -r args; do + case "$args" in + ''|"#"*) ;; + "!"*) + ( + eval vebegin "${args#*!}" + eval "${args#*!}" + veend $? + );; + *) + ( + set -o noglob + eval set -- "$args" + vebegin "$@" + $func "$int" "$@" + veend $? + );; + esac + done + eoutdent + done + eoutdent + eend $cr + + # Wait for any inet6 tentative addresses + r=5 + while [ $r -gt 0 ]; do + tentative || break + [ $r = 5 ] && vebegin "Waiting for tentative addresses" + sleep 1 + : $(( r -= 1 )) + done + if [ $r != 5 ]; then + [ $r != 0 ] + veend $? + fi + + if [ -n "$defaultroute" ]; then + ebegin "Setting default route $defaultroute" + route add default $defaultroute + eend $? + elif [ -n "$defaultiproute" ]; then + ebegin "Setting default route $defaultiproute" + ip route add default $defaultiproute + eend $? + fi + + if [ -n "$defaultroute6" ]; then + ebegin "Setting default route $defaultroute6" + if [ "$RC_UNAME" = Linux ]; then + routecmd="route -A inet6 add" + else + routecmd="route -inet6 add" + fi + $routecmd default $defaultroute6 + eend $? + elif [ -n "$defaultiproute6" ]; then + ebegin "Setting default route $defaultiproute6" + ip -f inet6 route add default $defaultiproute6 + eend $? + fi + + return 0 +} + +stop() +{ + # Don't stop the network at shutdown. + # We don't use the noshutdown keyword so that we are started again + # correctly if we go back to multiuser. + yesno ${keep_network:-YES} && yesno $RC_GOINGDOWN && return 0 + + local int= intv= cmd= downcmd= r= + einfo "Stopping network" + routeflush + eindent + for int in $(reverse $(interfaces u)); do + case "$int" in + lo|lo0) continue ;; + *) ;; + esac + intv=$(shell_var "$int") + eval downcmd=\$ifdown_$intv + eval cmd=\$ip_$intv + [ -z "$cmd" ] && eval cmd=\$ifconfig_$intv + if [ -n "$cmd" -o -f /etc/ip."$int" -o \ + -f /etc/ifconfig."$int" -o \ + -n "$downcmd" -o -f /etc/ifdown."$int" ]; + then + veinfo "$int" + runargs /etc/ifdown."$int" "$downcmd" + if [ -n "$(command -v ip)" ]; then + # We need to do this, otherwise we may + # fail to add things correctly on restart + ip address flush dev "$int" 2>/dev/null + fi + ifconfig "$int" down 2>/dev/null + ifconfig "$int" destroy 2>/dev/null + fi + done + eoutdent + eend 0 +} Index: contrib/openrc/init.d/newsyslog.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/newsyslog.in @@ -0,0 +1,26 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +required_files="/etc/newsyslog.conf" + +depend() +{ + after clock + need localmount + keyword -prefix +} + +start() +{ + ebegin "Creating and/or trimming log files" + newsyslog -s $newsyslog_args + eend $? +} Index: contrib/openrc/init.d/nscd.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/nscd.in @@ -0,0 +1,29 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/nscd +command_args=$nscd_args +pidfile=/var/run/nscd.pid +name="Name Service Cache Daemon" + +extra_started_commands="flush" + +depend() { + need localmount + use net dns ldap ypbind + after bootmisc +} + +flush() { + ebegin "Flushing $name" + nscd -I all >/dev/null + eend $? +} Index: contrib/openrc/init.d/numlock.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/numlock.in @@ -0,0 +1,49 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Turns numlock on for the consoles." + +ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}} + +depend() +{ + need localmount + keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver +} + +_setleds() +{ + [ -z "$1" ] && return 1 + + local dev=/dev/tty t= i=1 retval=0 + [ -d /dev/vc ] && dev=/dev/vc/ + + while [ $i -le $ttyn ]; do + setleds -D "$1"num < $dev$i || retval=1 + : $(( i += 1 )) + done + + return $retval +} + +start() +{ + ebegin "Enabling numlock on ttys" + _setleds + + eend $? "Failed to enable numlock" +} + +stop() +{ + ebegin "Disabling numlock on ttys" + _setleds - + eend $? "Failed to disable numlock" +} Index: contrib/openrc/init.d/osclock.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/osclock.in @@ -0,0 +1,19 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2014-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Can be used on OSs that take care of the clock. + +description="Provides clock" + +depend() +{ + provide clock +} Index: contrib/openrc/init.d/pf.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/pf.in @@ -0,0 +1,66 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +name="Packet Filter" +: ${pf_conf:=${pf_rules:-/etc/pf.conf}} +required_files=$pf_conf + +extra_commands="checkconfig showstatus" +extra_started_commands="reload" + +depend() { + need localmount + keyword -jail -prefix +} + +start() +{ + ebegin "Starting $name" + if command -v kldload >/dev/null 2>&1; then + kldload pf 2>/dev/null + fi + pfctl -q -F all + pfctl -q -f "$pf_conf" $pf_args + pfctl -q -e + eend $? +} + +stop() +{ + ebegin "Stopping $name" + pfctl -q -d + eend $? +} + +checkconfig() +{ + ebegin "Checking $name configuration" + pfctl -n -f "$pf_conf" + eend $? +} + +reload() +{ + ebegin "Reloading $name rules." + pfctl -q -n -f "$pf_conf" && \ + { + # Flush everything but existing state entries that way when + # rules are read in, it doesn't break established connections. + pfctl -q -Fnat -Fqueue -Frules -FSources -Finfo -FTables -Fosfp + pfctl -q -f "$pf_conf" $pf_args + } + eend $? +} + +showstatus() +{ + pfctl -s info +} Index: contrib/openrc/init.d/powerd.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/powerd.in @@ -0,0 +1,42 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/powerd +command_args=$powerd_args +pidfile=/var/run/powerd.pid +name="Power Control Daemon" + +depend() +{ + need localmount + use logger + after bootmisc + keyword -jail -prefix +} + +start_pre() +{ + if [ -n "$powerd_battery_mode" ]; then + command_args="$command_args -b $powerd_battery_mode" + fi + if [ -n "${powerd_ac_mode}" ]; then + command_args="$command_args -a $powerd_ac_mode" + fi +} + +stop_post() +{ + local level=$(sysctl -n dev.cpu.0.freq_levels | + sed -e 's:/.*::') + if [ -n "$level" ]; then + sysctl dev.cpu.0.freq="$level" >/dev/null + fi +} Index: contrib/openrc/init.d/procfs.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/procfs.in @@ -0,0 +1,41 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mounts misc filesystems in /proc." + +depend() +{ + after clock + use devfs + want modules + need localmount + keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver +} + +start() +{ + # Setup Kernel Support for miscellaneous Binary Formats + if [ -d /proc/sys/fs/binfmt_misc ] && + [ ! -e /proc/sys/fs/binfmt_misc/register ]; then + if ! grep -qs binfmt_misc /proc/filesystems && + modprobe -q binfmt-misc; then + ewarn "The binfmt-misc module needs to be loaded by" \ + "the modules service or built in." + fi + if grep -qs binfmt_misc /proc/filesystems; then + ebegin "Mounting misc binary format filesystem" + mount -t binfmt_misc -o nodev,noexec,nosuid \ + binfmt_misc /proc/sys/fs/binfmt_misc + eend $? + fi + fi + return 0 +} Index: contrib/openrc/init.d/rarpd.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/rarpd.in @@ -0,0 +1,30 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/rarpd +command_args="-f $rarpd_args" +pidfile=/var/run/rarpd.pid +name="Reverse ARP Daemon" +required_files=/etc/ethers + +if [ -z "$rarpd_interface" ]; then + command_args="$command_args -a" +else + command_args="$command_args $rarpd_interface" +fi +command_background=YES + +depend() +{ + need localmount + after bootmisc + need net +} Index: contrib/openrc/init.d/rc-enabled.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/rc-enabled.in @@ -0,0 +1,60 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() +{ + need localmount net + after * + before local + keyword -prefix +} + +start() +{ + ebegin "Starting local rc services" + local svc= enabled= retval=0 service= pkgdir= + [ -n "@PKG_PREFIX@" ] && pkgdir="@PKG_PREFIX@/etc/rc.d/*" + for svc in $(rcorder /etc/rc.d/* $pkgdir 2>/dev/null); do + [ -x "$svc" ] || continue + service=${svc##*/} + + # Skip these services + for s in cleartmp moused; do + [ "$s" = "$service" ] && continue 2 + done + + # If we have an init script for this service, continue + rc-service --exists "$service" && continue + + # Ensure that the users rc.conf will start us + eval enabled=\$${svc##*/}_enable + yesno $enabled || yesno ${svc##*/} || continue + + # Good to go! + "$svc" start && started="$started $svc" + : $(( retval += $? )) + done + service_set_value started "$started" + eend $retval "Some local rc services failed to start" + return 0 +} + +stop() +{ + ebegin "Stopping local rc services" + local svc= retval=0 + for svc in $(rcorder $(service_get_value started) 2>/dev/null | sort -r); do + "$svc" stop + : $(( retval += $? )) + done + eend $retval "Some local rc services failed to stop" + return 0 +} Index: contrib/openrc/init.d/root.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/root.in @@ -0,0 +1,61 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mount the root fs read/write" + +depend() +{ + after clock + need fsck + keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -vserver +} + +start() +{ + case ",$(fstabinfo -o /)," in + *,ro,*) + ;; + *) + # Check if the rootfs isn't already writable. + if checkpath -W /; then + rm -f /fastboot /forcefsck + else + ebegin "Remounting root filesystem read/write" + case "$RC_UNAME" in + Linux) + mount -n -o remount,rw / + ;; + *) + mount -u -o rw / + ;; + esac + eend $? "Root filesystem could not be mounted read/write" + if [ $? -eq 0 ]; then + rm -f /fastboot /forcefsck + fi + fi + ;; + esac + + ebegin "Remounting filesystems" + local mountpoint + for mountpoint in $(fstabinfo); do + case "${mountpoint}" in + /) + ;; + /*) + mountinfo -q "${mountpoint}" && \ + fstabinfo --remount "${mountpoint}" + ;; + esac + done + eend 0 +} Index: contrib/openrc/init.d/rpcbind.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/rpcbind.in @@ -0,0 +1,28 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/rpcbind +command_args=$rpcbind_args +name="RPC program number mapper" + +depend() +{ + provide rpc + need localmount + use net logger dns + before inetd xinetd ntpd ntp-client +} + +stop_post() +{ + # rpcbind returns too fast, so sleep for a second + sleep 1 +} Index: contrib/openrc/init.d/runsvdir.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/runsvdir.in @@ -0,0 +1,20 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2016 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/bin/runsvdir +command_background=yes +pidfile=/var/run/runsvdir.pid +command_args="-P $RC_SVCDIR/sv 'log: ...........................................................................................................................................................................................................................................................................................................................................................................................................'" + +start_pre() +{ + checkpath -m 0755 -o root:root -d ${RC_SVCDIR}/sv +} Index: contrib/openrc/init.d/s6-svscan.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/s6-svscan.in @@ -0,0 +1,38 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/bin/s6-svscan +command_args="${RC_SVCDIR}"/s6-scan +command_background=yes +pidfile=/var/run/s6-svscan.pid + +depend() +{ + need localmount +} + +start_pre() +{ + einfo "Creating s6 scan directory" + checkpath -d -m 0755 "$RC_SVCDIR"/s6-scan + return $? +} + +stop_post() +{ + ebegin "Stopping any remaining s6 services" + s6-svc -dx "${RC_SVCDIR}"/s6-scan/* 2>/dev/null || true + eend $? + + ebegin "Stopping any remaining s6 service loggers" + s6-svc -dx "${RC_SVCDIR}"/s6-scan/*/log 2>/dev/null || true + eend $? +} Index: contrib/openrc/init.d/savecache.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/savecache.in @@ -0,0 +1,66 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Saves the caches OpenRC uses to non volatile storage" + +start() +{ + if [ -e "$RC_SVCDIR"/clock-skewed ]; then + ewarn "Clock skew detected!" + if ! yesno "${RC_GOINGDOWN}"; then + eerror "Not saving deptree cache" + return 1 + fi + fi + if [ ! -d "$RC_LIBEXECDIR"/cache ]; then + if ! checkpath -W "$RC_LIBEXECDIR"; then + eerror "${RC_LIBEXECDIR} is not writable!" + eerror "Unable to save dependency cache" + if yesno "${RC_GOINGDOWN}"; then + return 0 + fi + return 1 + fi + rm -rf "$RC_LIBEXECDIR"/cache + if ! mkdir -p "$RC_LIBEXECDIR"/cache; then + eerror "Unable to create $RC_LIBEXECDIR/cache" + eerror "Unable to save dependency cache" + if yesno "${RC_GOINGDOWN}"; then + return 0 + fi + return 1 + fi + fi + if ! checkpath -W "$RC_LIBEXECDIR"/cache; then + eerror "${RC_LIBEXECDIR}/cache is not writable!" + eerror "Unable to save dependency cache" + if yesno "${RC_GOINGDOWN}"; then + return 0 + fi + return 1 + fi + ebegin "Saving dependency cache" + local rc=0 save= + for x in shutdowntime softlevel rc.log; do + [ -e "$RC_SVCDIR/$x" ] && save="$save $RC_SVCDIR/$x" + done + if [ -n "$save" ]; then + cp -p $save "$RC_LIBEXECDIR"/cache + rc=$? + fi + if yesno "${RC_GOINGDOWN}"; then + if [ $rc -ne 0 ]; then + eerror "Unable to save dependency cache" + fi + eend 0 + fi + eend $rc "Unable to save dependency cache" +} Index: contrib/openrc/init.d/savecore.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/savecore.in @@ -0,0 +1,45 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Saves a kernel dump." + +depend() +{ + need dumpon localmount + after clock + before encswap + keyword -jail -prefix +} + +start() +{ + : ${dump_dir:=/var/crash} + if ! [ -d "$dump_dir" ]; then + mkdir -p "$dump_dir" + chmod 700 "$dump_dir" + fi + + if [ "$RC_UNAME" = FreeBSD ]; then + # Don't quote ${dump_device}, so that if it's unset, + # savecore will check on the partitions listed in fstab + # without errors in the output + savecore -C $dump_device >/dev/null + else + ls "$dump_dir"/bsd* > /dev/null 2>&1 + fi + [ $? = 0 ] || return 0 + + local sopts="$dump_dir $dump_device" + yesno $dump_compress && sopts="-z $sopts" + ebegin "Saving kernel core dump in $dump_dir" + savecore $sopts >/dev/null + eend $? +} Index: contrib/openrc/init.d/staticroute.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/staticroute.in @@ -0,0 +1,111 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2009-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# This script was inspired by the equivalent rc.d staticroute from NetBSD. + +description="Configures static routes." +__nl=" +" +depend() +{ + after clock + provide net + use network + keyword -jail -prefix -vserver +} + +pre_flight_checks() +{ + route=route + [ -s /etc/route.conf ] && return 0 + + if [ -n "$staticiproute" ]; then + route="ip route" + staticroute="$staticiproute" + fi +} + +dump_args() +{ + # Route configuration file, as used by the NetBSD RC system + if [ -s /etc/route.conf ]; then + cat /etc/route.conf + return $? + fi + + case "$staticroute" in + *"$__nl"*) + echo "$staticroute" + ;; + *) + ( + set -o noglob + IFS=';'; set -- $staticroute + IFS="$__nl"; echo "$*" + ) + ;; + esac +} + +do_routes() +{ + local xtra= family= + [ "$RC_UNAME" != Linux ] && xtra=-q + + ebegin "$1 static routes" + eindent + pre_flight_checks + dump_args | while read args; do + [ -z "$args" ] && continue + case "$args" in + "#"*) + ;; + "+"*) + [ $2 = "add" ] && eval ${args#*+} + ;; + "-"*) + [ $2 = "del" -o $2 = "delete" ] && eval ${args#*-} + ;; + *) + veinfo "$args" + case "$route" in + "ip route") + ip route $2 $args + ;; + *) + # Linux route does cannot work it out ... + if [ "$RC_UNAME" = Linux ]; then + case "$args" in + *:*) family="-A inet6";; + *) family=;; + esac + fi + route $family $xtra $2 -$args + ;; + esac + veend $? + esac + done + eoutdent + eend 0 +} + +start() +{ + do_routes "Adding" "add" +} + +stop() +{ + local cmd="delete" + [ "$RC_UNAME" = Linux ] && cmd="del" + do_routes "Deleting" "$cmd" +} Index: contrib/openrc/init.d/swap-blk.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/swap-blk.in @@ -0,0 +1,31 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() +{ + after clock + before fsck + keyword -jail -prefix +} + +start() +{ + ebegin "Activating block swap devices" + swapctl -A -t blk >/dev/null + eend 0 # If swapon has nothing todo it errors, so always return 0 +} + +stop() +{ + ebegin "Deactivating block swap devices" + swapctl -U -t blk >/dev/null + eend 0 +} Index: contrib/openrc/init.d/swap.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/swap.in @@ -0,0 +1,37 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() +{ + after clock + before localmount + keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -vserver +} + +start() +{ + ebegin "Activating swap devices" + case "$RC_UNAME" in + NetBSD|OpenBSD) swapctl -A -t noblk >/dev/null;; + *) swapon -a >/dev/null;; + esac + eend 0 # If swapon has nothing todo it errors, so always return 0 +} + +stop() +{ + ebegin "Deactivating swap devices" + case "$RC_UNAME" in + NetBSD|OpenBSD) swapctl -U -t noblk >/dev/null;; + *) swapoff -a >/dev/null;; + esac + eend 0 +} Index: contrib/openrc/init.d/swclock.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/swclock.in @@ -0,0 +1,36 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2009-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Sets the local clock to the mtime of a given file." + +depend() +{ + provide clock + keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu +} + +# swclock is an OpenRC built in + +start() +{ + ebegin "Setting the local clock based on last shutdown time" + if ! swclock 2> /dev/null; then + swclock --warn @SBINDIR@/openrc-run + fi + eend $? +} + +stop() +{ + ebegin "Saving the shutdown time" + swclock --save + eend $? +} Index: contrib/openrc/init.d/syscons.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/syscons.in @@ -0,0 +1,91 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() { + after clock + need localmount + keyword -jail -prefix +} + +start() { + if [ -n "$allscreen_flags" ]; then + ebegin "Setting mode to $allscreen_flags for all screens" + for v in /dev/ttyv*; do + vidcontrol $allscreen_flags <$v + done + eend $? + fi + + if [ -n "$keymap" ]; then + ebegin "Setting keymap to $keymap" + kbdcontrol -l $keymap \`$2'" + kbdcontrol -f "$1" "$2" /dev/null || retval=1 + done < "$conf" + veend $retval + fi + done + eoutdent + return $retval +} + +Linux_sysctl() +{ + local quiet + yesno $rc_verbose || quiet=-q + + sysctl ${quiet} --system +} + +start() +{ + local rc=0 + + ebegin "Configuring kernel parameters" + case "$RC_UNAME" in + *BSD|GNU) BSD_sysctl; rc=$? ;; + Linux) Linux_sysctl; rc=$? ;; + esac + eend $rc "Unable to configure some kernel parameters" +} Index: contrib/openrc/init.d/sysfs.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/sysfs.in @@ -0,0 +1,125 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mount the sys filesystem." + +sysfs_opts=nodev,noexec,nosuid + +depend() +{ + keyword -docker -lxc -prefix -systemd-nspawn -vserver +} + +mount_sys() +{ + grep -Eq "[[:space:]]+sysfs$" /proc/filesystems || return 1 + mountinfo -q /sys && return 0 + + if [ ! -d /sys ]; then + if ! mkdir -m 0755 /sys; then + ewarn "Could not create /sys!" + return 1 + fi + fi + + ebegin "Mounting /sys" + if ! fstabinfo --mount /sys; then + mount -n -t sysfs -o ${sysfs_opts} sysfs /sys + fi + eend $? +} + +mount_misc() +{ + # Setup Kernel Support for securityfs + if [ -d /sys/kernel/security ] && \ + ! mountinfo -q /sys/kernel/security; then + if grep -qs securityfs /proc/filesystems; then + ebegin "Mounting security filesystem" + mount -n -t securityfs -o ${sysfs_opts} \ + securityfs /sys/kernel/security + eend $? + fi + fi + + # Setup Kernel Support for debugfs + if [ -d /sys/kernel/debug ] && ! mountinfo -q /sys/kernel/debug; then + if grep -qs debugfs /proc/filesystems; then + ebegin "Mounting debug filesystem" + mount -n -t debugfs -o ${sysfs_opts} debugfs /sys/kernel/debug + eend $? + fi + fi + + # Setup Kernel Support for configfs + if [ -d /sys/kernel/config ] && ! mountinfo -q /sys/kernel/config; then + if grep -qs configfs /proc/filesystems; then + ebegin "Mounting config filesystem" + mount -n -t configfs -o ${sysfs_opts} configfs /sys/kernel/config + eend $? + fi + fi + + # set up kernel support for fusectl + if [ -d /sys/fs/fuse/connections ] \ + && ! mountinfo -q /sys/fs/fuse/connections; then + if grep -qs fusectl /proc/filesystems; then + ebegin "Mounting fuse control filesystem" + mount -n -t fusectl -o ${sysfs_opts} \ + fusectl /sys/fs/fuse/connections + eend $? + fi + fi + + # Setup Kernel Support for SELinux + if [ -d /sys/fs/selinux ] && ! mountinfo -q /sys/fs/selinux; then + if grep -qs selinuxfs /proc/filesystems; then + ebegin "Mounting SELinux filesystem" + mount -t selinuxfs selinuxfs /sys/fs/selinux + eend $? + fi + fi + + # Setup Kernel Support for persistent storage + if [ -d /sys/fs/pstore ] && ! mountinfo -q /sys/fs/pstore; then + if grep -qs 'pstore$' /proc/filesystems; then + ebegin "Mounting persistent storage (pstore) filesystem" + mount -t pstore pstore -o ${sysfs_opts} /sys/fs/pstore + eend $? + fi + fi + + # set up kernel support for efivarfs + if [ -d /sys/firmware/efi/efivars ] && + ! mountinfo -q /sys/firmware/efi/efivars; then + ebegin "Mounting efivarfs filesystem" + mount -n -t efivarfs -o ro \ + efivarfs /sys/firmware/efi/efivars 2> /dev/null + eend 0 + fi +} + +restorecon_sys() +{ + if [ -x /sbin/restorecon ]; then + ebegin "Restoring SELinux contexts in /sys" + restorecon -F /sys/devices/system/cpu/online >/dev/null 2>&1 + eend $? + fi +} + +start() +{ + mount_sys + mount_misc + restorecon_sys + return 0 +} Index: contrib/openrc/init.d/syslogd.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/syslogd.in @@ -0,0 +1,27 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/syslogd +command_args=$syslogd_args +case "$RC_UNAME" in + FreeBSD|DragonFly) pidfile=/var/run/syslog.pid;; + *) pidfile=/var/run/syslogd.pid;; +esac +name="System Logger Daemon" + +depend() +{ + provide logger + use net newsyslog + need localmount + after bootmisc clock + keyword -prefix +} Index: contrib/openrc/init.d/termencoding.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/termencoding.in @@ -0,0 +1,55 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Configures terminal encoding." + +ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}} +: ${unicode:=${UNICODE}} + +depend() +{ + keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu + use root + after bootmisc clock +} + +start() +{ + local ttydev=/dev/tty n= + [ -d /dev/vc ] && ttydev=/dev/vc/ + + # Set terminal encoding to either ASCII or UNICODE. + # See utf-8(7) for more information. + local termencoding="%@" termmsg="ASCII" + if yesno ${unicode}; then + termencoding="%G" + termmsg="UTF-8" + fi + + ebegin "Setting terminal encoding [$termmsg]" + n=1 + while [ ${n} -le "$ttyn" ]; do + printf "\033%s" "$termencoding" >$ttydev$n + : $(( n += 1 )) + done + + # Save the encoding for use immediately at boot + if checkpath -W "$RC_LIBEXECDIR"; then + mkdir -p "$RC_LIBEXECDIR"/console + if yesno ${unicode:-${UNICODE}}; then + echo "" > "$RC_LIBEXECDIR"/console/unicode + else + rm -f "$RC_LIBEXECDIR"/console/unicode + fi + fi + + eend 0 +} Index: contrib/openrc/init.d/ttys.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/ttys.in @@ -0,0 +1,30 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() +{ + after clock fsck + keyword -prefix +} + +start() +{ + ebegin "Setting tty flags" + ttyflags -a + eend $? || return $? + + if [ -c /dev/ttyp0 ]; then + chmod 666 /dev/tty[p-uw-zP-T][0-9a-zA-Z] + fi + if [ -c /dev/ttyv1 ]; then + chmod 666 /dev/ttyv[0-9a-zA-Z] + fi +} Index: contrib/openrc/init.d/urandom.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/urandom.in @@ -0,0 +1,53 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +: ${urandom_seed:=${URANDOM_SEED:-/var/lib/misc/random-seed}} +description="Initializes the random number generator." + +depend() +{ + after clock + need localmount + keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn +} + +save_seed() +{ + local psz=1 + + if [ -e /proc/sys/kernel/random/poolsize ]; then + : $(( psz = $(cat /proc/sys/kernel/random/poolsize) / 4096 )) + fi + + ( # sub shell to prevent umask pollution + umask 077 + dd if=/dev/urandom of="$urandom_seed" count=${psz} 2>/dev/null + ) +} + +start() +{ + [ -c /dev/urandom ] || return + if [ -f "$urandom_seed" ]; then + ebegin "Initializing random number generator" + cat "$urandom_seed" > /dev/urandom + eend $? "Error initializing random number generator" + fi + rm -f "$urandom_seed" && save_seed + return 0 +} + +stop() +{ + ebegin "Saving random seed" + save_seed + eend $? "Failed to save random seed" +} Index: contrib/openrc/init.d/wscons.in =================================================================== --- /dev/null +++ contrib/openrc/init.d/wscons.in @@ -0,0 +1,108 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() +{ + after clock + need localmount + keyword -prefix +} + +start() +{ + wscfg=/usr/sbin/wsconscfg + wsfld=/usr/sbin/wsfontload + wsctl=/sbin/wsconsctl + config=/etc/wscons.conf + + # args mean: + # screen idx scr emul + # font name width height enc file + while read type arg1 arg2 arg3 arg4 arg5; do + case "$type" in + \#*|"") + continue + ;; + + font) + cmd=$wsfld + [ "$arg2" != "-" ] && cmd="$cmd -w $arg2" + [ "$arg3" != "-" ] && cmd="$cmd -h $arg3" + [ "$arg4" != "-" ] && cmd="$cmd -e $arg4" + cmd="$cmd -N $arg1 $arg5" + eval "$cmd" + ;; + + screen) + cmd=$wscfg + [ "$arg2" != "-" ] && cmd="$cmd -t $arg2" + [ "$arg3" != "-" ] && cmd="$cmd -e $arg3" + cmd="$cmd $arg1" + eval "$cmd" + ;; + + keyboard) + cmd=$wscfg + case "$arg1" in + -|auto) + cmd="$cmd -k" + ;; + *) + cmd="$cmd -k $arg1" + ;; + esac + $cmd + ;; + + encoding) + eval $wsctl -w "\"encoding=$arg1\"" + ;; + + mapfile) + local entry= + while read entry; do + case "$entry" in + \#*|"") + continue + ;; + *) + cmd="$wsctl -w \"map+=$entry\"" + eval "$cmd >/dev/null" + ;; + esac + done < "$arg1" + ;; + + mux) + eval "$wscfg -m $arg1" + ;; + + setvar) + case "$arg1" in + keyboard) + cmd="$wsctl -kw $arg2" + ;; + display) + cmd="$wsctl -dw $arg2" + ;; + mouse) + cmd="$wsctl -mw $arg2" + ;; + *) + cmd="$wsctl -w $arg1" + ;; + esac + eval "$cmd" + ;; + + esac + done < "$config" +} Index: contrib/openrc/local.d/Makefile =================================================================== --- /dev/null +++ contrib/openrc/local.d/Makefile @@ -0,0 +1,6 @@ +DIR= ${LOCALDIR} +CONF= README + +MK= ../mk +include ${MK}/os.mk +include ${MK}/scripts.mk Index: contrib/openrc/local.d/README =================================================================== --- /dev/null +++ contrib/openrc/local.d/README @@ -0,0 +1,14 @@ +This directory should contain programs or scripts which are to be run +when the local service is started or stopped. + +If a file in this directory is executable and it has a .start extension, +it will be run when the local service is started. If a file is +executable and it has a .stop extension, it will be run when the local +service is stopped. + +All files are processed in lexical order. + +Keep in mind that files in this directory are processed sequentially, +and the local service is not considered started or stopped until +everything is processed, so if you have a process which takes a long +time to run, it can delay your boot or shutdown processing. Index: contrib/openrc/man/Makefile =================================================================== --- /dev/null +++ contrib/openrc/man/Makefile @@ -0,0 +1,45 @@ +MK= ../mk +include ${MK}/sys.mk +include ${MK}/os.mk + +MAN3= einfo.3 \ + rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \ + rc_runlevel.3 rc_service.3 rc_stringlist.3 +MAN8= rc-service.8 rc-status.8 rc-update.8 openrc.8 openrc-run.8 \ + start-stop-daemon.8 supervise-daemon.8 + +ifeq (${OS},Linux) +MAN8 += rc-sstat.8 openrc-init.8 openrc-shutdown.8 +endif + +# Handy macro to create symlinks +# This does rely on correctly formatting our manpages! +MAKE_LINKS= suffix=$${man\#*.}; \ + prefix=$${man%%.*}; \ + for link in `sed -e 's/ ,//g' \ + -n -e '/^\.Sh NAME$$/,/\.Sh/ s/\.Nm //p' $${man}`; do \ + if test "$${link}" != "$${prefix}" ; then \ + ln -sf $${man} \ + ${DESTDIR}/${MANDIR}/man$${suffix}/$${link}.$${suffix} ; \ + fi; \ + done; + +include ${MK}/gitignore.mk + +all: + +install: + ${INSTALL} -d ${DESTDIR}/${MANDIR}/man3 + for man in ${MAN3}; do \ + ${INSTALL} -m ${MANMODE} "$$man" ${DESTDIR}/${MANDIR}/man3 || exit $$?; \ + ${MAKE_LINKS} \ + done + ${INSTALL} -d ${DESTDIR}/${MANDIR}/man8 + for man in ${MAN8}; do \ + ${INSTALL} -m ${MANMODE} "$$man" ${DESTDIR}/${MANDIR}/man8 || exit $$?; \ + ${MAKE_LINKS} \ + done + +check test:: + +clean: Index: contrib/openrc/man/einfo.3 =================================================================== --- /dev/null +++ contrib/openrc/man/einfo.3 @@ -0,0 +1,197 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Mar 16, 2008 +.Dt EINFO 3 SMM +.Os OpenRC +.Sh NAME +.Nm einfo , ewarn , eerror , ebegin , +.Nm einfon , ewarnn , eerrorn , ebeginn , +.Nm einfov , ewarnv , ebeginv , +.Nm einfovn , ewarnvn , ebeginvn , +.Nm ewarnx , eerrorx , +.Nm eend , ewend , +.Nm eendv , ewendv , +.Nm ebracket , +.Nm eindent , eoutdent , +.Nm eindentv , eoutdentv , +.Nm eprefix +.Nd colorful informational output +.Sh LIBRARY +Enhanced Information output library (libeinfo, -leinfo) +.Sh SYNOPSIS +.In einfo.h +.Ft int Fn einfo "const char * restrict format" ... +.Ft int Fn ewarn "const char * restrict format" ... +.Ft int Fn eerror "const char * restrict format" ... +.Ft int Fn ebegin "const char * restrict format" ... +.Ft int Fn einfon "const char * restrict format" ... +.Ft int Fn ewarnn "const char * restrict format" ... +.Ft int Fn eerrorn "const char * restrict format" ... +.Ft int Fn ebeginn "const char * restrict format" ... +.Ft int Fn einfov "const char * restrict format" ... +.Ft int Fn ewarnv "const char * restrict format" ... +.Ft int Fn ebeginv "const char * restrict format" ... +.Ft int Fn einfovn "const char * restrict format" ... +.Ft int Fn ewarnvn "const char * restrict format" ... +.Ft int Fn ebeginvn "const char * restrict format" ... +.Ft int Fn ewarnx "const char * restrict format" ... +.Ft int Fn eerrorx "const char * restrict format" ... +.Ft int Fn eend "int retval" "const char * restrict format" ... +.Ft int Fn ewend "int retval" "const char * restrict format" ... +.Ft int Fn eendv "int retval" "const char * restrict format" ... +.Ft int Fn ewendv "int retval" "const char * restrict format" ... +.Ft void Fn ebracket "int col" "ECOLOR color" "const char * restrict msg" +.Ft void Fn eindent void +.Ft void Fn eoutdent void +.Ft void Fn eindentv void +.Ft void Fn eoutdentv void +.Ft void Fn eprefix "const char * prefix" +.Sh DESCRIPTION +The +.Fn einfo +family of functions provide a simple informational output that is colorised. +Basically +.Fn einfo , +.Fn ewarn +and +.Fn eerror +behave exactly like +.Fn printf +but prefix the output with a colored *. The function called denotes the color +used with +.Fn einfo +being green, +.Fn ewarn +being yellow and +.Fn eerror +being red. +einfo goes to stdout and the others go to stderr. +The number of real characters printed is returned. +.Fn ebegin +is identical to +.Fn einfo +except that 3 dots are appended to the output. +.Pp +.Fn einfov , +.Fn ewarnv +and +.Fn ebeginv +work the same way to +.Fn einfo , +.Fn ewarn , +and +.Fn ebegin +respectively, but only work when +.Va EINFO_VERBOSE +is true. You can also make the +.Fn einfo , +.Fn ewarn , +and +.Fn ebegin +functions silent by setting +.Va EINFO_QUIET +to true. +.Pp +These functions are designed to output a whole line, so they also +append a newline to the string. To stop this behaviour, you can use the +functions +.Fn einfon , +.Fn ewarnn , +.Fn eerrorn , +.Fn einfovn , +.Fn ewarnvn , +and +.Fn ebeginvn . +.Pp +.Fn eend , +.Fn ewend , +.Fn eendv +and +.Fn ewendv +are the counterparts to the above functions. If +.Fa retval +is zero then ok in green is printed in a bracket at the end of the prior +line. Otherwise we print the formatted string using +.Fn error +(or +.Fn ewarn +if +.Fn ewend +is called) !! in red (or yellow if +.Fn ewend +is called) is printed in a bracket at the end of the line. +The value of +.Fa retval +is returned. +.Pp +.Fn ebracket +does the same as +.Fn eend +but prints +.Fa msg +instead of ok or !! in the color +.Fa color +at the column +.Fa col . +.Pp +.Fn eindent +indents subsequent calls to the above functions by 3 characters. +.Fn eoutdent +removes an +.Fn eindent . +.Fn eindentv +and +.Fn eoutdentv +only work when +.Va EINFO_VERBOSE +is true. +.Pp +.Fn eprefix +prefixes the string +.Fa prefix +to the above functions. +.Sh IMPLEMENTATION NOTES +einfo can optionally be linked against the +.Lb libtermcap +so that we can correctly query the connected console for our color and +cursor escape codes. +If not, then we have a hard coded list of terminals we know about that support +the commonly used codes for color and cursor position. +.Sh ENVIRONMENT +.Va EINFO_QUIET +when set to true makes the +.Fn einfo +and +.Fn einfon +family of functions quiet, so nothing is printed. +.Va EERROR_QUIET +when set to true makes the +.Fn eerror +and +.Fn eerrorn +family of functions quiet, so nothing is printed. +.Pp +.Va EINFO_VERBOSE +when set to true makes the +.Fn einfov +and +.Fn einfovn +family of functions work, so they do print. +.Sh FILES +.Pa /etc/init.d/functions.sh +is provided by OpenRC, which allows shell scripts to use the above functions. +For historical reasons our verbose functions are prefixed with v instead of +suffixed. So einfov becomes veinfo, einfovn becomes veinfon. +Rinse and repeat for the other verbose functions. +.Sh SEE ALSO +.Xr printf 3 , +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/openrc-init.8 =================================================================== --- /dev/null +++ contrib/openrc/man/openrc-init.8 @@ -0,0 +1,46 @@ +.\" Copyright (c) 2017 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd April 6, 2017 +.Dt openrc-init 8 SMM +.Os OpenRC +.Sh NAME +.Nm openrc-init +.Nd the parent of all processes +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +is an init process which can be an alternative to sysvinit or any other +init process. +.Pp +To use +.Nm +configure your boot loader to invoke it or symlink it to /sbin/init. +Also, you will need to use +.Xr openrc-shutdown 8 , +to halt, reboot or poweroff the system. +.Pp +The default runlevel is read from the init command line, the +rc_default_runlevel setting in rc.conf, the kernel command line, or it is +assumed to be "default" if it is not set in any of these places. +.Pp +.Nm +doesn't manage getty's directly, so you will need to manage them another +way. For example, you can use the agetty service script as described in +agetty-guide.md in this distribution. +.Sh BUGS +This was first released as part of OpenRC 0.25. +I do not know of any specific issues. However, since this is the first +release of openrc-init, please test and report any issues you find. +.Sh SEE ALSO +.Xr openrc-shutdown 8 , +.Sh AUTHORS +.An William Hubbs Index: contrib/openrc/man/openrc-run.8 =================================================================== --- /dev/null +++ contrib/openrc/man/openrc-run.8 @@ -0,0 +1,740 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd November 30, 2017 +.Dt openrc-run 8 SMM +.Os OpenRC +.Sh NAME +.Nm openrc-run +.Nd a means of hooking shell commands into a service +.Sh SYNOPSIS +.Nm +.Op Fl D , -nodeps +.Op Fl d , -debug +.Op Fl s , -ifstarted +.Op Fl S , -ifstopped +.Op Fl Z , -dry-run +.Op Ar command ... +.Sh DESCRIPTION +.Nm +is basically an interpreter for shell scripts which provides an easy interface +to the often complex system commands and daemons. +When a service runs a command it first loads its multiplexed configuration +file, then its master configuration file, then +.Pa /etc/rc.conf +and finally the script itself. At this point +.Nm +then runs the command given. +.Pp +Commands are defined as shell functions within the script. Here is a list of +some functions that all scripts have by default: +.Bl -tag -width "RC_DEFAULTLEVEL" +.It Ar describe +Describes what the service does and each command the service defines. +.It Ar start +First we ensure that any services we depend on are started. If any needed +services fail to start then we exit with a suitable error, otherwise call the +supplied start function if it exists. +.It Ar stop +First we ensure that any services that depend on us are stopped. If any +services that need us fail to stop then we exit with a suitable error, +otherwise call the supplied stop function if it exists. +.It Ar restart +Stops and starts the service, including dependencies. This cannot be +overridden. See the description of the RC_CMD variable below for the +method to make your service behave differently when restart is being +executed. +.It Ar status +Shows the status of the service. The return code matches the status, with the +exception of "started" returning 0 to match standard command behaviour. +.It Ar zap +Resets the service state to stopped and removes all saved data about the +service. +.El +.Pp +The following options affect how the service is run: +.Bl -tag -width "RC_DEFAULTLEVEL" +.It Fl d , -debug +Set xtrace on in the shell to assist in debugging. +.It Fl D , -nodeps +Ignore all dependency information the service supplies. +.It Fl s , -ifstarted +Only run the command if the service has been started. +.It Fl S , -ifstopped +Only run the command if the service has been stopped. +.It Fl q , -quiet +Turns off all informational output the service generates. +Output from any non OpenRC commands is not affected. +.It Fl v , -verbose +Turns on any extra informational output the service generates. +.It Fl Z , -dry-run +Shows which services would be stopped and/or started without actually stopping +or starting them. +.El +.Pp +The following variables affect the service script: +.Bl -tag -width "RC_DEFAULTLEVEL" +.It Ar extra_commands +Space separated list of extra commands the service defines. These should +not depend on the service being stopped or started. +.It Ar extra_started_commands +Space separated list of extra commands the service defines. These only work if +the service has already been started. +.It Ar extra_stopped_commands +Space separated list of extra commands the service defines. These only work if +the service has already been stopped. +.It Ar description +String describing the service. +.It Ar description_$command +String describing the extra command. +.It Ar supervisor +Supervisor to use to monitor this daemon. If this is unset or invalid, +start-stop-daemon will be used. +Currently, we support s6 from skarnet software, and supervise-daemon +which is a light-weight supervisor internal to OpenRC. +To use s6, set +supervisor=s6. +or set +supervisor=supervise-daemon +to use supervise-daemon. +Note that supervise-daemon is still in early development, so it is +considered experimental. +.It Ar s6_service_path +The path to the s6 service directory if you are monitoring this service +with S6. The default is /var/svc.d/${RC_SVCNAME}. +.It Ar s6_svwait_options_start +The options to pass to s6-svwait when starting the service via s6. +.It Ar s6_force_kill +Should we force-kill this service if s6_service_timeout_stop expires +but the service doesn't go down during shutdown? The default is yes. +.It Ar s6_service_timeout_stop +The amount of time, in milliseconds, s6-svc should wait for the service +to go down when stopping the service. The default is 60000. +.It Ar start_stop_daemon_args +List of arguments passed to start-stop-daemon when starting the daemon. +.It Ar command +Daemon to start or stop via +.Nm start-stop-daemon +or +.Nm supervise-daemon +if no start or stop function is defined by the service. +.It Ar command_args +List of arguments to pass to the daemon when starting via +.Nm start-stop-daemon . +.It Ar command_args_background +This variable should be used if the daemon you are starting with +.Xr start-stop-daemon 8 +runs in the foreground by default but has its own command line options +to request that it background and write a pid file. It should be set to +those options. It should not be used at the same time as +command_background, because command_background requests that +.Xr start-stop-daemon 8 +go into the background before executing the daemon. +.It Ar command_args_foreground +List of arguments to pass to the daemon when starting via +.Nm supervise-daemon . +to force the daemon to stay in the foreground +.It Ar command_background +Set this to "true", "yes" or "1" (case-insensitive) if you want +.Xr start-stop-daemon 8 +to force the daemon into the background. This forces the +"--make-pidfile" and "--pidfile" options, so the pidfile variable must be set. +.It Ar command_progress +Set this to "true", "yes" or "1" (case-insensitive) if you want +.Xr start-stop-daemon 8 +to display a progress meter when waiting for a daemon to stop. +.It Ar command_user +If the daemon does not support changing to a different user id, you can +use this to change the user id, and optionally group id, before +.Xr start-stop-daemon 8 +or +.Xr supervise-daemon 8 +launches the daemon. +.It Ar output_log +This is the path to a file or named pipe where the standard output from +the service will be redirected. If you are starting this service with +.Xr start-stop-daemon 8 , +, you must set +.Pa command_background +to true. Keep in mind that this path will be inside the chroot if the +.Pa chroot +variable is set. +.It Ar error_log +The same thing as +.Pa output_log +but for the standard error output. +.It Ar directory +.Xr start-stop-daemon 8 +and +.Xr supervise-daemon 8 +will chdir to this directory before starting the daemon. +.It Ar chroot +.Xr start-stop-daemon 8 +and +.Xr supervise-daemon 8 +will chroot into this path before writing the pid file or starting the daemon. +.It Ar pidfile +Pidfile to use for the above defined command. +.It Ar name +Display name used for the above defined command. +.It Ar procname +Process name to match when signaling the daemon. +.It Ar stopsig +Signal to send when stopping the daemon. +.It Ar respawn_delay +Respawn delay +.Xr supervise-daemon 8 +will use for this daemon. See +.Xr supervise-daemon 8 +for more information about this setting. +.It Ar respawn_max +Respawn max +.Xr supervise-daemon 8 +will use for this daemon. See +.Xr supervise-daemon 8 +for more information about this setting. +.It Ar respawn_period +Respawn period +.Xr supervise-daemon 8 +will use for this daemon. See +.Xr supervise-daemon 8 +for more information about this setting. +.It Ar retry +Retry schedule to use when stopping the daemon. It can either be a +timeout in seconds or multiple signal/timeout pairs (like SIGTERM/5). +.It Ar required_dirs +A list of directories which must exist for the service to start. +.It Ar required_files +A list of files which must exist for the service to start. +.It Ar start_inactive +Set to yes to have the service marked inactive when it starts. This is +used along with in_background_fake to support re-entrant services. +.It Ar in_background_fake +Space separated list of commands which should always succeed when +in_background is yes. +.It Ar umask +Set the umask of the daemon. +.Pp +Keep in mind that eval is used to process chroot, command, command_args_*, +command_user, pidfile and procname. This may affect how they are +evaluated depending on how they are quoted. +.El +.Sh DEPENDENCIES +You should define a +.Ic depend +function for the service so that +.Nm +will start and stop it in the right order in relation to other services. +As it's a function it can be very flexible, see the example below. +Here is a list of the functions you can use in a +.Ic depend +function. You simply pass the names of the services you want to add to +that dependency type to the function, or prefix the names with ! to +remove them from the dependencies. +.Bl -tag -width "RC_DEFAULTLEVEL" +.It Ic need +The service will attempt to start any services it needs regardless of +whether they have been added to the runlevel. It will refuse to start +until all services it needs have started, and it will refuse to stop until all +services that need it have stopped. +.It Ic use +The service will attempt to start any services it uses that have been added +to the runlevel. +.It Ic want +The service will attempt to start any services it wants, regardless of +whether they have been added to the runlevel. +.It Ic after +The service will start after these services and stop before these services. +.It Ic before +The service will start before these services and stop after these services. +.It Ic provide +The service provides this virtual service. For example, named provides dns. +Note that it is not legal to have a virtual and real service with the +same name. If you do this, you will receive an error message, and you +must rename either the real or virtual service. +.It Ic config +We should recalculate our dependencies if the listed files have changed. +.It Ic keyword +Tags a service with a keyword. These are the keywords we currently understand: +.Bl -tag -width indent +.It Dv -shutdown +Don't stop this service when shutting the system down. +This is normally quite safe as remaining daemons will be sent a SIGTERM just +before final shutdown. +Network related services such as the network and dhcpcd init scripts normally +have this keyword. +.It Dv -stop +Don't stop this service when changing runlevels, even if not present. +This includes shutting the system down. +.It Dv -timeout +Other services should wait indefinitely for this service to start. Use +this keyword if your service may take longer than 60 seconds to start. +.It Dv -jail +When in a jail, exclude this service from any dependencies. The service can +still be run directly. Set via +.Ic rc_sys +in +.Pa /etc/rc.conf +.It Dv -lxc +Same as -jail, but for Linux Resource Containers (LXC). +.It Dv -openvz +Same as -jail, but for OpenVZ systems. +.It Dv -prefix +Same as -jail, but for Prefix systems. +.It Dv -rkt +Same as -jail, but for RKT systems. +.It Dv -uml +Same as -jail, but for UML systems. +.It Dv -vserver +Same as -jail, but for VServer systems. +.It Dv -xen0 +Same as -jail, but for Xen DOM0 systems. +.It Dv -xenu +Same as -jail, but for Xen DOMU systems. +.It Dv -docker +Same as -jail, but for docker systems. +.It Dv -containers +Same as -jail, but for all relevant container types on the operating +system. +.El +.El +.Pp +To see how to influence dependencies in configuration files, see the +.Sx FILES +section below. +.Sh _pre AND _post FUNCTIONS +Any command defined in extra_commands, extra_started_commands or +extra_stopped_commands can have _pre and _post functions in the service +script. If the command function is called foo, the_pre and _post +functions for it should be called foo_pre and foo_post. +.Pp +These functions should be used to perform preparation before the +command is run and cleanup after the command completes. In order for +.Nm +to record the command as being run successfully, the _pre +function, command function itself and the _post function should all exit +with a zero return code. +.Sh BUILTINS +.Nm +defines some builtin functions that you can use inside your service scripts: +.Bl -tag -width indent +.It Ic einfo Op Ar string +Output a green asterisk followed by the string. +.It Ic ewarn Op Ar string +Output a yellow asterisk followed by the string. +.It Ic eerror Op Ar string +Output a red asterisk followed by the string to stderr. +.It Ic ebegin Op Ar string +Same as einfo, but append 3 dots to the end. +.It Ic eend Ar retval Op Ar string +If +.Ar retval +does not equal 0 then output the string using +.Ic eerror +and !! in square brackets +at the end of the line. +Otherwise output ok in square brackets at the end of the line. +The value of +.Ar retval +is returned. +.It Ic ewend Ar retval Op Ar string +Same as +.Ic eend , +but use +.Ic ewarn +instead of +.Ic eerror . +.El +.Pp +You can prefix the above commands with the letter +.Ic v , +which means they only +output when the environment variable +.Va EINFO_VERBOSE +is true. +.Bl -tag -width indent +.It Ic ewaitfile Ar timeout Ar file1 Ar file2 ... +Wait for +.Ar timeout +seconds until all files exist. +Returns 0 if all files exist, otherwise non zero. +If +.Ar timeout +is less than 1 then we wait indefinitely. +.It Ic is_newer_than Ar file1 Ar file2 ... +If +.Ar file1 +is newer than +.Ar file2 +return 0, otherwise 1. +If +.Ar file2 +is a directory, then check all its contents too. +.It Ic is_older_than Ar file1 Ar file2 ... +If +.Ar file1 +is newer than +.Ar file2 +return 0, otherwise 1. +If +.Ar file2 +is a directory, then check all its contents too. +.It Ic service_set_value Ar name Ar value +Saves the +.Ar name +.Ar value +for later retrieval. Saved values are lost when the service stops. +.It Ic service_get_value Ar name +Returns the saved value called +.Ar name . +.It Ic service_started Op Ar service +If the service is started, return 0 otherwise 1. +.It Ic service_starting Op Ar service +If the service is starting, return 0 otherwise 1. +.It Ic service_inactive Op Ar service +If the service is inactive, return 0 otherwise 1. +.It Ic service_stopping Op Ar service +If the service is stopping, return 0 otherwise 1. +.It Ic service_stopped Op Ar service +If the service is stopped, return 0 otherwise 1. +.It Ic service_coldplugged Op Ar service +If the service is coldplugged, return 0 otherwise 1. +.It Ic service_wasinactive Op Ar service +If the service was inactive, return 0 otherwise 1. +.It Xo +.Ic service_started_daemon +.Op Ar service +.Ar daemon +.Op Ar index +.Xc +If the service has started the daemon using +.Nm start-stop-daemon , +return 0 otherwise 1. +If an index is specified, it has to be the nth daemon started by the service. +.It Ic mark_service_started Op Ar service +Mark the service as started. +.It Ic mark_service_starting Op Ar service +Mark the service as starting. +.It Ic mark_service_inactive Op Ar service +Mark the service as inactive. +.It Ic mark_service_stopping Op Ar service +Mark the service as stopping. +.It Ic mark_service_stopped Op Ar service +Mark the service as stopped. +.It Ic mark_service_coldplugged Op Ar service +Mark the service as coldplugged. +.It Ic mark_service_wasinactive Op Ar service +Mark the service as inactive. +.It Xo +.Ic checkpath +.Op Fl D , -directory-truncate +.Op Fl d , -directory +.Op Fl F , -file-truncate +.Op Fl f , -file +.Op Fl p , -pipe +.Op Fl m , -mode Ar mode +.Op Fl o , -owner Ar owner +.Op Fl W , -writable +.Op Fl q , -quiet +.Ar path ... +.Xc +If -d, -f or -p is specified, checkpath checks to see if the path +exists, is the right type and has the correct owner and access modes. If +any of these tests fail, the path is created and set up as specified. If +more than one of -d, -f or -p are specified, the last one will be used. +.Pp +The argument to -m is a three or four digit octal number. If this option +is not provided, the value defaults to 0644 for files and 0775 for +directories. +.Pp +The argument to -o is a representation of the user and/or group which +should own the path. The user and group can be represented numerically +or with names, and are separated by a colon. +.Pp +The truncate options (-D and -F) cause the directory or file to be +cleared of all contents. +.Pp +If -W is specified, checkpath checks to see if the first path given on +the command line is writable. This is different from how the test +command in the shell works, because it also checks to make sure the file +system is not read only. +.Pp +Also, the -d, -f or -p options should not be specified along with this option. +.Pp +The -q option suppresses all informational output. If it is specified +twice, all error messages are suppressed as well. +.It Xo +.Ic fstabinfo +.Op Fl M , -mount +.Op Fl R , -remount +.Op Fl b , -blockdevice +.Op Fl m , -mountargs +.Op Fl o , -options +.Op Fl p , -passno Ar passno +.Op Fl t , -type Ar fstype +.Ar path +.Xc +If -b, -m, -o, -p or -t is specified,the appropriate information is +extracted from fstab. If -M or -R are given, file systems are mounted or +remounted. +.Pp +The -q option suppresses all informational output. If it is specified +twice, all error messages are suppressed as well. +.It Xo +.Ic mountinfo +.Op Fl f, -fstype-regex Ar regex +.Op Fl F, -skip-fstype-regex Ar regex +.Op Fl n, -node-regex Ar regex +.Op Fl N, -skip-node-regex Ar regex +.Op Fl o, -options-regex Ar regex +.Op Fl O, -skip-options-regex Ar regex +.Op Fl p, -point-regex Ar regex +.Op Fl P, -skip-point-regex Ar regex +.Op Fl e, -netdev +.Op Fl E, -nonetdev +.Op Fl i, -options +.Op Fl s, -fstype +.Op Fl t, -node +.Ar mount1 mount2 ... +.Xc +The f, F, n, N, o, O, p, P, e and E options specify what you want to +search for or skip in the mounted file systems. The i, s and t options +specify what you want to display. If no mount points are given, all +mount points will be considered. +.It Ic yesno Ar value +If +.Ar value +matches YES, TRUE, ON or 1 regardless of case then we return 0, otherwise 1. +.El +.Sh ENVIRONMENT +.Nm +sets the following environment variables for use in the service scripts: +.Bl -tag -width "RC_DEFAULTLEVEL" +.It Va RC_SVCNAME +Name of the service. +.It Va RC_SERVICE +Full path to the service. +.It Va RC_RUNLEVEL +Current runlevel that OpenRC is in. Note that, in OpenRC, the reboot +runlevel is mapped to the shutdown runlevel. This was done because most +services do not need to know if a system is shutting down or rebooting. +If you are writing a service that does need to know this, see the +RC_REBOOT variable. +.It Va RC_REBOOT +This variable contains YES if the system is rebooting. If your service +needs to know the system is rebooting, you should test this variable. +.It Va RC_BOOTLEVEL +Boot runlevel chosen. Default is boot. +.It Va RC_DEFAULTLEVEL +Default runlevel chosen. Default is default. +.It Va RC_SYS +A special variable to describe the system more. +Possible values are OPENVZ, XENU, XEN0, UML and VSERVER. +.It Va RC_PREFIX +In a Gentoo Prefix installation, this variable contains the prefix +offset. Otherwise it is undefined. +.It Va RC_UNAME +The result of `uname -s`. +.It Va RC_CMD +This contains the name of the command the service script is executing, such +as start, stop, restart etc. One example of using this is to make a +service script behave differently when restart is being executed. +.It Va RC_GOINGDOWN +This variable contains YES if the system is going into single user mode +or shutting down. +.It Va RC_LIBEXECDIR +The value of libexecdir which OpenRC was configured with during build +time. +.It Va RC_NO_UMOUNTS +This variable is used by plugins to contain a list of directories which +should not be unmounted. +.El +.Sh FILES +.Pp +Configuration files, relative to the location of the service. +If a file ending with .${RC_RUNLEVEL} exists then we use that instead. +.Bl -ohang +.It Pa ../conf.d/${RC_SVCNAME%%.*} +multiplexed configuration file. +Example: if ${RC_SVCNAME} is net.eth1 then look for +.Pa ../conf.d/net . +.It Pa ../conf.d/${RC_SVCNAME} +service configuration file. +.It Pa /etc/rc.conf +host configuration file. +.El +.Pp +With the exception of +.Pa /etc/rc.conf , +the configuration files can also influence the dependencies of the service +through variables. Simply prefix the name of the dependency with rc_. +Examples: +.Bd -literal -offset indent +# Whilst most services don't bind to a specific interface, our +# openvpn configuration requires a specific interface, namely bge0. +rc_need="net.bge0" +# To put it in /etc/rc.conf you would do it like this +rc_openvpn_need="net.bge0" + +# Services should not depend on the tap1 interface for network, +# but we need to add net.tap1 to the default runlevel to start it. +rc_provide="!net" +# To put it in /etc/conf.d/net you would do it like this +rc_provide_tap1="!net" +# To put in in /etc/rc.conf you would do it like this +rc_net_tap1_provide="!net" + +# It's also possible to negate keywords. This is mainly useful for prefix +# users testing OpenRC. +rc_keyword="!-prefix" +# This can also be used to block a script from runining in all +# containers except one or two +rc_keyword="!-containers !-docker" +.Ed +.Sh EXAMPLES +.Pp +An example service script for foo. +.Bd -literal -offset indent +#!/sbin/openrc-run +command=/usr/bin/foo +command_args="${foo_args} --bar" +pidfile=/var/run/foo.pid +name="FooBar Daemon" + +description="FooBar is a daemon that eats and drinks" +extra_commands="show" +extra_started_commands="drink eat" +description_drink="Opens mouth and reflexively swallows" +description_eat="Chews food in mouth" +description_show="Shows what's in the tummy" + +_need_dbus() +{ + grep -q dbus /etc/foo/plugins +} + +depend() +{ + # We write a pidfile and to /var/cache, so we need localmount. + need localmount + # We can optionally use the network, but it's not essential. + use net + # We should be after bootmisc so that /var/run is cleaned before + # we put our pidfile there. + after bootmisc + + # Foo may use a dbus plugin. + # However, if we add the dbus plugin whilst foo is running and + # stop dbus, we don't need to stop foo as foo didn't use dbus. + config /etc/foo/plugins + local _need= + if service_started; then + _need=`service_get_value need` + else + if _need_dbus; then + _need="${_need} dbus" + fi + fi + need ${_need} +} + +# This function does any pre-start setup. If it fails, the service will +# not be started. +# If you need this function to behave differently for a restart command, +# you should check the value of RC_CMD for "restart". +# This also applies to start_post, stop_pre and stop_post. +start_pre() +{ + if [ "$RC_CMD" = restart ]; then + # This block will only execute for a restart command. Use a + # structure like this if you need special processing for a + # restart which you do not need for a normal start. + # The function can also fail from here, which will mean that a + # restart can fail. + # This logic can also be used in start_post, stop_pre and + # stop_post. + fi + # Ensure that our dirs are correct + checkpath --directory --owner foo:foo --mode 0775 \\ + /var/run/foo /var/cache/foo +} + +start_post() +{ + # Save our need + if _need_dbus; then + service_set_value need dbus + fi +} + +stop_post() { + # Clean any spills + rm -rf /var/cache/foo/* +} + +drink() +{ + ebegin "Starting to drink" + ${command} --drink beer + eend $? "Failed to drink any beer :(" +} + +eat() +{ + local result=0 retval= ate= food= + ebegin "Starting to eat" + + if yesno "${foo_diet}"; then + eend 1 "We are on a diet!" + return 1 + fi + + for food in /usr/share/food/*; do + veinfo "Eating `basename ${food}`" + ${command} --eat ${food} + retval=$? + : $(( result += retval )) + [ ${retval} = 0 ] && ate="${ate} `basename ${food}`" + done + + if eend ${result} "Failed to eat all the food"; then + service_set_value ate "${ate}" + fi +} + +show() +{ + einfo "Foo has eaten: `service_get_value ate`" +} + +.Ed +.Sh BUGS +Because of the way we load our configuration files and the need to handle +more than one service directory, you can only use symlinks in service +directories to other services in the same directory. +You cannot symlink to a service in a different directory even if it is +another service directory. +.Pp +is_older_than should return 0 on success. +Instead we return 1 to be compliant with Gentoo baselayout. +Users are encouraged to use the is_newer_than function which returns correctly. +.Sh SEE ALSO +.Xr einfo 3 , +.Xr openrc 8 , +.Xr rc-status 8 , +.Xr rc-update 8 , +.Xr rc_plugin_hook 3 , +.Xr sh 1p , +.Xr start-stop-daemon 8 , +.Xr supervise-daemon 8 , +.Xr uname 1 +.Sh AUTHORS +.An Roy Marples +.An William Hubbs Index: contrib/openrc/man/openrc-shutdown.8 =================================================================== --- /dev/null +++ contrib/openrc/man/openrc-shutdown.8 @@ -0,0 +1,62 @@ +.\" Copyright (c) 2017 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd May 22, 2017 +.Dt openrc-shutdown 8 SMM +.Os OpenRC +.Sh NAME +.Nm openrc-shutdown +.Nd bring the system down +.Sh SYNOPSIS +.Nm +.Op Fl d , -no-write +.Op Fl D , -dry-run +.Op Fl H , -halt +.Op Fl k , -kexec +.Op Fl p , -poweroff +.Op Fl R , -reexec +.Op Fl r , -reboot +.Op Fl s , -single +.Op Fl w , -write-only +.Sh DESCRIPTION +.Nm +is the utility that communicates with +.Xr openrc-init 8 +to bring down the system or instruct openrc-init to re-execute itself. +It supports the following options: +.Bl -tag -width "poweroff" +.It Fl d , -no-write +Do not write the wtmp boot record. +.It Fl D , -dry-run +Print the action that would be taken without executing it. This is to +allow testing. +.It Fl H , -halt +Stop all services, kill all remaining processes and halt the system. +.It Fl k , -kexec +Stop all services, kill all processes and boot directly into a new +kernel loaded via +.Xr kexec 8 . +.It Fl p , -poweroff +Stop all services, kill all processes and power off the system. +.It Fl R , -reexec +instruct openrc-init to re-exec itself. This should be used after an +upgrade of OpenRC if you are using openrc-init as your init process. +.It Fl r , -reboot +Stop all services, kill all processes and reboot the system. +.It Fl s , -single +Stop all services, kill all processes and move to single user mode. +.It Fl w , -write-only +Stop all services, kill all processes and move to single user mode. +.El +.Sh SEE ALSO +.Xr openrc-init 8 , +.Xr kexec 8 , +.Sh AUTHORS +.An William Hubbs Index: contrib/openrc/man/openrc.8 =================================================================== --- /dev/null +++ contrib/openrc/man/openrc.8 @@ -0,0 +1,74 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd May 2, 2009 +.Dt OPENRC 8 SMM +.Os OpenRC +.Sh NAME +.Nm openrc +.Nd stops and starts services for the specified runlevel +.Sh SYNOPSIS +.Nm +.Op Fl n , -no-stop +.Op Fl o , -override +.Op Ar runlevel +.Sh DESCRIPTION +.Nm +first stops any services that are not in the specified runlevel unless +--no-stop is specified, then starts any services in the runlevel and +stacked runlevels added by +.Nm rc-update +that are not currently started. +If no runlevel is specified, we use the current runlevel. +.Pp +There are some special runlevels that you should be aware of: +.Bl -tag -width "shutdown" +.It Ar sysinit +Brings up any system specific stuff such as +.Pa /dev , +.Pa /proc +and optionally +.Pa /sys +for Linux based systems. It also mounts +.Pa /lib/rc/init.d +as a ramdisk using tmpfs where available unless / is mounted rw at boot. +.Nm +uses +.Pa /lib/rc/init.d +to hold state information about the services it runs. +sysinit always runs when the host first starts should not be run again. +.It Ar boot +Generally the only services you should add to the boot runlevel are those +which deal with the mounting of filesystems, set the initial state of attached +peripherals and logging. +Hotplugged services are added to the boot runlevel by the system. +All services in the boot and sysinit runlevels are automatically included +in all other runlevels except for those listed here. +.It Ar single +Stops all services except for those in the sysinit runlevel. +.It Ar reboot +Changes to the shutdown runlevel and then reboots the host. +.It Ar shutdown +Changes to the shutdown runlevel and then halts the host. +.El +.Pp +You should not call any of these runlevels yourself. +Instead you should use +.Xr init 8 +and +.Xr shutdown 8 +and let them call these special runlevels. +.Sh SEE ALSO +.Xr rc-status 8 , +.Xr rc-update 8 , +.Xr init 8 , +.Xr shutdown 8 +.Sh AUTHORS +.An Roy Marples Aq roy@marples.name Index: contrib/openrc/man/rc-service.8 =================================================================== --- /dev/null +++ contrib/openrc/man/rc-service.8 @@ -0,0 +1,75 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd May 1, 2009 +.Dt RC-SERVICE 8 SMM +.Os OpenRC +.Sh NAME +.Nm rc-service +.Nd locate and run an OpenRC service with the given arguments +.Sh SYNOPSIS +.Nm +.Op Fl c , -ifcrashed +.Ar service cmd +.Op Ar ... +.Nm +.Op Fl i , -ifexists +.Ar service cmd +.Op Ar ... +.Nm +.Op Fl I , -ifinactive +.Ar service cmd +.Op Ar ... +.Nm +.Op Fl N , -ifnotstarted +.Ar service cmd +.Op Ar ... +.Nm +.Fl e , -exists +.Ar service +.Nm +.Fl l , -list +.Nm +.Fl r , -resolve +.Ar service +.Sh DESCRIPTION +Service scripts could be in different places on different systems. +.Nm +locates the specified service and runs it with the given arguments. +If +.Fl i , -ifexists +is given then +.Nm +returns 0 even if the service does not exist. +If +.Fl I , -ifinactive +or +.Fl N , -ifnotstarted +is given then +.Nm +returns 0 if the service exists but is in the wrong state. +.Pp +If given the +.Fl l , -list +argument then +.Nm +will list all available services. +.Pp +.Fl e , -exists +return 0 if it can find +.Ar service , +otherwise -1. +.Fl r , -resolve +does the same and also prints the full path of the service to stdout. +.Sh SEE ALSO +.Xr openrc 8 , +.Xr stdout 3 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/rc-sstat.8 =================================================================== --- /dev/null +++ contrib/openrc/man/rc-sstat.8 @@ -0,0 +1,33 @@ +.\" Copyright (c) 2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd April 24, 2008 +.Dt RC-sstat 8 SMM +.Os OpenRC +.Sh NAME +.Nm rc-sstat +.Nd show status info about services supervised by s6 then rc-status +info +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +gathers and displays information about the status of services supervised +by s6 then runs rc-status to show info about nnormal OpenRC services. +.Pp +.Sh EXIT STATUS +.Nm +exits 1 if there is an internal error or exits with the same exit codes +as rc-status. +.Sh SEE ALSO +.Xr rc-status 8 , +.Xr rc-update 8 +.Sh AUTHORS +.An William Hubbs Index: contrib/openrc/man/rc-status.8 =================================================================== --- /dev/null +++ contrib/openrc/man/rc-status.8 @@ -0,0 +1,68 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd April 24, 2008 +.Dt RC-STATUS 8 SMM +.Os OpenRC +.Sh NAME +.Nm rc-status +.Nd show status info about runlevels +.Sh SYNOPSIS +.Nm +.Op Fl aclsuC +.Op Ar runlevel +.Sh DESCRIPTION +.Nm +gathers and displays information about the status of services +in different runlevels. The default behavior is to show information +about the current runlevel and any unassigned services that are not stopped, +but any runlevel can be quickly examined. +.Pp +If an active service is being supervised by +.Xr supervise-daemon 8, +the amount of time the daemon has been active along with the number of +times it has been respawned in the current respawn period will be +displayed. +.Pp +The options are as follows: +.Bl -tag -width ".Fl test , test string" +.It Fl a , -all +Show all runlevels and their services. +.It Fl c , -crashed +List all services that have crashed. +.It Fl l , -list +List all defined runlevels. +.It Fl m , -manual +Show all manually started services. +.It Fl r , -runlevel +Print the current runlevel name. +.It Fl s , -servicelist +Show all services. +.It Fl u , -unused +Show services not assigned to any runlevel. +.It Fl C , -nocolor +Disable color output. +.It Ar runlevel +Show information only for the named +.Ar runlevel . +.El +.Sh EXIT STATUS +.Nm +exits 0, except when checking for crashed services and it doesn't find any. +.Sh IMPLEMENTATION NOTES +.Nm +tries to list services within each runlevel in the presently resolved +dependency order if the dependency tree is available. +.Sh SEE ALSO +.Xr openrc 8 , +.Xr rc-update 8 +.Xr supervise-daemon 8 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/rc-update.8 =================================================================== --- /dev/null +++ contrib/openrc/man/rc-update.8 @@ -0,0 +1,89 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Jan 13, 2014 +.Dt RC-UPDATE 8 SMM +.Os OpenRC +.Sh NAME +.Nm rc-update +.Nd add and remove services to and from a runlevel +.Sh SYNOPSIS +.Nm +.Op Fl s , -stack +.Ar add +.Ar service +.Op Ar runlevel ... +.Nm +.Op Fl s , -stack +.Op Fl a , -all +.Ar delete +.Ar service +.Op Ar runlevel ... +.Nm +.Op Fl u , -update +.Op Fl v , -verbose +.Ar show +.Op Ar runlevel ... +.Sh DESCRIPTION +OpenRC uses named runlevels. Rather than editing some obscure +file or managing a directory of symlinks, +.Nm +exists to quickly add or delete services to and from from different runlevels. +All services must reside in the +.Pa /etc/init.d +or +.Pa /usr/local/etc/init.d +directories. +They must also be standard OpenRC scripts, meaning they must use +openrc-run. +.Pp +.Bl -tag -width "Fl a , -delete service" +.It Ar add Ar service +Add the +.Ar service +to the +.Ar runlevel +or the current one if none given. +Services added to the boot runlevel must exist in +.Pa /etc/init.d . +.It Ar delete Ar service +Delete the +.Ar service +from the +.Ar runlevel +or the current one if none given. +.It Ar show +Show all enabled services and the runlevels they belong to. If you specify +runlevels to show, then only those will be included in the output. +.It Fl v , -verbose +Show all services. +.It Fl u , -update +Forces an update of the dependency tree cache. +This may be needed in the event of clock skew (a file in /etc is newer than the +system clock). +.El +.Pp +If the +.Fl s , -stack +option is given then we either add or remove the runlevel from the runlevel. +This allows inheritance of runlevels. +.Pp +If the +.Fl a, -all +option is given, we remove the service from all runlevels. This is +useful, for example, to clean up the dangling symlinks after a service +is removed. +.Sh SEE ALSO +.Xr openrc 8 , +.Xr openrc-run 8 , +.Xr rc-status 8 +.Sh AUTHORS +.An Roy Marples +.An The OpenRC Team Index: contrib/openrc/man/rc_config.3 =================================================================== --- /dev/null +++ contrib/openrc/man/rc_config.3 @@ -0,0 +1,59 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Mar 17, 2008 +.Dt RC_CONFIG 3 SMM +.Os OpenRC +.Sh NAME +.Nm rc_config_list , rc_config_load , rc_config_value , rc_yesno +.Nd functions to query OpenRC service configurations +.Sh LIBRARY +Run Command library (librc, -lrc) +.Sh SYNOPSIS +.In rc.h +.Ft "RC_STRINGLIST *" Fn rc_config_list "const char *file" +.Ft "RC_STRINGLIST *" Fn rc_config_load "const char *file" +.Ft "char *" Fn rc_config_value "const char *const *list" "const char *entry" +.Ft bool Fn rc_yesno "const char *value" +.Sh DESCRIPTION +These functions provide an easy means of querying OpenRC configuration files. +.Pp +.Fn rc_config_list +returns a list of non comment lines in +.Fa file . +.Fn rc_config_load +does the same, but attempts to parse the line as if it was +a shell assignment. +.Fn rc_config_value +returns the value of +.Fa entry +found in +.Fa list . +.Pp +Each list should be freed using +.Fn rc_stringlist_free +when done. +.Pp +.Fn rc_yesno +returns if +.Fa value +is true, yes, on or 1 regardless of case, otherwise false. +If +.Fa value +is also not false, no, off or 0 regardless of case then +.Va errno +is set to +.Va EINVAL . +.Sh SEE ALSO +.Xr malloc 3 , +.Xr rc_stringlist_free 3 , +.Xr sh 1 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/rc_deptree.3 =================================================================== --- /dev/null +++ contrib/openrc/man/rc_deptree.3 @@ -0,0 +1,99 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Mar 16, 2008 +.Dt RC_DEPTREE 3 SMM +.Os OpenRC +.Sh NAME +.Nm rc_deptree_update , rc_deptree_update_needed , rc_deptree_load , +.Nm rc_deptree_depend , rc_deptree_depends , rc_deptree_order , +.Nm rc_deptree_free +.Nd RC dependency tree functions +.Sh LIBRARY +Run Command library (librc, -lrc) +.Sh SYNOPSIS +.In rc.h +.Ft bool Fn rc_deptree_update void +.Ft bool Fn rc_deptree_update_needed void +.Ft RC_DEPTREE Fn rc_deptree_load void +.Ft "RC_STRINGLIST *" Fo rc_deptree_depend +.Fa "const RC_DEPTREE *deptree" +.Fa "const char *type" +.Fa "const char *service" +.Fc +.Ft bool Fo rc_deptree_depends +.Fa "const RC_DEPTREE *deptree" +.Fa "const char *const *types" +.Fa "const char *const *services" +.Fa "const char *runlevel" +.Fa "int options" +.Fc +.Ft "RC_STRINGLIST *" Fo rc_deptree_order +.Fa "const RC_DEPTREE *deptree" +.Fa "const char *runlevel" +.Fa "int options" +.Fc +.Ft void Fn rc_deptree_free "RC_DEPTREE *deptree" +.Sh DESCRIPTION +These functions provide a means of querying the dependencies of OpenRC +services. +.Pp +.Fn rc_deptree_update +updates the service dependency tree, normally +.Pa /lib/rc/init.d/deptree . +.Fn rc_deptree_update_needed +checks to see if the dependency tree needs updated based on the mtime of it +compared to +.Pa /etc/init.d , +.Pa /etc/conf.d , +.Pa /usr/local/etc/init.d , +.Pa /usr/local/etc/conf.d , +.Pa /etc/rc.conf +and any files specified by a service. +.Pp +.Fn rc_deptree_load +loads the deptree and returns a pointer to it which needs to be freed by +.Fn rc_deptree_free +when done. +.Pp +.Fn rc_deptree_depend , +.Fn rc_deptree_depends +and +.Fn rc_deptree_order +return a list of services from the +.Fa deptree +based on the +.Fa type +or +.Fa types +of dependency. +.Fa options +can be a bitmask of +.Va RC_DEP_TRACE +and +.Va RC_DEP_STRICT . +.Va RC_DEP_TRACE +follows each services dependencies right down to the first service needed and +.Va RC_DEP_STRICT +only lists services actually needed or in the +.Va runlevel . +.Sh IMPLEMENTATION NOTES +Each function that returns +.Fr "RC_STRINGLIST *" +should be freed by calling +.Fn rc_stringlist_free +when done. +.Sh SEE ALSO +.Xr malloc 3 , +.Xr free 3 , +.Xr rc_stringlist_free 3 , +.Xr openrc-run 8 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/rc_find_pids.3 =================================================================== --- /dev/null +++ contrib/openrc/man/rc_find_pids.3 @@ -0,0 +1,56 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Mar 17, 2008 +.Dt RC_FIND_PIDS 3 SMM +.Os OpenRC +.Sh NAME +.Nm rc_find_pids +.Nd finds the pids of processes that match the given criteria +.Sh LIBRARY +Run Command library (librc, -lrc) +.Sh SYNOPSIS +.In rc.h +.Ft "RC_PIDLIST *" Fo rc_find_pids +.Fa "const char *const *argv" +.Fa "const char *cmd" +.Fa "uid_t uid" +.Fa "pid_t pid" +.Fc +.Sh DESCRIPTION +.Fn rc_find_pids +returns RC_PIDLIST, a structure based on the LIST macro from +.Xr queue 3 +which contains all the pids found matching the given criteria. +If +.Fa pid +is given then only that pid is returned if it is running. Otherise we check +all instances of +.Fa argv +with a process name of +.Fa cmd +owned by +.Fa uid , +all of which are optional. +.Pp +The returned list should be freed when done. +.Sh IMPLEMENTATION NOTES +On BSD systems we use +.Lb libkvm +and on Linux systems we use the +.Pa /proc +filesystem to find our processes. +.Pp +Each RC_PID should be freed in the list as well as the list itself when done. +.Sh SEE ALSO +.Xr free 3 , +.Xr queue 3 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/rc_plugin_hook.3 =================================================================== --- /dev/null +++ contrib/openrc/man/rc_plugin_hook.3 @@ -0,0 +1,37 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Mar 16, 2008 +.Dt RC_PLUGIN_HOOK 3 SMM +.Os OpenRC +.Sh NAME +.Nm rc_plugin_hook +.Nd hooks plugins into OpenRC services +.Sh LIBRARY +Run Command library (librc, -lrc) +.Sh SYNOPSIS +.In rc.h +.Ft int Fn rc_plugin_hook "RC_HOOK hook" "const char *name" +.Sh DESCRIPTION +.Fn rc_plugin_hook +is called for each shareable object found in +.Pa /lib/rc/plugins . +.Fa hook +is set to the hook running, and +.Fa name +is set to the name of the runlevel or name of the service. +.Pp +Plugins can affect the parent environment by writing NULL separated strings to +.Va rc_environ_fd . +.Sh SEE ALSO +.Xr openrc 8 , +.Xr openrc-run 8 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/rc_runlevel.3 =================================================================== --- /dev/null +++ contrib/openrc/man/rc_runlevel.3 @@ -0,0 +1,52 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Mar 16, 2008 +.Dt RC_RUNLEVEL 3 SMM +.Os OpenRC +.Sh NAME +.Nm rc_runlevel_get , rc_runlevel_exists , rc_runlevel_list , rc_runlevel_set , +.Nm rc_runlevel_starting , rc_runlevel_stopping +.Nd RC runlevel functions +.Sh LIBRARY +Run Command library (librc, -lrc) +.Sh SYNOPSIS +.In rc.h +.Ft "char *" Fn rc_runlevel_get void +.Ft bool Fn rc_runlevel_exists +.Ft "RC_STRINGLIST *" Fn rc_runlevel_list void +.Ft bool Fn rc_runlevel_set "const char *runlevel" +.Ft bool Fn rc_runlevel_starting void +.Ft bool Fn rc_runlevel_stopping void +.Sh DESCRIPTION +These functions provide a means of querying OpenRC to find out which runlevel +we are in and what services are in which runlevel. +.Sh IMPLEMENTATION NOTES +Each function that returns +.Fr "char *" +returns a malloced NULL terminated string that should be freed when done. +.Pp +Each function that returns +.Fr "RC_STRINGLIST *" +should by freed by calling +.Fn rc_stringlist_free +when done. +.Sh FILES +.Pa /etc/init.d/functions.sh +is provided by OpenRC, which allows shell scripts to use the above functions. +For historical reasons our verbose functions are prefixed with v instead of +suffixed. So einfov becomes veinfo, einfovn becomes veinfon. +Rinse and repeat for the other verbose functions. +.Sh SEE ALSO +.Xr malloc 3 , +.Xr free 3 +.Xr rc_stringlist_free 3 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/rc_service.3 =================================================================== --- /dev/null +++ contrib/openrc/man/rc_service.3 @@ -0,0 +1,216 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Mar 16, 2008 +.Dt RC_SERVICE 3 SMM +.Os OpenRC +.Sh NAME +.Nm rc_service_add , rc_service_delete , rc_service_daemon_set , +.Nm rc_service_description , rc_service_exists , rc_service_in_runlevel , +.Nm rc_service_mark , rc_service_extra_commands , rc_service_plugable , +.Nm rc_service_resolve , rc_service_schedule_start , rc_services_scheduled_by , +.Nm rc_service_schedule_clear , rc_service_state , +.Nm rc_service_started_daemon , rc_service_value_get , rc_service_value_set , +.Nm rc_services_in_runlevel , rc_services_in_state , rc_services_scheduled , +.Nm rc_service_daemons_crashed +.Nd functions to query OpenRC services +.Sh LIBRARY +Run Command library (librc, -lrc) +.Sh SYNOPSIS +.In rc.h +.Ft bool Fn rc_service_add "const char *runlevel" "const char *service" +.Ft bool Fn rc_service_delete "const char *runlevel" "const char *service" +.Ft bool Fo rc_service_daemon_set +.Fa "const char *service" +.Fa "const char *exec" +.Fa "const char *name" +.Fa "const char *pidfile" +.Fa "bool started" +.Fc +.Ft "char *" Fo rc_service_description +.Fa "const char *service" +.Fa "const char *option" +.Fc +.Ft bool Fn rc_service_exists "const char *service" +.Ft bool Fn rc_service_in_runlevel "const char *service" "const char *runlevel" +.Ft bool Fn rc_service_mark "const char *service" "RC_SERVICE state" +.Ft "RC_STRINGLIST *" Fn rc_service_extra_commands "const char *service" +.Ft bool Fn rc_service_plugable "const char *service" +.Ft "char *" rc_service_resolve "const char *service" +.Ft bool Fo rc_service_schedule_start +.Fa "const char *service" +.Fa "const char *service_to_start" +.Fc +.Ft "RC_STRINGLIST *" Fn rc_services_scheduled_by "const char *service" +.Ft bool Fn rc_service_schedule_clear "const char *service" +.Ft RC_SERVICE Fn rc_service_state "const char *service" +.Ft bool Fo rc_service_started_daemon +.Fa "const char *service" +.Fa "const char *exec" +.Fa "int indx" +.Fc +.Ft "char *" Fn rc_service_value_get "const char *service" "const char *option" +.Ft bool Fo rc_service_value_set +.Fa "const char *service" +.Fa "const char *option" +.Fa "const char *value" +.Fc +.Ft "RC_STRINGLIST *" Fn rc_services_in_runlevel "const char *runlevel" +.Ft "RC_STRINGLIST *" Fn rc_services_in_state "RC_SERVICE state" +.Ft "RC_STRINGLIST *" Fn rc_services_scheduled "const char *service" +.Ft bool Fn rc_service_daemons_crashed "const char *service" +.Sh DESCRIPTION +These functions provide a means of querying OpenRC services to find out the +state of each one, to start and stop it, and any other functions related +to it. +.Pp +Most functions should be self descriptive as to what they do and what they +return based on names and arguments. +.Pp +.Fn rc_service_add +adds the +.Fa service +to the +.Fa runlevel . +.Pp +.Fn rc_service_delete +deletes the +.Fa service +from the +.Fa runlevel . +.Pp +.Fn rc_service_daemon_set +saves the arguments in the +.Fa service +state data so that +.Fn rc_service_daemons_crashed +can check to see if they are still running or not. +.Pp +.Fn rc_service_description +returns the +.Va description +variable of the +.Fa service . +If +.Fa option +is not null then we return the +.Fa description_$option +variable instead. +.Pp +.Fn rc_service_exists +returns true if the +.Fa service +exists, otherwise false. +.Pp +.Fn rc_service_in_runlevel +returns true if the +.Fa service +is in the +.Fa runlevel , +otherwise false. +.Pp +.Fn rc_service_mark +puts the +.Fa service +into the given +.Fa state . +If the state is RC_SERVICE_STOPPED then all data associated with the +.Fa service +is lost. +.Fn rc_service_extra_commands +returns a list of extra commands the +.Fa service +supports beyond the default ones. See +.Nm openrc-run +for default commands. +.Pp +.Fn rc_service_plugable +returns true if the service is allowed to be plugged by +.Pa rc.conf . +Default is true. +.Pp +.Fn rc_service_resolve +resolves +.Fa service +to the full path of service that was started, or would be started. +.Pp +When +.Fa service +starts, it starts +.Fa service_to_start +afterswards as directed by +.Fn rc_service_schedule_start . +.Fn rc_services_scheduled +returns a list of services that will be started when +.Fa service +starts. +.Fn rc_service_schedule_clear +clears these scheduled services for +.Fa service . +.Pp +.Fn rc_service_state returns the state of +.Fa service . +The return value is a bitmask, where more than one state can apply. +.Pp +.Fn rc_service_started_daemon +checks to see if +.Fa service +started +.Fa exec +using +.Nm start-stop-daemon . +If +.Fa indx +is greater than zero, then it must also be the nth daemon started by +.Fa service . +.Fn rc_service_value_set +saves the +.Fa value +under the name +.Fa option . +.Fn rc_service_value_get +returns the value of the saved +.Fa option . +.Pp +.Fn rc_services_in_runlevel +returns a list of services in +.Fa runlevel . +If +.Fa runlevel +is not specified, then it returns a list of all available services. +.Pp +.Fn rc_services_in_state +returns a list of all the services in +.Fa state . +.Sh IMPLEMENTATION NOTES +Each function that returns +.Fr "char *" +returns a malloced NULL terminated string that should be freed when done. +.Pp +Each function that returns +.Fr "RC_STRINGLIST *" +should be freed using +.Fn rc_stringlist_free +when done. +.Pp +When a function fails it should either return false or NULL and set +.Va errno +unless specified otherwise as above. +.Sh FILES +.Pa /lib/rc/init.d +normally holds the volatile state data for services on a RAM backed disk. +.Sh SEE ALSO +.Xr errno 3 , +.Xr malloc 3 , +.Xr free 3 +.Xr rc_stringlist_free 3 , +.Xr start-stop-daemon 8 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/rc_stringlist.3 =================================================================== --- /dev/null +++ contrib/openrc/man/rc_stringlist.3 @@ -0,0 +1,74 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd Mar 16, 2008 +.Dt RC_STRLIST 3 SMM +.Os OpenRC +.Sh NAME +.Nm rc_stringlist_add , rc_stringlist_addu , rc_stringlist_delete , +.Nm rc_stringlist_free , rc_stringlist_new , rc_stringlist_sort +.Nd RC string list functions +.Sh LIBRARY +Run Command library (librc, -lrc) +.Sh SYNOPSIS +.In rc.h +.Ft "RC_STRINGLIST *" Fn rc_stringlist_new void +.Ft "RC_STRING *" Fn rc_stringlist_add "RC_STRINGLIST *list" "const char *item" +.Ft "RC_STRING *" Fn rc_stringlist_addu "RC_STRINGLIST *list" "const char *item" +.Ft bool Fn rc_stringlist_delete RC_STRINGLIST "const char *item" +.Ft void Fn rc_stringlist_free "RC_STRINGLIST *list" +.Ft void Fn rc_stringlist_sort "RC_STRINGLIST *list" +.Sh DESCRIPTION +These functions provide an easy means of manipulating string lists. They are +basically wrappers around TAILQ macros found in +.Xr queue 3 . +.Pp +.Fn rc_stringlist_new +creates a new list head to store the list. +.Pp +.Fn rc_stringlist_add +adds a malloced copy of +.Fa item +to +.Fa list . +It returns a pointer to the new item on success, or NULL on failure and sets +.Va errno +accordingly. +.Fn rc_stringlist_addu +only works if +.Fa list +does not already contain +.Fa item . +.Pp +.Fn rc_stringlist_delete +removes and frees +.Fa item +from +.Fa list , +retuning true on success, otherwise false. +.Pp +.Fn rc_stringlist_sort +sorts the +.Fa list +according to C locale. +.Pp +.Fn rc_stringlist_free +frees each item on +.Fa list +and the +.Fa list +itself. +.Sh SEE ALSO +.Xr malloc 3 , +.Xr free 3 , +.Xr queue 3 , +.Xr strcmp 3 +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/service.8 =================================================================== --- /dev/null +++ contrib/openrc/man/service.8 @@ -0,0 +1 @@ +.so rc-service.8 Index: contrib/openrc/man/start-stop-daemon.8 =================================================================== --- /dev/null +++ contrib/openrc/man/start-stop-daemon.8 @@ -0,0 +1,194 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd December 14, 2009 +.Dt START-STOP-DAEMON 8 SMM +.Os OpenRC +.Sh NAME +.Nm start-stop-daemon +.Nd ensures that daemons start and stop +.Sh SYNOPSIS +.Nm +.Fl S , -start +.Ar daemon +.Op Fl - +.Op Ar arguments +.Nm +.Fl K , -stop +.Ar daemon +.Nm +.Fl s , -signal +.Ar signal +.Ar daemon +.Sh DESCRIPTION +.Nm +provides a consistent method of starting, stopping and signaling daemons. +If neither +.Fl K , -stop +nor +.Fl s , -signal +are provided, then we assume we are starting the daemon. +If a daemon cannot background by itself, nor create a pidfile, +.Nm +can do it for the daemon in a secure fashion. +.Pp +If +.Nm +is used in an OpenRC service, then OpenRC can in turn check to see if the +daemon is still running. If not, then the service is marked as crashed. +.Pp +Here are the options to specify the daemon and how it should start or stop: +.Bl -tag -width indent +.It Fl x , -exec Ar daemon +The +.Ar daemon +we start or stop. +If this option is not specified, then the first non option argument +is used. +.It Fl p , -pidfile Ar pidfile +When starting, we expect the daemon to create a valid +.Ar pidfile +within a reasonable amount of time. When stopping we only stop the first pid +listed in the +.Ar pidfile . +.It Fl n , -name Ar name +Match the process +.Ar name +instead of a pidfile or executable. +.It Fl i , -interpreted +When matching process name, we should ensure that the correct interpreter +is also matched. +So if the daemon foo starts off like so +.D1 #!/usr/bin/perl -w +then +.Nm +matches the process +.D1 /usr/bin/perl -w foo +If an interpreted daemon changes its process name then this won't work. +.It Fl u , -user Ar user Ns Op : Ns Ar group +Start the daemon as the +.Ar user +and update $HOME accordingly or stop daemons +owned by the user. You can optionally append a +.Ar group +name here also. +.It Fl t , -test +Print the action(s) that would be taken, but don't actually do anything. +The return value is set as if the command was taken and worked. +.It Fl v , -verbose +Print the action(s) that are taken just before doing them. +.It Fl P , -progress +Echo a . to the console for each second elapsed whilst waiting. +.El +.Pp +These options are only used for starting daemons: +.Bl -tag -width indent +.It Fl a , -startas Ar name +Change the process name of the daemon to +.Ar name . +This just changes the first argument passed to the daemon. +.It Fl b , -background +Force the daemon into the background. Some daemons don't create pidfiles, so a +good trick is to get the daemon to run in the foreground, and use the this +option along with +.Fl m , -make-pidfile +to create a working pidfile. +.It Fl d , -chdir Ar path +chdir to this directory before starting the daemon. +.It Fl r , -chroot Ar path +chroot to this directory before starting the daemon. All other paths, such +as the path to the daemon, chdir and pidfile, should be relative to the chroot. +.It Fl c , -chuid Ar user +Same as the +.Fl u , -user +option. +.It Fl e , -env Ar VAR=VALUE +Set the environment variable VAR to VALUE. +.It Fl g , -group Ar group +Start the daemon as in the group. +.It Fl k , -umask Ar mode +Set the umask of the daemon. +.It Fl m , -make-pidfile +Saves the pid of the daemon in the file specified by the +.Fl p , -pidfile +option. Only useful when used with daemons that run in the foreground and +forced into the background with the +.Fl -b , -background +option. +.It Fl I , -ionice Ar class Ns Op : Ns Ar data +Modifies the IO scheduling priority of the daemon. +Class can be 0 for none, 1 for real time, 2 for best effort and 3 for idle. +Data can be from 0 to 7 inclusive. +.It Fl N , -nicelevel Ar level +Modifies the scheduling priority of the daemon. +.It Fl 1 , -stdout Ar logfile +Redirect the standard output of the process to logfile when started with +.Fl background . +Must be an absolute pathname, but relative to the path optionally given with +.Fl r , -chroot . +The logfile can also be a named pipe. +.It Fl w , -wait Ar milliseconds +Wait +.Ar milliseconds +after starting and check that daemon is still running. +Useful for daemons that check configuration after forking or stopping race +conditions where the pidfile is written out after forking. +.It Fl 2 , -stderr Ar logfile +The same thing as +.Fl 1 , -stdout +but with the standard error output. +.El +.Pp +These options are only used for stopping daemons: +.Bl -tag -width indent +.It Fl R , -retry Ar timeout | Ar signal Ns / Ns Ar timeout +The retry specification can be either a timeout in seconds or multiple +signal/timeout pairs (like SIGTERM/5). +.El +.Sh ENVIRONMENT +.Va SSD_IONICELEVEL +can also set the IO scheduling priority of the daemon, but the command line +option takes precedence. +.Pp +.Va SSD_NICELEVEL +can also set the scheduling priority of the daemon, but the command line +option takes precedence. +.Pp +.Va SSD_STARTWAIT +As the +.Fl w , -wait option above. +.Pa /etc/rc.conf +.Nm +waits for to check the daemon is still running. +.Sh NOTE +.Nm +uses +.Xr getopt 3 +to parse its options, which allows it to accept the `--' option which will +cause it to stop processing options at that point. Any subsequent arguments +are passed as arguments to the daemon to start and used when finding a daemon +to stop or signal. +.Sh SEE ALSO +.Xr chdir 2 , +.Xr chroot 2 , +.Xr getopt 3 , +.Xr nice 2 , +.Xr rc_find_pids 3 +.Sh BUGS +.Nm +cannot stop an interpreted daemon that no longer exists without a pidfile. +.Sh HISTORY +.Nm +first appeared in Debian. +.Pp +This is a complete re-implementation with the process finding code in the +OpenRC library (librc, -lrc) so other programs can make use of it. +.Sh AUTHORS +.An Roy Marples Index: contrib/openrc/man/supervise-daemon.8 =================================================================== --- /dev/null +++ contrib/openrc/man/supervise-daemon.8 @@ -0,0 +1,176 @@ +.\" Copyright (c) 2007-2015 The OpenRC Authors. +.\" See the Authors file at the top-level directory of this distribution and +.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS +.\" +.\" This file is part of OpenRC. It is subject to the license terms in +.\" the LICENSE file found in the top-level directory of this +.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +.\" This file may not be copied, modified, propagated, or distributed +.\" except according to the terms contained in the LICENSE file. +.\" +.Dd April 27, 2016 +.Dt supervise-DAEMON 8 SMM +.Os OpenRC +.Sh NAME +.Nm supervise-daemon +.Nd starts a daemon and restarts it if it crashes +.Sh SYNOPSIS +.Nm +.Fl D , -respawn-delay +.Ar seconds +.Fl d , -chdir +.Ar path +.Fl e , -env +.Ar var=value +.Fl g , -group +.Ar group +.Fl I , -ionice +.Ar arg +.Fl k , -umask +.Ar value +.Fl m , -respawn-max +.Ar count +.Fl N , -nicelevel +.Ar level +.Fl p , -pidfile +.Ar pidfile +.Fl P , -respawn-period +.Ar seconds +.Fl R , -retry +.Ar arg +.Fl r , -chroot +.Ar chrootpath +.Fl u , -user +.Ar user +.Fl 1 , -stdout +.Ar logfile +.Fl 2 , -stderr +.Ar logfile +.Fl S , -start +.Ar daemon +.Op Fl - +.Op Ar arguments +.Nm +.Fl K , -stop +.Ar daemon +.Fl p , -pidfile +.Ar pidfile +.Fl r , -chroot +.Ar chrootpath +.Sh DESCRIPTION +.Nm +provides a consistent method of starting, stopping and restarting +daemons. If +.Fl K , -stop +is not provided, then we assume we are starting the daemon. +.Nm +only works with daemons which do not fork. Also, it uses its own pid +file, so the daemon should not write a pid file, or the pid file passed +to +.Nm +should not be the one the daemon writes. +.Pp +Here are the options to specify the daemon and how it should start or stop: +.Bl -tag -width indent +.It Fl p , -pidfile Ar pidfile +When starting, we write a +.Ar pidfile +so we know which supervisor to stop. When stopping we only stop the pid(s) +listed in the +.Ar pidfile . +.It Fl u , -user Ar user Ns Op : Ns Ar group +Start the daemon as the +.Ar user +and update $HOME accordingly or stop daemons +owned by the user. You can optionally append a +.Ar group +name here also. +.It Fl v , -verbose +Print the action(s) that are taken just before doing them. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl D , -respawn-delay Ar seconds +wait this number of seconds before restarting a daemon after it crashes. +The default is 0. +.It Fl d , -chdir Ar path +chdir to this directory before starting the daemon. +.It Fl e , -env Ar VAR=VALUE +Set the environment variable VAR to VALUE. +.It Fl g , -group Ar group +Start the daemon as in the group. +.It Fl I , -ionice Ar class Ns Op : Ns Ar data +Modifies the IO scheduling priority of the daemon. +Class can be 0 for none, 1 for real time, 2 for best effort and 3 for idle. +Data can be from 0 to 7 inclusive. +.It Fl k , -umask Ar mode +Set the umask of the daemon. +.It Fl m , -respawn-max Ar count +Sets the maximum number of times a daemon will be respawned during a +respawn period. If a daemon dies more than this number of times during a +respawn period, +.Nm +will give up trying to respawn it and exit. The default is 10, and 0 +means unlimited. +.It Fl N , -nicelevel Ar level +Modifies the scheduling priority of the daemon. +.It Fl P , -respawn-period Ar seconds +Sets the length of a respawn period. The default is 10 seconds. See the +description of --respawn-max for more information. +.It Fl R , -retry Ar timeout | Ar signal Ns / Ns Ar timeout +The retry specification can be either a timeout in seconds or multiple +signal/timeout pairs (like SIGTERM/5). +.It Fl r , -chroot Ar path +chroot to this directory before starting the daemon. All other paths, such +as the path to the daemon, chdir and pidfile, should be relative to the chroot. +.It Fl u , -user Ar user +Start the daemon as the specified user. +.It Fl 1 , -stdout Ar logfile +Redirect the standard output of the process to logfile. +Must be an absolute pathname, but relative to the path optionally given with +.Fl r , -chroot . +The logfile can also be a named pipe. +.It Fl 2 , -stderr Ar logfile +The same thing as +.Fl 1 , -stdout +but with the standard error output. +.El +.El +.Sh ENVIRONMENT +.Va SSD_NICELEVEL +can also set the scheduling priority of the daemon, but the command line +option takes precedence. +.Sh NOTE +.Nm +uses +.Xr getopt 3 +to parse its options, which allows it to accept the `--' option which will +cause it to stop processing options at that point. Any subsequent arguments +are passed as arguments to the daemon to start and used when finding a daemon +to stop or signal. +.Sh NOTE +If respawn-delay, respawn-max and respawn-period are not set correctly, +it is possible to trigger a situation in which the supervisor will +infinitely try to respawn a daemon. To avoid this, if you change the +values of --respawn-delay, --respawn-max or --respawn-period, always +make sure the settings mmake sense. For example, a respawn period of 5 +seconds with a respawn max of 10 and a respawn delay of 1 second leads +to infinite respawning since there can never be 10 respawns within 5 +seconds. +.Sh SEE ALSO +.Xr chdir 2 , +.Xr chroot 2 , +.Xr getopt 3 , +.Xr nice 2 , +.Xr rc_find_pids 3 +.Sh BUGS +.Nm +cannot stop an interpreted daemon that no longer exists without a pidfile. +.Sh HISTORY +.Nm +first appeared in Debian. +.Pp +This is a complete re-implementation with the process finding code in the +OpenRC library (librc, -lrc) so other programs can make use of it. +.Sh AUTHORS +.An William Hubbs Index: contrib/openrc/mk/cc.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/cc.mk @@ -0,0 +1,44 @@ +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Setup some good default CFLAGS +CFLAGS?= -O2 -g + +# Default to using the C99 standard +CSTD?= c99 +ifneq (${CSTD},) +CFLAGS+= -std=${CSTD} +endif + +# Try and use some good cc flags if we're building from git +# We don't use -pedantic as it will warn about our perfectly valid +# use of %m in our logger. +_CCFLAGS= -Wall -Wextra -Wimplicit -Wshadow -Wformat=2 \ + -Wmissing-prototypes -Wmissing-declarations \ + -Wmissing-noreturn -Wmissing-format-attribute \ + -Wnested-externs \ + -Winline -Wwrite-strings -Wcast-align -Wcast-qual \ + -Wpointer-arith \ + -Wdeclaration-after-statement -Wsequence-point \ + -Werror=implicit-function-declaration + +# We should be using -Wredundant-decls, but our library hidden proto stuff +# gives loads of warnings. I don't fully understand it (the hidden proto, +# not the warning) so we just silence the warning. + +_CC_FLAGS_SH= for f in ${_CCFLAGS}; do \ + if echo "int main(void) { return 0;} " | \ + ${CC} $$f -S -xc -o /dev/null - ; \ + then printf "%s" "$$f "; fi \ + done; +_CC_FLAGS:= $(shell ${_CC_FLAGS_SH}) +CFLAGS+= ${_CC_FLAGS} + +include ${MK}/debug.mk Index: contrib/openrc/mk/debug.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/debug.mk @@ -0,0 +1,23 @@ +# rules to enable debugging support +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +_RC_DEBUG_SH= case "${DEBUG}" in "") echo "";; *) echo "-DRC_DEBUG";; esac +_RC_DEBUG:= $(shell ${_RC_DEBUG_SH}) +CPPFLAGS+= ${_RC_DEBUG} + +# Should we enable this with a different flag? +_LD_DEBUG_SH= case "${DEBUG}" in "") echo "";; *) echo "-Wl,--rpath=../librc -Wl,--rpath=../libeinfo";; esac +_LD_DEBUG:= $(shell ${_LD_DEBUG_SH}) +LDFLAGS+= ${_LD_DEBUG} + +_GGDB_SH= case "${DEBUG}" in "") echo "";; *) echo "-ggdb";; esac +_GGDB:= $(shell ${_GGDB_SH}) +CFLAGS+= ${_GGDB} Index: contrib/openrc/mk/depend.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/depend.mk @@ -0,0 +1,21 @@ +# Generate .depend +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +CLEANFILES+= .depend +IGNOREFILES+= .depend + +.depend: ${SRCS} + rm -f .depend + ${CC} ${LOCAL_CPPFLAGS} ${CPPFLAGS} -MM ${SRCS} > .depend + +depend: .depend extra_depend + +-include .depend Index: contrib/openrc/mk/dist.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/dist.mk @@ -0,0 +1,50 @@ +# rules to make a distribution tarball from a git repo +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +GITREF?= ${VERSION} +DISTPREFIX?= ${NAME}-${VERSION} +DISTFILE?= ${DISTPREFIX}.tar.gz + +CLEANFILES+= ${NAME}-*.tar.gz + +CHANGELOG_LIMIT?= --after="1 year ago" + +_SNAP_SH= date -u +%Y%m%d%H%M +_SNAP:= $(shell ${_SNAP_SH}) +SNAP= ${_SNAP} +SNAPDIR= ${DISTPREFIX}-${SNAP} +SNAPFILE= ${SNAPDIR}.tar.gz + +changelog: + git log ${CHANGELOG_LIMIT} --format=full > ChangeLog + +dist: + git archive --prefix=${DISTPREFIX}/ ${GITREF} --output=${DISTFILE} + +distcheck: dist + rm -rf ${DISTPREFIX} + tar xf ${DISTFILE} + MAKEFLAGS= $(MAKE) -C ${DISTPREFIX} + MAKEFLAGS= $(MAKE) -C ${DISTPREFIX} check + rm -rf ${DISTPREFIX} + +snapshot: + rm -rf /tmp/${SNAPDIR} + mkdir /tmp/${SNAPDIR} + cp -RPp * /tmp/${SNAPDIR} + (cd /tmp/${SNAPDIR}; make clean) + rm -rf /tmp/${SNAPDIR}/.git 2>/dev/null || true + tar -cvzpf ${SNAPFILE} -C /tmp ${SNAPDIR} + rm -rf /tmp/${SNAPDIR} + ls -l ${SNAPFILE} + +snap: snapshot + Index: contrib/openrc/mk/gitignore.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/gitignore.mk @@ -0,0 +1,22 @@ +# rules to make .gitignore files +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +IGNOREFILES+= ${CLEANFILES} + +.PHONY: .gitignore + +.gitignore: + @if test -n "${IGNOREFILES}"; then \ + echo "Ignoring ${IGNOREFILES}"; \ + echo ${IGNOREFILES} | tr ' ' '\n' > .gitignore; \ + fi + +ignore: .gitignore Index: contrib/openrc/mk/gitver.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/gitver.mk @@ -0,0 +1,8 @@ +_GITVER_SH= if git rev-parse --short HEAD >/dev/null 2>&1; then \ + printf "."; \ + git rev-parse --short HEAD; \ + else \ + echo ""; \ + fi +_GITVER:= $(shell ${_GITVER_SH}) +GITVER= ${_GITVER} Index: contrib/openrc/mk/lib.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/lib.mk @@ -0,0 +1,78 @@ +# rules to build a library +# based on FreeBSD's bsd.lib.mk + +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +SHLIB_NAME= lib${LIB}.so.${SHLIB_MAJOR} +SHLIB_LINK= lib${LIB}.so +SONAME?= ${SHLIB_NAME} + +SOBJS+= ${SRCS:.c=.So} + +MKSTATICLIBS?= yes +ifeq (${MKSTATICLIBS},yes) +OBJS+= ${SRCS:.c=.o} +_LIBS+= lib${LIB}.a +endif + +_LIBS+= ${SHLIB_NAME} + +CLEANFILES+= ${OBJS} ${SOBJS} ${_LIBS} ${SHLIB_LINK} + +%.o: %.c + ${CC} ${LOCAL_CFLAGS} ${LOCAL_CPPFLAGS} ${CFLAGS} ${CPPFLAGS} -c $< -o $@ + +%.So: %.c + ${CC} ${PICFLAG} -DPIC ${LOCAL_CFLAGS} ${LOCAL_CPPFLAGS} ${CPPFLAGS} ${CFLAGS} -c $< -o $@ + +all: depend ${_LIBS} + +lib${LIB}.a: ${OBJS} ${STATICOBJS} + @${ECHO} building static library $@ + ${AR} rc $@ $^ + ${RANLIB} $@ + +${SHLIB_NAME}: ${VERSION_MAP} +LDFLAGS+= -Wl,--version-script=${VERSION_MAP} + +${SHLIB_NAME}: ${SOBJS} + @${ECHO} building shared library $@ + @rm -f $@ ${SHLIB_LINK} + @ln -fs $@ ${SHLIB_LINK} + ${CC} ${LOCAL_CFLAGS} ${CFLAGS} ${LOCAL_LDFLAGS} ${LDFLAGS} -shared -Wl,-x \ + -o $@ -Wl,-soname,${SONAME} \ + ${SOBJS} ${LDADD} + +install: all +ifeq (${MKSTATICLIBS},yes) + ${INSTALL} -d ${DESTDIR}${LIBDIR} + ${INSTALL} -m ${LIBMODE} lib${LIB}.a ${DESTDIR}${LIBDIR} +endif + ${INSTALL} -d ${DESTDIR}${SHLIBDIR} + ${INSTALL} -m ${LIBMODE} ${SHLIB_NAME} ${DESTDIR}${SHLIBDIR} + ln -fs ${SHLIB_NAME} ${DESTDIR}${SHLIBDIR}/${SHLIB_LINK} + ${INSTALL} -d ${DESTDIR}${INCDIR} + for x in ${INCS}; do ${INSTALL} -m ${INCMODE} $$x ${DESTDIR}${INCDIR}; done + +check test:: + +clean: + rm -f ${OBJS} ${SOBJS} ${_LIBS} ${SHLIB_LINK} ${CLEANFILES} + +extra_depend: + @TMP=depend.$$$$; \ + ${SED} -e 's/^\([^\.]*\).o[ ]*:/\1.o \1.So:/' .depend > $${TMP}; \ + mv $${TMP} .depend + +include ${MK}/sys.mk +include ${MK}/os.mk +include ${MK}/depend.mk +include ${MK}/gitignore.mk Index: contrib/openrc/mk/net.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/net.mk @@ -0,0 +1 @@ +MKNET?= yes Index: contrib/openrc/mk/os-BSD.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os-BSD.mk @@ -0,0 +1,16 @@ +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Generic definitions + +PKG_PREFIX?= /usr/local +SFX= .BSD.in + +LIBKVM?= -lkvm Index: contrib/openrc/mk/os-DragonFly.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os-DragonFly.mk @@ -0,0 +1,13 @@ +# Copyright (c) 2013-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Generic definitions + +include ${MK}/os-BSD.mk Index: contrib/openrc/mk/os-FreeBSD.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os-FreeBSD.mk @@ -0,0 +1,13 @@ +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Generic definitions + +include ${MK}/os-BSD.mk Index: contrib/openrc/mk/os-GNU-kFreeBSD.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os-GNU-kFreeBSD.mk @@ -0,0 +1,18 @@ +# Copyright (c) 2013-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Generic definitions + +SFX= .GNU-kFreeBSD.in +PKG_PREFIX?= /usr + +CPPFLAGS+= -D_BSD_SOURCE -D_XOPEN_SOURCE=700 +LIBDL= -Wl,-Bdynamic -ldl +LIBKVM?= Index: contrib/openrc/mk/os-GNU.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os-GNU.mk @@ -0,0 +1,15 @@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +SFX= .GNU.in +PKG_PREFIX?= /usr + +CPPFLAGS+= -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 -DMAXPATHLEN=4096 -DPATH_MAX=4096 +LIBDL= -Wl,-Bdynamic -ldl Index: contrib/openrc/mk/os-Linux.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os-Linux.mk @@ -0,0 +1,34 @@ +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +SFX= .Linux.in +PKG_PREFIX?= /usr + +CPPFLAGS+= -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 +LIBDL= -Wl,-Bdynamic -ldl + +ifeq (${MKSELINUX},yes) +CPPFLAGS+= -DHAVE_SELINUX +LIBSELINUX?= -lselinux +LDADD += $(LIBSELINUX) + +ifneq (${MKPAM},pam) +# if using selinux but not pam then we need crypt +LIBCRYPT?= -lcrypt +LDADD += $(LIBCRYPT) +endif + +endif + +ifeq (${MKAUDIT},yes) +LIBAUDIT?= -laudit +CPPFLAGS+= -DHAVE_AUDIT +LDADD+= ${LIBAUDIT} +endif Index: contrib/openrc/mk/os-NetBSD.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os-NetBSD.mk @@ -0,0 +1,14 @@ +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Generic definitions + +PKG_PREFIX?= /usr/pkg +include ${MK}/os-BSD.mk Index: contrib/openrc/mk/os-prefix.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os-prefix.mk @@ -0,0 +1,8 @@ +# Copyright (c) 2012 William Hubbs +# Released under the 2-clause BSD license. + +ifeq (${MKPREFIX},yes) +CPPFLAGS+= -DPREFIX +PKG_PREFIX?= $(PREFIX)/usr +SED_EXTRA= -e '/_PATH=.*usr.bin/d' +endif Index: contrib/openrc/mk/os.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/os.mk @@ -0,0 +1,19 @@ +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Generic definitions + +_OS_SH= uname -s | tr '/' '-' +_OS:= $(shell ${_OS_SH}) +OS?= ${_OS} +include ${MK}/os-prefix.mk +include ${MK}/os-${OS}.mk + +RC_LIB= /$(LIBNAME)/rc Index: contrib/openrc/mk/pam.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/pam.mk @@ -0,0 +1,16 @@ +ifeq (${MKPAM},pam) +LIBPAM?= -lpam +CPPFLAGS+= -DHAVE_PAM +LDADD+= ${LIBPAM} + +ifeq (${MKSELINUX},yes) +# with selinux, pam_misc is needed too +LIBPAM_MISC?= -lpam_misc +LDADD+= ${LIBPAM_MISC} +endif + +PAMDIR?= /etc/pam.d +PAMMODE?= 0644 +else ifneq (${MKPAM},) +$(error if MKPAM is defined, it must be "pam") +endif Index: contrib/openrc/mk/prog.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/prog.mk @@ -0,0 +1,48 @@ +# rules to build a program +# based on FreeBSD's bsd.prog.mk + +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +OBJS+= ${SRCS:.c=.o} + +# Some systems don't include /lib in their standard link path +# so we should embed it if different +# This is currently hardcoded for NetBSD which has two dynamic linkers +# and we need to use the one in /libexec instead of /usr/libexec +_DYNLINK_SH= if test "${PREFIX}" = "" && test -e /libexec/ld.elf_so; then \ + echo "-Wl,-dynamic-linker=/libexec/ld.elf_so"; \ + else \ + echo ""; \ + fi +_DYNLINK:= $(shell ${_DYNLINK_SH}) +LDFLAGS+= ${_DYNLINK} +LDFLAGS+= -Wl,-rpath=${PREFIX}/${LIBNAME} +LDFLAGS+= ${PROGLDFLAGS} + +CLEANFILES+= ${OBJS} ${PROG} + +all: depend ${PROG} + +%.o: %.c + ${CC} ${LOCAL_CFLAGS} ${LOCAL_CPPFLAGS} ${CFLAGS} ${CPPFLAGS} -c $< -o $@ + +${PROG}: ${SCRIPTS} ${OBJS} + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJS} ${LDADD} + +clean: + rm -f ${CLEANFILES} + +extra_depend: + +include ${MK}/sys.mk +include ${MK}/os.mk +include ${MK}/depend.mk +include ${MK}/gitignore.mk Index: contrib/openrc/mk/scripts.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/scripts.mk @@ -0,0 +1,65 @@ +# Install rules for our scripts +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +include ${MK}/sys.mk +include ${MK}/os.mk + +OBJS+= ${SRCS:.in=} + +_PKG_SED_SH= if test "${PREFIX}" = "${PKG_PREFIX}"; then echo "-e 's:@PKG_PREFIX@::g'"; else echo "-e 's:@PKG_PREFIX@:${PKG_PREFIX}:g'"; fi +_PKG_SED:= $(shell ${_PKG_SED_SH}) +_LCL_SED_SH= if test "${PREFIX}" = "${LOCAL_PREFIX}"; then echo "-e 's:@LOCAL_PREFIX@::g'"; else echo "-e 's:@LOCAL_PREFIX@:${LOCAL_PREFIX}:g'"; fi +_LCL_SED:= $(shell ${_LCL_SED_SH}) + +SED_REPLACE= -e 's:@SHELL@:${SH}:g' -e 's:@LIB@:${LIBNAME}:g' -e 's:@SYSCONFDIR@:${SYSCONFDIR}:g' -e 's:@LIBEXECDIR@:${LIBEXECDIR}:g' -e 's:@PREFIX@:${PREFIX}:g' -e 's:@BINDIR@:${BINDIR}:g' -e 's:@SBINDIR@:${SBINDIR}:g' ${_PKG_SED} ${_LCL_SED} + +# Tweak our shell scripts +%.sh: %.sh.in + ${SED} ${SED_REPLACE} ${SED_EXTRA} $< > $@ + +%: %.in + ${SED} ${SED_REPLACE} ${SED_EXTRA} $< > $@ + +all: ${OBJS} ${TARGETS} + +realinstall: ${BIN} ${CONF} ${INC} + @if test -n "${DIR}"; then \ + ${ECHO} ${INSTALL} -d ${DESTDIR}/${DIR}; \ + ${INSTALL} -d ${DESTDIR}/${DIR} || exit $$?; \ + fi + @if test -n "${BIN}"; then \ + ${ECHO} ${INSTALL} -m ${BINMODE} ${BIN} ${DESTDIR}/${DIR}; \ + ${INSTALL} -m ${BINMODE} ${BIN} ${DESTDIR}/${DIR} || exit $$?; \ + fi + @if test -n "${INC}"; then \ + ${ECHO} ${INSTALL} -m ${INCMODE} ${INC} ${DESTDIR}/${DIR}; \ + ${INSTALL} -m ${INCMODE} ${INC} ${DESTDIR}/${DIR} || exit $$?; \ + fi + @for x in ${CONF}; do \ + if ! test -e ${DESTDIR}/${PREFIX}${DIR}/$$x; then \ + ${ECHO} ${INSTALL} -m ${CONFMODE} $$x ${DESTDIR}/${DIR}; \ + ${INSTALL} -m ${CONFMODE} $$x ${DESTDIR}/${DIR} || exit $$?; \ + fi; \ + done + +install: all realinstall ${INSTALLAFTER} + +check test:: + @if test -e runtests.sh ; then ./runtests.sh || exit $$? ; fi + +# A lot of scripts don't have anything to clean +# Also, some rm implentation require a file argument regardless of error +# so we ensure that it has a bogus argument +CLEANFILES+= ${OBJS} +clean: + @if test -n "${CLEANFILES}"; then echo "rm -f ${CLEANFILES}"; rm -f ${CLEANFILES}; fi + +include ${MK}/gitignore.mk Index: contrib/openrc/mk/subdir.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/subdir.mk @@ -0,0 +1,38 @@ +# Recursive rules +# Adapted from FreeBSDs bsd.subdir.mk +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +_+_ ?= + +ECHODIR ?= echo +_SUBDIR = @${_+_}for x in ${SUBDIR}; do \ + if test -d $$x; then \ + ${ECHODIR} "===> ${DIRPRFX}$$x (${@:realinstall=install})"; \ + cd $$x; \ + ${MAKE} ${@:realinstall=install} \ + DIRPRFX=${DIRPRFX}$$x/ || exit $$?; \ + cd ..; \ + fi; \ +done + +all: + ${_SUBDIR} +clean: + @if test -n "${CLEANFILES}"; then echo "rm -f ${CLEANFILES}"; rm -f ${CLEANFILES}; fi + ${_SUBDIR} +realinstall: + ${_SUBDIR} +install: realinstall ${INSTALLAFTER} +check test:: + ${_SUBDIR} +depend: + ${_SUBDIR} +ignore: + ${_SUBDIR} Index: contrib/openrc/mk/sys.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/sys.mk @@ -0,0 +1,71 @@ +# Generic system definitions +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +AR?= ar +CP?= cp +PKG_CONFIG?= pkg-config +ECHO?= echo +INSTALL?= install +RANLIB?= ranlib +SED?= sed +SH= /bin/sh + +PREFIX?= +ifeq (${PREFIX},) +UPREFIX= /usr +else +UPREFIX= ${PREFIX} +ifeq (${MKPREFIX},yes) +UPREFIX= ${PREFIX}/usr +endif +endif +LOCAL_PREFIX= $(UPREFIX)/local + +PICFLAG?= -fPIC + +SYSCONFDIR?= ${PREFIX}/etc +INITDIR?= ${SYSCONFDIR}/init.d +CONFDIR?= ${SYSCONFDIR}/conf.d +CONFMODE?= 0644 +LOCALDIR?= ${SYSCONFDIR}/local.d +SYSCTLDIR?= ${SYSCONFDIR}/sysctl.d + +BINDIR?= ${PREFIX}/bin +BINMODE?= 0755 + +SBINDIR?= ${PREFIX}/sbin +SBINMODE?= 0755 + +INCDIR?= ${UPREFIX}/include +INCMODE?= 0444 + +_LIBNAME_SH= case `readlink /lib` in /lib64|lib64) echo "lib64";; *) echo "lib";; esac +_LIBNAME:= $(shell ${_LIBNAME_SH}) +LIBNAME?= ${_LIBNAME} +LIBDIR?= ${UPREFIX}/${LIBNAME} +LIBMODE?= 0444 +SHLIBDIR?= ${PREFIX}/${LIBNAME} + +LIBEXECDIR?= ${PREFIX}/libexec/rc + +MANPREFIX?= ${UPREFIX}/share +MANDIR?= ${MANPREFIX}/man +MANMODE?= 0444 + +BASHCOMPDIR?= ${UPREFIX}/share/bash-completion/completions + +DATADIR?= ${UPREFIX}/share/openrc +DATAMODE?= 0644 + +DOCDIR?= ${UPREFIX}/share/doc +DOCMODE?= 0644 + +ZSHCOMPDIR?= ${UPREFIX}/share/zsh/site-functions Index: contrib/openrc/mk/termcap.mk =================================================================== --- /dev/null +++ contrib/openrc/mk/termcap.mk @@ -0,0 +1,17 @@ +ifeq (${MKTERMCAP},ncurses) +TERMCAP_CFLAGS:= $(shell ${PKG_CONFIG} ncurses --cflags 2> /dev/null) +LTERMCAP:= $(shell ${PKG_CONFIG} ncurses --libs 2> /dev/null) +ifeq ($(LTERMCAP),) +LIBTERMCAP?= -lncurses +else +LIBTERMCAP?= $(LTERMCAP) +endif +CPPFLAGS+= -DHAVE_TERMCAP ${TERMCAP_CFLAGS} +LDADD+= ${LIBTERMCAP} +else ifeq (${MKTERMCAP},termcap) +LIBTERMCAP?= -ltermcap +CPPFLAGS+= -DHAVE_TERMCAP +LDADD+= ${LIBTERMCAP} +else ifneq (${MKTERMCAP},) +$(error If MKTERMCAP is defined, it must be ncurses or termcap) +endif Index: contrib/openrc/pkgconfig/Makefile =================================================================== --- /dev/null +++ contrib/openrc/pkgconfig/Makefile @@ -0,0 +1,12 @@ +DIR= ${LIBDIR}/pkgconfig +SRCS= einfo.pc.in openrc.pc.in +INC= einfo.pc openrc.pc + +.DEFAULT: + ${SED} -n -e 's/^VERSION=[[:space:]]*\([^[:space:]]*\).*/#define VERSION "\1${GITVER}\"/p' ../../Makefile > version.h + +SED_EXTRA= -e 's:@VERSION@:${VERSION}:g' + +MK= ../mk +include ../Makefile.inc +include ${MK}/scripts.mk Index: contrib/openrc/pkgconfig/einfo.pc.in =================================================================== --- /dev/null +++ contrib/openrc/pkgconfig/einfo.pc.in @@ -0,0 +1,9 @@ +prefix=@PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/@LIB@ +includedir=/usr/include + +Name: einfo +Description: Pretty console informational display +Version: @VERSION@ +Libs: -L${libdir} -leinfo Index: contrib/openrc/pkgconfig/openrc.pc.in =================================================================== --- /dev/null +++ contrib/openrc/pkgconfig/openrc.pc.in @@ -0,0 +1,10 @@ +prefix=@PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/@LIB@ +includedir=/usr/include + +Name: OpenRC +Description: Universal init system +Version: @VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lrc Index: contrib/openrc/runit-guide.md =================================================================== --- /dev/null +++ contrib/openrc/runit-guide.md @@ -0,0 +1,42 @@ +Using runit with OpenRC +======================= + +Beginning with OpenRC-0.21, we support using runit [1] in place of +start-stop-daemon for monitoring and restarting daemons. + +## Setup + +Documenting runit in detail is beyond the scope of this guide. It will +document how to set up OpenRC services to communicate with runit. + +### Use Default start, stop and status functions + +If you write your own start, stop and status functions in your service +script, none of this will work. You must allow OpenRC to use the default +functions. + +### Dependencies + +All OpenRC service scripts that want their daemons monitored by runit +should have the following line added to their dependencies to make sure +the runit scan directory is being monitored. + +need runsvdir + +### Variable Settings + +The most important setting is the supervisor variable. At the top of +your service script, you should set this variable as follows: + +supervisor=runit + +The second variable you need is runit_service. This is the path to the +runit service you wish to control via OpenRC. The default is +/etc/sv/${RC_SVCNAME}. This means that for an OpenRC service +/etc/init.d/foo, you will need to create the same runit service in +/etc/sv/foo. + +This is very early support, so feel free to file bugs if you have +issues. + +[1] http://www.smarden.org/runit Index: contrib/openrc/runlevels/Makefile =================================================================== --- /dev/null +++ contrib/openrc/runlevels/Makefile @@ -0,0 +1,95 @@ +include ../mk/net.mk + +BOOT= bootmisc fsck hostname localmount loopback \ + root swap sysctl urandom ${BOOT-${OS}} +DEFAULT= local netmount +NONETWORK= local +SHUTDOWN= savecache ${SHUTDOWN-${OS}} +SYSINIT= ${SYSINIT-${OS}} + +LEVELDIR= ${DESTDIR}/${SYSCONFDIR}/runlevels +SYSINITDIR= ${LEVELDIR}/sysinit +BOOTDIR= ${LEVELDIR}/boot +DEFAULTDIR= ${LEVELDIR}/default +NONETWORKDIR= ${LEVELDIR}/nonetwork +SHUTDOWNDIR= ${LEVELDIR}/shutdown + +ifeq (${MKNET},yes) +BOOT+= network staticroute +endif + +INITFILES= ../init.d + +MK= ../mk +include ${MK}/sys.mk +include ${MK}/os.mk +include ${MK}/gitignore.mk + +BOOT-${OS}= +SHUTDOWN-${OS}= +SYSINIT-${OS}= + +BOOT-BSD= hostid newsyslog savecore syslogd swap-blk + +# Generic BSD stuff +BOOT-FreeBSD+= hostid modules newsyslog savecore syslogd +# FreeBSD specific stuff +BOOT-FreeBSD+= adjkerntz dumpon syscons + +BOOT-Linux+= binfmt hwclock keymaps modules mtab procfs termencoding +SHUTDOWN-Linux= killprocs mount-ro +SYSINIT-Linux= devfs cgroups dmesg sysfs + +# Generic BSD stuff +BOOT-NetBSD+= hostid newsyslog savecore syslogd +# NetBSD specific stuff +BOOT-NetBSD+= devdb swap-blk ttys wscons + +all: + +install: + if ! test -d "${SYSINITDIR}"; then \ + ${INSTALL} -d ${SYSINITDIR} || exit $$?; \ + for x in ${SYSINIT}; do \ + if test "${MKPREFIX}" = yes; then \ + grep -q "keyword .*-prefix" ${INITFILES}/"$$x" && continue; \ + fi; \ + ln -snf ${INITDIR}/"$$x" ${SYSINITDIR}/"$$x" || exit $$?; done \ + fi + if ! test -d "${BOOTDIR}"; then \ + ${INSTALL} -d ${BOOTDIR} || exit $$?; \ + for x in ${BOOT}; do \ + if test "${MKPREFIX}" = yes; then \ + grep -q "keyword .*-prefix" ${INITFILES}/"$$x" && continue; \ + fi; \ + ln -snf ${INITDIR}/"$$x" ${BOOTDIR}/"$$x" || exit $$?; \ + done \ + fi + if ! test -d "${DEFAULTDIR}"; then \ + ${INSTALL} -d ${DEFAULTDIR} || exit $$?; \ + for x in ${DEFAULT}; do \ + if test "${MKPREFIX}" = yes; then \ + grep -q "keyword .*-prefix" ${INITFILES}/"$$x" && continue; \ + fi; \ + ln -snf ${INITDIR}/"$$x" ${DEFAULTDIR}/"$$x" || exit $$?; done \ + fi + if ! test -d "${NONETWORKDIR}"; then \ + ${INSTALL} -d ${NONETWORKDIR} || exit $$?; \ + for x in ${NONETWORK}; do \ + if test "${MKPREFIX}" = yes; then \ + grep -q "keyword .*-prefix" ${INITFILES}/"$$x" && continue; \ + fi; \ + ln -snf ${INITDIR}/"$$x" ${NONETWORKDIR}/"$$x" || exit $$?; done \ + fi + if ! test -d "${SHUTDOWNDIR}"; then \ + ${INSTALL} -d ${SHUTDOWNDIR} || exit $$?; \ + for x in ${SHUTDOWN}; do \ + if test "${MKPREFIX}" = yes; then \ + grep -q "keyword .*-prefix" ${INITFILES}/"$$x" && continue; \ + fi; \ + ln -snf ${INITDIR}/"$$x" ${SHUTDOWNDIR}/"$$x" || exit $$?; done \ + fi + +check test:: + +clean: Index: contrib/openrc/s6-guide.md =================================================================== --- /dev/null +++ contrib/openrc/s6-guide.md @@ -0,0 +1,53 @@ +Using S6 with OpenRC +==================== + +Beginning with OpenRC-0.16, we support using the s6 supervision suite +from Skarnet Software in place of start-stop-daemon for monitoring +daemons [1]. + +## Setup + +Documenting s6 in detail is beyond the scope of this guide. It will +document how to set up OpenRC services to communicate with s6. + +### Use Default start, stop and status functions + +If you write your own start, stop and status functions in your service +script, none of this will work. You must allow OpenRC to use the default +functions. + +### Dependencies + +All OpenRC service scripts that want their daemons monitored by s6 +should have the following line added to their dependencies to make sure +the s6 scan directory is being monitored. + +need s6-svscan + +### Variable Settings + +The most important setting is the supervisor variable. At the top of +your service script, you should set this variable as follows: + +supervisor=s6 + +Several other variables affect s6 services. They are documented on the +openrc-run man page, but I will list them here for convenience: + +s6_service_path - the path to the s6 service directory. The default is +/var/svc.d/$RC_SVCNAME. + +s6_svwait_options_start - the options to pass to s6-svwait when starting +the service. If this is not set, s6-svwait will not be called. + +s6_force_kill - Should we try to force kill this service if the +s6_service_timeout_stop timeout expires when shutting down this service? +The default is yes. + +s6_service_timeout_stop - the amount of time, in milliseconds, s6-svc +should wait for a service to go down when stopping. + +This is very early support, so feel free to file bugs if you have +issues. + +[1] http://www.skarnet.org/software/s6 Index: contrib/openrc/scripts/Makefile =================================================================== --- /dev/null +++ contrib/openrc/scripts/Makefile @@ -0,0 +1,30 @@ +MK= ../mk +include ${MK}/os.mk + +DIR= ${LIBEXECDIR}/bin +BIN= on_ac_power +INSTALLAFTER = _installafter + +ifeq (${OS},Linux) +SRCS+= rc-sstat.in +BIN+= rc-sstat +ifeq (${MKSYSVINIT},yes) +SRCS+= halt.in poweroff.in reboot.in shutdown.in +BIN+= halt poweroff reboot shutdown + endif +endif + +_installafter: +ifeq (${OS},Linux) + ${INSTALL} -d ${DESTDIR}${SBINDIR} + ln -sf ${DIR}/rc-sstat ${DESTDIR}/${SBINDIR}/rc-sstat +ifeq (${MKSYSVINIT},yes) + ln -sf ${DIR}/halt ${DESTDIR}/${SBINDIR}/halt + ln -sf ${DIR}/poweroff ${DESTDIR}/${SBINDIR}/poweroff + ln -sf ${DIR}/reboot ${DESTDIR}/${SBINDIR}/reboot + ln -sf ${DIR}/shutdown ${DESTDIR}/${SBINDIR}/shutdown + ln -sf openrc-init ${DESTDIR}/${SBINDIR}/init +endif +endif + +include ${MK}/scripts.mk Index: contrib/openrc/scripts/halt.in =================================================================== --- /dev/null +++ contrib/openrc/scripts/halt.in @@ -0,0 +1,24 @@ +#!@SHELL@ + +option_arg= +poweroff_arg= +while getopts :nwdfiph opt; do + case "$opt" in + n) ;; + w) poweroff_arg=--write-only ;; + d) option_arg=--no-write ;; + f) ;; + i) ;; + p) poweroff_arg=--poweroff ;; + [?]) printf "%s\n" "${0##*/}: invalid command line option" >&2 + exit 1 + ;; + esac +done +shift $((OPTIND-1)) + +if [ -z "${poweroff_arg}" ]; then + poweroff_arg=--poweroff +fi + +exec @SBINDIR@/openrc-shutdown ${option_arg} ${poweroff_arg} "$@" Index: contrib/openrc/scripts/on_ac_power =================================================================== --- /dev/null +++ contrib/openrc/scripts/on_ac_power @@ -0,0 +1,46 @@ +#!/bin/sh +# Detect AC power or not in a portable way +# Exit 0 if on AC power, 1 if not and 255 if we don't know how to work it out + +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +if [ -f /proc/acpi/ac_adapter/*/state ]; then + cat /proc/acpi/ac_adapter/*/state | while read line; do + case "$line" in + "state:"*"off-line") exit 128;; + esac + done +elif [ -f /sys/class/power_supply/*/online ]; then + cat /sys/class/power_supply/*/online | while read line; do + [ "${line}" = 0 ] && exit 128 + done +elif [ -f /proc/pmu/info ]; then + cat /proc/pmu/info | while read line; do + case "$line" in + "AC Power"*": 0") exit 128;; + esac + done +elif command -v envstat >/dev/null 2>&1; then + # NetBSD has envstat + envstat -d acpiacad0 2>/dev/null | while read line; do + case "$line" in + "connected:"*"OFF") exit 128;; + esac + done +elif sysctl -q hw.acpi.acline >/dev/null 2>/dev/null; then + case $(sysctl -n hw.acpi.acline) in + 0) exit 1;; + *) exit 0;; + esac +else + exit 255 +fi +[ $? != 128 ] Index: contrib/openrc/scripts/poweroff.in =================================================================== --- /dev/null +++ contrib/openrc/scripts/poweroff.in @@ -0,0 +1,23 @@ +#!@SHELL@ + +option_arg= +poweroff_arg= +while getopts :nwdfiph opt; do + case "$opt" in + n) ;; + w) poweroff_arg=--write-only ;; + d) option_arg=--no-write ;; + f) ;; + i) ;; + [?]) printf "%s\n" "${0##*/}: invalid command line option" >&2 + exit 1 + ;; + esac +done +shift $((OPTIND-1)) + +if [ -z "${poweroff_arg}" ]; then + poweroff_arg=--poweroff +fi + +exec @SBINDIR@/openrc-shutdown ${option_arg} ${poweroff_arg} "$@" Index: contrib/openrc/scripts/rc-sstat.in =================================================================== --- /dev/null +++ contrib/openrc/scripts/rc-sstat.in @@ -0,0 +1,149 @@ +#!@SHELL@ +# Copyright (c) 2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Define variables +scandir="/run/openrc/s6-scan" +statfile=/dev/shm/s6-svstat.${USER} + +color_red='\E[01;31m' +color_green='\E[32m' +color_yellow='\E[01;33m' + +# Time Modules +uptimeModules() { + # Given a single integer argument representing seconds of uptime... + # convert uptime to a friendly human readable string: '2d 16h 58m 46s' + # define a variable to keep track of the longest length uptime string + uSec=${1:-0} + + uDay=$(( $uSec / 86400 )) + uSec=$(( $uSec % 86400 )) + uHour=$(( $uSec / 3600 )) + uSec=$(( $uSec % 3600 )) + uMin=$(( $uSec / 60 )) + uSec=$(( $uSec % 60 )) + + [ $uDay -ne 0 ] && pDay="${uDay}d " || pDay="" + [ $uHour -ne 0 ] && pHour="${uHour}h " || pHour="" + [ $uMin -ne 0 ] && pMin="${uMin}m " || pMin="" + [ $uSec -ne 0 ] && pSec="${uSec}s " || pSec="" + + parsedUptime="$( echo ${pDay}${pHour}${pMin}${pSec} | sed 's#[ \t]*$##' )" + uCharCount=${#parsedUptime} +} + +# Make sure we are running as root +if [ $(id -u) != 0 ]; then + printf "This command must be run as root\n" + exit 1 +fi + +# Make sure scandir exists +if [ ! -d $scandir ]; then + printf "%s\n" "$scandir does not exist" + exit 1 +fi + +# Make sure s6-svscan is running +if ! pgrep s6-svscan >/dev/null ; then + printf "s6-svscan is not running\n" + exit 1 +fi + +# If TERM is undefined (launching sstat through an ssh command) then make it vt100 +if [ -z $TERM -o $TERM = "dumb" ]; then + export TERM=vt100 +fi + +# Gather list of candidate services s6-supervise may be supervising +# filter for folders and symlinks at /run/openrc/s6-scan/* ommiting output starting with '.' +services="$(find $scandir -maxdepth 1 -mindepth 1 \( -type d -or -type l \) | awk -F'/' '{ if ( $NF !~ "^\\." ) print $NF}')" +if [ -z "$services" ]; then + printf "s6 found no services configured for supervision\n" + exit 1 +fi + +# Gather status for each service from s6-svstat +# write to tmp file in memory for non I/O bound repeatative access +rm -f $statfile 2>/dev/null +for service in $services ; do + echo "$service $(s6-svstat ${scandir}/${service})" >> $statfile +done + +# Define longest string from parsed uptime (default to 7 to match string length of 'Up Time') +timeStringLength=7 +for uptime in $(awk '$2 == "up" {print $5}' $statfile | sort -run) +do + uptimeModules $uptime + [ ${uCharCount} -gt $timeStringLength ] && timeStringLength=$uCharCount +done + + +# Print the status header like so... +# Service Name State PID Up Time Start Time +#---------------------------- ----- ----- -------------- ------------------- +printf "\n" +printf "%28s %5s %5s %${timeStringLength}s %19s\n" "Service Name" "State" "PID" "Up Time" "Start Time" +for dashes in 28 5 5 $timeStringLength 19 ; do + printf "%0.s-" $(seq 1 $dashes) ; echo -n ' ' +done && printf "\n" + + +# sshd up (pid 26300) 80373 seconds +cat $statfile | \ +while read line +do + set $line + + service=$1 + state=$2 + pid=${4/)/} + time=$5 + + # call function to convert time in seconds and define additional variables + uptimeModules $time + + if [ "$state" = up ]; then + if [ $time -lt 30 ]; then + # uptime < 30 seconds, color the whole line yellow + echo -en "$color_yellow" + # 1st 4 columns are printed with printf for space padding + printf "%28s %5s %5s %${timeStringLength}s" $service $state $pid "$parsedUptime" + # 4th column is output from date -d + echo -e " $(date -d "${time} seconds ago" "+%F %T")" + # reset terminal colors + tput sgr0 + else + printf "%28s" $service + # uptime > 30 seconds, color just the "state" value green + echo -en "$color_green" + printf " %5s" $state + # reset terminal colors + tput sgr0 + printf " %5s" $pid + printf " %${timeStringLength}s" "$parsedUptime" + echo -e " $(date -d "${time} seconds ago" "+%F %T")" + fi + else + printf "%28s" $service + echo -en "$color_red" + printf " %5s" $state + tput sgr0 + echo "" + fi +done + +# Cleanup +rm -f $statfile 2>/dev/null + +printf "\n\n" + +rc-status Index: contrib/openrc/scripts/reboot.in =================================================================== --- /dev/null +++ contrib/openrc/scripts/reboot.in @@ -0,0 +1,25 @@ +#!@SHELL@ + +option_arg= +poweroff_arg= +while getopts :nwdfhik opt; do + case "$opt" in + n) ;; + w) poweroff_arg=--write-only ;; + d) option_arg=--no-write ;; + f) ;; + h) ;; + i) ;; + k) poweroff_arg=--kexec ;; + [?]) printf "%s\n" "${0##*/}: invalid command line option" >&2 + exit 1 + ;; + esac +done +shift $((OPTIND-1)) + +if [ -z "${poweroff_arg}" ]; then + poweroff_arg=--reboot +fi + +exec @SBINDIR@/openrc-shutdown ${option_arg} ${poweroff_arg} "$@" Index: contrib/openrc/scripts/shutdown.in =================================================================== --- /dev/null +++ contrib/openrc/scripts/shutdown.in @@ -0,0 +1,29 @@ +#!@SHELL@ + +shutdown_arg= +while getopts :akrhPHfFnct: opt; do + case "$opt" in + a) ;; + k) ;; + r) shutdown_arg=--reboot ;; + h) shutdown_arg=--halt ;; + P) shutdown_arg=--poweroff ;; + H) shutdown_arg=--halt ;; + f) ;; + F) ;; + n) ;; + c) ;; + t) ;; + [?]) printf "%s\n" "${0##*/}: invalid command line option" >&2 + exit 1 + ;; + esac +done +shift $((OPTIND-1)) + +if [ -z "${shutdown_arg}" ]; then + shutdown_arg=--single +fi + +echo @SBINDIR@/openrc-shutdown ${shutdown_arg} "$@" +exec @SBINDIR@/openrc-shutdown ${shutdown_arg} "$@" Index: contrib/openrc/service-script-guide.md =================================================================== --- /dev/null +++ contrib/openrc/service-script-guide.md @@ -0,0 +1,493 @@ +OpenRC Service Script Writing Guide +=================================== + +This document is aimed at developers or packagers who +write OpenRC service scripts, either for their own projects, or for +the packages they maintain. It contains advice, suggestions, tips, +tricks, hints, and counsel; cautions, warnings, heads-ups, +admonitions, proscriptions, enjoinders, and reprimands. + +It is intended to prevent common mistakes that are found "in the wild" +by pointing out those mistakes and suggesting alternatives. Each +good/bad thing that you should/not do has a section devoted to it. We +don't consider anything exotic, and assume that you will use +start-stop-daemon to manage a fairly typical long-running UNIX +process. + +# Syntax of Service Scripts + +Service scripts are shell scripts. OpenRC aims at using only the standardized +POSIX sh subset for portability reasons. The default interpreter (build-time +toggle) is `/bin/sh`, so using for example mksh is not a problem. + +OpenRC has been tested with busybox sh, ash, dash, bash, mksh, zsh and possibly +others. Using busybox sh has been difficult as it replaces commands with +builtins that don't offer the expected features. + +The interpreter for service scripts is `#!/sbin/openrc-run`. +Not using this interpreter will break the use of dependencies and is not +supported. (iow: if you insist on using `#!/bin/sh` you're on your own) + +A `depend` function declares the dependencies of this service script. +All scripts must have start/stop/status functions, but defaults are provided and should be used unless you have a very strong reason not to use them. + +Extra functions can be added easily: + +``` +extra_commands="checkconfig" +checkconfig() { + doSomething +} +``` + +This exports the checkconfig function so that `/etc/init.d/someservice +checkconfig` will be available, and it "just" runs this function. + +While commands defined in `extra_commands` are always available, commands +defined in `extra_started_commands` will only work when the service is started +and those defined in `extra_stopped_commands` will only work when the service is +stopped. This can be used for implementing graceful reload and similar +behaviour. + +Adding a restart function will not work, this is a design decision within +OpenRC. Since there may be dependencies involved (e.g. network -> apache) a +restart function is in general not going to work. +restart is internally mapped to `stop()` + `start()` (plus handling dependencies). +If a service needs to behave differently when it is being restarted vs +started or stopped, it should test the `$RC_CMD` variable, for example: + +``` +[ "$RC_CMD" = restart ] && do_something +``` + +# The Depend Function + +This function declares the dependencies for a service script. This +determines the order the service scripts start. + +``` +depend() { + need net + use dns logger netmount + want coolservice +} +``` + +`need` declares a hard dependency - net always needs to be started before this + service does + +`use` is a soft dependency - if dns, logger or netmount is in this runlevel + start it before, but we don't care if it's not in this runlevel. + `want` is between need and use - try to start coolservice if it is + installed on the system, regardless of whether it is in the + runlevel, but we don't care if it starts. + +`before` declares that we need to be started before another service + +`after` declares that we need to be started after another service, without + creating a dependency (so on calling stop the two are independent) + +`provide` allows multiple implementations to provide one service type, e.g.: + `provide cron` is set in all cron-daemons, so any one of them started + satisfies a cron dependency + +`keyword` allows platform-specific overrides, e.g. `keyword -lxc` makes this + service script a noop in lxc containers. Useful for things like keymaps, + module loading etc. that are either platform-specific or not available + in containers/virtualization/... + +FIXME: Anything missing in this list? + +# The Default Functions + +All service scripts are assumed to have the following functions: + +``` +start() +stop() +status() +``` + +There are default implementations in `lib/rc/sh/openrc-run.sh` - this allows very +compact service scripts. These functions can be overridden per service script as +needed. + +The default functions assume the following variables to be set in the service +script: + +``` +command= +command_args= +pidfile= +``` + +Thus the 'smallest' service scripts can be half a dozen lines long + +## Don't write your own start/stop functions + +OpenRC is capable of stopping and starting most daemons based on the +information that you give it. For a well-behaved daemon that +backgrounds itself and writes its own PID file by default, the +following OpenRC variables are likely all that you'll need: + + * command + * command_args + * pidfile + +Given those three pieces of information, OpenRC will be able to start +and stop the daemon on its own. The following is taken from an +[OpenNTPD](http://www.openntpd.org/) service script: + +```sh +command="/usr/sbin/ntpd" + +# The special RC_SVCNAME variable contains the name of this service. +pidfile="/run/${RC_SVCNAME}.pid" +command_args="-p ${pidfile}" +``` + +If the daemon runs in the foreground by default but has options to +background itself and to create a pidfile, then you'll also need + + * command_args_background + +That variable should contain the flags needed to background your +daemon, and to make it write a PID file. Take for example the +following snippet of an +[NRPE](https://github.com/NagiosEnterprises/nrpe) service script: + +```sh +command="/usr/bin/nrpe" +command_args="--config=/etc/nagios/nrpe.cfg" +command_args_background="--daemon" +pidfile="/run/${RC_SVCNAME}.pid" +``` + +Since NRPE runs as *root* by default, it needs no special permissions +to write to `/run/nrpe.pid`. OpenRC takes care of starting and +stopping the daemon with the appropriate arguments, even passing the +`--daemon` flag during startup to force NRPE into the background (NRPE +knows how to write its own PID file). + +But what if the daemon isn't so well behaved? What if it doesn't know +how to background itself or create a pidfile? If it can do neither, +then use, + + * command_background=true + +which will additionally pass `--make-pidfile` to start-stop-daemon, +causing it to create the `$pidfile` for you (rather than the daemon +itself being responsible for creating the PID file). + +If your daemon doesn't know how to change its own user or group, then +you can tell start-stop-daemon to launch it as an unprivileged user +with + + * command_user="user:group" + +Finally, if your daemon always forks into the background but fails to +create a PID file, then your only option is to use + + * procname + +With `procname`, OpenRC will try to find the running daemon by +matching the name of its process. That's not so reliable, but daemons +shouldn't background themselves without creating a PID file in the +first place. The next example is part of the [CA NetConsole +Daemon](https://oss.oracle.com/projects/cancd/) service script: + +```sh +command="/usr/sbin/cancd" +command_args="-p ${CANCD_PORT} + -l ${CANCD_LOG_DIR} + -o ${CANCD_LOG_FORMAT}" +command_user="cancd" + +# cancd daemonizes itself, but doesn't write a PID file and doesn't +# have an option to run in the foreground. So, the best we can do +# is try to match the process name when stopping it. +procname="cancd" +``` + +To recap, in order of preference: + + 1. If the daemon backgrounds itself and creates its own PID file, use + `pidfile`. + 2. If the daemon does not background itself (or has an option to run + in the foreground) and does not create a PID file, then use + `command_background=true` and `pidfile`. + 3. If the daemon backgrounds itself and does not create a PID file, + use `procname` instead of `pidfile`. But, if your daemon has the + option to run in the foreground, then you should do that instead + (that would be the case in the previous item). + 4. The last case, where the daemon does not background itself but + does create a PID file, doesn't make much sense. If there's a way + to disable the daemon's PID file (or, to write it straight into the + garbage), then do that, and use `command_background=true`. + +## Reloading your daemon's configuration + +Many daemons will reload their configuration files in response to a +signal. Suppose your daemon will reload its configuration in response +to a `SIGHUP`. It's possible to add a new "reload" command to your +service script that performs this action. First, tell the service +script about the new command. + +```sh +extra_started_commands="reload" +``` + +We use `extra_started_commands` as opposed to `extra_commands` because +the "reload" action is only valid while the daemon is running (that +is, started). Now, start-stop-daemon can be used to send the signal to +the appropriate process (assuming you've defined the `pidfile` +variable elsewhere): + +```sh +reload() { + ebegin "Reloading ${RC_SVCNAME}" + start-stop-daemon --signal HUP --pidfile "${pidfile}" + eend $? +} +``` + +## Don't restart/reload with a broken config + +Often, users will start a daemon, make some configuration change, and +then attempt to restart the daemon. If the recent configuration change +contains a mistake, the result will be that the daemon is stopped but +then cannot be started again (due to the configuration error). It's +possible to prevent that situation with a function that checks for +configuration errors, and a combination of the `start_pre` and +`stop_pre` hooks. + +```sh +checkconfig() { + # However you want to check this... +} + +start_pre() { + # If this isn't a restart, make sure that the user's config isn't + # busted before we try to start the daemon (this will produce + # better error messages than if we just try to start it blindly). + # + # If, on the other hand, this *is* a restart, then the stop_pre + # action will have ensured that the config is usable and we don't + # need to do that again. + if [ "${RC_CMD}" != "restart" ] ; then + checkconfig || return $? + fi +} + +stop_pre() { + # If this is a restart, check to make sure the user's config + # isn't busted before we stop the running daemon. + if [ "${RC_CMD}" = "restart" ] ; then + checkconfig || return $? + fi +} +``` + +To prevent a *reload* with a broken config, keep it simple: + +```sh +reload() { + checkconfig || return $? + ebegin "Reloading ${RC_SVCNAME}" + start-stop-daemon --signal HUP --pidfile "${pidfile}" + eend $? +} +``` + +## PID files should be writable only by root + +PID files must be writable only by *root*, which means additionally +that they must live in a *root*-owned directory. This directory is +normally /run under Linux and /var/run under other operating systems. + +Some daemons run as an unprivileged user account, and create their PID +files (as the unprivileged user) in a path like +`/var/run/foo/foo.pid`. That can usually be exploited by the unprivileged +user to kill *root* processes, since when a service is stopped, *root* +usually sends a SIGTERM to the contents of the PID file (which are +controlled by the unprivileged user). The main warning sign for that +problem is using `checkpath` to set ownership on the directory +containing the PID file. For example, + +```sh +# BAD BAD BAD BAD BAD BAD BAD BAD +start_pre() { + # Ensure that the pidfile directory is writable by the foo user/group. + checkpath --directory --mode 0700 --owner foo:foo "/var/run/foo" +} +# BAD BAD BAD BAD BAD BAD BAD BAD +``` + +If the *foo* user owns `/var/run/foo`, then he can put whatever he wants +in the `/var/run/foo/foo.pid` file. Even if *root* owns the PID file, the +*foo* user can delete it and replace it with his own. To avoid +security concerns, the PID file must be created as *root* and live in +a *root*-owned directory. If your daemon is responsible for forking +and writing its own PID file but the PID file is still owned by the +unprivileged runtime user, then you may have an upstream issue. + +Once the PID file is being created as *root* (before dropping +privileges), it can be written directly to a *root*-owned +directory. For example, the *foo* daemon might write +`/var/run/foo.pid`. No calls to checkpath are needed. Note: there is +nothing technically wrong with using a directory structure like +`/var/run/foo/foo.pid`, so long as *root* owns the PID file and the +directory containing it. + +Ideally (see "Upstream your service scripts"), your service script +will be integrated upstream and the build system will determine the +appropriate directory for the pid file. For example, + +```sh +pidfile="@piddir@/${RC_SVCNAME}.pid" +``` + +A decent example of this is the [Nagios core service +script](https://github.com/NagiosEnterprises/nagioscore/blob/master/openrc-init.in), +where the full path to the PID file is specified at build-time. + +## Don't let the user control the PID file location + +It's usually a mistake to let the end user control the PID file +location through a conf.d variable, for a few reasons: + + 1. When the PID file path is controlled by the user, you need to + ensure that its parent directory exists and is writable. This + adds unnecessary code to the service script. + + 2. If the PID file path changes while the service is running, then + you'll find yourself unable to stop the service. + + 3. The directory that should contain the PID file is best determined + by the upstream build system (see "Upstream your service scripts"). + On Linux, the preferred location these days is `/run`. Other systems + still use `/var/run`, though, and a `./configure` script is the + best place to decide which one you want. + + 4. Nobody cares where the PID file is located, anyway. + +Since OpenRC service names must be unique, a value of + +```sh +pidfile="/var/run/${RC_SVCNAME}.pid" +``` + +guarantees that your PID file has a unique name. + +## Upstream your service scripts (for packagers) + +The ideal place for an OpenRC service script is **upstream**. Much like +systemd services, a well-crafted OpenRC service script should be +distribution-agnostic, and the best place for it is upstream. Why? For +two reasons. First, having it upstream means that there's a single +authoritative source for improvements. Second, a few paths in every +service script are dependent upon flags passed to the build system. For +example, + +```sh +command=/usr/bin/foo +``` + +in an autotools-based build system should really be + +```sh +command=@bindir@/foo +``` + +so that the user's value of `--bindir` is respected. If you keep the +service script in your own distribution's repository, then you have to +keep the command path and package synchronized yourself, and that's no +fun. + +## Be wary of "need net" dependencies + +There are two things you need to know about "need net" dependencies: + + 1. They are not satisfied by the loopback interface, so "need net" + requires some *other* interface to be up. + + 2. Depending on the value of `rc_depend_strict` in `rc.conf`, the + "need net" will be satisfied when either *any* non-loopback + interface is up, or when *all* non-loopback interfaces are up. + +The first item means that "need net" is wrong for daemons that are +happy with `0.0.0.0`, and the second point means that "need net" is +wrong for daemons that need a particular (for example, the WAN) +interface. We'll consider the two most common users of "need net"; +network clients who access some network resource, and network servers +who provide them. + +### Network clients + +Network clients typically want the WAN interface to be up. That may +tempt you to depend on the WAN interface; but first, you should ask +yourself a question: does anything bad happen if the WAN interface is +not available? In other words, if the administrator wants to disable +the WAN, should the service be stopped? Usually the answer to that +question is "no," and in that case, you should forego the "net" +dependency entirely. + +Suppose, for example, that your service retrieves virus signature +updates from the internet. In order to do its job correctly, it needs +a (working) internet connection. However, the service itself does not +require the WAN interface to be up: if it is, great; otherwise, the +worst that will happen is that a "server unavailable" warning will be +logged. The signature update service will not crash, and—perhaps more +importantly—you don't want it to terminate if the administrator turns +off the WAN interface for a second. + +### Network servers + +Network servers are generally easier to handle than their client +counterparts. Most server daemons listen on `0.0.0.0` (all addresses) +by default, and are therefore satisfied to have the loopback interface +present and operational. OpenRC ships with the loopback service in the +*boot* runlevel, and therefore most server daemons require no further +network dependencies. + +The exceptions to this rule are those daemons who produce negative +side-effects when the WAN is unavailable. For example, the Nagios +server daemon will generate "the sky is falling" alerts for as long as +your monitored hosts are unreachable. So in that case, you should +require some other interface (often the WAN) to be up. A "need" +dependency would be appropriate, because you want Nagios to be +stopped before the network is taken down. + +If your daemon can optionally be configured to listen on a particular +interface, then please see the "Depending on a particular interface" +section. + +### Depending on a particular interface + +If you need to depend on one particular interface, usually it's not +easy to determine programmatically what that interface is. For +example, if your *sshd* daemon listens on `192.168.1.100` (rather than +`0.0.0.0`), then you have two problems: + + 1. Parsing `sshd_config` to figure that out; and + + 2. Determining which network service name corresponds to the + interface for `192.168.1.100`. + +It's generally a bad idea to parse config files in your service +scripts, but the second problem is the harder one. Instead, the most +robust (i.e. the laziest) approach is to make the user specify the +dependency when he makes a change to sshd_config. Include something +like the following in the service configuration file, + +```sh +# Specify the network service that corresponds to the "bind" setting +# in your configuration file. For example, if you bind to 127.0.0.1, +# this should be set to "loopback" which provides the loopback interface. +rc_need="loopback" +``` + +This is a sensible default for daemons that are happy with `0.0.0.0`, +but lets the user specify something else, like `rc_need="net.wan"` if +he needs it. The burden is on the user to determine the appropriate +service whenever he changes the daemon's configuration file. Index: contrib/openrc/sh/.gitignore =================================================================== --- /dev/null +++ contrib/openrc/sh/.gitignore @@ -0,0 +1,10 @@ +functions.sh +gendepends.sh +rc-functions.sh +openrc-run.sh +cgroup-release-agent.sh +init.sh +init-early.sh +rc-cgroup.sh +migrate-to-run.sh +binfmt.sh Index: contrib/openrc/sh/Makefile =================================================================== --- /dev/null +++ contrib/openrc/sh/Makefile @@ -0,0 +1,35 @@ +DIR= ${LIBEXECDIR}/sh +SRCS= init.sh.in functions.sh.in gendepends.sh.in \ + openrc-run.sh.in rc-functions.sh.in ${SRCS-${OS}} +INC= rc-mount.sh functions.sh rc-functions.sh runit.sh s6.sh \ + start-stop-daemon.sh supervise-daemon.sh +BIN= gendepends.sh init.sh openrc-run.sh ${BIN-${OS}} + +INSTALLAFTER= _installafter + +MK= ../mk +include ${MK}/os.mk + +SRCS-FreeBSD= +BIN-FreeBSD= + +SRCS-Linux= binfmt.sh.in cgroup-release-agent.sh.in init-early.sh.in \ + migrate-to-run.sh.in rc-cgroup.sh.in +BIN-Linux= binfmt.sh cgroup-release-agent.sh init-early.sh migrate-to-run.sh \ + rc-cgroup.sh + +SRCS-NetBSD= +BIN-NetBSD= + +include ${MK}/scripts.mk + +%.sh: %.sh${SFX} + ${SED} ${SED_REPLACE} ${SED_EXTRA} $< > $@ + +_installafter: + ${INSTALL} -d ${DESTDIR}/${INITDIR} + @# Put functions.sh into init for backwards compat + ln -snf ${LIBEXECDIR}/sh/functions.sh ${DESTDIR}/${INITDIR} || exit $$? + +check test:: + ./runtests.sh Index: contrib/openrc/sh/binfmt.sh.in =================================================================== --- /dev/null +++ contrib/openrc/sh/binfmt.sh.in @@ -0,0 +1,90 @@ +#!@SHELL@ +# This is a reimplementation of the systemd binfmt.d code to register +# misc binary formats with the kernel. +# +# See the binfmt.d manpage as well: +# http://0pointer.de/public/systemd-man/binfmt.d.html +# This script should match the manpage as of 2015/03/31 + +# Copyright (c) 2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. +apply_file() { + [ $# -lt 1 ] && return 0 + FILE="$1" + LINENUM=0 + + ### FILE FORMAT ### + # See https://www.kernel.org/doc/Documentation/binfmt_misc.txt + while read -r line; do + LINENUM=$(( LINENUM+1 )) + case $line in + \#*) continue ;; + \;*) continue ;; + esac + + echo "${line}" > /proc/sys/fs/binfmt_misc/register + rc=$? + if [ $rc -ne 0 ]; then + printf "binfmt: invalid entry on line %d of \`%s'\n" \ + "$LINENUM" "$FILE" >&2 + error=1 + fi + done <$FILE + return $rc +} + +[ -e /proc/sys/fs/binfmt_misc/register ] || exit 0 +error=0 +if [ $# -gt 0 ]; then + while [ $# -gt 0 ]; do + apply_file "$1" + shift + done +else + # The hardcoding of these paths is intentional; we are following the + # systemd spec. + binfmt_dirs='/usr/lib/binfmt.d/ /run/binfmt.d/ /etc/binfmt.d/' + binfmt_basenames='' + binfmt_d='' + + # Build a list of sorted unique basenames + # directories declared later in the binfmt_d list will override earlier + # directories, on a per file basename basis. + # `/run/binfmt.d/foo.conf' supersedes `/usr/lib/binfmt.d/foo.conf'. + # `/run/binfmt.d/foo.conf' will always be read after `/etc/binfmt.d/bar.conf' + for d in ${binfmt_dirs} ; do + [ -d $d ] && for f in ${d}/*.conf ; do + case "${f##*/}" in + systemd.conf|systemd-*.conf) continue;; + esac + [ -e $f ] && binfmt_basenames="${binfmt_basenames}\n${f##*/}" + done # for f in ${d} + done # for d in ${binfmt_dirs} + binfmt_basenames="$(printf "${binfmt_basenames}\n" | sort -u )" + + for b in $binfmt_basenames ; do + real_f='' + for d in $binfmt_dirs ; do + f=${d}/${b} + [ -e "${f}" ] && real_f=$f + done + [ -e "${real_f}" ] && binfmt_d="${binfmt_d} ${real_f}" + done + + # loop through the gathered fragments, sorted globally by filename. + # `/run/binfmt.d/foo.conf' will always be read after `/etc/binfmt.d/bar.conf' + for FILE in $binfmt_d ; do + apply_file "$FILE" + done +fi + +exit $error + +# vim: set ts=2 sw=2 sts=2 noet ft=sh: Index: contrib/openrc/sh/cgroup-release-agent.sh.in =================================================================== --- /dev/null +++ contrib/openrc/sh/cgroup-release-agent.sh.in @@ -0,0 +1,19 @@ +#!@SHELL@ +# This is run by the kernel after the last task is removed from a +# control group in the openrc hierarchy. + +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +cgroup=/sys/fs/cgroup/openrc +PATH=/bin:/usr/bin:/sbin:/usr/sbin +if [ -d ${cgroup}/"$1" ]; then + rmdir ${cgroup}/"$1" +fi Index: contrib/openrc/sh/functions.sh.in =================================================================== --- /dev/null +++ contrib/openrc/sh/functions.sh.in @@ -0,0 +1,173 @@ +# Allow any sh script to work with einfo functions and friends +# We also provide a few helpful functions for other programs to use + +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +RC_GOT_FUNCTIONS="yes" + +eindent() +{ + : $(( EINFO_INDENT = ${EINFO_INDENT:-0} + 2 )) + [ "$EINFO_INDENT" -gt 40 ] && EINFO_INDENT=40 + export EINFO_INDENT +} + +eoutdent() +{ + : $(( EINFO_INDENT = ${EINFO_INDENT:-0} - 2 )) + [ "$EINFO_INDENT" -lt 0 ] && EINFO_INDENT=0 + return 0 +} + +checkyesno() +{ + yesno $1 + return $? +} + +yesno() +{ + [ -z "$1" ] && return 1 + + # Check the value directly so people can do: + # yesno ${VAR} + case "$1" in + [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) return 0;; + [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) return 1;; + esac + + # Check the value of the var so people can do: + # yesno VAR + # Note: this breaks when the var contains a double quote. + local value= + eval value=\"\$$1\" + case "$value" in + [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) return 0;; + [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) return 1;; + *) vewarn "\$$1 is not set properly"; return 1;; + esac +} + +rc_runlevel() +{ + rc-status --runlevel +} + +_sanitize_path() +{ + local IFS=":" p= path= + for p in $PATH; do + case "$p" in + @LIBEXECDIR@/bin|@LIBEXECDIR@/sbin);; + @BINDIR@|@SBINDIR@|/usr/bin|/usr/sbin);; + @PKG_PREFIX@/bin|@PKG_PREFIX@/sbin);; + @LOCAL_PREFIX@/bin|@LOCAL_PREFIX@/sbin);; + *) path="$path${path:+:}$p";; + esac + done + echo "$path" +} + +# Code common to scripts that need to load a kernel module +# if it isn't in the kernel yet. Syntax: +# load_kld [-e regex] [-m module] file +# where -e or -m chooses the way to check if the module +# is already loaded: +# regex is egrep'd in the output from `kldstat -v', +# module is passed to `kldstat -m'. +# The default way is as though `-m file' were specified. +load_kld() +{ + local _loaded _mod _opt _re + + while getopts "e:m:" _opt; do + case "$_opt" in + e) _re="$OPTARG" ;; + m) _mod="$OPTARG" ;; + *) eend 3 'USAGE: load_kld [-e regex] [-m module] file' ;; + esac + done + shift $(($OPTIND - 1)) + if [ $# -ne 1 ]; then + eend 3 'USAGE: load_kld [-e regex] [-m module] file' + fi + _mod=${_mod:-$1} + _loaded=false + if [ -n "$_re" ]; then + if kldstat -v | egrep -q -e "$_re"; then + _loaded=true + fi + else + if kldstat -q -m "$_mod"; then + _loaded=true + fi + fi + if ! $_loaded; then + if ! kldload "$1"; then + ewarn "Unable to load kernel module $1" + return 1 + fi + fi + return 0 +} + +# Allow our scripts to support zsh +if [ -n "$ZSH_VERSION" ]; then + emulate sh + NULLCMD=: + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +fi + +# Make a sane PATH +_PREFIX=@PREFIX@ +_PKG_PREFIX=@PKG_PREFIX@ +_LOCAL_PREFIX=@LOCAL_PREFIX@ +_LOCAL_PREFIX=${_LOCAL_PREFIX:-/usr/local} +_PATH=@LIBEXECDIR@/bin +case "$_PREFIX" in + "$_PKG_PREFIX"|"$_LOCAL_PREFIX") ;; + *) _PATH="$_PATH:$_PREFIX/bin:$_PREFIX/sbin";; +esac +_PATH="$_PATH":/bin:/sbin:/usr/bin:/usr/sbin + +if [ -n "$_PKG_PREFIX" ]; then + _PATH="$_PATH:$_PKG_PREFIX/bin:$_PKG_PREFIX/sbin" +fi +if [ -n "$_LOCAL_PREFIX" ]; then + _PATH="$_PATH:$_LOCAL_PREFIX/bin:$_LOCAL_PREFIX/sbin" +fi +_path="$(_sanitize_path "$PATH")" +PATH="$_PATH${_path:+:}$_path" ; export PATH +unset _sanitize_path _PREFIX _PKG_PREFIX _LOCAL_PREFIX _PATH _path + +for arg; do + case "$arg" in + --nocolor|--nocolour|-C) + EINFO_COLOR="NO" ; export EINFO_COLOR + ;; + esac +done + +if [ -t 1 ] && yesno "${EINFO_COLOR:-YES}"; then + if [ -z "$GOOD" ]; then + eval $(eval_ecolors) + fi +else + # We need to have shell stub functions so our init scripts can remember + # the last ecmd + for _e in ebegin eend error errorn einfo einfon ewarn ewarnn ewend \ + vebegin veend veinfo vewarn vewend; do + eval "$_e() { local _r; command $_e \"\$@\"; _r=\$?; \ + EINFO_LASTCMD=$_e; export EINFO_LASTCMD ; return \$_r; }" + done + unset _e +fi Index: contrib/openrc/sh/gendepends.sh.in =================================================================== --- /dev/null +++ contrib/openrc/sh/gendepends.sh.in @@ -0,0 +1,128 @@ +#!@SHELL@ +# Shell wrapper to list our dependencies + +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +. @LIBEXECDIR@/sh/functions.sh +. @LIBEXECDIR@/sh/rc-functions.sh + +config() { + [ -n "$*" ] && echo "$RC_SVCNAME config $*" >&3 +} +need() { + [ -n "$*" ] && echo "$RC_SVCNAME ineed $*" >&3 +} +use() { + [ -n "$*" ] && echo "$RC_SVCNAME iuse $*" >&3 +} +want() { + [ -n "$*" ] && echo "$RC_SVCNAME iwant $*" >&3 +} +before() { + [ -n "$*" ] && echo "$RC_SVCNAME ibefore $*" >&3 +} +after() { + [ -n "$*" ] && echo "$RC_SVCNAME iafter $*" >&3 +} +provide() { + [ -n "$*" ] && echo "$RC_SVCNAME iprovide $*" >&3 +} +keyword() { + local c x + set -- $* + while [ -n "$*" ]; do + case "$1" in + -containers) x="$(_get_containers)" ;; + !-containers) x="$(_get_containers_remove)" ;; + *) x=$1 ;; + esac + c="${c}${x} " + shift + done + [ -n "$c" ] && echo "$RC_SVCNAME keyword $c" >&3 +} +depend() { + : +} + +_done_dirs= +for _dir in \ +@SYSCONFDIR@/init.d \ +@LOCAL_PREFIX@/etc/init.d +do + [ -d "$_dir" ] || continue + + # Don't do the same dir twice + for _d in $_done_dirs; do + [ "$_d" = "$_dir" ] && continue 2 + done + unset _d + _done_dirs="$_done_dirs $_dir" + + cd "$_dir" + for RC_SERVICE in *; do + [ -x "$RC_SERVICE" -a -f "$RC_SERVICE" ] || continue + + # Only generate dependencies for OpenRC scripts + read one two three <"$RC_SERVICE" + case "$one" in + \#*/openrc-run) ;; + \#*/runscript) ;; + \#!) + case "$two" in + */openrc-run) ;; + */runscript) ;; + *) + continue + ;; + esac + ;; + *) + continue + ;; + esac + unset one two three + + RC_SVCNAME=${RC_SERVICE##*/} ; export RC_SVCNAME + + # Compat + SVCNAME=$RC_SVCNAME ; export SVCNAME + + ( + # Save stdout in fd3, then remap it to stderr + exec 3>&1 1>&2 + + _rc_c=${RC_SVCNAME%%.*} + if [ -n "$_rc_c" -a "$_rc_c" != "$RC_SVCNAME" ]; then + if [ -e "$_dir/../conf.d/$_rc_c" ]; then + . "$_dir/../conf.d/$_rc_c" + fi + fi + unset _rc_c + + if [ -e "$_dir/../conf.d/$RC_SVCNAME" ]; then + . "$_dir/../conf.d/$RC_SVCNAME" + fi + + [ -e @SYSCONFDIR@/rc.conf ] && . @SYSCONFDIR@/rc.conf + if [ -d "@SYSCONFDIR@/rc.conf.d" ]; then + for _f in "@SYSCONFDIR@"/rc.conf.d/*.conf; do + [ -e "$_f" ] && . "$_f" + done + fi + + if . "$_dir/$RC_SVCNAME"; then + echo "$RC_SVCNAME" >&3 + _depend + fi + ) + done +done Index: contrib/openrc/sh/init-early.sh.Linux.in =================================================================== --- /dev/null +++ contrib/openrc/sh/init-early.sh.Linux.in @@ -0,0 +1,57 @@ +#!@SHELL@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +: ${CONSOLE:=/dev/console} +: ${RC_LIBEXECDIR:=@LIBEXECDIR@} + +service_present() +{ + local p="@SYSCONFDIR@/runlevels/$1/$2" + # fail if the file doesn't exist + [ ! -e "$p" ] && return 1 + # succeed if $RC_SYS empty, can't check further, assume script will run + [ -z "$RC_SYS" ] && return 0 + # fail if file contains "-$RC_SYS", because then it won't run + egrep -qi "^[[:space:]]*keyword[[:space:]].*-$RC_SYS\>" "$p" && return 1 + # succeed otherwise + return 0 +} + +if [ -e "$RC_LIBEXECDIR"/console/unicode ]; then + termencoding="%G" + kmode="-u" +else + termencoding="(K" + kmode="-a" +fi + +# Try and set a font and as early as we can +if service_present "$RC_DEFAULTLEVEL" consolefont || + service_present "$RC_BOOTLEVEL" consolefont; then + printf "\033%s" "$termencoding" >"$CONSOLE" 2>/dev/null + if [ -r "$RC_LIBEXECDIR"/console/font ] && \ + command -v setfont > /dev/null 2>&1; then + [ -c "$CONSOLE" ] && cons="-C $CONSOLE" + setfont $cons "$RC_LIBEXECDIR"/console/font 2>/dev/null + fi +fi + +# Try and set a keyboard map as early as possible +if service_present "$RC_DEFAULTLEVEL" keymaps || + service_present "$RC_BOOTLEVEL" keymaps; then + kbd_mode $kmode -C "$CONSOLE" 2>/dev/null + if [ -r "$RC_LIBEXECDIR"/console/keymap ]; then + loadkeys -q "$RC_LIBEXECDIR"/console/keymap 2>/dev/null + fi +fi + +# Ensure we exit 0 so the boot continues +exit 0 Index: contrib/openrc/sh/init.sh.BSD.in =================================================================== --- /dev/null +++ contrib/openrc/sh/init.sh.BSD.in @@ -0,0 +1,65 @@ +#!@SHELL@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# This basically mounts $svcdir as a ramdisk, but preserving its content +# which allows us to run depscan.sh +# FreeBSD has a nice ramdisk - we don't set a size as we should always +# be fairly small and we unmount them after the boot level is done anyway +# NOTE we don't set a size for Linux either +# FreeBSD-7 supports tmpfs now :) +mount_svcdir() +{ + if ! fstabinfo --mount "$RC_SVCDIR"; then + if ! mount -t tmpfs -o rw,noexec,nosuid none \ + "$RC_SVCDIR" 2>/dev/null + then + mdconfig -a -t malloc -s "${rc_svcsize:-1024}"k -u 0 + newfs -b 4096 -i 1024 -n /dev/md0 + mount -o rw,noexec,nosuid /dev/md0 "$RC_SVCDIR" + fi + fi +} + +. "$RC_LIBEXECDIR"/sh/functions.sh +[ -r "@SYSCONFDIR@/rc.conf" ] && . "@SYSCONFDIR@/rc.conf" +if [ -d "@SYSCONFDIR@/rc.conf.d" ]; then + for _f in "@SYSCONFDIR@"/rc.conf.d/*.conf; do + [ -r "$_f" ] && . "$_f" + done +fi + +# Disable devd until we need it +#if [ -z "$RC_SYS" -a "$RC_UNAME" = "FreeBSD" ]; then +# sysctl hw.bus.devctl_disable=1 >/dev/null +#fi + +# mount $RC_SVCDIR as something we can write to if it's not rw +# On vservers, / is always rw at this point, so we need to clean out +# the old service state data +: ${RC_LIBEXECDIR:=@LIBEXECDIR@} +: ${RC_SVCDIR:=@LIBEXECDIR@/init.d} +case "$(openrc --sys)" in + OPENVZ|VSERVER) rm -rf "$RC_SVCDIR"/*;; + *) if mountinfo --quiet "$RC_SVCDIR"; then + rm -rf "$RC_SVCDIR"/* + else + mount_svcdir + fi + ;; +esac +retval=$? + +if [ -e "$RC_LIBEXECDIR"/cache/softlevel ]; then + cp -p "$RC_LIBEXECDIR"/cache/* "$RC_SVCDIR" 2>/dev/null +fi + +echo sysinit >"$RC_SVCDIR"/softlevel +exit $retval Index: contrib/openrc/sh/init.sh.GNU-kFreeBSD.in =================================================================== --- /dev/null +++ contrib/openrc/sh/init.sh.GNU-kFreeBSD.in @@ -0,0 +1,42 @@ +#!@SHELL@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +if [ ! -d /run ]; then + ebegin "Creating /run" + mkdir -p /run + eend $? +fi + +if [ -L $RC_SVCDIR ]; then + rm $RC_SVCDIR +fi + +ebegin "Mounting /run" +if ! fstabinfo --mount /run; then + mount -t tmpfs -o mode=0755,noexec,nosuid,size=10% tmpfs /run + if [ $? != 0 ]; then + eerror "Unable to mount tmpfs on /run." + eerror "Can't continue." + exit 1 + fi +fi +eend + +ebegin "Creating $RC_SVCDIR" +mkdir -p $RC_SVCDIR +eend $? + +if [ -e "$RC_LIBEXECDIR"/cache/softlevel ]; then + cp -p "$RC_LIBEXECDIR"/cache/* "$RC_SVCDIR" 2>/dev/null +fi + +echo sysinit >"$RC_SVCDIR"/softlevel +exit 0 Index: contrib/openrc/sh/init.sh.GNU.in =================================================================== --- /dev/null +++ contrib/openrc/sh/init.sh.GNU.in @@ -0,0 +1,44 @@ +#!@SHELL@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +if [ ! -d /run ]; then + ebegin "Creating /run" + mkdir -p /run + eend $? +fi + +if [ -L $RC_SVCDIR ]; then + rm $RC_SVCDIR +fi + +if ! mountinfo -q /run; then + ebegin "Mounting /run" + if ! fstabinfo --mount /run; then + mount -t tmpfs -o mode=0755,no-suid,size=10% tmpfs /run + if [ $? != 0 ]; then + eerror "Unable to mount tmpfs on /run." + eerror "Can't continue." + exit 1 + fi + fi + eend +fi + +ebegin "Creating $RC_SVCDIR" +mkdir -p $RC_SVCDIR +eend $? + +if [ -e "$RC_LIBEXECDIR"/cache/softlevel ]; then + cp -p "$RC_LIBEXECDIR"/cache/* "$RC_SVCDIR" 2>/dev/null +fi + +echo sysinit >"$RC_SVCDIR"/softlevel +exit 0 Index: contrib/openrc/sh/init.sh.Linux.in =================================================================== --- /dev/null +++ contrib/openrc/sh/init.sh.Linux.in @@ -0,0 +1,104 @@ +#!@SHELL@ +# Copyright (c) 1999-2007 Gentoo Foundation +# Copyright (c) 2007-2009 Roy Marples +# Released under the 2-clause BSD license. + +. "$RC_LIBEXECDIR"/sh/functions.sh +[ -r "@SYSCONFDIR@/rc.conf" ] && . "@SYSCONFDIR@/rc.conf" +if [ -d "@SYSCONFDIR@/rc.conf.d" ]; then + for _f in "@SYSCONFDIR@"/rc.conf.d/*.conf; do + [ -e "$_f" ] && . "$_f" + done +fi + +# check for md5sum, and probably /usr too +if command -v md5sum >/dev/null; then + got_md5sum=true +else + eerror "md5sum is missing, which suggests /usr is not mounted" + eerror "If you have separate /usr, it must be mounted by initramfs" + eerror "If not, you should check coreutils is installed correctly" + got_md5sum=false +fi + +# By default VServer already has /proc mounted, but OpenVZ does not! +# However, some of our users have an old proc image in /proc +# NFC how they managed that, but the end result means we have to test if +# /proc actually works or not. We do this by comparing two reads of +# /proc/self/environ for which we have set the variable VAR to two +# different values. If the comparison comes back equal, we know that +# /proc is not working. +mountproc=true +f=/proc/self/environ +if [ -e $f ]; then + if $got_md5sum && [ "$(VAR=a md5sum $f)" = "$(VAR=b md5sum $f)" ]; then + eerror "You have cruft in /proc that should be deleted" + else + # If they don't have md5sum, this will fail in pretty ways if + # /proc isn't really mounted. Oh well, their system is busted + # anyway, and they get to keep the pieces. + einfo "/proc is already mounted" + mountproc=false + fi +fi +unset f + +if $mountproc; then + ebegin "Mounting /proc" + if ! fstabinfo --mount /proc; then + mount -n -t proc -o noexec,nosuid,nodev proc /proc + fi + eend $? +fi + +# /run is a new directory for storing volatile runtime data. +# Read more about /run at https://lwn.net/Articles/436012 +sys="$(openrc --sys)" + +if [ ! -d /run ]; then + if [ "$sys" = VSERVER ]; then + if [ -e /run ]; then + rm -rf /run + fi + mkdir /run + else + eerror "The /run directory does not exist. Unable to continue." + return 1 + fi +fi + +if [ "$sys" = VSERVER ]; then + rm -rf /run/* +elif ! mountinfo -q /run; then + ebegin "Mounting /run" + rc=0 + if ! fstabinfo --mount /run; then + mount -t tmpfs -o mode=0755,nodev,size=10% tmpfs /run + rc=$? + fi + if [ $rc != 0 ]; then + eerror "Unable to mount tmpfs on /run." + eerror "Can't continue." + exit 1 + fi +fi + +checkpath -d $RC_SVCDIR +checkpath -d -m 0775 -o root:uucp /run/lock + +# Try to mount xenfs as early as possible, otherwise rc_sys() will always +# return RC_SYS_XENU and will think that we are in a domU while it's not. +if grep -Eq "[[:space:]]+xenfs$" /proc/filesystems; then + ebegin "Mounting xenfs" + if ! fstabinfo --mount /proc/xen; then + mount -n -t xenfs xenfs /proc/xen -o nosuid,nodev,noexec + fi + eend $? +fi + +if [ -e "$RC_LIBEXECDIR"/cache/softlevel ]; then + cp -p "$RC_LIBEXECDIR"/cache/* "$RC_SVCDIR" 2>/dev/null +fi + +echo sysinit >"$RC_SVCDIR"/softlevel +exit 0 Index: contrib/openrc/sh/migrate-to-run.sh.in =================================================================== --- /dev/null +++ contrib/openrc/sh/migrate-to-run.sh.in @@ -0,0 +1,36 @@ +#!@SHELL@ +# Copyright (c) 2012-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +. "@LIBEXECDIR@/sh/functions.sh" + +if [ -e /run/openrc/softlevel ]; then + einfo "The OpenRC dependency data has already been migrated." + exit 0 +fi + +if [ ! -d /run ]; then + eerror "/run is not a directory." + eerror "moving /run to /run.pre-openrc" + mv /run /run.pre-openrc + mkdir /run +fi + +rm -rf /run/openrc + +if ! mountinfo -q -f tmpfs /run; then + ln -s "@LIBEXECDIR@"/init.d /run/openrc +else + cp -a "@LIBEXECDIR@/init.d" /run/openrc + rc-update -u +fi + +einfo "The OpenRC dependency data was migrated successfully." +exit 0 Index: contrib/openrc/sh/openrc-run.sh.in =================================================================== --- /dev/null +++ contrib/openrc/sh/openrc-run.sh.in @@ -0,0 +1,400 @@ +#!@SHELL@ +# Shell wrapper for openrc-run + +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +verify_boot() +{ + if [ ! -e ${RC_SVCDIR}/softlevel ]; then + eerror "You are attempting to run an openrc service on a" + eerror "system which openrc did not boot." + eerror "You may be inside a chroot or you may have used" + eerror "another initialization system to boot this system." + eerror "In this situation, you will get unpredictable results!" + eerror + eerror "If you really want to do this, issue the following command:" + eerror "touch ${RC_SVCDIR}/softlevel" + exit 1 + fi + return 0 +} + +sourcex() +{ + if [ "$1" = "-e" ]; then + shift + [ -e "$1" ] || return 1 + fi + if ! . "$1"; then + eerror "$RC_SVCNAME: error loading $1" + exit 1 + fi +} + +sourcex "@LIBEXECDIR@/sh/functions.sh" +sourcex "@LIBEXECDIR@/sh/rc-functions.sh" +case $RC_SYS in + PREFIX|SYSTEMD-NSPAWN) ;; + *) sourcex -e "@LIBEXECDIR@/sh/rc-cgroup.sh";; +esac + +# Support LiveCD foo +if sourcex -e "/sbin/livecd-functions.sh"; then + livecd_read_commandline +fi + +if [ -z "$1" -o -z "$2" ]; then + eerror "$RC_SVCNAME: not enough arguments" + exit 1 +fi + +# So daemons know where to recall us if needed +RC_SERVICE="$1" ; export RC_SERVICE +shift + +# Compat +SVCNAME=$RC_SVCNAME ; export SVCNAME + +# Dependency function +config() { + [ -n "$*" ] && echo "config $*" +} +need() { + [ -n "$*" ] && echo "need $*" +} +use() { + [ -n "$*" ] && echo "use $*" +} +want() { + [ -n "$*" ] && echo "want $*" +} +before() { + [ -n "$*" ] && echo "before $*" +} +after() { + [ -n "$*" ] && echo "after $*" +} +provide() { + [ -n "$*" ] && echo "provide $*" +} +keyword() { + local c x + set -- $* + while [ -n "$*" ]; do + case "$1" in + -containers) x="$(_get_containers)" ;; + !-containers) x="$(_get_containers_remove)" ;; + *) x=$1 ;; + esac + c="${c}${x} " + shift + done + [ -n "$c" ] && echo "keyword $c" +} + +# Describe the init script to the user +describe() +{ + if [ -n "$description" ]; then + einfo "$description" + else + ewarn "No description for $RC_SVCNAME" + fi + + local svc= desc= + for svc in ${extra_commands:-$opts} $extra_started_commands \ + $extra_stopped_commands; do + eval desc=\$description_$svc + if [ -n "$desc" ]; then + einfo "$HILITE$svc$NORMAL: $desc" + else + ewarn "$HILITE$svc$NORMAL: no description" + fi + done +} + +# Report status +_status() +{ + if service_stopping; then + ewarn "status: stopping" + return 4 + elif service_starting; then + ewarn "status: starting" + return 8 + elif service_inactive; then + ewarn "status: inactive" + return 16 + elif service_started; then + if service_crashed; then + eerror "status: crashed" + return 32 + fi + einfo "status: started" + return 0 + else + einfo "status: stopped" + return 3 + fi +} + +# These functions select the appropriate function to call from the +# supervisor modules +default_start() +{ + local func=ssd_start + case "$supervisor" in + runit) func=runit_start ;; + s6) func=s6_start ;; + supervise-daemon) func=supervise_start ;; + ?*) + ewarn "Invalid supervisor, \"$supervisor\", using start-stop-daemon" + ;; + esac + $func +} + +default_stop() +{ + local func=ssd_stop + case "$supervisor" in + runit) func=runit_stop ;; + s6) func=s6_stop ;; + supervise-daemon) func=supervise_stop ;; + ?*) + ewarn "Invalid supervisor, \"$supervisor\", using start-stop-daemon" + ;; + esac + $func +} + +default_status() +{ + local func=ssd_status + case "$supervisor" in + runit) func=runit_status ;; + s6) func=s6_status ;; + supervise-daemon) func=supervise_status ;; + ?*) + ewarn "Invalid supervisor, \"$supervisor\", using start-stop-daemon" + ;; + esac + $func +} + +# Template start / stop / status functions +# package init scripts may override these, but the bodies are as minimal as +# possible, so that the init scripts can creatively wrap default_* +# functions. +start() +{ + default_start +} + +stop() +{ + default_stop +} + +status() +{ + default_status +} + +# Start debug output +yesno $RC_DEBUG && set -x + +# Load configuration settings. First the global ones, then any +# service-specific settings. +sourcex -e "@SYSCONFDIR@/defaults/rc.conf" +if [ -e "@SYSCONFDIR@/rc.conf.local" ]; then + sourcex -e "@SYSCONFDIR@/rc.conf.local" +fi +sourcex -e "@SYSCONFDIR@/rc.conf" +if [ -d "@SYSCONFDIR@/rc.conf.d" ]; then + for _f in "@SYSCONFDIR@"/rc.conf.d/*.conf; do + sourcex -e "$_f" + done +fi + +_conf_d=${RC_SERVICE%/*}/../conf.d +# If we're net.eth0 or openvpn.work then load net or openvpn config +_c=${RC_SVCNAME%%.*} +if [ -n "$_c" -a "$_c" != "$RC_SVCNAME" ]; then + if ! sourcex -e "$_conf_d/$_c.$RC_RUNLEVEL"; then + sourcex -e "$_conf_d/$_c" + fi +fi +unset _c + +# Overlay with our specific config +if ! sourcex -e "$_conf_d/$RC_SVCNAME.$RC_RUNLEVEL"; then + sourcex -e "$_conf_d/$RC_SVCNAME" +fi +unset _conf_d + +# load service supervisor functions +sourcex "@LIBEXECDIR@/sh/runit.sh" +sourcex "@LIBEXECDIR@/sh/s6.sh" +sourcex "@LIBEXECDIR@/sh/start-stop-daemon.sh" +sourcex "@LIBEXECDIR@/sh/supervise-daemon.sh" + +# Load our script +sourcex "$RC_SERVICE" + +# Set verbose mode +if yesno "${rc_verbose:-$RC_VERBOSE}"; then + EINFO_VERBOSE=yes + export EINFO_VERBOSE +fi + +for _cmd; do + if [ "$_cmd" != status -a "$_cmd" != describe ]; then + # Apply any ulimit defined + [ -n "${rc_ulimit:-$RC_ULIMIT}" ] && \ + ulimit ${rc_ulimit:-$RC_ULIMIT} + # Apply cgroups settings if defined + if [ "$(command -v cgroup_add_service)" = "cgroup_add_service" ] + then + if grep -qs /sys/fs/cgroup /proc/1/mountinfo + then + if [ -d /sys/fs/cgroup -a ! -w /sys/fs/cgroup ]; then + eerror "No permission to apply cgroup settings" + break + fi + fi + cgroup_add_service + fi + [ "$(command -v cgroup_set_limits)" = "cgroup_set_limits" ] && + cgroup_set_limits + [ "$(command -v cgroup2_set_limits)" = "cgroup2_set_limits" ] && + [ "$_cmd" = start ] && + cgroup2_set_limits + break + fi +done + +eval "printf '%s\n' $required_dirs" | while read _d; do + if [ -n "$_d" ] && [ ! -d "$_d" ]; then + eerror "$RC_SVCNAME: \`$_d' is not a directory" + exit 1 + fi +done +[ $? -ne 0 ] && exit 1 +unset _d + +eval "printf '%s\n' $required_files" | while read _f; do + if [ -n "$_f" ] && [ ! -r "$_f" ]; then + eerror "$RC_SVCNAME: \`$_f' is not readable" + exit 1 + fi +done +[ $? -ne 0 ] && exit 1 +unset _f + +if [ -n "$opts" ]; then + ewarn "Use of the opts variable is deprecated and will be" + ewarn "removed in the future." + ewarn "Please use extra_commands, extra_started_commands or extra_stopped_commands." +fi + +while [ -n "$1" ]; do + # Special case depend + if [ "$1" = depend ]; then + shift + + # Enter the dir of the init script to fix the globbing + # bug 412677 + cd ${RC_SERVICE%/*} + _depend + cd / + continue + fi + # See if we have the required function and run it + for _cmd in describe start stop status ${extra_commands:-$opts} \ + $extra_started_commands $extra_stopped_commands + do + if [ "$_cmd" = "$1" ]; then + if [ "$(command -v "$1")" = "$1" ]; then + # If we're in the background, we may wish to + # fake some commands. We do this so we can + # "start" ourselves from inactive which then + # triggers other services to start which + # depend on us. + # A good example of this is openvpn. + if yesno $IN_BACKGROUND; then + for _cmd in $in_background_fake; do + if [ "$_cmd" = "$1" ]; then + shift + continue 3 + fi + done + fi + # Check to see if we need to be started before + # we can run this command + for _cmd in $extra_started_commands; do + if [ "$_cmd" = "$1" ]; then + if verify_boot && ! service_started; then + eerror "$RC_SVCNAME: cannot \`$1' as it has not been started" + exit 1 + fi + fi + done + # Check to see if we need to be stopped before + # we can run this command + for _cmd in $extra_stopped_commands; do + if [ "$_cmd" = "$1" ]; then + if verify_boot && ! service_stopped; then + eerror "$RC_SVCNAME: cannot \`$1' as it has not been stopped" + exit 1 + fi + fi + done + unset _cmd + case $1 in + start|stop|status) verify_boot;; + esac + if [ "$(command -v "$1_pre")" = "$1_pre" ] + then + "$1"_pre || exit $? + fi + "$1" || exit $? + if [ "$(command -v "$1_post")" = "$1_post" ] + then + "$1"_post || exit $? + fi + [ "$(command -v cgroup_cleanup)" = "cgroup_cleanup" ] && + [ "$1" = "stop" ] && + yesno "${rc_cgroup_cleanup}" && \ + cgroup_cleanup + if [ "$(command -v cgroup2_remove)" = "cgroup2_remove" ]; then + [ "$1" = stop ] || [ -z "${command}" ] && + cgroup2_remove + fi + shift + continue 2 + else + if [ "$_cmd" = "start" -o "$_cmd" = "stop" ] + then + shift + continue 2 + else + eerror "$RC_SVCNAME: function \`$1' defined but does not exist" + exit 1 + fi + fi + fi + done + eerror "$RC_SVCNAME: unknown function \`$1'" + exit 1 +done + +exit 0 Index: contrib/openrc/sh/rc-cgroup.sh.in =================================================================== --- /dev/null +++ contrib/openrc/sh/rc-cgroup.sh.in @@ -0,0 +1,227 @@ +#!@SHELL@ +# Copyright (c) 2012-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +extra_stopped_commands="${extra_stopped_commands} cgroup_cleanup" +description_cgroup_cleanup="Kill all processes in the cgroup" + +cgroup_find_path() +{ + local OIFS name dir result + [ -n "$1" ] || return 0 + OIFS="$IFS" + IFS=":" + while read -r _ name dir; do + [ "$name" = "$1" ] && result="$dir" + done < /proc/1/cgroup + IFS="$OIFS" + printf "%s" "${result}" +} + +cgroup_get_pids() +{ + local cgroup_procs p pids + cgroup_procs="$(cgroup2_find_path)" + [ -n "${cgroup_procs}" ] && + cgroup_procs="${cgroup_procs}/${RC_SVCNAME}/cgroup.procs" || + cgroup_procs="/sys/fs/cgroup/openrc/${RC_SVCNAME}/tasks" + [ -f "${cgroup_procs}" ] || return 0 + while read -r p; do + [ "$p" -eq $$ ] || pids="${pids} ${p}" + done < "${cgroup_procs}" + printf "%s" "${pids}" + return 0 +} + +cgroup_running() +{ + [ -d "/sys/fs/cgroup/unified/${RC_SVCNAME}" ] || + [ -d "/sys/fs/cgroup/${RC_SVCNAME}" ] || + [ -d "/sys/fs/cgroup/openrc/${RC_SVCNAME}" ] +} + +cgroup_set_values() +{ + [ -n "$1" ] && [ -n "$2" ] && [ -d "/sys/fs/cgroup/$1" ] || return 0 + + local controller h + controller="$1" + h=$(cgroup_find_path "$1") + cgroup="/sys/fs/cgroup/${1}${h}openrc_${RC_SVCNAME}" + [ -d "$cgroup" ] || mkdir -p "$cgroup" + + set -- $2 + local name val + while [ -n "$1" ] && [ "$controller" != "cpuacct" ]; do + case "$1" in + $controller.*) + if [ -n "${name}" ] && [ -w "${cgroup}/${name}" ] && + [ -n "${val}" ]; then + veinfo "$RC_SVCNAME: Setting $cgroup/$name to $val" + printf "%s" "$val" > "$cgroup/$name" + fi + name=$1 + val= + ;; + *) + [ -n "$val" ] && + val="$val $1" || + val="$1" + ;; + esac + shift + done + if [ -n "${name}" ] && [ -w "${cgroup}/${name}" ] && [ -n "${val}" ]; then + veinfo "$RC_SVCNAME: Setting $cgroup/$name to $val" + printf "%s" "$val" > "$cgroup/$name" + fi + + if [ -w "$cgroup/tasks" ]; then + veinfo "$RC_SVCNAME: adding to $cgroup/tasks" + printf "%d" 0 > "$cgroup/tasks" + fi + + return 0 +} + +cgroup_add_service() +{ + # relocate starting process to the top of the cgroup + # it prevents from unwanted inheriting of the user + # cgroups. But may lead to a problems where that inheriting + # is needed. + for d in /sys/fs/cgroup/* ; do + [ -w "${d}"/tasks ] && printf "%d" 0 > "${d}"/tasks + done + + openrc_cgroup=/sys/fs/cgroup/openrc + if [ -d "$openrc_cgroup" ]; then + cgroup="$openrc_cgroup/$RC_SVCNAME" + mkdir -p "$cgroup" + [ -w "$cgroup/tasks" ] && printf "%d" 0 > "$cgroup/tasks" + fi +} + +cgroup_set_limits() +{ + local blkio="${rc_cgroup_blkio:-$RC_CGROUP_BLKIO}" + [ -n "$blkio" ] && cgroup_set_values blkio "$blkio" + + local cpu="${rc_cgroup_cpu:-$RC_CGROUP_CPU}" + [ -n "$cpu" ] && cgroup_set_values cpu "$cpu" + + local cpuacct="${rc_cgroup_cpuacct:-$RC_CGROUP_CPUACCT}" + [ -n "$cpuacct" ] && cgroup_set_values cpuacct "$cpuacct" + + local cpuset="${rc_cgroup_cpuset:-$RC_CGROUP_cpuset}" + [ -n "$cpuset" ] && cgroup_set_values cpuset "$cpuset" + + local devices="${rc_cgroup_devices:-$RC_CGROUP_DEVICES}" + [ -n "$devices" ] && cgroup_set_values devices "$devices" + + local hugetlb="${rc_cgroup_hugetlb:-$RC_CGROUP_HUGETLB}" + [ -n "$hugetlb" ] && cgroup_set_values hugetlb "$hugetlb" + + local memory="${rc_cgroup_memory:-$RC_CGROUP_MEMORY}" + [ -n "$memory" ] && cgroup_set_values memory "$memory" + + local net_cls="${rc_cgroup_net_cls:-$RC_CGROUP_NET_CLS}" + [ -n "$net_cls" ] && cgroup_set_values net_cls "$net_cls" + + local net_prio="${rc_cgroup_net_prio:-$RC_CGROUP_NET_PRIO}" + [ -n "$net_prio" ] && cgroup_set_values net_prio "$net_prio" + + local pids="${rc_cgroup_pids:-$RC_CGROUP_PIDS}" + [ -n "$pids" ] && cgroup_set_values pids "$pids" + + return 0 +} + +cgroup2_find_path() +{ + if grep -qw cgroup2 /proc/filesystems; then + case "${rc_cgroup_mode:-hybrid}" in + hybrid) printf "/sys/fs/cgroup/unified" ;; + unified) printf "/sys/fs/cgroup" ;; + esac + fi + return 0 +} + +cgroup2_remove() +{ + local cgroup_path rc_cgroup_path + cgroup_path="$(cgroup2_find_path)" + [ -z "${cgroup_path}" ] && return 0 + rc_cgroup_path="${cgroup_path}/${RC_SVCNAME}" + [ ! -d "${rc_cgroup_path}" ] || + [ ! -e "${rc_cgroup_path}"/cgroup.events ] && + return 0 + grep -qx "$$" "${rc_cgroup_path}/cgroup.procs" && + printf "%d" 0 > "${cgroup_path}/cgroup.procs" + local key populated vvalue + while read -r key value; do + case "${key}" in + populated) populated=${value} ;; + *) ;; + esac + done < "${rc_cgroup_path}/cgroup.events" + [ "${populated}" = 1 ] && return 0 + rmdir "${rc_cgroup_path}" + return 0 +} + +cgroup2_set_limits() +{ + local cgroup_path + cgroup_path="$(cgroup2_find_path)" + [ -d "${cgroup_path}" ] || return 0 + rc_cgroup_path="${cgroup_path}/${RC_SVCNAME}" + local OIFS="$IFS" + IFS=" +" + [ ! -d "${rc_cgroup_path}" ] && mkdir "${rc_cgroup_path}" + printf "%d" 0 > "${rc_cgroup_path}/cgroup.procs" + echo "${rc_cgroup_settings}" | while IFS="$OIFS" read -r key value; do + [ -z "${key}" ] || [ -z "${value}" ] && continue + [ ! -e "${rc_cgroup_path}/${key}" ] && continue + veinfo "${RC_SVCNAME}: cgroups: ${key} ${value}" + printf "%s" "${value}" > "${rc_cgroup_path}/${key}" + done + IFS="$OIFS" + return 0 +} + +cgroup_cleanup() +{ + cgroup_running || return 0 + ebegin "starting cgroups cleanup" + local pids loops=0 + pids="$(cgroup_get_pids)" + if [ -n "${pids}" ]; then + kill -s CONT ${pids} 2> /dev/null + kill -s "${stopsig:-TERM}" ${pids} 2> /dev/null + yesno "${rc_send_sighup:-no}" && + kill -s HUP ${pids} 2> /dev/null + kill -s "${stopsig:-TERM}" ${pids} 2> /dev/null + while [ -n "$(cgroup_get_pids)" ] && + [ "${loops}" -lt "${rc_timeout_stopsec:-90}" ]; do + loops=$((loops+1)) + sleep 1 + done + pids="$(cgroup_get_pids)" + [ -n "${pids}" ] && yesno "${rc_send_sigkill:-yes}" && + kill -s KILL ${pids} 2> /dev/null + fi + cgroup2_remove + [ -z "$(cgroup_get_pids)" ] + eend $? "Unable to stop all processes" + return 0 +} Index: contrib/openrc/sh/rc-functions.sh.in =================================================================== --- /dev/null +++ contrib/openrc/sh/rc-functions.sh.in @@ -0,0 +1,175 @@ +# Copyright (c) 2007 Gentoo Foundation +# Copyright (c) 2007-2009 Roy Marples +# Released under the 2-clause BSD license. + +has_addon() +{ + [ -e /@LIB@/rc/addons/"$1".sh -o -e /@LIB@/rcscripts/addons/"$1".sh ] +} + +_addon_warn() +{ + eindent + ewarn "$RC_SVCNAME uses addon code which is deprecated" + ewarn "and may not be available in the future." + eoutdent +} + +import_addon() +{ + if [ -e /@LIB@/rc/addons/"$1".sh ]; then + _addon_warn + . /@LIB@/rc/addons/"$1".sh + elif [ -e /@LIB@/rcscripts/addons/"$1".sh ]; then + _addon_warn + . /@LIB@/rcscripts/addons/"$1".sh + else + return 1 + fi +} + +start_addon() +{ + ( import_addon "$1-start" ) +} + +stop_addon() +{ + ( import_addon "$1-stop" ) +} + +net_fs_list="afs ceph cifs coda davfs fuse fuse.sshfs gfs glusterfs lustre +ncpfs nfs nfs4 ocfs2 shfs smbfs" +is_net_fs() +{ + [ -z "$1" ] && return 1 + + # Check OS specific flags to see if we're local or net mounted + mountinfo --quiet --netdev "$1" && return 0 + mountinfo --quiet --nonetdev "$1" && return 1 + + # Fall back on fs types + local t=$(mountinfo --fstype "$1") + for x in $net_fs_list $extra_net_fs_list; do + [ "$x" = "$t" ] && return 0 + done + return 1 +} + +is_union_fs() +{ + [ ! -x /sbin/unionctl ] && return 1 + unionctl "$1" --list >/dev/null 2>&1 +} + +get_bootparam() +{ + local match="$1" + [ -z "$match" -o ! -r /proc/cmdline ] && return 1 + + set -- $(cat /proc/cmdline) + while [ -n "$1" ]; do + [ "$1" = "$match" ] && return 0 + case "$1" in + gentoo=*) + local params="${1##*=}" + local IFS=, x= + for x in $params; do + [ "$x" = "$match" ] && return 0 + done + ;; + esac + shift + done + + return 1 +} + +get_bootparam_value() +{ + local match="$1" which_value="$2" sep="$3" result value + if [ -n "$match" -a -r /proc/cmdline ]; then + set -- $(cat /proc/cmdline) + while [ -n "$1" ]; do + case "$1" in + $match=*) + value="${1##*=}" + case "$which_value" in + all) + [ -z "$sep" ] && sep=' ' + if [ -z "$result" ]; then + result="$value" + else + result="${result}${sep}${value}" + fi + ;; + last) + result="$value" + ;; + *) + result="$value" + break + ;; + esac + ;; + esac + shift + done + fi + echo $result +} + +need_if_exists() +{ + for x; do + rc-service --exists "${x}" && need "${x}" + done +} + +# Called from openrc-run.sh or gendepends.sh +_get_containers() { + local c + case "${RC_UNAME}" in + FreeBSD) + c="-jail" + ;; + Linux) + c="-docker -lxc -openvz -rkt -systemd-nspawn -uml -vserver" + ;; + esac + echo $c +} + +_get_containers_remove() { + local c + for x in $(_get_containers); do + c="${c}!${x} " + done + echo $c +} + +_depend() { + depend + local _rc_svcname=$(shell_var "$RC_SVCNAME") _deptype= _depends= + + # Add any user defined depends + for _deptype in config:CONFIG need:NEED use:USE want:WANT \ + after:AFTER before:BEFORE \ + provide:PROVIDE keyword:KEYWORD; do + IFS=: + set -- $_deptype + unset IFS + eval _depends=\$rc_${_rc_svcname}_$1 + [ -z "$_depends" ] && eval _depends=\$rc_$1 + [ -z "$_depends" ] && eval _depends=\$RC_${_rc_svcname}_$2 + [ -z "$_depends" ] && eval _depends=\$RC_$2 + + $1 $_depends + done +} + +# Add our sbin to $PATH +case "$PATH" in + "$RC_LIBEXECDIR"/sbin|"$RC_LIBEXECDIR"/sbin:*);; + *) PATH="$RC_LIBEXECDIR/sbin:$PATH" ; export PATH ;; +esac Index: contrib/openrc/sh/rc-mount.sh =================================================================== --- /dev/null +++ contrib/openrc/sh/rc-mount.sh @@ -0,0 +1,87 @@ +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Declare this here so that no formatting doesn't affect the embedded newline +__IFS=" +" + +# Handy function to handle all our unmounting needs +# mountinfo is a C program to actually find our mounts on our supported OS's +# We rely on fuser being present, so if it's not then don't unmount anything. +# This isn't a real issue for the BSD's, but it is for Linux. +do_unmount() +{ + local cmd="$1" retval=0 retry= pids=- + local f_opts="-m -c" f_kill="-s " mnt= + if [ "$RC_UNAME" = "Linux" ]; then + f_opts="-m" + f_kill="-" + fi + + shift + local IFS="$__IFS" + set -- $(mountinfo "$@") + unset IFS + for mnt; do + # Unmounting a shared mount can unmount other mounts, so + # we need to check the mount is still valid + mountinfo --quiet "$mnt" || continue + # Ensure we interpret all characters properly. + mnt=$(printf "$mnt") + + case "$cmd" in + umount) + ebegin "Unmounting $mnt" + ;; + *) + ebegin "Remounting $mnt read only" + ;; + esac + + retry=4 # Effectively TERM, sleep 1, TERM, sleep 1, KILL, sleep 1 + while ! LC_ALL=C $cmd "$mnt" 2>/dev/null; do + if command -v fuser >/dev/null 2>&1; then + pids="$(timeout -k 10 -s KILL "${rc_fuser_timeout:-60}" \ + fuser $f_opts "$mnt" 2>/dev/null)" + fi + case " $pids " in + *" $$ "*) + eend 1 "failed because we are using" \ + "$mnt" + retry=0;; + " - ") + eend 1 + retry=0;; + " ") + eend 1 "in use but fuser finds nothing" + retry=0;; + *) + if [ $retry -le 0 ]; then + eend 1 + else + local sig="TERM" + : $(( retry -= 1 )) + [ $retry = 1 ] && sig="KILL" + fuser $f_kill$sig -k $f_opts \ + "$mnt" >/dev/null 2>&1 + sleep 1 + fi + ;; + esac + [ $retry -le 0 ] && break + done + if [ $retry -le 0 ]; then + retval=1 + else + eend 0 + fi + done + return $retval +} Index: contrib/openrc/sh/runit.sh =================================================================== --- /dev/null +++ contrib/openrc/sh/runit.sh @@ -0,0 +1,52 @@ +# Copyright (c) 2016 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. +# Released under the 2-clause BSD license. + +runit_start() +{ + local service_path service_link + service_path="${runit_service:-/etc/sv/${RC_SVCNAME}}" + if [ ! -d "${service_path}" ]; then + eerror "Runit service ${service_path} not found" + return 1 + fi + service_link="${RC_SVCDIR}/sv/${service_path##*/}" + ebegin "Starting ${name:-$RC_SVCNAME}" + ln -snf "${service_path}" "${service_link}" + sv start "${service_link}" > /dev/null 2>&1 + eend $? "Failed to start ${name:-$RC_SVCNAME}" +} + +runit_stop() +{ + local service_path service_link + service_path="${runit_service:-/etc/sv/${RC_SVCNAME}}" + if [ ! -d "${service_path}" ]; then + eerror "Runit service ${service_path} not found" + return 1 + fi + service_link="${RC_SVCDIR}/sv/${service_path##*/}" + ebegin "Stopping ${name:-$RC_SVCNAME}" + sv stop "${service_link}" > /dev/null 2>&1 && + rm "${service_link}" + eend $? "Failed to stop ${name:-$RC_SVCNAME}" +} + +runit_status() +{ + local service_path service_link + service_path="${runit_service:-/etc/sv/${RC_SVCNAME}}" + if [ ! -d "${service_path}" ]; then + eerror "Runit service ${service_path} not found" + return 1 + fi + service_link="${RC_SVCDIR}/sv/${service_path##*/}" + sv status "${service_link}" +} Index: contrib/openrc/sh/runtests.sh =================================================================== --- /dev/null +++ contrib/openrc/sh/runtests.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Copyright (c) 2008-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +: ${top_srcdir:=..} +. $top_srcdir/test/setup_env.sh + +ret=0 + +tret=0 +ebegin "Testing yesno()" +for f in yes YES Yes true TRUE True 1 ; do + if ! yesno $f; then + : $(( tret += 1 )) + echo "!$f!" + fi +done +for f in no NO No false FALSE False 0 ; do + if yesno $f; then + : $(( tret += 1 )) + echo "!$f!" + fi +done +eend $tret +: $(( ret += $tret )) + +exit $ret Index: contrib/openrc/sh/s6.sh =================================================================== --- /dev/null +++ contrib/openrc/sh/s6.sh @@ -0,0 +1,76 @@ +# Start / stop / status functions for s6 support + +# Copyright (c) 2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +[ -z "${s6_service_path}" ] && s6_service_path="/var/svc.d/${RC_SVCNAME}" + +_s6_force_kill() { + local pid + s6_service_link="${RC_SVCDIR}/s6-scan/${s6_service_path##*/}" + pid="${3%)}" + [ -z "${pid}" ] && return 0 + if kill -0 "${pid}" 2> /dev/null; then + ewarn "Sending DOWN & KILL for ${RC_SVCNAME}" + s6-svc -dk "${s6_service_link}" + sleep 1 + kill -0 "${pid}" 2>/dev/null && return 1 + fi + return 0 +} + +s6_start() +{ + if [ ! -d "${s6_service_path}" ]; then + eerror "${s6_service_path} does not exist." + return 1 + fi + s6_service_link="${RC_SVCDIR}/s6-scan/${s6_service_path##*/}" + ebegin "Starting ${name:-$RC_SVCNAME}" + ln -sf "${s6_service_path}" "${s6_service_link}" + s6-svscanctl -na "${RC_SVCDIR}"/s6-scan + sleep 1.5 + s6-svc -u "${s6_service_link}" + if [ -n "$s6_svwait_options_start" ]; then + s6-svwait ${s6_svwait_options_start} "${s6_service_link}" + fi + sleep 1.5 + set -- $(s6-svstat "${s6_service_link}") + [ "$1" = "up" ] + eend $? "Failed to start ${name:-$RC_SVCNAME}" +} + +s6_stop() +{ + if [ ! -d "${s6_service_path}" ]; then + eerror "${s6_service_path} does not exist." + return 1 + fi + s6_service_link="${RC_SVCDIR}/s6-scan/${s6_service_path##*/}" + ebegin "Stopping ${name:-$RC_SVCNAME}" + s6-svc -d -wD -T ${s6_service_timeout_stop:-60000} "${s6_service_link}" + set -- $(s6-svstat "${s6_service_link}") + [ "$1" = "up" ] && + yesno "${s6_force_kill:-yes}" && + _s6_force_kill "$@" + set -- $(s6-svstat "${s6_service_link}") + [ "$1" = "down" ] + eend $? "Failed to stop ${name:-$RC_SVCNAME}" +} + +s6_status() +{ + s6_service_link="${RC_SVCDIR}/s6-scan/${s6_service_path##*/}" + if [ -L "${s6_service_link}" ]; then + s6-svstat "${s6_service_link}" + else + _status + fi +} Index: contrib/openrc/sh/start-stop-daemon.sh =================================================================== --- /dev/null +++ contrib/openrc/sh/start-stop-daemon.sh @@ -0,0 +1,99 @@ +# start / stop / status functions for start-stop-daemon + +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +ssd_start() +{ + if [ -z "$command" ]; then + ewarn "The command variable is undefined." + ewarn "There is nothing for ${name:-$RC_SVCNAME} to start." + ewarn "If this is what you intend, please write a start function." + ewarn "This will become a failure in a future release." + return 0 + fi + + local _background= + ebegin "Starting ${name:-$RC_SVCNAME}" + if yesno "${command_background}"; then + if [ -z "${pidfile}" ]; then + eend 1 "command_background option used but no pidfile specified" + return 1 + fi + if [ -n "${command_args_background}" ]; then + eend 1 "command_background used with command_args_background" + return 1 + fi + _background="--background --make-pidfile" + fi + if yesno "$start_inactive"; then + local _inactive=false + service_inactive && _inactive=true + mark_service_inactive + fi + #the eval call is necessary for cases like: + # command_args="this \"is a\" test" + # to work properly. + eval start-stop-daemon --start \ + --exec $command \ + ${chroot:+--chroot} $chroot \ + ${directory:+--chdir} $directory \ + ${output_log+--stdout} $output_log \ + ${error_log+--stderr} $error_log \ + ${procname:+--name} $procname \ + ${pidfile:+--pidfile} $pidfile \ + ${command_user+--user} $command_user \ + ${umask+--umask} $umask \ + $_background $start_stop_daemon_args \ + -- $command_args $command_args_background + if eend $? "Failed to start ${name:-$RC_SVCNAME}"; then + service_set_value "command" "${command}" + [ -n "${chroot}" ] && service_set_value "chroot" "${chroot}" + [ -n "${pidfile}" ] && service_set_value "pidfile" "${pidfile}" + [ -n "${procname}" ] && service_set_value "procname" "${procname}" + return 0 + fi + if yesno "$start_inactive"; then + if ! $_inactive; then + mark_service_stopped + fi + fi + return 1 +} + +ssd_stop() +{ + local _progress= + local startcommand="$(service_get_value "command")" + local startchroot="$(service_get_value "chroot")" + local startpidfile="$(service_get_value "pidfile")" + local startprocname="$(service_get_value "procname")" + command="${startcommand:-$command}" + chroot="${startchroot:-$chroot}" + pidfile="${startpidfile:-$pidfile}" + procname="${startprocname:-$procname}" + [ -n "$command" -o -n "$procname" -o -n "$pidfile" ] || return 0 + yesno "${command_progress}" && _progress=--progress + ebegin "Stopping ${name:-$RC_SVCNAME}" + start-stop-daemon --stop \ + ${retry:+--retry} $retry \ + ${command:+--exec} $command \ + ${procname:+--name} $procname \ + ${pidfile:+--pidfile} $chroot$pidfile \ + ${stopsig:+--signal} $stopsig \ + ${_progress} + + eend $? "Failed to stop ${name:-$RC_SVCNAME}" +} + +ssd_status() +{ + _status +} Index: contrib/openrc/sh/supervise-daemon.sh =================================================================== --- /dev/null +++ contrib/openrc/sh/supervise-daemon.sh @@ -0,0 +1,100 @@ +# start / stop / status functions for supervise-daemon + +# Copyright (c) 2016 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +supervise_start() +{ + if [ -z "$command" ]; then + ewarn "The command variable is undefined." + ewarn "There is nothing for ${name:-$RC_SVCNAME} to start." + return 1 + fi + + ebegin "Starting ${name:-$RC_SVCNAME}" + # The eval call is necessary for cases like: + # command_args="this \"is a\" test" + # to work properly. + eval supervise-daemon "${RC_SVCNAME}" --start \ + ${retry:+--retry} $retry \ + ${directory:+--chdir} $directory \ + ${chroot:+--chroot} $chroot \ + ${output_log+--stdout} ${output_log} \ + ${error_log+--stderr} $error_log \ + ${pidfile:+--pidfile} $pidfile \ + ${respawn_delay:+--respawn-delay} $respawn_delay \ + ${respawn_max:+--respawn-max} $respawn_max \ + ${respawn_period:+--respawn-period} $respawn_period \ + ${command_user+--user} $command_user \ + ${umask+--umask} $umask \ + $supervise_daemon_args \ + $command \ + -- $command_args $command_args_foreground + rc=$? + if [ $rc = 0 ]; then + [ -n "${chroot}" ] && service_set_value "chroot" "${chroot}" + [ -n "${pidfile}" ] && service_set_value "pidfile" "${pidfile}" + fi + eend $rc "failed to start ${name:-$RC_SVCNAME}" +} + +supervise_stop() +{ + local startchroot="$(service_get_value "chroot")" + local startpidfile="$(service_get_value "pidfile")" + chroot="${startchroot:-$chroot}" + pidfile="${startpidfile:-$pidfile}" + [ -n "$pidfile" ] || return 0 + ebegin "Stopping ${name:-$RC_SVCNAME}" + supervise-daemon "${RC_SVCNAME}" --stop \ + ${pidfile:+--pidfile} $chroot$pidfile \ + ${stopsig:+--signal} $stopsig + + eend $? "Failed to stop ${name:-$RC_SVCNAME}" +} + +_check_supervised() +{ + local child_pid start_time + child_pid="$(service_get_value "child_pid")" + start_time="$(service_get_value "start_time")" + if [ -n "${child_pid}" ] && [ -n "${start_time}" ]; then + return 1 + fi + return 0 +} + +supervise_status() +{ + if service_stopping; then + ewarn "status: stopping" + return 4 + elif service_starting; then + ewarn "status: starting" + return 8 + elif service_inactive; then + ewarn "status: inactive" + return 16 + elif service_started; then + if service_crashed; then + if ! _check_supervised; then + eerror "status: unsupervised" + return 64 + fi + eerror "status: crashed" + return 32 + fi + einfo "status: started" + return 0 + else + einfo "status: stopped" + return 3 + fi +} Index: contrib/openrc/src/Makefile =================================================================== --- /dev/null +++ contrib/openrc/src/Makefile @@ -0,0 +1,7 @@ +# Copyright (c) 2007-2008 Roy Marples +# Released under the 2-clause BSD license. + +SUBDIR= test libeinfo librc rc + +MK= ../mk +include ${MK}/subdir.mk Index: contrib/openrc/src/includes/helpers.h =================================================================== --- /dev/null +++ contrib/openrc/src/includes/helpers.h @@ -0,0 +1,174 @@ +/* + * helpers.h + * This is private to us and not for user consumption + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __HELPERS_H__ +#define __HELPERS_H__ + +#define ERRX fprintf (stderr, "out of memory\n"); exit (1) + +#define UNCONST(a) ((void *)(unsigned long)(const void *)(a)) + +#ifdef lint +# define _unused +#endif +#if __GNUC__ > 2 || defined(__INTEL_COMPILER) +# define _dead __attribute__((__noreturn__)) +# define _unused __attribute__((__unused__)) +# define _xasprintf(a, b) __attribute__((__format__(__printf__, a, b))) +#else +# define _dead +# define _unused +# define _xasprintf(a, b) +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#ifdef __GLIBC__ +# if ! defined (__UCLIBC__) && ! defined (__dietlibc__) +# define strlcpy(dst, src, size) snprintf(dst, size, "%s", src) +# endif +#endif + +#ifndef timespecsub +#define timespecsub(tsp, usp, vsp) \ + do { \ + (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ + if ((vsp)->tv_nsec < 0) { \ + (vsp)->tv_sec--; \ + (vsp)->tv_nsec += 1000000000L; \ + } \ + } while (/* CONSTCOND */ 0) +#endif + +#include +#include +#include + +_unused static void *xmalloc (size_t size) +{ + void *value = malloc(size); + + if (value) + return (value); + + ERRX; + /* NOTREACHED */ +} + +_unused static void *xrealloc(void *ptr, size_t size) +{ + void *value = realloc(ptr, size); + + if (value) + return (value); + + ERRX; + /* NOTREACHED */ +} + +_unused static char *xstrdup(const char *str) +{ + char *value; + + if (! str) + return (NULL); + + value = strdup(str); + + if (value) + return (value); + + ERRX; + /* NOTREACHED */ +} + +#undef ERRX + +/* + * basename_c never modifies the argument. As such, if there is a trailing + * slash then an empty string is returned. + */ +_unused static const char *basename_c(const char *path) +{ + const char *slash = strrchr(path, '/'); + + if (slash) + return (++slash); + return (path); +} + +_unused static bool exists(const char *pathname) +{ + struct stat buf; + + return (stat(pathname, &buf) == 0); +} + +_unused static bool existss(const char *pathname) +{ + struct stat buf; + + return (stat(pathname, &buf) == 0 && buf.st_size != 0); +} + +/* + * This is an OpenRC specific version of the asprintf() function. + * We do this to avoid defining the _GNU_SOURCE feature test macro on + * glibc systems and to insure that we have a consistent function across + * platforms. This also allows us to call our xmalloc and xrealloc + * functions to handle memory allocation. + * this function was originally written by Mike Frysinger. + */ +_unused _xasprintf(2,3) static int xasprintf(char **strp, const char *fmt, ...) +{ + va_list ap; + int len; + int memlen; + char *ret; + + /* + * Start with a buffer size that should cover the vast majority of uses + * (path construction). + */ + memlen = 4096; + ret = xmalloc(memlen); + + va_start(ap, fmt); + len = vsnprintf(ret, memlen, fmt, ap); + va_end(ap); + if (len >= memlen) { + /* + * Output was truncated, so increase buffer to exactly what we need. + */ + memlen = len + 1; + ret = xrealloc(ret, memlen); + va_start(ap, fmt); + len = vsnprintf(ret, len + 1, fmt, ap); + va_end(ap); + } + if (len < 0 || len >= memlen) { + /* Give up! */ + fprintf(stderr, "xasprintf: unable to format a buffer\n"); + free(ret); + exit(1); + } + *strp = ret; + return len; +} + +#endif Index: contrib/openrc/src/includes/hidden-visibility.h =================================================================== --- /dev/null +++ contrib/openrc/src/includes/hidden-visibility.h @@ -0,0 +1,26 @@ +/* + * Written by Mike Frysinger + * Placed in the Public Domain + */ + +#ifndef _HIDDEN_VISIBILITY_H_ +#define _HIDDEN_VISIBILITY_H_ + +#if defined(__ELF__) && defined(__GNUC__) +# define __hidden_asmname(name) __hidden_asmname1 (__USER_LABEL_PREFIX__, name) +# define __hidden_asmname1(prefix, name) __hidden_asmname2(prefix, name) +# define __hidden_asmname2(prefix, name) #prefix name +# define __hidden_proto(name, internal) \ + extern __typeof (name) name __asm__ (__hidden_asmname (#internal)) \ + __attribute__ ((visibility ("hidden"))); +# define __hidden_ver(local, internal, name) \ + extern __typeof (name) __EI_##name __asm__(__hidden_asmname (#internal)); \ + extern __typeof (name) __EI_##name __attribute__((alias (__hidden_asmname1 (,#local)))) +# define hidden_proto(name) __hidden_proto(name, __RC_##name) +# define hidden_def(name) __hidden_ver(__RC_##name, name, name); +#else +# define hidden_proto(name) +# define hidden_def(name) +#endif + +#endif Index: contrib/openrc/src/includes/queue.h =================================================================== --- /dev/null +++ contrib/openrc/src/includes/queue.h @@ -0,0 +1,846 @@ +/* $NetBSD: queue.h,v 1.67 2014/05/17 21:22:56 rmind Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * Include the definition of NULL only on NetBSD because sys/null.h + * is not available elsewhere. This conditional makes the header + * portable and it can simply be dropped verbatim into any system. + * The caveat is that on other systems some other header + * must provide NULL before the macros can be used. + */ +#ifdef __NetBSD__ +#include +#endif + +#if defined(QUEUEDEBUG) +# if defined(_KERNEL) +# define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__) +# else +# include +# define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__) +# endif +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; \ + (var) != SLIST_END(head); \ + (var) = (var)->field.sle_next) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) != SLIST_END(head) && \ + ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = SLIST_END(head); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_AFTER(slistelm, field) do { \ + (slistelm)->field.sle_next = \ + SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (/*CONSTCOND*/0) + + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods. + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var) != LIST_END(head); \ + (var) = ((var)->field.le_next)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) != LIST_END(head) && \ + ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_MOVE(head1, head2) do { \ + LIST_INIT((head2)); \ + if (!LIST_EMPTY((head1))) { \ + (head2)->lh_first = (head1)->lh_first; \ + LIST_INIT((head1)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * List functions. + */ +#if defined(QUEUEDEBUG) +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ + if ((head)->lh_first && \ + (head)->lh_first->field.le_prev != &(head)->lh_first) \ + QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_OP(elm, field) \ + if ((elm)->field.le_next && \ + (elm)->field.le_next->field.le_prev != \ + &(elm)->field.le_next) \ + QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + if (*(elm)->field.le_prev != (elm)) \ + QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ + (elm)->field.le_next = (void *)1L; \ + (elm)->field.le_prev = (void *)1L; +#else +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_LIST_OP(elm, field) +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) +#endif + +#define LIST_INIT(head) do { \ + (head)->lh_first = LIST_END(head); \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + if (((elm)->field.le_next = (listelm)->field.le_next) != \ + LIST_END(head)) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define LIST_REMOVE(elm, field) do { \ + QUEUEDEBUG_LIST_OP((elm), field) \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var) != SIMPLEQ_END(head); \ + (var) = ((var)->field.sqe_next)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->sqh_first); \ + (var) != SIMPLEQ_END(head) && \ + ((next = ((var)->field.sqe_next)), 1); \ + (var) = (next)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_CONCAT(head1, head2) do { \ + if (!SIMPLEQ_EMPTY((head2))) { \ + *(head1)->sqh_last = (head2)->sqh_first; \ + (head1)->sqh_last = (head2)->sqh_last; \ + SIMPLEQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_LAST(head, type, field) \ + (SIMPLEQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->sqh_last) - offsetof(struct type, field)))) + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { TAILQ_END(head), &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue access methods. + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) (NULL) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head)) + + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var) != TAILQ_END(head); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->tqh_first); \ + (var) != TAILQ_END(head) && \ + ((next) = TAILQ_NEXT(var, field), 1); (var) = (next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));\ + (var) != TAILQ_END(head); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) != TAILQ_END(head) && \ + ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev)) + +/* + * Tail queue functions. + */ +#if defined(QUEUEDEBUG) +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ + if ((head)->tqh_first && \ + (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ + QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ + if (*(head)->tqh_last != NULL) \ + QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_OP(elm, field) \ + if ((elm)->field.tqe_next && \ + (elm)->field.tqe_next->field.tqe_prev != \ + &(elm)->field.tqe_next) \ + QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + if (*(elm)->field.tqe_prev != (elm)) \ + QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ + if ((elm)->field.tqe_next == NULL && \ + (head)->tqh_last != &(elm)->field.tqe_next) \ + QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\ + (head), (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ + (elm)->field.tqe_next = (void *)1L; \ + (elm)->field.tqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) +#define QUEUEDEBUG_TAILQ_OP(elm, field) +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) +#endif + +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = TAILQ_END(head); \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ + (elm)->field.tqe_next = TAILQ_END(head); \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \ + TAILQ_END(head)) \ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ + QUEUEDEBUG_TAILQ_OP((elm), field) \ + if (((elm)->field.tqe_next) != TAILQ_END(head)) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \ + TAILQ_END(head)) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ +} while (/*CONSTCOND*/0) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_END(head) NULL +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) +#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head)) + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - offsetof(struct type, field)))) + + +#ifndef _KERNEL +/* + * Circular queue definitions. Do not use. We still keep the macros + * for compatibility but because of pointer aliasing issues their use + * is discouraged! + */ + +/* + * __launder_type(): We use this ugly hack to work around the the compiler + * noticing that two types may not alias each other and elide tests in code. + * We hit this in the CIRCLEQ macros when comparing 'struct name *' and + * 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC + * 4.8) declare these comparisons as always false, causing the code to + * not run as designed. + * + * This hack is only to be used for comparisons and thus can be fully const. + * Do not use for assignment. + * + * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix + * this by changing the head/tail sentinal values, but see the note above + * this one. + */ +static __inline const void * __launder_type(const void *); +static __inline const void * +__launder_type(const void *__x) +{ + __asm __volatile("" : "+r" (__x)); + return __x; +} + +#if defined(QUEUEDEBUG) +#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \ + if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \ + (head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head)) \ + QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head), \ + __FILE__, __LINE__); \ + if ((head)->cqh_last != CIRCLEQ_ENDC(head) && \ + (head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head)) \ + QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \ + if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) { \ + if ((head)->cqh_last != (elm)) \ + QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d", \ + (elm), __FILE__, __LINE__); \ + } else { \ + if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \ + QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d", \ + (elm), __FILE__, __LINE__); \ + } \ + if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) { \ + if ((head)->cqh_first != (elm)) \ + QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d", \ + (elm), __FILE__, __LINE__); \ + } else { \ + if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \ + QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d", \ + (elm), __FILE__, __LINE__); \ + } +#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \ + (elm)->field.cqe_next = (void *)1L; \ + (elm)->field.cqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) +#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) +#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) +#endif + +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_ENDC(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_ENDC(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \ + if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != CIRCLEQ_ENDC(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != CIRCLEQ_ENDC(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +/* For comparisons */ +#define CIRCLEQ_ENDC(head) (__launder_type(head)) +/* For assignments */ +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head)) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) +#endif /* !_KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ Index: contrib/openrc/src/includes/rc-misc.h =================================================================== --- /dev/null +++ contrib/openrc/src/includes/rc-misc.h @@ -0,0 +1,77 @@ +/* + * rc-misc.h + * This is private to us and not for user consumption +*/ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __RC_MISC_H__ +#define __RC_MISC_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include "helpers.h" + +#define RC_LEVEL_BOOT "boot" +#define RC_LEVEL_DEFAULT "default" + +#define RC_DEPTREE_CACHE RC_SVCDIR "/deptree" +#define RC_DEPTREE_SKEWED RC_SVCDIR "/clock-skewed" +#define RC_KRUNLEVEL RC_SVCDIR "/krunlevel" +#define RC_STARTING RC_SVCDIR "/rc.starting" +#define RC_STOPPING RC_SVCDIR "/rc.stopping" + +#define RC_SVCDIR_STARTING RC_SVCDIR "/starting" +#define RC_SVCDIR_INACTIVE RC_SVCDIR "/inactive" +#define RC_SVCDIR_STARTED RC_SVCDIR "/started" +#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "/coldplugged" + +char *rc_conf_value(const char *var); +bool rc_conf_yesno(const char *var); +void env_filter(void); +void env_config(void); +int signal_setup(int sig, void (*handler)(int)); +int signal_setup_restart(int sig, void (*handler)(int)); +int svc_lock(const char *); +int svc_unlock(const char *, int); +pid_t exec_service(const char *, const char *); + +/* + * Check whether path is writable or not, + * this also works properly with read-only filesystems + */ +int is_writable(const char *); + +#define service_start(service) exec_service(service, "start"); +#define service_stop(service) exec_service(service, "stop"); + +int parse_mode(mode_t *, char *); + +/* Handy function so we can wrap einfo around our deptree */ +RC_DEPTREE *_rc_deptree_load (int, int *); + +/* Test to see if we can see pid 1 or not */ +bool _rc_can_find_pids(void); + +RC_SERVICE lookup_service_state(const char *service); +void from_time_t(char *time_string, time_t tv); +time_t to_time_t(char *timestring); +pid_t get_pid(const char *applet, const char *pidfile); + +#endif Index: contrib/openrc/src/includes/rc-wtmp.h =================================================================== --- /dev/null +++ contrib/openrc/src/includes/rc-wtmp.h @@ -0,0 +1,26 @@ +/* + * rc-wtmp.h + * This is private to us and not for user consumption +*/ + +/* + * Copyright (c) 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __RC_WTMP_H__ +#define __RC_WTMP_H__ + +#include + +void log_wtmp(const char *user, const char *id, pid_t pid, int type, + const char *line); + +#endif Index: contrib/openrc/src/libeinfo/Makefile =================================================================== --- /dev/null +++ contrib/openrc/src/libeinfo/Makefile @@ -0,0 +1,12 @@ +LIB= einfo +SHLIB_MAJOR= 1 +SRCS= libeinfo.c +INCS= einfo.h +VERSION_MAP= einfo.map + +LOCAL_CPPFLAGS+= -I../includes + +MK= ../../mk +include ${MK}/lib.mk +include ${MK}/cc.mk +include ${MK}/termcap.mk Index: contrib/openrc/src/libeinfo/einfo.h =================================================================== --- /dev/null +++ contrib/openrc/src/libeinfo/einfo.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __EINFO_H__ +#define __EINFO_H__ + +#if defined(__GNUC__) +# define EINFO_PRINTF(a, b) __attribute__((__format__(__printf__, a, b))) +# define EINFO_XPRINTF(a, b) __attribute__((__noreturn__,__format__(__printf__, a, b))) +#else +# define EINFO_PRINTF(a, b) +# define EINFO_XPRINTF(a, b) +#endif + +#include +#include + +/* Although OpenRC requires C99, linking to us should not. */ +#ifdef restrict +# define EINFO_RESTRICT restrict +#else +# ifdef __restrict +# define EINFO_RESTRICT __restrict +# else +# define EINFO_RESTRICT +# endif +#endif + +/* __BEGIN_DECLS */ +#ifdef __cplusplus +extern "C" { +#endif + +/*! @brief Color types to use */ +typedef enum +{ + ECOLOR_NORMAL = 1, + ECOLOR_GOOD = 2, + ECOLOR_WARN = 3, + ECOLOR_BAD = 4, + ECOLOR_HILITE = 5, + ECOLOR_BRACKET = 6 +} ECOLOR; + +/*! @brief Returns the ASCII code for the color */ +const char *ecolor(ECOLOR); + +/*! @brief Writes to syslog. */ +void elog(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); + +/*! + * @brief Display informational messages. + * + * The einfo family of functions display messages in a consistent manner + * across applications. Basically they prefix the message with + * " * ". If the terminal can handle color then we color the * based on + * the command used. Otherwise we are identical to the printf function. + * + * - einfo - green + * - ewarn - yellow + * - eerror - red + * + * The n suffix denotes that no new line should be printed. + * The v suffix means only print if EINFO_VERBOSE is yes. + * The x suffix means function will exit() returning failure. + */ +/*@{*/ +int einfon(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ewarnn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int eerrorn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int einfo(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ewarn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +void ewarnx(const char * __EINFO_RESTRICT, ...) EINFO_XPRINTF(1, 2); +int eerror(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +void eerrorx(const char * __EINFO_RESTRICT, ...) EINFO_XPRINTF(1, 2); + +int einfovn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ewarnvn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ebeginvn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int eendvn(int, const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +int ewendvn(int, const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +int einfov(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ewarnv(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +/*@}*/ + +/*! @ingroup ebegin + * @brief Display informational messages that may take some time. + * + * Similar to einfo, but we add ... to the end of the message */ +/*@{*/ +int ebeginv(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ebegin(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +/*@}*/ + +/*! @ingroup eend + * @brief End an ebegin. + * + * If you ebegin, you should eend also. + * eend places [ ok ] or [ !! ] at the end of the terminal line depending on + * retval (0 or ok, anything else for !!) + * + * ebracket allows you to specifiy the position, color and message */ +/*@{*/ +int eend(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +int ewend(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +void ebracket(int, ECOLOR, const char * EINFO_RESTRICT); + +int eendv(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +int ewendv(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +/*@}*/ + +/*! @ingroup eindent + * @brief Indents the einfo lines. + * + * For each indent you should outdent when done */ +/*@{*/ +void eindent(void); +void eoutdent(void); +void eindentv(void); +void eoutdentv(void); + +/*! @brief Prefix each einfo line with something */ +void eprefix(const char * EINFO_RESTRICT); + +/* __END_DECLS */ +#ifdef __cplusplus +} +#endif + +#endif Index: contrib/openrc/src/libeinfo/einfo.map =================================================================== --- /dev/null +++ contrib/openrc/src/libeinfo/einfo.map @@ -0,0 +1,35 @@ +EINFO_1.0 { +global: + ecolor; + elog; + einfon; + ewarnn; + eerrorn; + einfo; + ewarn; + ewarnx; + eerror; + eerrorx; + einfovn; + ewarnvn; + ebeginvn; + eendvn; + ewendvn; + einfov; + ewarnv; + ebeginv; + ebegin; + eend; + ewend; + ebracket; + eendv; + ewendv; + eindent; + eoutdent; + eindentv; + eoutdentv; + eprefix; + +local: + *; +}; Index: contrib/openrc/src/libeinfo/libeinfo.c =================================================================== --- /dev/null +++ contrib/openrc/src/libeinfo/libeinfo.c @@ -0,0 +1,1057 @@ +/* + einfo.c + Informational functions +*/ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +static const char libeinfo_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_TERMCAP +# include +#endif +#include + +#include "einfo.h" +#include "helpers.h" +#include "hidden-visibility.h" + +hidden_proto(ecolor) +hidden_proto(ebegin) +hidden_proto(ebeginv) +hidden_proto(ebracket) +hidden_proto(eend) +hidden_proto(eendv) +hidden_proto(eerror) +hidden_proto(eerrorn) +hidden_proto(eerrorx) +hidden_proto(eindent) +hidden_proto(eindentv) +hidden_proto(einfo) +hidden_proto(einfon) +hidden_proto(einfov) +hidden_proto(einfovn) +hidden_proto(elog) +hidden_proto(eoutdent) +hidden_proto(eoutdentv) +hidden_proto(eprefix) +hidden_proto(ewarn) +hidden_proto(ewarnn) +hidden_proto(ewarnv) +hidden_proto(ewarnvn) +hidden_proto(ewarnx) +hidden_proto(ewend) +hidden_proto(ewendv) + +/* Incase we cannot work out how many columns from ioctl, supply a default */ +#define DEFAULT_COLS 80 + +#define OK "ok" +#define NOT_OK "!!" + +/* Number of spaces for an indent */ +#define INDENT_WIDTH 2 + +/* How wide can the indent go? */ +#define INDENT_MAX 40 + +/* Default colours */ +#define GOOD 2 +#define WARN 3 +#define BAD 1 +#define HILITE 6 +#define BRACKET 4 + +/* We fallback to these escape codes if termcap isn't available + * like say /usr isn't mounted */ +#define AF "\033[3%dm" +#define CE "\033[K" +#define CH "\033[%dC" +#define MD "\033[1m" +#define ME "\033[m" +#define UP "\033[A" + +#define _GET_CAP(_d, _c) strlcpy(_d, tgoto(_c, 0, 0), sizeof(_d)); +#define _ASSIGN_CAP(_v) do { \ + _v = p; \ + p += strlcpy(p, tmp, sizeof(ebuffer) - (p - ebuffer)) + 1; \ + } while (0) + +/* A pointer to a string to prefix to einfo/ewarn/eerror messages */ +static const char *_eprefix = NULL; + +/* Buffers and structures to hold the final colours */ +static char ebuffer[100]; +struct ecolor { + ECOLOR color; + int def; + const char *name; +}; +static char nullstr = '\0'; + +static const struct ecolor ecolors[] = { + { ECOLOR_GOOD, GOOD, "good" }, + { ECOLOR_WARN, WARN, "warn" }, + { ECOLOR_BAD, BAD, "bad" }, + { ECOLOR_HILITE, HILITE, "hilite" }, + { ECOLOR_BRACKET, BRACKET, "bracket" }, + { ECOLOR_NORMAL, 0, NULL }, +}; +static const char *ecolors_str[ARRAY_SIZE(ecolors)]; + +static char *flush = NULL; +static char *up = NULL; +static char *goto_column = NULL; + +static const char *term = NULL; +static bool term_is_cons25 = false; + +/* Termcap buffers and pointers + * Static buffers suck hard, but some termcap implementations require them */ +#ifdef HAVE_TERMCAP +static char termcapbuf[2048]; +static char tcapbuf[512]; +#else +/* No curses support, so we hardcode a list of colour capable terms + * Only terminals without "color" in the name need to be explicitly listed */ +static const char *const color_terms[] = { + "Eterm", + "ansi", + "con132x25", + "con132x30", + "con132x43", + "con132x60", + "con80x25", + "con80x28", + "con80x30", + "con80x43", + "con80x50", + "con80x60", + "cons25", + "console", + "cygwin", + "dtterm", + "gnome", + "konsole", + "kterm", + "linux", + "linux-c", + "mlterm", + "putty", + "rxvt", + "rxvt-cygwin", + "rxvt-cygwin-native", + "rxvt-unicode", + "screen", + "screen-bce", + "screen-w", + "screen.linux", + "vt100", + "vt220", + "wsvt25", + "xterm", + "xterm-debian", + NULL +}; +#endif + +/* strlcat and strlcpy are nice, shame glibc does not define them */ +#ifdef __GLIBC__ +# if ! defined (__UCLIBC__) && ! defined (__dietlibc__) +static size_t +strlcat(char *dst, const char *src, size_t size) +{ + char *d = dst; + const char *s = src; + size_t src_n = size; + size_t dst_n; + + while (src_n-- != 0 && *d != '\0') + d++; + dst_n = d - dst; + src_n = size - dst_n; + + if (src_n == 0) + return dst_n + strlen(src); + + while (*s != '\0') { + if (src_n != 1) { + *d++ = *s; + src_n--; + } + s++; + } + *d = '\0'; + + return dst_n + (s - src); +} +# endif +#endif + +static bool +yesno(const char *value) +{ + if (!value) { + errno = ENOENT; + return false; + } + + if (strcasecmp(value, "yes") == 0 || + strcasecmp(value, "y") == 0 || + strcasecmp(value, "true") == 0 || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "1") == 0) + return true; + + if (strcasecmp(value, "no") != 0 && + strcasecmp(value, "n") != 0 && + strcasecmp(value, "false") != 0 && + strcasecmp(value, "off") != 0 && + strcasecmp(value, "0") != 0) + errno = EINVAL; + + return false; +} + +static bool +noyes(const char *value) +{ + int serrno = errno; + bool retval; + + errno = 0; + retval = yesno(value); + if (errno == 0) { + retval = !retval; + errno = serrno; + } + + return retval; +} + +static bool +is_quiet(void) +{ + return yesno(getenv("EINFO_QUIET")); +} + +static bool +is_really_quiet(void) +{ + return yesno(getenv("EERROR_QUIET")); +} + +static bool +is_verbose(void) +{ + return yesno(getenv ("EINFO_VERBOSE")); +} + +/* Fake tgoto call - very crapy, but works for our needs */ +#ifndef HAVE_TERMCAP +static char * +tgoto(const char *cap, int col, int line) +{ + static char buf[20]; + char *p, *e, c, dbuf[6]; + int oncol = 0, which = line, i; + + p = buf; + e = p + sizeof(buf); + while ((c = *cap++)) { + if (c != '%' || ((c = *cap++) == '%')) { + *p++ = c; + if (p >= e) { + errno = E2BIG; + return NULL; + } + continue; + } + switch (c) { + case '3': + case '2': + case 'd': + i = 0; + do + dbuf[i++] = which % 10 | '0'; + while ((which /= 10)); + if (c != 'd') { + c -= '0'; + if (i > c) { + errno = EINVAL; + return NULL; + } + while (i < c) + dbuf[i++] = '0'; + } + if (p + i >= e) { + errno = E2BIG; + return NULL; + } + do + *p++ = dbuf[--i]; + while (i); + break; + case 'r': + oncol = 0; + break; + case 'i': + col++; + line++; + which++; + continue; + default: + errno = EINVAL; + return NULL; + } + + oncol = 1 - oncol; + which = oncol ? col : line; + } + *p = '\0'; + return buf; +} +#endif + +static bool +colour_terminal(FILE * EINFO_RESTRICT f) +{ + static int in_colour = -1; + char *e, *ee, *end, *d, *p; + int c; + const char *_af = NULL, *_ce = NULL, *_ch = NULL; + const char *_md = NULL, *_me = NULL, *_up = NULL; + const char *bold; + char tmp[100]; + unsigned int i = 0; +#ifdef HAVE_TERMCAP + char *bp; +#endif + + if (f && !isatty(fileno(f))) + return false; + + if (noyes(getenv("EINFO_COLOR"))) + return false; + + if (in_colour == 0) + return false; + if (in_colour == 1) + return true; + + term_is_cons25 = false; + if (!term) { + term = getenv("TERM"); + if (!term) + return false; + } + if (strcmp(term, "cons25") == 0) + term_is_cons25 = true; + +#ifdef HAVE_TERMCAP + /* Check termcap to see if we can do colour or not */ + if (tgetent(termcapbuf, term) == 1) { + bp = tcapbuf; + _af = tgetstr("AF", &bp); + _ce = tgetstr("ce", &bp); + _ch = tgetstr("ch", &bp); + /* Our ch use also works with RI .... for now */ + if (!_ch) + _ch = tgetstr("RI", &bp); + _md = tgetstr("md", &bp); + _me = tgetstr("me", &bp); + _up = tgetstr("up", &bp); + } + + /* Cheat here as vanilla BSD has the whole termcap info in /usr + * which is not available to us when we boot */ + if (term_is_cons25 || strcmp(term, "wsvt25") == 0) { +#else + if (strstr(term, "color")) + in_colour = 1; + + while (color_terms[i] && in_colour != 1) { + if (strcmp(color_terms[i], term) == 0) { + in_colour = 1; + } + i++; + } + + if (in_colour != 1) { + in_colour = 0; + return false; + } +#endif + if (!_af) + _af = AF; + if (!_ce) + _ce = CE; + if (!_ch) + _ch = CH; + if (!_md) + _md = MD; + if (!_me) + _me = ME; + if (!_up) + _up = UP; +#ifdef HAVE_TERMCAP + } + + if (!_af || !_ce || !_me || !_md || !_up) { + in_colour = 0; + return false; + } + + /* Many termcap databases don't have ch or RI even though they + * do work */ + if (!_ch) + _ch = CH; +#endif + + /* Now setup our colours */ + p = ebuffer; + for (i = 0; i < ARRAY_SIZE(ecolors); ++i) { + tmp[0] = '\0'; + if (ecolors[i].name) { + bold = _md; + c = ecolors[i].def; + + /* See if the user wants to override the colour + * We use a :col;bold: format like 2;1: for bold green + * and 1;0: for a normal red */ + if ((e = getenv("EINFO_COLOR"))) { + ee = strstr(e, ecolors[i].name); + if (ee) + ee += strlen(ecolors[i].name); + + if (ee && *ee == '=') { + d = strdup(ee + 1); + if (d) { + end = strchr(d, ':'); + if (end) + *end = '\0'; + c = atoi(d); + end = strchr(d, ';'); + if (end && *++end == '0') + bold = _me; + free(d); + } + } + } + strlcpy(tmp, tgoto(bold, 0, 0), sizeof(tmp)); + strlcat(tmp, tgoto(_af, 0, c & 0x07), sizeof(tmp)); + } else + _GET_CAP(tmp, _me); + + if (tmp[0]) + _ASSIGN_CAP(ecolors_str[i]); + else + ecolors_str[i] = &nullstr; + } + + _GET_CAP(tmp, _ce); + _ASSIGN_CAP(flush); + _GET_CAP(tmp, _up); + _ASSIGN_CAP(up); + strlcpy(tmp, _ch, sizeof(tmp)); + _ASSIGN_CAP(goto_column); + + in_colour = 1; + return true; +} + +static int +get_term_columns(FILE * EINFO_RESTRICT stream) +{ + struct winsize ws; + char *env = getenv("COLUMNS"); + char *p; + int i; + + if (env) { + i = strtoimax(env, &p, 10); + if (!*p) + return i; + } + + if (ioctl(fileno(stream), TIOCGWINSZ, &ws) == 0) + return ws.ws_col; + + return DEFAULT_COLS; +} + +void +eprefix(const char *EINFO_RESTRICT prefix) +{ + _eprefix = prefix; +} +hidden_def(eprefix) + +static void EINFO_PRINTF(2, 0) +elogv(int level, const char *EINFO_RESTRICT fmt, va_list ap) +{ + char *e = getenv("EINFO_LOG"); + va_list apc; + + if (fmt && e) { + closelog(); + openlog(e, LOG_PID, LOG_DAEMON); + va_copy(apc, ap); + vsyslog(level, fmt, apc); + va_end(apc); + closelog(); + } +} + +void +elog(int level, const char *EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + elogv(level, fmt, ap); + va_end(ap); +} +hidden_def(elog) + +static int +_eindent(FILE * EINFO_RESTRICT stream) +{ + char *env = getenv("EINFO_INDENT"); + int amount = 0; + char indent[INDENT_MAX]; + + if (env) { + errno = 0; + amount = strtoimax(env, NULL, 0); + if (errno != 0 || amount < 0) + amount = 0; + else if (amount > INDENT_MAX) + amount = INDENT_MAX; + + if (amount > 0) + memset(indent, ' ', (size_t)amount); + } + + /* Terminate it */ + memset(indent + amount, 0, 1); + return fprintf(stream, "%s", indent); +} + +static const char * +_ecolor(FILE * EINFO_RESTRICT f, ECOLOR color) +{ + unsigned int i; + + if (!colour_terminal(f)) + return ""; + + for (i = 0; i < ARRAY_SIZE(ecolors); ++i) + if (ecolors[i].color == color) + return ecolors_str[i]; + return ""; +} +hidden_def(ecolor) + +const char * +ecolor(ECOLOR color) +{ + FILE *f = stdout; + + /* Try and guess a valid tty */ + if (!isatty(fileno(f))) { + f = stderr; + if (!isatty(fileno(f))) { + f = stdin; + if (!isatty(fileno(f))) + f = NULL; + } + } + + return _ecolor(f, color); +} + +#define LASTCMD(_cmd) { \ + unsetenv("EINFO_LASTCMD"); \ + setenv("EINFO_LASTCMD", _cmd, 1); \ + } + +static int EINFO_PRINTF(3, 0) + _einfo(FILE *f, ECOLOR color, const char *EINFO_RESTRICT fmt, va_list va) +{ + int retval = 0; + char *last = getenv("EINFO_LASTCMD"); + va_list ap; + + if (last && + !colour_terminal(f) && + strcmp(last, "ewarn") != 0 && + last[strlen(last) - 1] == 'n') + fprintf(f, "\n"); + if (_eprefix) + fprintf(f, "%s%s%s|", _ecolor(f, color), _eprefix, _ecolor(f, ECOLOR_NORMAL)); + fprintf(f, " %s*%s ", _ecolor(f, color), _ecolor(f, ECOLOR_NORMAL)); + retval += _eindent(f); + va_copy(ap, va); + retval += vfprintf(f, fmt, ap) + 3; + va_end(ap); \ + if (colour_terminal(f)) + fprintf(f, "%s", flush); + return retval; +} + +#define _einfovn(fmt, ap) _einfo(stdout, ECOLOR_GOOD, fmt, ap) +#define _ewarnvn(fmt, ap) _einfo(stderr, ECOLOR_WARN, fmt, ap) +#define _eerrorvn(fmt, ap) _einfo(stderr, ECOLOR_BAD, fmt, ap) + +int +einfon(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || is_quiet()) + return 0; + va_start(ap, fmt); + retval = _einfovn(fmt, ap); + va_end(ap); + LASTCMD("einfon"); + return retval; +} +hidden_def(einfon) + +int +ewarnn(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || is_quiet()) + return 0; + va_start(ap, fmt); + retval = _ewarnvn(fmt, ap); + va_end(ap); + LASTCMD("ewarnn"); + return retval; +} +hidden_def(ewarnn) + +int +eerrorn(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || is_really_quiet()) + return 0; + va_start(ap, fmt); + retval = _eerrorvn(fmt, ap); + va_end(ap); + LASTCMD("errorn"); + return retval; +} +hidden_def(eerrorn) + +int +einfo(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || is_quiet()) + return 0; + va_start(ap, fmt); + retval = _einfovn(fmt, ap); + retval += printf("\n"); + va_end(ap); + LASTCMD("einfo"); + return retval; +} +hidden_def(einfo) + +int +ewarn(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || is_quiet()) + return 0; + va_start(ap, fmt); + elogv(LOG_WARNING, fmt, ap); + retval = _ewarnvn(fmt, ap); + retval += fprintf(stderr, "\n"); + va_end(ap); + LASTCMD("ewarn"); + return retval; +} +hidden_def(ewarn) + +void +ewarnx(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (fmt && !is_quiet()) { + va_start(ap, fmt); + elogv(LOG_WARNING, fmt, ap); + retval = _ewarnvn(fmt, ap); + va_end(ap); + retval += fprintf(stderr, "\n"); + } + exit(EXIT_FAILURE); +} +hidden_def(ewarnx) + +int +eerror(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || is_really_quiet()) + return 0; + va_start(ap, fmt); + elogv(LOG_ERR, fmt, ap); + retval = _eerrorvn(fmt, ap); + va_end(ap); + retval += fprintf(stderr, "\n"); + LASTCMD("eerror"); + return retval; +} +hidden_def(eerror) + +void +eerrorx(const char *EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (fmt && !is_really_quiet()) { + va_start(ap, fmt); + elogv(LOG_ERR, fmt, ap); + _eerrorvn(fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + } + exit(EXIT_FAILURE); +} +hidden_def(eerrorx) + +int +ebegin(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || is_quiet()) + return 0; + va_start(ap, fmt); + retval = _einfovn(fmt, ap); + va_end(ap); + retval += printf(" ..."); + if (colour_terminal(stdout)) + retval += printf("\n"); + LASTCMD("ebegin"); + return retval; +} +hidden_def(ebegin) + +static void +_eend(FILE * EINFO_RESTRICT fp, int col, ECOLOR color, const char *msg) +{ + int i; + int cols; + + if (!msg) + return; + + cols = get_term_columns(fp) - (strlen(msg) + 5); + + /* cons25 is special - we need to remove one char, otherwise things + * do not align properly at all. */ + if (!term) { + term = getenv("TERM"); + if (term && strcmp(term, "cons25") == 0) + term_is_cons25 = true; + else + term_is_cons25 = false; + } + if (term_is_cons25) + cols--; + + if (cols > 0 && colour_terminal(fp)) { + fprintf(fp, "%s%s %s[%s %s %s]%s\n", up, tgoto(goto_column, 0, cols), + ecolor(ECOLOR_BRACKET), ecolor(color), msg, + ecolor(ECOLOR_BRACKET), ecolor(ECOLOR_NORMAL)); + } else { + if (col > 0) + for (i = 0; i < cols - col; i++) + fprintf(fp, " "); + fprintf(fp, " [ %s ]\n", msg); + } +} + +static int EINFO_PRINTF(3, 0) +_do_eend(const char *cmd, int retval, + const char *EINFO_RESTRICT fmt, va_list ap) +{ + int col = 0; + FILE *fp = stdout; + va_list apc; + + if (fmt && *fmt != '\0' && retval != 0) { + fp = stderr; + va_copy(apc, ap); + if (strcmp(cmd, "ewend") == 0) + col = _ewarnvn(fmt, apc); + else + col = _eerrorvn(fmt, apc); + col += fprintf(fp, "\n"); + va_end(apc); + } + _eend(fp, col, + retval == 0 ? ECOLOR_GOOD : ECOLOR_BAD, + retval == 0 ? OK : NOT_OK); + return retval; +} + +int +eend(int retval, const char *EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (is_quiet()) + return retval; + va_start(ap, fmt); + _do_eend("eend", retval, fmt, ap); + va_end(ap); + LASTCMD("eend"); + return retval; +} +hidden_def(eend) + +int +ewend(int retval, const char *EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (is_quiet()) + return retval; + va_start(ap, fmt); + _do_eend("ewend", retval, fmt, ap); + va_end(ap); + LASTCMD("ewend"); + return retval; +} +hidden_def(ewend) + +void +ebracket(int col, ECOLOR color, const char *msg) +{ + _eend(stdout, col, color, msg); +} +hidden_def(ebracket) + +void +eindent(void) +{ + char *env = getenv("EINFO_INDENT"); + int amount = 0; + char num[10]; + + if (env) { + errno = 0; + amount = strtoimax(env, NULL, 0); + if (errno != 0) + amount = 0; + } + amount += INDENT_WIDTH; + if (amount > INDENT_MAX) + amount = INDENT_MAX; + snprintf(num, 10, "%08d", amount); + setenv("EINFO_INDENT", num, 1); +} +hidden_def(eindent) + +void eoutdent(void) +{ + char *env = getenv("EINFO_INDENT"); + int amount = 0; + char num[10]; + int serrno = errno; + + if (!env) + return; + errno = 0; + amount = strtoimax(env, NULL, 0); + if (errno != 0) + amount = 0; + else + amount -= INDENT_WIDTH; + if (amount <= 0) + unsetenv("EINFO_INDENT"); + else { + snprintf(num, 10, "%08d", amount); + setenv("EINFO_INDENT", num, 1); + } + errno = serrno; +} +hidden_def(eoutdent) + +int +einfovn(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || !is_verbose()) + return 0; + va_start(ap, fmt); + retval = _einfovn(fmt, ap); + va_end(ap); + LASTCMD("einfovn"); + return retval; +} +hidden_def(einfovn) + +int +ewarnvn(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || !is_verbose()) + return 0; + va_start(ap, fmt); + retval = _ewarnvn(fmt, ap); + va_end(ap); + LASTCMD("ewarnvn"); + return retval; +} +hidden_def(ewarnvn) + +int +einfov(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || !is_verbose()) + return 0; + va_start(ap, fmt); + retval = _einfovn(fmt, ap); + retval += printf("\n"); + va_end(ap); + LASTCMD("einfov"); + return retval; +} +hidden_def(einfov) + +int +ewarnv(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || !is_verbose()) + return 0; + va_start(ap, fmt); + retval = _ewarnvn(fmt, ap); + retval += printf("\n"); + va_end(ap); + LASTCMD("ewarnv"); + return retval; +} +hidden_def(ewarnv) + +int +ebeginv(const char *EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (!fmt || !is_verbose()) + return 0; + + va_start(ap, fmt); + retval = _einfovn(fmt, ap); + retval += printf(" ..."); + if (colour_terminal(stdout)) + retval += printf("\n"); + va_end(ap); + LASTCMD("ebeginv"); + return retval; +} +hidden_def(ebeginv) + +int +eendv(int retval, const char *EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (!is_verbose()) + return 0; + va_start(ap, fmt); + _do_eend("eendv", retval, fmt, ap); + va_end(ap); + LASTCMD("eendv"); + return retval; +} +hidden_def(eendv) + +int +ewendv(int retval, const char *EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (!is_verbose()) + return 0; + va_start(ap, fmt); + _do_eend("ewendv", retval, fmt, ap); + va_end(ap); + LASTCMD("ewendv"); + return retval; +} +hidden_def(ewendv) + +void +eindentv(void) +{ + if (is_verbose()) + eindent(); +} +hidden_def(eindentv) + +void +eoutdentv(void) +{ + if (is_verbose()) + eoutdent(); +} +hidden_def(eoutdentv) Index: contrib/openrc/src/librc/Makefile =================================================================== --- /dev/null +++ contrib/openrc/src/librc/Makefile @@ -0,0 +1,48 @@ +LIB= rc +SHLIB_MAJOR= 1 +SRCS= librc.c librc-daemon.c librc-depend.c librc-misc.c \ + librc-stringlist.c +INCS= rc.h +VERSION_MAP= rc.map + +LDADD+= ${LIBKVM} + +LOCAL_CPPFLAGS+= -I../includes + +MK= ../../mk +include ${MK}/lib.mk +include ${MK}/cc.mk + +# Massage our header file for our dirs +SED_CMD= -e 's:@PREFIX@:${PREFIX}:g' +SED_CMD+= -e 's:@LIB@:${LIBNAME}:g' +SED_CMD+= -e 's:@SYSCONFDIR@:${SYSCONFDIR}:g' +SED_CMD+= -e 's:@LIBEXECDIR@:${LIBEXECDIR}:g' +SED_CMD+= -e 's:@BINDIR@:${BINDIR}:g' +SED_CMD+= -e 's:@SBINDIR@:${SBINDIR}:g' + +_PKG_PREFIX= -e 's:.*@PKG_PREFIX@.*:\#undef RC_PKG_PREFIX:g' +ifneq (${PKG_PREFIX},) +ifneq (${PKG_PREFIX},/) +ifneq (${PKG_PREFIX},${PREFIX}) +_PKG_PREFIX= -e 's:@PKG_PREFIX@:${PKG_PREFIX}:g' +endif +endif +endif +SED_CMD+= ${_PKG_PREFIX} + +_LCL_PREFIX= -e 's:@LOCAL_PREFIX@::g' +ifneq (${LOCAL_PREFIX},) +ifneq (${LOCAL_PREFIX},/) +ifneq (${LOCAL_PREFIX},${PREFIX}) +_LCL_PREFIX= -e 's:@LOCAL_PREFIX@:${LOCAL_PREFIX}:g' +endif +endif +endif +SED_CMD+= ${_LCL_PREFIX} + +%.h: %.h.in + ${SED} ${SED_CMD} $< > $@ +${SRCS}: rc.h + +CLEANFILES+= rc.h Index: contrib/openrc/src/librc/librc-daemon.c =================================================================== --- /dev/null +++ contrib/openrc/src/librc/librc-daemon.c @@ -0,0 +1,652 @@ +/* + * librc-daemon + * Finds PID for given daemon criteria +*/ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include "queue.h" +#include "librc.h" + +#if defined(__linux__) || (defined (__FreeBSD_kernel__) && defined(__GLIBC__)) \ + || defined(__GNU__) +static bool +pid_is_exec(pid_t pid, const char *exec) +{ + char buffer[32]; + FILE *fp; + int c; + bool retval = false; + + exec = basename_c(exec); + snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid); + if ((fp = fopen(buffer, "r"))) { + while ((c = getc(fp)) != EOF && c != '(') + ; + if (c == '(') { + while ((c = getc(fp)) != EOF && c == *exec) + exec++; + if (c == ')' && *exec == '\0') + retval = true; + } + fclose(fp); + } + return retval; +} + +static bool +pid_is_argv(pid_t pid, const char *const *argv) +{ + char cmdline[32]; + int fd; + char buffer[PATH_MAX]; + char *p; + ssize_t bytes; + + snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid); + if ((fd = open(cmdline, O_RDONLY)) < 0) + return false; + bytes = read(fd, buffer, sizeof(buffer)); + close(fd); + if (bytes == -1) + return false; + + buffer[bytes] = '\0'; + p = buffer; + while (*argv) { + if (strcmp(*argv, p) != 0) + return false; + argv++; + p += strlen(p) + 1; + if ((unsigned)(p - buffer) > sizeof(buffer)) + return false; + } + return true; +} + +RC_PIDLIST * +rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid) +{ + DIR *procdir; + struct dirent *entry; + FILE *fp; + int rc; + bool container_pid = false; + bool openvz_host = false; + char *line = NULL; + char my_ns[30]; + char proc_ns[30]; + size_t len = 0; + pid_t p; + char buffer[PATH_MAX]; + struct stat sb; + pid_t openrc_pid = 0; + char *pp; + RC_PIDLIST *pids = NULL; + RC_PID *pi; + + if ((procdir = opendir("/proc")) == NULL) + return NULL; + + /* + We never match RC_OPENRC_PID if present so we avoid the below + scenario + + /etc/init.d/ntpd stop does + start-stop-daemon --stop --name ntpd + catching /etc/init.d/ntpd stop + + nasty + */ + + if ((pp = getenv("RC_OPENRC_PID"))) { + if (sscanf(pp, "%d", &openrc_pid) != 1) + openrc_pid = 0; + } + + /* + If /proc/self/status contains EnvID: 0, then we are an OpenVZ host, + and we will need to filter out processes that are inside containers + from our list of pids. + */ + + if (exists("/proc/self/status")) { + fp = fopen("/proc/self/status", "r"); + if (fp) { + while (! feof(fp)) { + rc_getline(&line, &len, fp); + if (strncmp(line, "envID:\t0", 8) == 0) { + openvz_host = true; + break; + } + } + fclose(fp); + } + } + + memset(my_ns, 0, sizeof(my_ns)); + memset(proc_ns, 0, sizeof(proc_ns)); + if (exists("/proc/self/ns/pid")) { + rc = readlink("/proc/self/ns/pid", my_ns, sizeof(my_ns)); + if (rc <= 0) + my_ns[0] = '\0'; + } + + while ((entry = readdir(procdir)) != NULL) { + if (sscanf(entry->d_name, "%d", &p) != 1) + continue; + if (openrc_pid != 0 && openrc_pid == p) + continue; + if (pid != 0 && pid != p) + continue; + snprintf(buffer, sizeof(buffer), "/proc/%d/ns/pid", p); + if (exists(buffer)) { + rc = readlink(buffer, proc_ns, sizeof(proc_ns)); + if (rc <= 0) + proc_ns[0] = '\0'; + } + if (strlen(my_ns) && strlen (proc_ns) && strcmp(my_ns, proc_ns)) + continue; + if (uid) { + snprintf(buffer, sizeof(buffer), "/proc/%d", p); + if (stat(buffer, &sb) != 0 || sb.st_uid != uid) + continue; + } + if (exec && !pid_is_exec(p, exec)) + continue; + if (argv && + !pid_is_argv(p, (const char *const *)argv)) + continue; + /* If this is an OpenVZ host, filter out container processes */ + if (openvz_host) { + snprintf(buffer, sizeof(buffer), "/proc/%d/status", p); + if (exists(buffer)) { + fp = fopen(buffer, "r"); + if (! fp) + continue; + while (! feof(fp)) { + rc_getline(&line, &len, fp); + if (strncmp(line, "envID:", 6) == 0) { + container_pid = ! (strncmp(line, "envID:\t0", 8) == 0); + break; + } + } + fclose(fp); + } + } + if (container_pid) + continue; + if (!pids) { + pids = xmalloc(sizeof(*pids)); + LIST_INIT(pids); + } + pi = xmalloc(sizeof(*pi)); + pi->pid = p; + LIST_INSERT_HEAD(pids, pi, entries); + } + if (line != NULL) + free(line); + closedir(procdir); + return pids; +} +librc_hidden_def(rc_find_pids) + +#elif BSD + +# if defined(__NetBSD__) || defined(__OpenBSD__) +# define _KVM_GETPROC2 +# define _KINFO_PROC kinfo_proc2 +# define _KVM_GETARGV kvm_getargv2 +# define _GET_KINFO_UID(kp) (kp.p_ruid) +# define _GET_KINFO_COMM(kp) (kp.p_comm) +# define _GET_KINFO_PID(kp) (kp.p_pid) +# define _KVM_PATH NULL +# define _KVM_FLAGS KVM_NO_FILES +# else +# ifndef KERN_PROC_PROC +# define KERN_PROC_PROC KERN_PROC_ALL +# endif +# define _KINFO_PROC kinfo_proc +# define _KVM_GETARGV kvm_getargv +# if defined(__DragonFly__) +# define _GET_KINFO_UID(kp) (kp.kp_ruid) +# define _GET_KINFO_COMM(kp) (kp.kp_comm) +# define _GET_KINFO_PID(kp) (kp.kp_pid) +# else +# define _GET_KINFO_UID(kp) (kp.ki_ruid) +# define _GET_KINFO_COMM(kp) (kp.ki_comm) +# define _GET_KINFO_PID(kp) (kp.ki_pid) +# endif +# define _KVM_PATH _PATH_DEVNULL +# define _KVM_FLAGS O_RDONLY +# endif + +RC_PIDLIST * +rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid) +{ + static kvm_t *kd = NULL; + char errbuf[_POSIX2_LINE_MAX]; + struct _KINFO_PROC *kp; + int i; + int processes = 0; + int pargc = 0; + char **pargv; + RC_PIDLIST *pids = NULL; + RC_PID *pi; + pid_t p; + const char *const *arg; + int match; + + if ((kd = kvm_openfiles(_KVM_PATH, _KVM_PATH, + NULL, _KVM_FLAGS, errbuf)) == NULL) + { + fprintf(stderr, "kvm_open: %s\n", errbuf); + return NULL; + } + +#ifdef _KVM_GETPROC2 + kp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(*kp), &processes); +#else + kp = kvm_getprocs(kd, KERN_PROC_PROC, 0, &processes); +#endif + if ((kp == NULL && processes > 0) || (kp != NULL && processes < 0)) { + fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); + kvm_close(kd); + return NULL; + } + + if (exec) + exec = basename_c(exec); + for (i = 0; i < processes; i++) { + p = _GET_KINFO_PID(kp[i]); + if (pid != 0 && pid != p) + continue; + if (uid != 0 && uid != _GET_KINFO_UID(kp[i])) + continue; + if (exec) { + if (!_GET_KINFO_COMM(kp[i]) || + strcmp(exec, _GET_KINFO_COMM(kp[i])) != 0) + continue; + } + if (argv && *argv) { + pargv = _KVM_GETARGV(kd, &kp[i], pargc); + if (!pargv || !*pargv) + continue; + arg = argv; + match = 1; + while (*arg && *pargv) + if (strcmp(*arg++, *pargv++) != 0) { + match = 0; + break; + } + if (!match) + continue; + } + if (!pids) { + pids = xmalloc(sizeof(*pids)); + LIST_INIT(pids); + } + pi = xmalloc(sizeof(*pi)); + pi->pid = p; + LIST_INSERT_HEAD(pids, pi, entries); + } + kvm_close(kd); + + return pids; +} +librc_hidden_def(rc_find_pids) + +#else +# error "Platform not supported!" +#endif + +static bool +_match_daemon(const char *path, const char *file, RC_STRINGLIST *match) +{ + char *line = NULL; + size_t len = 0; + char ffile[PATH_MAX]; + FILE *fp; + RC_STRING *m; + + snprintf(ffile, sizeof(ffile), "%s/%s", path, file); + fp = fopen(ffile, "r"); + + if (!fp) + return false; + + while ((rc_getline(&line, &len, fp))) { + TAILQ_FOREACH(m, match, entries) + if (strcmp(line, m->value) == 0) { + TAILQ_REMOVE(match, m, entries); + break; + } + if (!TAILQ_FIRST(match)) + break; + } + fclose(fp); + free(line); + if (TAILQ_FIRST(match)) + return false; + return true; +} + +static RC_STRINGLIST * +_match_list(const char *exec, const char *const *argv, const char *pidfile) +{ + RC_STRINGLIST *match = rc_stringlist_new(); + int i = 0; + size_t l; + char *m; + + if (exec) { + l = strlen(exec) + 6; + m = xmalloc(sizeof(char) * l); + snprintf(m, l, "exec=%s", exec); + rc_stringlist_add(match, m); + free(m); + } + + while (argv && argv[i]) { + l = strlen(*argv) + strlen("argv_=") + 16; + m = xmalloc(sizeof(char) * l); + snprintf(m, l, "argv_0=%s", argv[i++]); + rc_stringlist_add(match, m); + free(m); + } + + if (pidfile) { + l = strlen(pidfile) + 9; + m = xmalloc(sizeof(char) * l); + snprintf(m, l, "pidfile=%s", pidfile); + rc_stringlist_add(match, m); + free(m); + } + + return match; +} + +bool +rc_service_daemon_set(const char *service, const char *exec, + const char *const *argv, + const char *pidfile, bool started) +{ + char dirpath[PATH_MAX]; + char file[PATH_MAX]; + int nfiles = 0; + char oldfile[PATH_MAX] = { '\0' }; + bool retval = false; + DIR *dp; + struct dirent *d; + RC_STRINGLIST *match; + int i = 0; + FILE *fp; + + if (!exec && !pidfile) { + errno = EINVAL; + return false; + } + + snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", + basename_c(service)); + + /* Regardless, erase any existing daemon info */ + if ((dp = opendir(dirpath))) { + match = _match_list(exec, argv, pidfile); + while ((d = readdir(dp))) { + if (d->d_name[0] == '.') + continue; + + snprintf(file, sizeof(file), "%s/%s", + dirpath, d->d_name); + nfiles++; + + if (!*oldfile) { + if (_match_daemon(dirpath, d->d_name, match)) { + unlink(file); + strlcpy(oldfile, file, sizeof(oldfile)); + nfiles--; + } + } else { + rename(file, oldfile); + strlcpy(oldfile, file, sizeof(oldfile)); + } + } + closedir(dp); + rc_stringlist_free(match); + } + + /* Now store our daemon info */ + if (started) { + if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) { + snprintf(file, sizeof(file), "%s/%03d", + dirpath, nfiles + 1); + if ((fp = fopen(file, "w"))) { + fprintf(fp, "exec="); + if (exec) + fprintf(fp, "%s", exec); + while (argv && argv[i]) { + fprintf(fp, "\nargv_%d=%s", i, argv[i]); + i++; + } + fprintf(fp, "\npidfile="); + if (pidfile) + fprintf(fp, "%s", pidfile); + fprintf(fp, "\n"); + fclose(fp); + retval = true; + } + } + } else + retval = true; + + return retval; +} +librc_hidden_def(rc_service_daemon_set) + +bool +rc_service_started_daemon(const char *service, + const char *exec, const char *const *argv, int indx) +{ + char dirpath[PATH_MAX]; + char file[16]; + RC_STRINGLIST *match; + bool retval = false; + DIR *dp; + struct dirent *d; + + if (!service || !exec) + return false; + + snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", + basename_c(service)); + match = _match_list(exec, argv, NULL); + + if (indx > 0) { + snprintf(file, sizeof(file), "%03d", indx); + retval = _match_daemon(dirpath, file, match); + } else { + if ((dp = opendir(dirpath))) { + while ((d = readdir(dp))) { + if (d->d_name[0] == '.') + continue; + retval = _match_daemon(dirpath, d->d_name, match); + if (retval) + break; + } + closedir(dp); + } + } + + rc_stringlist_free(match); + return retval; +} +librc_hidden_def(rc_service_started_daemon) + +bool +rc_service_daemons_crashed(const char *service) +{ + char dirpath[PATH_MAX]; + DIR *dp; + struct dirent *d; + char *path = dirpath; + FILE *fp; + char *line = NULL; + size_t len = 0; + char **argv = NULL; + char *exec = NULL; + char *name = NULL; + char *pidfile = NULL; + pid_t pid = 0; + RC_PIDLIST *pids; + RC_PID *p1; + RC_PID *p2; + char *p; + char *token; + bool retval = false; + RC_STRINGLIST *list = NULL; + RC_STRING *s; + size_t i; + char *ch_root; + char *spidfile; + + path += snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", + basename_c(service)); + + if (!(dp = opendir(dirpath))) + return false; + + while ((d = readdir(dp))) { + if (d->d_name[0] == '.') + continue; + + snprintf(path, sizeof(dirpath) - (path - dirpath), "/%s", + d->d_name); + fp = fopen(dirpath, "r"); + if (!fp) + break; + + while ((rc_getline(&line, &len, fp))) { + p = line; + if ((token = strsep(&p, "=")) == NULL || !p) + continue; + + if (!*p) + continue; + + if (strcmp(token, "exec") == 0) { + if (exec) + free(exec); + exec = xstrdup(p); + } else if (strncmp(token, "argv_", 5) == 0) { + if (!list) + list = rc_stringlist_new(); + rc_stringlist_add(list, p); + } else if (strcmp(token, "name") == 0) { + if (name) + free(name); + name = xstrdup(p); + } else if (strcmp(token, "pidfile") == 0) { + pidfile = xstrdup(p); + break; + } + } + fclose(fp); + + ch_root = rc_service_value_get(basename_c(service), "chroot"); + spidfile = pidfile; + if (ch_root && pidfile) { + spidfile = xmalloc(strlen(ch_root) + strlen(pidfile) + 1); + strcpy(spidfile, ch_root); + strcat(spidfile, pidfile); + free(pidfile); + pidfile = spidfile; + } + + pid = 0; + if (pidfile) { + retval = true; + if ((fp = fopen(pidfile, "r"))) { + if (fscanf(fp, "%d", &pid) == 1) + retval = false; + fclose(fp); + } + free(pidfile); + pidfile = NULL; + + /* We have the pid, so no need to match + on exec or name */ + free(exec); + exec = NULL; + free(name); + name = NULL; + } else { + if (exec) { + if (!list) + list = rc_stringlist_new(); + if (!TAILQ_FIRST(list)) + rc_stringlist_add(list, exec); + + free(exec); + exec = NULL; + } + + if (list) { + /* We need to flatten our linked list + into an array */ + i = 0; + TAILQ_FOREACH(s, list, entries) + i++; + argv = xmalloc(sizeof(char *) * (i + 1)); + i = 0; + TAILQ_FOREACH(s, list, entries) + argv[i++] = s->value; + argv[i] = NULL; + } + } + + if (!retval) { + if (pid != 0) { + if (kill(pid, 0) == -1 && errno == ESRCH) + retval = true; + } else if ((pids = rc_find_pids(exec, + (const char *const *)argv, + 0, pid))) + { + p1 = LIST_FIRST(pids); + while (p1) { + p2 = LIST_NEXT(p1, entries); + free(p1); + p1 = p2; + } + free(pids); + } else + retval = true; + } + rc_stringlist_free(list); + list = NULL; + free(argv); + argv = NULL; + free(exec); + exec = NULL; + free(name); + name = NULL; + if (retval) + break; + } + closedir(dp); + free(line); + + return retval; +} +librc_hidden_def(rc_service_daemons_crashed) Index: contrib/openrc/src/librc/librc-depend.c =================================================================== --- /dev/null +++ contrib/openrc/src/librc/librc-depend.c @@ -0,0 +1,1085 @@ +/* + * librc-depend + * rc service dependency and ordering + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include + +#include "queue.h" +#include "librc.h" + +#define GENDEP RC_LIBEXECDIR "/sh/gendepends.sh" + +#define RC_DEPCONFIG RC_SVCDIR "/depconfig" + +static const char *bootlevel = NULL; + +static char * +get_shell_value(char *string) +{ + char *p = string; + char *e; + + if (! string) + return NULL; + + if (*p == '\'') + p++; + + e = p + strlen(p) - 1; + if (*e == '\n') + *e-- = 0; + if (*e == '\'') + *e-- = 0; + + if (*p != 0) + return p; + + return NULL; +} + +void +rc_deptree_free(RC_DEPTREE *deptree) +{ + RC_DEPINFO *di; + RC_DEPINFO *di2; + RC_DEPTYPE *dt; + RC_DEPTYPE *dt2; + + if (!deptree) + return; + + di = TAILQ_FIRST(deptree); + while (di) { + di2 = TAILQ_NEXT(di, entries); + dt = TAILQ_FIRST(&di->depends); + while (dt) { + dt2 = TAILQ_NEXT(dt, entries); + rc_stringlist_free(dt->services); + free(dt->type); + free(dt); + dt = dt2; + } + free(di->service); + free(di); + di = di2; + } + free(deptree); +} +librc_hidden_def(rc_deptree_free) + +static RC_DEPINFO * +get_depinfo(const RC_DEPTREE *deptree, const char *service) +{ + RC_DEPINFO *di; + + TAILQ_FOREACH(di, deptree, entries) + if (strcmp(di->service, service) == 0) + return di; + return NULL; +} + +static RC_DEPTYPE * +get_deptype(const RC_DEPINFO *depinfo, const char *type) +{ + RC_DEPTYPE *dt; + + TAILQ_FOREACH(dt, &depinfo->depends, entries) + if (strcmp(dt->type, type) == 0) + return dt; + return NULL; +} + +RC_DEPTREE * +rc_deptree_load(void) { + return rc_deptree_load_file(RC_DEPTREE_CACHE); +} +librc_hidden_def(rc_deptree_load) + +RC_DEPTREE * +rc_deptree_load_file(const char *deptree_file) +{ + FILE *fp; + RC_DEPTREE *deptree; + RC_DEPINFO *depinfo = NULL; + RC_DEPTYPE *deptype = NULL; + char *line = NULL; + size_t len = 0; + char *type; + char *p; + char *e; + int i; + + if (!(fp = fopen(deptree_file, "r"))) + return NULL; + + deptree = xmalloc(sizeof(*deptree)); + TAILQ_INIT(deptree); + while ((rc_getline(&line, &len, fp))) + { + p = line; + e = strsep(&p, "_"); + if (!e || strcmp(e, "depinfo") != 0) + continue; + e = strsep(&p, "_"); + if (!e || sscanf(e, "%d", &i) != 1) + continue; + if (!(type = strsep(&p, "_="))) + continue; + if (strcmp(type, "service") == 0) { + /* Sanity */ + e = get_shell_value(p); + if (! e || *e == '\0') + continue; + depinfo = xmalloc(sizeof(*depinfo)); + TAILQ_INIT(&depinfo->depends); + depinfo->service = xstrdup(e); + TAILQ_INSERT_TAIL(deptree, depinfo, entries); + deptype = NULL; + continue; + } + e = strsep(&p, "="); + if (!e || sscanf(e, "%d", &i) != 1) + continue; + /* Sanity */ + e = get_shell_value(p); + if (!e || *e == '\0') + continue; + if (!deptype || strcmp(deptype->type, type) != 0) { + deptype = xmalloc(sizeof(*deptype)); + deptype->services = rc_stringlist_new(); + deptype->type = xstrdup(type); + TAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries); + } + rc_stringlist_add(deptype->services, e); + } + fclose(fp); + free(line); + + return deptree; +} +librc_hidden_def(rc_deptree_load_file) + +static bool +valid_service(const char *runlevel, const char *service, const char *type) +{ + RC_SERVICE state; + + if (!runlevel || + strcmp(type, "ineed") == 0 || + strcmp(type, "needsme") == 0 || + strcmp(type, "iwant") == 0 || + strcmp(type, "wantsme") == 0) + return true; + + if (rc_service_in_runlevel(service, runlevel)) + return true; + if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0) + return false; + if (strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 && + strcmp(type, "iafter") == 0) + return false; + if (strcmp(runlevel, bootlevel) != 0) { + if (rc_service_in_runlevel(service, bootlevel)) + return true; + } + + state = rc_service_state(service); + if (state & RC_SERVICE_HOTPLUGGED || + state & RC_SERVICE_STARTED) + return true; + + return false; +} + +static bool +get_provided1(const char *runlevel, RC_STRINGLIST *providers, + RC_DEPTYPE *deptype, const char *level, + bool hotplugged, RC_SERVICE state) +{ + RC_STRING *service; + RC_SERVICE st; + bool retval = false; + bool ok; + const char *svc; + + TAILQ_FOREACH(service, deptype->services, entries) { + ok = true; + svc = service->value; + st = rc_service_state(svc); + + if (level) + ok = rc_service_in_runlevel(svc, level); + else if (hotplugged) + ok = (st & RC_SERVICE_HOTPLUGGED && + !rc_service_in_runlevel(svc, runlevel) && + !rc_service_in_runlevel(svc, bootlevel)); + if (!ok) + continue; + switch (state) { + case RC_SERVICE_STARTED: + ok = (st & RC_SERVICE_STARTED); + break; + case RC_SERVICE_INACTIVE: + case RC_SERVICE_STARTING: + case RC_SERVICE_STOPPING: + ok = (st & RC_SERVICE_STARTING || + st & RC_SERVICE_STOPPING || + st & RC_SERVICE_INACTIVE); + break; + default: + break; + } + if (!ok) + continue; + retval = true; + rc_stringlist_add(providers, svc); + } + + return retval; +} + +/* Work out if a service is provided by another service. + For example metalog provides logger. + We need to be able to handle syslogd providing logger too. + We do this by checking whats running, then what's starting/stopping, + then what's run in the runlevels and finally alphabetical order. + + If there are any bugs in rc-depend, they will probably be here as + provided dependancy can change depending on runlevel state. + */ +static RC_STRINGLIST * +get_provided(const RC_DEPINFO *depinfo, const char *runlevel, int options) +{ + RC_DEPTYPE *dt; + RC_STRINGLIST *providers = rc_stringlist_new(); + RC_STRING *service; + + dt = get_deptype(depinfo, "providedby"); + if (!dt) + return providers; + + /* If we are stopping then all depends are true, regardless of state. + This is especially true for net services as they could force a restart + of the local dns resolver which may depend on net. */ + if (options & RC_DEP_STOP) { + TAILQ_FOREACH(service, dt->services, entries) + rc_stringlist_add(providers, service->value); + return providers; + } + + /* If we're strict or starting, then only use what we have in our + * runlevel and bootlevel. If we starting then check hotplugged too. */ + if (options & RC_DEP_STRICT || options & RC_DEP_START) { + TAILQ_FOREACH(service, dt->services, entries) + if (rc_service_in_runlevel(service->value, runlevel) || + rc_service_in_runlevel(service->value, bootlevel) || + (options & RC_DEP_START && + rc_service_state(service->value) & RC_SERVICE_HOTPLUGGED)) + rc_stringlist_add(providers, service->value); + if (TAILQ_FIRST(providers)) + return providers; + } + + /* OK, we're not strict or there were no services in our runlevel. + * This is now where the logic gets a little fuzzy :) + * If there is >1 running service then we return NULL. + * We do this so we don't hang around waiting for inactive services and + * our need has already been satisfied as it's not strict. + * We apply this to these states in order:- + * started, starting | stopping | inactive, stopped + * Our sub preference in each of these is in order:- + * runlevel, hotplugged, bootlevel, any + */ +#define DO \ + if (TAILQ_FIRST(providers)) { \ + if (TAILQ_NEXT(TAILQ_FIRST(providers), entries)) { \ + rc_stringlist_free(providers); \ + providers = rc_stringlist_new(); \ + } \ + return providers; \ + } + + /* Anything running has to come first */ + if (get_provided1(runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTED)) + { DO } + if (get_provided1(runlevel, providers, dt, NULL, true, RC_SERVICE_STARTED)) + { DO } + if (bootlevel && strcmp(runlevel, bootlevel) != 0 && + get_provided1(runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTED)) + { DO } + if (get_provided1(runlevel, providers, dt, NULL, false, RC_SERVICE_STARTED)) + { DO } + + /* Check starting services */ + if (get_provided1(runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTING)) + return providers; + if (get_provided1(runlevel, providers, dt, NULL, true, RC_SERVICE_STARTING)) + return providers; + if (bootlevel && strcmp(runlevel, bootlevel) != 0 && + get_provided1(runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTING)) + return providers; + if (get_provided1(runlevel, providers, dt, NULL, false, RC_SERVICE_STARTING)) + return providers; + + /* Nothing started then. OK, lets get the stopped services */ + if (get_provided1(runlevel, providers, dt, runlevel, false, RC_SERVICE_STOPPED)) + return providers; + if (get_provided1(runlevel, providers, dt, NULL, true, RC_SERVICE_STOPPED)) + { DO } + if (bootlevel && (strcmp(runlevel, bootlevel) != 0) && + get_provided1(runlevel, providers, dt, bootlevel, false, RC_SERVICE_STOPPED)) + return providers; + + /* Still nothing? OK, list our first provided service. */ + service = TAILQ_FIRST(dt->services); + if (service != NULL) + rc_stringlist_add(providers, service->value); + + return providers; +} + +static void +visit_service(const RC_DEPTREE *deptree, + const RC_STRINGLIST *types, + RC_STRINGLIST *sorted, + RC_STRINGLIST *visited, + const RC_DEPINFO *depinfo, + const char *runlevel, int options) +{ + RC_STRING *type; + RC_STRING *service; + RC_DEPTYPE *dt; + RC_DEPINFO *di; + RC_STRINGLIST *provided; + RC_STRING *p; + const char *svcname; + + /* Check if we have already visited this service or not */ + TAILQ_FOREACH(type, visited, entries) + if (strcmp(type->value, depinfo->service) == 0) + return; + /* Add ourselves as a visited service */ + rc_stringlist_add(visited, depinfo->service); + + TAILQ_FOREACH(type, types, entries) + { + if (!(dt = get_deptype(depinfo, type->value))) + continue; + + TAILQ_FOREACH(service, dt->services, entries) { + if (!(options & RC_DEP_TRACE) || + strcmp(type->value, "iprovide") == 0) + { + rc_stringlist_add(sorted, service->value); + continue; + } + + if (!(di = get_depinfo(deptree, service->value))) + continue; + provided = get_provided(di, runlevel, options); + + if (TAILQ_FIRST(provided)) { + TAILQ_FOREACH(p, provided, entries) { + di = get_depinfo(deptree, p->value); + if (di && valid_service(runlevel, di->service, type->value)) + visit_service(deptree, types, sorted, visited, di, + runlevel, options | RC_DEP_TRACE); + } + } + else if (di && valid_service(runlevel, service->value, type->value)) + visit_service(deptree, types, sorted, visited, di, + runlevel, options | RC_DEP_TRACE); + + rc_stringlist_free(provided); + } + } + + /* Now visit the stuff we provide for */ + if (options & RC_DEP_TRACE && + (dt = get_deptype(depinfo, "iprovide"))) + { + TAILQ_FOREACH(service, dt->services, entries) { + if (!(di = get_depinfo(deptree, service->value))) + continue; + provided = get_provided(di, runlevel, options); + TAILQ_FOREACH(p, provided, entries) + if (strcmp(p->value, depinfo->service) == 0) { + visit_service(deptree, types, sorted, visited, di, + runlevel, options | RC_DEP_TRACE); + break; + } + rc_stringlist_free(provided); + } + } + + /* We've visited everything we need, so add ourselves unless we + are also the service calling us or we are provided by something */ + svcname = getenv("RC_SVCNAME"); + if (!svcname || strcmp(svcname, depinfo->service) != 0) { + if (!get_deptype(depinfo, "providedby")) + rc_stringlist_add(sorted, depinfo->service); + } +} + +RC_STRINGLIST * +rc_deptree_depend(const RC_DEPTREE *deptree, + const char *service, const char *type) +{ + RC_DEPINFO *di; + RC_DEPTYPE *dt; + RC_STRINGLIST *svcs; + RC_STRING *svc; + + svcs = rc_stringlist_new(); + if (!(di = get_depinfo(deptree, service)) || + !(dt = get_deptype(di, type))) + { + errno = ENOENT; + return svcs; + } + + /* For consistency, we copy the array */ + TAILQ_FOREACH(svc, dt->services, entries) + rc_stringlist_add(svcs, svc->value); + return svcs; +} +librc_hidden_def(rc_deptree_depend) + +RC_STRINGLIST * +rc_deptree_depends(const RC_DEPTREE *deptree, + const RC_STRINGLIST *types, + const RC_STRINGLIST *services, + const char *runlevel, int options) +{ + RC_STRINGLIST *sorted = rc_stringlist_new(); + RC_STRINGLIST *visited = rc_stringlist_new(); + RC_DEPINFO *di; + const RC_STRING *service; + + bootlevel = getenv("RC_BOOTLEVEL"); + if (!bootlevel) + bootlevel = RC_LEVEL_BOOT; + TAILQ_FOREACH(service, services, entries) { + if (!(di = get_depinfo(deptree, service->value))) { + errno = ENOENT; + continue; + } + if (types) + visit_service(deptree, types, sorted, visited, + di, runlevel, options); + } + rc_stringlist_free(visited); + return sorted; +} +librc_hidden_def(rc_deptree_depends) + +RC_STRINGLIST * +rc_deptree_order(const RC_DEPTREE *deptree, const char *runlevel, int options) +{ + RC_STRINGLIST *list; + RC_STRINGLIST *list2; + RC_STRINGLIST *types; + RC_STRINGLIST *services; + + bootlevel = getenv("RC_BOOTLEVEL"); + if (! bootlevel) + bootlevel = RC_LEVEL_BOOT; + + /* When shutting down, list all running services */ + if (strcmp(runlevel, RC_LEVEL_SINGLE) == 0 || + strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0) + { + list = rc_services_in_state(RC_SERVICE_STARTED); + list2 = rc_services_in_state(RC_SERVICE_INACTIVE); + TAILQ_CONCAT(list, list2, entries); + free(list2); + list2 = rc_services_in_state(RC_SERVICE_STARTING); + TAILQ_CONCAT(list, list2, entries); + free(list2); + } else { + list = rc_services_in_runlevel(RC_LEVEL_SYSINIT); + if (strcmp(runlevel, RC_LEVEL_SYSINIT) != 0) { + list2 = rc_services_in_runlevel(runlevel); + TAILQ_CONCAT(list, list2, entries); + free(list2); + list2 = rc_services_in_state(RC_SERVICE_HOTPLUGGED); + TAILQ_CONCAT(list, list2, entries); + free(list2); + /* If we're not the boot runlevel then add that too */ + if (strcmp(runlevel, bootlevel) != 0) { + list2 = rc_services_in_runlevel(bootlevel); + TAILQ_CONCAT(list, list2, entries); + free(list2); + } + } + } + + /* Now we have our lists, we need to pull in any dependencies + and order them */ + types = rc_stringlist_new(); + rc_stringlist_add(types, "ineed"); + rc_stringlist_add(types, "iuse"); + rc_stringlist_add(types, "iwant"); + rc_stringlist_add(types, "iafter"); + services = rc_deptree_depends(deptree, types, list, runlevel, + RC_DEP_STRICT | RC_DEP_TRACE | options); + rc_stringlist_free(list); + rc_stringlist_free(types); + return services; +} +librc_hidden_def(rc_deptree_order) + + +/* Given a time, recurse the target path to find out if there are + any older (or newer) files. If false, sets the time to the + oldest (or newest) found. +*/ +static bool +deep_mtime_check(const char *target, bool newer, + time_t *rel, char *file) +{ + struct stat buf; + bool retval = true; + DIR *dp; + struct dirent *d; + char path[PATH_MAX]; + int serrno = errno; + + /* If target does not exist, return true to mimic shell test */ + if (stat(target, &buf) != 0) + return true; + + if (newer) { + if (*rel < buf.st_mtime) { + retval = false; + + if (file) + strlcpy(file, target, PATH_MAX); + *rel = buf.st_mtime; + } + } else { + if (*rel > buf.st_mtime) { + retval = false; + + if (file) + strlcpy(file, target, PATH_MAX); + *rel = buf.st_mtime; + } + } + + /* If not a dir then reset errno */ + if (!(dp = opendir(target))) { + errno = serrno; + return retval; + } + + /* Check all the entries in the dir */ + while ((d = readdir(dp))) { + if (d->d_name[0] == '.') + continue; + snprintf(path, sizeof(path), "%s/%s", target, d->d_name); + if (!deep_mtime_check(path, newer, rel, file)) { + retval = false; + } + } + closedir(dp); + return retval; +} + +/* Recursively check if target is older/newer than source. + * If false, return the filename and most different time (if + * the return value arguments are non-null). + */ +static bool +mtime_check(const char *source, const char *target, bool newer, + time_t *rel, char *file) +{ + struct stat buf; + time_t mtime; + bool retval = true; + + /* We have to exist */ + if (stat(source, &buf) != 0) + return false; + mtime = buf.st_mtime; + + retval = deep_mtime_check(target,newer,&mtime,file); + if (rel) { + *rel = mtime; + } + return retval; +} + +bool +rc_newer_than(const char *source, const char *target, + time_t *newest, char *file) +{ + + return mtime_check(source, target, true, newest, file); +} +librc_hidden_def(rc_newer_than) + +bool +rc_older_than(const char *source, const char *target, + time_t *oldest, char *file) +{ + return mtime_check(source, target, false, oldest, file); +} +librc_hidden_def(rc_older_than) + +typedef struct deppair +{ + const char *depend; + const char *addto; +} DEPPAIR; + +static const DEPPAIR deppairs[] = { + { "ineed", "needsme" }, + { "iuse", "usesme" }, + { "iwant", "wantsme" }, + { "iafter", "ibefore" }, + { "ibefore", "iafter" }, + { "iprovide", "providedby" }, + { NULL, NULL } +}; + +static const char *const depdirs[] = +{ + RC_SVCDIR, + RC_SVCDIR "/starting", + RC_SVCDIR "/started", + RC_SVCDIR "/stopping", + RC_SVCDIR "/inactive", + RC_SVCDIR "/wasinactive", + RC_SVCDIR "/failed", + RC_SVCDIR "/hotplugged", + RC_SVCDIR "/daemons", + RC_SVCDIR "/options", + RC_SVCDIR "/exclusive", + RC_SVCDIR "/scheduled", + RC_SVCDIR "/tmp", + NULL +}; + +bool +rc_deptree_update_needed(time_t *newest, char *file) +{ + bool newer = false; + RC_STRINGLIST *config; + RC_STRING *s; + int i; + struct stat buf; + time_t mtime; + + /* Create base directories if needed */ + for (i = 0; depdirs[i]; i++) + if (mkdir(depdirs[i], 0755) != 0 && errno != EEXIST) + fprintf(stderr, "mkdir `%s': %s\n", depdirs[i], strerror(errno)); + + /* Quick test to see if anything we use has changed and we have + * data in our deptree. */ + + if (stat(RC_DEPTREE_CACHE, &buf) == 0) { + mtime = buf.st_mtime; + } else { + /* No previous cache found. + * We still run the scan, in case of clock skew; we still need to return + * the newest time. + */ + newer = true; + mtime = time(NULL); + } + + newer |= !deep_mtime_check(RC_INITDIR,true,&mtime,file); + newer |= !deep_mtime_check(RC_CONFDIR,true,&mtime,file); +#ifdef RC_PKG_INITDIR + newer |= !deep_mtime_check(RC_PKG_INITDIR,true,&mtime,file); +#endif +#ifdef RC_PKG_CONFDIR + newer |= !deep_mtime_check(RC_PKG_CONFDIR,true,&mtime,file); +#endif +#ifdef RC_LOCAL_INITDIRs + newer |= !deep_mtime_check(RC_LOCAL_INITDIR,true,&mtime,file); +#endif +#ifdef RC_LOCAL_CONFDIR + newer |= !deep_mtime_check(RC_LOCAL_CONFDIR,true,&mtime,file); +#endif + newer |= !deep_mtime_check(RC_CONF,true,&mtime,file); + newer |= !deep_mtime_check(RC_CONF_DEFAULTS,true,&mtime,file); + + /* Some init scripts dependencies change depending on config files + * outside of baselayout, like syslog-ng, so we check those too. */ + config = rc_config_list(RC_DEPCONFIG); + TAILQ_FOREACH(s, config, entries) { + newer |= !deep_mtime_check(s->value, true, &mtime, file); + } + rc_stringlist_free(config); + + /* Return newest file time, if requested */ + if ((newer) && (newest != NULL)) { + *newest = mtime; + } + + return newer; +} +librc_hidden_def(rc_deptree_update_needed) + +/* This is a 7 phase operation + Phase 1 is a shell script which loads each init script and config in turn + and echos their dependency info to stdout + Phase 2 takes that and populates a depinfo object with that data + Phase 3 adds any provided services to the depinfo object + Phase 4 scans that depinfo object and puts in backlinks + Phase 5 removes broken before dependencies + Phase 6 looks for duplicate services indicating a real and virtual service + with the same names + Phase 7 saves the depinfo object to disk + */ +bool +rc_deptree_update(void) +{ + FILE *fp; + RC_DEPTREE *deptree, *providers; + RC_DEPINFO *depinfo = NULL, *depinfo_np, *di; + RC_DEPTYPE *deptype = NULL, *dt_np, *dt, *provide; + RC_STRINGLIST *config, *dupes, *types, *sorted, *visited; + RC_STRING *s, *s2, *s2_np, *s3, *s4; + char *line = NULL; + size_t len = 0; + char *depend, *depends, *service, *type, *nosys, *onosys; + size_t i, k, l; + bool retval = true; + const char *sys = rc_sys(); + struct utsname uts; + int serrno; + + /* Some init scripts need RC_LIBEXECDIR to source stuff + Ideally we should be setting our full env instead */ + if (!getenv("RC_LIBEXECDIR")) + setenv("RC_LIBEXECDIR", RC_LIBEXECDIR, 0); + + if (uname(&uts) == 0) + setenv("RC_UNAME", uts.sysname, 1); + /* Phase 1 - source all init scripts and print dependencies */ + if (!(fp = popen(GENDEP, "r"))) + return false; + + deptree = xmalloc(sizeof(*deptree)); + TAILQ_INIT(deptree); + config = rc_stringlist_new(); + while ((rc_getline(&line, &len, fp))) + { + depends = line; + service = strsep(&depends, " "); + if (!service || !*service) + continue; + + type = strsep(&depends, " "); + if (!depinfo || strcmp(depinfo->service, service) != 0) { + deptype = NULL; + depinfo = get_depinfo(deptree, service); + if (!depinfo) { + depinfo = xmalloc(sizeof(*depinfo)); + TAILQ_INIT(&depinfo->depends); + depinfo->service = xstrdup(service); + TAILQ_INSERT_TAIL(deptree, depinfo, entries); + } + } + + /* We may not have any depends */ + if (!type || !depends) + continue; + + /* Get the type */ + if (strcmp(type, "config") != 0) { + if (!deptype || strcmp(deptype->type, type) != 0) + deptype = get_deptype(depinfo, type); + if (!deptype) { + deptype = xmalloc(sizeof(*deptype)); + deptype->type = xstrdup(type); + deptype->services = rc_stringlist_new(); + TAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries); + } + } + + /* Now add each depend to our type. + We do this individually so we handle multiple spaces gracefully */ + while ((depend = strsep(&depends, " "))) + { + if (depend[0] == 0) + continue; + + if (strcmp(type, "config") == 0) { + rc_stringlist_addu(config, depend); + continue; + } + + /* Don't provide ourself */ + if (strcmp(type, "iprovide") == 0 && + strcmp(depend, service) == 0) + continue; + + /* .sh files are not init scripts */ + l = strlen(depend); + if (l > 2 && + depend[l - 3] == '.' && + depend[l - 2] == 's' && + depend[l - 1] == 'h') + continue; + + /* Remove our dependency if instructed */ + if (depend[0] == '!') { + rc_stringlist_delete(deptype->services, depend + 1); + continue; + } + + rc_stringlist_add(deptype->services, depend); + + /* We need to allow `after *; before local;` to work. + * Conversely, we need to allow 'before *; after modules' also */ + /* If we're before something, remove us from the after list */ + if (strcmp(type, "ibefore") == 0) { + if ((dt = get_deptype(depinfo, "iafter"))) + rc_stringlist_delete(dt->services, depend); + } + /* If we're after something, remove us from the before list */ + if (strcmp(type, "iafter") == 0 || + strcmp(type, "ineed") == 0 || + strcmp(type, "iwant") == 0 || + strcmp(type, "iuse") == 0) { + if ((dt = get_deptype(depinfo, "ibefore"))) + rc_stringlist_delete(dt->services, depend); + } + } + } + free(line); + pclose(fp); + + /* Phase 2 - if we're a special system, remove services that don't + * work for them. This doesn't stop them from being run directly. */ + if (sys) { + len = strlen(sys); + nosys = xmalloc(len + 2); + nosys[0] = '-'; + for (i = 0; i < len; i++) + nosys[i + 1] = (char)tolower((unsigned char)sys[i]); + nosys[i + 1] = '\0'; + + onosys = xmalloc(len + 3); + onosys[0] = 'n'; + onosys[1] = 'o'; + for (i = 0; i < len; i++) + onosys[i + 2] = (char)tolower((unsigned char)sys[i]); + onosys[i + 2] = '\0'; + + TAILQ_FOREACH_SAFE(depinfo, deptree, entries, depinfo_np) + if ((deptype = get_deptype(depinfo, "keyword"))) + TAILQ_FOREACH(s, deptype->services, entries) + if (strcmp(s->value, nosys) == 0 || + strcmp(s->value, onosys) == 0) + { + provide = get_deptype(depinfo, "iprovide"); + TAILQ_REMOVE(deptree, depinfo, entries); + TAILQ_FOREACH(di, deptree, entries) { + TAILQ_FOREACH_SAFE(dt, &di->depends, entries, dt_np) { + rc_stringlist_delete(dt->services, depinfo->service); + if (provide) + TAILQ_FOREACH(s2, provide->services, entries) + rc_stringlist_delete(dt->services, s2->value); + if (!TAILQ_FIRST(dt->services)) { + TAILQ_REMOVE(&di->depends, dt, entries); + free(dt->type); + free(dt->services); + free(dt); + } + } + } + } + free(nosys); + free(onosys); + } + + /* Phase 3 - add our providers to the tree */ + providers = xmalloc(sizeof(*providers)); + TAILQ_INIT(providers); + TAILQ_FOREACH(depinfo, deptree, entries) + if ((deptype = get_deptype(depinfo, "iprovide"))) + TAILQ_FOREACH(s, deptype->services, entries) { + TAILQ_FOREACH(di, providers, entries) + if (strcmp(di->service, s->value) == 0) + break; + if (!di) { + di = xmalloc(sizeof(*di)); + TAILQ_INIT(&di->depends); + di->service = xstrdup(s->value); + TAILQ_INSERT_TAIL(providers, di, entries); + } + } + TAILQ_CONCAT(deptree, providers, entries); + free(providers); + + /* Phase 4 - backreference our depends */ + TAILQ_FOREACH(depinfo, deptree, entries) + for (i = 0; deppairs[i].depend; i++) { + deptype = get_deptype(depinfo, deppairs[i].depend); + if (!deptype) + continue; + TAILQ_FOREACH(s, deptype->services, entries) { + di = get_depinfo(deptree, s->value); + if (!di) { + if (strcmp(deptype->type, "ineed") == 0) { + fprintf(stderr, + "Service `%s' needs non" + " existent service `%s'\n", + depinfo->service, s->value); + dt = get_deptype(depinfo, "broken"); + if (!dt) { + dt = xmalloc(sizeof(*dt)); + dt->type = xstrdup("broken"); + dt->services = rc_stringlist_new(); + TAILQ_INSERT_TAIL(&depinfo->depends, dt, entries); + } + rc_stringlist_addu(dt->services, s->value); + } + continue; + } + + dt = get_deptype(di, deppairs[i].addto); + if (!dt) { + dt = xmalloc(sizeof(*dt)); + dt->type = xstrdup(deppairs[i].addto); + dt->services = rc_stringlist_new(); + TAILQ_INSERT_TAIL(&di->depends, dt, entries); + } + rc_stringlist_addu(dt->services, depinfo->service); + } + } + + + /* Phase 5 - Remove broken before directives */ + types = rc_stringlist_new(); + rc_stringlist_add(types, "ineed"); + rc_stringlist_add(types, "iwant"); + rc_stringlist_add(types, "iuse"); + rc_stringlist_add(types, "iafter"); + TAILQ_FOREACH(depinfo, deptree, entries) { + deptype = get_deptype(depinfo, "ibefore"); + if (!deptype) + continue; + sorted = rc_stringlist_new(); + visited = rc_stringlist_new(); + visit_service(deptree, types, sorted, visited, depinfo, + NULL, 0); + rc_stringlist_free(visited); + TAILQ_FOREACH_SAFE(s2, deptype->services, entries, s2_np) { + TAILQ_FOREACH(s3, sorted, entries) { + di = get_depinfo(deptree, s3->value); + if (!di) + continue; + if (strcmp(s2->value, s3->value) == 0) { + dt = get_deptype(di, "iafter"); + if (dt) + rc_stringlist_delete(dt->services, depinfo->service); + break; + } + dt = get_deptype(di, "iprovide"); + if (!dt) + continue; + TAILQ_FOREACH(s4, dt->services, entries) { + if (strcmp(s4->value, s2->value) == 0) + break; + } + if (s4) { + di = get_depinfo(deptree, s4->value); + if (di) { + dt = get_deptype(di, "iafter"); + if (dt) + rc_stringlist_delete(dt->services, depinfo->service); + } + break; + } + } + if (s3) + rc_stringlist_delete(deptype->services, s2->value); + } + rc_stringlist_free(sorted); + } + rc_stringlist_free(types); + + /* Phase 6 - Print errors for duplicate services */ + dupes = rc_stringlist_new(); + TAILQ_FOREACH(depinfo, deptree, entries) { + serrno = errno; + errno = 0; + rc_stringlist_addu(dupes,depinfo->service); + if (errno == EEXIST) { + fprintf(stderr, + "Error: %s is the name of a real and virtual service.\n", + depinfo->service); + } + errno = serrno; + } + rc_stringlist_free(dupes); + + /* Phase 7 - save to disk + Now that we're purely in C, do we need to keep a shell parseable file? + I think yes as then it stays human readable + This works and should be entirely shell parseable provided that depend + names don't have any non shell variable characters in + */ + if ((fp = fopen(RC_DEPTREE_CACHE, "w"))) { + i = 0; + TAILQ_FOREACH(depinfo, deptree, entries) { + fprintf(fp, "depinfo_%zu_service='%s'\n", + i, depinfo->service); + TAILQ_FOREACH(deptype, &depinfo->depends, entries) { + k = 0; + TAILQ_FOREACH(s, deptype->services, entries) { + fprintf(fp, + "depinfo_%zu_%s_%zu='%s'\n", + i, deptype->type, k, s->value); + k++; + } + } + i++; + } + fclose(fp); + } else { + fprintf(stderr, "fopen `%s': %s\n", + RC_DEPTREE_CACHE, strerror(errno)); + retval = false; + } + + /* Save our external config files to disk */ + if (TAILQ_FIRST(config)) { + if ((fp = fopen(RC_DEPCONFIG, "w"))) { + TAILQ_FOREACH(s, config, entries) + fprintf(fp, "%s\n", s->value); + fclose(fp); + } else { + fprintf(stderr, "fopen `%s': %s\n", + RC_DEPCONFIG, strerror(errno)); + retval = false; + } + } else { + unlink(RC_DEPCONFIG); + } + + rc_stringlist_free(config); + rc_deptree_free(deptree); + return retval; +} +librc_hidden_def(rc_deptree_update) Index: contrib/openrc/src/librc/librc-misc.c =================================================================== --- /dev/null +++ contrib/openrc/src/librc/librc-misc.c @@ -0,0 +1,456 @@ +/* + * rc-misc.c + * rc misc functions +*/ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include + +#include "queue.h" +#include "librc.h" +#include "helpers.h" + +bool +rc_yesno(const char *value) +{ + if (!value) { + errno = ENOENT; + return false; + } + + if (strcasecmp(value, "yes") == 0 || + strcasecmp(value, "y") == 0 || + strcasecmp(value, "true") == 0 || + strcasecmp(value, "1") == 0) + return true; + + if (strcasecmp(value, "no") != 0 && + strcasecmp(value, "n") != 0 && + strcasecmp(value, "false") != 0 && + strcasecmp(value, "0") != 0) + errno = EINVAL; + + return false; +} +librc_hidden_def(rc_yesno) + + +/** + * Read the entire @file into the buffer and set @len to the + * size of the buffer when finished. For C strings, this will + * be strlen(buffer) + 1. + * Don't forget to free the buffer afterwards! + */ +bool +rc_getfile(const char *file, char **buffer, size_t *len) +{ + bool ret = false; + FILE *fp; + int fd; + struct stat st; + size_t done, left; + + fp = fopen(file, "re"); + if (!fp) + return false; + + /* assume fileno() never fails */ + fd = fileno(fp); + + if (fstat(fd, &st)) + goto finished; + + left = st.st_size; + *len = left + 1; /* NUL terminator */ + *buffer = xrealloc(*buffer, *len); + while (left) { + done = fread(*buffer, sizeof(*buffer[0]), left, fp); + if (done == 0 && ferror(fp)) + goto finished; + left -= done; + } + ret = true; + + finished: + if (!ret) { + free(*buffer); + *len = 0; + } else + (*buffer)[*len - 1] = '\0'; + fclose(fp); + return ret; +} +librc_hidden_def(rc_getfile) + +ssize_t +rc_getline(char **line, size_t *len, FILE *fp) +{ + char *p; + size_t last = 0; + + while (!feof(fp)) { + if (*line == NULL || last != 0) { + *len += BUFSIZ; + *line = xrealloc(*line, *len); + } + p = *line + last; + memset(p, 0, BUFSIZ); + if (fgets(p, BUFSIZ, fp) == NULL) + break; + last += strlen(p); + if (last && (*line)[last - 1] == '\n') { + (*line)[last - 1] = '\0'; + break; + } + } + return last; +} +librc_hidden_def(rc_getline) + +char * +rc_proc_getent(const char *ent _unused) +{ +#ifdef __linux__ + FILE *fp; + char *proc, *p, *value = NULL; + size_t i, len; + + if (!exists("/proc/cmdline")) + return NULL; + + if (!(fp = fopen("/proc/cmdline", "r"))) + return NULL; + + proc = NULL; + i = 0; + if (rc_getline(&proc, &i, fp) == -1 || proc == NULL) + return NULL; + + if (proc != NULL) { + len = strlen(ent); + + while ((p = strsep(&proc, " "))) { + if (strncmp(ent, p, len) == 0 && (p[len] == '\0' || p[len] == ' ' || p[len] == '=')) { + p += len; + + if (*p == '=') + p++; + + value = xstrdup(p); + } + } + } + + if (!value) + errno = ENOENT; + + fclose(fp); + free(proc); + + return value; +#else + return NULL; +#endif +} +librc_hidden_def(rc_proc_getent) + +RC_STRINGLIST * +rc_config_list(const char *file) +{ + FILE *fp; + char *buffer = NULL; + size_t len = 0; + char *p; + char *token; + RC_STRINGLIST *list = rc_stringlist_new(); + + if (!(fp = fopen(file, "r"))) + return list; + + while ((rc_getline(&buffer, &len, fp))) { + p = buffer; + /* Strip leading spaces/tabs */ + while ((*p == ' ') || (*p == '\t')) + p++; + + /* Get entry - we do not want comments */ + token = strsep(&p, "#"); + if (token && (strlen(token) > 1)) { + /* If not variable assignment then skip */ + if (strchr(token, '=')) { + /* Stip the newline if present */ + if (token[strlen(token) - 1] == '\n') + token[strlen(token) - 1] = 0; + + rc_stringlist_add(list, token); + } + } + } + fclose(fp); + free(buffer); + + return list; +} +librc_hidden_def(rc_config_list) + +static void rc_config_set_value(RC_STRINGLIST *config, char *value) +{ + RC_STRING *cline; + char *entry; + size_t i = 0; + char *newline; + char *p = value; + bool replaced; + char *token; + + if (! p) + return; + if (strncmp(p, "export ", 7) == 0) + p += 7; + if (! (token = strsep(&p, "="))) + return; + + entry = xstrdup(token); + /* Preserve shell coloring */ + if (*p == '$') + token = value; + else + do { + /* Bash variables are usually quoted */ + token = strsep(&p, "\"\'"); + } while (token && *token == '\0'); + + /* Drop a newline if that's all we have */ + if (token) { + i = strlen(token) - 1; + if (token[i] == '\n') + token[i] = 0; + + i = strlen(entry) + strlen(token) + 2; + newline = xmalloc(sizeof(char) * i); + snprintf(newline, i, "%s=%s", entry, token); + } else { + i = strlen(entry) + 2; + newline = xmalloc(sizeof(char) * i); + snprintf(newline, i, "%s=", entry); + } + + replaced = false; + /* In shells the last item takes precedence, so we need to remove + any prior values we may already have */ + TAILQ_FOREACH(cline, config, entries) { + i = strlen(entry); + if (strncmp(entry, cline->value, i) == 0 && cline->value[i] == '=') { + /* We have a match now - to save time we directly replace it */ + free(cline->value); + cline->value = newline; + replaced = true; + break; + } + } + + if (!replaced) { + rc_stringlist_add(config, newline); + free(newline); + } + free(entry); +} + +/* + * Override some specific rc.conf options on the kernel command line. + * I only know how to do this in Linux, so if someone wants to supply + * a patch for this on *BSD or tell me how to write the code to do this, + * any suggestions are welcome. + */ +static RC_STRINGLIST *rc_config_kcl(RC_STRINGLIST *config) +{ +#ifdef __linux__ + RC_STRINGLIST *overrides; + RC_STRING *cline, *override, *config_np; + char *tmp = NULL; + char *value = NULL; + size_t varlen = 0; + size_t len = 0; + + overrides = rc_stringlist_new(); + + /* A list of variables which may be overridden on the kernel command line */ + rc_stringlist_add(overrides, "rc_parallel"); + + TAILQ_FOREACH(override, overrides, entries) { + varlen = strlen(override->value); + value = rc_proc_getent(override->value); + + /* No need to continue if there's nothing to override */ + if (!value) { + free(value); + continue; + } + + if (value != NULL) { + len = varlen + strlen(value) + 2; + tmp = xmalloc(sizeof(char) * len); + snprintf(tmp, len, "%s=%s", override->value, value); + } + + /* + * Whenever necessary remove the old config entry first to prevent + * duplicates + */ + TAILQ_FOREACH_SAFE(cline, config, entries, config_np) { + if (strncmp(override->value, cline->value, varlen) == 0 + && cline->value[varlen] == '=') { + rc_stringlist_delete(config, cline->value); + break; + } + } + + /* Add the option (var/value) to the current config */ + rc_stringlist_add(config, tmp); + + free(tmp); + free(value); + } + + rc_stringlist_free(overrides); +#endif + return config; +} + +static RC_STRINGLIST * rc_config_directory(RC_STRINGLIST *config) +{ + DIR *dp; + struct dirent *d; + RC_STRINGLIST *rc_conf_d_files = rc_stringlist_new(); + RC_STRING *fname; + RC_STRINGLIST *rc_conf_d_list; + char path[PATH_MAX]; + RC_STRING *line; + + if ((dp = opendir(RC_CONF_D)) != NULL) { + while ((d = readdir(dp)) != NULL) { + if (fnmatch("*.conf", d->d_name, FNM_PATHNAME) == 0) { + rc_stringlist_addu(rc_conf_d_files, d->d_name); + } + } + closedir(dp); + + if (rc_conf_d_files) { + rc_stringlist_sort(&rc_conf_d_files); + TAILQ_FOREACH(fname, rc_conf_d_files, entries) { + if (! fname->value) + continue; + sprintf(path, "%s/%s", RC_CONF_D, fname->value); + rc_conf_d_list = rc_config_list(path); + TAILQ_FOREACH(line, rc_conf_d_list, entries) + if (line->value) + rc_config_set_value(config, line->value); + rc_stringlist_free(rc_conf_d_list); + } + rc_stringlist_free(rc_conf_d_files); + } + } + return config; +} + +RC_STRINGLIST * +rc_config_load(const char *file) +{ + RC_STRINGLIST *list; + RC_STRINGLIST *config; + RC_STRING *line; + + list = rc_config_list(file); + config = rc_stringlist_new(); + TAILQ_FOREACH(line, list, entries) { + rc_config_set_value(config, line->value); + } + rc_stringlist_free(list); + + return config; +} +librc_hidden_def(rc_config_load) + +char * +rc_config_value(RC_STRINGLIST *list, const char *entry) +{ + RC_STRING *line; + char *p; + size_t len; + + len = strlen(entry); + TAILQ_FOREACH(line, list, entries) { + p = strchr(line->value, '='); + if (p != NULL) { + if (strncmp(entry, line->value, len) == 0 && line->value[len] == '=') + return ++p; + } + } + return NULL; +} +librc_hidden_def(rc_config_value) + +/* Global for caching the strings loaded from rc.conf to avoid reparsing for + * each rc_conf_value call */ +static RC_STRINGLIST *rc_conf = NULL; + +static void +_free_rc_conf(void) +{ + rc_stringlist_free(rc_conf); +} + +char * +rc_conf_value(const char *setting) +{ + RC_STRINGLIST *defaults; + RC_STRINGLIST *old; + RC_STRING *s; + char *p; + + if (! rc_conf) { + rc_conf = rc_config_load(RC_CONF); + atexit(_free_rc_conf); + + /* Support defaults rc.conf */ + if (exists(RC_CONF_DEFAULTS)) { + defaults = rc_config_load(RC_CONF_DEFAULTS); + TAILQ_CONCAT(rc_conf, defaults, entries); + free(defaults); + } + + /* Support old configs. */ + if (exists(RC_CONF_OLD)) { + old = rc_config_load(RC_CONF_OLD); + TAILQ_CONCAT(rc_conf, old, entries); + free(old); + } + + rc_conf = rc_config_directory(rc_conf); + rc_conf = rc_config_kcl(rc_conf); + + /* Convert old uppercase to lowercase */ + TAILQ_FOREACH(s, rc_conf, entries) { + p = s->value; + while (p && *p && *p != '=') { + if (isupper((unsigned char)*p)) + *p = tolower((unsigned char)*p); + p++; + } + } + } + + return rc_config_value(rc_conf, setting); +} +librc_hidden_def(rc_conf_value) Index: contrib/openrc/src/librc/librc-stringlist.c =================================================================== --- /dev/null +++ contrib/openrc/src/librc/librc-stringlist.c @@ -0,0 +1,151 @@ +/* + * librc-strlist.h + * String list functions to make using queue(3) a little easier. +*/ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include "queue.h" +#include "librc.h" + +RC_STRINGLIST * +rc_stringlist_new(void) +{ + RC_STRINGLIST *l = xmalloc(sizeof(*l)); + TAILQ_INIT(l); + return l; +} +librc_hidden_def(rc_stringlist_new) + +RC_STRING * +rc_stringlist_add(RC_STRINGLIST *list, const char *value) +{ + RC_STRING *s = xmalloc(sizeof(*s)); + + s->value = xstrdup(value); + TAILQ_INSERT_TAIL(list, s, entries); + return s; +} +librc_hidden_def(rc_stringlist_add) + +RC_STRING * +rc_stringlist_addu(RC_STRINGLIST *list, const char *value) +{ + RC_STRING *s; + + TAILQ_FOREACH(s, list, entries) + if (strcmp(s->value, value) == 0) { + errno = EEXIST; + return NULL; + } + + return rc_stringlist_add(list, value); +} +librc_hidden_def(rc_stringlist_addu) + +bool +rc_stringlist_delete(RC_STRINGLIST *list, const char *value) +{ + RC_STRING *s; + + TAILQ_FOREACH(s, list, entries) + if (strcmp(s->value, value) == 0) { + TAILQ_REMOVE(list, s, entries); + free(s->value); + free(s); + return true; + } + + errno = EEXIST; + return false; +} +librc_hidden_def(rc_stringlist_delete) + +RC_STRING * +rc_stringlist_find(RC_STRINGLIST *list, const char *value) +{ + RC_STRING *s; + + if (list) { + TAILQ_FOREACH(s, list, entries) + if (strcmp(s->value, value) == 0) + return s; + } + return NULL; +} +librc_hidden_def(rc_stringlist_find) + +RC_STRINGLIST * +rc_stringlist_split(const char *value, const char *sep) +{ + RC_STRINGLIST *list = rc_stringlist_new(); + char *d = xstrdup(value); + char *p = d, *token; + + while ((token = strsep(&p, sep))) + rc_stringlist_add(list, token); + free(d); + + return list; +} +librc_hidden_def(rc_stringlist_split) + +void +rc_stringlist_sort(RC_STRINGLIST **list) +{ + RC_STRINGLIST *l = *list; + RC_STRINGLIST *new = rc_stringlist_new(); + RC_STRING *s; + RC_STRING *sn; + RC_STRING *n; + RC_STRING *last; + + TAILQ_FOREACH_SAFE(s, l, entries, sn) { + TAILQ_REMOVE(l, s, entries); + last = NULL; + TAILQ_FOREACH(n, new, entries) { + if (strcmp(s->value, n->value) < 0) + break; + last = n; + } + if (last) + TAILQ_INSERT_AFTER(new, last, s, entries); + else + TAILQ_INSERT_HEAD(new, s, entries); + } + + /* Now we've sorted the list, copy across the new head */ + free(l); + *list = new; +} +librc_hidden_def(rc_stringlist_sort) + +void +rc_stringlist_free(RC_STRINGLIST *list) +{ + RC_STRING *s1; + RC_STRING *s2; + + if (!list) + return; + + s1 = TAILQ_FIRST(list); + while (s1) { + s2 = TAILQ_NEXT(s1, entries); + free(s1->value); + free(s1); + s1 = s2; + } + free(list); +} +librc_hidden_def(rc_stringlist_free) Index: contrib/openrc/src/librc/librc.h =================================================================== --- /dev/null +++ contrib/openrc/src/librc/librc.h @@ -0,0 +1,122 @@ +/* + * librc.h + * Internal header file to setup build env for files in librc.so + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef _LIBRC_H_ +#define _LIBRC_H_ + +#define _IN_LIBRC + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BSD) && !defined(__GNU__) +#include +#include +#include +#include +#else +#include +#endif + +#include "rc.h" +#include "rc-misc.h" + +#include "hidden-visibility.h" +#define librc_hidden_proto(x) hidden_proto(x) +#define librc_hidden_def(x) hidden_def(x) + +librc_hidden_proto(rc_conf_value) +librc_hidden_proto(rc_config_list) +librc_hidden_proto(rc_config_load) +librc_hidden_proto(rc_config_value) +librc_hidden_proto(rc_deptree_depend) +librc_hidden_proto(rc_deptree_depends) +librc_hidden_proto(rc_deptree_free) +librc_hidden_proto(rc_deptree_load) +librc_hidden_proto(rc_deptree_load_file) +librc_hidden_proto(rc_deptree_order) +librc_hidden_proto(rc_deptree_update) +librc_hidden_proto(rc_deptree_update_needed) +librc_hidden_proto(rc_find_pids) +librc_hidden_proto(rc_getfile) +librc_hidden_proto(rc_getline) +librc_hidden_proto(rc_newer_than) +librc_hidden_proto(rc_proc_getent) +librc_hidden_proto(rc_older_than) +librc_hidden_proto(rc_runlevel_exists) +librc_hidden_proto(rc_runlevel_get) +librc_hidden_proto(rc_runlevel_list) +librc_hidden_proto(rc_runlevel_set) +librc_hidden_proto(rc_runlevel_stack) +librc_hidden_proto(rc_runlevel_stacks) +librc_hidden_proto(rc_runlevel_starting) +librc_hidden_proto(rc_runlevel_stopping) +librc_hidden_proto(rc_runlevel_unstack) +librc_hidden_proto(rc_service_add) +librc_hidden_proto(rc_service_daemons_crashed) +librc_hidden_proto(rc_service_daemon_set) +librc_hidden_proto(rc_service_delete) +librc_hidden_proto(rc_service_description) +librc_hidden_proto(rc_service_exists) +librc_hidden_proto(rc_service_extra_commands) +librc_hidden_proto(rc_service_in_runlevel) +librc_hidden_proto(rc_service_mark) +librc_hidden_proto(rc_service_resolve) +librc_hidden_proto(rc_service_schedule_clear) +librc_hidden_proto(rc_service_schedule_start) +librc_hidden_proto(rc_services_in_runlevel) +librc_hidden_proto(rc_services_in_runlevel_stacked) +librc_hidden_proto(rc_services_in_state) +librc_hidden_proto(rc_services_scheduled) +librc_hidden_proto(rc_services_scheduled_by) +librc_hidden_proto(rc_service_started_daemon) +librc_hidden_proto(rc_service_state) +librc_hidden_proto(rc_service_value_get) +librc_hidden_proto(rc_service_value_set) +librc_hidden_proto(rc_stringlist_add) +librc_hidden_proto(rc_stringlist_addu) +librc_hidden_proto(rc_stringlist_delete) +librc_hidden_proto(rc_stringlist_find) +librc_hidden_proto(rc_stringlist_free) +librc_hidden_proto(rc_stringlist_new) +librc_hidden_proto(rc_stringlist_split) +librc_hidden_proto(rc_stringlist_sort) +librc_hidden_proto(rc_sys) +librc_hidden_proto(rc_yesno) + +#endif Index: contrib/openrc/src/librc/librc.c =================================================================== --- /dev/null +++ contrib/openrc/src/librc/librc.c @@ -0,0 +1,1127 @@ +/* + * librc + * core RC functions + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +static const char librc_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; + +#include "queue.h" +#include "librc.h" +#include +#ifdef __FreeBSD__ +# include +#endif + +#define RC_RUNLEVEL RC_SVCDIR "/softlevel" + +#ifndef S_IXUGO +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) +#endif + +/* File stream used for plugins to write environ vars to */ +FILE *rc_environ_fd = NULL; + +typedef struct rc_service_state_name { + RC_SERVICE state; + const char *name; +} rc_service_state_name_t; + +/* We MUST list the states below 0x10 first + * The rest can be in any order */ +static const rc_service_state_name_t rc_service_state_names[] = { + { RC_SERVICE_STARTED, "started" }, + { RC_SERVICE_STOPPED, "stopped" }, + { RC_SERVICE_STARTING, "starting" }, + { RC_SERVICE_STOPPING, "stopping" }, + { RC_SERVICE_INACTIVE, "inactive" }, + { RC_SERVICE_WASINACTIVE, "wasinactive" }, + { RC_SERVICE_HOTPLUGGED, "hotplugged" }, + { RC_SERVICE_FAILED, "failed" }, + { RC_SERVICE_SCHEDULED, "scheduled"}, + { 0, NULL} +}; + +#define LS_INITD 0x01 +#define LS_DIR 0x02 +static RC_STRINGLIST * +ls_dir(const char *dir, int options) +{ + DIR *dp; + struct dirent *d; + RC_STRINGLIST *list = NULL; + struct stat buf; + size_t l; + char file[PATH_MAX]; + int r; + + list = rc_stringlist_new(); + if ((dp = opendir(dir)) == NULL) + return list; + while (((d = readdir(dp)) != NULL)) { + if (d->d_name[0] != '.') { + if (options & LS_INITD) { + /* Check that our file really exists. + * This is important as a service maybe in a + * runlevel, but could have been removed. */ + snprintf(file, sizeof(file), "%s/%s", + dir, d->d_name); + r = stat(file, &buf); + if (r != 0) + continue; + + /* .sh files are not init scripts */ + l = strlen(d->d_name); + if (l > 2 && d->d_name[l - 3] == '.' && + d->d_name[l - 2] == 's' && + d->d_name[l - 1] == 'h') + continue; + } + if (options & LS_DIR) { + snprintf(file, sizeof(file), "%s/%s", + dir, d->d_name); + if (stat(file, &buf) != 0 || + !S_ISDIR(buf.st_mode)) + continue; + } + rc_stringlist_add(list, d->d_name); + } + } + closedir(dp); + return list; +} + +static bool +rm_dir(const char *pathname, bool top) +{ + DIR *dp; + struct dirent *d; + char file[PATH_MAX]; + struct stat s; + bool retval = true; + + if ((dp = opendir(pathname)) == NULL) + return false; + + errno = 0; + while (((d = readdir(dp)) != NULL) && errno == 0) { + if (strcmp(d->d_name, ".") != 0 && + strcmp(d->d_name, "..") != 0) + { + snprintf(file, sizeof(file), + "%s/%s", pathname, d->d_name); + if (stat(file, &s) != 0) { + retval = false; + break; + } + if (S_ISDIR(s.st_mode)) { + if (!rm_dir(file, true)) + { + retval = false; + break; + } + } else { + if (unlink(file)) { + retval = false; + break; + } + } + } + } + closedir(dp); + + if (!retval) + return false; + + if (top && rmdir(pathname) != 0) + return false; + + return true; +} + +/* Other systems may need this at some point, but for now it's Linux only */ +#ifdef __linux__ +static bool +file_regex(const char *file, const char *regex) +{ + FILE *fp; + char *line = NULL; + size_t len = 0; + regex_t re; + bool retval = true; + int result; + + if (!(fp = fopen(file, "r"))) + return false; + + if ((result = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) { + fclose(fp); + line = xmalloc(sizeof(char) * BUFSIZ); + regerror(result, &re, line, BUFSIZ); + fprintf(stderr, "file_regex: %s", line); + free(line); + return false; + } + + while ((rc_getline(&line, &len, fp))) { + char *str = line; + /* some /proc files have \0 separated content so we have to + loop through the 'line' */ + do { + if (regexec(&re, str, 0, NULL, 0) == 0) + goto found; + str += strlen(str) + 1; + /* len is the size of allocated buffer and we don't + want call regexec BUFSIZE times. find next str */ + while (str < line + len && *str == '\0') + str++; + } while (str < line + len); + } + retval = false; +found: + fclose(fp); + free(line); + regfree(&re); + + return retval; +} +#endif + + +static const char * +get_systype(void) +{ + char *systype = rc_conf_value("rc_sys"); + if (systype) { + char *s = systype; + /* Convert to uppercase */ + while (s && *s) { + if (islower((unsigned char) *s)) + *s = toupper((unsigned char) *s); + s++; + } + } + return systype; +} + +static const char * +detect_prefix(const char *systype) +{ +#ifdef PREFIX + return RC_SYS_PREFIX; +#else + if (systype) { + if (strcmp(systype, RC_SYS_NONE) == 0) + return NULL; + if (strcmp(systype, RC_SYS_PREFIX) == 0) + return RC_SYS_PREFIX; + } + + return NULL; +#endif +} + +static const char * +detect_container(const char *systype _unused) +{ +#ifdef __FreeBSD__ + if (systype) { + if (strcmp(systype, RC_SYS_NONE) == 0) + return NULL; + if (strcmp(systype, RC_SYS_JAIL) == 0) + return RC_SYS_JAIL; + } + + int jailed = 0; + size_t len = sizeof(jailed); + + if (sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0) == 0) + if (jailed == 1) + return RC_SYS_JAIL; +#endif + +#ifdef __linux__ + if (systype) { + if (strcmp(systype, RC_SYS_NONE) == 0) + return NULL; + if (strcmp(systype, RC_SYS_UML) == 0) + return RC_SYS_UML; + if (strcmp(systype, RC_SYS_VSERVER) == 0) + return RC_SYS_VSERVER; + if (strcmp(systype, RC_SYS_OPENVZ) == 0) + return RC_SYS_OPENVZ; + if (strcmp(systype, RC_SYS_LXC) == 0) + return RC_SYS_LXC; + if (strcmp(systype, RC_SYS_RKT) == 0) + return RC_SYS_RKT; + if (strcmp(systype, RC_SYS_SYSTEMD_NSPAWN) == 0) + return RC_SYS_SYSTEMD_NSPAWN; + if (strcmp(systype, RC_SYS_DOCKER) == 0) + return RC_SYS_DOCKER; + } + if (file_regex("/proc/cpuinfo", "UML")) + return RC_SYS_UML; + else if (file_regex("/proc/self/status", + "(s_context|VxID):[[:space:]]*[1-9]")) + return RC_SYS_VSERVER; + else if (exists("/proc/vz/veinfo") && !exists("/proc/vz/version")) + return RC_SYS_OPENVZ; + else if (file_regex("/proc/self/status", + "envID:[[:space:]]*[1-9]")) + return RC_SYS_OPENVZ; /* old test */ + else if (file_regex("/proc/1/environ", "container=lxc")) + return RC_SYS_LXC; + else if (file_regex("/proc/1/environ", "container=rkt")) + return RC_SYS_RKT; + else if (file_regex("/proc/1/environ", "container=systemd-nspawn")) + return RC_SYS_SYSTEMD_NSPAWN; + else if (exists("/.dockerenv")) + return RC_SYS_DOCKER; + /* old test, I'm not sure when this was valid. */ + else if (file_regex("/proc/1/environ", "container=docker")) + return RC_SYS_DOCKER; +#endif + + return NULL; +} + +static const char * +detect_vm(const char *systype _unused) +{ +#ifdef __NetBSD__ + if (systype) { + if (strcmp(systype, RC_SYS_NONE) == 0) + return NULL; + if (strcmp(systype, RC_SYS_XEN0) == 0) + return RC_SYS_XEN0; + if (strcmp(systype, RC_SYS_XENU) == 0) + return RC_SYS_XENU; + } + if (exists("/kern/xen/privcmd")) + return RC_SYS_XEN0; + if (exists("/kern/xen")) + return RC_SYS_XENU; +#endif + +#ifdef __linux__ + if (systype) { + if (strcmp(systype, RC_SYS_NONE) == 0) + return NULL; + if (strcmp(systype, RC_SYS_XEN0) == 0) + return RC_SYS_XEN0; + if (strcmp(systype, RC_SYS_XENU) == 0) + return RC_SYS_XENU; + } + if (exists("/proc/xen")) { + if (file_regex("/proc/xen/capabilities", "control_d")) + return RC_SYS_XEN0; + return RC_SYS_XENU; + } +#endif + + return NULL; +} + +const char * +rc_sys(void) +{ + const char *systype; + const char *sys; + + systype = get_systype(); + sys = detect_prefix(systype); + if (!sys) { + sys = detect_container(systype); + if (!sys) { + sys = detect_vm(systype); + } + } + + return sys; +} +librc_hidden_def(rc_sys) + +static const char * +rc_parse_service_state(RC_SERVICE state) +{ + int i; + + for (i = 0; rc_service_state_names[i].name; i++) { + if (rc_service_state_names[i].state == state) + return rc_service_state_names[i].name; + } + return NULL; +} + +/* Returns a list of all the chained runlevels used by the + * specified runlevel in dependency order, including the + * specified runlevel. */ +static void +get_runlevel_chain(const char *runlevel, RC_STRINGLIST *level_list, RC_STRINGLIST *ancestor_list) +{ + char path[PATH_MAX]; + RC_STRINGLIST *dirs; + RC_STRING *d, *parent; + const char *nextlevel; + + /* + * If we haven't been passed a runlevel or a level list, or + * if the passed runlevel doesn't exist then we're done already! + */ + if (!runlevel || !level_list || !rc_runlevel_exists(runlevel)) + return; + + /* + * We want to add this runlevel to the list but if + * it is already in the list it needs to go at the + * end again. + */ + if (rc_stringlist_find(level_list, runlevel)) + rc_stringlist_delete(level_list, runlevel); + rc_stringlist_add(level_list, runlevel); + + /* + * We can now do exactly the above procedure for our chained + * runlevels. + */ + snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel); + dirs = ls_dir(path, LS_DIR); + TAILQ_FOREACH(d, dirs, entries) { + nextlevel = d->value; + + /* Check for loop */ + if (rc_stringlist_find(ancestor_list, nextlevel)) { + fprintf(stderr, "Loop detected in stacked runlevels attempting to enter runlevel %s!\n", + nextlevel); + fprintf(stderr, "Ancestors:\n"); + TAILQ_FOREACH(parent, ancestor_list, entries) + fprintf(stderr, "\t%s\n", parent->value); + exit(1); + } + + /* Add new ancestor */ + rc_stringlist_add(ancestor_list, nextlevel); + + get_runlevel_chain(nextlevel, level_list, ancestor_list); + + rc_stringlist_delete(ancestor_list, nextlevel); + } + rc_stringlist_free(dirs); +} + +bool +rc_runlevel_starting(void) +{ + return exists(RC_STARTING); +} +librc_hidden_def(rc_runlevel_starting) + +bool +rc_runlevel_stopping(void) +{ + return exists(RC_STOPPING); +} +librc_hidden_def(rc_runlevel_stopping) + +RC_STRINGLIST *rc_runlevel_list(void) +{ + return ls_dir(RC_RUNLEVELDIR, LS_DIR); +} +librc_hidden_def(rc_runlevel_list) + +char * +rc_runlevel_get(void) +{ + FILE *fp; + char *runlevel = NULL; + size_t i; + + if ((fp = fopen(RC_RUNLEVEL, "r"))) { + runlevel = xmalloc(sizeof(char) * PATH_MAX); + if (fgets(runlevel, PATH_MAX, fp)) { + i = strlen(runlevel) - 1; + if (runlevel[i] == '\n') + runlevel[i] = 0; + } else + *runlevel = '\0'; + fclose(fp); + } + + if (!runlevel || !*runlevel) { + free(runlevel); + runlevel = xstrdup(RC_LEVEL_SYSINIT); + } + + return runlevel; +} +librc_hidden_def(rc_runlevel_get) + +bool +rc_runlevel_set(const char *runlevel) +{ + FILE *fp = fopen(RC_RUNLEVEL, "w"); + + if (!fp) + return false; + fprintf(fp, "%s", runlevel); + fclose(fp); + return true; +} +librc_hidden_def(rc_runlevel_set) + +bool +rc_runlevel_exists(const char *runlevel) +{ + char path[PATH_MAX]; + struct stat buf; + + if (!runlevel || strcmp(runlevel, ".") == 0 || strcmp(runlevel, "..") == 0) + return false; + snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel); + if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) + return true; + return false; +} +librc_hidden_def(rc_runlevel_exists) + +bool +rc_runlevel_stack(const char *dst, const char *src) +{ + char d[PATH_MAX], s[PATH_MAX]; + + if (!rc_runlevel_exists(dst) || !rc_runlevel_exists(src)) + return false; + snprintf(s, sizeof(s), "../%s", src); + snprintf(d, sizeof(s), "%s/%s/%s", RC_RUNLEVELDIR, dst, src); + return (symlink(s, d) == 0 ? true : false); +} +librc_hidden_def(rc_runlevel_stack) + +bool +rc_runlevel_unstack(const char *dst, const char *src) +{ + char path[PATH_MAX]; + + snprintf(path, sizeof(path), "%s/%s/%s", RC_RUNLEVELDIR, dst, src); + return (unlink(path) == 0 ? true : false); +} +librc_hidden_def(rc_runlevel_unstack) + +RC_STRINGLIST * +rc_runlevel_stacks(const char *runlevel) +{ + RC_STRINGLIST *stack, *ancestor_list; + stack = rc_stringlist_new(); + ancestor_list = rc_stringlist_new(); + rc_stringlist_add(ancestor_list, runlevel); + get_runlevel_chain(runlevel, stack, ancestor_list); + rc_stringlist_free(ancestor_list); + return stack; +} +librc_hidden_def(rc_runlevel_stacks) + +/* Resolve a service name to its full path */ +char * +rc_service_resolve(const char *service) +{ + char buffer[PATH_MAX]; + char file[PATH_MAX]; + int r; + struct stat buf; + + if (!service) + return NULL; + + if (service[0] == '/') + return xstrdup(service); + + /* First check started services */ + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", "started", service); + if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) { + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + "inactive", service); + if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) + *file = '\0'; + } + + if (*file) { + memset(buffer, 0, sizeof(buffer)); + r = readlink(file, buffer, sizeof(buffer)); + if (r > 0) + return xstrdup(buffer); + } + +#ifdef RC_LOCAL_INITDIR + /* Nope, so lets see if the user has written it */ + snprintf(file, sizeof(file), RC_LOCAL_INITDIR "/%s", service); + if (stat(file, &buf) == 0) + return xstrdup(file); +#endif + + /* System scripts take precedence over 3rd party ones */ + snprintf(file, sizeof(file), RC_INITDIR "/%s", service); + if (stat(file, &buf) == 0) + return xstrdup(file); + +#ifdef RC_PKG_INITDIR + /* Check RC_PKG_INITDIR */ + snprintf(file, sizeof(file), RC_PKG_INITDIR "/%s", service); + if (stat(file, &buf) == 0) + return xstrdup(file); +#endif + + return NULL; +} +librc_hidden_def(rc_service_resolve) + +bool +rc_service_exists(const char *service) +{ + char *file; + bool retval = false; + size_t len; + struct stat buf; + + if (!service) { + errno = EINVAL; + return false; + } + + len = strlen(service); + + /* .sh files are not init scripts */ + if (len > 2 && service[len - 3] == '.' && + service[len - 2] == 's' && + service[len - 1] == 'h') { + errno = EINVAL; + return false; + } + + if (!(file = rc_service_resolve(service))) { + errno = ENOENT; + return false; + } + + if (stat(file, &buf) == 0) { + if (buf.st_mode & S_IXUGO) + retval = true; + else + errno = ENOEXEC; + } + free(file); + return retval; +} +librc_hidden_def(rc_service_exists) + +#define OPTSTR \ +". '%s'; echo $extra_commands $extra_started_commands $extra_stopped_commands" + +RC_STRINGLIST * +rc_service_extra_commands(const char *service) +{ + char *svc; + char *cmd = NULL; + char *buffer = NULL; + size_t len = 0; + RC_STRINGLIST *commands = NULL; + char *token; + char *p; + FILE *fp; + size_t l; + + if (!(svc = rc_service_resolve(service))) + return NULL; + + l = strlen(OPTSTR) + strlen(svc) + 1; + cmd = xmalloc(sizeof(char) * l); + snprintf(cmd, l, OPTSTR, svc); + free(svc); + + if ((fp = popen(cmd, "r"))) { + rc_getline(&buffer, &len, fp); + p = buffer; + commands = rc_stringlist_new(); + + while ((token = strsep(&p, " "))) + if (token[0] != '\0') + rc_stringlist_add(commands, token); + + pclose(fp); + free(buffer); + } + + free(cmd); + return commands; +} +librc_hidden_def(rc_service_extra_commands) + +#define DESCSTR ". '%s'; echo \"${description%s%s}\"" +char * +rc_service_description(const char *service, const char *option) +{ + char *svc; + char *cmd; + char *desc = NULL; + size_t len = 0; + FILE *fp; + size_t l; + + if (!(svc = rc_service_resolve(service))) + return NULL; + + if (!option) + option = ""; + + l = strlen(DESCSTR) + strlen(svc) + strlen(option) + 2; + cmd = xmalloc(sizeof(char) * l); + snprintf(cmd, l, DESCSTR, svc, *option ? "_" : "", option); + free(svc); + if ((fp = popen(cmd, "r"))) { + rc_getline(&desc, &len, fp); + pclose(fp); + } + free(cmd); + return desc; +} +librc_hidden_def(rc_service_description) + +bool +rc_service_in_runlevel(const char *service, const char *runlevel) +{ + char file[PATH_MAX]; + + snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", + runlevel, basename_c(service)); + return exists(file); +} +librc_hidden_def(rc_service_in_runlevel) + +bool +rc_service_mark(const char *service, const RC_SERVICE state) +{ + char file[PATH_MAX]; + int i = 0; + int skip_state = -1; + const char *base; + char *init = rc_service_resolve(service); + bool skip_wasinactive = false; + int s; + char was[PATH_MAX]; + RC_STRINGLIST *dirs; + RC_STRING *dir; + int serrno; + + if (!init) + return false; + + base = basename_c(service); + if (state != RC_SERVICE_STOPPED) { + if (!exists(init)) { + free(init); + return false; + } + + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + rc_parse_service_state(state), base); + if (exists(file)) + unlink(file); + i = symlink(init, file); + if (i != 0) { + free(init); + return false; + } + skip_state = state; + } + + if (state == RC_SERVICE_HOTPLUGGED || state == RC_SERVICE_FAILED) { + free(init); + return true; + } + + /* Remove any old states now */ + for (i = 0; rc_service_state_names[i].name; i++) { + s = rc_service_state_names[i].state; + + if ((s != skip_state && + s != RC_SERVICE_STOPPED && + s != RC_SERVICE_HOTPLUGGED && + s != RC_SERVICE_SCHEDULED) && + (! skip_wasinactive || s != RC_SERVICE_WASINACTIVE)) + { + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + rc_service_state_names[i].name, base); + if (exists(file)) { + if ((state == RC_SERVICE_STARTING || + state == RC_SERVICE_STOPPING) && + s == RC_SERVICE_INACTIVE) + { + snprintf(was, sizeof(was), + RC_SVCDIR "/%s/%s", + rc_parse_service_state(RC_SERVICE_WASINACTIVE), + base); + if (symlink(init, was) == -1) + return false; + skip_wasinactive = true; + } + if (unlink(file) == -1) { + free(init); + return false; + } + } + } + } + + /* Remove the exclusive state if we're inactive */ + if (state == RC_SERVICE_STARTED || + state == RC_SERVICE_STOPPED || + state == RC_SERVICE_INACTIVE) + { + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + "exclusive", base); + unlink(file); + } + + /* Remove any options and daemons the service may have stored */ + if (state == RC_SERVICE_STOPPED) { + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + "options", base); + rm_dir(file, true); + + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + "daemons", base); + rm_dir(file, true); + + rc_service_schedule_clear(service); + } + + /* These are final states, so remove us from scheduled */ + if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) { + snprintf(file, sizeof(file), RC_SVCDIR "/%s", "scheduled"); + dirs = ls_dir(file, 0); + TAILQ_FOREACH(dir, dirs, entries) { + snprintf(was, sizeof(was), "%s/%s/%s", + file, dir->value, base); + unlink(was); + + /* Try and remove the dir; we don't care about errors */ + snprintf(was, sizeof(was), "%s/%s", file, dir->value); + serrno = errno; + rmdir(was); + errno = serrno; + } + rc_stringlist_free(dirs); + } + free(init); + return true; +} +librc_hidden_def(rc_service_mark) + +RC_SERVICE +rc_service_state(const char *service) +{ + int i; + int state = RC_SERVICE_STOPPED; + char file[PATH_MAX]; + RC_STRINGLIST *dirs; + RC_STRING *dir; + const char *base = basename_c(service); + + for (i = 0; rc_service_state_names[i].name; i++) { + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + rc_service_state_names[i].name, base); + if (exists(file)) { + if (rc_service_state_names[i].state <= 0x10) + state = rc_service_state_names[i].state; + else + state |= rc_service_state_names[i].state; + } + } + + if (state & RC_SERVICE_STOPPED) { + dirs = ls_dir(RC_SVCDIR "/scheduled", 0); + TAILQ_FOREACH(dir, dirs, entries) { + snprintf(file, sizeof(file), + RC_SVCDIR "/scheduled/%s/%s", + dir->value, service); + if (exists(file)) { + state |= RC_SERVICE_SCHEDULED; + break; + } + } + rc_stringlist_free(dirs); + } + + return state; +} +librc_hidden_def(rc_service_state) + +char * +rc_service_value_get(const char *service, const char *option) +{ + char *buffer = NULL; + size_t len = 0; + char file[PATH_MAX]; + + snprintf(file, sizeof(file), RC_SVCDIR "/options/%s/%s", + service, option); + rc_getfile(file, &buffer, &len); + + return buffer; +} +librc_hidden_def(rc_service_value_get) + +bool +rc_service_value_set(const char *service, const char *option, + const char *value) +{ + FILE *fp; + char file[PATH_MAX]; + char *p = file; + + p += snprintf(file, sizeof(file), RC_SVCDIR "/options/%s", service); + if (mkdir(file, 0755) != 0 && errno != EEXIST) + return false; + + snprintf(p, sizeof(file) - (p - file), "/%s", option); + if (value) { + if (!(fp = fopen(file, "w"))) + return false; + fprintf(fp, "%s", value); + fclose(fp); + } else { + unlink(file); + } + return true; +} +librc_hidden_def(rc_service_value_set) + + +bool +rc_service_schedule_start(const char *service, const char *service_to_start) +{ + char file[PATH_MAX]; + char *p = file; + char *init; + bool retval; + + /* service may be a provided service, like net */ + if (! service || ! rc_service_exists(service_to_start)) + return false; + + p += snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s", + basename_c(service)); + if (mkdir(file, 0755) != 0 && errno != EEXIST) + return false; + + init = rc_service_resolve(service_to_start); + snprintf(p, sizeof(file) - (p - file), + "/%s", basename_c(service_to_start)); + retval = (exists(file) || symlink(init, file) == 0); + free(init); + return retval; +} +librc_hidden_def(rc_service_schedule_start) + +bool +rc_service_schedule_clear(const char *service) +{ + char dir[PATH_MAX]; + + snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s", + basename_c(service)); + if (!rm_dir(dir, true) && errno == ENOENT) + return true; + return false; +} +librc_hidden_def(rc_service_schedule_clear) + +RC_STRINGLIST * +rc_services_in_runlevel(const char *runlevel) +{ + char dir[PATH_MAX]; + RC_STRINGLIST *list = NULL; + + if (!runlevel) { +#ifdef RC_PKG_INITDIR + RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD); +#endif +#ifdef RC_LOCAL_INITDIR + RC_STRINGLIST *local = ls_dir(RC_LOCAL_INITDIR, LS_INITD); +#endif + + list = ls_dir(RC_INITDIR, LS_INITD); + +#ifdef RC_PKG_INITDIR + TAILQ_CONCAT(list, pkg, entries); + free(pkg); +#endif +#ifdef RC_LOCAL_INITDIR + TAILQ_CONCAT(list, local, entries); + free(local); +#endif + return list; + } + + /* These special levels never contain any services */ + if (strcmp(runlevel, RC_LEVEL_SINGLE) != 0) { + snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel); + list = ls_dir(dir, LS_INITD); + } + if (!list) + list = rc_stringlist_new(); + return list; +} +librc_hidden_def(rc_services_in_runlevel) + +RC_STRINGLIST * +rc_services_in_runlevel_stacked(const char *runlevel) +{ + RC_STRINGLIST *list, *stacks, *sl; + RC_STRING *stack; + + list = rc_services_in_runlevel(runlevel); + stacks = rc_runlevel_stacks(runlevel); + TAILQ_FOREACH(stack, stacks, entries) { + sl = rc_services_in_runlevel(stack->value); + TAILQ_CONCAT(list, sl, entries); + free(sl); + } + return list; +} +librc_hidden_def(rc_services_in_runlevel_stacked) + +RC_STRINGLIST * +rc_services_in_state(RC_SERVICE state) +{ + RC_STRINGLIST *services; + RC_STRINGLIST *list; + RC_STRINGLIST *dirs; + RC_STRING *d; + char dir[PATH_MAX]; + char *p = dir; + + p += snprintf(dir, sizeof(dir), RC_SVCDIR "/%s", + rc_parse_service_state(state)); + + if (state != RC_SERVICE_SCHEDULED) + return ls_dir(dir, LS_INITD); + + dirs = ls_dir(dir, 0); + list = rc_stringlist_new(); + if (! dirs) + return list; + + TAILQ_FOREACH(d, dirs, entries) { + snprintf(p, sizeof(dir) - (p - dir), "/%s", d->value); + services = ls_dir(dir, LS_INITD); + if (services) { + TAILQ_CONCAT(list, services, entries); + free(services); + } + } + rc_stringlist_free(dirs); + return list; +} +librc_hidden_def(rc_services_in_state) + +bool +rc_service_add(const char *runlevel, const char *service) +{ + bool retval; + char *init; + char file[PATH_MAX]; + char path[MAXPATHLEN] = { '\0' }; + char *p = NULL; + char binit[PATH_MAX]; + char *i; + + if (!rc_runlevel_exists(runlevel)) { + errno = ENOENT; + return false; + } + + if (rc_service_in_runlevel(service, runlevel)) { + errno = EEXIST; + return false; + } + + i = init = rc_service_resolve(service); + snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", + runlevel, basename_c(service)); + + /* We need to ensure that only things in /etc/init.d are added + * to the boot runlevel */ + if (strcmp(runlevel, RC_LEVEL_BOOT) == 0) { + p = realpath(dirname(init), path); + if (!*p) { + free(init); + return false; + } + if (strcmp(path, RC_INITDIR) != 0) { + free(init); + errno = EPERM; + return false; + } + snprintf(binit, sizeof(binit), RC_INITDIR "/%s", service); + i = binit; + } + + retval = (symlink(i, file) == 0); + free(init); + return retval; +} +librc_hidden_def(rc_service_add) + +bool +rc_service_delete(const char *runlevel, const char *service) +{ + char file[PATH_MAX]; + + snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", + runlevel, basename_c(service)); + if (unlink(file) == 0) + return true; + return false; +} +librc_hidden_def(rc_service_delete) + +RC_STRINGLIST * +rc_services_scheduled_by(const char *service) +{ + RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0); + RC_STRINGLIST *list = rc_stringlist_new(); + RC_STRING *dir; + char file[PATH_MAX]; + + TAILQ_FOREACH(dir, dirs, entries) { + snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s/%s", + dir->value, service); + if (exists(file)) + rc_stringlist_add(list, file); + } + rc_stringlist_free(dirs); + return list; +} +librc_hidden_def(rc_services_scheduled_by) + +RC_STRINGLIST * +rc_services_scheduled(const char *service) +{ + char dir[PATH_MAX]; + + snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s", + basename_c(service)); + return ls_dir(dir, LS_INITD); +} +librc_hidden_def(rc_services_scheduled) Index: contrib/openrc/src/librc/rc.h.in =================================================================== --- /dev/null +++ contrib/openrc/src/librc/rc.h.in @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __RC_H__ +#define __RC_H__ + +#include +#include +#include + +/* __BEGIN_DECLS */ +#ifdef __cplusplus +extern "C" { +#endif + +#define RC_PREFIX "@PREFIX@" +#define RC_SYSCONFDIR "@SYSCONFDIR@" +#define RC_LIBDIR "@PREFIX@/@LIB@/rc" +#define RC_LIBEXECDIR "@LIBEXECDIR@" +#if defined(PREFIX) +#define RC_SVCDIR RC_LIBEXECDIR "/init.d" +#elif defined(__linux__) || (defined(__FreeBSD_kernel__) && \ + defined(__GLIBC__)) || defined(__GNU__) +#define RC_SVCDIR "/run/openrc" +#else +#define RC_SVCDIR RC_LIBEXECDIR "/init.d" +#endif +#define RC_RUNLEVELDIR RC_SYSCONFDIR "/runlevels" +#define RC_INITDIR RC_SYSCONFDIR "/init.d" +#define RC_CONFDIR RC_SYSCONFDIR "/conf.d" +#define RC_PLUGINDIR RC_LIBDIR "/plugins" + +#define RC_INIT_FIFO RC_SVCDIR"/init.ctl" +#define RC_PROFILE_ENV RC_SYSCONFDIR "/profile.env" +#define RC_SYS_WHITELIST RC_LIBEXECDIR "/conf.d/env_whitelist" +#define RC_USR_WHITELIST RC_SYSCONFDIR "/conf.d/env_whitelist" +#define RC_CONF RC_SYSCONFDIR "/rc.conf" +#define RC_CONF_DEFAULTS RC_SYSCONFDIR "/defaults/rc.conf" +#define RC_CONF_D RC_SYSCONFDIR "/rc.conf.d" +#define RC_CONF_OLD RC_SYSCONFDIR "/conf.d/rc" + +#define RC_PATH_PREFIX RC_LIBEXECDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin" + +/* PKG_PREFIX is where packages are installed if different from the base OS + * On Gentoo this is normally unset, on FreeBSD /usr/local and on NetBSD + * /usr/pkg. */ +#define RC_PKG_PREFIX "@PKG_PREFIX@" +#ifdef RC_PKG_PREFIX +# define RC_PKG_INITDIR RC_PKG_PREFIX "/etc/init.d" +# define RC_PKG_CONFDIR RC_PKG_PREFIX "/etc/conf.d" +#endif + +/* LOCAL_PREFIX is for user written stuff, which the base OS and package + * manger don't touch. */ +/* Disable on FreeBSD +#define RC_LOCAL_PREFIX "@LOCAL_PREFIX@" +#ifdef RC_LOCAL_PREFIX +# define RC_LOCAL_INITDIR RC_LOCAL_PREFIX "/etc/init.d" +# define RC_LOCAL_CONFDIR RC_LOCAL_PREFIX "/etc/conf.d" +#endif +*/ + +#ifndef _SYS_QUEUE_H_ + +/* + * The following are copied directly from our imported queue.h. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { TAILQ_END(head), &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +#endif /* _SYS_QUEUE_H_ */ + +/* A doubly linked list using queue(3) for ease of use */ +typedef struct rc_string { + char *value; + TAILQ_ENTRY(rc_string) entries; +} RC_STRING; +typedef TAILQ_HEAD(rc_stringlist, rc_string) RC_STRINGLIST; + +/*! @name Reserved runlevel names */ +#define RC_LEVEL_SYSINIT "sysinit" +#define RC_LEVEL_SINGLE "single" +#define RC_LEVEL_SHUTDOWN "shutdown" + +/*! Return the current runlevel. + * @return the current runlevel */ +char *rc_runlevel_get(void); + +/*! Checks if the runlevel exists or not + * @param runlevel to check + * @return true if the runlevel exists, otherwise false */ +bool rc_runlevel_exists(const char *); + +/*! Stack a runlevel onto another + * @param runlevel to stack onto + * @param runlevel being stacked + * @return true if successful, otherwise false */ +bool rc_runlevel_stack(const char *, const char *); + +/*! Unstack a runlevel from another + * @param runlevel to unstack from + * @param runlevel being unstacked + * @return true if successful, otherwise false */ +bool rc_runlevel_unstack(const char *, const char *); + +/*! Return a NULL terminated list of runlevel stacks in the runlevels + * @return a NULL terminated list of runlevels */ +RC_STRINGLIST *rc_runlevel_stacks(const char *); + +/*! Return a NULL terminated list of runlevels + * @return a NULL terminated list of runlevels */ +RC_STRINGLIST *rc_runlevel_list(void); + +/*! Set the runlevel. + * This just changes the stored runlevel and does not start or stop any + * services. + * @param runlevel to store */ +bool rc_runlevel_set(const char *); + +/*! Is the runlevel starting? + * @return true if yes, otherwise false */ +bool rc_runlevel_starting(void); + +/*! Is the runlevel stopping? + * @return true if yes, otherwise false */ +bool rc_runlevel_stopping(void); + +/*! @name RC + * A service can be given as a full path or just its name. + * If it's just a name then we try to resolve the service to a full path. + * This should allow the use if local init.d directories in the future. */ + +/*! @brief States a service can be in */ +typedef enum +{ + /* These are actual states + * The service has to be in one only at all times */ + RC_SERVICE_STOPPED = 0x0001, + RC_SERVICE_STARTED = 0x0002, + RC_SERVICE_STOPPING = 0x0004, + RC_SERVICE_STARTING = 0x0008, + RC_SERVICE_INACTIVE = 0x0010, + + /* Service may or may not have been hotplugged */ + RC_SERVICE_HOTPLUGGED = 0x0100, + + /* Optional states service could also be in */ + RC_SERVICE_FAILED = 0x0200, + RC_SERVICE_SCHEDULED = 0x0400, + RC_SERVICE_WASINACTIVE = 0x0800 +} RC_SERVICE; + +/*! Add the service to the runlevel + * @param runlevel to add to + * @param service to add + * @return true if successful, otherwise false */ +bool rc_service_add(const char *, const char *); + +/*! Remove the service from the runlevel + * @param runlevel to remove from + * @param service to remove + * @return true if sucessful, otherwise false */ +bool rc_service_delete(const char *, const char *); + +/*! Save the arguments to find a running daemon + * @param service to save arguments for + * @param exec that we started + * @param name of the process (optional) + * @param pidfile of the process (optional) + * @param started if true, add the arguments otherwise remove existing matching arguments */ +bool rc_service_daemon_set(const char *, const char *, const char *const *, const char *, + bool); + +/*! Returns a description of what the service and/or option does. + * @param service to check + * @param option to check (if NULL, service description) + * @return a newly allocated pointer to the description */ +char *rc_service_description(const char *, const char *); + +/*! Checks if a service exists or not. + * @param service to check + * @return true if service exists, otherwise false */ +bool rc_service_exists(const char *); + +/*! Checks if a service is in a runlevel + * @param service to check + * @param runlevel it should be in + * @return true if service is in the runlevel, otherwise false */ +bool rc_service_in_runlevel(const char *, const char *); + +/*! Marks the service state + * @param service to mark + * @param state service should be in + * @return true if service state change was successful, otherwise false */ +bool rc_service_mark(const char *, RC_SERVICE); + +/*! Lists the extra commands a service has + * @param service to load the commands from + * @return NULL terminated string list of commands */ +RC_STRINGLIST *rc_service_extra_commands(const char *); + +/*! Resolves a service name to its full path. + * @param service to check + * @return pointer to full path of service */ +char *rc_service_resolve(const char *); + +/*! Schedule a service to be started when another service starts + * @param service that starts the scheduled service when started + * @param service_to_start service that will be started */ +bool rc_service_schedule_start(const char *, const char *); + +/*! Return a NULL terminated list of services that are scheduled to start + * when the given service has started + * @param service to check + * @return NULL terminated list of services scheduled to start */ +RC_STRINGLIST *rc_services_scheduled_by(const char *); + +/*! Clear the list of services scheduled to be started by this service + * @param service to clear + * @return true if no errors, otherwise false */ +bool rc_service_schedule_clear(const char *); + +/*! Checks if a service in in a state + * @param service to check + * @return state of the service */ +RC_SERVICE rc_service_state(const char *); + +/*! Check if the service started the daemon + * @param service to check + * @param exec to check + * @param argv to check + * @param indx of the daemon (optional - 1st daemon, 2nd daemon, etc) + * @return true if started by this service, otherwise false */ +bool rc_service_started_daemon(const char *, const char *, + const char *const *, int); + +/*! Return a saved value for a service + * @param service to check + * @param option to load + * @return saved value */ +char *rc_service_value_get(const char *, const char *); + +/*! Save a persistent value for a service + * @param service to save for + * @param option to save + * @param value of the option + * @return true if saved, otherwise false */ +bool rc_service_value_set(const char *, const char *, const char *); + +/*! List the services in a runlevel + * @param runlevel to list + * @return NULL terminated list of services */ +RC_STRINGLIST *rc_services_in_runlevel(const char *); + +/*! List the stacked services in a runlevel + * @param runlevel to list + * @return NULL terminated list of services */ +RC_STRINGLIST *rc_services_in_runlevel_stacked(const char *); + +/*! List the services in a state + * @param state to list + * @return NULL terminated list of services */ +RC_STRINGLIST *rc_services_in_state(RC_SERVICE); + +/*! List the services shceduled to start when this one does + * @param service to check + * @return NULL terminated list of services */ +RC_STRINGLIST *rc_services_scheduled(const char *); + +/*! Checks that all daemons started with start-stop-daemon by the service + * are still running. + * @param service to check + * @return true if all daemons started are still running, otherwise false */ +bool rc_service_daemons_crashed(const char *); + +/*! @name System types + * OpenRC can support some special sub system types, normally virtualization. + * Some services cannot work in these systems, or we do something else. */ +#define RC_SYS_DOCKER "DOCKER" +#define RC_SYS_JAIL "JAIL" +#define RC_SYS_NONE "" +#define RC_SYS_OPENVZ "OPENVZ" +#define RC_SYS_LXC "LXC" +#define RC_SYS_PREFIX "PREFIX" +#define RC_SYS_RKT "RKT" +#define RC_SYS_SYSTEMD_NSPAWN "SYSTEMD-NSPAWN" +#define RC_SYS_UML "UML" +#define RC_SYS_VSERVER "VSERVER" +#define RC_SYS_XEN0 "XEN0" +#define RC_SYS_XENU "XENU" + +/*! Returns the type of subsystem + * @return string from RC_SYS_* types or NULL if none detected */ +const char *rc_sys(void); + +/*! @name Dependency options + * These options can change the services found by the rc_get_depinfo and + * rc_get_depends functions. */ +/*! Trace provided services */ +#define RC_DEP_TRACE (1<<0) +/*! Only use services added to runlevels */ +#define RC_DEP_STRICT (1<<1) +/*! Runlevel is starting */ +#define RC_DEP_START (1<<2) +/*! Runlevel is stopping */ +#define RC_DEP_STOP (1<<3) + +/*! @name Dependencies + * We analyse each init script and cache the resultant dependency tree. + * This tree can be accessed using the below functions. */ + +#ifdef _IN_LIBRC +/*! @name Dependency structures + * private to librc */ + +/*! Singly linked list of dependency types that list the services the + * type is for */ +typedef struct rc_deptype +{ + /*! ineed, iuse, iafter, etc */ + char *type; + /*! list of services */ + RC_STRINGLIST *services; + /*! list of types */ + TAILQ_ENTRY(rc_deptype) entries; +} RC_DEPTYPE; + +/*! Singly linked list of services and their dependencies */ +typedef struct rc_depinfo +{ + /*! Name of service */ + char *service; + /*! Dependencies */ + TAILQ_HEAD(, rc_deptype) depends; + /*! List of entries */ + TAILQ_ENTRY(rc_depinfo) entries; +} RC_DEPINFO; + +typedef TAILQ_HEAD(,rc_depinfo) RC_DEPTREE; +#else +/* Handles to internal structures */ +typedef void *RC_DEPTREE; +#endif + +/*! Check to see if source is newer than target. + * If target is a directory then we traverse it and its children. + * @param source + * @param target + * @param mtime of newest target + * @param filename of the newest target (needs mtime param) + * @return true if source is newer than target, otherwise false */ +bool rc_newer_than(const char *, const char *, time_t *, char *); + +/*! Check to see if source is older than target. + * If target is a directory then we traverse it and its children. + * @param source + * @param target + * @param mtime of oldest target + * @param filename of the oldest target (needs mtime param) + * @return true if source is older than target, otherwise false */ +bool rc_older_than(const char *, const char *, time_t *, char *); + +/*! Read variables/values from /proc/cmdline + * @param value + * @return pointer to the value, otherwise NULL */ +char *rc_proc_getent(const char *); + +/*! Update the cached dependency tree if it's older than any init script, + * its configuration file or an external configuration file the init script + * has specified. + * time_t returns the time of the newest file that the dependency tree + * will be checked against. + * @return true if successful, otherwise false */ +bool rc_deptree_update(void); + +/*! Check if the cached dependency tree is older than any init script, + * its configuration file or an external configuration file the init script + * has specified. + * @param mtime of newest file + * @param buffer of PATH_MAX to store newest file + * @return true if it needs updating, otherwise false */ +bool rc_deptree_update_needed(time_t *, char *); + +/*! Load the cached dependency tree and return a pointer to it. + * This pointer should be freed with rc_deptree_free when done. + * @return pointer to the dependency tree */ +RC_DEPTREE *rc_deptree_load(void); + +/*! Load a cached dependency tree from the specified file and return a pointer + * to it. This pointer should be freed with rc_deptree_free when done. + * @return pointer to the dependency tree */ +RC_DEPTREE *rc_deptree_load_file(const char *); + +/*! List the depend for the type of service + * @param deptree to search + * @param type to use (keywords, etc) + * @param service to check + * @return NULL terminated list of services in order */ +RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *, const char *, const char *); + +/*! List all the services in order that the given services have + * for the given types and options. + * @param deptree to search + * @param types to use (ineed, iuse, etc) + * @param services to check + * @param options to pass + * @return NULL terminated list of services in order */ +RC_STRINGLIST *rc_deptree_depends(const RC_DEPTREE *, const RC_STRINGLIST *, + const RC_STRINGLIST *, const char *, int); + +/*! List all the services that should be stoppned and then started, in order, + * for the given runlevel, including sysinit and boot services where + * approriate. + * @param deptree to search + * @param runlevel to change into + * @param options to pass + * @return NULL terminated list of services in order */ +RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *, const char *, int); + +/*! Free a deptree and its information + * @param deptree to free */ +void rc_deptree_free(RC_DEPTREE *); + +/*! @name Plugins + * For each plugin loaded we will call rc_plugin_hook with the below + * enum and either the runlevel name or service name. + * + * Plugins are called when rc does something. This does not indicate an + * end result and the plugin should use the above functions to query things + * like service status. + * + * The service hooks have extra ones - now and done. This is because after + * start_in we may start other services before we start the service in + * question. now shows we really will start the service now and done shows + * when we have done it as may start scheduled services at this point. */ +/*! Points at which a plugin can hook into RC */ +typedef enum +{ + RC_HOOK_RUNLEVEL_STOP_IN = 1, + RC_HOOK_RUNLEVEL_STOP_OUT = 4, + RC_HOOK_RUNLEVEL_START_IN = 5, + RC_HOOK_RUNLEVEL_START_OUT = 8, + /*! We send the abort if an init script requests we abort and drop + * into single user mode if system not fully booted */ + RC_HOOK_ABORT = 99, + RC_HOOK_SERVICE_STOP_IN = 101, + RC_HOOK_SERVICE_STOP_NOW = 102, + RC_HOOK_SERVICE_STOP_DONE = 103, + RC_HOOK_SERVICE_STOP_OUT = 104, + RC_HOOK_SERVICE_START_IN = 105, + RC_HOOK_SERVICE_START_NOW = 106, + RC_HOOK_SERVICE_START_DONE = 107, + RC_HOOK_SERVICE_START_OUT = 108 +} RC_HOOK; + +/*! Plugin entry point + * @param hook point + * @param name of runlevel or service + * @return 0 for success otherwise -1 */ +int rc_plugin_hook(RC_HOOK, const char *); + +/*! Plugins should write FOO=BAR to this fd to set any environment + * variables they wish. Variables should be separated by NULLs. */ +extern FILE *rc_environ_fd; + + +/*! Return a NULL terminated list of non comment lines from a file. */ +RC_STRINGLIST *rc_config_list(const char *); + +/*! Return a NULL terminated list of key=value lines from a file. */ +RC_STRINGLIST *rc_config_load(const char *); + +/*! Return the value of the entry from a key=value list. */ +char *rc_config_value(RC_STRINGLIST *, const char *); + +/*! Return the value of the entry from rc.conf. */ +char *rc_conf_value(const char *); + +/*! Check if a variable is a boolean and return its value. + * If variable is not a boolean then we set errno to be ENOENT when it does + * not exist or EINVAL if it's not a boolean. + * @param variable to check + * @return true if it matches true, yes or 1, false if otherwise. */ +bool rc_yesno(const char *); + +/*! @name String List functions + * Every string list should be released with a call to rc_stringlist_free. */ + +/*! Create a new stringlinst + * @return pointer to new list */ +RC_STRINGLIST *rc_stringlist_new(void); + +/*! Duplicate the item, add it to end of the list and return a pointer to it. + * @param list to add the item too + * @param item to add. + * @return pointer to newly added item */ +RC_STRING *rc_stringlist_add(RC_STRINGLIST *, const char *); + +/*! If the item does not exist in the list, duplicate it, add it to the + * list and then return a pointer to it. + * @param list to add the item too + * @param item to add. + * @return pointer to newly added item */ +RC_STRING *rc_stringlist_addu(RC_STRINGLIST *, const char *); + +/*! Free the item and remove it from the list. Return 0 on success otherwise -1. + * @param list to add the item too + * @param item to add. + * @return true on success, otherwise false */ +bool rc_stringlist_delete(RC_STRINGLIST *, const char *); + +/*! Find the item on the list. + * @param list to search + * @param item to find. + * @return pointer to item */ +RC_STRING *rc_stringlist_find(RC_STRINGLIST *, const char *); + +/*! Split a string into a stringlist based on separator. + * @param string to split + * @param separator + * @return new list */ +RC_STRINGLIST *rc_stringlist_split(const char *, const char *); + + +/*! Sort the list according to C locale + * @param list to sort */ +void rc_stringlist_sort(RC_STRINGLIST **); + +/*! Frees each item on the list and the list itself. + * @param list to free */ +void rc_stringlist_free(RC_STRINGLIST *); + +typedef struct rc_pid +{ + pid_t pid; + LIST_ENTRY(rc_pid) entries; +} RC_PID; +typedef LIST_HEAD(rc_pidlist, rc_pid) RC_PIDLIST; + +/*! Find processes based on criteria. + * All of these are optional. + * pid overrides anything else. + * If both exec and cmd are given then we ignore exec. + * @param exec to check for + * @param argv to check for + * @param uid to check for + * @param pid to check for + * @return NULL terminated list of pids */ +RC_PIDLIST *rc_find_pids(const char *, const char *const *, uid_t, pid_t); + +/* Basically the same as rc_getline() below, it just returns multiple lines */ +bool rc_getfile(const char *, char **, size_t *); + +/* getline is a handy glibc function that not all libcs have, so + * we have our own */ +ssize_t rc_getline(char **, size_t *, FILE *); + +/* __END_DECLS */ +#ifdef __cplusplus +} +#endif + +#endif Index: contrib/openrc/src/librc/rc.map =================================================================== --- /dev/null +++ contrib/openrc/src/librc/rc.map @@ -0,0 +1,66 @@ +RC_1.0 { +global: + rc_conf_value; + rc_config_list; + rc_config_load; + rc_config_value; + rc_deptree_depend; + rc_deptree_depends; + rc_deptree_free; + rc_deptree_load; + rc_deptree_load_file; + rc_deptree_order; + rc_deptree_update; + rc_deptree_update_needed; + rc_environ_fd; + rc_find_pids; + rc_getfile; + rc_getline; + rc_newer_than; + rc_older_than; + rc_proc_getent; + rc_runlevel_exists; + rc_runlevel_get; + rc_runlevel_list; + rc_runlevel_set; + rc_runlevel_stack; + rc_runlevel_stacks; + rc_runlevel_starting; + rc_runlevel_stopping; + rc_runlevel_unstack; + rc_service_add; + rc_service_daemons_crashed; + rc_service_daemon_set; + rc_service_delete; + rc_service_description; + rc_service_exists; + rc_service_extra_commands; + rc_service_in_runlevel; + rc_service_mark; + rc_service_options; + rc_service_resolve; + rc_service_schedule_clear; + rc_service_schedule_start; + rc_services_in_runlevel; + rc_services_in_runlevel_stacked; + rc_services_in_state; + rc_services_scheduled; + rc_services_scheduled_by; + rc_service_started_daemon; + rc_service_state; + rc_service_value_get; + rc_service_value_set; + rc_stringlist_add; + rc_stringlist_addu; + rc_stringlist_delete; + rc_stringlist_find; + rc_stringlist_split; + rc_stringlist_new; + rc_stringlist_sort; + rc_stringlist_free; + rc_sys; + rc_yesno; + +local: + *; +}; Index: contrib/openrc/src/rc/Makefile =================================================================== --- /dev/null +++ contrib/openrc/src/rc/Makefile @@ -0,0 +1,179 @@ +include ../../Makefile.inc +MK= ../../mk +include ${MK}/os.mk + +SRCS= checkpath.c do_e.c do_mark_service.c do_service.c \ + do_value.c fstabinfo.c is_newer_than.c is_older_than.c \ + mountinfo.c openrc-run.c rc-abort.c rc.c \ + rc-depend.c rc-logger.c rc-misc.c rc-plugin.c \ + rc-service.c rc-status.c rc-update.c \ + shell_var.c start-stop-daemon.c supervise-daemon.c swclock.c _usage.c + +ifeq (${MKSELINUX},yes) +SRCS+= rc-selinux.c +endif + +ifeq (${OS},Linux) +SRCS+= kill_all.c openrc-init.c openrc-shutdown.c rc-wtmp.c +endif + +CLEANFILES= version.h rc-selinux.o + +BINDIR= ${PREFIX}/bin +SBINDIR= ${PREFIX}/sbin +LINKDIR= ${LIBEXECDIR} + +BINPROGS= rc-status +SBINPROGS = openrc openrc-run rc rc-service rc-update runscript \ + start-stop-daemon supervise-daemon +RC_BINPROGS= einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \ + eindent eoutdent esyslog eval_ecolors ewaitfile \ + veinfo vewarn vebegin veend vewend veindent veoutdent \ + checkpath fstabinfo mountinfo rc-depend \ + is_newer_than is_older_than \ + service_get_value service_set_value get_options save_options \ + service_starting service_started \ + service_stopping service_stopped \ + service_inactive service_wasinactive \ + service_hotplugged service_started_daemon service_crashed \ + shell_var +RC_SBINPROGS= mark_service_starting mark_service_started \ + mark_service_stopping mark_service_stopped \ + mark_service_inactive mark_service_wasinactive \ + mark_service_hotplugged mark_service_failed \ + rc-abort swclock + +ifeq (${OS},Linux) +RC_BINPROGS+= kill_all +SBINPROGS+= openrc-init openrc-shutdown +endif + +ALL_PROGS= ${BINPROGS} ${SBINPROGS} ${RC_BINPROGS} ${RC_SBINPROGS} +CLEANFILES+= ${ALL_PROGS} + +LOCAL_CPPFLAGS=-I../includes -I../librc -I../libeinfo +LOCAL_LDFLAGS=-L../librc -L../libeinfo +LDADD+= -lutil -lrc -leinfo + +include ${MK}/prog.mk +include ${MK}/gitver.mk +include ${MK}/cc.mk + +include ${MK}/termcap.mk +LDADD+= ${LIBDL} ${LIBKVM} +include ${MK}/pam.mk + +${SRCS}: version.h + +.PHONY: version.h.tmp +version.h.tmp: + echo "#define VERSION \"${VERSION}${GITVER}\"" >$@ + if test -n "${BRANDING}"; then \ + echo "#define BRANDING \"${BRANDING}\"" >> $@; \ + fi + +version.h: version.h.tmp + cmp -s $@.tmp $@ && rm $@.tmp || mv $@.tmp $@ + +install: all + ${INSTALL} -d ${DESTDIR}${SBINDIR} + ${INSTALL} -m ${BINMODE} ${SBINPROGS} ${DESTDIR}${SBINDIR} + ${INSTALL} -d ${DESTDIR}${BINDIR} + ${INSTALL} -m ${BINMODE} ${BINPROGS} ${DESTDIR}${BINDIR} + ${INSTALL} -d ${DESTDIR}${LINKDIR}/bin + ${INSTALL} -m ${BINMODE} ${RC_BINPROGS} ${DESTDIR}${LINKDIR}/bin + ${INSTALL} -d ${DESTDIR}${LINKDIR}/sbin + ${INSTALL} -m ${BINMODE} ${RC_SBINPROGS} ${DESTDIR}${LINKDIR}/sbin + if test "${MKPAM}" = pam; then \ + ${INSTALL} -d ${DESTDIR}${PAMDIR}; \ + ${INSTALL} -m ${PAMMODE} start-stop-daemon.pam ${DESTDIR}${PAMDIR}/start-stop-daemon; \ + ${INSTALL} -m ${PAMMODE} supervise-daemon.pam ${DESTDIR}${PAMDIR}/supervise-daemon; \ + fi + +check test:: + +all: ${ALL_PROGS} + +checkpath: checkpath.o _usage.o rc-misc.o +ifeq (${MKSELINUX},yes) +checkpath: rc-selinux.o +endif + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +kill_all: kill_all.o _usage.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \ +eindent eoutdent esyslog eval_ecolors ewaitfile \ +veinfo vewarn vebegin veend vewend veindent veoutdent: do_e.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +fstabinfo: fstabinfo.o _usage.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +openrc-init: openrc-init.o rc-wtmp.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +is_newer_than: is_newer_than.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +is_older_than: is_older_than.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +mark_service_starting mark_service_started \ +mark_service_stopping mark_service_stopped \ +mark_service_inactive mark_service_wasinactive \ +mark_service_hotplugged mark_service_failed: do_mark_service.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +mountinfo: mountinfo.o _usage.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +openrc rc: rc.o rc-logger.o rc-misc.o rc-plugin.o _usage.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +openrc-shutdown: openrc-shutdown.o _usage.o rc-wtmp.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +openrc-run runscript: openrc-run.o _usage.o rc-misc.o rc-plugin.o +ifeq (${MKSELINUX},yes) +openrc-run runscript: rc-selinux.o +endif + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +rc-abort: rc-abort.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ -leinfo + +rc-depend: rc-depend.o _usage.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +rc-status: rc-status.o _usage.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +rc-service: rc-service.o _usage.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +rc-update: rc-update.o _usage.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o rc-schedules.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +supervise-daemon: supervise-daemon.o _usage.o rc-misc.o rc-schedules.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +service_get_value service_set_value get_options save_options: do_value.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +service_starting service_started \ +service_stopping service_stopped \ +service_inactive service_wasinactive \ +service_hotplugged service_started_daemon \ +service_crashed: do_service.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +shell_var: shell_var.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ + +swclock: swclock.o _usage.o rc-misc.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} Index: contrib/openrc/src/rc/_usage.h =================================================================== --- /dev/null +++ contrib/openrc/src/rc/_usage.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include + +#define getoptstring_COMMON "ChqVv" + +#define longopts_COMMON \ + { "help", 0, NULL, 'h'}, \ + { "nocolor", 0, NULL, 'C'}, \ + { "version", 0, NULL, 'V'}, \ + { "verbose", 0, NULL, 'v'}, \ + { "quiet", 0, NULL, 'q'}, \ + { NULL, 0, NULL, 0 } + +#define longopts_help_COMMON \ + "Display this help output", \ + "Disable color output", \ + "Display software version", \ + "Run verbosely", \ + "Run quietly (repeat to suppress errors)" + +#define case_RC_COMMON_getopt_case_C setenv ("EINFO_COLOR", "NO", 1); +#define case_RC_COMMON_getopt_case_h usage (EXIT_SUCCESS); +#define case_RC_COMMON_getopt_case_V if (argc == 2) show_version(); +#define case_RC_COMMON_getopt_case_v setenv ("EINFO_VERBOSE", "YES", 1); +#define case_RC_COMMON_getopt_case_q set_quiet_options(); +#define case_RC_COMMON_getopt_default usage (EXIT_FAILURE); + +#define case_RC_COMMON_GETOPT \ + case 'C': case_RC_COMMON_getopt_case_C; break; \ + case 'h': case_RC_COMMON_getopt_case_h; break; \ + case 'V': case_RC_COMMON_getopt_case_V; break; \ + case 'v': case_RC_COMMON_getopt_case_v; break; \ + case 'q': case_RC_COMMON_getopt_case_q; break; \ + default: case_RC_COMMON_getopt_default; break; + +extern const char *applet; +extern const char *extraopts; +extern const char *getoptstring; +extern const struct option longopts[]; +extern const char * const longopts_help[]; +extern const char *usagestring; + +void set_quiet_options(void); +void show_version(void); +void usage(int exit_status); Index: contrib/openrc/src/rc/_usage.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/_usage.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" +#include "version.h" + +#if lint +# define _noreturn +#endif +#if __GNUC__ > 2 || defined(__INTEL_COMPILER) +# define _noreturn __attribute__ ((__noreturn__)) +#else +# define _noreturn +#endif + +void set_quiet_options(void) +{ + static int qcount = 0; + + qcount ++; + switch (qcount) { + case 1: + setenv ("EINFO_QUIET", "YES", 1); + break; + case 2: + setenv ("EERROR_QUIET", "YES", 1); + break; + } +} + +_noreturn void show_version(void) +{ + const char *systype = NULL; + + printf("%s (OpenRC", applet); + if ((systype = rc_sys())) + printf(" [%s]", systype); + printf(") %s", VERSION); +#ifdef BRANDING + printf(" (%s)", BRANDING); +#endif + printf("\n"); + exit(EXIT_SUCCESS); +} + +_noreturn void usage(int exit_status) +{ + const char * const has_arg[] = { "", "", "[arg]" }; + int i; + int len; + char *lo; + char *p; + char *token; + char val[4] = "-?,"; + + if (usagestring) + printf("%s", usagestring); + else + printf("Usage: %s [options] ", applet); + + if (extraopts) + printf("%s", extraopts); + + printf("\n\nOptions: [ %s ]\n", getoptstring); + for (i = 0; longopts[i].name; ++i) { + val[1] = longopts[i].val; + len = printf(" %3s --%s %s", isprint(longopts[i].val) ? val : "", + longopts[i].name, has_arg[longopts[i].has_arg]); + + lo = p = xstrdup(longopts_help[i]); + while ((token = strsep(&p, "\n"))) { + len = 36 - len; + if (len > 0) + printf("%*s", len, ""); + puts(token); + len = 0; + } + free(lo); + } + exit(exit_status); +} Index: contrib/openrc/src/rc/checkpath.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/checkpath.c @@ -0,0 +1,330 @@ +/* + * checkpath.c + * Checks for the existance of a file or directory and creates it + * if necessary. It can also correct its ownership. + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" +#include "rc-selinux.h" +#include "_usage.h" + +typedef enum { + inode_unknown = 0, + inode_file = 1, + inode_dir = 2, + inode_fifo = 3, +} inode_t; + +const char *applet = NULL; +const char *extraopts ="path1 [path2] [...]"; +const char *getoptstring = "dDfFpm:o:W" getoptstring_COMMON; +const struct option longopts[] = { + { "directory", 0, NULL, 'd'}, + { "directory-truncate", 0, NULL, 'D'}, + { "file", 0, NULL, 'f'}, + { "file-truncate", 0, NULL, 'F'}, + { "pipe", 0, NULL, 'p'}, + { "mode", 1, NULL, 'm'}, + { "owner", 1, NULL, 'o'}, + { "writable", 0, NULL, 'W'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Create a directory if not exists", + "Create/empty directory", + "Create a file if not exists", + "Truncate file", + "Create a named pipe (FIFO) if not exists", + "Mode to check", + "Owner to check (user:group)", + "Check whether the path is writable or not", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode, + inode_t type, bool trunc, bool chowner, bool selinux_on) +{ + struct stat st; + int fd; + int flags; + int r; + int readfd; + int readflags; + int u; + + memset(&st, 0, sizeof(st)); + flags = O_CREAT|O_NDELAY|O_WRONLY|O_NOCTTY; + readflags = O_NDELAY|O_NOCTTY|O_RDONLY; +#ifdef O_CLOEXEC + flags |= O_CLOEXEC; + readflags |= O_CLOEXEC; +#endif +#ifdef O_NOFOLLOW + flags |= O_NOFOLLOW; + readflags |= O_NOFOLLOW; +#endif + if (trunc) + flags |= O_TRUNC; + readfd = open(path, readflags); + if (readfd == -1 || (type == inode_file && trunc)) { + if (type == inode_file) { + einfo("%s: creating file", path); + if (!mode) /* 664 */ + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; + u = umask(0); + fd = open(path, flags, mode); + umask(u); + if (fd == -1) { + eerror("%s: open: %s", applet, strerror(errno)); + return -1; + } + if (readfd != -1 && trunc) + close(readfd); + readfd = fd; + } else if (type == inode_dir) { + einfo("%s: creating directory", path); + if (!mode) /* 775 */ + mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; + u = umask(0); + /* We do not recursively create parents */ + r = mkdir(path, mode); + umask(u); + if (r == -1 && errno != EEXIST) { + eerror("%s: mkdir: %s", applet, + strerror (errno)); + return -1; + } + readfd = open(path, readflags); + if (readfd == -1) { + eerror("%s: unable to open directory: %s", applet, + strerror(errno)); + return -1; + } + } else if (type == inode_fifo) { + einfo("%s: creating fifo", path); + if (!mode) /* 600 */ + mode = S_IRUSR | S_IWUSR; + u = umask(0); + r = mkfifo(path, mode); + umask(u); + if (r == -1 && errno != EEXIST) { + eerror("%s: mkfifo: %s", applet, + strerror (errno)); + return -1; + } + readfd = open(path, readflags); + if (readfd == -1) { + eerror("%s: unable to open fifo: %s", applet, + strerror(errno)); + return -1; + } + } + } + if (fstat(readfd, &st) != -1) { + if (type != inode_dir && S_ISDIR(st.st_mode)) { + eerror("%s: is a directory", path); + close(readfd); + return 1; + } + if (type != inode_file && S_ISREG(st.st_mode)) { + eerror("%s: is a file", path); + close(readfd); + return 1; + } + if (type != inode_fifo && S_ISFIFO(st.st_mode)) { + eerror("%s: is a fifo", path); + close(readfd); + return -1; + } + + if (mode && (st.st_mode & 0777) != mode) { + if ((type != inode_dir) && (st.st_nlink > 1)) { + eerror("%s: chmod: %s %s", applet, "Too many hard links to", path); + close(readfd); + return -1; + } + if (S_ISLNK(st.st_mode)) { + eerror("%s: chmod: %s %s", applet, path, " is a symbolic link"); + close(readfd); + return -1; + } + einfo("%s: correcting mode", path); + if (fchmod(readfd, mode)) { + eerror("%s: chmod: %s", applet, strerror(errno)); + close(readfd); + return -1; + } + } + + if (chowner && (st.st_uid != uid || st.st_gid != gid)) { + if ((type != inode_dir) && (st.st_nlink > 1)) { + eerror("%s: chown: %s %s", applet, "Too many hard links to", path); + close(readfd); + return -1; + } + if (S_ISLNK(st.st_mode)) { + eerror("%s: chown: %s %s", applet, path, " is a symbolic link"); + close(readfd); + return -1; + } + einfo("%s: correcting owner", path); + if (fchown(readfd, uid, gid)) { + eerror("%s: chown: %s", applet, strerror(errno)); + close(readfd); + return -1; + } + } + if (selinux_on) + selinux_util_label(path); + } else { + eerror("fstat: %s: %s", path, strerror(errno)); + close(readfd); + return -1; + } + close(readfd); + + return 0; +} + +static int parse_owner(struct passwd **user, struct group **group, + const char *owner) +{ + char *u = xstrdup (owner); + char *g = strchr (u, ':'); + int id = 0; + int retval = 0; + + if (g) + *g++ = '\0'; + + if (user && *u) { + if (sscanf(u, "%d", &id) == 1) + *user = getpwuid((uid_t) id); + else + *user = getpwnam(u); + if (*user == NULL) + retval = -1; + } + + if (group && g && *g) { + if (sscanf(g, "%d", &id) == 1) + *group = getgrgid((gid_t) id); + else + *group = getgrnam(g); + if (*group == NULL) + retval = -1; + } + + free(u); + return retval; +} + +int main(int argc, char **argv) +{ + int opt; + uid_t uid = geteuid(); + gid_t gid = getgid(); + mode_t mode = 0; + struct passwd *pw = NULL; + struct group *gr = NULL; + inode_t type = inode_unknown; + int retval = EXIT_SUCCESS; + bool trunc = false; + bool chowner = false; + bool writable = false; + bool selinux_on = false; + + applet = basename_c(argv[0]); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'D': + trunc = true; + case 'd': + type = inode_dir; + break; + case 'F': + trunc = true; + case 'f': + type = inode_file; + break; + case 'p': + type = inode_fifo; + break; + case 'm': + if (parse_mode(&mode, optarg) != 0) + eerrorx("%s: invalid mode `%s'", + applet, optarg); + break; + case 'o': + chowner = true; + if (parse_owner(&pw, &gr, optarg) != 0) + eerrorx("%s: owner `%s' not found", + applet, optarg); + break; + case 'W': + writable = true; + break; + + case_RC_COMMON_GETOPT + } + } + + if (optind >= argc) + usage(EXIT_FAILURE); + + if (writable && type != inode_unknown) + eerrorx("%s: -W cannot be specified along with -d, -f or -p", applet); + + if (pw) { + uid = pw->pw_uid; + gid = pw->pw_gid; + } + if (gr) + gid = gr->gr_gid; + + if (selinux_util_open() == 1) + selinux_on = true; + + while (optind < argc) { + if (writable) + exit(!is_writable(argv[optind])); + if (do_check(argv[optind], uid, gid, mode, type, trunc, chowner, selinux_on)) + retval = EXIT_FAILURE; + optind++; + } + + if (selinux_on) + selinux_util_close(); + + return retval; +} Index: contrib/openrc/src/rc/do_e.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/do_e.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#define SYSLOG_NAMES + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "helpers.h" + +/* usecs to wait while we poll the file existance */ +#define WAIT_INTERVAL 20000000 + +const char *applet = NULL; + +static int syslog_decode(char *name, const CODE *codetab) +{ + const CODE *c; + + if (isdigit((unsigned char)*name)) + return atoi(name); + + for (c = codetab; c->c_name; c++) + if (! strcasecmp(name, c->c_name)) + return c->c_val; + + return -1; +} + +int main(int argc, char **argv) +{ + int retval = EXIT_SUCCESS; + int i; + size_t l = 0; + char *message = NULL; + char *p; + int level = 0; + struct timespec ts; + struct timeval stop, now; + int (*e) (const char *, ...) EINFO_PRINTF(1, 2) = NULL; + int (*ee) (int, const char *, ...) EINFO_PRINTF(2, 3) = NULL; + + applet = basename_c(argv[0]); + argc--; + argv++; + + if (strcmp(applet, "eval_ecolors") == 0) { + printf("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n", + ecolor(ECOLOR_GOOD), + ecolor(ECOLOR_WARN), + ecolor(ECOLOR_BAD), + ecolor(ECOLOR_HILITE), + ecolor(ECOLOR_BRACKET), + ecolor(ECOLOR_NORMAL)); + exit(EXIT_SUCCESS); + } + + if (argc > 0) { + if (strcmp(applet, "eend") == 0 || + strcmp(applet, "ewend") == 0 || + strcmp(applet, "veend") == 0 || + strcmp(applet, "vweend") == 0 || + strcmp(applet, "ewaitfile") == 0) + { + errno = 0; + retval = (int)strtoimax(argv[0], &p, 0); + if (!p || *p != '\0') + errno = EINVAL; + if (errno) + retval = EXIT_FAILURE; + else { + argc--; + argv++; + } + } else if (strcmp(applet, "esyslog") == 0 || + strcmp(applet, "elog") == 0) { + p = strchr(argv[0], '.'); + if (!p || + (level = syslog_decode(p + 1, prioritynames)) == -1) + eerrorx("%s: invalid log level `%s'", applet, argv[0]); + + if (argc < 3) + eerrorx("%s: not enough arguments", applet); + + unsetenv("EINFO_LOG"); + setenv("EINFO_LOG", argv[1], 1); + + argc -= 2; + argv += 2; + } + } + + if (strcmp(applet, "ewaitfile") == 0) { + if (errno) + eerrorx("%s: invalid timeout", applet); + if (argc == 0) + eerrorx("%s: not enough arguments", applet); + + gettimeofday(&stop, NULL); + /* retval stores the timeout */ + stop.tv_sec += retval; + ts.tv_sec = 0; + ts.tv_nsec = WAIT_INTERVAL; + for (i = 0; i < argc; i++) { + ebeginv("Waiting for %s", argv[i]); + for (;;) { + if (exists(argv[i])) + break; + if (nanosleep(&ts, NULL) == -1) + return EXIT_FAILURE; + gettimeofday(&now, NULL); + if (retval <= 0) + continue; + if (timercmp(&now, &stop, <)) + continue; + eendv(EXIT_FAILURE, + "timed out waiting for %s", argv[i]); + return EXIT_FAILURE; + } + eendv(EXIT_SUCCESS, NULL); + } + return EXIT_SUCCESS; + } + + if (argc > 0) { + for (i = 0; i < argc; i++) + l += strlen(argv[i]) + 1; + + message = xmalloc(l); + p = message; + + for (i = 0; i < argc; i++) { + if (i > 0) + *p++ = ' '; + l = strlen(argv[i]); + memcpy(p, argv[i], l); + p += l; + } + *p = 0; + } + + if (strcmp(applet, "einfo") == 0) + e = einfo; + else if (strcmp(applet, "einfon") == 0) + e = einfon; + else if (strcmp(applet, "ewarn") == 0) + e = ewarn; + else if (strcmp(applet, "ewarnn") == 0) + e = ewarnn; + else if (strcmp(applet, "eerror") == 0) { + e = eerror; + retval = 1; + } else if (strcmp(applet, "eerrorn") == 0) { + e = eerrorn; + retval = 1; + } else if (strcmp(applet, "ebegin") == 0) + e = ebegin; + else if (strcmp(applet, "eend") == 0) + ee = eend; + else if (strcmp(applet, "ewend") == 0) + ee = ewend; + else if (strcmp(applet, "esyslog") == 0) { + elog(retval, "%s", message); + retval = 0; + } else if (strcmp(applet, "veinfo") == 0) + e = einfov; + else if (strcmp(applet, "veinfon") == 0) + e = einfovn; + else if (strcmp(applet, "vewarn") == 0) + e = ewarnv; + else if (strcmp(applet, "vewarnn") == 0) + e = ewarnvn; + else if (strcmp(applet, "vebegin") == 0) + e = ebeginv; + else if (strcmp(applet, "veend") == 0) + ee = eendv; + else if (strcmp(applet, "vewend") == 0) + ee = ewendv; + else if (strcmp(applet, "eindent") == 0) + eindent(); + else if (strcmp(applet, "eoutdent") == 0) + eoutdent(); + else if (strcmp(applet, "veindent") == 0) + eindentv(); + else if (strcmp(applet, "veoutdent") == 0) + eoutdentv(); + else { + eerror("%s: unknown applet", applet); + retval = EXIT_FAILURE; + } + + if (message) { + if (e) + e("%s", message); + else if (ee) + ee(retval, "%s", message); + } else { + if (e) + e(NULL); + else if (ee) + ee(retval, NULL); + } + + free(message); + return retval; +} Index: contrib/openrc/src/rc/do_mark_service.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/do_mark_service.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" + +const char *applet = NULL; + +int main(int argc, char **argv) +{ + bool ok = false; + char *svcname = getenv("RC_SVCNAME"); + char *service = NULL; + char *openrc_pid; + /* char *mtime; */ + pid_t pid; + RC_SERVICE bit; + /* size_t l; */ + + applet = basename_c(argv[0]); + if (argc > 1) + service = argv[1]; + else + service = svcname; + + if (service == NULL || *service == '\0') + eerrorx("%s: no service specified", applet); + + if (!strncmp(applet, "mark_", 5) && + (bit = lookup_service_state(applet + 5))) + ok = rc_service_mark(service, bit); + else + eerrorx("%s: unknown applet", applet); + + /* If we're marking ourselves then we need to inform our parent + openrc-run process so they do not mark us based on our exit code */ + /* + * FIXME: svcname and service are almost always equal except called from a + * shell with just argv[1] - So that doesn't seem to do what Roy initially + * expected. + * See 20120424041423.GA23657@odin.qasl.de (Tue, 24 Apr 2012 06:14:23 +0200, + * openrc@gentoo.org). + */ + if (ok && svcname && strcmp(svcname, service) == 0) { + openrc_pid = getenv("RC_OPENRC_PID"); + if (openrc_pid && sscanf(openrc_pid, "%d", &pid) == 1) + if (kill(pid, SIGHUP) != 0) + eerror("%s: failed to signal parent %d: %s", + applet, pid, strerror(errno)); + + /* Remove the exclusive time test. This ensures that it's not + in control as well */ + /* + l = strlen(RC_SVCDIR "/exclusive") + strlen(svcname) + + strlen(openrc_pid) + 4; + mtime = xmalloc(l); + snprintf(mtime, l, RC_SVCDIR "/exclusive/%s.%s", + svcname, openrc_pid); + if (exists(mtime) && unlink(mtime) != 0) + eerror("%s: unlink: %s", applet, strerror(errno)); + free(mtime); + */ + } + + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +} Index: contrib/openrc/src/rc/do_service.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/do_service.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" + +const char *applet = NULL; + +int main(int argc, char **argv) +{ + bool ok = false; + char *service; + char *exec; + int idx = 0; + RC_SERVICE state, bit; + + applet = basename_c(argv[0]); + if (argc > 1) + service = argv[1]; + else + service = getenv("RC_SVCNAME"); + + if (service == NULL || *service == '\0') + eerrorx("%s: no service specified", applet); + + state = rc_service_state(service); + bit = lookup_service_state(applet); + if (bit) { + ok = (state & bit); + } else if (strcmp(applet, "service_started_daemon") == 0) { + service = getenv("RC_SVCNAME"); + exec = argv[1]; + if (argc > 3) { + service = argv[1]; + exec = argv[2]; + sscanf(argv[3], "%d", &idx); + } else if (argc == 3) { + if (sscanf(argv[2], "%d", &idx) != 1) { + service = argv[1]; + exec = argv[2]; + } + } + ok = rc_service_started_daemon(service, exec, NULL, idx); + + } else if (strcmp(applet, "service_crashed") == 0) { + ok = (_rc_can_find_pids() && + rc_service_daemons_crashed(service) && + errno != EACCES); + } else + eerrorx("%s: unknown applet", applet); + + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +} Index: contrib/openrc/src/rc/do_value.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/do_value.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#define SYSLOG_NAMES + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" + +const char *applet = NULL; + +int main(int argc, char **argv) +{ + bool ok = false; + char *service = getenv("RC_SVCNAME"); + char *option; + + applet = basename_c(argv[0]); + if (service == NULL) + eerrorx("%s: no service specified", applet); + + if (argc < 2 || ! argv[1] || *argv[1] == '\0') + eerrorx("%s: no option specified", applet); + + if (strcmp(applet, "service_get_value") == 0 || + strcmp(applet, "get_options") == 0) + { + option = rc_service_value_get(service, argv[1]); + if (option) { + printf("%s", option); + free(option); + ok = true; + } + } else if (strcmp(applet, "service_set_value") == 0 || + strcmp(applet, "save_options") == 0) + ok = rc_service_value_set(service, argv[1], argv[2]); + else + eerrorx("%s: unknown applet", applet); + + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +} Index: contrib/openrc/src/rc/fstabinfo.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/fstabinfo.c @@ -0,0 +1,339 @@ +/* + * fstabinfo.c + * Gets information about /etc/fstab. + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include + +#include +#include +#include +#include +#include +#include + +/* Yay for linux and its non liking of POSIX functions. + Okay, we could use getfsent but the man page says use getmntent instead + AND we don't have getfsent on uclibc or dietlibc for some odd reason. */ +#ifdef __linux__ +# define HAVE_GETMNTENT +# include +# define ENT mntent +# define START_ENT fp = setmntent ("/etc/fstab", "r"); +# define GET_ENT getmntent (fp) +# define GET_ENT_FILE(_name) getmntfile (_name) +# define END_ENT endmntent (fp) +# define ENT_BLOCKDEVICE(_ent) (_ent)->mnt_fsname +# define ENT_FILE(_ent) (_ent)->mnt_dir +# define ENT_TYPE(_ent) (_ent)->mnt_type +# define ENT_OPTS(_ent) (_ent)->mnt_opts +# define ENT_PASS(_ent) (_ent)->mnt_passno +#else +# define HAVE_GETFSENT +# include +# define ENT fstab +# define START_ENT +# define GET_ENT getfsent () +# define GET_ENT_FILE(_name) getfsfile (_name) +# define END_ENT endfsent () +# define ENT_BLOCKDEVICE(_ent) (_ent)->fs_spec +# define ENT_TYPE(_ent) (_ent)->fs_vfstype +# define ENT_FILE(_ent) (_ent)->fs_file +# define ENT_OPTS(_ent) (_ent)->fs_mntops +# define ENT_PASS(_ent) (_ent)->fs_passno +#endif + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "MRbmop:t:" getoptstring_COMMON; +const struct option longopts[] = { + { "mount", 0, NULL, 'M' }, + { "remount", 0, NULL, 'R' }, + { "blockdevice", 0, NULL, 'b' }, + { "mountargs", 0, NULL, 'm' }, + { "options", 0, NULL, 'o' }, + { "passno", 1, NULL, 'p' }, + { "fstype", 1, NULL, 't' }, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Mounts the filesytem from the mountpoint", + "Remounts the filesystem based on the information in fstab", + "Extract the block device", + "Show arguments needed to mount the entry", + "Extract the options field", + "Extract or query the pass number field", + "List entries with matching file system type", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +#ifdef HAVE_GETMNTENT +static struct mntent * +getmntfile(const char *file) +{ + struct mntent *ent; + FILE *fp; + + START_ENT; + while ((ent = getmntent(fp))) + if (strcmp(file, ent->mnt_dir) == 0) + break; + END_ENT; + + return ent; +} +#endif + +extern const char *applet; + +static int +do_mount(struct ENT *ent, bool remount) +{ + char *argv[10]; + pid_t pid; + int status; + + argv[0] = UNCONST("mount"); + argv[1] = UNCONST("-o"); + argv[2] = ENT_OPTS(ent); + argv[3] = UNCONST("-t"); + argv[4] = ENT_TYPE(ent); + if (!remount) { + argv[5] = ENT_BLOCKDEVICE(ent); + argv[6] = ENT_FILE(ent); + argv[7] = NULL; + } else { +#ifdef __linux__ + argv[5] = UNCONST("-o"); + argv[6] = UNCONST("remount"); + argv[7] = ENT_BLOCKDEVICE(ent); + argv[8] = ENT_FILE(ent); + argv[9] = NULL; +#else + argv[5] = UNCONST("-u"); + argv[6] = ENT_BLOCKDEVICE(ent); + argv[7] = ENT_FILE(ent); + argv[8] = NULL; +#endif + } + switch (pid = vfork()) { + case -1: + eerrorx("%s: vfork: %s", applet, strerror(errno)); + /* NOTREACHED */ + case 0: + execvp(argv[0], argv); + eerror("%s: execv: %s", applet, strerror(errno)); + _exit(EXIT_FAILURE); + /* NOTREACHED */ + default: + waitpid(pid, &status, 0); + if (WIFEXITED(status)) + return WEXITSTATUS(status); + else + return -1; + /* NOTREACHED */ + } +} + +#define OUTPUT_FILE (1 << 1) +#define OUTPUT_MOUNTARGS (1 << 2) +#define OUTPUT_OPTIONS (1 << 3) +#define OUTPUT_PASSNO (1 << 4) +#define OUTPUT_BLOCKDEV (1 << 5) +#define OUTPUT_MOUNT (1 << 6) +#define OUTPUT_REMOUNT (1 << 7) + +int main(int argc, char **argv) +{ + struct ENT *ent; + int result = EXIT_SUCCESS; + char *token; + int i, p; + int opt; + int output = OUTPUT_FILE; + RC_STRINGLIST *files = rc_stringlist_new(); + RC_STRING *file, *file_np; + bool filtered = false; + +#ifdef HAVE_GETMNTENT + FILE *fp; +#endif + + /* fail if there is no /etc/fstab */ + if (!exists("/etc/fstab")) + eerrorx("/etc/fstab does not exist"); + /* Ensure that we are only quiet when explicitly told to be */ + unsetenv("EINFO_QUIET"); + + applet = basename_c(argv[0]); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'M': + output = OUTPUT_MOUNT; + break; + case 'R': + output = OUTPUT_REMOUNT; + break; + case 'b': + output = OUTPUT_BLOCKDEV; + break; + case 'o': + output = OUTPUT_OPTIONS; + break; + case 'm': + output = OUTPUT_MOUNTARGS; + break; + + case 'p': + switch (optarg[0]) { + case '=': + case '<': + case '>': + if (sscanf(optarg + 1, "%d", &i) != 1) + eerrorx("%s: invalid passno %s", + argv[0], optarg + 1); + + filtered = true; + opt = optarg[0]; + START_ENT; + while ((ent = GET_ENT)) { + if (strcmp(ENT_FILE(ent), "none") == 0) + continue; + p = ENT_PASS(ent); + if ((opt == '=' && i == p) || + (opt == '<' && i > p && p != 0) || + (opt == '>' && i < p && p != 0)) + rc_stringlist_add(files, + ENT_FILE(ent)); + } + END_ENT; + break; + + default: + rc_stringlist_add(files, optarg); + output = OUTPUT_PASSNO; + break; + } + break; + + case 't': + filtered = true; + while ((token = strsep(&optarg, ","))) { + START_ENT; + while ((ent = GET_ENT)) + if (strcmp(token, ENT_TYPE(ent)) == 0) + rc_stringlist_add(files, + ENT_FILE(ent)); + END_ENT; + } + break; + + case_RC_COMMON_GETOPT + } + } + + if (optind < argc) { + if (TAILQ_FIRST(files)) { + TAILQ_FOREACH_SAFE(file, files, entries, file_np) { + for (i = optind; i < argc; i++) + if (strcmp(argv[i], file->value) == 0) + break; + if (i >= argc) + rc_stringlist_delete(files, + file->value); + } + } else { + while (optind < argc) + rc_stringlist_add(files, argv[optind++]); + } + } else if (!filtered) { + START_ENT; + while ((ent = GET_ENT)) + rc_stringlist_add(files, ENT_FILE(ent)); + END_ENT; + + if (!TAILQ_FIRST(files)) + eerrorx("%s: empty fstab", argv[0]); + } + + if (!TAILQ_FIRST(files)) { + rc_stringlist_free(files); + return (EXIT_FAILURE); + } + + /* Ensure we always display something */ + START_ENT; + TAILQ_FOREACH(file, files, entries) { + if (!(ent = GET_ENT_FILE(file->value))) { + result = EXIT_FAILURE; + continue; + } + + /* mount or remount? */ + switch (output) { + case OUTPUT_MOUNT: + result += do_mount(ent, false); + break; + + case OUTPUT_REMOUNT: + result += do_mount(ent, true); + break; + } + + /* No point in outputting if quiet */ + if (rc_yesno(getenv("EINFO_QUIET"))) + continue; + + switch (output) { + case OUTPUT_BLOCKDEV: + printf("%s\n", ENT_BLOCKDEVICE(ent)); + break; + + case OUTPUT_MOUNTARGS: + printf("-o %s -t %s %s %s\n", + ENT_OPTS(ent), + ENT_TYPE(ent), + ENT_BLOCKDEVICE(ent), + file->value); + break; + + case OUTPUT_OPTIONS: + printf("%s\n", ENT_OPTS(ent)); + break; + + case OUTPUT_FILE: + printf("%s\n", file->value); + break; + + case OUTPUT_PASSNO: + printf("%d\n", ENT_PASS(ent)); + break; + } + } + END_ENT; + + rc_stringlist_free(files); + exit(result); + /* NOTREACHED */ +} Index: contrib/openrc/src/rc/is_newer_than.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/is_newer_than.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include + +#include "rc.h" +#include "rc-misc.h" + +int main(int argc, char **argv) +{ + int i; + + if (argc < 3) + return EXIT_FAILURE; + + /* This test is correct as it's not present in baselayout */ + for (i = 2; i < argc; ++i) + if (!rc_newer_than(argv[1], argv[i], NULL, NULL)) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} Index: contrib/openrc/src/rc/is_older_than.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/is_older_than.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include + +#include "rc.h" +#include "rc-misc.h" + +int main(int argc, char **argv) +{ + int i; + + if (argc < 3) + return EXIT_FAILURE; + + /* This test is perverted - historically the baselayout function + * returns 0 on *failure*, which is plain wrong */ + for (i = 2; i < argc; ++i) + if (!rc_newer_than(argv[1], argv[i], NULL, NULL)) + return EXIT_SUCCESS; + + return EXIT_FAILURE; +} Index: contrib/openrc/src/rc/kill_all.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/kill_all.c @@ -0,0 +1,260 @@ +/* + * kill_all.c + * Sends a signal to all processes on the system. + */ + +/* + * Copyright (c) 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +const char *applet = NULL; +const char *extraopts = "[signal number]"; +const char *getoptstring = "do:" getoptstring_COMMON; +const struct option longopts[] = { + { "dry-run", 0, NULL, 'd' }, + { "omit", 1, NULL, 'o' }, + longopts_COMMON +}; +const char * const longopts_help[] = { + "print what would be done", + "omit this pid (can be repeated)", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +static int mount_proc(void) +{ + pid_t pid; + pid_t rc; + int status; + + if (exists("/proc/version")) + return 0; + pid = fork(); + switch(pid) { + case -1: + syslog(LOG_ERR, "Unable to fork"); + return -1; + break; + case 0: + /* attempt to mount /proc */ + execl("mount", "mount", "-t", "proc", "proc", "/proc", NULL); + syslog(LOG_ERR, "Unable to execute mount"); + exit(1); + break; + default: + /* wait for child process */ + while ((rc = wait(&status)) != pid) + if (rc < 0 && errno == ECHILD) + break; + if (rc != pid || WEXITSTATUS(status) != 0) + syslog(LOG_ERR, "mount returned non-zero exit status"); + break; + } + if (! exists("/proc/version")) { + syslog(LOG_ERR, "Could not mount /proc"); + return -1; + } + return 0; +} + +static bool is_user_process(pid_t pid) +{ + char *buf = NULL; + FILE *fp; + char *path = NULL; + pid_t temp_pid; + size_t size; + bool user_process = true; + + while (pid >0 && user_process) { + if (pid == 2) { + user_process = false; + continue; + } + xasprintf(&path, "/proc/%d/status", pid); + fp = fopen(path, "r"); + free(path); + /* + * if we could not open the file, the process disappeared, which + * leaves us no way to determine for sure whether it was a user + * process or kernel thread, so we say it is a kernel thread to + * avoid accidentally killing it. + */ + if (!fp) { + user_process = false; + continue; + } + temp_pid = -1; + while (! feof(fp)) { + buf = NULL; + if (getline(&buf, &size, fp) != -1) { + sscanf(buf, "PPid: %d", &temp_pid); + free(buf); + } else { + free(buf); + break; + } + } + fclose(fp); + if (temp_pid == -1) { + syslog(LOG_ERR, "Unable to read pid from /proc/%d/status", pid); + user_process = false; + continue; + } + pid = temp_pid; + } + return user_process; +} + +static int signal_processes(int sig, RC_STRINGLIST *omits, bool dryrun) +{ + sigset_t signals; + sigset_t oldsigs; + DIR *dir; + struct dirent *d; + char *buf = NULL; + pid_t pid; + int sendcount = 0; + + kill(-1, SIGSTOP); + sigfillset(&signals); + sigemptyset(&oldsigs); + sigprocmask(SIG_SETMASK, &signals, &oldsigs); + /* + * Open the /proc directory. + * CWD must be /proc to avoid problems if / is affected by the killing + * (i.e. depends on fuse). + */ + if (chdir("/proc") == -1) { + syslog(LOG_ERR, "chdir /proc failed"); + sigprocmask(SIG_SETMASK, &oldsigs, NULL); + kill(-1, SIGCONT); + return -1; + } + dir = opendir("."); + if (!dir) { + syslog(LOG_ERR, "cannot opendir(/proc)"); + sigprocmask(SIG_SETMASK, &oldsigs, NULL); + kill(-1, SIGCONT); + return -1; + } + + /* Walk through the directory. */ + while ((d = readdir(dir)) != NULL) { + /* Is this a process? */ + pid = (pid_t) atoi(d->d_name); + if (pid == 0) + continue; + + /* Is this a process we have been requested to omit? */ + if (buf) { + free(buf); + buf = NULL; + } + xasprintf(&buf, "%d", pid); + if (rc_stringlist_find(omits, buf)) + continue; + + /* Is this process in our session? */ + if (getsid(getpid()) == getsid(pid)) + continue; + + /* Is this a kernel thread? */ + if (!is_user_process(pid)) + continue; + + if (dryrun) + einfo("Would send signal %d to process %d", sig, pid); + else if (kill(pid, sig) == 0) + sendcount++; + } + closedir(dir); + sigprocmask(SIG_SETMASK, &oldsigs, NULL); + kill(-1, SIGCONT); + return sendcount; +} + +int main(int argc, char **argv) +{ + char *arg = NULL; + int opt; + bool dryrun = false; + RC_STRINGLIST *omits = rc_stringlist_new(); + int sig = SIGKILL; + char *here; + char *token; + + /* Ensure that we are only quiet when explicitly told to be */ + unsetenv("EINFO_QUIET"); + + applet = basename_c(argv[0]); + rc_stringlist_addu(omits, "1"); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'd': + dryrun = true; + break; + case 'o': + here = optarg; + while ((token = strsep(&here, ",;:"))) { + if ((pid_t) atoi(token) > 0) + rc_stringlist_addu(omits, token); + else { + eerror("Invalid omit pid value %s", token); + usage(EXIT_FAILURE); + } + } + break; + case_RC_COMMON_GETOPT + } + } + + if (argc > optind) { + arg = argv[optind]; + sig = atoi(arg); + if (sig <= 0 || sig > 31) { + rc_stringlist_free(omits); + eerror("Invalid signal %s", arg); + usage(EXIT_FAILURE); + } + } + + openlog(applet, LOG_CONS|LOG_PID, LOG_DAEMON); + if (mount_proc() != 0) { + rc_stringlist_free(omits); + eerrorx("Unable to mount /proc file system"); + } + signal_processes(sig, omits, dryrun); + rc_stringlist_free(omits); + return 0; +} Index: contrib/openrc/src/rc/mountinfo.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/mountinfo.c @@ -0,0 +1,488 @@ +/* + * mountinfo.c + * Obtains information about mounted filesystems. + */ + +/* + * Copyright 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#if defined(__DragonFly__) || defined(__FreeBSD__) +# include +# include +# define F_FLAGS f_flags +#elif defined(BSD) && !defined(__GNU__) +# include +# define statfs statvfs +# define F_FLAGS f_flag +#elif defined(__linux__) || (defined(__FreeBSD_kernel__) && \ + defined(__GLIBC__)) || defined(__GNU__) +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +const char *applet = NULL; +const char *procmounts = "/proc/mounts"; +const char *extraopts = "[mount1] [mount2] ..."; +const char *getoptstring = "f:F:n:N:o:O:p:P:iste:E:" getoptstring_COMMON; +const struct option longopts[] = { + { "fstype-regex", 1, NULL, 'f'}, + { "skip-fstype-regex", 1, NULL, 'F'}, + { "node-regex", 1, NULL, 'n'}, + { "skip-node-regex", 1, NULL, 'N'}, + { "options-regex", 1, NULL, 'o'}, + { "skip-options-regex", 1, NULL, 'O'}, + { "point-regex", 1, NULL, 'p'}, + { "skip-point-regex", 1, NULL, 'P'}, + { "options", 0, NULL, 'i'}, + { "fstype", 0, NULL, 's'}, + { "node", 0, NULL, 't'}, + { "netdev", 0, NULL, 'e'}, + { "nonetdev", 0, NULL, 'E'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "fstype regex to find", + "fstype regex to skip", + "node regex to find", + "node regex to skip", + "options regex to find", + "options regex to skip", + "point regex to find", + "point regex to skip", + "print options", + "print fstype", + "print node", + "is it a network device", + "is it not a network device", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +typedef enum { + mount_from, + mount_to, + mount_fstype, + mount_options +} mount_type; + +typedef enum { + net_ignore, + net_yes, + net_no +} net_opts; + +struct args { + regex_t *node_regex; + regex_t *skip_node_regex; + regex_t *fstype_regex; + regex_t *skip_fstype_regex; + regex_t *options_regex; + regex_t *skip_options_regex; + RC_STRINGLIST *mounts; + mount_type mount_type; + net_opts netdev; +}; + +static int +process_mount(RC_STRINGLIST *list, struct args *args, + char *from, char *to, char *fstype, char *options, + int netdev) +{ + char *p; + RC_STRING *s; + + errno = ENOENT; + +#ifdef __linux__ + /* Skip the really silly rootfs */ + if (strcmp(fstype, "rootfs") == 0) + return -1; +#endif + + if (args->netdev == net_yes && + (netdev != -1 || TAILQ_FIRST(args->mounts))) + { + if (netdev != 0) + return 1; + } else if (args->netdev == net_no && + (netdev != -1 || TAILQ_FIRST(args->mounts))) + { + if (netdev != 1) + return 1; + } else { + if (args->node_regex && + regexec(args->node_regex, from, 0, NULL, 0) != 0) + return 1; + if (args->skip_node_regex && + regexec(args->skip_node_regex, from, 0, NULL, 0) == 0) + return 1; + + if (args->fstype_regex && + regexec(args->fstype_regex, fstype, 0, NULL, 0) != 0) + return -1; + if (args->skip_fstype_regex && + regexec(args->skip_fstype_regex, fstype, 0, NULL, 0) == 0) + return -1; + + if (args->options_regex && + regexec(args->options_regex, options, 0, NULL, 0) != 0) + return -1; + if (args->skip_options_regex && + regexec(args->skip_options_regex, options, 0, NULL, 0) == 0) + return -1; + } + + if (TAILQ_FIRST(args->mounts)) { + TAILQ_FOREACH(s, args->mounts, entries) + if (strcmp(s->value, to) == 0) + break; + if (! s) + return -1; + } + + switch (args->mount_type) { + case mount_from: + p = from; + break; + case mount_to: + p = to; + break; + case mount_fstype: + p = fstype; + break; + case mount_options: + p = options; + break; + default: + p = NULL; + errno = EINVAL; + break; + } + + if (p) { + errno = 0; + rc_stringlist_add(list, p); + return 0; + } + + return -1; +} + +#if defined(BSD) && !defined(__GNU__) + +/* Translate the mounted options to english + * This is taken directly from FreeBSD mount.c */ +static struct opt { + int o_opt; + const char *o_name; +} optnames[] = { + { MNT_ASYNC, "asynchronous" }, + { MNT_EXPORTED, "NFS exported" }, + { MNT_LOCAL, "local" }, + { MNT_NOATIME, "noatime" }, + { MNT_NOEXEC, "noexec" }, + { MNT_NOSUID, "nosuid" }, +#ifdef MNT_NOSYMFOLLOW + { MNT_NOSYMFOLLOW, "nosymfollow" }, +#endif + { MNT_QUOTA, "with quotas" }, + { MNT_RDONLY, "read-only" }, + { MNT_SYNCHRONOUS, "synchronous" }, + { MNT_UNION, "union" }, +#ifdef MNT_NOCLUSTERR + { MNT_NOCLUSTERR, "noclusterr" }, +#endif +#ifdef MNT_NOCLUSTERW + { MNT_NOCLUSTERW, "noclusterw" }, +#endif +#ifdef MNT_SUIDDIR + { MNT_SUIDDIR, "suiddir" }, +#endif + { MNT_SOFTDEP, "soft-updates" }, +#ifdef MNT_MULTILABEL + { MNT_MULTILABEL, "multilabel" }, +#endif +#ifdef MNT_ACLS + { MNT_ACLS, "acls" }, +#endif +#ifdef MNT_GJOURNAL + { MNT_GJOURNAL, "gjournal" }, +#endif + { 0, NULL } +}; + +static RC_STRINGLIST * +find_mounts(struct args *args) +{ + struct statfs *mnts; + int nmnts; + int i; + RC_STRINGLIST *list; + char *options = NULL; + uint64_t flags; + struct opt *o; + int netdev; + char *tmp; + + if ((nmnts = getmntinfo(&mnts, MNT_NOWAIT)) == 0) + eerrorx("getmntinfo: %s", strerror (errno)); + + list = rc_stringlist_new(); + for (i = 0; i < nmnts; i++) { + netdev = 0; + flags = mnts[i].F_FLAGS & MNT_VISFLAGMASK; + for (o = optnames; flags && o->o_opt; o++) { + if (flags & o->o_opt) { + if (o->o_opt == MNT_LOCAL) + netdev = 1; + if (! options) + options = xstrdup(o->o_name); + else { + xasprintf(&tmp, "%s,%s", options, o->o_name); + free(options); + options = tmp; + } + } + flags &= ~o->o_opt; + } + + process_mount(list, args, + mnts[i].f_mntfromname, + mnts[i].f_mntonname, + mnts[i].f_fstypename, + options, + netdev); + + free(options); + options = NULL; + } + + return list; +} + +#elif defined(__linux__) || (defined(__FreeBSD_kernel__) && \ + defined(__GLIBC__)) || defined(__GNU__) +static struct mntent * +getmntfile(const char *file) +{ + struct mntent *ent = NULL; + FILE *fp; + + if (!exists("/etc/fstab")) + return NULL; + + fp = setmntent("/etc/fstab", "r"); + while ((ent = getmntent(fp))) + if (strcmp(file, ent->mnt_dir) == 0) + break; + endmntent(fp); + + return ent; +} + +static RC_STRINGLIST * +find_mounts(struct args *args) +{ + FILE *fp; + char *buffer; + size_t size; + char *p; + char *from; + char *to; + char *fst; + char *opts; + struct mntent *ent; + int netdev; + RC_STRINGLIST *list; + + if ((fp = fopen(procmounts, "r")) == NULL) + eerrorx("getmntinfo: %s", strerror(errno)); + + list = rc_stringlist_new(); + + buffer = NULL; + while (getline(&buffer, &size, fp) != -1) { + netdev = -1; + p = buffer; + from = strsep(&p, " "); + to = strsep(&p, " "); + fst = strsep(&p, " "); + opts = strsep(&p, " "); + + if ((ent = getmntfile(to))) { + if (strstr(ent->mnt_opts, "_netdev")) + netdev = 0; + else + netdev = 1; + } + + process_mount(list, args, from, to, fst, opts, netdev); + free(buffer); + buffer = NULL; + } + free(buffer); + fclose(fp); + + return list; +} + +#else +# error "Operating system not supported!" +#endif + +static regex_t * +get_regex(const char *string) +{ + regex_t *reg = xmalloc(sizeof (*reg)); + int result; + char buffer[256]; + + if ((result = regcomp(reg, string, REG_EXTENDED | REG_NOSUB)) != 0) + { + regerror(result, reg, buffer, sizeof(buffer)); + eerrorx("%s: invalid regex `%s'", applet, buffer); + } + + return reg; +} + +int main(int argc, char **argv) +{ + struct args args; + regex_t *point_regex = NULL; + regex_t *skip_point_regex = NULL; + RC_STRINGLIST *nodes; + RC_STRING *s; + char *real_path = NULL; + int opt; + int result; + char *this_path; + +#define DO_REG(_var) \ + if (_var) free(_var); \ + _var = get_regex(optarg); +#define REG_FREE(_var) \ + if (_var) { regfree(_var); free(_var); } + + applet = basename_c(argv[0]); + memset (&args, 0, sizeof(args)); + args.mount_type = mount_to; + args.netdev = net_ignore; + args.mounts = rc_stringlist_new(); + + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'e': + args.netdev = net_yes; + break; + case 'E': + args.netdev = net_no; + break; + case 'f': + DO_REG(args.fstype_regex); + break; + case 'F': + DO_REG(args.skip_fstype_regex); + break; + case 'n': + DO_REG(args.node_regex); + break; + case 'N': + DO_REG(args.skip_node_regex); + break; + case 'o': + DO_REG(args.options_regex); + break; + case 'O': + DO_REG(args.skip_options_regex); + break; + case 'p': + DO_REG(point_regex); + break; + case 'P': + DO_REG(skip_point_regex); + break; + case 'i': + args.mount_type = mount_options; + break; + case 's': + args.mount_type = mount_fstype; + break; + case 't': + args.mount_type = mount_from; + break; + + case_RC_COMMON_GETOPT + } + } + + while (optind < argc) { + if (argv[optind][0] != '/') + eerrorx("%s: `%s' is not a mount point", + argv[0], argv[optind]); + this_path = argv[optind++]; + real_path = realpath(this_path, NULL); + if (real_path) + this_path = real_path; + rc_stringlist_add(args.mounts, this_path); + free(real_path); + real_path = NULL; + } + nodes = find_mounts(&args); + rc_stringlist_free(args.mounts); + + REG_FREE(args.fstype_regex); + REG_FREE(args.skip_fstype_regex); + REG_FREE(args.node_regex); + REG_FREE(args.skip_node_regex); + REG_FREE(args.options_regex); + REG_FREE(args.skip_options_regex); + + result = EXIT_FAILURE; + + /* We should report the mounts in reverse order to ease unmounting */ + TAILQ_FOREACH_REVERSE(s, nodes, rc_stringlist, entries) { + if (point_regex && + regexec(point_regex, s->value, 0, NULL, 0) != 0) + continue; + if (skip_point_regex && + regexec(skip_point_regex, s->value, 0, NULL, 0) == 0) + continue; + if (! rc_yesno(getenv("EINFO_QUIET"))) + printf("%s\n", s->value); + result = EXIT_SUCCESS; + } + rc_stringlist_free(nodes); + + REG_FREE(point_regex); + REG_FREE(skip_point_regex); + + return result; +} Index: contrib/openrc/src/rc/openrc-init.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/openrc-init.c @@ -0,0 +1,218 @@ +/* + * openrc-init.c + * This is the init process (pid 1) for OpenRC. + * + * This is based on code written by James Hammons , so + * I would like to publically thank him for his work. + */ + +/* + * Copyright (c) 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "helpers.h" +#include "rc.h" +#include "rc-wtmp.h" +#include "version.h" + +static const char *rc_default_runlevel = "default"; + +static pid_t do_openrc(const char *runlevel) +{ + pid_t pid; + sigset_t signals; + + pid = fork(); + switch(pid) { + case -1: + perror("fork"); + break; + case 0: + setsid(); + /* unblock all signals */ + sigemptyset(&signals); + sigprocmask(SIG_SETMASK, &signals, NULL); + printf("Starting %s runlevel\n", runlevel); + execl("/sbin/openrc", "/sbin/openrc", runlevel, NULL); + perror("exec"); + break; + default: + break; + } + return pid; +} + +static void init(const char *default_runlevel) +{ + const char *runlevel = NULL; + pid_t pid; + + pid = do_openrc("sysinit"); + waitpid(pid, NULL, 0); + pid = do_openrc("boot"); + waitpid(pid, NULL, 0); + if (default_runlevel) + runlevel = default_runlevel; + else + runlevel = rc_conf_value("rc_default_runlevel"); + if (!runlevel) + runlevel = rc_default_runlevel; + if (!rc_runlevel_exists(runlevel)) { + printf("%s is an invalid runlevel\n", runlevel); + runlevel = rc_default_runlevel; + } + pid = do_openrc(runlevel); + waitpid(pid, NULL, 0); + log_wtmp("reboot", "~~", 0, RUN_LVL, "~~"); +} + +static void handle_reexec(char *my_name) +{ + execl(my_name, my_name, "reexec", NULL); + return; +} + +static void handle_shutdown(const char *runlevel, int cmd) +{ + pid_t pid; + + pid = do_openrc(runlevel); + while (waitpid(pid, NULL, 0) != pid); + printf("Sending the final term signal\n"); + kill(-1, SIGTERM); + sleep(3); + printf("Sending the final kill signal\n"); + kill(-1, SIGKILL); + sync(); + reboot(cmd); +} + +static void handle_single(void) +{ + pid_t pid; + + pid = do_openrc("single"); + while (waitpid(pid, NULL, 0) != pid); +} + +static void reap_zombies(void) +{ + pid_t pid; + + for (;;) { + pid = waitpid(-1, NULL, WNOHANG); + if (pid == 0) + break; + else if (pid == -1) { + if (errno == ECHILD) + break; + perror("waitpid"); + continue; + } + } +} + +static void signal_handler(int sig) +{ + switch(sig) { + case SIGINT: + handle_shutdown("reboot", RB_AUTOBOOT); + break; + case SIGCHLD: + reap_zombies(); + break; + default: + printf("Unknown signal received, %d\n", sig); + break; + } +} + +int main(int argc, char **argv) +{ + char *default_runlevel; + char buf[2048]; + int count; + FILE *fifo; + bool reexec = false; + sigset_t signals; + struct sigaction sa; + + if (getpid() != 1) + return 1; + + printf("OpenRC init version %s starting\n", VERSION); + + if (argc > 1) + default_runlevel = argv[1]; + else + default_runlevel = NULL; + + if (default_runlevel && strcmp(default_runlevel, "reexec") == 0) + reexec = true; + + /* block all signals we do not handle */ + sigfillset(&signals); + sigdelset(&signals, SIGCHLD); + sigdelset(&signals, SIGINT); + sigprocmask(SIG_SETMASK, &signals, NULL); + + /* install signal handler */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + reboot(RB_DISABLE_CAD); + + if (! reexec) + init(default_runlevel); + + if (mkfifo(RC_INIT_FIFO, 0600) == -1 && errno != EEXIST) + perror("mkfifo"); + + for (;;) { + /* This will block until a command is sent down the pipe... */ + fifo = fopen(RC_INIT_FIFO, "r"); + if (!fifo) { + if (errno != EINTR) + perror("fopen"); + continue; + } + count = fread(buf, 1, sizeof(buf) - 1, fifo); + buf[count] = 0; + fclose(fifo); + printf("PID1: Received \"%s\" from FIFO...\n", buf); + if (strcmp(buf, "halt") == 0) + handle_shutdown("shutdown", RB_HALT_SYSTEM); + else if (strcmp(buf, "kexec") == 0) + handle_shutdown("reboot", RB_KEXEC); + else if (strcmp(buf, "poweroff") == 0) + handle_shutdown("shutdown", RB_POWER_OFF); + else if (strcmp(buf, "reboot") == 0) + handle_shutdown("reboot", RB_AUTOBOOT); + else if (strcmp(buf, "reexec") == 0) + handle_reexec(argv[0]); + else if (strcmp(buf, "single") == 0) + handle_single(); + } + return 0; +} Index: contrib/openrc/src/rc/openrc-run.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/openrc-run.c @@ -0,0 +1,1432 @@ +/* + * openrc-run.c + * Handle launching of init scripts. + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) \ + || defined(__GNU__) +# include +#elif defined(__NetBSD__) || defined(__OpenBSD__) +# include +#else +# include +#endif + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "rc-plugin.h" +#include "rc-selinux.h" +#include "_usage.h" + +#define PREFIX_LOCK RC_SVCDIR "/prefix.lock" + +#define WAIT_INTERVAL 20000000 /* usecs to poll the lock file */ +#define WAIT_TIMEOUT 60 /* seconds until we timeout */ +#define WARN_TIMEOUT 10 /* warn about this every N seconds */ + +const char *applet = NULL; +const char *extraopts = "stop | start | restart | describe | zap"; +const char *getoptstring = "dDsSvl:Z" getoptstring_COMMON; +const struct option longopts[] = { + { "debug", 0, NULL, 'd'}, + { "dry-run", 0, NULL, 'Z'}, + { "ifstarted", 0, NULL, 's'}, + { "ifstopped", 0, NULL, 'S'}, + { "nodeps", 0, NULL, 'D'}, + { "lockfd", 1, NULL, 'l'}, + longopts_COMMON +}; +const char *const longopts_help[] = { + "set xtrace when running the script", + "show what would be done", + "only run commands when started", + "only run commands when stopped", + "ignore dependencies", + "fd of the exclusive lock from rc", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +static char *service, *runlevel, *ibsave, *prefix; +static RC_DEPTREE *deptree; +static RC_STRINGLIST *applet_list, *services, *tmplist; +static RC_STRINGLIST *restart_services; +static RC_STRINGLIST *need_services; +static RC_STRINGLIST *use_services; +static RC_STRINGLIST *want_services; +static RC_HOOK hook_out; +static int exclusive_fd = -1, master_tty = -1; +static bool sighup, in_background, deps, dry_run; +static pid_t service_pid; +static int signal_pipe[2] = { -1, -1 }; + +static RC_STRINGLIST *deptypes_b; /* broken deps */ +static RC_STRINGLIST *deptypes_n; /* needed deps */ +static RC_STRINGLIST *deptypes_nw; /* need+want deps */ +static RC_STRINGLIST *deptypes_nwu; /* need+want+use deps */ +static RC_STRINGLIST *deptypes_nwua; /* need+want+use+after deps */ +static RC_STRINGLIST *deptypes_m; /* needed deps for stopping */ +static RC_STRINGLIST *deptypes_mwua; /* need+want+use+after deps for stopping */ + +static void +handle_signal(int sig) +{ + int serrno = errno; + char *signame = NULL; + struct winsize ws; + + switch (sig) { + case SIGHUP: + sighup = true; + break; + + case SIGCHLD: + if (signal_pipe[1] > -1) { + if (write(signal_pipe[1], &sig, sizeof(sig)) == -1) + eerror("%s: send: %s", + service, strerror(errno)); + } else + rc_waitpid(-1); + break; + + case SIGWINCH: + if (master_tty >= 0) { + ioctl(fileno(stdout), TIOCGWINSZ, &ws); + ioctl(master_tty, TIOCSWINSZ, &ws); + } + break; + + case SIGINT: + if (!signame) + xasprintf(&signame, "SIGINT"); + /* FALLTHROUGH */ + case SIGTERM: + if (!signame) + xasprintf(&signame, "SIGTERM"); + /* FALLTHROUGH */ + case SIGQUIT: + if (!signame) + xasprintf(&signame, "SIGQUIT"); + /* Send the signal to our children too */ + if (service_pid > 0) + kill(service_pid, sig); + eerror("%s: caught %s, aborting", applet, signame); + free(signame); + exit(EXIT_FAILURE); + /* NOTREACHED */ + + default: + eerror("%s: caught unknown signal %d", applet, sig); + } + + /* Restore errno */ + errno = serrno; +} + +static void +unhotplug() +{ + char *file = NULL; + + xasprintf(&file, RC_SVCDIR "/hotplugged/%s", applet); + if (exists(file) && unlink(file) != 0) + eerror("%s: unlink `%s': %s", applet, file, strerror(errno)); + free(file); +} + +static void +start_services(RC_STRINGLIST *list) +{ + RC_STRING *svc; + RC_SERVICE state = rc_service_state (service); + + if (!list) + return; + + if (state & RC_SERVICE_INACTIVE || + state & RC_SERVICE_WASINACTIVE || + state & RC_SERVICE_STARTING || + state & RC_SERVICE_STARTED) + { + TAILQ_FOREACH(svc, list, entries) { + if (!(rc_service_state(svc->value) & + RC_SERVICE_STOPPED)) + continue; + if (state & RC_SERVICE_INACTIVE || + state & RC_SERVICE_WASINACTIVE) + { + rc_service_schedule_start(service, + svc->value); + ewarn("WARNING: %s will start when %s has started", + svc->value, applet); + } else + service_start(svc->value); + } + } +} + +static void +restore_state(void) +{ + RC_SERVICE state; + + if (rc_in_plugin || exclusive_fd == -1) + return; + state = rc_service_state(applet); + if (state & RC_SERVICE_STOPPING) { + if (state & RC_SERVICE_WASINACTIVE) + rc_service_mark(applet, RC_SERVICE_INACTIVE); + else + rc_service_mark(applet, RC_SERVICE_STARTED); + if (rc_runlevel_stopping()) + rc_service_mark(applet, RC_SERVICE_FAILED); + } else if (state & RC_SERVICE_STARTING) { + if (state & RC_SERVICE_WASINACTIVE) + rc_service_mark(applet, RC_SERVICE_INACTIVE); + else + rc_service_mark(applet, RC_SERVICE_STOPPED); + if (rc_runlevel_starting()) + rc_service_mark(applet, RC_SERVICE_FAILED); + } + exclusive_fd = svc_unlock(applet, exclusive_fd); +} + +static void +cleanup(void) +{ + restore_state(); + + if (!rc_in_plugin) { + if (hook_out) { + rc_plugin_run(hook_out, applet); + if (hook_out == RC_HOOK_SERVICE_START_DONE) + rc_plugin_run(RC_HOOK_SERVICE_START_OUT, + applet); + else if (hook_out == RC_HOOK_SERVICE_STOP_DONE) + rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, + applet); + } + + if (restart_services) + start_services(restart_services); + } + + rc_plugin_unload(); + + rc_stringlist_free(deptypes_b); + rc_stringlist_free(deptypes_n); + rc_stringlist_free(deptypes_nw); + rc_stringlist_free(deptypes_nwu); + rc_stringlist_free(deptypes_nwua); + rc_stringlist_free(deptypes_m); + rc_stringlist_free(deptypes_mwua); + rc_deptree_free(deptree); + rc_stringlist_free(restart_services); + rc_stringlist_free(need_services); + rc_stringlist_free(use_services); + rc_stringlist_free(want_services); + rc_stringlist_free(services); + rc_stringlist_free(applet_list); + rc_stringlist_free(tmplist); + free(ibsave); + free(service); + free(prefix); + free(runlevel); +} + +/* Buffer and lock all output messages so that we get readable content */ +/* FIXME: Use a dynamic lock file that contains the tty/pts as well. + * For example openrc-pts8.lock or openrc-tty1.lock. + * Using a static lock file makes no sense, esp. in multi-user environments. + * Why don't we use (f)printf, as it is thread-safe through POSIX already? + * Bug: 360013 + */ +static int +write_prefix(const char *buffer, size_t bytes, bool *prefixed) +{ + size_t i, j; + const char *ec = ecolor(ECOLOR_HILITE); + const char *ec_normal = ecolor(ECOLOR_NORMAL); + ssize_t ret = 0; + int fd = fileno(stdout), lock_fd = -1; + + /* + * Lock the prefix. + * open() may fail here when running as user, as RC_SVCDIR may not be writable. + */ + lock_fd = open(PREFIX_LOCK, O_WRONLY | O_CREAT, 0664); + + if (lock_fd != -1) { + while (flock(lock_fd, LOCK_EX) != 0) { + if (errno != EINTR) { + ewarnv("flock() failed: %s", strerror(errno)); + break; + } + } + } + else + ewarnv("Couldn't open the prefix lock, please make sure you have enough permissions"); + + for (i = 0; i < bytes; i++) { + /* We don't prefix eend calls (cursor up) */ + if (buffer[i] == '\033' && !*prefixed) { + for (j = i + 1; j < bytes; j++) { + if (buffer[j] == 'A') + *prefixed = true; + if (isalpha((unsigned int)buffer[j])) + break; + } + } + + if (!*prefixed) { + ret += write(fd, ec, strlen(ec)); + ret += write(fd, prefix, strlen(prefix)); + ret += write(fd, ec_normal, strlen(ec_normal)); + ret += write(fd, "|", 1); + *prefixed = true; + } + + if (buffer[i] == '\n') + *prefixed = false; + ret += write(fd, buffer + i, 1); + } + + /* Release the lock */ + close(lock_fd); + + return ret; +} + +static int +svc_exec(const char *arg1, const char *arg2) +{ + int ret, fdout = fileno(stdout); + struct termios tt; + struct winsize ws; + int i; + int flags = 0; + struct pollfd fd[2]; + int s; + char *buffer; + size_t bytes; + bool prefixed = false; + int slave_tty; + sigset_t sigchldmask; + sigset_t oldmask; + + /* Setup our signal pipe */ + if (pipe(signal_pipe) == -1) + eerrorx("%s: pipe: %s", service, applet); + for (i = 0; i < 2; i++) + if ((flags = fcntl(signal_pipe[i], F_GETFD, 0) == -1 || + fcntl(signal_pipe[i], F_SETFD, flags | FD_CLOEXEC) == -1)) + eerrorx("%s: fcntl: %s", service, strerror(errno)); + + /* Open a pty for our prefixed output + * We do this instead of mapping pipes to stdout, stderr so that + * programs can tell if they're attached to a tty or not. + * The only loss is that we can no longer tell the difference + * between the childs stdout or stderr */ + master_tty = slave_tty = -1; + if (prefix && isatty(fdout)) { + tcgetattr(fdout, &tt); + ioctl(fdout, TIOCGWINSZ, &ws); + + /* If the below call fails due to not enough ptys then we don't + * prefix the output, but we still work */ + openpty(&master_tty, &slave_tty, NULL, &tt, &ws); + if (master_tty >= 0 && + (flags = fcntl(master_tty, F_GETFD, 0)) == 0) + fcntl(master_tty, F_SETFD, flags | FD_CLOEXEC); + + if (slave_tty >=0 && + (flags = fcntl(slave_tty, F_GETFD, 0)) == 0) + fcntl(slave_tty, F_SETFD, flags | FD_CLOEXEC); + } + + service_pid = fork(); + if (service_pid == -1) + eerrorx("%s: fork: %s", service, strerror(errno)); + if (service_pid == 0) { + if (slave_tty >= 0) { + dup2(slave_tty, STDOUT_FILENO); + dup2(slave_tty, STDERR_FILENO); + } + + if (exists(RC_SVCDIR "/openrc-run.sh")) { + if (arg2) + einfov("Executing: %s %s %s %s %s", + RC_SVCDIR "/openrc-run.sh", RC_SVCDIR "/openrc-run.sh", + service, arg1, arg2); + else + einfov("Executing: %s %s %s %s", + RC_SVCDIR "/openrc-run.sh", RC_SVCDIR "/openrc-run.sh", + service, arg1); + execl(RC_SVCDIR "/openrc-run.sh", + RC_SVCDIR "/openrc-run.sh", + service, arg1, arg2, (char *) NULL); + eerror("%s: exec `" RC_SVCDIR "/openrc-run.sh': %s", + service, strerror(errno)); + _exit(EXIT_FAILURE); + } else { + if (arg2) + einfov("Executing: %s %s %s %s %s", + RC_LIBEXECDIR "/sh/openrc-run.sh", + RC_LIBEXECDIR "/sh/openrc-run.sh", + service, arg1, arg2); + else + einfov("Executing: %s %s %s %s", + RC_LIBEXECDIR "/sh/openrc-run.sh", + RC_LIBEXECDIR "/sh/openrc-run.sh", + service, arg1); + execl(RC_LIBEXECDIR "/sh/openrc-run.sh", + RC_LIBEXECDIR "/sh/openrc-run.sh", + service, arg1, arg2, (char *) NULL); + eerror("%s: exec `" RC_LIBEXECDIR "/sh/openrc-run.sh': %s", + service, strerror(errno)); + _exit(EXIT_FAILURE); + } + } + + buffer = xmalloc(sizeof(char) * BUFSIZ); + fd[0].fd = signal_pipe[0]; + fd[0].events = fd[1].events = POLLIN; + fd[0].revents = fd[1].revents = 0; + if (master_tty >= 0) { + fd[1].fd = master_tty; + fd[1].events = POLLIN; + fd[1].revents = 0; + } + + for (;;) { + if ((s = poll(fd, master_tty >= 0 ? 2 : 1, -1)) == -1) { + if (errno != EINTR) { + eerror("%s: poll: %s", + service, strerror(errno)); + break; + } + } + + if (s > 0) { + if (fd[1].revents & (POLLIN | POLLHUP)) { + bytes = read(master_tty, buffer, BUFSIZ); + write_prefix(buffer, bytes, &prefixed); + } + + /* Only SIGCHLD signals come down this pipe */ + if (fd[0].revents & (POLLIN | POLLHUP)) + break; + } + } + + free(buffer); + + sigemptyset (&sigchldmask); + sigaddset (&sigchldmask, SIGCHLD); + sigprocmask (SIG_BLOCK, &sigchldmask, &oldmask); + + close(signal_pipe[0]); + close(signal_pipe[1]); + signal_pipe[0] = signal_pipe[1] = -1; + + sigprocmask (SIG_SETMASK, &oldmask, NULL); + + if (master_tty >= 0) { + /* Why did we do this? */ + /* signal (SIGWINCH, SIG_IGN); */ + close(master_tty); + master_tty = -1; + } + + ret = rc_waitpid(service_pid); + ret = WEXITSTATUS(ret); + if (ret != 0 && errno == ECHILD) + /* killall5 -9 could cause this */ + ret = 0; + service_pid = 0; + + return ret; +} + +static bool +svc_wait(const char *svc) +{ + char *file = NULL; + int fd; + bool forever = false; + RC_STRINGLIST *keywords; + struct timespec interval, timeout, warn; + + /* Some services don't have a timeout, like fsck */ + keywords = rc_deptree_depend(deptree, svc, "keyword"); + if (rc_stringlist_find(keywords, "-timeout") || + rc_stringlist_find(keywords, "notimeout")) + forever = true; + rc_stringlist_free(keywords); + + xasprintf(&file, RC_SVCDIR "/exclusive/%s", basename_c(svc)); + + interval.tv_sec = 0; + interval.tv_nsec = WAIT_INTERVAL; + timeout.tv_sec = WAIT_TIMEOUT; + timeout.tv_nsec = 0; + warn.tv_sec = WARN_TIMEOUT; + warn.tv_nsec = 0; + for (;;) { + fd = open(file, O_RDONLY | O_NONBLOCK); + if (fd != -1) { + if (flock(fd, LOCK_SH | LOCK_NB) == 0) { + close(fd); + free(file); + return true; + } + close(fd); + } + if (errno == ENOENT) { + free(file); + return true; + } + if (errno != EWOULDBLOCK) { + eerror("%s: open `%s': %s", applet, file, + strerror(errno)); + free(file); + exit(EXIT_FAILURE); + } + if (nanosleep(&interval, NULL) == -1) { + if (errno != EINTR) + goto finish; + } + if (!forever) { + timespecsub(&timeout, &interval, &timeout); + if (timeout.tv_sec <= 0) + goto finish; + timespecsub(&warn, &interval, &warn); + if (warn.tv_sec <= 0) { + ewarn("%s: waiting for %s (%d seconds)", + applet, svc, (int)timeout.tv_sec); + warn.tv_sec = WARN_TIMEOUT; + warn.tv_nsec = 0; + } + } + } +finish: + free(file); + return false; +} + +static void +get_started_services(void) +{ + RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE); + + rc_stringlist_free(restart_services); + restart_services = rc_services_in_state(RC_SERVICE_STARTED); + TAILQ_CONCAT(restart_services, tmp, entries); + free(tmp); +} + +static void +setup_deptypes(void) +{ + deptypes_b = rc_stringlist_new(); + rc_stringlist_add(deptypes_b, "broken"); + + deptypes_n = rc_stringlist_new(); + rc_stringlist_add(deptypes_n, "ineed"); + + deptypes_nw = rc_stringlist_new(); + rc_stringlist_add(deptypes_nw, "ineed"); + rc_stringlist_add(deptypes_nw, "iwant"); + + deptypes_nwu = rc_stringlist_new(); + rc_stringlist_add(deptypes_nwu, "ineed"); + rc_stringlist_add(deptypes_nwu, "iwant"); + rc_stringlist_add(deptypes_nwu, "iuse"); + + deptypes_nwua = rc_stringlist_new(); + rc_stringlist_add(deptypes_nwua, "ineed"); + rc_stringlist_add(deptypes_nwua, "iwant"); + rc_stringlist_add(deptypes_nwua, "iuse"); + rc_stringlist_add(deptypes_nwua, "iafter"); + + deptypes_m = rc_stringlist_new(); + rc_stringlist_add(deptypes_m, "needsme"); + + deptypes_mwua = rc_stringlist_new(); + rc_stringlist_add(deptypes_mwua, "needsme"); + rc_stringlist_add(deptypes_mwua, "wantsme"); + rc_stringlist_add(deptypes_mwua, "usesme"); + rc_stringlist_add(deptypes_mwua, "beforeme"); +} + +static void +svc_start_check(void) +{ + RC_SERVICE state; + + state = rc_service_state(service); + + if (in_background) { + if (!(state & (RC_SERVICE_INACTIVE | RC_SERVICE_STOPPED))) + exit(EXIT_FAILURE); + if (rc_yesno(getenv("IN_HOTPLUG"))) + rc_service_mark(service, RC_SERVICE_HOTPLUGGED); + if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0) + ewarnx("WARNING: %s will be started in the" + " next runlevel", applet); + } + + if (exclusive_fd == -1) + exclusive_fd = svc_lock(applet); + if (exclusive_fd == -1) { + if (errno == EACCES) + eerrorx("%s: superuser access required", applet); + if (state & RC_SERVICE_STOPPING) + ewarnx("WARNING: %s is stopping", applet); + else + ewarnx("WARNING: %s is already starting", applet); + } + fcntl(exclusive_fd, F_SETFD, + fcntl(exclusive_fd, F_GETFD, 0) | FD_CLOEXEC); + + if (state & RC_SERVICE_STARTED) { + ewarn("WARNING: %s has already been started", applet); + exit(EXIT_SUCCESS); + } + else if (state & RC_SERVICE_INACTIVE && !in_background) + ewarnx("WARNING: %s has already started, but is inactive", + applet); + + rc_service_mark(service, RC_SERVICE_STARTING); + hook_out = RC_HOOK_SERVICE_START_OUT; + rc_plugin_run(RC_HOOK_SERVICE_START_IN, applet); +} + +static void +svc_start_deps(void) +{ + bool first; + RC_STRING *svc, *svc2; + RC_SERVICE state; + int depoptions = RC_DEP_TRACE, n; + size_t len; + char *p, *tmp; + pid_t pid; + + errno = 0; + if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT) + depoptions |= RC_DEP_STRICT; + + if (!deptree && ((deptree = _rc_deptree_load(0, NULL)) == NULL)) + eerrorx("failed to load deptree"); + if (!deptypes_b) + setup_deptypes(); + + services = rc_deptree_depends(deptree, deptypes_b, applet_list, + runlevel, 0); + if (TAILQ_FIRST(services)) { + eerrorn("ERROR: %s needs service(s) ", applet); + first = true; + TAILQ_FOREACH(svc, services, entries) { + if (first) + first = false; + else + fprintf(stderr, ", "); + fprintf(stderr, "%s", svc->value); + } + fprintf(stderr, "\n"); + exit(EXIT_FAILURE); + } + rc_stringlist_free(services); + services = NULL; + + need_services = rc_deptree_depends(deptree, deptypes_n, + applet_list, runlevel, depoptions); + want_services = rc_deptree_depends(deptree, deptypes_nw, + applet_list, runlevel, depoptions); + use_services = rc_deptree_depends(deptree, deptypes_nwu, + applet_list, runlevel, depoptions); + + if (!rc_runlevel_starting()) { + TAILQ_FOREACH(svc, use_services, entries) { + state = rc_service_state(svc->value); + /* Don't stop failed services again. + * If you remove this check, ensure that the + * exclusive file isn't created. */ + if (state & RC_SERVICE_FAILED && + rc_runlevel_starting()) + continue; + if (state & RC_SERVICE_STOPPED) { + if (dry_run) { + printf(" %s", svc->value); + continue; + } + pid = service_start(svc->value); + if (!rc_conf_yesno("rc_parallel")) + rc_waitpid(pid); + } + } + } + + if (dry_run) + return; + + /* Now wait for them to start */ + services = rc_deptree_depends(deptree, deptypes_nwua, applet_list, + runlevel, depoptions); + /* We use tmplist to hold our scheduled by list */ + tmplist = rc_stringlist_new(); + TAILQ_FOREACH(svc, services, entries) { + state = rc_service_state(svc->value); + if (state & RC_SERVICE_STARTED) + continue; + + /* Don't wait for services which went inactive but are + * now in starting state which we are after */ + if (state & RC_SERVICE_STARTING && + state & RC_SERVICE_WASINACTIVE) + { + if (!rc_stringlist_find(need_services, svc->value) && + !rc_stringlist_find(want_services, svc->value) && + !rc_stringlist_find(use_services, svc->value)) + continue; + } + + if (!svc_wait(svc->value)) + eerror("%s: timed out waiting for %s", + applet, svc->value); + state = rc_service_state(svc->value); + if (state & RC_SERVICE_STARTED) + continue; + if (rc_stringlist_find(need_services, svc->value)) { + if (state & RC_SERVICE_INACTIVE || + state & RC_SERVICE_WASINACTIVE) + { + rc_stringlist_add(tmplist, svc->value); + } else if (!TAILQ_FIRST(tmplist)) + eerrorx("ERROR: cannot start %s as" + " %s would not start", + applet, svc->value); + } + } + + if (TAILQ_FIRST(tmplist)) { + /* Set the state now, then unlink our exclusive so that + our scheduled list is preserved */ + rc_service_mark(service, RC_SERVICE_STOPPED); + + rc_stringlist_free(use_services); + use_services = NULL; + len = 0; + n = 0; + TAILQ_FOREACH(svc, tmplist, entries) { + rc_service_schedule_start(svc->value, service); + use_services = rc_deptree_depend(deptree, + "iprovide", svc->value); + TAILQ_FOREACH(svc2, use_services, entries) + rc_service_schedule_start(svc2->value, service); + rc_stringlist_free(use_services); + use_services = NULL; + len += strlen(svc->value) + 2; + n++; + } + + len += 5; + tmp = p = xmalloc(sizeof(char) * len); + TAILQ_FOREACH(svc, tmplist, entries) { + if (p != tmp) + p += snprintf(p, len, ", "); + p += snprintf(p, len - (p - tmp), + "%s", svc->value); + } + rc_stringlist_free(tmplist); + tmplist = NULL; + ewarnx("WARNING: %s will start when %s has started", applet, tmp); + free(tmp); + } + + rc_stringlist_free(tmplist); + tmplist = NULL; + rc_stringlist_free(services); + services = NULL; +} + +static void svc_start_real() +{ + bool started; + RC_STRING *svc, *svc2; + + if (ibsave) + setenv("IN_BACKGROUND", ibsave, 1); + hook_out = RC_HOOK_SERVICE_START_DONE; + rc_plugin_run(RC_HOOK_SERVICE_START_NOW, applet); + started = (svc_exec("start", NULL) == 0); + if (ibsave) + unsetenv("IN_BACKGROUND"); + + if (rc_service_state(service) & RC_SERVICE_INACTIVE) + ewarnx("WARNING: %s has started, but is inactive", applet); + else if (!started) + eerrorx("ERROR: %s failed to start", applet); + + rc_service_mark(service, RC_SERVICE_STARTED); + exclusive_fd = svc_unlock(applet, exclusive_fd); + hook_out = RC_HOOK_SERVICE_START_OUT; + rc_plugin_run(RC_HOOK_SERVICE_START_DONE, applet); + + /* Now start any scheduled services */ + services = rc_services_scheduled(service); + TAILQ_FOREACH(svc, services, entries) + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + service_start(svc->value); + rc_stringlist_free(services); + services = NULL; + + /* Do the same for any services we provide */ + if (deptree) { + tmplist = rc_deptree_depend(deptree, "iprovide", applet); + TAILQ_FOREACH(svc, tmplist, entries) { + services = rc_services_scheduled(svc->value); + TAILQ_FOREACH(svc2, services, entries) + if (rc_service_state(svc2->value) & + RC_SERVICE_STOPPED) + service_start(svc2->value); + rc_stringlist_free(services); + services = NULL; + } + rc_stringlist_free(tmplist); + tmplist = NULL; + } + + hook_out = 0; + rc_plugin_run(RC_HOOK_SERVICE_START_OUT, applet); +} + +static void +svc_start(void) +{ + if (dry_run) + einfon("start:"); + else + svc_start_check(); + if (deps) + svc_start_deps(); + if (dry_run) + printf(" %s\n", applet); + else + svc_start_real(); +} + +static int +svc_stop_check(RC_SERVICE *state) +{ + *state = rc_service_state(service); + + if (rc_runlevel_stopping() && *state & RC_SERVICE_FAILED) + exit(EXIT_FAILURE); + + if (in_background && + !(*state & RC_SERVICE_STARTED) && + !(*state & RC_SERVICE_INACTIVE)) + exit(EXIT_FAILURE); + + if (exclusive_fd == -1) + exclusive_fd = svc_lock(applet); + if (exclusive_fd == -1) { + if (errno == EACCES) + eerrorx("%s: superuser access required", applet); + if (*state & RC_SERVICE_STOPPING) + ewarnx("WARNING: %s is already stopping", applet); + eerrorx("ERROR: %s stopped by something else", applet); + } + fcntl(exclusive_fd, F_SETFD, + fcntl(exclusive_fd, F_GETFD, 0) | FD_CLOEXEC); + + if (*state & RC_SERVICE_STOPPED) { + ewarn("WARNING: %s is already stopped", applet); + return 1; + } + + rc_service_mark(service, RC_SERVICE_STOPPING); + hook_out = RC_HOOK_SERVICE_STOP_OUT; + rc_plugin_run(RC_HOOK_SERVICE_STOP_IN, applet); + + if (!rc_runlevel_stopping()) { + if (rc_service_in_runlevel(service, RC_LEVEL_SYSINIT)) + ewarn("WARNING: you are stopping a sysinit service"); + else if (rc_service_in_runlevel(service, RC_LEVEL_BOOT)) + ewarn("WARNING: you are stopping a boot service"); + } + + return 0; +} + +static void +svc_stop_deps(RC_SERVICE state) +{ + int depoptions = RC_DEP_TRACE; + RC_STRING *svc; + pid_t pid; + + if (state & RC_SERVICE_WASINACTIVE) + return; + + errno = 0; + if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT) + depoptions |= RC_DEP_STRICT; + + if (!deptree && ((deptree = _rc_deptree_load(0, NULL)) == NULL)) + eerrorx("failed to load deptree"); + + if (!deptypes_m) + setup_deptypes(); + + services = rc_deptree_depends(deptree, deptypes_m, applet_list, + runlevel, depoptions); + tmplist = rc_stringlist_new(); + TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) { + state = rc_service_state(svc->value); + /* Don't stop failed services again. + * If you remove this check, ensure that the + * exclusive file isn't created. */ + if (state & RC_SERVICE_FAILED && + rc_runlevel_stopping()) + continue; + if (state & RC_SERVICE_STARTED || + state & RC_SERVICE_INACTIVE) + { + if (dry_run) { + printf(" %s", svc->value); + continue; + } + svc_wait(svc->value); + state = rc_service_state(svc->value); + if (state & RC_SERVICE_STARTED || + state & RC_SERVICE_INACTIVE) + { + pid = service_stop(svc->value); + if (!rc_conf_yesno("rc_parallel")) + rc_waitpid(pid); + rc_stringlist_add(tmplist, svc->value); + } + } + } + rc_stringlist_free(services); + services = NULL; + if (dry_run) + return; + + TAILQ_FOREACH(svc, tmplist, entries) { + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + continue; + svc_wait(svc->value); + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + continue; + if (rc_runlevel_stopping()) { + /* If shutting down, we should stop even + * if a dependant failed */ + if (runlevel && + (strcmp(runlevel, + RC_LEVEL_SHUTDOWN) == 0 || + strcmp(runlevel, + RC_LEVEL_SINGLE) == 0)) + continue; + rc_service_mark(service, RC_SERVICE_FAILED); + } + eerrorx("ERROR: cannot stop %s as %s " + "is still up", applet, svc->value); + } + rc_stringlist_free(tmplist); + tmplist = NULL; + + /* We now wait for other services that may use us and are + * stopping. This is important when a runlevel stops */ + services = rc_deptree_depends(deptree, deptypes_mwua, applet_list, + runlevel, depoptions); + TAILQ_FOREACH(svc, services, entries) { + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + continue; + svc_wait(svc->value); + } + rc_stringlist_free(services); + services = NULL; +} + +static void +svc_stop_real(void) +{ + bool stopped; + + /* If we're stopping localmount, set LC_ALL=C so that + * bash doesn't load anything blocking the unmounting of /usr */ + if (strcmp(applet, "localmount") == 0) + setenv("LC_ALL", "C", 1); + + if (ibsave) + setenv("IN_BACKGROUND", ibsave, 1); + hook_out = RC_HOOK_SERVICE_STOP_DONE; + rc_plugin_run(RC_HOOK_SERVICE_STOP_NOW, applet); + stopped = (svc_exec("stop", NULL) == 0); + if (ibsave) + unsetenv("IN_BACKGROUND"); + + if (!stopped) + eerrorx("ERROR: %s failed to stop", applet); + + if (in_background) + rc_service_mark(service, RC_SERVICE_INACTIVE); + else + rc_service_mark(service, RC_SERVICE_STOPPED); + + hook_out = RC_HOOK_SERVICE_STOP_OUT; + rc_plugin_run(RC_HOOK_SERVICE_STOP_DONE, applet); + hook_out = 0; + rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, applet); +} + +static int +svc_stop(void) +{ + RC_SERVICE state; + + state = 0; + if (dry_run) + einfon("stop:"); + else + if (svc_stop_check(&state) == 1) + return 1; /* Service has been stopped already */ + if (deps) + svc_stop_deps(state); + if (dry_run) + printf(" %s\n", applet); + else + svc_stop_real(); + + return 0; +} + +static void +svc_restart(void) +{ + /* This is hairly and a better way needs to be found I think! + * The issue is this - openvpn need net and dns. net can restart + * dns via resolvconf, so you could have openvpn trying to restart + * dnsmasq which in turn is waiting on net which in turn is waiting + * on dnsmasq. + * The work around is for resolvconf to restart its services with + * --nodeps which means just that. + * The downside is that there is a small window when our status is + * invalid. + * One workaround would be to introduce a new status, + * or status locking. */ + if (!deps) { + RC_SERVICE state = rc_service_state(service); + if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE) + svc_exec("stop", "start"); + else + svc_exec("start", NULL); + return; + } + + if (!(rc_service_state(service) & RC_SERVICE_STOPPED)) { + get_started_services(); + svc_stop(); + if (dry_run) + ewarn("Cannot calculate restart start dependencies" + " on a dry-run"); + } + + svc_start(); + start_services(restart_services); + rc_stringlist_free(restart_services); + restart_services = NULL; +} + +static bool +service_plugable(void) +{ + char *list, *p, *token; + bool allow = true, truefalse; + char *match = rc_conf_value("rc_hotplug"); + + if (!match) + match = rc_conf_value("rc_plug_services"); + if (!match) + return false; + + list = xstrdup(match); + p = list; + while ((token = strsep(&p, " "))) { + if (token[0] == '!') { + truefalse = false; + token++; + } else + truefalse = true; + + if (fnmatch(token, applet, 0) == 0) { + allow = truefalse; + break; + } + } + free(list); + return allow; +} + +int main(int argc, char **argv) +{ + bool doneone = false; + bool runscript = false; + int retval, opt, depoptions = RC_DEP_TRACE; + RC_STRING *svc; + char *path = NULL; + char *lnk = NULL; + char *dir, *save = NULL, *saveLnk = NULL; + char *pidstr = NULL; + size_t l = 0, ll; + const char *file; + struct stat stbuf; + + /* Show help if insufficient args */ + if (argc < 2 || !exists(argv[1])) { + fprintf(stderr, "openrc-run should not be run directly\n"); + exit(EXIT_FAILURE); + } + + applet = basename_c(argv[0]); + if (strcmp(applet, "runscript") == 0) + runscript = true; + + if (stat(argv[1], &stbuf) != 0) { + fprintf(stderr, "openrc-run `%s': %s\n", + argv[1], strerror(errno)); + exit(EXIT_FAILURE); + } + + atexit(cleanup); + + /* We need to work out the real full path to our service. + * This works fine, provided that we ONLY allow multiplexed services + * to exist in the same directory as the master link. + * Also, the master link as to be a real file in the init dir. */ + path = realpath(argv[1], NULL); + if (!path) { + fprintf(stderr, "realpath: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + lnk = xmalloc(4096); + memset(lnk, 0, 4096); + if (readlink(argv[1], lnk, 4096)) { + dir = dirname(path); + if (strchr(lnk, '/')) { + save = xstrdup(dir); + saveLnk = xstrdup(lnk); + dir = dirname(saveLnk); + if (strcmp(dir, save) == 0) + file = basename_c(argv[1]); + else + file = basename_c(lnk); + dir = save; + } else + file = basename_c(argv[1]); + ll = strlen(dir) + strlen(file) + 2; + xasprintf(&service, "%s/%s", dir, file); + if (stat(service, &stbuf) != 0) { + free(service); + service = xstrdup(lnk); + } + free(save); + free(saveLnk); + } + free(lnk); + if (!service) + service = xstrdup(path); + applet = basename_c(service); + + if (argc < 3) + usage(EXIT_FAILURE); + + /* Change dir to / to ensure all init scripts don't use stuff in pwd */ + if (chdir("/") == -1) + eerror("chdir: %s", strerror(errno)); + + if ((runlevel = xstrdup(getenv("RC_RUNLEVEL"))) == NULL) { + env_filter(); + env_config(); + runlevel = rc_runlevel_get(); + } + + setenv("EINFO_LOG", service, 1); + setenv("RC_SVCNAME", applet, 1); + + /* Set an env var so that we always know our pid regardless of any + subshells the init script may create so that our mark_service_* + functions can always instruct us of this change */ + xasprintf(&pidstr, "%d", (int) getpid()); + setenv("RC_OPENRC_PID", pidstr, 1); + /* + * RC_RUNSCRIPT_PID is deprecated, but we will keep it for a while + * for safety. + */ + setenv("RC_RUNSCRIPT_PID", pidstr, 1); + + /* eprefix is kinda klunky, but it works for our purposes */ + if (rc_conf_yesno("rc_parallel")) { + /* Get the longest service name */ + services = rc_services_in_runlevel(NULL); + TAILQ_FOREACH(svc, services, entries) { + ll = strlen(svc->value); + if (ll > l) + l = ll; + } + rc_stringlist_free(services); + services = NULL; + ll = strlen(applet); + if (ll > l) + l = ll; + + /* Make our prefix string */ + prefix = xmalloc(sizeof(char) * l + 1); + ll = strlen(applet); + memcpy(prefix, applet, ll); + memset(prefix + ll, ' ', l - ll); + memset(prefix + l, 0, 1); + eprefix(prefix); + } + + /* Ok, we are ready to go, so setup selinux if applicable */ + selinux_setup(argv); + + deps = true; + + /* Punt the first arg as its our service name */ + argc--; + argv++; + + /* Right then, parse any options there may be */ + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *)0)) != -1) + switch (opt) { + case 'd': + setenv("RC_DEBUG", "YES", 1); + break; + case 'l': + exclusive_fd = atoi(optarg); + fcntl(exclusive_fd, F_SETFD, + fcntl(exclusive_fd, F_GETFD, 0) | FD_CLOEXEC); + break; + case 's': + if (!(rc_service_state(service) & RC_SERVICE_STARTED)) + exit(EXIT_FAILURE); + break; + case 'S': + if (!(rc_service_state(service) & RC_SERVICE_STOPPED)) + exit(EXIT_FAILURE); + break; + case 'D': + deps = false; + break; + case 'Z': + dry_run = true; + break; + case_RC_COMMON_GETOPT + } + + /* If we're changing runlevels and not called by rc then we cannot + work with any dependencies */ + if (deps && getenv("RC_PID") == NULL && + (rc_runlevel_starting() || rc_runlevel_stopping())) + deps = false; + + /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service + that is being called and not any dependents */ + if (getenv("IN_BACKGROUND")) { + ibsave = xstrdup(getenv("IN_BACKGROUND")); + in_background = rc_yesno(ibsave); + unsetenv("IN_BACKGROUND"); + } + + if (rc_yesno(getenv("IN_HOTPLUG"))) { + if (!service_plugable()) + eerrorx("%s: not allowed to be hotplugged", applet); + in_background = true; + } + + /* Setup a signal handler */ + signal_setup(SIGHUP, handle_signal); + signal_setup(SIGINT, handle_signal); + signal_setup(SIGQUIT, handle_signal); + signal_setup(SIGTERM, handle_signal); + signal_setup(SIGCHLD, handle_signal); + + /* Load our plugins */ + rc_plugin_load(); + + applet_list = rc_stringlist_new(); + rc_stringlist_add(applet_list, applet); + + if (runscript) + ewarn("%s uses runscript, please convert to openrc-run.", service); + + /* Now run each option */ + retval = EXIT_SUCCESS; + while (optind < argc) { + optarg = argv[optind++]; + + /* Abort on a sighup here */ + if (sighup) + exit (EXIT_FAILURE); + + /* Export the command we're running. + This is important as we stamp on the restart function now but + some start/stop routines still need to behave differently if + restarting. */ + unsetenv("RC_CMD"); + setenv("RC_CMD", optarg, 1); + + doneone = true; + + if (strcmp(optarg, "describe") == 0 || + strcmp(optarg, "help") == 0 || + strcmp(optarg, "depend") == 0) + { + save = prefix; + eprefix(NULL); + prefix = NULL; + svc_exec(optarg, NULL); + eprefix(save); + prefix = save; + } else if (strcmp(optarg, "ineed") == 0 || + strcmp(optarg, "iuse") == 0 || + strcmp(optarg, "iwant") == 0 || + strcmp(optarg, "needsme") == 0 || + strcmp(optarg, "usesme") == 0 || + strcmp(optarg, "wantsme") == 0 || + strcmp(optarg, "iafter") == 0 || + strcmp(optarg, "ibefore") == 0 || + strcmp(optarg, "iprovide") == 0) + { + errno = 0; + if (rc_conf_yesno("rc_depend_strict") || + errno == ENOENT) + depoptions |= RC_DEP_STRICT; + + if (!deptree && + ((deptree = _rc_deptree_load(0, NULL)) == NULL)) + eerrorx("failed to load deptree"); + + tmplist = rc_stringlist_new(); + rc_stringlist_add(tmplist, optarg); + services = rc_deptree_depends(deptree, tmplist, + applet_list, + runlevel, depoptions); + rc_stringlist_free(tmplist); + tmplist = NULL; + TAILQ_FOREACH(svc, services, entries) + printf("%s ", svc->value); + printf ("\n"); + rc_stringlist_free(services); + services = NULL; + } else if (strcmp (optarg, "status") == 0 || strcmp(optarg, "onestatus") == 0) { + save = prefix; + eprefix(NULL); + prefix = NULL; + retval = svc_exec("status", NULL); + } else { + if (strcmp(optarg, "conditionalrestart") == 0 || + strcmp(optarg, "condrestart") == 0) + { + if (rc_service_state(service) & + RC_SERVICE_STARTED) + svc_restart(); + } else if (strcmp(optarg, "restart") == 0 || strcmp(optarg, "onerestart") == 0) { + svc_restart(); + } else if (strcmp(optarg, "start") == 0 || strcmp(optarg, "onestart") == 0) { + svc_start(); + } else if (strcmp(optarg, "stop") == 0 || strcmp(optarg, "onestop") == 0 || strcmp(optarg, "pause") == 0) { + if (strcmp(optarg, "pause") == 0) { + ewarn("WARNING: 'pause' is deprecated; please use '--nodeps stop'"); + deps = false; + } + if (deps && in_background) + get_started_services(); + if (svc_stop() == 1) + continue; /* Service has been stopped already */ + if (deps) { + if (!in_background && + !rc_runlevel_stopping() && + rc_service_state(service) & + RC_SERVICE_STOPPED) + unhotplug(); + + if (in_background && + rc_service_state(service) & + RC_SERVICE_INACTIVE) + { + TAILQ_FOREACH(svc, + restart_services, + entries) + if (rc_service_state(svc->value) & + RC_SERVICE_STOPPED) + rc_service_schedule_start(service, svc->value); + } + } + } else if (strcmp(optarg, "zap") == 0) { + einfo("Manually resetting %s to stopped state", + applet); + if (!rc_service_mark(applet, + RC_SERVICE_STOPPED)) + eerrorx("rc_service_mark: %s", + strerror(errno)); + unhotplug(); + } else + retval = svc_exec(optarg, NULL); + + /* We should ensure this list is empty after + * an action is done */ + rc_stringlist_free(restart_services); + restart_services = NULL; + } + + if (!doneone) + usage(EXIT_FAILURE); + } + + return retval; +} Index: contrib/openrc/src/rc/openrc-shutdown.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/openrc-shutdown.c @@ -0,0 +1,170 @@ +/* + * openrc-shutdown.c + * If you are using OpenRC's provided init, this will shut down or + * reboot your system. + * + * This is based on code written by James Hammons , so + * I would like to publically thank him for his work. + */ + +/* + * Copyright 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "rc.h" +#include "helpers.h" +#include "_usage.h" +#include "rc-wtmp.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "dDHKpRrsw" getoptstring_COMMON; +const struct option longopts[] = { + { "no-write", no_argument, NULL, 'd'}, + { "dry-run", no_argument, NULL, 'D'}, + { "halt", no_argument, NULL, 'H'}, + { "kexec", no_argument, NULL, 'K'}, + { "poweroff", no_argument, NULL, 'p'}, + { "reexec", no_argument, NULL, 'R'}, + { "reboot", no_argument, NULL, 'r'}, + { "single", no_argument, NULL, 's'}, + { "write-only", no_argument, NULL, 'w'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "do not write wtmp record", + "print actions instead of executing them", + "halt the system", + "reboot the system using kexec", + "power off the system", + "re-execute init (use after upgrading)", + "reboot the system", + "single user mode", + "write wtmp boot record and exit", + longopts_help_COMMON +}; +const char *usagestring = NULL; +const char *exclusive = "Select one of " +"--halt, --kexec, --poweroff, --reexec, --reboot, --single or --write-only"; + +static bool do_dryrun = false; +static bool do_halt = false; +static bool do_kexec = false; +static bool do_poweroff = false; +static bool do_reboot = false; +static bool do_reexec = false; +static bool do_single = false; +static bool do_wtmp = true; +static bool do_wtmp_only = false; + +static void send_cmd(const char *cmd) +{ + FILE *fifo; + size_t ignored; + + if (do_dryrun) { + einfo("Would send %s to init", cmd); + return; + } + if (do_wtmp && (do_halt || do_kexec || do_reboot || do_poweroff)) + log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); + fifo = fopen(RC_INIT_FIFO, "w"); + if (!fifo) { + perror("fopen"); + return; + } + + ignored = fwrite(cmd, 1, strlen(cmd), fifo); + if (ignored != strlen(cmd)) + printf("Error writing to init fifo\n"); + fclose(fifo); +} + +int main(int argc, char **argv) +{ + int opt; + int cmd_count = 0; + + applet = basename_c(argv[0]); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'd': + do_wtmp = false; + break; + case 'D': + do_dryrun = true; + break; + case 'H': + do_halt = true; + cmd_count++; + break; + case 'K': + do_kexec = true; + cmd_count++; + break; + case 'p': + do_poweroff = true; + cmd_count++; + break; + case 'R': + do_reexec = true; + cmd_count++; + break; + case 'r': + do_reboot = true; + cmd_count++; + break; + case 's': + do_single = true; + cmd_count++; + break; + case 'w': + do_wtmp_only = true; + cmd_count++; + break; + case_RC_COMMON_GETOPT + } + } + if (geteuid() != 0 && ! do_dryrun) + eerrorx("%s: you must be root\n", applet); + if (cmd_count != 1) { + eerror("%s: %s\n", applet, exclusive); + usage(EXIT_FAILURE); + } + if (do_halt) + send_cmd("halt"); + else if (do_kexec) + send_cmd("kexec"); + else if (do_poweroff) + send_cmd("poweroff"); + else if (do_reboot) + send_cmd("reboot"); + else if (do_reexec) + send_cmd("reexec"); + else if (do_wtmp_only) + log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); + else if (do_single) + send_cmd("single"); + return 0; +} Index: contrib/openrc/src/rc/rc-abort.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-abort.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" + +int main(void) +{ + const char *p = getenv("RC_PID"); + int pid; + + if (p && sscanf(p, "%d", &pid) == 1) { + if (kill(pid, SIGUSR1) != 0) + eerrorx("rc-abort: failed to signal parent %d: %s", + pid, strerror(errno)); + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; +} Index: contrib/openrc/src/rc/rc-depend.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-depend.c @@ -0,0 +1,177 @@ +/* + * rc-depend + * rc service dependency and ordering + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "aot:suTF:" getoptstring_COMMON; +const struct option longopts[] = { + { "starting", 0, NULL, 'a'}, + { "stopping", 0, NULL, 'o'}, + { "type", 1, NULL, 't'}, + { "notrace", 0, NULL, 'T'}, + { "strict", 0, NULL, 's'}, + { "update", 0, NULL, 'u'}, + { "deptree-file", 1, NULL, 'F'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Order services as if runlevel is starting", + "Order services as if runlevel is stopping", + "Type(s) of dependency to list", + "Don't trace service dependencies", + "Only use what is in the runlevels", + "Force an update of the dependency tree", + "File to load cached deptree from", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +int main(int argc, char **argv) +{ + RC_STRINGLIST *list; + RC_STRINGLIST *types; + RC_STRINGLIST *services; + RC_STRINGLIST *depends; + RC_STRING *s; + RC_DEPTREE *deptree = NULL; + int options = RC_DEP_TRACE, update = 0; + bool first = true; + char *runlevel = xstrdup(getenv("RC_RUNLEVEL")); + int opt; + char *token; + char *deptree_file = NULL; + + applet = basename_c(argv[0]); + types = rc_stringlist_new(); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'a': + options |= RC_DEP_START; + break; + case 'o': + options |= RC_DEP_STOP; + break; + case 's': + options |= RC_DEP_STRICT; + break; + case 't': + while ((token = strsep(&optarg, ","))) + rc_stringlist_add(types, token); + break; + case 'u': + update = 1; + break; + case 'T': + options &= RC_DEP_TRACE; + break; + case 'F': + deptree_file = xstrdup(optarg); + break; + + case_RC_COMMON_GETOPT + } + } + + if (deptree_file) { + if (!(deptree = rc_deptree_load_file(deptree_file))) + eerrorx("failed to load deptree"); + } else { + if (!(deptree = _rc_deptree_load(update, NULL))) + eerrorx("failed to load deptree"); + } + + if (!runlevel) + runlevel = rc_runlevel_get(); + + services = rc_stringlist_new(); + while (optind < argc) { + list = rc_stringlist_new(); + rc_stringlist_add(list, argv[optind]); + errno = 0; + depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0); + if (!depends && errno == ENOENT) + eerror("no dependency info for service `%s'", + argv[optind]); + else + rc_stringlist_add(services, argv[optind]); + + rc_stringlist_free(depends); + rc_stringlist_free(list); + optind++; + } + if (!TAILQ_FIRST(services)) { + rc_stringlist_free(services); + rc_stringlist_free(types); + rc_deptree_free(deptree); + free(runlevel); + if (update) + return EXIT_SUCCESS; + eerrorx("no services specified"); + } + + /* If we don't have any types, then supply some defaults */ + if (!TAILQ_FIRST(types)) { + rc_stringlist_add(types, "ineed"); + rc_stringlist_add(types, "iuse"); + } + + depends = rc_deptree_depends(deptree, types, services, + runlevel, options); + + if (TAILQ_FIRST(depends)) { + TAILQ_FOREACH(s, depends, entries) { + if (first) + first = false; + else + printf (" "); + printf ("%s", s->value); + + } + printf ("\n"); + } + + rc_stringlist_free(types); + rc_stringlist_free(services); + rc_stringlist_free(depends); + rc_deptree_free(deptree); + free(runlevel); + return EXIT_SUCCESS; +} Index: contrib/openrc/src/rc/rc-logger.h =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-logger.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef RC_LOGGER_H +#define RC_LOGGER_H + +pid_t rc_logger_pid; +int rc_logger_tty; +extern bool rc_in_logger; + +void rc_logger_open(const char *runlevel); +void rc_logger_close(void); + +#endif Index: contrib/openrc/src/rc/rc-logger.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-logger.c @@ -0,0 +1,312 @@ +/* + * rc-logger.c + * Spawns a logging daemon to capture stdout and stderr so we can log + * them to a buffer and/or files. + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) \ + || defined(__GNU__) +# include +#elif defined(__NetBSD__) || defined(__OpenBSD__) +# include +#else +# include +#endif + +#include "einfo.h" +#include "rc-logger.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" + +#define TMPLOG RC_SVCDIR "/rc.log" +#define DEFAULTLOG "/var/log/rc.log" + +static int signal_pipe[2] = { -1, -1 }; +static int fd_stdout = -1; +static int fd_stderr = -1; +static const char *runlevel = NULL; +static bool in_escape = false; +static bool in_term = false; + +static char *logbuf = NULL; +static size_t logbuf_size = 0; +static size_t logbuf_len = 0; + +pid_t rc_logger_pid = -1; +int rc_logger_tty = -1; +bool rc_in_logger = false; + +static void +write_log(int logfd, const char *buffer, size_t bytes) +{ + const char *p = buffer; + + while ((size_t)(p - buffer) < bytes) { + switch (*p) { + case '\r': + goto cont; + case '\033': + in_escape = true; + in_term = false; + goto cont; + case '\n': + in_escape = in_term = false; + break; + case '[': + if (in_escape) + in_term = true; + break; + } + + if (!in_escape) { + if (write(logfd, p++, 1) == -1) + eerror("write: %s", strerror(errno)); + continue; + } + + if (! in_term || isalpha((unsigned char)*p)) + in_escape = in_term = false; +cont: + p++; + } +} + +static void +write_time(FILE *f, const char *s) +{ + time_t now = time(NULL); + struct tm *tm = localtime(&now); + + fprintf(f, "\nrc %s logging %s at %s\n", runlevel, s, asctime(tm)); + fflush(f); +} + +void +rc_logger_close(void) +{ + int sig = SIGTERM; + + if (signal_pipe[1] > -1) { + if (write(signal_pipe[1], &sig, sizeof(sig)) == -1) + eerror("write: %s", strerror(errno)); + close(signal_pipe[1]); + signal_pipe[1] = -1; + } + + if (rc_logger_pid > 0) + waitpid(rc_logger_pid, 0, 0); + + if (fd_stdout > -1) + dup2(fd_stdout, STDOUT_FILENO); + if (fd_stderr > -1) + dup2(fd_stderr, STDERR_FILENO); +} + +void +rc_logger_open(const char *level) +{ + int slave_tty; + struct termios tt; + struct winsize ws; + char buffer[BUFSIZ]; + struct pollfd fd[2]; + int s = 0; + size_t bytes; + int i; + FILE *log = NULL; + FILE *plog = NULL; + const char *logfile; + int log_error = 0; + + if (!rc_conf_yesno("rc_logger")) + return; + + if (pipe(signal_pipe) == -1) + eerrorx("pipe: %s", strerror(errno)); + for (i = 0; i < 2; i++) + if ((s = fcntl (signal_pipe[i], F_GETFD, 0) == -1 || + fcntl (signal_pipe[i], F_SETFD, s | FD_CLOEXEC) == -1)) + eerrorx("fcntl: %s", strerror (errno)); + + if (isatty(STDOUT_FILENO)) { + tcgetattr(STDOUT_FILENO, &tt); + ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); + if (openpty(&rc_logger_tty, &slave_tty, NULL, &tt, &ws)) + return; + } else + if (openpty(&rc_logger_tty, &slave_tty, NULL, NULL, NULL)) + return; + + if ((s = fcntl(rc_logger_tty, F_GETFD, 0)) == 0) + fcntl(rc_logger_tty, F_SETFD, s | FD_CLOEXEC); + + if ((s = fcntl(slave_tty, F_GETFD, 0)) == 0) + fcntl(slave_tty, F_SETFD, s | FD_CLOEXEC); + + rc_logger_pid = fork(); + switch (rc_logger_pid) { + case -1: + eerror("fork: %s", strerror(errno)); + break; + case 0: + rc_in_logger = true; + close(signal_pipe[1]); + signal_pipe[1] = -1; + + runlevel = level; + if ((log = fopen(TMPLOG, "ae"))) + write_time(log, "started"); + else { + free(logbuf); + logbuf_size = BUFSIZ * 10; + logbuf = xmalloc(sizeof (char) * logbuf_size); + logbuf_len = 0; + } + + fd[0].fd = signal_pipe[0]; + fd[0].events = fd[1].events = POLLIN; + fd[0].revents = fd[1].revents = 0; + if (rc_logger_tty >= 0) + fd[1].fd = rc_logger_tty; + for (;;) { + if ((s = poll(fd, + rc_logger_tty >= 0 ? 2 : 1, -1)) == -1) + { + eerror("poll: %s", strerror(errno)); + break; + } else if (s == 0) + continue; + + if (fd[1].revents & (POLLIN | POLLHUP)) { + memset(buffer, 0, BUFSIZ); + bytes = read(rc_logger_tty, buffer, BUFSIZ); + if (write(STDOUT_FILENO, buffer, bytes) == -1) + eerror("write: %s", strerror(errno)); + + if (log) + write_log(fileno (log), buffer, bytes); + else { + if (logbuf_size - logbuf_len < bytes) { + logbuf_size += BUFSIZ * 10; + logbuf = xrealloc(logbuf, + sizeof(char ) * + logbuf_size); + } + + memcpy(logbuf + logbuf_len, + buffer, bytes); + logbuf_len += bytes; + } + } + + /* Only SIGTERMS signals come down this pipe */ + if (fd[0].revents & (POLLIN | POLLHUP)) + break; + } + if (logbuf) { + if ((log = fopen(TMPLOG, "ae"))) { + write_time(log, "started"); + write_log(fileno(log), logbuf, logbuf_len); + } + free(logbuf); + } + if (log) { + write_time(log, "stopped"); + fclose(log); + } + + /* Append the temporary log to the real log */ + logfile = rc_conf_value("rc_log_path"); + if (logfile == NULL) + logfile = DEFAULTLOG; + if (!strcmp(logfile, TMPLOG)) { + eerror("Cowardly refusing to concatenate a logfile into itself."); + eerrorx("Please change rc_log_path to something other than %s to get rid of this message", TMPLOG); + } + + if ((plog = fopen(logfile, "ae"))) { + if ((log = fopen(TMPLOG, "re"))) { + while ((bytes = fread(buffer, sizeof(*buffer), BUFSIZ, log)) > 0) { + if (fwrite(buffer, sizeof(*buffer), bytes, plog) < bytes) { + log_error = 1; + eerror("Error: write(%s) failed: %s", logfile, strerror(errno)); + break; + } + } + fclose(log); + } else { + log_error = 1; + eerror("Error: fopen(%s) failed: %s", TMPLOG, strerror(errno)); + } + + fclose(plog); + } else { + /* + * logfile or its basedir may be read-only during sysinit and + * shutdown so skip the error in this case + */ + if (errno != EROFS && ((strcmp(level, RC_LEVEL_SHUTDOWN) != 0) && (strcmp(level, RC_LEVEL_SYSINIT) != 0))) { + log_error = 1; + eerror("Error: fopen(%s) failed: %s", logfile, strerror(errno)); + } + } + + /* Try to keep the temporary log in case of errors */ + if (!log_error) { + if (errno != EROFS && ((strcmp(level, RC_LEVEL_SHUTDOWN) != 0) && (strcmp(level, RC_LEVEL_SYSINIT) != 0))) + if (unlink(TMPLOG) == -1) + eerror("Error: unlink(%s) failed: %s", TMPLOG, strerror(errno)); + } else if (exists(TMPLOG)) + eerrorx("Warning: temporary logfile left behind: %s", TMPLOG); + + exit(0); + /* NOTREACHED */ + + default: + setpgid(rc_logger_pid, 0); + fd_stdout = dup(STDOUT_FILENO); + fd_stderr = dup(STDERR_FILENO); + if ((s = fcntl(fd_stdout, F_GETFD, 0)) == 0) + fcntl(fd_stdout, F_SETFD, s | FD_CLOEXEC); + + if ((s = fcntl(fd_stderr, F_GETFD, 0)) == 0) + fcntl(fd_stderr, F_SETFD, s | FD_CLOEXEC); + dup2(slave_tty, STDOUT_FILENO); + dup2(slave_tty, STDERR_FILENO); + if (slave_tty != STDIN_FILENO && + slave_tty != STDOUT_FILENO && + slave_tty != STDERR_FILENO) + close(slave_tty); + close(signal_pipe[0]); + signal_pipe[0] = -1; + break; + } +} Index: contrib/openrc/src/rc/rc-misc.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-misc.c @@ -0,0 +1,518 @@ +/* + * rc-misc.c + * rc misc functions + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include + +#ifdef __linux__ +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "version.h" + +extern char **environ; + +bool +rc_conf_yesno(const char *setting) +{ + return rc_yesno(rc_conf_value (setting)); +} + +static const char *const env_whitelist[] = { + "EERROR_QUIET", "EINFO_QUIET", + "IN_BACKGROUND", "IN_HOTPLUG", + "LANG", "LC_MESSAGES", "TERM", + "EINFO_COLOR", "EINFO_VERBOSE", + NULL +}; + +void +env_filter(void) +{ + RC_STRINGLIST *env_allow; + RC_STRINGLIST *profile; + RC_STRINGLIST *env_list; + RC_STRING *env; + char *e; + size_t i = 0; + + /* Add the user defined list of vars */ + env_allow = rc_stringlist_split(rc_conf_value("rc_env_allow"), " "); + /* + * If '*' is an entry in rc_env_allow, do nothing as we are to pass + * through all environment variables. + */ + if (rc_stringlist_find(env_allow, "*")) + return; + profile = rc_config_load(RC_PROFILE_ENV); + + /* Copy the env and work from this so we can manipulate it safely */ + env_list = rc_stringlist_new(); + while (environ && environ[i]) { + env = rc_stringlist_add(env_list, environ[i++]); + e = strchr(env->value, '='); + if (e) + *e = '\0'; + } + + TAILQ_FOREACH(env, env_list, entries) { + /* Check the whitelist */ + for (i = 0; env_whitelist[i]; i++) { + if (strcmp(env_whitelist[i], env->value) == 0) + break; + } + if (env_whitelist[i]) + continue; + + /* Check our user defined list */ + if (rc_stringlist_find(env_allow, env->value)) + continue; + + /* OK, not allowed! */ + unsetenv(env->value); + } + + /* Now add anything missing from the profile */ + TAILQ_FOREACH(env, profile, entries) { + e = strchr(env->value, '='); + *e = '\0'; + if (!getenv(env->value)) + setenv(env->value, e + 1, 1); + } + + rc_stringlist_free(env_list); + rc_stringlist_free(env_allow); + rc_stringlist_free(profile); +} + +void +env_config(void) +{ + size_t pplen = strlen(RC_PATH_PREFIX); + char *path; + char *p; + char *e; + size_t l; + struct utsname uts; + FILE *fp; + char *token; + char *np; + char *npp; + char *tok; + const char *sys = rc_sys(); + char *buffer = NULL; + size_t size = 0; + + /* Ensure our PATH is prefixed with the system locations first + for a little extra security */ + path = getenv("PATH"); + if (! path) + setenv("PATH", RC_PATH_PREFIX, 1); + else if (strncmp (RC_PATH_PREFIX, path, pplen) != 0) { + l = strlen(path) + pplen + 3; + e = p = xmalloc(sizeof(char) * l); + p += snprintf(p, l, "%s", RC_PATH_PREFIX); + + /* Now go through the env var and only add bits not in our + * PREFIX */ + while ((token = strsep(&path, ":"))) { + np = npp = xstrdup(RC_PATH_PREFIX); + while ((tok = strsep(&npp, ":"))) + if (strcmp(tok, token) == 0) + break; + if (! tok) + p += snprintf(p, l - (p - e), ":%s", token); + free (np); + } + *p++ = '\0'; + unsetenv("PATH"); + setenv("PATH", e, 1); + free(e); + } + + setenv("RC_VERSION", VERSION, 1); + setenv("RC_LIBEXECDIR", RC_LIBEXECDIR, 1); + setenv("RC_SVCDIR", RC_SVCDIR, 1); + setenv("RC_TMPDIR", RC_SVCDIR "/tmp", 1); + setenv("RC_BOOTLEVEL", RC_LEVEL_BOOT, 1); + e = rc_runlevel_get(); + setenv("RC_RUNLEVEL", e, 1); + free(e); + + if ((fp = fopen(RC_KRUNLEVEL, "r"))) { + if (getline(&buffer, &size, fp) != -1) { + l = strlen (buffer) - 1; + if (buffer[l] == '\n') + buffer[l] = 0; + setenv("RC_DEFAULTLEVEL", buffer, 1); + } + fclose(fp); + } else + setenv("RC_DEFAULTLEVEL", RC_LEVEL_DEFAULT, 1); + + free(buffer); + if (sys) + setenv("RC_SYS", sys, 1); + +#ifdef PREFIX + setenv("RC_PREFIX", RC_PREFIX, 1); +#endif + + /* Some scripts may need to take a different code path if + Linux/FreeBSD, etc + To save on calling uname, we store it in an environment variable */ + if (uname(&uts) == 0) + setenv("RC_UNAME", uts.sysname, 1); + + /* Be quiet or verbose as necessary */ + if (rc_conf_yesno("rc_quiet")) + setenv("EINFO_QUIET", "YES", 1); + if (rc_conf_yesno("rc_verbose")) + setenv("EINFO_VERBOSE", "YES", 1); + + errno = 0; + if ((! rc_conf_yesno("rc_color") && errno == 0) || + rc_conf_yesno("rc_nocolor")) + setenv("EINFO_COLOR", "NO", 1); +} + +int +signal_setup(int sig, void (*handler)(int)) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof (sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = handler; + return sigaction(sig, &sa, NULL); +} + +int +signal_setup_restart(int sig, void (*handler)(int)) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof (sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = handler; + sa.sa_flags = SA_RESTART; + return sigaction(sig, &sa, NULL); +} + +int +svc_lock(const char *applet) +{ + char *file = NULL; + int fd; + + xasprintf(&file, RC_SVCDIR "/exclusive/%s", applet); + fd = open(file, O_WRONLY | O_CREAT | O_NONBLOCK, 0664); + free(file); + if (fd == -1) + return -1; + if (flock(fd, LOCK_EX | LOCK_NB) == -1) { + eerror("Call to flock failed: %s", strerror(errno)); + close(fd); + return -1; + } + return fd; +} + +int +svc_unlock(const char *applet, int fd) +{ + char *file = NULL; + + xasprintf(&file, RC_SVCDIR "/exclusive/%s", applet); + close(fd); + unlink(file); + free(file); + return -1; +} + +pid_t +exec_service(const char *service, const char *arg) +{ + char *file, sfd[32]; + int fd; + pid_t pid = -1; + sigset_t full; + sigset_t old; + struct sigaction sa; + + fd = svc_lock(basename_c(service)); + if (fd == -1) + return -1; + + file = rc_service_resolve(service); + if (!exists(file)) { + rc_service_mark(service, RC_SERVICE_STOPPED); + svc_unlock(basename_c(service), fd); + free(file); + return 0; + } + snprintf(sfd, sizeof(sfd), "%d", fd); + + /* We need to block signals until we have forked */ + memset(&sa, 0, sizeof (sa)); + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sigfillset(&full); + sigprocmask(SIG_SETMASK, &full, &old); + + if ((pid = fork()) == 0) { + /* Restore default handlers */ + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGWINCH, &sa, NULL); + + /* Unmask signals */ + sigprocmask(SIG_SETMASK, &old, NULL); + + /* Safe to run now */ + execl(file, file, "--lockfd", sfd, arg, (char *) NULL); + fprintf(stderr, "unable to exec `%s': %s\n", + file, strerror(errno)); + svc_unlock(basename_c(service), fd); + _exit(EXIT_FAILURE); + } + + if (pid == -1) { + fprintf(stderr, "fork: %s\n",strerror (errno)); + svc_unlock(basename_c(service), fd); + } else + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); + + sigprocmask(SIG_SETMASK, &old, NULL); + free(file); + return pid; +} + +int +parse_mode(mode_t *mode, char *text) +{ + char *p; + unsigned long l; + + /* Check for a numeric mode */ + if ((*text - '0') < 8) { + l = strtoul(text, &p, 8); + if (*p || l > 07777U) { + errno = EINVAL; + return -1; + } + *mode = (mode_t) l; + return 0; + } + + /* We currently don't check g+w type stuff */ + errno = EINVAL; + return -1; +} + +int +is_writable(const char *path) +{ + if (access(path, W_OK) == 0) + return 1; + + return 0; +} + +RC_DEPTREE * _rc_deptree_load(int force, int *regen) +{ + int fd; + int retval; + int serrno = errno; + int merrno; + time_t t; + char *file = NULL; + struct stat st; + struct utimbuf ut; + FILE *fp; + + t = 0; + if (rc_deptree_update_needed(&t, file) || force != 0) { + /* Test if we have permission to update the deptree */ + fd = open(RC_DEPTREE_CACHE, O_WRONLY); + merrno = errno; + errno = serrno; + if (fd == -1 && merrno == EACCES) + return rc_deptree_load(); + close(fd); + + if (regen) + *regen = 1; + ebegin("Caching service dependencies"); + retval = rc_deptree_update() ? 0 : -1; + eend (retval, "Failed to update the dependency tree"); + + if (retval == 0) { + if (stat(RC_DEPTREE_CACHE, &st) != 0) { + eerror("stat(%s): %s", RC_DEPTREE_CACHE, strerror(errno)); + return NULL; + } + if (st.st_mtime < t) { + eerror("Clock skew detected with `%s'", file); + eerrorn("Adjusting mtime of `" RC_DEPTREE_CACHE + "' to %s", ctime(&t)); + fp = fopen(RC_DEPTREE_SKEWED, "w"); + if (fp != NULL) { + fprintf(fp, "%s\n", file); + fclose(fp); + } + ut.actime = t; + ut.modtime = t; + utime(RC_DEPTREE_CACHE, &ut); + } else { + if (exists(RC_DEPTREE_SKEWED)) + unlink(RC_DEPTREE_SKEWED); + } + } + if (force == -1 && regen != NULL) + *regen = retval; + } + return rc_deptree_load(); +} + +bool _rc_can_find_pids(void) +{ + RC_PIDLIST *pids; + RC_PID *pid; + RC_PID *pid2; + bool retval = false; + + if (geteuid() == 0) + return true; + + /* If we cannot see process 1, then we don't test to see if + * services crashed or not */ + pids = rc_find_pids(NULL, NULL, 0, 1); + if (pids) { + pid = LIST_FIRST(pids); + if (pid) { + retval = true; + while (pid) { + pid2 = LIST_NEXT(pid, entries); + free(pid); + pid = pid2; + } + } + free(pids); + } + return retval; +} + +static const struct { + const char * const name; + RC_SERVICE bit; +} service_bits[] = { + { "service_started", RC_SERVICE_STARTED, }, + { "service_stopped", RC_SERVICE_STOPPED, }, + { "service_inactive", RC_SERVICE_INACTIVE, }, + { "service_starting", RC_SERVICE_STARTING, }, + { "service_stopping", RC_SERVICE_STOPPING, }, + { "service_hotplugged", RC_SERVICE_HOTPLUGGED, }, + { "service_wasinactive", RC_SERVICE_WASINACTIVE, }, + { "service_failed", RC_SERVICE_FAILED, }, +}; + +RC_SERVICE lookup_service_state(const char *service) +{ + size_t i; + for (i = 0; i < ARRAY_SIZE(service_bits); ++i) + if (!strcmp(service, service_bits[i].name)) + return service_bits[i].bit; + return 0; +} + +void from_time_t(char *time_string, time_t tv) +{ + strftime(time_string, 20, "%Y-%m-%d %H:%M:%S", localtime(&tv)); +} + +time_t to_time_t(char *timestring) +{ + int check = 0; + int year = 0; + int month = 0; + int day = 0; + int hour = 0; + int min = 0; + int sec = 0; + struct tm breakdown = {0}; + time_t result = -1; + + check = sscanf(timestring, "%4d-%2d-%2d %2d:%2d:%2d", + &year, &month, &day, &hour, &min, &sec); + if (check == 6) { + breakdown.tm_year = year - 1900; /* years since 1900 */ + breakdown.tm_mon = month - 1; + breakdown.tm_mday = day; + breakdown.tm_hour = hour; + breakdown.tm_min = min; + breakdown.tm_sec = sec; + breakdown.tm_isdst = -1; + result = mktime(&breakdown); + } + return result; +} + +pid_t get_pid(const char *applet,const char *pidfile) +{ + FILE *fp; + pid_t pid; + + if (! pidfile) + return -1; + + if ((fp = fopen(pidfile, "r")) == NULL) { + ewarnv("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); + return -1; + } + + if (fscanf(fp, "%d", &pid) != 1) { + ewarnv("%s: no pid found in `%s'", applet, pidfile); + fclose(fp); + return -1; + } + + fclose(fp); + + return pid; +} Index: contrib/openrc/src/rc/rc-plugin.h =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-plugin.h @@ -0,0 +1,41 @@ +/* + * rc-plugin.h + * Private instructions to use plugins + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __LIBRC_PLUGIN_H__ +#define __LIBRC_PLUGIN_H__ + +/* A simple flag to say if we're in a plugin proccess or not. + * Mainly used in atexit code. */ +extern bool rc_in_plugin; + +int rc_waitpid(pid_t pid); +void rc_plugin_load(void); +void rc_plugin_unload(void); +void rc_plugin_run(RC_HOOK, const char *value); + +/* dlfunc defines needed to avoid ISO errors. FreeBSD has this right :) */ +#if !defined(__FreeBSD__) && !defined(__DragonFly__) +struct __dlfunc_arg { + int __dlfunc_dummy; +}; + +typedef void (*dlfunc_t)(struct __dlfunc_arg); + +dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol); +#endif + +#endif Index: contrib/openrc/src/rc/rc-plugin.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-plugin.c @@ -0,0 +1,245 @@ +/* + * rc-plugin.c + * Simple plugin handler + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "rc-plugin.h" + +#define RC_PLUGIN_HOOK "rc_plugin_hook" + +bool rc_in_plugin = false; + +typedef struct plugin +{ + char *name; + void *handle; + int (*hook)(RC_HOOK, const char *); + TAILQ_ENTRY(plugin) entries; +} PLUGIN; +TAILQ_HEAD(, plugin) plugins; + +#ifndef __FreeBSD__ +dlfunc_t +dlfunc(void * __restrict handle, const char * __restrict symbol) +{ + union { + void *d; + dlfunc_t f; + } rv; + + rv.d = dlsym(handle, symbol); + return rv.f; +} +#endif + +void +rc_plugin_load(void) +{ + DIR *dp; + struct dirent *d; + PLUGIN *plugin; + char *file = NULL; + void *h; + int (*fptr)(RC_HOOK, const char *); + + /* Don't load plugins if we're in one */ + if (rc_in_plugin) + return; + + TAILQ_INIT(&plugins); + + if (!(dp = opendir(RC_PLUGINDIR))) + return; + + while ((d = readdir(dp))) { + if (d->d_name[0] == '.') + continue; + + xasprintf(&file, RC_PLUGINDIR "/%s", d->d_name); + h = dlopen(file, RTLD_LAZY); + free(file); + if (h == NULL) { + eerror("dlopen: %s", dlerror()); + continue; + } + + fptr = (int (*)(RC_HOOK, const char *)) + dlfunc(h, RC_PLUGIN_HOOK); + if (fptr == NULL) { + eerror("%s: cannot find symbol `%s'", + d->d_name, RC_PLUGIN_HOOK); + dlclose(h); + } else { + plugin = xmalloc(sizeof(*plugin)); + plugin->name = xstrdup(d->d_name); + plugin->handle = h; + plugin->hook = fptr; + TAILQ_INSERT_TAIL(&plugins, plugin, entries); + } + } + closedir(dp); +} + +int +rc_waitpid(pid_t pid) +{ + int status; + + while (waitpid(pid, &status, 0) == -1) { + if (errno != EINTR) { + status = -1; + break; + } + } + return status; +} + +void +rc_plugin_run(RC_HOOK hook, const char *value) +{ + PLUGIN *plugin; + struct sigaction sa; + sigset_t empty; + sigset_t full; + sigset_t old; + int i; + int flags; + int pfd[2]; + pid_t pid; + char *buffer; + char *token; + char *p; + ssize_t nr; + int retval; + + /* Don't run plugins if we're in one */ + if (rc_in_plugin) + return; + + /* We need to block signals until we have forked */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sigemptyset(&empty); + sigfillset(&full); + + TAILQ_FOREACH(plugin, &plugins, entries) { + /* We create a pipe so that plugins can affect our environment + * vars, which in turn influence our scripts. */ + if (pipe(pfd) == -1) { + eerror("pipe: %s", strerror(errno)); + return; + } + + /* Stop any scripts from inheriting us. + * This is actually quite important as without this, the splash + * plugin will probably hang when running in silent mode. */ + for (i = 0; i < 2; i++) + if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 || + fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0) + eerror("fcntl: %s", strerror(errno)); + + sigprocmask(SIG_SETMASK, &full, &old); + + /* We run the plugin in a new process so we never crash + * or otherwise affected by it */ + if ((pid = fork()) == -1) { + eerror("fork: %s", strerror(errno)); + break; + } + + if (pid == 0) { + /* Restore default handlers */ + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGWINCH, &sa, NULL); + sigprocmask(SIG_SETMASK, &old, NULL); + + rc_in_plugin = true; + close(pfd[0]); + rc_environ_fd = fdopen(pfd[1], "w"); + retval = plugin->hook(hook, value); + fclose(rc_environ_fd); + rc_environ_fd = NULL; + + /* Just in case the plugin sets this to false */ + rc_in_plugin = true; + exit(retval); + } + + sigprocmask(SIG_SETMASK, &old, NULL); + close(pfd[1]); + buffer = xmalloc(sizeof(char) * BUFSIZ); + memset(buffer, 0, BUFSIZ); + + while ((nr = read(pfd[0], buffer, BUFSIZ)) > 0) { + p = buffer; + while (*p && p - buffer < nr) { + token = strsep(&p, "="); + if (token) { + unsetenv(token); + if (*p) { + setenv(token, p, 1); + p += strlen(p) + 1; + } else + p++; + } + } + } + + free(buffer); + close(pfd[0]); + + rc_waitpid(pid); + } +} + +void +rc_plugin_unload(void) +{ + PLUGIN *plugin = TAILQ_FIRST(&plugins); + PLUGIN *next; + + while (plugin) { + next = TAILQ_NEXT(plugin, entries); + dlclose(plugin->handle); + free(plugin->name); + free(plugin); + plugin = next; + } + TAILQ_INIT(&plugins); +} Index: contrib/openrc/src/rc/rc-schedules.h =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-schedules.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __RC_SCHEDULES_H +#define __RC_SCHEDULES_H + +void free_schedulelist(void); +int parse_signal(const char *applet, const char *sig); +void parse_schedule(const char *applet, const char *string, int timeout); +int do_stop(const char *applet, const char *exec, const char *const *argv, + pid_t pid, uid_t uid,int sig, bool test, bool quiet); +int run_stop_schedule(const char *applet, + const char *exec, const char *const *argv, + pid_t pid, uid_t uid, + bool test, bool progress, bool quiet); + +#endif Index: contrib/openrc/src/rc/rc-schedules.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-schedules.c @@ -0,0 +1,422 @@ +/* + * The functions in this file control the stopping of daemons by + * start-stop-daemon and supervise-daemon. + */ + +/* + * Copyright (c) 2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +/* nano seconds */ +#define POLL_INTERVAL 20000000 +#define WAIT_PIDFILE 500000000 +#define ONE_SECOND 1000000000 +#define ONE_MS 1000000 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "rc-schedules.h" +#include "helpers.h" + +typedef struct scheduleitem { + enum { + SC_TIMEOUT, + SC_SIGNAL, + SC_GOTO, + SC_FOREVER, + } type; + int value; + struct scheduleitem *gotoitem; + TAILQ_ENTRY(scheduleitem) entries; +} SCHEDULEITEM; + +static TAILQ_HEAD(, scheduleitem) schedule; + +void free_schedulelist(void) +{ + SCHEDULEITEM *s1 = TAILQ_FIRST(&schedule); + SCHEDULEITEM *s2; + + while (s1) { + s2 = TAILQ_NEXT(s1, entries); + free(s1); + s1 = s2; + } + TAILQ_INIT(&schedule); +} + +int parse_signal(const char *applet, const char *sig) +{ + typedef struct signalpair + { + const char *name; + int signal; + } SIGNALPAIR; + +#define signalpair_item(name) { #name, SIG##name }, + + static const SIGNALPAIR signallist[] = { + signalpair_item(HUP) + signalpair_item(INT) + signalpair_item(QUIT) + signalpair_item(ILL) + signalpair_item(TRAP) + signalpair_item(ABRT) + signalpair_item(BUS) + signalpair_item(FPE) + signalpair_item(KILL) + signalpair_item(USR1) + signalpair_item(SEGV) + signalpair_item(USR2) + signalpair_item(PIPE) + signalpair_item(ALRM) + signalpair_item(TERM) + signalpair_item(CHLD) + signalpair_item(CONT) + signalpair_item(STOP) + signalpair_item(TSTP) + signalpair_item(TTIN) + signalpair_item(TTOU) + signalpair_item(URG) + signalpair_item(XCPU) + signalpair_item(XFSZ) + signalpair_item(VTALRM) + signalpair_item(PROF) +#ifdef SIGWINCH + signalpair_item(WINCH) +#endif +#ifdef SIGIO + signalpair_item(IO) +#endif +#ifdef SIGPWR + signalpair_item(PWR) +#endif + signalpair_item(SYS) + { "NULL", 0 }, + }; + + unsigned int i = 0; + const char *s; + + if (!sig || *sig == '\0') + return -1; + + if (sscanf(sig, "%u", &i) == 1) { + if (i < NSIG) + return i; + eerrorx("%s: `%s' is not a valid signal", applet, sig); + } + + if (strncmp(sig, "SIG", 3) == 0) + s = sig + 3; + else + s = NULL; + + for (i = 0; i < ARRAY_SIZE(signallist); ++i) + if (strcmp(sig, signallist[i].name) == 0 || + (s && strcmp(s, signallist[i].name) == 0)) + return signallist[i].signal; + + eerrorx("%s: `%s' is not a valid signal", applet, sig); + /* NOTREACHED */ +} + +static SCHEDULEITEM *parse_schedule_item(const char *applet, const char *string) +{ + const char *after_hyph; + int sig; + SCHEDULEITEM *item = xmalloc(sizeof(*item)); + + item->value = 0; + item->gotoitem = NULL; + if (strcmp(string,"forever") == 0) + item->type = SC_FOREVER; + else if (isdigit((unsigned char)string[0])) { + item->type = SC_TIMEOUT; + errno = 0; + if (sscanf(string, "%d", &item->value) != 1) + eerrorx("%s: invalid timeout value in schedule `%s'", + applet, string); + } else if ((after_hyph = string + (string[0] == '-')) && + ((sig = parse_signal(applet, after_hyph)) != -1)) + { + item->type = SC_SIGNAL; + item->value = (int)sig; + } else + eerrorx("%s: invalid schedule item `%s'", applet, string); + + return item; +} + +void parse_schedule(const char *applet, const char *string, int timeout) +{ + char buffer[20]; + const char *slash; + int count = 0; + SCHEDULEITEM *repeatat = NULL; + size_t len; + SCHEDULEITEM *item; + + TAILQ_INIT(&schedule); + if (string) + for (slash = string; *slash; slash++) + if (*slash == '/') + count++; + + free_schedulelist(); + + if (count == 0) { + item = xmalloc(sizeof(*item)); + item->type = SC_SIGNAL; + item->value = timeout; + item->gotoitem = NULL; + TAILQ_INSERT_TAIL(&schedule, item, entries); + + item = xmalloc(sizeof(*item)); + item->type = SC_TIMEOUT; + item->gotoitem = NULL; + TAILQ_INSERT_TAIL(&schedule, item, entries); + if (string) { + if (sscanf(string, "%d", &item->value) != 1) + eerrorx("%s: invalid timeout in schedule", + applet); + } else + item->value = 5; + + return; + } + + while (string != NULL) { + if ((slash = strchr(string, '/'))) + len = slash - string; + else + len = strlen(string); + + if (len >= (ptrdiff_t)sizeof(buffer)) + eerrorx("%s: invalid schedule item, far too long", + applet); + + memcpy(buffer, string, len); + buffer[len] = 0; + string = slash ? slash + 1 : NULL; + + item = parse_schedule_item(applet, buffer); + TAILQ_INSERT_TAIL(&schedule, item, entries); + if (item->type == SC_FOREVER) { + if (repeatat) + eerrorx("%s: invalid schedule, `forever' " + "appears more than once", applet); + + repeatat = item; + continue; + } + } + + if (repeatat) { + item = xmalloc(sizeof(*item)); + item->type = SC_GOTO; + item->value = 0; + item->gotoitem = repeatat; + TAILQ_INSERT_TAIL(&schedule, item, entries); + } + + return; +} + +/* return number of processes killed, -1 on error */ +int do_stop(const char *applet, const char *exec, const char *const *argv, + pid_t pid, uid_t uid,int sig, bool test, bool quiet) +{ + RC_PIDLIST *pids; + RC_PID *pi; + RC_PID *np; + bool killed; + int nkilled = 0; + + if (pid > 0) + pids = rc_find_pids(NULL, NULL, 0, pid); + else + pids = rc_find_pids(exec, argv, uid, 0); + + if (!pids) + return 0; + + LIST_FOREACH_SAFE(pi, pids, entries, np) { + if (test) { + einfo("Would send signal %d to PID %d", sig, pi->pid); + nkilled++; + } else { + if (!quiet) + ebeginv("Sending signal %d to PID %d", sig, pi->pid); + errno = 0; + killed = (kill(pi->pid, sig) == 0 || + errno == ESRCH ? true : false); + if (! quiet) + eendv(killed ? 0 : 1, + "%s: failed to send signal %d to PID %d: %s", + applet, sig, pi->pid, strerror(errno)); + if (!killed) { + nkilled = -1; + } else { + if (nkilled != -1) + nkilled++; + } + } + free(pi); + } + + free(pids); + return nkilled; +} + +int run_stop_schedule(const char *applet, + const char *exec, const char *const *argv, + pid_t pid, uid_t uid, + bool test, bool progress, bool quiet) +{ + SCHEDULEITEM *item = TAILQ_FIRST(&schedule); + int nkilled = 0; + int tkilled = 0; + int nrunning = 0; + long nloops, nsecs; + struct timespec ts; + const char *const *p; + bool progressed = false; + + if (!(pid > 0 || exec || uid || (argv && *argv))) + return 0; + + if (exec) + einfov("Will stop %s", exec); + if (pid > 0) + einfov("Will stop PID %d", pid); + if (uid) + einfov("Will stop processes owned by UID %d", uid); + if (argv && *argv) { + einfovn("Will stop processes of `"); + if (rc_yesno(getenv("EINFO_VERBOSE"))) { + for (p = argv; p && *p; p++) { + if (p != argv) + printf(" "); + printf("%s", *p); + } + printf("'\n"); + } + } + + while (item) { + switch (item->type) { + case SC_GOTO: + item = item->gotoitem; + continue; + + case SC_SIGNAL: + nrunning = 0; + nkilled = do_stop(applet, exec, argv, pid, uid, item->value, test, + quiet); + if (nkilled == 0) { + if (tkilled == 0) { + if (progressed) + printf("\n"); + eerror("%s: no matching processes found", applet); + } + return tkilled; + } + else if (nkilled == -1) + return 0; + + tkilled += nkilled; + break; + case SC_TIMEOUT: + if (item->value < 1) { + item = NULL; + break; + } + + ts.tv_sec = 0; + ts.tv_nsec = POLL_INTERVAL; + + for (nsecs = 0; nsecs < item->value; nsecs++) { + for (nloops = 0; + nloops < ONE_SECOND / POLL_INTERVAL; + nloops++) + { + if ((nrunning = do_stop(applet, exec, argv, + pid, uid, 0, test, quiet)) == 0) + return 0; + + + if (nanosleep(&ts, NULL) == -1) { + if (progressed) { + printf("\n"); + progressed = false; + } + if (errno == EINTR) + eerror("%s: caught an" + " interrupt", applet); + else { + eerror("%s: nanosleep: %s", + applet, strerror(errno)); + return 0; + } + } + } + if (progress) { + printf("."); + fflush(stdout); + progressed = true; + } + } + break; + default: + if (progressed) { + printf("\n"); + progressed = false; + } + eerror("%s: invalid schedule item `%d'", + applet, item->type); + return 0; + } + + if (item) + item = TAILQ_NEXT(item, entries); + } + + if (test || (tkilled > 0 && nrunning == 0)) + return nkilled; + + if (progressed) + printf("\n"); + if (! quiet) { + if (nrunning == 1) + eerror("%s: %d process refused to stop", applet, nrunning); + else + eerror("%s: %d process(es) refused to stop", applet, nrunning); + } + + return -nrunning; +} Index: contrib/openrc/src/rc/rc-selinux.h =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-selinux.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef RC_SELINUX_UTIL_H +#define RC_SELINUX_UTIL_H + +#ifdef HAVE_SELINUX + +int selinux_util_open(void); +int selinux_util_label(const char *path); +int selinux_util_close(void); + +void selinux_setup(char **argv); + +#else + +/* always return false for selinux_util_open() */ +#define selinux_util_open() (0) +#define selinux_util_label(x) do { } while (0) +#define selinux_util_close() do { } while (0) + +#define selinux_setup(x) do { } while (0) + +#endif + + +#endif Index: contrib/openrc/src/rc/rc-selinux.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-selinux.c @@ -0,0 +1,417 @@ +/* + * rc-selinux.c + * SELinux helpers to get and set contexts. + */ + +/* + * Copyright (c) 2014-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "rc-plugin.h" +#include "rc-selinux.h" + +/* the context files for selinux */ +#define INITRC_FILE "initrc_context" + +#ifdef HAVE_AUDIT +#include +#endif + +/* PAM or shadow for authentication */ +#ifdef HAVE_PAM +# define PAM_SERVICE_NAME "run_init" /* the name of this program for PAM */ +# include +# include +#else +# define PASSWORD_PROMPT "Password:" +# include +# include +# include +#endif + + +/* The handle for the fcontext lookups */ +static struct selabel_handle *hnd = NULL; + +int selinux_util_label(const char *path) +{ + int retval = 0; + int enforce; + struct stat st; + security_context_t con; + + enforce = security_getenforce(); + if (retval < 0) + return retval; + + if (!hnd) + return (enforce) ? -1 : 0; + + retval = lstat(path, &st); + if (retval < 0) { + if (errno == ENOENT) + return 0; + return (enforce) ? -1 : 0; + } + + /* lookup the context */ + retval = selabel_lookup_raw(hnd, &con, path, st.st_mode); + if (retval < 0) { + if (errno == ENOENT) + return 0; + return (enforce) ? -1 : 0; + } + + /* apply the context */ + retval = lsetfilecon(path, con); + freecon(con); + if (retval < 0) { + if (errno == ENOENT) + return 0; + if (errno == ENOTSUP) + return 0; + return (enforce) ? -1 : 0; + } + + return 0; +} + +/* + * Open the label handle + * returns 1 on success, 0 if no selinux, negative on error + */ +int selinux_util_open(void) +{ + int retval = 0; + + retval = is_selinux_enabled(); + if (retval <= 0) + return retval; + + hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + if (!hnd) + return -2; + + return 1; +} + +/* + * Close the label handle + * returns 1 on success, 0 if no selinux, negative on error + */ +int selinux_util_close(void) +{ + int retval = 0; + + retval = is_selinux_enabled(); + if (retval <= 0) + return retval; + + if (hnd) { + selabel_close(hnd); + hnd = NULL; + } + + return 0; +} + +/* + * This will check the users password and return 0 on success or -1 on fail + * + * We ask for the password to make sure it is intended vs run by malicious software. + * Actual authorization is covered by the policy itself. + */ +static int check_password(char *username) +{ + int ret = 1; +#ifdef HAVE_PAM + pam_handle_t *pamh; + int pam_err = 0; + const struct pam_conv pconv = { + misc_conv, + NULL + }; + + pam_err = pam_start(PAM_SERVICE_NAME, username, &pconv, &pamh); + if (pam_err != PAM_SUCCESS) { + ret = -1; + goto outpam; + } + + pam_err = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK); + if (pam_err != PAM_SUCCESS) { + ret = -1; + goto outpam; + } + + ret = 0; +outpam: + pam_end(pamh, pam_err); + pamh = NULL; + +#else /* authenticating via /etc/shadow instead */ + struct spwd *spw; + char *password; + char *attempt; + + spw = getspnam(username); + if (!spw) { + eerror("Failed to read shadow entry"); + ret = -1; + goto outshadow; + } + + attempt = getpass(PASSWORD_PROMPT); + if (!attempt) { + ret = -1; + goto outshadow; + } + + if (*spw->sp_pwdp == '\0' && *attempt == '\0') { + ret = -1; + goto outshadow; + } + + /* salt must be at least two characters long */ + if (!(spw->sp_pwdp[0] && spw->sp_pwdp[1])) { + ret = -1; + goto outshadow; + } + + /* encrypt the password attempt */ + password = crypt(attempt, spw->sp_pwdp); + + if (password && strcmp(password, spw->sp_pwdp) == 0) + ret = 0; + else + ret = -1; +outshadow: +#endif + return ret; +} + +/* Authenticates the user, returns 0 on success, 1 on fail */ +static int check_auth() +{ + struct passwd *pw; + uid_t uid; + +#ifdef HAVE_AUDIT + uid = audit_getloginuid(); + if (uid == (uid_t) -1) + uid = getuid(); +#else + uid = getuid(); +#endif + + pw = getpwuid(uid); + if (!pw) { + eerror("cannot find your entry in the passwd file."); + return (-1); + } + + printf("Authenticating %s.\n", pw->pw_name); + + /* do the actual check */ + if (check_password(pw->pw_name) == 0) { + return 0; + } + + eerrorx("Authentication failed for %s", pw->pw_name); + return 1; +} + +/* + * Read the context from the given context file. context must be free'd by the user. + */ +static int read_context_file(const char *filename, char **context) +{ + int ret = -1; + FILE *fp; + char *filepath = NULL; + char *line = NULL; + char *p; + char *p2; + size_t len = 0; + ssize_t read; + + xasprintf(&filepath, "%s/%s", selinux_contexts_path(), filename); + + fp = fopen(filepath, "r"); + if (fp == NULL) { + eerror("Failed to open context file: %s", filename); + free(filepath); + return -1; + } + + while ((read = getline(&line, &len, fp)) != -1) { + /* cut off spaces before the string */ + p = line; + while (isspace(*p) && *p != '\0') + p++; + + /* empty string, skip */ + if (*p == '\0') + continue; + + /* cut off spaces after the string */ + p2 = p; + while (!isspace(*p2) && *p2 != '\0') + p2++; + *p2 = '\0'; + + *context = xstrdup(p); + ret = 0; + break; + } + + free(line); + free(filepath); + fclose(fp); + return ret; +} + +static int read_run_init_context(char **context) +{ + int ret = -1; + RC_STRINGLIST *list; + char *value = NULL; + + list = rc_config_list(selinux_openrc_contexts_path()); + if (list == NULL) + return ret; + + value = rc_config_value(list, "run_init"); + if (value != NULL && strlen(value) > 0) { + *context = xstrdup(value); + ret = 0; + } + + rc_stringlist_free(list); + return ret; +} + +void selinux_setup(char **argv) +{ + char *new_context = NULL; + char *curr_context = NULL; + context_t curr_con; + char *curr_t = NULL; + char *run_init_t = NULL; + + /* Return, if selinux is disabled. */ + if (is_selinux_enabled() < 1) { + return; + } + + if (read_run_init_context(&run_init_t) != 0) { + /* assume a reasonable default, rather than bailing out */ + run_init_t = xstrdup("run_init_t"); + ewarn("Assuming SELinux run_init type is %s", run_init_t); + } + + /* Get our current context. */ + if (getcon(&curr_context) < 0) { + if (errno == ENOENT) { + /* should only hit this if proc is not mounted. this + * happens on Gentoo right after init starts, when + * the init script processing starts. + */ + goto out; + } else { + perror("getcon"); + exit(1); + } + } + + /* extract the type from the context */ + curr_con = context_new(curr_context); + if (!curr_con) { + free(curr_context); + goto out; + } + + curr_t = xstrdup(context_type_get(curr_con)); + if (!curr_t) { + context_free(curr_con); + free(curr_context); + goto out; + } + + /* dont need them anymore so free() now */ + context_free(curr_con); + free(curr_context); + + /* if we are not in the run_init domain, we should not do anything */ + if (strncmp(run_init_t, curr_t, strlen(run_init_t)) != 0) { + goto out; + } + + free(curr_t); + free(run_init_t); + + if (check_auth() != 0) { + eerrorx("Authentication failed."); + } + + /* Get the context for the script to be run in. */ + if (read_context_file(INITRC_FILE, &new_context) != 0) { + /* assume a reasonable default, rather than bailing out */ + new_context = xstrdup("system_u:system_r:initrc_t"); + ewarn("Assuming SELinux initrc context is %s", new_context); + } + + /* Set the new context */ + if (setexeccon(new_context) < 0) { + eerrorx("Could not set SELinux exec context to %s.", new_context); + } + + free(new_context); + + /* + * exec will recycle ptys so try and use open_init_pty if it exists + * which will open the pty with initrc_devpts_t, if it doesnt exist, + * fall back to plain exec + */ + if (!access("/usr/sbin/open_init_pty", X_OK)) { + if (execvp("/usr/sbin/open_init_pty", argv)) { + perror("execvp"); + exit(-1); + } + } else if (execvp(argv[1], argv + 1)) { + perror("execvp"); + exit(-1); + } + +out: + free(run_init_t); + free(curr_t); +} Index: contrib/openrc/src/rc/rc-service.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-service.c @@ -0,0 +1,144 @@ +/* + * rc-service.c + * Finds all OpenRC services + */ + +/* + * Copyright (c) 2008-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "ce:ilr:IN" getoptstring_COMMON; +const struct option longopts[] = { + { "exists", 1, NULL, 'e' }, + { "ifcrashed", 0, NULL, 'c' }, + { "ifexists", 0, NULL, 'i' }, + { "ifinactive", 0, NULL, 'I' }, + { "ifnotstarted", 0, NULL, 'N' }, + { "list", 0, NULL, 'l' }, + { "resolve", 1, NULL, 'r' }, + longopts_COMMON +}; +const char * const longopts_help[] = { + "tests if the service exists or not", + "if the service is crashed then run the command", + "if the service exists then run the command", + "if the service is inactive then run the command", + "if the service is not started then run the command", + "list all available services", + "resolve the service name to an init script", + longopts_help_COMMON +}; +const char *usagestring = "" \ + "Usage: rc-service [options] [-i] ...\n" \ + " or: rc-service [options] -e \n" \ + " or: rc-service [options] -l\n" \ + " or: rc-service [options] -r "; + +int main(int argc, char **argv) +{ + int opt; + char *service; + RC_STRINGLIST *list; + RC_STRING *s; + RC_SERVICE state; + bool if_crashed = false; + bool if_exists = false; + bool if_inactive = false; + bool if_notstarted = false; + + applet = basename_c(argv[0]); + /* Ensure that we are only quiet when explicitly told to be */ + unsetenv("EINFO_QUIET"); + + // Check if openrc sysinit has run (fixes jails) + if(!exists("/libexec/rc/init.d/started")) + system("openrc sysinit"); + + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'e': + service = rc_service_resolve(optarg); + opt = service ? EXIT_SUCCESS : EXIT_FAILURE; + free(service); + return opt; + /* NOTREACHED */ + case 'c': + if_crashed = true; + break; + case 'i': + if_exists = true; + break; + case 'I': + if_inactive = true; + break; + case 'N': + if_notstarted = true; + break; + case 'l': + list = rc_services_in_runlevel(NULL); + if (TAILQ_FIRST(list) == NULL) + return EXIT_FAILURE; + rc_stringlist_sort(&list); + TAILQ_FOREACH(s, list, entries) + printf("%s\n", s->value); + rc_stringlist_free(list); + return EXIT_SUCCESS; + /* NOTREACHED */ + case 'r': + service = rc_service_resolve(optarg); + if (service == NULL) + return EXIT_FAILURE; + printf("%s\n", service); + free(service); + return EXIT_SUCCESS; + /* NOTREACHED */ + + case_RC_COMMON_GETOPT + } + } + + argc -= optind; + argv += optind; + if (*argv == NULL) + eerrorx("%s: you need to specify a service", applet); + if ((service = rc_service_resolve(*argv)) == NULL) { + if (if_exists) + return 0; + eerrorx("%s: service `%s' does not exist", applet, *argv); + } + state = rc_service_state(*argv); + if (if_crashed && ! (rc_service_daemons_crashed(*argv) && errno != EACCES)) + return 0; + if (if_inactive && ! (state & RC_SERVICE_INACTIVE)) + return 0; + if (if_notstarted && (state & RC_SERVICE_STARTED)) + return 0; + *argv = service; + execv(*argv, argv); + eerrorx("%s: %s", applet, strerror(errno)); + /* NOTREACHED */ +} Index: contrib/openrc/src/rc/rc-status.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-status.c @@ -0,0 +1,425 @@ +/* + * rc-status.c + * Display the status of the services in runlevels + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "aclmrsu" getoptstring_COMMON; +const struct option longopts[] = { + {"all", 0, NULL, 'a'}, + {"crashed", 0, NULL, 'c'}, + {"list", 0, NULL, 'l'}, + {"manual", 0, NULL, 'm'}, + {"runlevel", 0, NULL, 'r'}, + {"servicelist", 0, NULL, 's'}, + {"unused", 0, NULL, 'u'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Show services from all run levels", + "Show crashed services", + "Show list of run levels", + "Show manually started services", + "Show the name of the current runlevel", + "Show service list", + "Show services not assigned to any runlevel", + longopts_help_COMMON +}; +const char *usagestring = "" \ + "Usage: rc-status [options] ...\n" \ + " or: rc-status [options] [-a | -c | -l | -m | -r | -s | -u]"; + +static bool test_crashed = false; +static RC_DEPTREE *deptree; +static RC_STRINGLIST *types; + +static RC_STRINGLIST *levels, *services, *tmp, *alist; +static RC_STRINGLIST *sservices, *nservices, *needsme; + +static void +print_level(const char *prefix, const char *level) +{ + if (prefix) + printf("%s ", prefix); + printf ("Runlevel: "); + if (isatty(fileno(stdout))) + printf("%s%s%s\n", + ecolor(ECOLOR_HILITE), + level, + ecolor(ECOLOR_NORMAL)); + else + printf("%s\n", level); +} + +static void get_uptime(const char *service, char *uptime, int uptime_size) +{ + RC_SERVICE state = rc_service_state(service); + char *start_count; + time_t now; + char *start_time_string; + time_t start_time; + time_t time_diff; + time_t diff_days = (time_t) 0; + time_t diff_hours = (time_t) 0; + time_t diff_mins = (time_t) 0; + time_t diff_secs = (time_t) 0; + + uptime[0] = '\0'; + if (state & RC_SERVICE_STARTED) { + start_count = rc_service_value_get(service, "start_count"); + start_time_string = rc_service_value_get(service, "start_time"); + if (start_count && start_time_string) { + start_time = to_time_t(start_time_string); + now = time(NULL); + time_diff = (time_t) difftime(now, start_time); + diff_secs = time_diff; + if (diff_secs > (time_t) 86400) { + diff_days = diff_secs / (time_t) 86400; + diff_secs %= diff_days * (time_t) 86400; + } + if (diff_secs > (time_t) 3600) { + diff_hours = diff_secs / (time_t) 3600; + diff_secs %= diff_hours * (time_t) 3600; + } + if (diff_secs > (time_t) 60) { + diff_mins = diff_secs / (time_t) 60; + diff_secs %= diff_mins * (time_t) 60; + } + if (diff_days > 0) + snprintf(uptime, uptime_size, + "%ld day(s) %02ld:%02ld:%02ld (%s)", + diff_days, diff_hours, diff_mins, diff_secs, + start_count); + else + snprintf(uptime, uptime_size, + "%02ld:%02ld:%02ld (%s)", + diff_hours, diff_mins, diff_secs, start_count); + } + } +} + +static void +print_service(const char *service) +{ + char status[60]; + char uptime [40]; + char *child_pid = NULL; + char *start_time = NULL; + int cols = printf(" %s", service); + const char *c = ecolor(ECOLOR_GOOD); + RC_SERVICE state = rc_service_state(service); + ECOLOR color = ECOLOR_BAD; + + if (state & RC_SERVICE_STOPPING) + snprintf(status, sizeof(status), "stopping "); + else if (state & RC_SERVICE_STARTING) { + snprintf(status, sizeof(status), "starting "); + color = ECOLOR_WARN; + } else if (state & RC_SERVICE_INACTIVE) { + snprintf(status, sizeof(status), "inactive "); + color = ECOLOR_WARN; + } else if (state & RC_SERVICE_STARTED) { + errno = 0; + if (test_crashed && + rc_service_daemons_crashed(service) && + errno != EACCES) + { + child_pid = rc_service_value_get(service, "child_pid"); + start_time = rc_service_value_get(service, "start_time"); + if (start_time && child_pid) + snprintf(status, sizeof(status), " unsupervised "); + else + snprintf(status, sizeof(status), " crashed "); + free(child_pid); + free(start_time); + } else { + get_uptime(service, uptime, 40); + snprintf(status, sizeof(status), " started %s", uptime); + color = ECOLOR_GOOD; + } + } else if (state & RC_SERVICE_SCHEDULED) { + snprintf(status, sizeof(status), "scheduled"); + color = ECOLOR_WARN; + } else + snprintf(status, sizeof(status), " stopped "); + + errno = 0; + if (c && *c && isatty(fileno(stdout))) + printf("\n"); + ebracket(cols, color, status); +} + +static void +print_services(const char *runlevel, RC_STRINGLIST *svcs) +{ + RC_STRINGLIST *l = NULL; + RC_STRING *s; + char *r = NULL; + + if (!svcs) + return; + if (!deptree) + deptree = _rc_deptree_load(0, NULL); + if (!deptree) { + TAILQ_FOREACH(s, svcs, entries) + if (!runlevel || + rc_service_in_runlevel(s->value, runlevel)) + print_service(s->value); + return; + } + if (!types) { + types = rc_stringlist_new(); + rc_stringlist_add(types, "ineed"); + rc_stringlist_add(types, "iuse"); + rc_stringlist_add(types, "iafter"); + } + if (!runlevel) + r = rc_runlevel_get(); + l = rc_deptree_depends(deptree, types, svcs, r ? r : runlevel, + RC_DEP_STRICT | RC_DEP_TRACE | RC_DEP_START); + free(r); + if (!l) + return; + TAILQ_FOREACH(s, l, entries) { + if (!rc_stringlist_find(svcs, s->value)) + continue; + if (!runlevel || rc_service_in_runlevel(s->value, runlevel)) + print_service(s->value); + } + rc_stringlist_free(l); +} + +static void +print_stacked_services(const char *runlevel) +{ + RC_STRINGLIST *stackedlevels, *servicelist; + RC_STRING *stackedlevel; + + stackedlevels = rc_runlevel_stacks(runlevel); + TAILQ_FOREACH(stackedlevel, stackedlevels, entries) { + if (rc_stringlist_find(levels, stackedlevel->value) != NULL) + continue; + print_level("Stacked", stackedlevel->value); + servicelist = rc_services_in_runlevel(stackedlevel->value); + print_services(stackedlevel->value, servicelist); + rc_stringlist_free(servicelist); + } + rc_stringlist_free(stackedlevels); + stackedlevels = NULL; +} + +int main(int argc, char **argv) +{ + RC_STRING *s, *l, *t, *level; + bool show_all = false; + char *p, *runlevel = NULL; + int opt, retval = 0; + + test_crashed = _rc_can_find_pids(); + + applet = basename_c(argv[0]); + while ((opt = getopt_long(argc, argv, getoptstring, longopts, + (int *) 0)) != -1) + switch (opt) { + case 'a': + show_all = true; + levels = rc_runlevel_list(); + break; + case 'c': + services = rc_services_in_state(RC_SERVICE_STARTED); + retval = 1; + TAILQ_FOREACH(s, services, entries) + if (rc_service_daemons_crashed(s->value)) { + printf("%s\n", s->value); + retval = 0; + } + goto exit; + /* NOTREACHED */ + case 'l': + levels = rc_runlevel_list(); + TAILQ_FOREACH(l, levels, entries) + printf("%s\n", l->value); + goto exit; + case 'm': + services = rc_services_in_runlevel(NULL); + levels = rc_runlevel_list(); + TAILQ_FOREACH_SAFE(s, services, entries, t) { + TAILQ_FOREACH(l, levels, entries) + if (rc_service_in_runlevel(s->value, l->value)) { + TAILQ_REMOVE(services, s, entries); + free(s->value); + free(s); + break; + } + } + TAILQ_FOREACH_SAFE(s, services, entries, t) + if (rc_service_state(s->value) & + (RC_SERVICE_STOPPED | RC_SERVICE_HOTPLUGGED)) { + TAILQ_REMOVE(services, s, entries); + free(s->value); + free(s); + } + print_services(NULL, services); + goto exit; + case 'r': + runlevel = rc_runlevel_get(); + printf("%s\n", runlevel); + goto exit; + /* NOTREACHED */ + case 's': + services = rc_services_in_runlevel(NULL); + print_services(NULL, services); + goto exit; + /* NOTREACHED */ + case 'u': + services = rc_services_in_runlevel(NULL); + levels = rc_runlevel_list(); + TAILQ_FOREACH_SAFE(s, services, entries, t) { + TAILQ_FOREACH(l, levels, entries) + if (rc_service_in_runlevel(s->value, l->value)) { + TAILQ_REMOVE(services, s, entries); + free(s->value); + free(s); + break; + } + } + print_services(NULL, services); + goto exit; + /* NOTREACHED */ + + case_RC_COMMON_GETOPT + } + + if (!levels) + levels = rc_stringlist_new(); + opt = (optind < argc) ? 0 : 1; + while (optind < argc) { + if (rc_runlevel_exists(argv[optind])) { + rc_stringlist_add(levels, argv[optind++]); + opt++; + } else + eerror("runlevel `%s' does not exist", argv[optind++]); + } + if (opt == 0) + exit(EXIT_FAILURE); + if (!TAILQ_FIRST(levels)) { + runlevel = rc_runlevel_get(); + rc_stringlist_add(levels, runlevel); + } + + /* Output the services in the order in which they would start */ + deptree = _rc_deptree_load(0, NULL); + + TAILQ_FOREACH(l, levels, entries) { + print_level(NULL, l->value); + services = rc_services_in_runlevel(l->value); + print_services(l->value, services); + print_stacked_services(l->value); + rc_stringlist_free(nservices); + nservices = NULL; + rc_stringlist_free(services); + services = NULL; + } + + if (show_all || argc < 2) { + /* Show hotplugged services */ + print_level("Dynamic", "hotplugged"); + services = rc_services_in_state(RC_SERVICE_HOTPLUGGED); + print_services(NULL, services); + rc_stringlist_free(services); + services = NULL; + + /* Show manually started and unassigned depended services */ + if (show_all) { + rc_stringlist_free(levels); + levels = rc_stringlist_new(); + if (!runlevel) + runlevel = rc_runlevel_get(); + rc_stringlist_add(levels, runlevel); + } + rc_stringlist_add(levels, RC_LEVEL_SYSINIT); + rc_stringlist_add(levels, RC_LEVEL_BOOT); + services = rc_services_in_runlevel(NULL); + sservices = rc_stringlist_new(); + TAILQ_FOREACH(l, levels, entries) { + nservices = rc_services_in_runlevel_stacked(l->value); + TAILQ_CONCAT(sservices, nservices, entries); + free(nservices); + } + TAILQ_FOREACH_SAFE(s, services, entries, t) { + if ((rc_stringlist_find(sservices, s->value) || + (rc_service_state(s->value) & ( RC_SERVICE_STOPPED | RC_SERVICE_HOTPLUGGED)))) { + TAILQ_REMOVE(services, s, entries); + free(s->value); + free(s); + } + } + needsme = rc_stringlist_new(); + rc_stringlist_add(needsme, "needsme"); + rc_stringlist_add(needsme, "wantsme"); + nservices = rc_stringlist_new(); + alist = rc_stringlist_new(); + l = rc_stringlist_add(alist, ""); + p = l->value; + TAILQ_FOREACH(level, levels, entries) { + TAILQ_FOREACH_SAFE(s, services, entries, t) { + l->value = s->value; + setenv("RC_SVCNAME", l->value, 1); + tmp = rc_deptree_depends(deptree, needsme, alist, level->value, RC_DEP_TRACE); + if (TAILQ_FIRST(tmp)) { + TAILQ_REMOVE(services, s, entries); + TAILQ_INSERT_TAIL(nservices, s, entries); + } + rc_stringlist_free(tmp); + } + } + l->value = p; + /* + * we are unsetting RC_SVCNAME because last loaded service will not + * be added to the list + */ + unsetenv("RC_SVCNAME"); + print_level("Dynamic", "needed/wanted"); + print_services(NULL, nservices); + print_level("Dynamic", "manual"); + print_services(NULL, services); + } + +exit: + free(runlevel); + rc_stringlist_free(alist); + rc_stringlist_free(needsme); + rc_stringlist_free(sservices); + rc_stringlist_free(nservices); + rc_stringlist_free(services); + rc_stringlist_free(types); + rc_stringlist_free(levels); + rc_deptree_free(deptree); + + return retval; +} Index: contrib/openrc/src/rc/rc-update.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-update.c @@ -0,0 +1,353 @@ +/* + * rc-update + * Manage init scripts and runlevels + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *usagestring = "" \ + "Usage: rc-update [options] add [...]\n" \ + " or: rc-update [options] del [...]\n" \ + " or: rc-update [options] [show [...]]"; +const char *getoptstring = "asu" getoptstring_COMMON; +const struct option longopts[] = { + { "all", 0, NULL, 'a' }, + { "stack", 0, NULL, 's' }, + { "update", 0, NULL, 'u' }, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Process all runlevels", + "Stack a runlevel instead of a service", + "Force an update of the dependency tree", + longopts_help_COMMON +}; + +/* Return the number of changes made: + * -1 = no changes (error) + * 0 = no changes (nothing to do) + * 1+ = number of runlevels updated + */ +static int +add(const char *runlevel, const char *service) +{ + int retval = -1; + + if (!rc_service_exists(service)) { + if (errno == ENOEXEC) + eerror("%s: service `%s' is not executeable", + applet, service); + else + eerror("%s: service `%s' does not exist", + applet, service); + } else if (rc_service_in_runlevel(service, runlevel)) { + einfo("%s: %s already installed in runlevel `%s'; skipping", + applet, service, runlevel); + retval = 0; + } else if (rc_service_add(runlevel, service)) { + einfo("service %s added to runlevel %s", service, runlevel); + retval = 1; + } else + eerror("%s: failed to add service `%s' to runlevel `%s': %s", + applet, service, runlevel, strerror (errno)); + + return retval; +} + +static int +delete(const char *runlevel, const char *service) +{ + int retval = -1; + + errno = 0; + if (rc_service_delete(runlevel, service)) { + einfo("service %s removed from runlevel %s", + service, runlevel); + return 1; + } + + if (errno == ENOENT) + eerror("%s: service `%s' is not in the runlevel `%s'", + applet, service, runlevel); + else + eerror("%s: failed to remove service `%s' from runlevel `%s': %s", + applet, service, runlevel, strerror (errno)); + + return retval; +} + +static int +addstack(const char *runlevel, const char *stack) +{ + if (!rc_runlevel_exists(runlevel)) { + eerror("%s: runlevel `%s' does not exist", applet, runlevel); + return -1; + } + if (!rc_runlevel_exists(stack)) { + eerror("%s: runlevel `%s' does not exist", applet, stack); + return -1; + } + if (strcmp(runlevel, stack) == 0) { + eerror("%s: cannot stack `%s' onto itself", applet, stack); + return -1; + } + if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 || + strcmp(stack, RC_LEVEL_SYSINIT) == 0 || + strcmp(runlevel, RC_LEVEL_BOOT) == 0 || + strcmp(stack, RC_LEVEL_BOOT) == 0 || + strcmp(runlevel, RC_LEVEL_SINGLE) == 0 || + strcmp(stack, RC_LEVEL_SINGLE) == 0 || + strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 || + strcmp(stack, RC_LEVEL_SHUTDOWN) == 0) + { + eerror("%s: cannot stack the %s runlevel", + applet, RC_LEVEL_SYSINIT); + return -1; + } + if (!rc_runlevel_stack(runlevel, stack)) { + eerror("%s: failed to stack `%s' to `%s': %s", + applet, stack, runlevel, strerror(errno)); + return -1; + } + einfo("runlevel %s added to runlevel %s", stack, runlevel); + return 1; +} + +static int +delstack(const char *runlevel, const char *stack) +{ + if (rc_runlevel_unstack(runlevel, stack)) { + einfo("runlevel %s removed from runlevel %s", stack, runlevel); + return 1; + } + + if (errno == ENOENT) + eerror("%s: runlevel `%s' is not in the runlevel `%s'", + applet, stack, runlevel); + else + eerror("%s: failed to remove runlevel `%s' from runlevel `%s': %s", + applet, stack, runlevel, strerror (errno)); + + return -1; +} + +static void +show(RC_STRINGLIST *runlevels, bool verbose) +{ + RC_STRINGLIST *services = rc_services_in_runlevel(NULL); + RC_STRING *service; + RC_STRING *runlevel; + RC_STRINGLIST *in; + bool inone; + char *buffer = NULL; + size_t l; + + rc_stringlist_sort(&services); + TAILQ_FOREACH(service, services, entries) { + in = rc_stringlist_new(); + inone = false; + + TAILQ_FOREACH(runlevel, runlevels, entries) { + if (rc_service_in_runlevel(service->value, + runlevel->value)) + { + rc_stringlist_add(in, runlevel->value); + inone = true; + } else { + l = strlen(runlevel->value); + buffer = xmalloc(l+1); + memset (buffer, ' ', l); + buffer[l] = 0; + rc_stringlist_add (in, buffer); + free(buffer); + } + } + + if (inone || verbose) { + printf(" %20s |", service->value); + TAILQ_FOREACH(runlevel, in, entries) + printf (" %s", runlevel->value); + printf ("\n"); + } + rc_stringlist_free(in); + } + + rc_stringlist_free (services); +} + +#define DOADD (1 << 1) +#define DODELETE (1 << 2) +#define DOSHOW (1 << 3) + +int main(int argc, char **argv) +{ + RC_DEPTREE *deptree; + RC_STRINGLIST *runlevels; + RC_STRING *runlevel; + char *service = NULL; + char *p; + int action = 0; + bool verbose = false, stack = false, all_runlevels = false; + int opt; + int retval = EXIT_FAILURE; + int num_updated = 0; + int (*actfunc)(const char *, const char *); + int ret; + + applet = basename_c(argv[0]); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *)0)) != -1) + switch (opt) { + case 'a': + all_runlevels = true; + break; + case 's': + stack = true; + break; + case 'u': + deptree = _rc_deptree_load(-1, &ret); + if (deptree) + rc_deptree_free(deptree); + return ret; + case_RC_COMMON_GETOPT + } + + verbose = rc_yesno(getenv ("EINFO_VERBOSE")); + + if ((action & DOSHOW && action != DOSHOW) || + (action & DOADD && action != DOADD) || + (action & DODELETE && action != DODELETE)) + eerrorx("%s: cannot mix commands", applet); + + /* We need to be backwards compatible */ + if (optind < argc) { + if (strcmp(argv[optind], "add") == 0) + action = DOADD; + else if (strcmp(argv[optind], "delete") == 0 || + strcmp(argv[optind], "del") == 0) + action = DODELETE; + else if (strcmp(argv[optind], "show") == 0) + action = DOSHOW; + if (action) + optind++; + else + eerrorx("%s: invalid command `%s'", + applet, argv[optind]); + } + if (!action) + action = DOSHOW; + + runlevels = rc_stringlist_new(); + + if (optind >= argc) { + if (!(action & DOSHOW)) + eerrorx("%s: no service specified", applet); + } else { + service = argv[optind]; + optind++; + + while (optind < argc) + if (rc_runlevel_exists(argv[optind])) + rc_stringlist_add(runlevels, argv[optind++]); + else { + rc_stringlist_free(runlevels); + eerrorx ("%s: `%s' is not a valid runlevel", + applet, argv[optind]); + } + } + + retval = EXIT_SUCCESS; + if (action & DOSHOW) { + if (service) + rc_stringlist_add(runlevels, service); + if (!TAILQ_FIRST(runlevels)) { + free(runlevels); + runlevels = rc_runlevel_list(); + } + + rc_stringlist_sort(&runlevels); + show (runlevels, verbose); + } else { + if (!service) + eerror ("%s: no service specified", applet); + else { + if (action & DOADD) { + if (all_runlevels) { + rc_stringlist_free(runlevels); + eerrorx("%s: the -a option is invalid with add", applet); + } + actfunc = stack ? addstack : add; + } else if (action & DODELETE) { + actfunc = stack ? delstack : delete; + } else { + rc_stringlist_free(runlevels); + eerrorx("%s: invalid action", applet); + } + + if (!TAILQ_FIRST(runlevels)) { + if (all_runlevels) { + free(runlevels); + runlevels = rc_runlevel_list(); + } else { + p = rc_runlevel_get(); + rc_stringlist_add(runlevels, p); + free(p); + } + } + + if (!TAILQ_FIRST(runlevels)) { + free(runlevels); + eerrorx("%s: no runlevels found", applet); + } + + TAILQ_FOREACH(runlevel, runlevels, entries) { + if (!rc_runlevel_exists(runlevel->value)) { + eerror ("%s: runlevel `%s' does not exist", + applet, runlevel->value); + continue; + } + + ret = actfunc(runlevel->value, service); + if (ret < 0) + retval = EXIT_FAILURE; + num_updated += ret; + } + + if (retval == EXIT_SUCCESS && + num_updated == 0 && action & DODELETE) + ewarnx("%s: service `%s' not found in any" + " of the specified runlevels", + applet, service); + } + } + + rc_stringlist_free(runlevels); + return retval; +} Index: contrib/openrc/src/rc/rc-wtmp.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc-wtmp.c @@ -0,0 +1,51 @@ +/* + * rc-wtmp.c + * This file contains routines to deal with the wtmp file. + */ + +/* + * Copyright 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rc-wtmp.h" + +void log_wtmp(const char *user, const char *id, pid_t pid, int type, + const char *line) +{ + struct timeval tv; + struct utmp utmp; + struct utsname uname_buf; + + memset(&utmp, 0, sizeof(utmp)); + gettimeofday(&tv, NULL); + utmp.ut_tv.tv_sec = tv.tv_sec; + utmp.ut_tv.tv_usec = tv.tv_usec; + utmp.ut_pid = pid; + utmp.ut_type = type; + strncpy(utmp.ut_name, user, sizeof(utmp.ut_name)); + strncpy(utmp.ut_id , id , sizeof(utmp.ut_id )); + strncpy(utmp.ut_line, line, sizeof(utmp.ut_line)); + + /* Put the OS version in place of the hostname */ + if (uname(&uname_buf) == 0) + strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host)); + + updwtmp(WTMP_FILE, &utmp); +} Index: contrib/openrc/src/rc/rc.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/rc.c @@ -0,0 +1,1131 @@ +/* + * rc.c + * rc - manager for init scripts which control the startup, shutdown + * and the running of daemons. + * + * Also a multicall binary for various commands that can be used in shell + * scripts to query service state, mark service state and provide the + * einfo family of informational functions. + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-logger.h" +#include "rc-misc.h" +#include "rc-plugin.h" + +#include "version.h" +#include "_usage.h" + +const char *extraopts = NULL; +const char *getoptstring = "a:no:s:S" getoptstring_COMMON; +const struct option longopts[] = { + { "no-stop", 0, NULL, 'n' }, + { "override", 1, NULL, 'o' }, + { "service", 1, NULL, 's' }, + { "sys", 0, NULL, 'S' }, + longopts_COMMON +}; +const char * const longopts_help[] = { + "do not stop any services", + "override the next runlevel to change into\n" + "when leaving single user or boot runlevels", + "runs the service specified with the rest\nof the arguments", + "output the RC system type, if any", + longopts_help_COMMON +}; +const char *usagestring = "" \ + "Usage: openrc [options] []"; + +#define INITSH RC_LIBEXECDIR "/sh/init.sh" +#define INITEARLYSH RC_LIBEXECDIR "/sh/init-early.sh" + +#define SHUTDOWN "/sbin/shutdown" +#define SULOGIN "/sbin/sulogin" + +#define INTERACTIVE RC_SVCDIR "/interactive" + +#define DEVBOOT "/dev/.rcboot" + +const char *applet = NULL; +static RC_STRINGLIST *main_hotplugged_services; +static RC_STRINGLIST *main_stop_services; +static RC_STRINGLIST *main_start_services; +static RC_STRINGLIST *main_types_nw; +static RC_STRINGLIST *main_types_nwua; +static RC_DEPTREE *main_deptree; +static char *runlevel; +static RC_HOOK hook_out; + +struct termios *termios_orig = NULL; + +RC_PIDLIST service_pids; + +static void +clean_failed(void) +{ + DIR *dp; + struct dirent *d; + size_t l; + char *path; + + /* Clean the failed services state dir now */ + if ((dp = opendir(RC_SVCDIR "/failed"))) { + while ((d = readdir(dp))) { + if (d->d_name[0] == '.' && + (d->d_name[1] == '\0' || + (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + continue; + + l = strlen(RC_SVCDIR "/failed/") + + strlen(d->d_name) + 1; + path = xmalloc(sizeof(char) * l); + snprintf(path, l, RC_SVCDIR "/failed/%s", d->d_name); + if (path) { + if (unlink(path)) + eerror("%s: unlink `%s': %s", + applet, path, strerror(errno)); + free(path); + } + } + closedir(dp); + } +} + +static void +cleanup(void) +{ + RC_PID *p1 = LIST_FIRST(&service_pids); + RC_PID *p2; + + if (!rc_in_logger && !rc_in_plugin && + applet && (strcmp(applet, "rc") == 0 || strcmp(applet, "openrc") == 0)) + { + if (hook_out) + rc_plugin_run(hook_out, runlevel); + + rc_plugin_unload(); + + if (termios_orig) { + tcsetattr(STDIN_FILENO, TCSANOW, termios_orig); + free(termios_orig); + } + + /* Clean runlevel start, stop markers */ + rmdir(RC_STARTING); + rmdir(RC_STOPPING); + clean_failed(); + rc_logger_close(); + } + + while (p1) { + p2 = LIST_NEXT(p1, entries); + free(p1); + p1 = p2; + } + + rc_stringlist_free(main_hotplugged_services); + rc_stringlist_free(main_stop_services); + rc_stringlist_free(main_start_services); + rc_stringlist_free(main_types_nw); + rc_stringlist_free(main_types_nwua); + rc_deptree_free(main_deptree); + free(runlevel); +} + +static char +read_key(bool block) +{ + struct termios termios; + char c = 0; + int fd = STDIN_FILENO; + + if (!isatty(fd)) + return false; + + /* Now save our terminal settings. We need to restore them at exit as + we will be changing it for non-blocking reads for Interactive */ + if (!termios_orig) { + termios_orig = xmalloc(sizeof(*termios_orig)); + tcgetattr(fd, termios_orig); + } + + tcgetattr(fd, &termios); + termios.c_lflag &= ~(ICANON | ECHO); + if (block) + termios.c_cc[VMIN] = 1; + else { + termios.c_cc[VMIN] = 0; + termios.c_cc[VTIME] = 0; + } + tcsetattr(fd, TCSANOW, &termios); + if (read(fd, &c, 1) == -1) + eerror("read: %s", strerror(errno)); + tcsetattr(fd, TCSANOW, termios_orig); + return c; +} + +static bool +want_interactive(void) +{ + char c; + static bool gotinteractive; + static bool interactive; + + if (rc_yesno(getenv("EINFO_QUIET"))) + return false; + if (!gotinteractive) { + gotinteractive = true; + interactive = rc_conf_yesno("rc_interactive"); + } + if (!interactive) + return false; + c = read_key(false); + return (c == 'I' || c == 'i') ? true : false; +} + +static void +mark_interactive(void) +{ + FILE *fp = fopen(INTERACTIVE, "w"); + if (fp) + fclose(fp); +} + +static void +run_program(const char *prog) +{ + struct sigaction sa; + sigset_t full; + sigset_t old; + pid_t pid; + + /* We need to block signals until we have forked */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sigfillset(&full); + sigprocmask(SIG_SETMASK, &full, &old); + pid = fork(); + + if (pid == -1) + eerrorx("%s: fork: %s", applet, strerror(errno)); + if (pid == 0) { + /* Restore default handlers */ + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGWINCH, &sa, NULL); + + /* Unmask signals */ + sigprocmask(SIG_SETMASK, &old, NULL); + + if (termios_orig) + tcsetattr(STDIN_FILENO, TCSANOW, termios_orig); + + execl(prog, prog, (char *)NULL); + eerror("%s: unable to exec `%s': %s", applet, prog, + strerror(errno)); + _exit(EXIT_FAILURE); + } + + /* Unmask signals and wait for child */ + sigprocmask(SIG_SETMASK, &old, NULL); + if (rc_waitpid(pid) == -1) + eerrorx("%s: failed to exec `%s'", applet, prog); +} + +static void +open_shell(void) +{ + const char *shell; + struct passwd *pw; + +#ifdef __linux__ + const char *sys = rc_sys(); + + /* VSERVER systems cannot really drop to shells */ + if (sys && strcmp(sys, RC_SYS_VSERVER) == 0) + { + execl("/sbin/halt", "/sbin/halt", "-f", (char *) NULL); + eerrorx("%s: unable to exec `/sbin/halt': %s", + applet, strerror(errno)); + } +#endif + + shell = rc_conf_value("rc_shell"); + /* No shell set, so obey env, then passwd, then default to /bin/sh */ + if (shell == NULL) { + shell = getenv("SHELL"); + if (shell == NULL) { + pw = getpwuid(getuid()); + if (pw) + shell = pw->pw_shell; + if (shell == NULL) + shell = "/bin/sh"; + } + } + run_program(shell); +} + +static bool +set_krunlevel(const char *level) +{ + FILE *fp; + + if (!level || + strcmp(level, getenv ("RC_BOOTLEVEL")) == 0 || + strcmp(level, RC_LEVEL_SINGLE) == 0 || + strcmp(level, RC_LEVEL_SYSINIT) == 0) + { + if (exists(RC_KRUNLEVEL) && + unlink(RC_KRUNLEVEL) != 0) + eerror("unlink `%s': %s", RC_KRUNLEVEL, + strerror(errno)); + return false; + } + + if (!(fp = fopen(RC_KRUNLEVEL, "w"))) { + eerror("fopen `%s': %s", RC_KRUNLEVEL, strerror(errno)); + return false; + } + + fprintf(fp, "%s", level); + fclose(fp); + return true; +} + +static char *get_krunlevel(void) +{ + char *buffer = NULL; + FILE *fp; + size_t i = 0; + + if (!exists(RC_KRUNLEVEL)) + return NULL; + if (!(fp = fopen(RC_KRUNLEVEL, "r"))) { + eerror("fopen `%s': %s", RC_KRUNLEVEL, strerror(errno)); + return NULL; + } + + if (getline(&buffer, &i, fp) != -1) { + i = strlen(buffer); + if (buffer[i - 1] == '\n') + buffer[i - 1] = 0; + } + fclose(fp); + return buffer; +} + +static void +add_pid(pid_t pid) +{ + RC_PID *p = xmalloc(sizeof(*p)); + p->pid = pid; + LIST_INSERT_HEAD(&service_pids, p, entries); +} + +static void +remove_pid(pid_t pid) +{ + RC_PID *p; + + LIST_FOREACH(p, &service_pids, entries) + if (p->pid == pid) { + LIST_REMOVE(p, entries); + free(p); + return; + } +} + +static void +wait_for_services(void) +{ + for (;;) { + while (waitpid(0, 0, 0) != -1) + ; + if (errno != EINTR) + break; + } +} + +static void +handle_signal(int sig) +{ + int serrno = errno; + char signame[10] = { '\0' }; + pid_t pid; + RC_PID *pi; + int status = 0; + struct winsize ws; + sigset_t sset; + + switch (sig) { + case SIGCHLD: + do { + pid = waitpid(-1, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + eerror("waitpid: %s", strerror(errno)); + return; + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + + /* Remove that pid from our list */ + if (pid > 0) + remove_pid(pid); + break; + + case SIGWINCH: + if (rc_logger_tty >= 0) { + ioctl(STDIN_FILENO, TIOCGWINSZ, &ws); + ioctl(rc_logger_tty, TIOCSWINSZ, &ws); + } + break; + + case SIGINT: + if (!signame[0]) + snprintf(signame, sizeof(signame), "SIGINT"); + /* FALLTHROUGH */ + case SIGTERM: + if (!signame[0]) + snprintf(signame, sizeof(signame), "SIGTERM"); + /* FALLTHROUGH */ + case SIGQUIT: + if (!signame[0]) + snprintf(signame, sizeof(signame), "SIGQUIT"); + eerrorx("%s: caught %s, aborting", applet, signame); + /* NOTREACHED */ + case SIGUSR1: + eerror("rc: Aborting!"); + + /* Block child signals */ + sigemptyset(&sset); + sigaddset(&sset, SIGCHLD); + sigprocmask(SIG_BLOCK, &sset, NULL); + + /* Kill any running services we have started */ + LIST_FOREACH(pi, &service_pids, entries) + kill(pi->pid, SIGTERM); + + /* Notify plugins we are aborting */ + rc_plugin_run(RC_HOOK_ABORT, NULL); + + exit(EXIT_FAILURE); + /* NOTREACHED */ + + default: + eerror("%s: caught unknown signal %d", applet, sig); + } + + /* Restore errno */ + errno = serrno; +} + +static void +do_sysinit() +{ + struct utsname uts; + const char *sys; + + /* exec init-early.sh if it exists + * This should just setup the console to use the correct + * font. Maybe it should setup the keyboard too? */ + if (exists(INITEARLYSH)) + run_program(INITEARLYSH); + + uname(&uts); + printf("\n %sOpenRC %s" VERSION "%s is starting up %s", + ecolor(ECOLOR_GOOD), ecolor(ECOLOR_HILITE), + ecolor(ECOLOR_NORMAL), ecolor(ECOLOR_BRACKET)); +#ifdef BRANDING + printf(BRANDING " (%s)", uts.machine); +#else + printf("%s %s (%s)", + uts.sysname, + uts.release, + uts.machine); +#endif + + if ((sys = rc_sys())) + printf(" [%s]", sys); + + printf("%s\n\n", ecolor(ECOLOR_NORMAL)); + + if (!rc_yesno(getenv ("EINFO_QUIET")) && + rc_conf_yesno("rc_interactive")) + printf("Press %sI%s to enter interactive boot mode\n\n", + ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL)); + + setenv("RC_RUNLEVEL", RC_LEVEL_SYSINIT, 1); + run_program(INITSH); + + /* init may have mounted /proc so we can now detect or real + * sys */ + if ((sys = rc_sys())) + setenv("RC_SYS", sys, 1); + /* force an update of the dependency tree */ + if ((main_deptree = _rc_deptree_load(1, NULL)) == NULL) + eerrorx("failed to load deptree"); +} + +static bool +runlevel_config(const char *service, const char *level) +{ + char *init = rc_service_resolve(service); + char *conf, *dir; + size_t l; + bool retval; + + dir = dirname(init); + dir = dirname(init); + l = strlen(dir) + strlen(level) + strlen(service) + 10; + conf = xmalloc(sizeof(char) * l); + snprintf(conf, l, "%s/conf.d/%s.%s", dir, service, level); + retval = exists(conf); + free(conf); + free(init); + return retval; +} + +static void +do_stop_services(RC_STRINGLIST *types_nw, RC_STRINGLIST *start_services, + const RC_STRINGLIST *stop_services, const RC_DEPTREE *deptree, + const char *newlevel, bool parallel, bool going_down) +{ + pid_t pid; + RC_STRING *service, *svc1, *svc2; + RC_STRINGLIST *deporder, *tmplist, *kwords; + RC_SERVICE state; + RC_STRINGLIST *nostop; + bool crashed, nstop; + + if (!types_nw) { + types_nw = rc_stringlist_new(); + rc_stringlist_add(types_nw, "needsme"); + rc_stringlist_add(types_nw, "wantsme"); + } + + crashed = rc_conf_yesno("rc_crashed_stop"); + + nostop = rc_stringlist_split(rc_conf_value("rc_nostop"), " "); + TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) + { + state = rc_service_state(service->value); + if (state & RC_SERVICE_STOPPED || state & RC_SERVICE_FAILED) + continue; + + /* Sometimes we don't ever want to stop a service. */ + if (rc_stringlist_find(nostop, service->value)) { + rc_service_mark(service->value, RC_SERVICE_FAILED); + continue; + } + kwords = rc_deptree_depend(deptree, service->value, "keyword"); + if (rc_stringlist_find(kwords, "-stop") || + rc_stringlist_find(kwords, "nostop") || + (going_down && + (rc_stringlist_find(kwords, "-shutdown") || + rc_stringlist_find(kwords, "noshutdown")))) + nstop = true; + else + nstop = false; + rc_stringlist_free(kwords); + if (nstop) { + rc_service_mark(service->value, RC_SERVICE_FAILED); + continue; + } + + /* If the service has crashed, skip futher checks and just stop + it */ + if (crashed && + rc_service_daemons_crashed(service->value)) + goto stop; + + /* If we're in the start list then don't bother stopping us */ + svc1 = rc_stringlist_find(start_services, service->value); + if (svc1) { + if (newlevel && strcmp(runlevel, newlevel) != 0) { + /* So we're in the start list. But we should + * be stopped if we have a runlevel + * configuration file for either the current + * or next so we use the correct one. */ + if (!runlevel_config(service->value,runlevel) && + !runlevel_config(service->value,newlevel)) + continue; + } + else + continue; + } + + /* We got this far. Last check is to see if any any service + * that going to be started depends on us */ + if (!svc1) { + tmplist = rc_stringlist_new(); + rc_stringlist_add(tmplist, service->value); + deporder = rc_deptree_depends(deptree, types_nw, + tmplist, newlevel ? newlevel : runlevel, + RC_DEP_STRICT | RC_DEP_TRACE); + rc_stringlist_free(tmplist); + svc2 = NULL; + TAILQ_FOREACH(svc1, deporder, entries) { + svc2 = rc_stringlist_find(start_services, + svc1->value); + if (svc2) + break; + } + rc_stringlist_free(deporder); + + if (svc2) + continue; + } + +stop: + /* After all that we can finally stop the blighter! */ + pid = service_stop(service->value); + if (pid > 0) { + add_pid(pid); + if (!parallel) { + rc_waitpid(pid); + remove_pid(pid); + } + } + } + + rc_stringlist_free(nostop); +} + +static void +do_start_services(const RC_STRINGLIST *start_services, bool parallel) +{ + RC_STRING *service; + pid_t pid; + bool interactive = false; + RC_SERVICE state; + bool crashed = false; + + if (!rc_yesno(getenv("EINFO_QUIET"))) + interactive = exists(INTERACTIVE); + errno = 0; + crashed = rc_conf_yesno("rc_crashed_start"); + if (errno == ENOENT) + crashed = true; + + TAILQ_FOREACH(service, start_services, entries) { + state = rc_service_state(service->value); + if (state & RC_SERVICE_FAILED) + continue; + if (!(state & RC_SERVICE_STOPPED)) { + if (crashed && + rc_service_daemons_crashed(service->value)) + rc_service_mark(service->value, + RC_SERVICE_STOPPED); + else + continue; + } + if (!interactive) + interactive = want_interactive(); + + if (interactive) { + interactive_retry: + printf("\n"); + einfo("About to start the service %s", + service->value); + eindent(); + einfo("1) Start the service\t\t2) Skip the service"); + einfo("3) Continue boot process\t\t4) Exit to shell"); + eoutdent(); + interactive_option: + switch (read_key(true)) { + case '1': break; + case '2': continue; + case '3': interactive = false; break; + case '4': open_shell(); goto interactive_retry; + default: goto interactive_option; + } + } + + pid = service_start(service->value); + if (pid == -1) + break; + /* Remember the pid if we're running in parallel */ + if (pid > 0) { + add_pid(pid); + if (!parallel) { + rc_waitpid(pid); + remove_pid(pid); + } + } + } + + /* Store our interactive status for boot */ + if (interactive && + (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 || + strcmp(runlevel, getenv("RC_BOOTLEVEL")) == 0)) + mark_interactive(); + else { + if (exists(INTERACTIVE)) + unlink(INTERACTIVE); + } + +} + +#ifdef RC_DEBUG +static void +handle_bad_signal(int sig) +{ + char pid[10]; + int status; + pid_t crashed_pid = getpid(); + + switch (fork()) { + case -1: + _exit(sig); + /* NOTREACHED */ + case 0: + sprintf(pid, "%i", crashed_pid); + printf("\nAuto launching gdb!\n\n"); + _exit(execlp("gdb", "gdb", "--quiet", "--pid", pid, + "-ex", "bt full", NULL)); + /* NOTREACHED */ + default: + wait(&status); + } + _exit(1); + /* NOTREACHED */ +} +#endif + +int main(int argc, char **argv) +{ + const char *bootlevel = NULL; + char *newlevel = NULL; + const char *systype = NULL; + RC_STRINGLIST *deporder = NULL; + RC_STRINGLIST *tmplist; + RC_STRING *service; + bool going_down = false; + int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; + char *krunlevel = NULL; + char pidstr[10]; + int opt; + bool parallel; + int regen = 0; + bool nostop = false; +#ifdef __linux__ + char *proc; + char *p; + char *token; +#endif + +#ifdef RC_DEBUG + signal_setup(SIGBUS, handle_bad_signal); + signal_setup(SIGILL, handle_bad_signal); + signal_setup(SIGSEGV, handle_bad_signal); +#endif + + applet = basename_c(argv[0]); + LIST_INIT(&service_pids); + atexit(cleanup); + if (!applet) + eerrorx("arguments required"); + + argc--; + argv++; + + /* Change dir to / to ensure all scripts don't use stuff in pwd */ + if (chdir("/") == -1) + eerror("chdir: %s", strerror(errno)); + + /* Ensure our environment is pure + * Also, add our configuration to it */ + env_filter(); + env_config(); + + /* complain about old configuration settings if they exist */ + if (exists(RC_CONF_OLD)) { + ewarn("%s still exists on your system and should be removed.", + RC_CONF_OLD); + ewarn("Please migrate to the appropriate settings in %s", RC_CONF); + } + + argc++; + argv--; + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'n': + nostop = true; + break; + case 'o': + if (*optarg == '\0') + optarg = NULL; + if (!rc_runlevel_exists(optarg)) { + eerror("runlevel `%s' does not exist", optarg); + exit(EXIT_FAILURE); + } + if (!set_krunlevel(optarg)) + exit(EXIT_FAILURE); + einfo("Overriding next runlevel to %s", optarg); + exit(EXIT_SUCCESS); + /* NOTREACHED */ + case 's': + newlevel = rc_service_resolve(optarg); + if (!newlevel) + eerrorx("%s: service `%s' does not exist", + applet, optarg); + argv += optind - 1; + *argv = newlevel; + execv(*argv, argv); + eerrorx("%s: %s", applet, strerror(errno)); + /* NOTREACHED */ + case 'S': + systype = rc_sys(); + if (systype) + printf("%s\n", systype); + exit(EXIT_SUCCESS); + /* NOTREACHED */ + case_RC_COMMON_GETOPT + } + } + + if (strcmp(applet, "rc") == 0) + ewarn("rc is deprecated, please use openrc instead."); + newlevel = argv[optind++]; + /* To make life easier, we only have the shutdown runlevel as + * nothing really needs to know that we're rebooting. + * But for those that do, you can test against RC_REBOOT. */ + if (newlevel) { + if (strcmp(newlevel, "reboot") == 0) { + newlevel = UNCONST(RC_LEVEL_SHUTDOWN); + setenv("RC_REBOOT", "YES", 1); + } + } + + /* Enable logging */ + setenv("EINFO_LOG", "openrc", 1); + + /* Export our PID */ + snprintf(pidstr, sizeof(pidstr), "%d", getpid()); + setenv("RC_PID", pidstr, 1); + + /* Create a list of all services which should be started for the new or + * current runlevel including those in boot, sysinit and hotplugged + * runlevels. Clearly, some of these will already be started so we + * won't actually be starting them all. + */ + bootlevel = getenv("RC_BOOTLEVEL"); + runlevel = rc_runlevel_get(); + + rc_logger_open(newlevel ? newlevel : runlevel); + + /* Setup a signal handler */ + signal_setup(SIGINT, handle_signal); + signal_setup(SIGQUIT, handle_signal); + signal_setup(SIGTERM, handle_signal); + signal_setup(SIGUSR1, handle_signal); + signal_setup(SIGWINCH, handle_signal); + + /* Run any special sysinit foo */ + if (newlevel && strcmp(newlevel, RC_LEVEL_SYSINIT) == 0) { + do_sysinit(); + free(runlevel); + runlevel = rc_runlevel_get(); + } + + rc_plugin_load(); + + /* Now we start handling our children */ + signal_setup(SIGCHLD, handle_signal); + + if (newlevel && + (strcmp(newlevel, RC_LEVEL_SHUTDOWN) == 0 || + strcmp(newlevel, RC_LEVEL_SINGLE) == 0)) + { + going_down = true; + if (!exists(RC_KRUNLEVEL)) + set_krunlevel(runlevel); + rc_runlevel_set(newlevel); + setenv("RC_RUNLEVEL", newlevel, 1); + setenv("RC_GOINGDOWN", "YES", 1); + } else { + /* We should not use krunevel in sysinit or boot runlevels */ + if (!newlevel || + (strcmp(newlevel, RC_LEVEL_SYSINIT) != 0 && + strcmp(newlevel, getenv("RC_BOOTLEVEL")) != 0)) + { + krunlevel = get_krunlevel(); + if (krunlevel) { + newlevel = krunlevel; + set_krunlevel(NULL); + } + } + + if (newlevel) { + if (strcmp(runlevel, newlevel) != 0 && + !rc_runlevel_exists(newlevel)) + eerrorx("%s: not a valid runlevel", newlevel); + +#ifdef __linux__ + if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0) { + /* If we requested a runlevel, save it now */ + p = rc_proc_getent("rc_runlevel"); + if (p == NULL) + p = rc_proc_getent("softlevel"); + if (p != NULL) { + set_krunlevel(p); + free(p); + } + } +#endif + } + } + + if (going_down) { +#ifdef __FreeBSD__ + /* FIXME: we shouldn't have todo this */ + /* For some reason, wait_for_services waits for the logger + * proccess to finish as well, but only on FreeBSD. + * We cannot allow this so we stop logging now. */ + rc_logger_close(); +#endif + + rc_plugin_run(RC_HOOK_RUNLEVEL_STOP_IN, newlevel); + } else { + rc_plugin_run(RC_HOOK_RUNLEVEL_STOP_IN, runlevel); + } + hook_out = RC_HOOK_RUNLEVEL_STOP_OUT; + + /* Check if runlevel is valid if we're changing */ + if (newlevel && strcmp(runlevel, newlevel) != 0 && !going_down) { + if (!rc_runlevel_exists(newlevel)) + eerrorx("%s: is not a valid runlevel", newlevel); + } + + /* Load our deptree */ + if ((main_deptree = _rc_deptree_load(0, ®en)) == NULL) + eerrorx("failed to load deptree"); + if (exists(RC_DEPTREE_SKEWED)) + ewarn("WARNING: clock skew detected!"); + + /* Clean the failed services state dir */ + clean_failed(); + + if (mkdir(RC_STOPPING, 0755) != 0) { + if (errno == EACCES) + eerrorx("%s: superuser access required", applet); + eerrorx("%s: failed to create stopping dir `%s': %s", + applet, RC_STOPPING, strerror(errno)); + } + + /* Create a list of all services which we could stop (assuming + * they won't be active in the new or current runlevel) including + * all those services which have been started, are inactive or + * are currently starting. Clearly, some of these will be listed + * in the new or current runlevel so we won't actually be stopping + * them all. + */ + main_stop_services = rc_services_in_state(RC_SERVICE_STARTED); + tmplist = rc_services_in_state(RC_SERVICE_INACTIVE); + TAILQ_CONCAT(main_stop_services, tmplist, entries); + free(tmplist); + tmplist = rc_services_in_state(RC_SERVICE_STARTING); + TAILQ_CONCAT(main_stop_services, tmplist, entries); + free(tmplist); + if (main_stop_services) + rc_stringlist_sort(&main_stop_services); + + main_types_nwua = rc_stringlist_new(); + rc_stringlist_add(main_types_nwua, "ineed"); + rc_stringlist_add(main_types_nwua, "iwant"); + rc_stringlist_add(main_types_nwua, "iuse"); + rc_stringlist_add(main_types_nwua, "iafter"); + + if (main_stop_services) { + tmplist = rc_deptree_depends(main_deptree, main_types_nwua, main_stop_services, + runlevel, depoptions | RC_DEP_STOP); + rc_stringlist_free(main_stop_services); + main_stop_services = tmplist; + } + + /* Create a list of all services which should be started for the new or + * current runlevel including those in boot, sysinit and hotplugged + * runlevels. Clearly, some of these will already be started so we + * won't actually be starting them all. + */ + main_hotplugged_services = rc_services_in_state(RC_SERVICE_HOTPLUGGED); + main_start_services = rc_services_in_runlevel_stacked(newlevel ? + newlevel : runlevel); + if (strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 && + strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SYSINIT) != 0) + { + tmplist = rc_services_in_runlevel(RC_LEVEL_SYSINIT); + TAILQ_CONCAT(main_start_services, tmplist, entries); + free(tmplist); + /* If we are NOT headed for the single-user runlevel... */ + if (strcmp(newlevel ? newlevel : runlevel, + RC_LEVEL_SINGLE) != 0) + { + /* If we are NOT headed for the boot runlevel... */ + if (strcmp(newlevel ? newlevel : runlevel, + bootlevel) != 0) + { + tmplist = rc_services_in_runlevel(bootlevel); + TAILQ_CONCAT(main_start_services, tmplist, entries); + free(tmplist); + } + if (main_hotplugged_services) { + TAILQ_FOREACH(service, main_hotplugged_services, + entries) + rc_stringlist_addu(main_start_services, + service->value); + } + } + } + + parallel = rc_conf_yesno("rc_parallel"); + + /* Now stop the services that shouldn't be running */ + if (main_stop_services && !nostop) + do_stop_services(main_types_nw, main_start_services, main_stop_services, main_deptree, newlevel, parallel, going_down); + + /* Wait for our services to finish */ + wait_for_services(); + + /* Notify the plugins we have finished */ + rc_plugin_run(RC_HOOK_RUNLEVEL_STOP_OUT, + going_down ? newlevel : runlevel); + hook_out = 0; + + rmdir(RC_STOPPING); + + /* Store the new runlevel */ + if (newlevel) { + rc_runlevel_set(newlevel); + free(runlevel); + runlevel = xstrdup(newlevel); + setenv("RC_RUNLEVEL", runlevel, 1); + } + +#ifdef __linux__ + /* We can't log beyond this point as the shutdown runlevel + * will mount / readonly. */ + if (strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0) + rc_logger_close(); +#endif + + mkdir(RC_STARTING, 0755); + rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, runlevel); + hook_out = RC_HOOK_RUNLEVEL_START_OUT; + + /* Re-add our hotplugged services if they stopped */ + if (main_hotplugged_services) + TAILQ_FOREACH(service, main_hotplugged_services, entries) + rc_service_mark(service->value, RC_SERVICE_HOTPLUGGED); + +#ifdef __linux__ + /* If the "noinit" parameter was passed on the kernel command line then + * mark the specified services as started so they will not be started + * by us. */ + proc = p = rc_proc_getent("noinit"); + if (proc) { + while ((token = strsep(&p, ","))) + rc_service_mark(token, RC_SERVICE_STARTED); + free(proc); + } +#endif + + /* If we have a list of services to start then... */ + if (main_start_services) { + /* Get a list of the chained runlevels which compose the target runlevel */ + RC_STRINGLIST *runlevel_chain = rc_runlevel_stacks(runlevel); + + /* Loop through them in reverse order. */ + RC_STRING *rlevel; + TAILQ_FOREACH_REVERSE(rlevel, runlevel_chain, rc_stringlist, entries) + { + /* Get a list of all the services in that runlevel */ + RC_STRINGLIST *run_services = rc_services_in_runlevel(rlevel->value); + + /* Start those services. */ + rc_stringlist_sort(&run_services); + deporder = rc_deptree_depends(main_deptree, main_types_nwua, run_services, rlevel->value, depoptions | RC_DEP_START); + rc_stringlist_free(run_services); + run_services = deporder; + do_start_services(run_services, parallel); + + /* Wait for our services to finish */ + wait_for_services(); + + /* Free the list of services, we're done with it. */ + rc_stringlist_free(run_services); + } + rc_stringlist_free(runlevel_chain); + } + +#ifdef __linux__ + /* If the "noinit" parameter was passed on the kernel command line then + * mark the specified services as stopped so that our records reflect + * reality. */ + proc = p = rc_proc_getent("noinit"); + if (proc) { + while ((token = strsep(&p, ","))) + rc_service_mark(token, RC_SERVICE_STOPPED); + free(proc); + } + +#endif + + rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel); + hook_out = 0; + + /* If we're in the boot runlevel and we regenerated our dependencies + * we need to delete them so that they are regenerated again in the + * default runlevel as they may depend on things that are now + * available */ + if (regen && strcmp(runlevel, bootlevel) == 0) + unlink(RC_DEPTREE_CACHE); + + return EXIT_SUCCESS; +} Index: contrib/openrc/src/rc/shell_var.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/shell_var.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int i; + char *p; + int c; + + for (i = 1; i < argc; i++) { + p = argv[i]; + if (i != 1) + putchar(' '); + while (*p) { + c = (unsigned char)*p++; + if (! isalnum(c)) + c = '_'; + putchar(c); + } + } + putchar('\n'); + return EXIT_SUCCESS; +} Index: contrib/openrc/src/rc/start-stop-daemon.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/start-stop-daemon.c @@ -0,0 +1,995 @@ +/* + start-stop-daemon + * Starts, stops, tests and signals daemons + * + * This is essentially a ground up re-write of Debians + * start-stop-daemon for cleaner code and to integrate into our RC + * system so we can monitor daemons a little. + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#define ONE_MS 1000000 + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include /* For io priority */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_PAM +#include + +/* We are not supporting authentication conversations */ +static struct pam_conv conv = { NULL, NULL}; +#endif + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "rc-schedules.h" +#include "_usage.h" +#include "helpers.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:" \ + getoptstring_COMMON; +const struct option longopts[] = { + { "ionice", 1, NULL, 'I'}, + { "stop", 0, NULL, 'K'}, + { "nicelevel", 1, NULL, 'N'}, + { "retry", 1, NULL, 'R'}, + { "start", 0, NULL, 'S'}, + { "startas", 1, NULL, 'a'}, + { "background", 0, NULL, 'b'}, + { "chuid", 1, NULL, 'c'}, + { "chdir", 1, NULL, 'd'}, + { "env", 1, NULL, 'e'}, + { "umask", 1, NULL, 'k'}, + { "group", 1, NULL, 'g'}, + { "interpreted", 0, NULL, 'i'}, + { "make-pidfile", 0, NULL, 'm'}, + { "name", 1, NULL, 'n'}, + { "oknodo", 0, NULL, 'o'}, + { "pidfile", 1, NULL, 'p'}, + { "signal", 1, NULL, 's'}, + { "test", 0, NULL, 't'}, + { "user", 1, NULL, 'u'}, + { "chroot", 1, NULL, 'r'}, + { "wait", 1, NULL, 'w'}, + { "exec", 1, NULL, 'x'}, + { "stdout", 1, NULL, '1'}, + { "stderr", 1, NULL, '2'}, + { "progress", 0, NULL, 'P'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Set an ionice class:data when starting", + "Stop daemon", + "Set a nicelevel when starting", + "Retry schedule to use when stopping", + "Start daemon", + "deprecated, use --exec or --name", + "Force daemon to background", + "deprecated, use --user", + "Change the PWD", + "Set an environment string", + "Set the umask for the daemon", + "Change the process group", + "Match process name by interpreter", + "Create a pidfile", + "Match process name", + "deprecated", + "Match pid found in this file", + "Send a different signal", + "Test actions, don't do them", + "Change the process user", + "Chroot to this directory", + "Milliseconds to wait for daemon start", + "Binary to start/stop", + "Redirect stdout to file", + "Redirect stderr to file", + "Print dots each second while waiting", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +static char **nav; + +static char *changeuser, *ch_root, *ch_dir; + +extern char **environ; + +#if !defined(SYS_ioprio_set) && defined(__NR_ioprio_set) +# define SYS_ioprio_set __NR_ioprio_set +#endif +#if !defined(__DragonFly__) +static inline int ioprio_set(int which _unused, + int who _unused, + int ioprio _unused) +{ +#ifdef SYS_ioprio_set + return syscall(SYS_ioprio_set, which, who, ioprio); +#else + return 0; +#endif +} +#endif + +static void +cleanup(void) +{ + free(changeuser); + free(nav); + free_schedulelist(); +} + +static void +handle_signal(int sig) +{ + int status; + int serrno = errno; + char signame[10] = { '\0' }; + + switch (sig) { + case SIGINT: + if (!signame[0]) + snprintf(signame, sizeof(signame), "SIGINT"); + /* FALLTHROUGH */ + case SIGTERM: + if (!signame[0]) + snprintf(signame, sizeof(signame), "SIGTERM"); + /* FALLTHROUGH */ + case SIGQUIT: + if (!signame[0]) + snprintf(signame, sizeof(signame), "SIGQUIT"); + eerrorx("%s: caught %s, aborting", applet, signame); + /* NOTREACHED */ + + case SIGCHLD: + for (;;) { + if (waitpid(-1, &status, WNOHANG) < 0) { + if (errno != ECHILD) + eerror("%s: waitpid: %s", + applet, strerror(errno)); + break; + } + } + break; + + default: + eerror("%s: caught unknown signal %d", applet, sig); + } + + /* Restore errno */ + errno = serrno; +} + +static char * +expand_home(const char *home, const char *path) +{ + char *opath, *ppath, *p, *nh; + size_t len; + struct passwd *pw; + + if (!path || *path != '~') + return xstrdup(path); + + opath = ppath = xstrdup(path); + if (ppath[1] != '/' && ppath[1] != '\0') { + p = strchr(ppath + 1, '/'); + if (p) + *p = '\0'; + pw = getpwnam(ppath + 1); + if (pw) { + home = pw->pw_dir; + ppath = p; + if (ppath) + *ppath = '/'; + } else + home = NULL; + } else + ppath++; + + if (!home) { + free(opath); + return xstrdup(path); + } + if (!ppath) { + free(opath); + return xstrdup(home); + } + + len = strlen(ppath) + strlen(home) + 1; + nh = xmalloc(len); + snprintf(nh, len, "%s%s", home, ppath); + free(opath); + return nh; +} + +int main(int argc, char **argv) +{ + int devnull_fd = -1; +#ifdef TIOCNOTTY + int tty_fd = -1; +#endif + +#ifdef HAVE_PAM + pam_handle_t *pamh = NULL; + int pamr; + const char *const *pamenv = NULL; +#endif + + int opt; + size_t size = 0; + bool start = false; + bool stop = false; + bool oknodo = false; + bool test = false; + char *exec = NULL; + char *startas = NULL; + char *name = NULL; + char *pidfile = NULL; + char *retry = NULL; + int sig = -1; + int nicelevel = 0, ionicec = -1, ioniced = 0; + bool background = false; + bool makepidfile = false; + bool interpreted = false; + bool progress = false; + uid_t uid = 0; + gid_t gid = 0; + char *home = NULL; + int tid = 0; + char *redirect_stderr = NULL; + char *redirect_stdout = NULL; + int stdin_fd; + int stdout_fd; + int stderr_fd; + pid_t pid, spid; + RC_PIDLIST *pids; + int i; + char *svcname = getenv("RC_SVCNAME"); + RC_STRINGLIST *env_list; + RC_STRING *env; + char *tmp, *newpath, *np; + char *p; + char *token; + char *exec_file = NULL; + struct passwd *pw; + struct group *gr; + char *line = NULL; + FILE *fp; + size_t len; + mode_t numask = 022; + char **margv; + unsigned int start_wait = 0; + + applet = basename_c(argv[0]); + atexit(cleanup); + + signal_setup(SIGINT, handle_signal); + signal_setup(SIGQUIT, handle_signal); + signal_setup(SIGTERM, handle_signal); + + if ((tmp = getenv("SSD_NICELEVEL"))) + if (sscanf(tmp, "%d", &nicelevel) != 1) + eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)", + applet, tmp); + if ((tmp = getenv("SSD_IONICELEVEL"))) { + int n = sscanf(tmp, "%d:%d", &ionicec, &ioniced); + if (n != 1 && n != 2) + eerror("%s: invalid ionice level `%s' (SSD_IONICELEVEL)", + applet, tmp); + if (ionicec == 0) + ioniced = 0; + else if (ionicec == 3) + ioniced = 7; + ionicec <<= 13; /* class shift */ + } + + /* Get our user name and initial dir */ + p = getenv("USER"); + home = getenv("HOME"); + if (home == NULL || p == NULL) { + pw = getpwuid(getuid()); + if (pw != NULL) { + if (p == NULL) + setenv("USER", pw->pw_name, 1); + if (home == NULL) { + setenv("HOME", pw->pw_dir, 1); + home = pw->pw_dir; + } + } + } + + while ((opt = getopt_long(argc, argv, getoptstring, longopts, + (int *) 0)) != -1) + switch (opt) { + case 'I': /* --ionice */ + if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0) + eerrorx("%s: invalid ionice `%s'", + applet, optarg); + if (ionicec == 0) + ioniced = 0; + else if (ionicec == 3) + ioniced = 7; + ionicec <<= 13; /* class shift */ + break; + + case 'K': /* --stop */ + stop = true; + break; + + case 'N': /* --nice */ + if (sscanf(optarg, "%d", &nicelevel) != 1) + eerrorx("%s: invalid nice level `%s'", + applet, optarg); + break; + + case 'P': /* --progress */ + progress = true; + break; + + case 'R': /* --retry | */ + retry = optarg; + break; + + case 'S': /* --start */ + start = true; + break; + + case 'b': /* --background */ + background = true; + break; + + case 'c': /* --chuid | */ + /* DEPRECATED */ + ewarn("WARNING: -c/--chuid is deprecated and will be removed in the future, please use -u/--user instead"); + case 'u': /* --user | */ + { + p = optarg; + tmp = strsep(&p, ":"); + changeuser = xstrdup(tmp); + if (sscanf(tmp, "%d", &tid) != 1) + pw = getpwnam(tmp); + else + pw = getpwuid((uid_t)tid); + + if (pw == NULL) + eerrorx("%s: user `%s' not found", + applet, tmp); + uid = pw->pw_uid; + home = pw->pw_dir; + unsetenv("HOME"); + if (pw->pw_dir) + setenv("HOME", pw->pw_dir, 1); + unsetenv("USER"); + if (pw->pw_name) + setenv("USER", pw->pw_name, 1); + if (gid == 0) + gid = pw->pw_gid; + + if (p) { + tmp = strsep (&p, ":"); + if (sscanf(tmp, "%d", &tid) != 1) + gr = getgrnam(tmp); + else + gr = getgrgid((gid_t) tid); + + if (gr == NULL) + eerrorx("%s: group `%s'" + " not found", + applet, tmp); + gid = gr->gr_gid; + } + } + break; + + case 'd': /* --chdir /new/dir */ + ch_dir = optarg; + break; + + case 'e': /* --env */ + putenv(optarg); + break; + + case 'g': /* --group | */ + if (sscanf(optarg, "%d", &tid) != 1) + gr = getgrnam(optarg); + else + gr = getgrgid((gid_t)tid); + if (gr == NULL) + eerrorx("%s: group `%s' not found", + applet, optarg); + gid = gr->gr_gid; + break; + + case 'i': /* --interpreted */ + interpreted = true; + break; + + case 'k': + if (parse_mode(&numask, optarg)) + eerrorx("%s: invalid mode `%s'", + applet, optarg); + break; + + case 'm': /* --make-pidfile */ + makepidfile = true; + break; + + case 'n': /* --name */ + name = optarg; + break; + + case 'o': /* --oknodo */ + /* DEPRECATED */ + ewarn("WARNING: -o/--oknodo is deprecated and will be removed in the future"); + oknodo = true; + break; + + case 'p': /* --pidfile */ + pidfile = optarg; + break; + + case 's': /* --signal */ + sig = parse_signal(applet, optarg); + break; + + case 't': /* --test */ + test = true; + break; + + case 'r': /* --chroot /new/root */ + ch_root = optarg; + break; + + case 'a': /* --startas */ + /* DEPRECATED */ + ewarn("WARNING: -a/--startas is deprecated and will be removed in the future, please use -x/--exec or -n/--name instead"); + startas = optarg; + break; + case 'w': + if (sscanf(optarg, "%d", &start_wait) != 1) + eerrorx("%s: `%s' not a number", + applet, optarg); + break; + case 'x': /* --exec */ + exec = optarg; + break; + + case '1': /* --stdout /path/to/stdout.lgfile */ + redirect_stdout = optarg; + break; + + case '2': /* --stderr /path/to/stderr.logfile */ + redirect_stderr = optarg; + break; + + case_RC_COMMON_GETOPT + } + + endpwent(); + argc -= optind; + argv += optind; + + /* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq + * instead of forcing --stop --oknodo as well */ + if (!start && + !stop && + sig != SIGINT && + sig != SIGTERM && + sig != SIGQUIT && + sig != SIGKILL) + oknodo = true; + + if (!exec) + exec = startas; + else if (!name) + name = startas; + + if (!exec) { + exec = *argv; + if (!exec) + exec = name; + if (name && start) + *argv = name; + } else if (name) { + *--argv = name; + ++argc; + } else if (exec) { + *--argv = exec; + ++argc; + }; + + if (stop || sig != -1) { + if (sig == -1) + sig = SIGTERM; + if (!*argv && !pidfile && !name && !uid) + eerrorx("%s: --stop needs --exec, --pidfile," + " --name or --user", applet); + if (background) + eerrorx("%s: --background is only relevant with" + " --start", applet); + if (makepidfile) + eerrorx("%s: --make-pidfile is only relevant with" + " --start", applet); + if (redirect_stdout || redirect_stderr) + eerrorx("%s: --stdout and --stderr are only relevant" + " with --start", applet); + if (start_wait) + ewarn("using --wait with --stop has no effect," + " use --retry instead"); + } else { + if (!exec) + eerrorx("%s: nothing to start", applet); + if (makepidfile && !pidfile) + eerrorx("%s: --make-pidfile is only relevant with" + " --pidfile", applet); + if ((redirect_stdout || redirect_stderr) && !background) + eerrorx("%s: --stdout and --stderr are only relevant" + " with --background", applet); + } + + /* Expand ~ */ + if (ch_dir && *ch_dir == '~') + ch_dir = expand_home(home, ch_dir); + if (ch_root && *ch_root == '~') + ch_root = expand_home(home, ch_root); + if (exec) { + if (*exec == '~') + exec = expand_home(home, exec); + + /* Validate that the binary exists if we are starting */ + if (*exec == '/' || *exec == '.') { + /* Full or relative path */ + if (ch_root) + xasprintf(&exec_file, "%s/%s", ch_root, exec); + else + xasprintf(&exec_file, "%s", exec); + } else { + /* Something in $PATH */ + p = tmp = xstrdup(getenv("PATH")); + exec_file = NULL; + while ((token = strsep(&p, ":"))) { + if (ch_root) + xasprintf(&exec_file, "%s/%s/%s", ch_root, token, exec); + else + xasprintf(&exec_file, "%s/%s", token, exec); + if (exec_file && exists(exec_file)) + break; + free(exec_file); + exec_file = NULL; + } + free(tmp); + } + } + if (start && !exists(exec_file)) { + eerror("%s: %s does not exist", applet, + *exec_file ? exec_file : exec); + free(exec_file); + exit(EXIT_FAILURE); + + } + if (start && retry) + ewarn("using --retry with --start has no effect," + " use --wait instead"); + + /* If we don't have a pidfile we should check if it's interpreted + * or not. If it we, we need to pass the interpreter through + * to our daemon calls to find it correctly. */ + if (interpreted && !pidfile) { + fp = fopen(exec_file, "r"); + if (fp) { + line = NULL; + if (getline(&line, &size, fp) == -1) + eerrorx("%s: %s", applet, strerror(errno)); + p = line; + fclose(fp); + if (p != NULL && line[0] == '#' && line[1] == '!') { + p = line + 2; + /* Strip leading spaces */ + while (*p == ' ' || *p == '\t') + p++; + /* Remove the trailing newline */ + len = strlen(p) - 1; + if (p[len] == '\n') + p[len] = '\0'; + token = strsep(&p, " "); + free(exec_file); + xasprintf(&exec_file, "%s", token); + opt = 0; + for (nav = argv; *nav; nav++) + opt++; + nav = xmalloc(sizeof(char *) * (opt + 3)); + nav[0] = exec_file; + len = 1; + if (p) + nav[len++] = p; + for (i = 0; i < opt; i++) + nav[i + len] = argv[i]; + nav[i + len] = NULL; + } + } + } + margv = nav ? nav : argv; + + if (stop || sig != -1) { + if (sig == -1) + sig = SIGTERM; + if (!stop) + oknodo = true; + if (retry) + parse_schedule(applet, retry, sig); + else if (test || oknodo) + parse_schedule(applet, "0", sig); + else + parse_schedule(applet, NULL, sig); + if (pidfile) { + pid = get_pid(applet, pidfile); + if (pid == -1) + exit(EXIT_FAILURE); + } else { + pid = 0; + } + i = run_stop_schedule(applet, exec, (const char *const *)margv, + pid, uid, test, progress, false); + + if (i < 0) + /* We failed to stop something */ + exit(EXIT_FAILURE); + if (test || oknodo) + return i > 0 ? EXIT_SUCCESS : EXIT_FAILURE; + + /* Even if we have not actually killed anything, we should + * remove information about it as it may have unexpectedly + * crashed out. We should also return success as the end + * result would be the same. */ + if (pidfile && exists(pidfile)) + unlink(pidfile); + if (svcname) + rc_service_daemon_set(svcname, exec, + (const char *const *)argv, + pidfile, false); + exit(EXIT_SUCCESS); + } + + if (pidfile) + pid = get_pid(applet, pidfile); + else + pid = 0; + + if (pid) + pids = rc_find_pids(NULL, NULL, 0, pid); + else + pids = rc_find_pids(exec, (const char * const *) argv, uid, 0); + if (pids) + eerrorx("%s: %s is already running", applet, exec); + + free(pids); + if (test) { + if (rc_yesno(getenv("EINFO_QUIET"))) + exit (EXIT_SUCCESS); + + einfon("Would start"); + while (argc-- > 0) + printf(" %s", *argv++); + printf("\n"); + eindent(); + if (uid != 0) + einfo("as user id %d", uid); + if (gid != 0) + einfo("as group id %d", gid); + if (ch_root) + einfo("in root `%s'", ch_root); + if (ch_dir) + einfo("in dir `%s'", ch_dir); + if (nicelevel != 0) + einfo("with a priority of %d", nicelevel); + if (name) + einfo ("with a process name of %s", name); + eoutdent(); + exit(EXIT_SUCCESS); + } + + ebeginv("Detaching to start `%s'", exec); + eindentv(); + + /* Remove existing pidfile */ + if (pidfile) + unlink(pidfile); + + if (background) + signal_setup(SIGCHLD, handle_signal); + + if ((pid = fork()) == -1) + eerrorx("%s: fork: %s", applet, strerror(errno)); + + /* Child process - lets go! */ + if (pid == 0) { + pid_t mypid = getpid(); + umask(numask); + +#ifdef TIOCNOTTY + tty_fd = open("/dev/tty", O_RDWR); +#endif + + devnull_fd = open("/dev/null", O_RDWR); + + if (nicelevel) { + if (setpriority(PRIO_PROCESS, mypid, nicelevel) == -1) + eerrorx("%s: setpritory %d: %s", + applet, nicelevel, + strerror(errno)); + } + + if (ionicec != -1 && + ioprio_set(1, mypid, ionicec | ioniced) == -1) + eerrorx("%s: ioprio_set %d %d: %s", applet, + ionicec, ioniced, strerror(errno)); + + if (ch_root && chroot(ch_root) < 0) + eerrorx("%s: chroot `%s': %s", + applet, ch_root, strerror(errno)); + + if (ch_dir && chdir(ch_dir) < 0) + eerrorx("%s: chdir `%s': %s", + applet, ch_dir, strerror(errno)); + + if (makepidfile && pidfile) { + fp = fopen(pidfile, "w"); + if (! fp) + eerrorx("%s: fopen `%s': %s", applet, pidfile, + strerror(errno)); + fprintf(fp, "%d\n", mypid); + fclose(fp); + } + +#ifdef HAVE_PAM + if (changeuser != NULL) { + pamr = pam_start("start-stop-daemon", + changeuser, &conv, &pamh); + + if (pamr == PAM_SUCCESS) + pamr = pam_acct_mgmt(pamh, PAM_SILENT); + if (pamr == PAM_SUCCESS) + pamr = pam_open_session(pamh, PAM_SILENT); + if (pamr != PAM_SUCCESS) + eerrorx("%s: pam error: %s", + applet, pam_strerror(pamh, pamr)); + } +#endif + + if (gid && setgid(gid)) + eerrorx("%s: unable to set groupid to %d", + applet, gid); + if (changeuser && initgroups(changeuser, gid)) + eerrorx("%s: initgroups (%s, %d)", + applet, changeuser, gid); + if (uid && setuid(uid)) + eerrorx ("%s: unable to set userid to %d", + applet, uid); + + /* Close any fd's to the passwd database */ + endpwent(); + +#ifdef TIOCNOTTY + ioctl(tty_fd, TIOCNOTTY, 0); + close(tty_fd); +#endif + + /* Clean the environment of any RC_ variables */ + env_list = rc_stringlist_new(); + i = 0; + while (environ[i]) + rc_stringlist_add(env_list, environ[i++]); + +#ifdef HAVE_PAM + if (changeuser != NULL) { + pamenv = (const char *const *)pam_getenvlist(pamh); + if (pamenv) { + while (*pamenv) { + /* Don't add strings unless they set a var */ + if (strchr(*pamenv, '=')) + putenv(xstrdup(*pamenv)); + else + unsetenv(*pamenv); + pamenv++; + } + } + } +#endif + + TAILQ_FOREACH(env, env_list, entries) { + if ((strncmp(env->value, "RC_", 3) == 0 && + strncmp(env->value, "RC_SERVICE=", 10) != 0 && + strncmp(env->value, "RC_SVCNAME=", 10) != 0) || + strncmp(env->value, "SSD_NICELEVEL=", 14) == 0 || + strncmp(env->value, "SSD_IONICELEVEL=", 16) == 0) + { + p = strchr(env->value, '='); + *p = '\0'; + unsetenv(env->value); + continue; + } + } + rc_stringlist_free(env_list); + + /* For the path, remove the rcscript bin dir from it */ + if ((token = getenv("PATH"))) { + len = strlen(token); + newpath = np = xmalloc(len + 1); + while (token && *token) { + p = strchr(token, ':'); + if (p) { + *p++ = '\0'; + while (*p == ':') + p++; + } + if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 && + strcmp(token, RC_LIBEXECDIR "/sbin") != 0) + { + len = strlen(token); + if (np != newpath) + *np++ = ':'; + memcpy(np, token, len); + np += len; + } + token = p; + } + *np = '\0'; + unsetenv("PATH"); + setenv("PATH", newpath, 1); + } + + stdin_fd = devnull_fd; + stdout_fd = devnull_fd; + stderr_fd = devnull_fd; + if (redirect_stdout) { + if ((stdout_fd = open(redirect_stdout, + O_WRONLY | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) + eerrorx("%s: unable to open the logfile" + " for stdout `%s': %s", + applet, redirect_stdout, strerror(errno)); + } + if (redirect_stderr) { + if ((stderr_fd = open(redirect_stderr, + O_WRONLY | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) + eerrorx("%s: unable to open the logfile" + " for stderr `%s': %s", + applet, redirect_stderr, strerror(errno)); + } + + if (background) + dup2(stdin_fd, STDIN_FILENO); + if (background || redirect_stdout || rc_yesno(getenv("EINFO_QUIET"))) + dup2(stdout_fd, STDOUT_FILENO); + if (background || redirect_stderr || rc_yesno(getenv("EINFO_QUIET"))) + dup2(stderr_fd, STDERR_FILENO); + + for (i = getdtablesize() - 1; i >= 3; --i) + close(i); + + setsid(); + execvp(exec, argv); +#ifdef HAVE_PAM + if (changeuser != NULL && pamr == PAM_SUCCESS) + pam_close_session(pamh, PAM_SILENT); +#endif + eerrorx("%s: failed to exec `%s': %s", + applet, exec,strerror(errno)); + } + + /* Parent process */ + if (!background) { + /* As we're not backgrounding the process, wait for our pid + * to return */ + i = 0; + spid = pid; + + do { + pid = waitpid(spid, &i, 0); + if (pid < 1) { + eerror("waitpid %d: %s", + spid, strerror(errno)); + return -1; + } + } while (!WIFEXITED(i) && !WIFSIGNALED(i)); + if (!WIFEXITED(i) || WEXITSTATUS(i) != 0) { + eerror("%s: failed to start `%s'", applet, exec); + exit(EXIT_FAILURE); + } + pid = spid; + } + + /* Wait a little bit and check that process is still running + We do this as some badly written daemons fork and then barf */ + if (start_wait == 0 && + ((p = getenv("SSD_STARTWAIT")) || + (p = rc_conf_value("rc_start_wait")))) + { + if (sscanf(p, "%u", &start_wait) != 1) + start_wait = 0; + } + + if (start_wait > 0) { + struct timespec ts; + bool alive = false; + + ts.tv_sec = start_wait / 1000; + ts.tv_nsec = (start_wait % 1000) * ONE_MS; + if (nanosleep(&ts, NULL) == -1) { + if (errno == EINTR) + eerror("%s: caught an interrupt", applet); + else { + eerror("%s: nanosleep: %s", + applet, strerror(errno)); + return 0; + } + } + if (background) { + if (kill(pid, 0) == 0) + alive = true; + } else { + if (pidfile) { + pid = get_pid(applet, pidfile); + if (pid == -1) { + eerrorx("%s: did not " + "create a valid" + " pid in `%s'", + applet, pidfile); + } + } else + pid = 0; + if (do_stop(applet, exec, (const char *const *)margv, + pid, uid, 0, test, false) > 0) + alive = true; + } + + if (!alive) + eerrorx("%s: %s died", applet, exec); + } + + if (svcname) + rc_service_daemon_set(svcname, exec, + (const char *const *)margv, pidfile, true); + + exit(EXIT_SUCCESS); + /* NOTREACHED */ +} Index: contrib/openrc/src/rc/start-stop-daemon.pam =================================================================== --- /dev/null +++ contrib/openrc/src/rc/start-stop-daemon.pam @@ -0,0 +1,6 @@ +#%PAM-1.0 + +auth required pam_permit.so +account required pam_permit.so +password required pam_deny.so +session optional pam_limits.so Index: contrib/openrc/src/rc/supervise-daemon.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/supervise-daemon.c @@ -0,0 +1,931 @@ +/* + * supervise-daemon + * This is an experimental supervisor for daemons. + * It will start a deamon and make sure it restarts if it crashes. + */ + +/* + * Copyright (c) 2016 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +/* nano seconds */ +#define POLL_INTERVAL 20000000 +#define WAIT_PIDFILE 500000000 +#define ONE_SECOND 1000000000 +#define ONE_MS 1000000 + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include /* For io priority */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_PAM +#include + +/* We are not supporting authentication conversations */ +static struct pam_conv conv = { NULL, NULL}; +#endif + +#include "einfo.h" +#include "queue.h" +#include "rc.h" +#include "rc-misc.h" +#include "rc-schedules.h" +#include "_usage.h" +#include "helpers.h" + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r:Su:1:2:3" \ + getoptstring_COMMON; +const struct option longopts[] = { + { "respawn-delay", 1, NULL, 'D'}, + { "chdir", 1, NULL, 'd'}, + { "env", 1, NULL, 'e'}, + { "group", 1, NULL, 'g'}, + { "ionice", 1, NULL, 'I'}, + { "stop", 0, NULL, 'K'}, + { "umask", 1, NULL, 'k'}, + { "respawn-max", 1, NULL, 'm'}, + { "nicelevel", 1, NULL, 'N'}, + { "pidfile", 1, NULL, 'p'}, + { "respawn-period", 1, NULL, 'P'}, + { "retry", 1, NULL, 'R'}, + { "chroot", 1, NULL, 'r'}, + { "start", 0, NULL, 'S'}, + { "user", 1, NULL, 'u'}, + { "stdout", 1, NULL, '1'}, + { "stderr", 1, NULL, '2'}, + { "reexec", 0, NULL, '3'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Set a respawn delay", + "Change the PWD", + "Set an environment string", + "Change the process group", + "Set an ionice class:data when starting", + "Stop daemon", + "Set the umask for the daemon", + "set maximum number of respawn attempts", + "Set a nicelevel when starting", + "Match pid found in this file", + "Set respawn time period", + "Retry schedule to use when stopping", + "Chroot to this directory", + "Start daemon", + "Change the process user", + "Redirect stdout to file", + "Redirect stderr to file", + "reexec (used internally)", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +static int nicelevel = 0; +static int ionicec = -1; +static int ioniced = 0; +static char *changeuser, *ch_root, *ch_dir; +static uid_t uid = 0; +static gid_t gid = 0; +static int devnull_fd = -1; +static int stdin_fd; +static int stdout_fd; +static int stderr_fd; +static char *redirect_stderr = NULL; +static char *redirect_stdout = NULL; +static bool exiting = false; +#ifdef TIOCNOTTY +static int tty_fd = -1; +#endif +static pid_t child_pid; +static int respawn_count = 0; +static int respawn_delay = 0; +static int respawn_max = 10; +static int respawn_period = 5; +static char *pidfile = NULL; +static char *svcname = NULL; + +extern char **environ; + +#if !defined(SYS_ioprio_set) && defined(__NR_ioprio_set) +# define SYS_ioprio_set __NR_ioprio_set +#endif +#if !defined(__DragonFly__) +static inline int ioprio_set(int which _unused, int who _unused, + int ioprio _unused) +{ +#ifdef SYS_ioprio_set + return syscall(SYS_ioprio_set, which, who, ioprio); +#else + return 0; +#endif +} +#endif + +static void cleanup(void) +{ + free(changeuser); +} + +static void re_exec_supervisor(void) +{ + syslog(LOG_WARNING, "Re-executing for %s", svcname); + execlp("supervise-daemon", "supervise-daemon", svcname, "--reexec", + (char *) NULL); + syslog(LOG_ERR, "Unable to execute supervise-daemon: %s", + strerror(errno)); + exit(EXIT_FAILURE); +} + +static void handle_signal(int sig) +{ + int serrno = errno; + + syslog(LOG_WARNING, "caught signal %d", sig); + + if (sig == SIGTERM) + exiting = true; + /* Restore errno */ + errno = serrno; + if (! exiting) + re_exec_supervisor(); +} + +static char * expand_home(const char *home, const char *path) +{ + char *opath, *ppath, *p, *nh; + size_t len; + struct passwd *pw; + + if (!path || *path != '~') + return xstrdup(path); + + opath = ppath = xstrdup(path); + if (ppath[1] != '/' && ppath[1] != '\0') { + p = strchr(ppath + 1, '/'); + if (p) + *p = '\0'; + pw = getpwnam(ppath + 1); + if (pw) { + home = pw->pw_dir; + ppath = p; + if (ppath) + *ppath = '/'; + } else + home = NULL; + } else + ppath++; + + if (!home) { + free(opath); + return xstrdup(path); + } + if (!ppath) { + free(opath); + return xstrdup(home); + } + + len = strlen(ppath) + strlen(home) + 1; + nh = xmalloc(len); + snprintf(nh, len, "%s%s", home, ppath); + free(opath); + return nh; +} + +static char *make_cmdline(char **argv) +{ + char **c; + char *cmdline = NULL; + size_t len = 0; + + for (c = argv; c && *c; c++) + len += (strlen(*c) + 1); + cmdline = xmalloc(len); + memset(cmdline, 0, len); + for (c = argv; c && *c; c++) { + strcat(cmdline, *c); + strcat(cmdline, " "); + } + return cmdline; +} + +static void child_process(char *exec, char **argv) +{ + RC_STRINGLIST *env_list; + RC_STRING *env; + int i; + char *p; + char *token; + size_t len; + char *newpath; + char *np; + char *cmdline = NULL; + time_t start_time; + char start_count_string[20]; + char start_time_string[20]; + +#ifdef HAVE_PAM + pam_handle_t *pamh = NULL; + int pamr; + const char *const *pamenv = NULL; +#endif + + setsid(); + + if (svcname) { + start_time = time(NULL); + from_time_t(start_time_string, start_time); + rc_service_value_set(svcname, "start_time", start_time_string); + sprintf(start_count_string, "%i", respawn_count); + rc_service_value_set(svcname, "start_count", start_count_string); + sprintf(start_count_string, "%d", getpid()); + rc_service_value_set(svcname, "child_pid", start_count_string); + } + + if (nicelevel) { + if (setpriority(PRIO_PROCESS, getpid(), nicelevel) == -1) + eerrorx("%s: setpriority %d: %s", applet, nicelevel, + strerror(errno)); + } + + if (ionicec != -1 && ioprio_set(1, getpid(), ionicec | ioniced) == -1) + eerrorx("%s: ioprio_set %d %d: %s", applet, ionicec, ioniced, + strerror(errno)); + + if (ch_root && chroot(ch_root) < 0) + eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno)); + + if (ch_dir && chdir(ch_dir) < 0) + eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno)); + +#ifdef HAVE_PAM + if (changeuser != NULL) { + pamr = pam_start("supervise-daemon", + changeuser, &conv, &pamh); + + if (pamr == PAM_SUCCESS) + pamr = pam_acct_mgmt(pamh, PAM_SILENT); + if (pamr == PAM_SUCCESS) + pamr = pam_open_session(pamh, PAM_SILENT); + if (pamr != PAM_SUCCESS) + eerrorx("%s: pam error: %s", applet, pam_strerror(pamh, pamr)); + } +#endif + + if (gid && setgid(gid)) + eerrorx("%s: unable to set groupid to %d", applet, gid); + if (changeuser && initgroups(changeuser, gid)) + eerrorx("%s: initgroups (%s, %d)", applet, changeuser, gid); + if (uid && setuid(uid)) + eerrorx ("%s: unable to set userid to %d", applet, uid); + + /* Close any fd's to the passwd database */ + endpwent(); + + /* remove the controlling tty */ +#ifdef TIOCNOTTY + ioctl(tty_fd, TIOCNOTTY, 0); + close(tty_fd); +#endif + + /* Clean the environment of any RC_ variables */ + env_list = rc_stringlist_new(); + i = 0; + while (environ[i]) + rc_stringlist_add(env_list, environ[i++]); + +#ifdef HAVE_PAM + if (changeuser != NULL) { + pamenv = (const char *const *)pam_getenvlist(pamh); + if (pamenv) { + while (*pamenv) { + /* Don't add strings unless they set a var */ + if (strchr(*pamenv, '=')) + putenv(xstrdup(*pamenv)); + else + unsetenv(*pamenv); + pamenv++; + } + } + } +#endif + + TAILQ_FOREACH(env, env_list, entries) { + if ((strncmp(env->value, "RC_", 3) == 0 && + strncmp(env->value, "RC_SERVICE=", 10) != 0 && + strncmp(env->value, "RC_SVCNAME=", 10) != 0) || + strncmp(env->value, "SSD_NICELEVEL=", 14) == 0) + { + p = strchr(env->value, '='); + *p = '\0'; + unsetenv(env->value); + continue; + } + } + rc_stringlist_free(env_list); + + /* For the path, remove the rcscript bin dir from it */ + if ((token = getenv("PATH"))) { + len = strlen(token); + newpath = np = xmalloc(len + 1); + while (token && *token) { + p = strchr(token, ':'); + if (p) { + *p++ = '\0'; + while (*p == ':') + p++; + } + if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 && + strcmp(token, RC_LIBEXECDIR "/sbin") != 0) + { + len = strlen(token); + if (np != newpath) + *np++ = ':'; + memcpy(np, token, len); + np += len; + } + token = p; + } + *np = '\0'; + unsetenv("PATH"); + setenv("PATH", newpath, 1); + } + + stdin_fd = devnull_fd; + stdout_fd = devnull_fd; + stderr_fd = devnull_fd; + if (redirect_stdout) { + if ((stdout_fd = open(redirect_stdout, + O_WRONLY | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR)) == -1) + eerrorx("%s: unable to open the logfile" + " for stdout `%s': %s", + applet, redirect_stdout, strerror(errno)); + } + if (redirect_stderr) { + if ((stderr_fd = open(redirect_stderr, + O_WRONLY | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR)) == -1) + eerrorx("%s: unable to open the logfile" + " for stderr `%s': %s", + applet, redirect_stderr, strerror(errno)); + } + + dup2(stdin_fd, STDIN_FILENO); + if (redirect_stdout || rc_yesno(getenv("EINFO_QUIET"))) + dup2(stdout_fd, STDOUT_FILENO); + if (redirect_stderr || rc_yesno(getenv("EINFO_QUIET"))) + dup2(stderr_fd, STDERR_FILENO); + + for (i = getdtablesize() - 1; i >= 3; --i) + fcntl(i, F_SETFD, FD_CLOEXEC); + cmdline = make_cmdline(argv); + syslog(LOG_INFO, "Child command line: %s", cmdline); + free(cmdline); + execvp(exec, argv); + +#ifdef HAVE_PAM + if (changeuser != NULL && pamr == PAM_SUCCESS) + pam_close_session(pamh, PAM_SILENT); +#endif + eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno)); +} + +static void supervisor(char *exec, char **argv) +{ + FILE *fp; + int i; + int nkilled; + time_t respawn_now= 0; + time_t first_spawn= 0; + +#ifndef RC_DEBUG + signal_setup_restart(SIGHUP, handle_signal); + signal_setup_restart(SIGINT, handle_signal); + signal_setup_restart(SIGQUIT, handle_signal); + signal_setup_restart(SIGILL, handle_signal); + signal_setup_restart(SIGABRT, handle_signal); + signal_setup_restart(SIGFPE, handle_signal); + signal_setup_restart(SIGSEGV, handle_signal); + signal_setup_restart(SIGPIPE, handle_signal); + signal_setup_restart(SIGALRM, handle_signal); + signal_setup(SIGTERM, handle_signal); + signal_setup_restart(SIGUSR1, handle_signal); + signal_setup_restart(SIGUSR2, handle_signal); + signal_setup_restart(SIGBUS, handle_signal); +#ifdef SIGPOLL + signal_setup_restart(SIGPOLL, handle_signal); +#endif + signal_setup_restart(SIGPROF, handle_signal); + signal_setup_restart(SIGSYS, handle_signal); + signal_setup_restart(SIGTRAP, handle_signal); + signal_setup_restart(SIGVTALRM, handle_signal); + signal_setup_restart(SIGXCPU, handle_signal); + signal_setup_restart(SIGXFSZ, handle_signal); +#ifdef SIGEMT + signal_setup_restart(SIGEMT, handle_signal); +#endif + signal_setup_restart(SIGIO, handle_signal); +#ifdef SIGPWR + signal_setup_restart(SIGPWR, handle_signal); +#endif +#ifdef SIGUNUSED + signal_setup_restart(SIGUNUSED, handle_signal); +#endif +#ifdef SIGRTMIN + for (i = SIGRTMIN; i <= SIGRTMAX; i++) + signal_setup_restart(i, handle_signal); +#endif +#endif + + fp = fopen(pidfile, "w"); + if (! fp) + eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); + fprintf(fp, "%d\n", getpid()); + fclose(fp); + + if (svcname) + rc_service_daemon_set(svcname, exec, (const char * const *) argv, + pidfile, true); + + /* remove the controlling tty */ +#ifdef TIOCNOTTY + ioctl(tty_fd, TIOCNOTTY, 0); + close(tty_fd); +#endif + + /* + * Supervisor main loop + */ + i = 0; + while (!exiting) { + wait(&i); + if (exiting) { + signal_setup(SIGCHLD, SIG_IGN); + syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid); + nkilled = run_stop_schedule(applet, exec, NULL, child_pid, 0, + false, false, true); + if (nkilled > 0) + syslog(LOG_INFO, "killed %d processes", nkilled); + } else { + sleep(respawn_delay); + if (respawn_max > 0 && respawn_period > 0) { + respawn_now = time(NULL); + if (first_spawn == 0) + first_spawn = respawn_now; + if (respawn_now - first_spawn > respawn_period) { + respawn_count = 0; + first_spawn = 0; + } else + respawn_count++; + if (respawn_count >= respawn_max) { + syslog(LOG_WARNING, + "respawned \"%s\" too many times, exiting", exec); + exiting = true; + continue; + } + } + if (WIFEXITED(i)) + syslog(LOG_WARNING, "%s, pid %d, exited with return code %d", + exec, child_pid, WEXITSTATUS(i)); + else if (WIFSIGNALED(i)) + syslog(LOG_WARNING, "%s, pid %d, terminated by signal %d", + exec, child_pid, WTERMSIG(i)); + child_pid = fork(); + if (child_pid == -1) + eerrorx("%s: fork: %s", applet, strerror(errno)); + if (child_pid == 0) + child_process(exec, argv); + } + } + + if (pidfile && exists(pidfile)) + unlink(pidfile); + if (svcname) { + rc_service_daemon_set(svcname, exec, (const char *const *)argv, + pidfile, false); + rc_service_mark(svcname, RC_SERVICE_STOPPED); + rc_service_value_set(svcname, "child_pid", NULL); + } + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + int opt; + char **c; + int x; + bool start = false; + bool stop = false; + bool reexec = false; + char *exec = NULL; + char *retry = NULL; + int sig = SIGTERM; + char *home = NULL; + int tid = 0; + pid_t pid; + char *tmp; + char *p; + char *token; + int i; + int n; + char *exec_file = NULL; + char *varbuf = NULL; + struct timespec ts; + struct passwd *pw; + struct group *gr; + FILE *fp; + mode_t numask = 022; + int child_argc = 0; + char **child_argv = NULL; + char *str = NULL; + char *cmdline = NULL; + + applet = basename_c(argv[0]); + atexit(cleanup); + svcname = getenv("RC_SVCNAME"); + if (!svcname) + eerrorx("%s: The RC_SVCNAME environment variable is not set", applet); + openlog(applet, LOG_PID, LOG_DAEMON); + + if (argc >= 1 && svcname && strcmp(argv[1], svcname)) + eerrorx("%s: the first argument must be %s", applet, svcname); + + if ((tmp = getenv("SSD_NICELEVEL"))) + if (sscanf(tmp, "%d", &nicelevel) != 1) + eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)", + applet, tmp); + + /* Get our user name and initial dir */ + p = getenv("USER"); + home = getenv("HOME"); + if (home == NULL || p == NULL) { + pw = getpwuid(getuid()); + if (pw != NULL) { + if (p == NULL) + setenv("USER", pw->pw_name, 1); + if (home == NULL) { + setenv("HOME", pw->pw_dir, 1); + home = pw->pw_dir; + } + } + } + + cmdline = make_cmdline(argv); + if (svcname) { + argc--; + argv++; + } + while ((opt = getopt_long(argc, argv, getoptstring, longopts, + (int *) 0)) != -1) + switch (opt) { + case 'D': /* --respawn-delay time */ + n = sscanf(optarg, "%d", &respawn_delay); + if (n != 1 || respawn_delay < 1) + eerrorx("Invalid respawn-delay value '%s'", optarg); + break; + + case 'I': /* --ionice */ + if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0) + eerrorx("%s: invalid ionice `%s'", + applet, optarg); + if (ionicec == 0) + ioniced = 0; + else if (ionicec == 3) + ioniced = 7; + ionicec <<= 13; /* class shift */ + break; + + case 'K': /* --stop */ + stop = true; + break; + + case 'N': /* --nice */ + if (sscanf(optarg, "%d", &nicelevel) != 1) + eerrorx("%s: invalid nice level `%s'", + applet, optarg); + break; + + case 'P': /* --respawn-period time */ + n = sscanf(optarg, "%d", &respawn_period); + if (n != 1 || respawn_period < 1) + eerrorx("Invalid respawn-period value '%s'", optarg); + break; + + case 'S': /* --start */ + start = true; + break; + + case 'd': /* --chdir /new/dir */ + ch_dir = optarg; + break; + + case 'e': /* --env */ + putenv(optarg); + break; + + case 'g': /* --group | */ + if (sscanf(optarg, "%d", &tid) != 1) + gr = getgrnam(optarg); + else + gr = getgrgid((gid_t)tid); + if (gr == NULL) + eerrorx("%s: group `%s' not found", + applet, optarg); + gid = gr->gr_gid; + break; + + case 'k': + if (parse_mode(&numask, optarg)) + eerrorx("%s: invalid mode `%s'", + applet, optarg); + break; + + case 'm': /* --respawn-max count */ + n = sscanf(optarg, "%d", &respawn_max); + if (n != 1 || respawn_max < 1) + eerrorx("Invalid respawn-max value '%s'", optarg); + break; + + case 'p': /* --pidfile */ + pidfile = optarg; + break; + + case 'R': /* --retry |timeout */ + retry = optarg; + break; + case 'r': /* --chroot /new/root */ + ch_root = optarg; + break; + + case 'u': /* --user | */ + { + p = optarg; + tmp = strsep(&p, ":"); + changeuser = xstrdup(tmp); + if (sscanf(tmp, "%d", &tid) != 1) + pw = getpwnam(tmp); + else + pw = getpwuid((uid_t)tid); + + if (pw == NULL) + eerrorx("%s: user `%s' not found", + applet, tmp); + uid = pw->pw_uid; + home = pw->pw_dir; + unsetenv("HOME"); + if (pw->pw_dir) + setenv("HOME", pw->pw_dir, 1); + unsetenv("USER"); + if (pw->pw_name) + setenv("USER", pw->pw_name, 1); + if (gid == 0) + gid = pw->pw_gid; + + if (p) { + tmp = strsep (&p, ":"); + if (sscanf(tmp, "%d", &tid) != 1) + gr = getgrnam(tmp); + else + gr = getgrgid((gid_t) tid); + + if (gr == NULL) + eerrorx("%s: group `%s'" + " not found", + applet, tmp); + gid = gr->gr_gid; + } + } + break; + + case '1': /* --stdout /path/to/stdout.lgfile */ + redirect_stdout = optarg; + break; + + case '2': /* --stderr /path/to/stderr.logfile */ + redirect_stderr = optarg; + break; + case '3': /* --reexec */ + reexec = true; + break; + + case_RC_COMMON_GETOPT + } + + if (!pidfile && !reexec) + eerrorx("%s: --pidfile must be specified", applet); + endpwent(); + argc -= optind; + argv += optind; + exec = *argv; + + /* Expand ~ */ + if (ch_dir && *ch_dir == '~') + ch_dir = expand_home(home, ch_dir); + if (ch_root && *ch_root == '~') + ch_root = expand_home(home, ch_root); + + umask(numask); + + if (reexec) { + str = rc_service_value_get(svcname, "argc"); + sscanf(str, "%d", &child_argc); + child_argv = xmalloc((child_argc + 1) * sizeof(char *)); + memset(child_argv, 0, (child_argc + 1) * sizeof(char *)); + for (x = 0; x < child_argc; x++) { + xasprintf(&varbuf, "argv_%d", x); + str = rc_service_value_get(svcname, varbuf); + child_argv[x] = str; + free(varbuf); + varbuf = NULL; + } + free(str); + str = rc_service_value_get(svcname, "child_pid"); + sscanf(str, "%d", &child_pid); + free(str); + exec = rc_service_value_get(svcname, "exec"); + pidfile = rc_service_value_get(svcname, "pidfile"); + retry = rc_service_value_get(svcname, "retry"); + if (retry) { + parse_schedule(applet, retry, sig); + rc_service_value_set(svcname, "retry", retry); + } else + parse_schedule(applet, NULL, sig); + + str = rc_service_value_get(svcname, "respawn_delay"); + sscanf(str, "%d", &respawn_delay); + str = rc_service_value_get(svcname, "respawn_max"); + sscanf(str, "%d", &respawn_max); + supervisor(exec, child_argv); + } else if (start) { + if (exec) { + if (*exec == '~') + exec = expand_home(home, exec); + + /* Validate that the binary exists if we are starting */ + if (*exec == '/' || *exec == '.') { + /* Full or relative path */ + if (ch_root) + xasprintf(&exec_file, "%s/%s", ch_root, exec); + else + xasprintf(&exec_file, "%s", exec); + } else { + /* Something in $PATH */ + p = tmp = xstrdup(getenv("PATH")); + exec_file = NULL; + while ((token = strsep(&p, ":"))) { + if (ch_root) + xasprintf(&exec_file, "%s/%s/%s", ch_root, token, exec); + else + xasprintf(&exec_file, "%s/%s", token, exec); + if (exec_file && exists(exec_file)) + break; + free(exec_file); + exec_file = NULL; + } + free(tmp); + } + if (!exists(exec_file)) { + eerror("%s: %s does not exist", applet, + *exec_file ? exec_file : exec); + free(exec_file); + exit(EXIT_FAILURE); + } + } else + eerrorx("%s: nothing to start", applet); + + pid = get_pid(applet, pidfile); + if (pid != -1) + if (do_stop(applet, exec, (const char * const *)argv, pid, uid, + 0, false, true) > 0) + eerrorx("%s: %s is already running", applet, exec); + + if (respawn_delay * respawn_max > respawn_period) + ewarn("%s: Please increase the value of --respawn-period to more " + "than %d to avoid infinite respawning", applet, + respawn_delay * respawn_max); + + if (retry) { + parse_schedule(applet, retry, sig); + rc_service_value_set(svcname, "retry", retry); + } else + parse_schedule(applet, NULL, sig); + + einfov("Detaching to start `%s'", exec); + syslog(LOG_INFO, "Supervisor command line: %s", cmdline); + free(cmdline); + cmdline = NULL; + + /* Remove existing pidfile */ + if (pidfile) + unlink(pidfile); + + /* Make sure we can write a pid file */ + fp = fopen(pidfile, "w"); + if (! fp) + eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); + fclose(fp); + + rc_service_value_set(svcname, "pidfile", pidfile); + varbuf = NULL; + xasprintf(&varbuf, "%i", respawn_delay); + rc_service_value_set(svcname, "respawn_delay", varbuf); + xasprintf(&varbuf, "%i", respawn_max); + rc_service_value_set(svcname, "respawn_max", varbuf); + xasprintf(&varbuf, "%i", respawn_period); + rc_service_value_set(svcname, "respawn_period", varbuf); + child_pid = fork(); + if (child_pid == -1) + eerrorx("%s: fork: %s", applet, strerror(errno)); + if (child_pid != 0) + /* first parent process, do nothing. */ + exit(EXIT_SUCCESS); +#ifdef TIOCNOTTY + tty_fd = open("/dev/tty", O_RDWR); +#endif + devnull_fd = open("/dev/null", O_RDWR); + child_pid = fork(); + if (child_pid == -1) + eerrorx("%s: fork: %s", applet, strerror(errno)); + else if (child_pid != 0) { + c = argv; + x = 0; + while (c && *c) { + varbuf = NULL; + xasprintf(&varbuf, "argv_%-d",x); + rc_service_value_set(svcname, varbuf, *c); + free(varbuf); + varbuf = NULL; + x++; + c++; + } + xasprintf(&varbuf, "%d", x); + rc_service_value_set(svcname, "argc", varbuf); + rc_service_value_set(svcname, "exec", exec); + supervisor(exec, argv); + } else + child_process(exec, argv); + } else if (stop) { + pid = get_pid(applet, pidfile); + if (pid != -1) { + i = kill(pid, SIGTERM); + if (i != 0) + /* We failed to send the signal */ + ewarn("Unable to shut down the supervisor"); + else { + /* wait for the supervisor to go down */ + while (kill(pid, 0) == 0) { + ts.tv_sec = 0; + ts.tv_nsec = 1; + nanosleep(&ts, NULL); + } + } + } + + /* Even if we have not actually killed anything, we should + * remove information about it as it may have unexpectedly + * crashed out. We should also return success as the end + * result would be the same. */ + if (pidfile && exists(pidfile)) + unlink(pidfile); + if (svcname) { + rc_service_daemon_set(svcname, exec, + (const char *const *)argv, + pidfile, false); + rc_service_mark(svcname, RC_SERVICE_STOPPED); + } + exit(EXIT_SUCCESS); + } +} Index: contrib/openrc/src/rc/supervise-daemon.pam =================================================================== --- /dev/null +++ contrib/openrc/src/rc/supervise-daemon.pam @@ -0,0 +1,6 @@ +#%PAM-1.0 + +auth required pam_permit.so +account required pam_permit.so +password required pam_deny.so +session optional pam_limits.so Index: contrib/openrc/src/rc/swclock.c =================================================================== --- /dev/null +++ contrib/openrc/src/rc/swclock.c @@ -0,0 +1,106 @@ +/* + * swclock.c + * Sets the system time from the mtime of the given file. + * This is useful for systems who do not have a working RTC and rely on ntp. + * OpenRC relies on the correct system time for a lot of operations + * so this is needed quite early. + */ + +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +#define RC_SHUTDOWNTIME RC_SVCDIR "/shutdowntime" + +const char *applet = NULL; +const char *extraopts = "file"; +const char *getoptstring = "sw" getoptstring_COMMON; +const struct option longopts[] = { + { "save", 0, NULL, 's' }, + { "warn", 0, NULL, 'w' }, + longopts_COMMON +}; +const char * const longopts_help[] = { + "saves the time", + "no error if no reference file", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +int main(int argc, char **argv) +{ + int opt, sflag = 0, wflag = 0; + const char *file = RC_SHUTDOWNTIME; + struct stat sb; + struct timeval tv; + + applet = basename_c(argv[0]); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 's': + sflag = 1; + break; + case 'w': + wflag = 1; + break; + case_RC_COMMON_GETOPT + } + } + + if (optind < argc) + file = argv[optind++]; + + if (sflag) { + if (stat(file, &sb) == -1) { + opt = open(file, O_WRONLY | O_CREAT, 0644); + if (opt == -1) + eerrorx("swclock: open: %s", strerror(errno)); + close(opt); + } else + if (utime(file, NULL) == -1) + eerrorx("swclock: utime: %s", strerror(errno)); + return 0; + } + + if (stat(file, &sb) == -1) { + if (wflag != 0 && errno == ENOENT) + ewarn("swclock: `%s': %s", file, strerror(errno)); + else + eerrorx("swclock: `%s': %s", file, strerror(errno)); + return 0; + } + + tv.tv_sec = sb.st_mtime; + tv.tv_usec = 0; + + if (settimeofday(&tv, NULL) == -1) + eerrorx("swclock: settimeofday: %s", strerror(errno)); + + return 0; +} Index: contrib/openrc/src/test/Makefile =================================================================== --- /dev/null +++ contrib/openrc/src/test/Makefile @@ -0,0 +1,14 @@ +all: + +install: + +ignore: + +check test:: + ./runtests.sh + +verbose-test: + VERBOSE=yes ./runtests.sh + +clean: + rm -rf *.out tmp-* Index: contrib/openrc/src/test/einfo.data.list =================================================================== --- /dev/null +++ contrib/openrc/src/test/einfo.data.list @@ -0,0 +1 @@ +EINFO_1.0 Index: contrib/openrc/src/test/einfo.funcs.list =================================================================== --- /dev/null +++ contrib/openrc/src/test/einfo.funcs.list @@ -0,0 +1,52 @@ +ebegin +ebegin@@EINFO_1.0 +ebeginv +ebeginv@@EINFO_1.0 +ebracket +ebracket@@EINFO_1.0 +ecolor +ecolor@@EINFO_1.0 +eend +eend@@EINFO_1.0 +eendv +eendv@@EINFO_1.0 +eerror +eerror@@EINFO_1.0 +eerrorn +eerrorn@@EINFO_1.0 +eerrorx +eerrorx@@EINFO_1.0 +eindent +eindent@@EINFO_1.0 +eindentv +eindentv@@EINFO_1.0 +einfo +einfo@@EINFO_1.0 +einfon +einfon@@EINFO_1.0 +einfov +einfov@@EINFO_1.0 +einfovn +einfovn@@EINFO_1.0 +elog +elog@@EINFO_1.0 +eoutdent +eoutdent@@EINFO_1.0 +eoutdentv +eoutdentv@@EINFO_1.0 +eprefix +eprefix@@EINFO_1.0 +ewarn +ewarn@@EINFO_1.0 +ewarnn +ewarnn@@EINFO_1.0 +ewarnv +ewarnv@@EINFO_1.0 +ewarnvn +ewarnvn@@EINFO_1.0 +ewarnx +ewarnx@@EINFO_1.0 +ewend +ewend@@EINFO_1.0 +ewendv +ewendv@@EINFO_1.0 Index: contrib/openrc/src/test/rc.data.list =================================================================== --- /dev/null +++ contrib/openrc/src/test/rc.data.list @@ -0,0 +1,3 @@ +RC_1.0 +rc_environ_fd +rc_environ_fd@@RC_1.0 Index: contrib/openrc/src/test/rc.funcs.list =================================================================== --- /dev/null +++ contrib/openrc/src/test/rc.funcs.list @@ -0,0 +1,116 @@ +rc_conf_value +rc_conf_value@@RC_1.0 +rc_config_list +rc_config_list@@RC_1.0 +rc_config_load +rc_config_load@@RC_1.0 +rc_config_value +rc_config_value@@RC_1.0 +rc_deptree_depend +rc_deptree_depend@@RC_1.0 +rc_deptree_depends +rc_deptree_depends@@RC_1.0 +rc_deptree_free +rc_deptree_free@@RC_1.0 +rc_deptree_load +rc_deptree_load@@RC_1.0 +rc_deptree_load_file +rc_deptree_load_file@@RC_1.0 +rc_deptree_order +rc_deptree_order@@RC_1.0 +rc_deptree_update +rc_deptree_update@@RC_1.0 +rc_deptree_update_needed +rc_deptree_update_needed@@RC_1.0 +rc_find_pids +rc_find_pids@@RC_1.0 +rc_getfile +rc_getfile@@RC_1.0 +rc_getline +rc_getline@@RC_1.0 +rc_newer_than +rc_newer_than@@RC_1.0 +rc_older_than +rc_older_than@@RC_1.0 +rc_proc_getent +rc_proc_getent@@RC_1.0 +rc_runlevel_exists +rc_runlevel_exists@@RC_1.0 +rc_runlevel_get +rc_runlevel_get@@RC_1.0 +rc_runlevel_list +rc_runlevel_list@@RC_1.0 +rc_runlevel_set +rc_runlevel_set@@RC_1.0 +rc_runlevel_stack +rc_runlevel_stack@@RC_1.0 +rc_runlevel_stacks +rc_runlevel_stacks@@RC_1.0 +rc_runlevel_starting +rc_runlevel_starting@@RC_1.0 +rc_runlevel_stopping +rc_runlevel_stopping@@RC_1.0 +rc_runlevel_unstack +rc_runlevel_unstack@@RC_1.0 +rc_service_add +rc_service_add@@RC_1.0 +rc_service_daemon_set +rc_service_daemon_set@@RC_1.0 +rc_service_daemons_crashed +rc_service_daemons_crashed@@RC_1.0 +rc_service_delete +rc_service_delete@@RC_1.0 +rc_service_description +rc_service_description@@RC_1.0 +rc_service_exists +rc_service_exists@@RC_1.0 +rc_service_extra_commands +rc_service_extra_commands@@RC_1.0 +rc_service_in_runlevel +rc_service_in_runlevel@@RC_1.0 +rc_service_mark +rc_service_mark@@RC_1.0 +rc_service_resolve +rc_service_resolve@@RC_1.0 +rc_service_schedule_clear +rc_service_schedule_clear@@RC_1.0 +rc_service_schedule_start +rc_service_schedule_start@@RC_1.0 +rc_service_started_daemon +rc_service_started_daemon@@RC_1.0 +rc_service_state +rc_service_state@@RC_1.0 +rc_service_value_get +rc_service_value_get@@RC_1.0 +rc_service_value_set +rc_service_value_set@@RC_1.0 +rc_services_in_runlevel +rc_services_in_runlevel@@RC_1.0 +rc_services_in_runlevel_stacked +rc_services_in_runlevel_stacked@@RC_1.0 +rc_services_in_state +rc_services_in_state@@RC_1.0 +rc_services_scheduled +rc_services_scheduled@@RC_1.0 +rc_services_scheduled_by +rc_services_scheduled_by@@RC_1.0 +rc_stringlist_add +rc_stringlist_add@@RC_1.0 +rc_stringlist_addu +rc_stringlist_addu@@RC_1.0 +rc_stringlist_delete +rc_stringlist_delete@@RC_1.0 +rc_stringlist_find +rc_stringlist_find@@RC_1.0 +rc_stringlist_free +rc_stringlist_free@@RC_1.0 +rc_stringlist_new +rc_stringlist_new@@RC_1.0 +rc_stringlist_sort +rc_stringlist_sort@@RC_1.0 +rc_stringlist_split +rc_stringlist_split@@RC_1.0 +rc_sys +rc_sys@@RC_1.0 +rc_yesno +rc_yesno@@RC_1.0 Index: contrib/openrc/src/test/runtests.sh =================================================================== --- /dev/null +++ contrib/openrc/src/test/runtests.sh @@ -0,0 +1,127 @@ +#!/bin/sh + +top_srcdir=${top_srcdir:-../..} +. ${top_srcdir}/test/setup_env.sh + +libeinfo_srcdir="${srcdir}/../libeinfo" +libeinfo_builddir="${builddir}/../libeinfo" +librc_srcdir="${srcdir}/../librc" +librc_builddir="${builddir}/../librc" +rc_srcdir="${srcdir}/../rc" +rc_builddir="${builddir}/../rc" + +checkit() { + local base=$1; shift + echo "$@" | tr ' ' '\n' > ${base}.out + diff -u ${base}.list ${base}.out + eend $? + : $(( ret += $? )) +} + +ret=0 + +ebegin "Checking exported symbols in libeinfo.so (data)" +checkit einfo.data $( +readelf -Ws ${libeinfo_builddir}/libeinfo.so \ + | awk '$4 == "OBJECT" && $5 == "GLOBAL" && $7 != "UND" {print $NF}' \ + | LC_ALL=C sort -u +) + +ebegin "Checking exported symbols in libeinfo.so (functions)" +checkit einfo.funcs $( +readelf -Ws ${libeinfo_builddir}/libeinfo.so \ + | awk '$4 == "FUNC" && $5 == "GLOBAL" && $7 != "UND" {print $NF}' \ + | LC_ALL=C sort -u \ + | egrep -v \ + -e '^_(init|fini)$' +) + +ebegin "Checking exported symbols in librc.so (data)" +checkit rc.data $( +readelf -Ws ${librc_builddir}/librc.so \ + | awk '$4 == "OBJECT" && $5 == "GLOBAL" && $7 != "UND" {print $NF}' \ + | LC_ALL=C sort -u +) + +ebegin "Checking exported symbols in librc.so (functions)" +checkit rc.funcs $( +readelf -Ws ${librc_builddir}/librc.so \ + | awk '$4 == "FUNC" && $5 == "GLOBAL" && $7 != "UND" {print $NF}' \ + | LC_ALL=C sort -u \ + | egrep -v \ + -e '^_(init|fini)$' +) + +ebegin "Checking hidden functions in librc.so" +sed -n '/^librc_hidden_proto/s:.*(\(.*\))$:\1:p' ${librc_srcdir}/librc.h \ + | LC_ALL=C sort -u \ + > librc.funcs.hidden.list +readelf -Wr $(grep -l '#include[[:space:]]"librc\.h"' ${librc_srcdir}/*.c | sed 's:\.c$:.o:') \ + | egrep -v -e 'R_PARISC_(DP|SEG)REL' \ + | awk '$5 ~ /^rc_/ {print $5}' \ + | LC_ALL=C sort -u \ + | egrep -v '^rc_environ_fd$' \ + > librc.funcs.hidden.out +syms=$(diff -u librc.funcs.hidden.list librc.funcs.hidden.out | sed -n '/^+[^+]/s:^+::p') +[ -z "${syms}" ] +eend $? "Missing hidden defs:"$'\n'"${syms}" +: $(( ret += $? )) + +ebegin "Checking trailing whitespace in code" +# XXX: Should we check man pages too ? +out=$(cd ${top_srcdir}; find */ \ + '(' -name '*.[ch]' -o -name '*.in' -o -name '*.sh' ')' \ + -exec grep -n -E '[[:space:]]+$' {} +) +[ -z "${out}" ] +eend $? "Trailing whitespace needs to be deleted:"$'\n'"${out}" + +ebegin "Checking trailing newlines in code" +out=$(cd ${top_srcdir}; + for f in `find */ -name '*.[ch]'` ; do + sed -n -e :a -e '/^\n*$/{$q1;N;ba' -e '}' $f || echo $f + done) +[ -z "${out}" ] +eend $? "Trailing newlines need to be deleted:"$'\n'"${out}" + +ebegin "Checking for obsolete functions" +out=$(cd ${top_srcdir}; find src -name '*.[ch]' \ + ! -name queue.h \ + -exec grep -n -E '\<(malloc|memory|sys/(errno|fcntl|signal|stropts|termios|unistd))\.h\>' {} +) +[ -z "${out}" ] +eend $? "Avoid these obsolete functions:"$'\n'"${out}" + +ebegin "Checking for x* func usage" +out=$(cd ${top_srcdir}; find src -name '*.[ch]' \ + ! -name queue.h \ + -exec grep -n -E '\<(malloc|strdup)[[:space:]]*\(' {} + \ + | grep -v \ + -e src/includes/helpers.h \ + -e src/libeinfo/libeinfo.c) +[ -z "${out}" ] +eend $? "These need to be using the x* variant:"$'\n'"${out}" + +ebegin "Checking spacing style" +out=$(cd ${top_srcdir}; find src -name '*.[ch]' \ + ! -name queue.h \ + -exec grep -n -E \ + -e '\<(for|if|switch|while)\(' \ + -e '\<(for|if|switch|while) \( ' \ + -e ' ;' \ + -e '[[:space:]]$' \ + -e '\){' \ + -e '(^|[^:])//' \ + {} +) +[ -z "${out}" ] +eend $? "These lines violate style rules:"$'\n'"${out}" + +einfo "Running unit tests" +eindent +for u in units/*; do + [ -x "${u}" -a -f "${u}" ] || continue + ebegin "$(basename "${u}")" + ./"${u}" + eend $? + : $(( ret += $? )) +done + +exit ${ret} Index: contrib/openrc/src/test/units/is_older_than =================================================================== --- /dev/null +++ contrib/openrc/src/test/units/is_older_than @@ -0,0 +1,83 @@ +#!/bin/sh +# unit test for is_older_than code of baselayout (2008/06/19) +# Author: Matthias Schwarzott + +TMPDIR=tmp-"$(basename "$0")" + +# Please note that we added this unit test because the function +# should really be called is_newer_than as it's what it's really testing. +# Or more perversly, returning 0 on failure and 1 and success. + +# bool is_older_than(reference, files/dirs to check) +# +# return 0 if any of the files/dirs are newer than +# the reference file +# +# EXAMPLE: if is_older_than a.out *.o ; then ... +ref_is_older_than() +{ + local x= ref="$1" + shift + + for x; do + [ "${x}" -nt "${ref}" ] && return 0 + if [ -d "${x}" ]; then + ref_is_older_than "${ref}" "${x}"/* && return 0 + fi + done + return 1 +} + +do_test() +{ + local r1= r2= + + ref_is_older_than "$@" + r1=$? + is_older_than "$@" + r2=$? + + [ -n "${VERBOSE}" ] && echo "reference = $r1 | OpenRC = $r2" + [ $r1 = $r2 ] +} + +echo_cmd() +{ + [ -n "${VERBOSE}" ] && echo "$@" + "$@" +} + +test_it() +{ + do_test "${TMPDIR}"/ref "${TMPDIR}"/dir1 "${TMPDIR}"/dir2 +} + +run_test() +{ + echo_cmd mkdir -p "${TMPDIR}"/dir1 "${TMPDIR}"/dir2 + echo_cmd touch "${TMPDIR}"/dir1/f1 "${TMPDIR}"/dir1/f2 \ + "${TMPDIR}"/dir1/f3 "${TMPDIR}"/dir2/f1 \ + "${TMPDIR}"/dir2/f2 "${TMPDIR}"/dir2/f3 + echo_cmd sleep 1 + echo_cmd touch "${TMPDIR}"/ref + test_it || return 1 + + echo_cmd sleep 1 + echo_cmd touch "${TMPDIR}"/dir1/f2 + test_it || return 1 + + echo_cmd sleep 1 + echo_cmd touch "${TMPDIR}"/ref + test_it || return 1 + + echo_cmd sleep 1 + echo_cmd touch "${TMPDIR}"/dir2/f2 + test_it || return 1 +} + +rm -rf "${TMPDIR}" +mkdir "${TMPDIR}" +run_test +retval=$? +rm -rf "${TMPDIR}" +exit ${retval} Index: contrib/openrc/supervise-daemon-guide.md =================================================================== --- /dev/null +++ contrib/openrc/supervise-daemon-guide.md @@ -0,0 +1,50 @@ +Using supervise-daemon +====================== + +Beginning with OpenRC-0.21 we have our own daemon supervisor, +supervise-daemon., which can start a daemon and restart it if it +terminates unexpectedly. + +The following is a brief guide on using this capability. + +## Use Default start, stop and status functions + +If you write your own start, stop and status functions in your service +script, none of this will work. You must allow OpenRC to use the default +functions. + +## Daemons must not fork + +Any deamon that you would like to have monitored by supervise-daemon +must not fork. Instead, it must stay in the foreground. If the daemon +itself forks, the supervisor will be unable to monitor it. + +If the daemon can be configured to not fork, this should be done in the +daemon's configuration file, or by adding a command line option that +instructs it not to fork to the command_args_foreground variable shown +below. + +## Variable Settings + +The most important setting is the supervisor variable. At the top of +your service script, you should set this variable as follows: + +supervisor=supervise-daemon + +Several other variables affect the way services behave under +supervise-daemon. They are documented on the openrc-run man page, but I +will list them here for convenience: + +pidfile=/pid/of/supervisor.pid + +If you are using start-stop-daemon to monitor your scripts, the pidfile +is the path to the pidfile the daemon creates. If, on the other hand, +you are using supervise-daemon, this is the path to the pidfile the +supervisor creates. + +command_args_foreground should be used if the daemon you want to monitor +forks and goes to the background by default. This should be set to the +command line option that instructs the daemon to stay in the foreground. + +This is very early support, so feel free to file bugs if you have +issues. Index: contrib/openrc/support/Makefile =================================================================== --- /dev/null +++ contrib/openrc/support/Makefile @@ -0,0 +1,20 @@ +# Copyright (c) 2017 the OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +MK= ../mk +include ${MK}/os.mk + +SUBDIR= deptree2dot init.d.examples openvpn + +ifeq (${OS},Linux) +SUBDIR+= sysvinit +endif + +include ${MK}/subdir.mk Index: contrib/openrc/support/deptree2dot/Makefile =================================================================== --- /dev/null +++ contrib/openrc/support/deptree2dot/Makefile @@ -0,0 +1,9 @@ +MK= ../../mk +include ${MK}/os.mk + +DIR= ${DATADIR}/support/deptree2dot +BIN= deptree2dot +INC= README.md + + +include ${MK}/scripts.mk Index: contrib/openrc/support/init.d.examples/Makefile =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/Makefile @@ -0,0 +1,11 @@ +DIR= ${DATADIR}/support/init.d.examples +INC= README.md +SRCS= avahi-dnsconfd.in avahid.in dhcpcd.in dbus.in \ + hald.in named.in ntpd.in \ + openvpn.in polkitd.in sshd.in wpa_supplicant.in +BIN= ${OBJS} + +MK= ../../mk + +include ${MK}/os.mk +include ${MK}/scripts.mk Index: contrib/openrc/support/init.d.examples/avahi-dnsconfd.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/avahi-dnsconfd.in @@ -0,0 +1,22 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=@PKG_PREFIX@/sbin/avahi-dnsconfd +command_args="$avahi_dnsconfd_args -D" +pidfile=/var/run/avahi-dnsconfd.pid +name="Avahi DNS Configuration Daemon" + +depend() +{ + use dns + need localmount dbus + after bootmisc +} Index: contrib/openrc/support/init.d.examples/avahid.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/avahid.in @@ -0,0 +1,22 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=@PKG_PREFIX@/sbin/avahi-daemon +command_args="$avahid_args -D" +pidfile=/var/run/avahi-daemon/pid +name="Avahi Service Advertisement Daemon" + +depend() +{ + use dns + need localmount dbus + after bootmisc +} Index: contrib/openrc/support/init.d.examples/dbus.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/dbus.in @@ -0,0 +1,26 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=@PKG_PREFIX@/bin/dbus-daemon +pidfile=/var/run/dbus/pid +command_args="${dbusd_args---system}" +name="Message Bus Daemon" + +depend() +{ + need localmount net + after bootmisc +} + +start_pre() +{ + mkdir -p $(dirname $pidfile) +} Index: contrib/openrc/support/init.d.examples/dhcpcd.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/dhcpcd.in @@ -0,0 +1,34 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/sbin/dhcpcd +pidfile=/var/run/dhcpcd.pid +command_args=-q +name="DHCP Client Daemon" + +depend() +{ + provide net + need localmount + use logger + after bootmisc modules + before dns +} + +stop_pre() +{ + # When shutting down, kill dhcpcd but preserve network + # We do this as /var/run/dhcpcd could be cleaned out when we + # return to multiuser. + if yesno $RC_GOINGDOWN; then + : ${stopsig:=SIGKILL} + fi +} Index: contrib/openrc/support/init.d.examples/dnsmasq.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/dnsmasq.in @@ -0,0 +1,31 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=@PKG_PREFIX@/sbin/dnsmasq +command_args=$dnsmasq_args +pidfile=/var/run/dnsmasq.pid +required_files=/etc/dnsmasq.conf + +extra_started_commands="reload" + +depend() +{ + provide dns + need localmount net + after bootmisc +} + +reload() +{ + ebegin "Reloading $RC_SVCNAME" + start-stop-daemon --signal SIGHUP --pidfile "$pidfile" + eend $? +} Index: contrib/openrc/support/init.d.examples/hald.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/hald.in @@ -0,0 +1,20 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=@PKG_PREFIX@/sbin/hald +pidfile=/var/run/hald/hald.pid +command_args=$hald_args +name="Hardware Abstraction Layer Daemon" + +depend() +{ + need dbus +} Index: contrib/openrc/support/init.d.examples/named.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/named.in @@ -0,0 +1,119 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/named +command_args=$named_args +pidfile=/var/run/named.pid +name="Domain Name server" +extra_started_commands="reload" + +namedb=/etc/namedb +uid=named +case "$RC_UNAME" in + FreeBSD) + uid=bind + pidfile=/var/run/named/pid + ;; + Linux) + uid=bind + ;; +esac +: ${named_uid:=${uid}} + +depend() +{ + provide dns + need localmount + after bootmisc +} + +start_pre() +{ + if [ -n "$named_chroot" ]; then + # Create (or update) the chroot directory structure + if [ -r /etc/mtree/BIND.chroot.dist ]; then + mtree -deU -f /etc/mtree/BIND.chroot.dist -p "$named_chroot" + else + ewarn "/etc/mtree/BIND.chroot.dist missing," + ewarn "chroot directory structure not updated" + fi + + if [ ! -d "$named_chroot"/. ]; then + eerror "chroot directory $named_chroot missing" + exit 1 + fi + + # Create /etc/namedb symlink + if [ ! -L "$namedb" ]; then + if [ -d "$namedb" ]; then + ewarn "named chroot: $namedb is a directory!" + elif [ -e "$namedb" ]; then + ewarn "named chroot: $namedb exists!" + else + ln -s "$named_chroot$namedb" "$namedb" + fi + else + # Make sure it points to the right place. + ln -shf "$named_chroot$namedb" "$namedb" + fi + + case "$RC_UNAME" in + *BSD|DragonFly) + # Mount a devfs in the chroot directory if needed + umount "$named_chroot"/dev 2>/dev/null + mount -t devfs dev "$named_chroot"/dev + devfs -m "$named_chroot"/dev \ + ruleset devfsrules_hide_all + devfs -m "$named_chroot"/dev \ + rule apply path null unhide + devfs -m "$named_chroot"/dev \ + rule apply path random unhide + ;; + esac + + # Copy local timezone information if it is not up to date. + if [ -r /etc/localtime ]; then + cmp -s /etc/localtime "$named_chroot/etc/localtime" || + cp -p /etc/localtime "$named_chroot/etc/localtime" + fi + + command_args="$command_args -t $named_chroot" + + ln -fs "$named_chroot$pidfile" "$pidfile" + fi + + if [ ! -s "$named_chroot$namedb/rndc.conf" ]; then + local confgen="${command%/named}/rndc-confgen -a -b256 -u $named_uid \ + -c $named_chrootdir/etc/namedb/rndc.key" + if [ -s "$named_chroot$namedb/rndc.key" ]; then + local getuser="stat -f%Su" + [ "$RC_UNAME" = Linux ] && getuser="stat -c%U" + case $(${getuser} "$named_chroot$namedb"/rndc.key) in + root|"$named_uid");; + *) $confgen;; + esac + else + $confgen + fi + fi +} + +reload() +{ + rndc reload +} + +stop_post() +{ + if [ -n "$named_chroot" -a -c "$named_chroot"/dev/null ]; then + umount "$named_chroot"/dev 2>/dev/null || true + fi +} Index: contrib/openrc/support/init.d.examples/ntpd.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/ntpd.in @@ -0,0 +1,44 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +: ${ntpd_config:=/etc/ntp.conf} +: ${ntpd_drift:=/var/db/ntpd.drift} + +command=/usr/sbin/ntpd +required_files=$ntpd_config +pidfile=/var/run/ntpd.pid +command_args="$ntpd_args -c $ntpd_config -f $ntpd_drift -p $pidfile" +name="Network Time Protocol Daemon" + +depend() +{ + use dns + need localmount + after bootmisc ntp-client +} + +start_pre() +{ + if [ -n "$ntpd_chroot" ]; then + case "$RC_UNAME" in + *BSD|DragonFly) + if [ ! -c "$ntpd_chroot/dev/clockctl" ]; then + rm -f "$ntpd_chroot/dev/clockctl" + (cd /dev; /bin/pax -rw -pe clockctl \ + "$ntpd_chroot/dev") + fi + ;; + esac + ln -fs "$ntpd_chroot$ntpd_drift" "$ntpd_drift" + + command_args="$command_args -u ntpd:ntpd -i $ntpd_chroot" + fi +} Index: contrib/openrc/support/init.d.examples/openvpn.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/openvpn.in @@ -0,0 +1,74 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +vpn=${RC_SVCNAME#*.} +name="OpenVPN" +[ "$vpn" != openvpn ] && name="$name ($vpn)" +command=@PKG_PREFIX@/sbin/openvpn + +pidfile=/var/run/"$RC_SVCNAME".pid +: ${openvpn_dir:=@PKG_PREFIX@/etc/openvpn} +: ${openvpn_config:=$openvpn_dir/$vpn.conf} +command_args="$openvpn_args --daemon --config $openvpn_config" +command_args="$command_args --writepid $pidfile" +required_dirs=$openvpn_dir +required_files=$openvpn_config + +# If we're an openvpn client, then supply a nice default config +# You can find sample up/down scripts in the OpenRC support/openvpn dir +if yesno $openvpn_client; then + : ${openvpn_up:=${openvpn_dir}/up.sh} + : ${openvpn_down:=${openvpn_dir}/down.sh} + command_args="$command_args --nobind --up-delay --up-restart --down-pre" + command_args="$command_args --up $openvpn_up" + command_args="$command_args --down $openvpn_down" + required_files="$required_files $openvpn_up $openvpn_down" + + in_background_fake="start stop" + start_inactive=YES +fi + +depend() +{ + need localmount net + use dns + after bootmisc +} + +start_pre() +{ + # Linux has good dynamic tun/tap creation + if [ "$RC_UNAME" = Linux ]; then + if [ ! -e /dev/net/tun ]; then + if ! modprobe tun; then + eerror "TUN/TAP support is not available in this kernel" + return 1 + fi + fi + if [ -h /dev/net/tun -a -c /dev/misc/net/tun ]; then + ebegin "Detected broken /dev/net/tun symlink, fixing..." + rm -f /dev/net/tun + ln -s /dev/misc/net/tun /dev/net/tun + eend $? + fi + else + if command -v kldload >/dev/null 2>&1; then + # Hammer the modules home by default + sysctl -a | grep -q '\.tun\.' || kldload if_tun + sysctl -a | grep -q '\.tap\.' || kldload if_tap + fi + fi + + # If the config file does not specify the cd option, we do + if ! grep -q "^[ \t]*cd[ \t].*" "$openvpn_config"; then + command_args="$command_args --cd $openvpn_dir" + fi +} Index: contrib/openrc/support/init.d.examples/polkitd.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/polkitd.in @@ -0,0 +1,20 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=@PKG_PREFIX@/sbin/polkitd +pidfile=/var/run/polkitd/polkitd.pid +command_args="$polkitd_args" +name="PolicyKit Daemon" + +depend() +{ + need dbus +} Index: contrib/openrc/support/init.d.examples/sshd.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/sshd.in @@ -0,0 +1,42 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/sshd +command_args=$sshd_args +pidfile=/var/run/sshd.pid +required_files=/etc/ssh/sshd_config + +depend() +{ + use logger dns + need net +} + +start_pre() +{ + if [ ! -e /etc/ssh/ssh_host_key ]; then + ebegin "Generating Hostkey" + ssh-keygen -t rsa1 -b 1024 -f /etc/ssh/ssh_host_key -N '' + eend $? || return 1 + fi + if [ ! -e /etc/ssh/ssh_host_dsa_key ]; then + ebegin "Generating DSA Hostkey" + ssh-keygen -d -f /etc/ssh/ssh_host_dsa_key -N '' + eend $? || return 1 + fi + if [ ! -e /etc/ssh/ssh_host_rsa_key ]; then + ebegin "Generating RSA Hostkey" + ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' + eend $? || return 1 + fi + + $command -t +} Index: contrib/openrc/support/init.d.examples/wpa_supplicant.in =================================================================== --- /dev/null +++ contrib/openrc/support/init.d.examples/wpa_supplicant.in @@ -0,0 +1,82 @@ +#!@SBINDIR@/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/wpa_supplicant +: ${wpa_supplicant_conf:=/etc/wpa_supplicant.conf} +wpa_supplicant_if=${wpa_supplicant_if:+-i}$wpa_supplicant_if +command_args="$wpa_supplicant_args -B -c$wpa_supplicant_conf $wpa_supplicant_if" +name="WPA Supplicant Daemon" + +depend() +{ + need localmount + use logger + after bootmisc modules + before dns dhcpcd net + keyword -shutdown +} + +find_wireless() +{ + local iface= + + case "$RC_UNAME" in + Linux) + for iface in /sys/class/net/*; do + if [ -e "$iface"/wireless -o \ + -e "$iface"/phy80211 ] + then + echo "${iface##*/}" + return 0 + fi + done + ;; + FreeBSD) + for iface in $(sysctl -b net.wlan.devices 2>/dev/null); do + echo "${iface##*/}" + done + ;; + *) + for iface in /dev/net/* $(ifconfig -l 2>/dev/null); do + if ifconfig "${iface##*/}" 2>/dev/null | \ + grep -q "[ ]*ssid " + then + echo "${iface##*/}" + return 0 + fi + done + ;; + esac + + return 1 +} + +append_wireless() +{ + local iface= i= + + iface=$(find_wireless) + if [ -n "$iface" ]; then + for i in $iface; do + command_args="$command_args -i$i" + done + else + eerror "Could not find a wireless interface" + fi +} + +start_pre() +{ + case " $command_args" in + *" -i"*) ;; + *) append_wireless;; + esac +} Index: contrib/openrc/support/openvpn/Makefile =================================================================== --- /dev/null +++ contrib/openrc/support/openvpn/Makefile @@ -0,0 +1,9 @@ +MK= ../../mk +include ${MK}/os.mk + +DIR= ${DATADIR}/support/openvpn +BIN= down.sh up.sh +INC= README.md + + +include ${MK}/scripts.mk Index: contrib/openrc/support/openvpn/down.sh =================================================================== --- /dev/null +++ contrib/openrc/support/openvpn/down.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# If we have a service specific script, run this now +[ -x "${RC_SVCNAME}"-down.sh ] && "${RC_SVCNAME}"-down.sh + +# Restore resolv.conf to how it was +if command -v resolvconf >/dev/null 2>&1; then + resolvconf -d "${dev}" +elif [ -e /etc/resolv.conf-"${dev}".sv ]; then + # Important that we copy instead of move incase resolv.conf is + # a symlink and not an actual file + cp -p /etc/resolv.conf-"${dev}".sv /etc/resolv.conf + rm -f /etc/resolv.conf-"${dev}".sv +fi + +# Re-enter the init script to stop any dependant services +if [ -x "${RC_SERVICE}" ]; then + if "${RC_SERVICE}" --quiet status; then + IN_BACKGROUND=YES + export IN_BACKGROUND + "${RC_SERVICE}" --quiet stop + fi +fi + +exit 0 Index: contrib/openrc/support/openvpn/up.sh =================================================================== --- /dev/null +++ contrib/openrc/support/openvpn/up.sh @@ -0,0 +1,80 @@ +#!/bin/sh +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Setup our resolv.conf +# Vitally important that we use the domain entry in resolv.conf so we +# can setup the nameservers are for the domain ONLY in resolvconf if +# we're using a decent dns cache/forwarder like dnsmasq and NOT nscd/libc. +# nscd/libc users will get the VPN nameservers before their other ones +# and will use the first one that responds - maybe the LAN ones? +# non resolvconf users just the the VPN resolv.conf + +# FIXME:- if we have >1 domain, then we have to use search :/ +# We need to add a flag to resolvconf to say +# "these nameservers should only be used for the listed search domains +# if other global nameservers are present on other interfaces" +# This however, will break compatibility with Debians resolvconf +# A possible workaround would be to just list multiple domain lines +# and try and let resolvconf handle it + +NS= +DOMAIN= +SEARCH= +i=1 +while true; do + eval opt=\$foreign_option_${i} + [ -z "${opt}" ] && break + if [ "${opt}" != "${opt#dhcp-option DOMAIN *}" ]; then + if [ -z "${DOMAIN}" ]; then + DOMAIN="${opt#dhcp-option DOMAIN *}" + else + SEARCH="${SEARCH:+ }${opt#dhcp-option DOMAIN *}" + fi + elif [ "${opt}" != "${opt#dhcp-option DNS *}" ]; then + NS="${NS}nameserver ${opt#dhcp-option DNS *}\n" + fi + : $(( i += 1 )) +done + +if [ -n "${NS}" ]; then + DNS="# Generated by openvpn for interface ${dev}\n" + if [ -n "${SEARCH}" ]; then + DNS="${DNS}search ${DOMAIN} ${SEARCH}\n" + else + DNS="${DNS}domain ${DOMAIN}\n" + fi + DNS="${DNS}${NS}" + if command -v resolvconf >/dev/null 2>&1; then + printf "${DNS}" | resolvconf -a "${dev}" + else + # Preserve the existing resolv.conf + if [ -e /etc/resolv.conf ]; then + cp -p /etc/resolv.conf /etc/resolv.conf-"${dev}".sv + fi + (umask 022; printf "${DNS}" > /etc/resolv.conf) + fi +fi + +# Below section is OpenRC specific + +# If we have a service specific script, run this now +[ -x "${RC_SVCNAME}"-up.sh ] && "${RC_SVCNAME}"-up.sh + +# Re-enter the init script to start any dependant services +if [ -x "${RC_SERVICE}" ]; then + if ! "${RC_SERVICE}" --quiet status; then + IN_BACKGROUND=YES + export IN_BACKGROUND + "${RC_SERVICE}" --quiet start + fi +fi + +exit 0 Index: contrib/openrc/support/sysvinit/Makefile =================================================================== --- /dev/null +++ contrib/openrc/support/sysvinit/Makefile @@ -0,0 +1,8 @@ +MK= ../../mk +include ${MK}/os.mk + +DIR= ${DATADIR}/support/sysvinit +INC= inittab README.md + + +include ${MK}/scripts.mk Index: contrib/openrc/support/sysvinit/inittab =================================================================== --- /dev/null +++ contrib/openrc/support/sysvinit/inittab @@ -0,0 +1,41 @@ +# /etc/inittab: This file describes how the INIT process should set up +# the system in a certain run-level. + +# Default runlevel. +id:3:initdefault: + +# System initialization, mount local filesystems, etc. +si::sysinit:/sbin/openrc sysinit + +# Further system initialization, brings up the boot runlevel. +rc::bootwait:/sbin/openrc boot + +l0:0:wait:/sbin/openrc shutdown +l0s:0:wait:/sbin/halt -dhip +l1:S1:wait:/sbin/openrc single +l2:2:wait:/sbin/openrc nonetwork +l3:3:wait:/sbin/openrc default +l4:4:wait:/sbin/openrc default +l5:5:wait:/sbin/openrc default +l6:6:wait:/sbin/openrc reboot +l6r:6:wait:/sbin/reboot -d +#z6:6:respawn:/sbin/sulogin + +# new-style single-user +su0:S:wait:/sbin/openrc single +su1:S:wait:/sbin/sulogin + +# TERMINALS +c1:12345:respawn:/sbin/agetty 38400 tty1 linux +c2:2345:respawn:/sbin/agetty 38400 tty2 linux +c3:2345:respawn:/sbin/agetty 38400 tty3 linux +c4:2345:respawn:/sbin/agetty 38400 tty4 linux +c5:2345:respawn:/sbin/agetty 38400 tty5 linux +c6:2345:respawn:/sbin/agetty 38400 tty6 linux + +# SERIAL CONSOLES +#s0:12345:respawn:/sbin/agetty 9600 ttyS0 vt100 +#s1:12345:respawn:/sbin/agetty 9600 ttyS1 vt100 + +# What to do at the "Three Finger Salute". +ca:12345:ctrlaltdel:/sbin/shutdown -r now Index: contrib/openrc/sysctl.d/Makefile =================================================================== --- /dev/null +++ contrib/openrc/sysctl.d/Makefile @@ -0,0 +1,6 @@ +DIR= ${SYSCTLDIR} +CONF= README + +MK= ../mk +include ${MK}/os.mk +include ${MK}/scripts.mk Index: contrib/openrc/sysctl.d/README =================================================================== --- /dev/null +++ contrib/openrc/sysctl.d/README @@ -0,0 +1,13 @@ +Kernel system variables configuration files + +Files found under the /etc/sysctl.d directory that end with .conf are +parsed within sysctl(8) at boot time. If you want to set kernel variables +you can either edit /etc/sysctl.conf or make a new file. + +The filename isn't important, but don't make it a package name as it may clash +with something the package builder needs later. The file name must end +with .conf, or it will not be read. + +The recommended location for local system settings is /etc/sysctl.d/local.conf +but as long as you follow the rules for the name of the file, anything will +work. see the sysctl.conf(5) man page for details of the format. Index: contrib/openrc/test/setup_env.sh =================================================================== --- /dev/null +++ contrib/openrc/test/setup_env.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +if [ -z "${top_srcdir}" ] ; then + echo "You must set top_srcdir before sourcing this file" 1>&2 + exit 1 +fi + +srcdir=${srcdir:-.} +top_builddir=${top_builddir:-${top_srcdir}} +builddir=${builddir:-${srcdir}} + +LD_LIBRARY_PATH=${top_builddir}/src/libeinfo:${top_builddir}/src/librc:${LD_LIBRARY_PATH} +PATH=${top_builddir}/src/rc:${PATH} +export LD_LIBRARY_PATH PATH + +if [ ! -f ${top_srcdir}/sh/functions.sh ] ; then + echo "functions.sh not yet created !?" 1>&2 + exit 1 +elif ! . ${top_srcdir}/sh/functions.sh; then + echo "Sourcing functions.sh failed !?" 1>&2 + exit 1 +fi + Index: contrib/openrc/test/skel.runtests.sh =================================================================== --- /dev/null +++ contrib/openrc/test/skel.runtests.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +# top_srcdir=${top_srcdir:-SET/THIS/PATH/OK!?} +. ${top_srcdir}/test/setup_env.sh + Index: contrib/openrc/user-guide.md =================================================================== --- /dev/null +++ contrib/openrc/user-guide.md @@ -0,0 +1,179 @@ +OpenRC Users Guide +================== + +# Purpose and description + +OpenRC is an init system for Unixoid operating systems. It takes care of +startup and shutdown of the whole system, including services. + +It evolved out of the Gentoo "Baselayout" package which was a custom pure-shell +startup solution. (This was both hard to maintain and debug, and not very +performant) + +Most of the core parts are written in C99 for performance and flexibility +reasons, while everything else is posix sh. +The License is 2-clause BSD + +Current size is about 10k LoC C, and about 4k LoC shell. + +OpenRC is known to work on Linux, many BSDs (FreeBSD, OpenBSD, DragonFlyBSD at +least) and HURD. + +Services are stateful (i.e. `start`; `start` will lead to "it's already started") + +# Startup + +Usually PID1 (aka. `init`) calls the OpenRC binary (`/sbin/openrc` by default). +(The default setup assumes sysvinit for this) + +openrc scans the runlevels (default: `/etc/runlevels`) and builds a dependency +graph, then starts the needed service scripts, either serialized (default) or in +parallel. + +When all the service scripts are started openrc terminates. There is no +persistent daemon. (Integration with tools like monit, runit or s6 can be done) + +# Shutdown + +On change to runlevel 0/6 or running `reboot`, `halt` etc., openrc stops all +services that are started and runs the services in the `shutdown` runlevel. + +# Modifying Service Scripts + +Any service can, at any time, be started/stopped/restarted by executing +`rc-service someservice start`, `rc-service someservice stop`, etc. +Another, less preferred method, is to run the service script directly, +e.g. `/etc/init.d/service start`, `/etc/init.d/service stop`, etc. + +OpenRC will take care of dependencies, e.g starting apache will start network +first, and stopping network will stop apache first. + +There is a special command `zap` that makes OpenRC 'forget' that a service is +started; this is mostly useful to reset a crashed service to stopped state +without invoking the (possibly broken) stop function of the service script. + +Calling `openrc` without any arguments will try to reset all services so +that the current runlevel is satisfied; if you manually started apache it will be +stopped, and if squid died but is in the current runlevel it'll be restarted. + +# Runlevels + +OpenRC has a concept of runlevels, similar to what sysvinit historically +offered. A runlevel is basically a collection of services that needs to be +started. Instead of random numbers they are named, and users can create their +own if needed. This allows, for example, to have a default runlevel with +"everything" enabled, and a "powersaving" runlevel where some services are +disabled. + +The `rc-status` helper will print all currently active runlevels and the state +of services in them: + +``` +# rc-status + * Caching service dependencies ... [ ok ] +Runlevel: default + modules [ started ] + lvm [ started ] +``` + +All runlevels are represented as folders in `/etc/runlevels/` with symlinks to +the actual service scripts. + +Calling openrc with an argument (`openrc default`) will switch to that +runlevel; this will start and stop services as needed. + +Managing runlevels is usually done through the `rc-update` helper, but could of +course be done by hand if desired. +e.g. `rc-update add nginx default` - add nginx to the default runlevel +Note: This will not auto-start nginx! You'd still have to trigger `rc` or run +the service script by hand. + +FIXME: Document stacked runlevels + +The default startup uses the runlevels `boot`, `sysinit` and `default`, in that +order. Shutdown uses the `shutdown` runlevel. + +# The Magic of `conf.d` + +Most service scripts need default values. It would be fragile to +explicitly source some arbitrary files. By convention `openrc-run` will source +the matching file in `/etc/conf.d/` for any script in `/etc/init.d/` + +This allows you to set random startup-related things easily. Example: + +``` +conf.d/foo: +START_OPTS="--extraparameter sausage" + +init.d/foo: +start() { + /usr/sbin/foo-daemon ${STARTOPTS} +} +``` + +The big advantage of this split is that most of the time editing of the service +script can be avoided. + +# Start-Stop-Daemon + +OpenRC has its own modified version of s-s-d, which is historically related and +mostly syntax-compatible to Debian's s-s-d, but has been rewritten from scratch. + +It helps with starting daemons, backgrounding, creating PID files and many +other convenience functions related to managing daemons. + +# `/etc/rc.conf` + +This file manages the default configuration for OpenRC, and it has examples of +per-service-script variables. + +Among these are `rc_parallel` (for parallelized startup), `rc_log` (logs all boot +messages to a file), and a few others. + +# ulimit and CGroups + +Setting `ulimit` and `nice` values per service can be done through the +`rc_ulimit` variable. + +Under Linux, OpenRC can use cgroups for process management as well. Once +the kernel is configured appropriately, the `rc_cgroup_mode` setting in +/etc/rc.conf should be used to control whether cgroups version one,, +two, or both are used. The default is to use both if they are available. + +By changing certain settings in the service's `conf.d` file limits can be +enforced per service. These settings are documented in detail in the +default /etc/rc.conf under `LINUX CGROUPS RESOURCE MANAGEMENT`. + +# Dealing with Orphaned Processes + +It is possible to get into a state where there are orphaned processes +running which were part of a service. For example, if you are monitoring +a service with supervise-daemon and supervise-daemon dies for an unknown +reason. The way to deal with this will be different for each system. + +On Linux systems with cgroups enabled, the cgroup_cleanup command is +added to all services. You can run it manually, when the service is +stopped, by using: + +``` +# rc-service someservice cgroup_cleanup +``` + +The `rc_cgroup_cleanup` setting can be changed to yes to make this +happen automatically when the service is stopped. + + +# Caching + +For performance reasons OpenRC keeps a cache of pre-parsed service metadata +(e.g. `depend`). The default location for this is `/${RC_SVCDIR}/cache`. + +The cache uses `mtime` to check for file staleness. Should any service script +change it'll re-source the relevant files and update the cache + +# Convenience functions + +OpenRC has wrappers for many common output tasks in libeinfo. +This allows to print colour-coded status notices and other things. +To make the output consistent the bundled service scripts all use ebegin/eend to +print nice messages. Index: contrib/openrc/zsh-completion/Makefile =================================================================== --- /dev/null +++ contrib/openrc/zsh-completion/Makefile @@ -0,0 +1,10 @@ +DIR= ${ZSHCOMPDIR} +CONF= _openrc \ + _rc-service \ + _rc-status \ + _rc-update \ + +MK= ../mk +include ${MK}/os.mk + +include ${MK}/scripts.mk Index: contrib/openrc/zsh-completion/_openrc =================================================================== --- /dev/null +++ contrib/openrc/zsh-completion/_openrc @@ -0,0 +1,7 @@ +#compdef openrc + +if (( CURRENT == 2 )); then + _values "runlevels" $(rc-status --list) +fi + +# vim: set et sw=2 ts=2 ft=zsh: Index: contrib/openrc/zsh-completion/_rc-service =================================================================== --- /dev/null +++ contrib/openrc/zsh-completion/_rc-service @@ -0,0 +1,27 @@ +#compdef rc-service + +if (( CURRENT == 2 )); then + _arguments -s \ + '(-e --exists)'{-e,--exists}"[tests if the service exists or not]" \ + '(-l --list)'{-l,--list}'[list all available services]' \ + '(-r --resolve)'{-r,--resolve}'[resolve the service name to an init script]' \ + '(-C --nocolor)'{-C,--nocolor}'[Disable color output]' \ + '(-v --verbose)'{-v,--verbose}'[Run verbosely]' \ + '(-q --quiet)'{-q,--quiet}'[Run quietly]' + _values "service" $(rc-service --list) +else + case $words[2] in + -e|--exists|-r|--resolve) + (( CURRENT > 3 )) && return 0 + _values "service" $(rc-service --list) + ;; + -*) + return 0 + ;; + *) + _values "action" stop start restart describe zap + ;; + esac +fi + +# vim: set et sw=2 ts=2 ft=zsh: Index: contrib/openrc/zsh-completion/_rc-status =================================================================== --- /dev/null +++ contrib/openrc/zsh-completion/_rc-status @@ -0,0 +1,18 @@ +#compdef rc-status + +_arguments -s \ + {'(--all)-a','(-a)--all'}'[Show services at all runlevels]' \ + {'(--crashed)-c','(-c)--crashed'}'[Show crashed services]' \ + {'(--list)-l','(-l)--list'}'[Show list of runlevels]' \ + {'(--runlevel)-r','(-r)--runlevel'}'[Show the name of the current runlevel]' \ + {'(--servicelist)-s','(-s)--servicelist'}'[Show all services]' \ + {'(--unused)-u','(-u)--unused'}'[Show services not assigned to any run level]' \ + {'(--help)-h','(-h)--help'}'[Print this help output]' \ + {'(--nocolor)-C','(-C)--nocolor'}'[Disable color output]' \ + {'(--version)-V','(-V)--version'}'[Display software version]' \ + {'(--verbose)-v','(-v)--verbose'}'[Run verbosely]' \ + {'(--quiet)-q','(-q)--quiet'}'[Run quietly (Does not affect errors)]' + +_values 'runlevels' $(rc-status --list) + +# vim: set et sw=2 ts=2 ft=zsh: Index: contrib/openrc/zsh-completion/_rc-update =================================================================== --- /dev/null +++ contrib/openrc/zsh-completion/_rc-update @@ -0,0 +1,31 @@ +#compdef rc-update + +local used_init +used_init=(${=${(M)${(f)"$(rc-update show 2>/dev/null)"}:#*|*[a-z]*}% |*}) + +if (( CURRENT == 2 )); then + _values "rc-update actions" \ + 'add[Add script to a runlevel]' \ + 'del[Delete script from a runlevel]' \ + 'show[Show scripts in a runlevel]' \ + '-a[Process all runlevels]' \ + '-s[Stack a runlevel instead of a service]' +elif (( CURRENT == 3 )); then + case "$words[2]" in + add) + _values "service" $(rc-service --list) + ;; + del) + _values "service" $used_init + ;; + show) + _values "runlevels" $(rc-status --list) \ + '-v[Show all service scripts]' \ + '--verbose[Show all service scripts]' + ;; + esac +elif (( CURRENT == 4 )); then + _values "runlevels" $(rc-status --list) +fi + +# vim: set et sw=2 ts=2 ft=zsh: Index: etc/mtree/BSD.root.dist =================================================================== --- etc/mtree/BSD.root.dist +++ etc/mtree/BSD.root.dist @@ -36,6 +36,8 @@ .. bluetooth .. + conf.d + .. cron.d .. defaults @@ -45,7 +47,11 @@ dma .. gss + .. + init.d .. + local.d + .. mail .. mtree @@ -74,12 +80,26 @@ .. rc.d .. + runlevels + boot + .. + default + .. + nonetwork + .. + shutdown + .. + sysinit + .. + .. security .. ssh .. ssl .. + sysctl.d + .. syslog.d .. zfs @@ -94,8 +114,22 @@ .. .. libexec + dhcpcd-hooks + .. resolvconf .. + rc + bin + .. + init.d + .. + sbin + .. + sh + .. + tmp + .. + .. .. media .. Index: include/einfo.h =================================================================== --- /dev/null +++ include/einfo.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2007-2015 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __EINFO_H__ +#define __EINFO_H__ + +#if defined(__GNUC__) +# define EINFO_PRINTF(a, b) __attribute__((__format__(__printf__, a, b))) +# define EINFO_XPRINTF(a, b) __attribute__((__noreturn__,__format__(__printf__, a, b))) +#else +# define EINFO_PRINTF(a, b) +# define EINFO_XPRINTF(a, b) +#endif + +#include +#include + +/* Although OpenRC requires C99, linking to us should not. */ +#ifdef restrict +# define EINFO_RESTRICT restrict +#else +# ifdef __restrict +# define EINFO_RESTRICT __restrict +# else +# define EINFO_RESTRICT +# endif +#endif + +/* __BEGIN_DECLS */ +#ifdef __cplusplus +extern "C" { +#endif + +/*! @brief Color types to use */ +typedef enum +{ + ECOLOR_NORMAL = 1, + ECOLOR_GOOD = 2, + ECOLOR_WARN = 3, + ECOLOR_BAD = 4, + ECOLOR_HILITE = 5, + ECOLOR_BRACKET = 6 +} ECOLOR; + +/*! @brief Returns the ASCII code for the color */ +const char *ecolor(ECOLOR); + +/*! @brief Writes to syslog. */ +void elog(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); + +/*! + * @brief Display informational messages. + * + * The einfo family of functions display messages in a consistent manner + * across applications. Basically they prefix the message with + * " * ". If the terminal can handle color then we color the * based on + * the command used. Otherwise we are identical to the printf function. + * + * - einfo - green + * - ewarn - yellow + * - eerror - red + * + * The n suffix denotes that no new line should be printed. + * The v suffix means only print if EINFO_VERBOSE is yes. + * The x suffix means function will exit() returning failure. + */ +/*@{*/ +int einfon(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ewarnn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int eerrorn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int einfo(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ewarn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +void ewarnx(const char * __EINFO_RESTRICT, ...) EINFO_XPRINTF(1, 2); +int eerror(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +void eerrorx(const char * __EINFO_RESTRICT, ...) EINFO_XPRINTF(1, 2); + +int einfovn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ewarnvn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ebeginvn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int eendvn(int, const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +int ewendvn(int, const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +int einfov(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ewarnv(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +/*@}*/ + +/*! @ingroup ebegin + * @brief Display informational messages that may take some time. + * + * Similar to einfo, but we add ... to the end of the message */ +/*@{*/ +int ebeginv(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +int ebegin(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2); +/*@}*/ + +/*! @ingroup eend + * @brief End an ebegin. + * + * If you ebegin, you should eend also. + * eend places [ ok ] or [ !! ] at the end of the terminal line depending on + * retval (0 or ok, anything else for !!) + * + * ebracket allows you to specifiy the position, color and message */ +/*@{*/ +int eend(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +int ewend(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +void ebracket(int, ECOLOR, const char * EINFO_RESTRICT); + +int eendv(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +int ewendv(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3); +/*@}*/ + +/*! @ingroup eindent + * @brief Indents the einfo lines. + * + * For each indent you should outdent when done */ +/*@{*/ +void eindent(void); +void eoutdent(void); +void eindentv(void); +void eoutdentv(void); + +/*! @brief Prefix each einfo line with something */ +void eprefix(const char * EINFO_RESTRICT); + +/* __END_DECLS */ +#ifdef __cplusplus +} +#endif + +#endif Index: lib/Makefile =================================================================== --- lib/Makefile +++ lib/Makefile @@ -45,6 +45,7 @@ libdl \ libdwarf \ libedit \ + libeinfo \ libelftc \ libevent \ libexecinfo \ @@ -72,6 +73,7 @@ libpjdlog \ ${_libproc} \ libprocstat \ + librc \ libregex \ librpcsvc \ librss \ Index: lib/libeinfo/Makefile =================================================================== --- /dev/null +++ lib/libeinfo/Makefile @@ -0,0 +1,31 @@ +# $FreeBSD$ + +PACKAGE=lib${LIB} +LIB= einfo +LIBADD+= kvm +SHLIBDIR?= /lib + +.include + +LIBEINFOSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${LIBEINFOSRC}/libeinfo + +SHLIB_MAJOR= 1 +SHLIB_MINOR= 0 +SRCS= libeinfo.c +INCS= einfo.h +CFLAGS+= -D_GNU_SOURCE -I${LIBEINFOSRC}/libeinfo \ + -I${SRCTOP}/contrib/openrc/src/includes + +.if defined(HAVE_DEBUG) +CFLAGS+= -g +CFLAGS+= -DHAVE_DEBUG +.endif + +SYM_MAPS+= ${LIBEINFOSRC}/libeinfo/einfo.map +SYMBOL_MAPS= ${SYM_MAPS} + +MLINKS= + +.include Index: lib/librc/Makefile =================================================================== --- /dev/null +++ lib/librc/Makefile @@ -0,0 +1,55 @@ +# $FreeBSD$ +# +GITVER="0.35" +PACKAGE=lib${LIB} +LIB= rc +SHLIBDIR?= /lib +SHLIB_MAJOR= 1 +SHLIB_MINOR= 0 + +.include + +LIBRCSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${LIBRCSRC}/librc + +SRCS= librc.c \ + librc-daemon.c \ + librc-depend.c \ + librc-misc.c \ + librc-stringlist.c +CFLAGS+= -D_GNU_SOURCE -I${LIBRCSRC}/libeinfo \ + -I${LIBRCSRC}/rc \ + -I${.OBJDIR}/contrib/openrc/src/librc \ + -I${LIBRCSRC}/includes + +rc.h: + mkdir -p ${.OBJDIR}/contrib/openrc/src/librc + cp ${LIBRCSRC}/librc/rc.h.in ${.OBJDIR}/contrib/openrc/src/librc/rc.h + sed -i '' 's|@PREFIX@||g' ${.OBJDIR}/contrib/openrc/src/librc/rc.h + sed -i '' 's|@LIBEXECDIR@|/libexec/rc|g' ${.OBJDIR}/contrib/openrc/src/librc/rc.h + sed -i '' 's|@BINDIR@|/usr/local/bin|g' ${.OBJDIR}/contrib/openrc/src/librc/rc.h + sed -i '' 's|@SBINDIR@|/usr/local/sbin|g' ${.OBJDIR}/contrib/openrc/src/librc/rc.h + sed -i '' 's|@PKG_PREFIX@|/usr/local|g' ${.OBJDIR}/contrib/openrc/src/librc/rc.h + sed -i '' 's|@LOCAL_PREFIX@|/usr/local|g' ${.OBJDIR}/contrib/openrc/src/librc/rc.h + sed -i '' 's|@SYSCONFDIR@|/etc|g' ${.OBJDIR}/contrib/openrc/src/librc/rc.h + sed -i '' 's|@LIB@|/lib|g' ${.OBJDIR}/contrib/openrc/src/librc/rc.h + +version.h: + mkdir -p ${.OBJDIR}/contrib/openrc/src/librc + echo "#define VERSION \"${GITVER}\"" >${.OBJDIR}/contrib/openrc/src/librc/version.h + +beforedepend: rc.h version.h + +.if defined(HAVE_DEBUG) +CFLAGS+= -g +CFLAGS+= -DHAVE_DEBUG +.endif +LIBADD+= kvm + +SYM_MAPS+= ${LIBRCSRC}/librc/rc.map +SYMBOL_MAPS= ${SYM_MAPS} + +MLINKS= + +.include Index: lib/librc/Makefile.depend =================================================================== --- /dev/null +++ lib/librc/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libc \ + lib/libkvm + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/Makefile =================================================================== --- libexec/rc/Makefile +++ libexec/rc/Makefile @@ -2,7 +2,7 @@ CONFGROUPS= CONFETC CONFETCEXEC CONFETCDEFAULTS CONFETCDIR= /etc -CONFETC= network.subr rc rc.initdiskless rc.subr rc.shutdown +CONFETC= network.subr openrc openrc.shutdown rc rc.initdiskless rc.subr rc.shutdown CONFETCMODE= 644 CONFETCEXEC= netstart pccard_ether rc.resume rc.suspend CONFETCEXECDIR= /etc @@ -11,6 +11,13 @@ CONFETCDEFAULTS= rc.conf #PACKAGE=rc +SUBDIR+= bin +SUBDIR+= init.d SUBDIR+= rc.d +SUBDIR+= sbin +SUBDIR+= sh + +# Needs to be added after sh +SUBDIR+= etc.init.d .include Index: libexec/rc/bin/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/Makefile @@ -0,0 +1,19 @@ +# $FreeBSD$ + +BINDIR=/libexec/rc/bin + +SUBDIR= checkpath +SUBDIR+= einfo +SUBDIR+= fstabinfo +SUBDIR+= get_options +SUBDIR+= is_newer_than +SUBDIR+= is_older_than +SUBDIR+= mountinfo +SUBDIR+= on_ac_power +SUBDIR+= rc-depend +SUBDIR+= service_starting +SUBDIR+= shell_var +SUBDIR_PARALLEL= + +.include + Index: libexec/rc/bin/Makefile.inc =================================================================== --- /dev/null +++ libexec/rc/bin/Makefile.inc @@ -0,0 +1,7 @@ +# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93 +# $FreeBSD$ + +BINDIR?= /libexec/rc/bin + +WARNS?= 6 +WFORMAT?= 1 Index: libexec/rc/bin/checkpath/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/checkpath/Makefile @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= checkpath + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= checkpath.c \ + rc-misc.c \ + _usage.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/checkpath/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/checkpath/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/einfo/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/einfo/Makefile @@ -0,0 +1,46 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= einfo + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +LINKS= ${BINDIR}/einfo ${BINDIR}/einfon \ + ${BINDIR}/einfo ${BINDIR}/ewarn \ + ${BINDIR}/einfo ${BINDIR}/ewarnn \ + ${BINDIR}/einfo ${BINDIR}/eerror \ + ${BINDIR}/einfo ${BINDIR}/eerrorn \ + ${BINDIR}/einfo ${BINDIR}/ebegin \ + ${BINDIR}/einfo ${BINDIR}/eend \ + ${BINDIR}/einfo ${BINDIR}/ewend \ + ${BINDIR}/einfo ${BINDIR}/eindent \ + ${BINDIR}/einfo ${BINDIR}/eoutdent \ + ${BINDIR}/einfo ${BINDIR}/esyslog \ + ${BINDIR}/einfo ${BINDIR}/eval_ecolors \ + ${BINDIR}/einfo ${BINDIR}/ewaitfile \ + ${BINDIR}/einfo ${BINDIR}/veinfo \ + ${BINDIR}/einfo ${BINDIR}/vewarn \ + ${BINDIR}/einfo ${BINDIR}/vebegin \ + ${BINDIR}/einfo ${BINDIR}/veend \ + ${BINDIR}/einfo ${BINDIR}/vewend \ + ${BINDIR}/einfo ${BINDIR}/veindent \ + ${BINDIR}/einfo ${BINDIR}/veoutdent +SRCS= do_e.c \ + rc-misc.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/einfo/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/einfo/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/fstabinfo/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/fstabinfo/Makefile @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= fstabinfo + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= fstabinfo.c \ + rc-misc.c \ + _usage.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/fstabinfo/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/fstabinfo/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/get_options/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/get_options/Makefile @@ -0,0 +1,29 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= get_options + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +LINKS= ${BINDIR}/get_options ${BINDIR}/service_get_value \ + ${BINDIR}/get_options ${BINDIR}/service_set_value \ + ${BINDIR}/get_options ${BINDIR}/save_options +SRCS= do_value.c \ + rc-misc.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/get_options/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/get_options/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/is_newer_than/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/is_newer_than/Makefile @@ -0,0 +1,26 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= is_newer_than + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= is_newer_than.c \ + rc-misc.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/is_newer_than/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/is_newer_than/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/is_older_than/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/is_older_than/Makefile @@ -0,0 +1,26 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= is_older_than + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= is_older_than.c \ + rc-misc.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/is_older_than/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/is_older_than/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/mountinfo/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/mountinfo/Makefile @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= mountinfo + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= mountinfo.c \ + rc-misc.c \ + _usage.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/mountinfo/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/mountinfo/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/on_ac_power/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/on_ac_power/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +FILES= ${.CURDIR}/../../../../contrib/openrc/scripts/on_ac_power + +NO_OBJ= +FILESDIR= /libexec/rc/bin +FILESMODE= 755 +MAN= + +.include + Index: libexec/rc/bin/rc-depend/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/rc-depend/Makefile @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= rc-depend + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= rc-depend.c \ + rc-misc.c \ + _usage.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/rc-depend/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/rc-depend/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/service_starting/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/service_starting/Makefile @@ -0,0 +1,34 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= service_starting + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +LINKS= ${BINDIR}/service_starting ${BINDIR}/service_started \ + ${BINDIR}/service_starting ${BINDIR}/service_stopping \ + ${BINDIR}/service_starting ${BINDIR}/service_stopped \ + ${BINDIR}/service_starting ${BINDIR}/service_inactive \ + ${BINDIR}/service_starting ${BINDIR}/service_wasinactive \ + ${BINDIR}/service_starting ${BINDIR}/service_hotplugged \ + ${BINDIR}/service_starting ${BINDIR}/service_started_daemon \ + ${BINDIR}/service_starting ${BINDIR}/service_crashed +SRCS= do_service.c \ + rc-misc.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/service_starting/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/service_starting/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/bin/shell_var/Makefile =================================================================== --- /dev/null +++ libexec/rc/bin/shell_var/Makefile @@ -0,0 +1,25 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= shell_var + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= shell_var.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR?=/libexec/rc/bin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/bin/shell_var/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/bin/shell_var/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/etc.init.d/Makefile =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/Makefile @@ -0,0 +1,37 @@ +# $FreeBSD$ + +PACKAGE=runtime + +.include + +CONFDIR= /etc/init.d +CONFGROUP= CONFS + +CONFS= abi accounting adjkerntz amd apm apmd archdep auditd auditdistd automount \ + automountd autounmountd \ + bgfsck blacklistd bluetooth bootmisc bootparams bridge bsnmpd bthidd \ + ccd cfumass cleanvar cleartmp cron ctld \ + ddb devd devfs devmatch dmesg dumpon \ + earlykld encswap fsck ftpd ftp-proxy \ + gbde gptboot growfs gssd \ + hastd hcsecd hostid hostid_save hostname \ + inetd iovctl ipfs ipropd_master ipropd_slave iscsictl iscsid ipfw ipfw_netflow ipsec \ + jail kadmind kdc keyserv kfd kldxref kpasswdd \ + ldconfig local localmount local_unbound lockd lpd hostapd \ + mixer modules mountd mountlate moused motd \ + natd netmount network newsyslog nfscbd nfsclient nfsd nfsuserd nisdomain nsswitch \ + nscd ntpd ntpdate pf pflog powerd ppp rarpd rc-enabled resolv rwho root routing rpcbind runsvdir \ + s6-svscan savecache savecore sdpd sendmail \ + sshd statd staticroute swap syscons sysctl syslogd timed tmp tmpfiles.setup ubthidhci urandom \ + var watchdogd wpa_supplicant \ + ypbind ypldap yppasswdd ypserv ypset ypupdated ypxfrd \ + zfs zfsd zvol +CONFSMODE= 755 + +LINKS= /libexec/rc/sh/functions.sh /etc/init.d/functions.sh + +.for fg in ${CONFGROUPS} +${fg}MODE?= ${BINMODE} +.endfor + +.include Index: libexec/rc/etc.init.d/abi =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/abi @@ -0,0 +1,64 @@ +#!/sbin/openrc-run + +name="abi" + +depend() +{ + before bootmisc logger + keyword -stop +} + +sysv_start() +{ + ABIS="sysvipc $ABIS" + load_kld sysvmsg + load_kld sysvsem + load_kld sysvshm +} + +linux_start() +{ + local _tmpdir + + ABIS="linux $ABIS" + load_kld -e 'linux(aout|elf)' linux + case `sysctl -n hw.machine_arch` in + amd64) + load_kld -e 'linux64elf' linux64 + ;; + esac + if [ -x /compat/linux/sbin/ldconfigDisabled ]; then + _tmpdir=`mktemp -d -t linux-ldconfig` + /compat/linux/sbin/ldconfig -C ${_tmpdir}/ld.so.cache + if ! cmp -s ${_tmpdir}/ld.so.cache /compat/linux/etc/ld.so.cache; then + cat ${_tmpdir}/ld.so.cache > /compat/linux/etc/ld.so.cache + fi + rm -rf ${_tmpdir} + fi +} + +svr4_start() +{ + ABIS="svr4 $ABIS" + load_kld -m svr4elf svr4 +} + +start() +{ + if ! yesno sysvipc_enable && ! yesno linux_enable && ! yesno svr4_enable; then + mark_service_inactive + return 0 + fi + + yesno sysvipc_enable && sysv_start + yesno linux_enable && linux_start + yesno svr4_enable && svr4_start + + einfo "Additional ABI support: $ABIS" + return 0 +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/accounting =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/accounting @@ -0,0 +1,65 @@ +#!/sbin/openrc-run + +name="accounting" + +accounting_command="/usr/sbin/accton" +accounting_file="/var/account/acct" + +extra_commands="rotate_log" +description_rotate_log="Rotate the accounting logs" + +depend() +{ + need localmount +} + +start() +{ + local _dir + + _dir="${accounting_file%/*}" + if [ ! -d "$_dir" ]; then + if ! mkdir -p "$_dir"; then + eend 1 "Could not create $_dir." + fi + fi + + if [ ! -e "$accounting_file" ]; then + einfo "Creating accounting file ${accounting_file}" + touch "$accounting_file" + fi + chmod 644 "$accounting_file" + + ebegin "Turning on accounting." + ${accounting_command} ${accounting_file} + eend $? +} + +stop() +{ + ebegin "Turning off accounting." + ${accounting_command} + eend $? +} + +rotate_log() +{ + local _dir _file + + _dir="${accounting_file%/*}" + cd $_dir + + ebegin "Rotating accounting logs" + if yesno accounting_enable; then + _file=`mktemp newacct-XXXXX` + chmod 644 $_file + ${accounting_command} ${_dir}/${_file} + fi + + mv ${accounting_file} ${accounting_file}.0 + + if yesno accounting_enable; then + mv $_file ${accounting_file} + fi + eend 0 +} Index: libexec/rc/etc.init.d/adjkerntz =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/adjkerntz @@ -0,0 +1,62 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +extra_commands="save" + +description="Sets the local clock to UTC or Local Time." +description_save="Saves the current time in the BIOS." + +: ${clock:=${CLOCK:-UTC}} +if [ "$clock" = "UTC" ]; then + utc="UTC" +else + utc="Local Time" +fi + +depend() +{ + provide clock + keyword -jail -prefix +} + +start() +{ + ebegin "Starting the System Clock Adjuster [${utc}]" + if [ "$clock" != "UTC" ]; then + start-stop-daemon --start --exec /sbin/adjkerntz -- -i + else + /sbin/adjkerntz -i + fi + eend $? +} + +save() +{ + ebegin "Setting hardware clock using the system clock [${utc}]" + adjkerntz -a + eend $? +} + +stop() +{ + # Don't tweak the hardware clock on LiveCD halt. + if yesno "${clock_systohc:-$CLOCK_SYSTOHC}"; then + [ -z "$CDBOOT" ] && save + fi + + ebegin "Stopping the System Clock Adjuster" + if start-stop-daemon --test --quiet --stop --exec /sbin/adjkerntz; then + start-stop-daemon --stop --exec /sbin/adjkerntz + eend $? + else + eend 0 + fi +} Index: libexec/rc/etc.init.d/amd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/amd @@ -0,0 +1,35 @@ +#!/sbin/openrc-run + +name="amd" + +depend() +{ + need localmount nfsclient rpcbind + use net logger +} + +start_pre() +{ + case ${amd_map_program} in + [Nn][Oo] | '') + ;; + *) + amd_flags="${amd_flags} `echo $(eval ${amd_map_program})`" + ;; + esac + + case "${amd_flags}" in + '') if [ ! -r /etc/amd.conf ]; then + eend 1 'amd will not load without arguments' + fi + ;; + *) + ;; + esac +} + +start() +{ + start-stop-daemon --start --exec /usr/sbin/amd \ + --pidfile /var/run/amd.pid -b -m -- $amd_flags +} Index: libexec/rc/etc.init.d/apm =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/apm @@ -0,0 +1,47 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +depend() +{ + keyword -jail +} + +name="apm" +desc="Advanced power management" +command="/usr/sbin/${name}" + +start_pre() +{ + case `${SYSCTL_N} hw.machine_arch` in + i386) + return 0 + ;; + esac + return 1 +} + +start() +{ + $command -e enable +} + +stop() +{ + $command -e disable +} + +status() +{ + case `${command} -s` in + 1) + einfo "APM is enabled." + return 0 + ;; + 0) + einfo "APM is disabled" + ;; + esac + return 1 +} Index: libexec/rc/etc.init.d/apmd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/apmd @@ -0,0 +1,30 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +depend() +{ + need apm + keyword -jail -shutdown +} + +name="apmd" +desc="Advanced power management daemon" +command="/usr/sbin/${name}" + +start_pre() +{ + case `${SYSCTL_N} hw.machine_arch` in + i386) + # Warn user about acpi apm compatibility support which + # does not work with apmd. + if [ ! -e /dev/apmctl ]; then + ewarn "/dev/apmctl not found; kernel is missing apm(4)" + fi + ;; + *) + return 1 + ;; + esac +} Index: libexec/rc/etc.init.d/archdep =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/archdep @@ -0,0 +1,45 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +SYSCTL_N="sysctl -n" + +depend() +{ + keyword -jail +} + +name="archdep" + +start() +{ + local _arch + + _arch=`${SYSCTL_N} hw.machine_arch` + case $_arch in + i386) + # SCO binary emulation + # + if checkyesno ibcs2_enable; then + einfo -n 'Initial i386 initialization: ibcs2' + load_kld ibcs2 + case ${ibcs2_loaders} in + [Nn][Oo]) + ;; + *) + for i in ${ibcs2_loaders}; do + load_kld ibcs2_$i + done + ;; + esac + echo '.' + fi + ;; + esac +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/auditd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/auditd @@ -0,0 +1,22 @@ +#!/sbin/openrc-run + +command=/usr/sbin/auditd +command_args=$auditd_flags +name="auditd" +description="Audit daemon" +required_files="/etc/security/audit_class /etc/security/audit_control /etc/security/audit_event /etc/security/audit_user /etc/security/audit_warn" + +depend() +{ + need localmount + use logger + before inetd xinetd +} + +stop() +{ + + ebegin "Stopping auditd" + /usr/sbin/audit -t + eend $? +} Index: libexec/rc/etc.init.d/auditdistd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/auditdistd @@ -0,0 +1,14 @@ +#!/sbin/openrc-run + +name="auditdistd" +description="Audit trail files distribution daemon" +command=/usr/sbin/auditdistd +pidfile="/var/run/auditdistd.pid" +required_files="/etc/security/auditdistd.conf" + +depend() +{ + need localmount + use logger + before inetd xinetd +} Index: libexec/rc/etc.init.d/automount =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/automount @@ -0,0 +1,83 @@ +#!/sbin/openrc-run + +name="NFS Automount Client" +command="/usr/sbin/automount" +command_args=${automount_flags} +desktop_generator="/usr/local/bin/trueos-mount" +extra_actions=clean_shortcuts + +depend() +{ + need localmount nfsclient automountd autounmountd + use net logger dns + before inetd xinetd +} + +stop() +{ + /sbin/umount -At autofs +} + +clean_shortcuts() +{ + #Cleanup any device *.desktop files within the /media directory + for i in `ls /media | grep -E "^(da|ada)[0-9].*(.desktop)"` ; do + rm /media/${i} + done + return 0 +} + +stop_post() +{ + clean_shortcuts + rm ${tmp_proc_flag} 1>/dev/null 2>/dev/null + return 0 +} + +start(){ + clean_shortcuts + #Note: This command is a one-off, it does not remain running persistantly. + ${command} ${command_args} + return 0 #don't worry about the return code of the autmount command - the automountd service is what handles the main daemon +} + +skip_device() +{ + #internal function which checks if the argument is currently in-use + #and returns 0 if unused + dev=$1 + if [ -z "${activelist}" ] ; then + #Load all the mount/zpool information if first-run + mntlist=`/sbin/mount` + zlist=`/sbin/zpool list -vH` + activelist="${tmp} +${zlist}" + unset mntlist + unset zlist + #einfo "#activelist: ${activelist}" + fi + tmp=`echo "${activelist}" | grep ${dev}` + if [ -z "${tmp}" ] ; then + return 0 + else + return 1 + fi +} + +start_post() +{ + #Generate any device *.desktop files within the /media directory for things that are currently attached but unmounted + + if [ -e ${desktop_generator} ] ; then + for i in `ls /dev | grep -E "^(da|ada|cd|acd).*"` ; do + einfo "Checking device ${i}" + skip_device ${i} + if [ $? -eq 0 ] ; then + #einfo "Generate Shortcut ${i}" + ${desktop_generator} ${i} 1>/dev/null 2>/dev/null + fi + done + fi + mark_service_started automount + return 0 +} Index: libexec/rc/etc.init.d/automountd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/automountd @@ -0,0 +1,23 @@ +#!/sbin/openrc-run + +command=/usr/sbin/automountd +command_args="-i" +name="automountd" +pidfile="/var/run/automountd.pid" +output_log="/var/log/automountd_service.log" +error_log=${output_log} + +#Using supervise-daemon (NOT WORKING: automountd in non-daemon mode exits after one run) +#command_args_foreground="-d" +#supervisor=supervise-daemon + +#Using start-stop-daemon +command_background="true" + +depend() +{ + need nfsclient localmount + use net logger dns + before inetd xinetd +} + Index: libexec/rc/etc.init.d/autounmountd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/autounmountd @@ -0,0 +1,15 @@ +#!/sbin/openrc-run + +command=/usr/sbin/autounmountd +command_args="-D $autounmountd_args ${autounmountd_flags}" +name="autounmountd" +pidfile="/var/run/autounmountdaemond.pid" +supervisor=supervise-daemon +supervise_daemon_args="-1 /var/log/autounmountdaemond.log -2 /var/log/autounmountdaemond.log" + +depend() +{ + need localmount + use net logger dns + before inetd xinetd +} Index: libexec/rc/etc.init.d/bgfsck =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/bgfsck @@ -0,0 +1,50 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +depend() +{ + need devfs cron syslogd + keyword -jail +} + +name="background_fsck" +desc="Run fsck in background" + +start_pre() +{ + if [ $(id -u) != 0 ]; then + ewarn "Must be root." + return 1 + fi +} + +start() +{ + : ${background_fsck_delay=0} + if [ -n "${rc_force}" ]; then + background_fsck_delay=0 + fi + if [ ${background_fsck_delay} -lt 0 ]; then + warn "Background file system checks delayed indefinitely" + return 0 + fi + + bgfsck_msg='Starting background file system checks' + if [ "${background_fsck_delay}" -gt 0 ]; then + bgfsck_msg="${bgfsck_msg} in ${background_fsck_delay} seconds" + fi + if [ -z "${rc_force}" ]; then + einfo "${bgfsck_msg}." + fi + + (sleep ${background_fsck_delay}; nice -4 fsck -B -p) 2>&1 | \ + logger -p daemon.notice -t fsck & + return 0 +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/blacklistd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/blacklistd @@ -0,0 +1,13 @@ +#!/sbin/openrc-run + +name="blacklistd" +description="System blacklist daemon" +command=/usr/sbin/blacklistd +required_files="/etc/blacklistd.conf" + +depend() +{ + need localmount pf + use net + before inetd xinetd +} Index: libexec/rc/etc.init.d/bluetooth =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/bluetooth @@ -0,0 +1,439 @@ +#!/sbin/openrc-run +# Copyright (c) 2018 - Ken Moore +# +# Copyright (c) 2016 - Kris Moore +# +# Copyright (c) 2005 Maksim Yevmenkin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +name="bluetooth" +description="Bluetooth setup script" +required_modules="ng_bluetooth ng_hci ng_l2cap ng_btsocket" + +hccontrol="${bluetooth_hccontrol:-/usr/sbin/hccontrol}" +hcseriald="${bluetooth_hcseriald:-/usr/sbin/hcseriald}" + +#Get the sub-service device name +dev=${RC_SVCNAME##*.} + +depend() +{ + need localmount + if [ -n ${dev} ] ; then + #Only startup these other services if an actual BT device is connected + use hcsecd sdpd bthidd + fi + keyword -jail +} + +#Add support for all the device interactions (sub-devices only) +if [ -n "${dev}" ] ; then + extra_started_commands="inquiry" + description_inquiry="Scan for discoverable BT devices and output address/name of each" +fi + +######################################### +# Device Interaction Commands +######################################### +getDevNodes(){ + nodes=`hccontrol Read_Node_List | grep ${dev} | cut -w -f 1` +} + +inquiry(){ + getDevNodes + local _addr _hrname + for node in "${nodes}" + do + #Output the addresses for devices + for _addr in `hccontrol -N -n ${node} inquiry | grep -o "BD_ADDR: .*" | cut -w -f 2` + do + _hrname=`hccontrol Remote_Name_Request ${_addr} | grep -o "Name: .*" | cut -w -f 2-` + echo "${_addr} [${_hrname}]" + done + done +} + + +######################################### +# Start/Stop individual device services +######################################### + +start_dev_services(){ + local svcdir _dev _devlist + _devlist=$(ngctl list | grep -o "Name: .* Type: ubt" | cut -w -f 2) + svcdir=`dirname ${RC_SERVICE}` + for _dev in ${_devlist} + do + _dev=`basename "${_dev}"` + if [ ! -e "${RC_SERVICE}.${_dev}" ] ; then + ln -f "${RC_SERVICE}" "${RC_SERVICE}.${_dev}" + fi + if ! service_started "${name}.${_dev}" ; then + /sbin/service "${name}.${_dev}" start + fi + done +} + +stop_dev_services(){ + local _svc _dev _devlist _found + _devlist=$(ngctl list | grep -o "Name: .* Type: ubt" | cut -w -f 2) + for _svc in `ls ${RC_SERVICE}.* 2>/dev/null` + do + _svc=`basename ${_svc}` + _dev=${_svc##*.} + _found=`echo "_devlist" | grep -c "${_dev}"` + if service_started ${_svc} && [ "${RC_CMD}" != "restart" ] || [ "${found}" != "1" ] ; then + /sbin/service ${_svc} stop + fi + if [ "${found}" != "1" ] ; then + #Device removed, remove the child service as well + rm ${RC_SERVICE}.${_dev} + fi + done +} + +############################################################################## +# Read and parse Bluetooth device configuration file +############################################################################## + +bluetooth_read_conf() +{ + local _err _line _namespace + + #NOTE: This needs the "_file" variable to be pre-set to the config file path + _namespace="bluetooth_device_" + _err=0 + + if [ ! -e $_file ]; then + return 0 + fi + + if [ ! -f $_file -o ! -r $_file ]; then + eerror 1 "Bluetooth configuration file $_file is not a file or not readable" + fi + + while read _line + do + case "$_line" in + \#*) + continue + ;; + + *) + if [ -z "$_line" ]; then + continue; + fi + + + if expr "$_line" : "[a-zA-Z0-9_]*=" > /dev/null 2>&1; then + eval "${_namespace}${_line}" + else + ewarn "Unable to parse line \"$_line\" in $_file" + _err=1 + fi + ;; + esac + done < $_file + + return $_err +} + +############################################################################## +# Setup Bluetooth stack. Create and connect nodes +############################################################################## + +bluetooth_setup_stack() +{ + hook="hook" + + # Setup HCI + ngctl mkpeer ${dev}: hci ${hook} drv \ + > /dev/null 2>&1 || return 1 + + ngctl name ${dev}:${hook} ${dev}hci \ + > /dev/null 2>&1 || return 1 + + ngctl msg ${dev}hci: set_debug ${bluetooth_device_hci_debug_level} \ + > /dev/null 2>&1 || return 1 + + # Setup L2CAP + ngctl mkpeer ${dev}hci: l2cap acl hci \ + > /dev/null 2>&1 || return 1 + + ngctl name ${dev}hci:acl ${dev}l2cap \ + > /dev/null 2>&1 || return 1 + + ngctl msg ${dev}l2cap: set_debug ${bluetooth_device_l2cap_debug_level} \ + > /dev/null 2>&1 || return 1 + + # Connect HCI node to the Bluetooth sockets layer + ngctl connect ${dev}hci: btsock_hci_raw: raw ${dev}raw \ + > /dev/null 2>&1 || return 1 + + # Connect L2CAP node to Bluetooth sockets layer + ngctl connect ${dev}l2cap: btsock_l2c_raw: ctl ${dev}ctl \ + > /dev/null 2>&1 || return 1 + + ngctl connect ${dev}l2cap: btsock_l2c: l2c ${dev}l2c \ + > /dev/null 2>&1 || return 1 + + # Initilalize HCI node + ${hccontrol} -n ${dev}hci reset \ + > /dev/null 2>&1 || return 1 + + ${hccontrol} -n ${dev}hci read_bd_addr \ + > /dev/null 2>&1 || return 1 + + ${hccontrol} -n ${dev}hci read_local_supported_features \ + > /dev/null 2>&1 || return 1 + + ${hccontrol} -n ${dev}hci read_buffer_size \ + > /dev/null 2>&1 || return 1 + + if yesno bluetooth_device_discoverable; then + if yesno bluetooth_device_connectable; then + ${hccontrol} -n ${dev}hci write_scan_enable 3 \ + > /dev/null 2>&1 || return 1 + else + ${hccontrol} -n ${dev}hci write_scan_enable 1 \ + > /dev/null 2>&1 || return 1 + fi + else + if yesno bluetooth_device_connectable; then + ${hccontrol} -n ${dev}hci write_scan_enable 2 \ + > /dev/null 2>&1 || return 1 + else + ${hccontrol} -n ${dev}hci write_scan_enable 0 \ + > /dev/null 2>&1 || return 1 + fi + fi + + + ${hccontrol} -n ${dev}hci write_class_of_device ${bluetooth_device_class} \ + > /dev/null 2>&1 || return 1 + + if yesno bluetooth_device_authentication_enable; then + ${hccontrol} -n ${dev}hci write_authentication_enable 1 \ + > /dev/null 2>&1 || return 1 + else + ${hccontrol} -n ${dev}hci write_authentication_enable 0 \ + > /dev/null 2>&1 || return 1 + fi + + case "${bluetooth_device_encryption_mode}" in + [Nn][Oo][Nn][Ee]|0) + ${hccontrol} -n ${dev}hci write_encryption_mode 0 \ + > /dev/null 2>&1 || return 1 + ;; + + [Pp][2][Pp]|1) + ${hccontrol} -n ${dev}hci write_encryption_mode 1 \ + > /dev/null 2>&1 || return 1 + ;; + + [Al][Ll][Ll]|2) + ${hccontrol} -n ${dev}hci write_encryption_mode 2 \ + > /dev/null 2>&1 || return 1 + ;; + + *) + ewarn "Unsupported encryption mode ${bluetooth_device_encryption_mode} for device ${dev}" + return 1 + ;; + esac + + if yesno bluetooth_device_role_switch; then + ${hccontrol} -n ${dev}hci write_node_role_switch 1 \ + > /dev/null 2>&1 || return 1 + else + ${hccontrol} -n ${dev}hci write_node_role_switch 0 \ + > /dev/null 2>&1 || return 1 + fi + + ${hccontrol} -n ${dev}hci change_local_name "${bluetooth_device_local_name}" \ + > /dev/null 2>&1 || return 1 + + ${hccontrol} -n ${dev}hci initialize \ + > /dev/null 2>&1 || return 1 + + return 0 +} + +############################################################################## +# Shutdown Bluetooth stack. Destroy all nodes +############################################################################## + +bluetooth_shutdown_stack() +{ + ngctl shutdown ${dev}hci: > /dev/null 2>&1 + ngctl shutdown ${dev}l2cap: > /dev/null 2>&1 + + return 0 +} + +############################################################################## +# start() +############################################################################## + +start_pre(){ + #Make sure all the required modules are loaded + for _mod in ${required_modules} + do + kldload -nq "${_mod}" + if [ 0 -ne $? ] ; then + ewarn "Could not load kernel module: ${_mod}" + fi + done + +} + +start() +{ + if [ -z ${dev} ] || [ "${dev}" = "bluetooth" ] ; then + #Master service, detect/start all BT device services + start_dev_services + return 0 + fi + + + ebegin "Starting Bluetooth for: $dev" + + # Try to figure out device type by looking at device name + case "${dev}" in + # uartX - serial/UART Bluetooth device + uart*) + load_kld ng_h4 || return 1 + + # Obtain unit number from device. + unit=`expr ${dev} : 'uart\([0-9]\{1,\}\)'` + if [ -z "${unit}" ]; then + eend 1 "Unable to get uart unit number: ${dev}" + fi + + ${hcseriald} -f /dev/cuau${unit} -n ${dev} + sleep 1 # wait a little bit + + if [ ! -f "/var/run/hcseriald.${dev}.pid" ]; then + eend 1 "Unable to start hcseriald on ${dev}" + fi + ;; + + # 3Com Bluetooth Adapter 3CRWB60-A + btccc*) + # Obtain unit number from device. + unit=`expr ${dev} : 'btccc\([0-9]\{1,\}\)'` + if [ -z "${unit}" ]; then + eend 1 "Unable to get bt3c unit number: ${dev}" + fi + ;; + + # USB Bluetooth adapters + ubt*) + # Obtain unit number from device. + unit=`expr ${dev} : 'ubt\([0-9]\{1,\}\)'` + if [ -z "${unit}" ]; then + eend 1 "Unable to get ubt unit number: ${dev}" + fi + ;; + + # Unknown + *) + eend 1 "Unsupported device: ${dev}" + ;; + esac + + # Be backward compatible and setup reasonable defaults + bluetooth_device_authentication_enable="0" + bluetooth_device_class="ff:01:0c" + bluetooth_device_connectable="1" + bluetooth_device_discoverable="1" + bluetooth_device_encryption_mode="0" + bluetooth_device_hci_debug_level="3" + bluetooth_device_l2cap_debug_level="3" + bluetooth_device_local_name="`/usr/bin/uname -n` (${dev})" + bluetooth_device_role_switch="1" + + # Load the general device defaults + _file="/etc/defaults/bluetooth.device.conf" + if ! bluetooth_read_conf ; then + eend 1 "Unable to read default Bluetooth configuration from $_file" + fi + + # Load device specific overrides + _file="/etc/bluetooth/$dev.conf" + if ! bluetooth_read_conf ; then + eend 1 "Unable to read Bluetooth device configuration from $_file" + fi + + # Setup stack + if ! bluetooth_setup_stack ; then + bluetooth_shutdown_stack + eend 1 "Unable to setup Bluetooth stack for device ${dev}" + fi + + eend 0 +} + +############################################################################## +# stop() +############################################################################## + +stop() +{ + if [ -z ${dev} ] || [ "${dev}" = "bluetooth" ] ; then + #Master service, detect/stop all BT device services + stop_dev_services + return 0 + fi + + # Try to figure out device type by looking at device name + case "${dev}" in + # uartX - serial/UART Bluetooth device + uart*) + if [ -f "/var/run/hcseriald.${dev}.pid" ]; then + kill `cat /var/run/hcseriald.${dev}.pid` + sleep 1 # wait a little bit + fi + ;; + + # 3Com Bluetooth Adapter 3CRWB60-A + btccc*) + ;; + + # USB Bluetooth adapters + ubt*) + ;; + + # Unknown + *) + ewarn 1 "Unsupported device: ${dev}" + ;; + esac + + bluetooth_shutdown_stack + + return 0 +} Index: libexec/rc/etc.init.d/bootmisc =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/bootmisc @@ -0,0 +1,17 @@ +#!/sbin/openrc-run + +name="bootmisc" +desc="Dummy service for boot services" + +depend() +{ + need cleartmp cleanvar localmount ldconfig + before logger + after clock root sysctl + keyword -prefix -timeout +} + +start() +{ + return 0 +} Index: libexec/rc/etc.init.d/bootparams =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/bootparams @@ -0,0 +1,15 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +depend() +{ + need rpcbind + keyword -jail +} + +name="bootparamd" +desc="Boot parameter daemon" +required_files="/etc/bootparams" +command="/usr/sbin/${name}" Index: libexec/rc/etc.init.d/bridge =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/bridge @@ -0,0 +1,109 @@ +#!/sbin/openrc-run +# Copyright (c) 2016 - Kris Moore +# +# Copyright (c) 2006 The FreeBSD Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE PROJECT ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE PROJECT BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ +# + +name="bridge" +description="Network bridge setup" +extra_commands="static staticstop" + +. /etc/rc.subr +. /etc/network.subr + +depend() +{ + need localmount + use net + before inetd xinetd + keyword -jail -stop +} + +glob_int() { + case "$1" in + $2 ) true ;; + * ) false ;; + esac +} + +static() +{ + start +} + +staticstop() +{ + stop +} + +bridge_test() { + bridge=$1 + iface=$2 + + eval interfaces=\$autobridge_${bridge} + if [ -n "${interfaces}" ]; then + for i in ${interfaces}; do + if glob_int $iface $i ; then + ifconfig $bridge $cmd $iface > /dev/null 2>&1 + return + fi + done + fi +} + +autobridge() +{ + if [ -n "${autobridge_interfaces}" ]; then + if [ -z "$iflist" ]; then + # We're operating as a general network start routine. + iflist="`list_net_interfaces`" + fi + + for br in ${autobridge_interfaces}; do + for i in $iflist; do + bridge_test $br $i + done + done + fi +} + +start() +{ + iflist=${BRIDGE_IFLIST} + ebegin "Setting up bridge interfaces" + cmd="addm" + autobridge + eend $? +} + +stop() +{ + iflist=${BRIDGE_IFLIST} + ebegin "Destroying bridge interfaces" + cmd="deletem" + autobridge + eend $? +} + Index: libexec/rc/etc.init.d/bsnmpd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/bsnmpd @@ -0,0 +1,16 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +depend() +{ + need syslogd + keyword -jail -shutdown +} + +name="bsnmpd" +desc="Simple and extensible SNMP daemon" +command="/usr/sbin/${name}" +pidfile="${bsnmpd_pidfile:-/var/run/snmpd.pid}" +command_args="-p ${pidfile}" Index: libexec/rc/etc.init.d/bthidd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/bthidd @@ -0,0 +1,40 @@ +#!/sbin/openrc-run +################################### +# OpenRC service file for the "hcsecd" daemon +# Written by Ken Moore 4/10/2018 +# Available under the 2-clause BSD license +# +################################### +#General Info/Settings +name="bthidd" +description="Bluetooth HID daemon" +command="/usr/sbin/${name}" +pidfile="/var/run/${name}.pid" +command_background="true" +output_file="/var/log/${name}" +error_file="/var/log/${name}" + +config="${bthidd_config:-/etc/bluetooth/${name}.conf}" +hids="${bthidd_hids:-/var/db/${name}.hids}" +command_args="-d -c ${config} -H ${hids} -p ${pidfile}" +required_modules="kbdmux vkbd ng_btsocket" + +depend(){ + before bluetooth + keyword -jail -shutdown +} + +start_pre(){ + for i in ${required_modules} + do + kldload -n "${i}" >/dev/null 2>/dev/null + if [ $? -ne 0 ] ; then + eerror "Could not load required kernel module: ${i}" + return 1 + fi + done + if [ ! -e "${config}" ] ; then + touch "${config}" + fi + return 0 +} Index: libexec/rc/etc.init.d/ccd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ccd @@ -0,0 +1,23 @@ +#!/sbin/openrc-run +# + +depend() +{ + keyword -jail +} + +name="ccd" +desc="Concatenated disks setup" + +start() +{ + if [ -f /etc/ccd.conf ]; then + einfo "Configuring CCD devices." + ccdconfig -C + fi +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/cfumass =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/cfumass @@ -0,0 +1,113 @@ +#!/sbin/openrc-run +# + +depend() +{ + keyword -jail +} + +name="cfumass" +desc="Configure the LUN for device mode USB mass storage" + +: ${cfumass_dir:=/var/cfumass} +: ${cfumass_image:=/var/tmp/cfumass.img} +: ${cfumass_vendor:="FreeBSD"} +: ${cfumass_product:="cfumass(4)"} + +remove_luns() +{ + local _lun _luns + + _luns=`ctladm devlist -b block -v | awk ' + + $1 ~ /^[0-9]+$/ { + lun = $1 + } + + $1 == "file='"${cfumass_image}"'" { + print lun + }'` + + for _lun in ${_luns}; do + ctladm remove -b block -l "${_lun}" > /dev/null + done +} + +start() +{ + local err _files _template + + if [ ! -d "${cfumass_dir}" ]; then + ewarn "${cfumass_dir} does not exist" + return 1 + fi + + _files=`find "${cfumass_dir}" -newer "${cfumass_image}" -print 2> /dev/null` + if [ ! -e "${cfumass_image}" -o -n "${_files}" ]; then + # The image doesn't exist or is out of date. + makefs -t cd9660 -o rockridge "${cfumass_image}" "${cfumass_dir}" + err=$? + if [ "${err}" -ne 0 ]; then + ewarn "unable to create ${cfumass_image}" + return "${err}" + fi + fi + + remove_luns + + ctladm create -b block -o file="${cfumass_image}" -o readonly=on \ + -o vendor="${cfumass_vendor}" -o product="${cfumass_product}" \ + -t 5 -S 0 > /dev/null + err=$? + if [ "${err}" -ne 0 ]; then + ewarn "unable to create CTL LUN" + return "${err}" + fi + + load_kld -e cfumass cfumass + + # If the template is already switched to Mass Storage, then reset + # it to -1 to force the host to reenumerate it; otherwise it might + # not notice the new LUN. + _template=`sysctl -n hw.usb.template` + if [ "${_template}" -eq 0 ]; then + sysctl hw.usb.template=-1 > /dev/null + err=$? + if [ "${err}" -ne 0 ]; then + ewarn "unable to set hw.usb.template sysctl" + return "${err}" + fi + fi + + _template=`sysctl -n hw.usb.template` + if [ "${_template}" -lt 0 ]; then + sysctl hw.usb.template=0 > /dev/null + err=$? + if [ "${err}" -ne 0 ]; then + ewarn "unable to set hw.usb.template sysctl" + return "${err}" + fi + else + # Otherwise don't touch the sysctl - we could lock the user + # out of the machine otherwise. + ewarn "hw.usb.template sysctl set to neither -1 nor 0" + fi +} + +stop() +{ + local err _template + + _template=`sysctl -n hw.usb.template` + if [ "${_template}" -eq 0 ]; then + sysctl hw.usb.template=-1 > /dev/null + err=$? + if [ "${err}" -ne 0 ]; then + ewarn "unable to set hw.usb.template sysctl" + return "${err}" + fi + fi + + remove_luns + return 0 +} Index: libexec/rc/etc.init.d/cleanvar =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/cleanvar @@ -0,0 +1,66 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +. /etc/rc.subr + +name="cleanvar" +desc="Purge /var directory" + +depend() +{ + need localmount var + before logger + after clock root sysctl + keyword -prefix -timeout +} + +purgedir() +{ + local dir file + + if [ $# -eq 0 ]; then + purgedir . + else + for dir + do + ( + cd "$dir" && for file in .* * + do + # Skip over logging sockets + [ -S "$file" -a "$file" = "log" ] && continue + [ -S "$file" -a "$file" = "logpriv" ] && continue + [ ."$file" = .. -o ."$file" = ... ] && continue + if [ -d "$file" -a ! -L "$file" ] + then + purgedir "$file" + else + rm -f -- "$file" + fi + done + ) + done + fi +} + +start_pre() +{ + # These files must be removed only the first time this script is run + # on boot. + # + rm -f /var/run/clean_var /var/spool/lock/clean_var +} + +start() +{ + if [ -d /var/run -a ! -f /var/run/clean_var ]; then + purgedir /var/run + >/var/run/clean_var + fi + if [ -d /var/spool/lock -a ! -f /var/spool/lock/clean_var ]; then + purgedir /var/spool/lock + >/var/spool/lock/clean_var + fi + rm -rf /var/spool/uucp/.Temp/* +} Index: libexec/rc/etc.init.d/cleartmp =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/cleartmp @@ -0,0 +1,57 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +. /etc/rc.subr + +name="cleartmp" +desc="Purge /tmp directory" + +depend() +{ + need localmount tmp + before logger + after clock root sysctl + keyword -prefix -timeout +} + +start() +{ + # Make /tmp location variable for easier debugging. + local tmp="/tmp" + + # X related directories to create in /tmp. + local x11_socket_dirs="${tmp}/.X11-unix ${tmp}/.XIM-unix \ + ${tmp}/.ICE-unix ${tmp}/.font-unix" + + check_startmsgs && einfo "Clearing ${tmp}." + + # This is not needed for mfs, but doesn't hurt anything. + # Things to note: + # + The dot in ${tmp}/. is important. + # + Put -prune before -exec so find never descends + # into a directory that was already passed to rm -rf. + # + "--" in rm arguments isn't strictly necessary, but + # it can prevent foot-shooting in future. + # + /tmp/lost+found is preserved, but its contents are removed. + # + lost+found and quota.* in subdirectories are removed. + # + .sujournal and .snap are preserved. + find -x ${tmp}/. ! -name . \ + ! \( -name .sujournal -type f -user root \) \ + ! \( -name .snap -type d -user root \) \ + ! \( -name lost+found -type d -user root \) \ + ! \( \( -name quota.user -or -name quota.group \) \ + -type f -user root \) \ + -prune -exec rm -rf -- {} + + if checkyesno clear_tmp_X; then + # Remove X lock files, since they will prevent you from + # restarting X. Remove other X related directories. + check_startmsgs && einfo "Clearing ${tmp} (X related)." + rm -rf ${tmp}/.X[0-9]-lock ${x11_socket_dirs} + fi + if checkyesno clear_tmp_X; then + # Create X related directories with proper permissions. + mkdir -m 1777 ${x11_socket_dirs} + fi +} Index: libexec/rc/etc.init.d/cron =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/cron @@ -0,0 +1,13 @@ +#!/sbin/openrc-run + +name="cron" +desc="Daemon to execute scheduled commands" +command="/usr/sbin/${name}" +command_args_foreground="-n -s" +pidfile=/var/run/supervised-cron.pid +supervisor=supervise-daemon + +depend() { + use clock logger + need localmount +} Index: libexec/rc/etc.init.d/ctld =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ctld @@ -0,0 +1,14 @@ +#!/sbin/openrc-run +# + +depend() +{ + keyword -jail +} + +name="ctld" +desc="CAM Target Layer / iSCSI target daemon" +pidfile="/var/run/${name}.pid" +command="/usr/sbin/${name}" +required_files="/etc/ctl.conf" +required_modules="ctl" Index: libexec/rc/etc.init.d/ddb =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ddb @@ -0,0 +1,33 @@ +#!/sbin/openrc-run +# + +depend() +{ + need dumpon + keyword -jail +} + +name="ddb" +desc="DDB kernel debugger" +rcvar="ddb_enable" +command="/sbin/${name}" +required_files="${ddb_config}" +command_args="${ddb_config}" + +start_pre() +{ + # Silently exit if ddb is not enabled + if [ -z "`sysctl -Nq debug.ddb.scripting.scripts`" ]; then + return 1 + fi +} + +start() +{ + ${command} ${command_args} +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/devd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/devd @@ -0,0 +1,33 @@ +#!/sbin/openrc-run + +BIN=/sbin/devd +pid="/var/run/devd.pid" +args="$devd_args -f /etc/devd-openrc.conf -d -q" +name="devd" +description="Device State Change Daemon" + +depend() { + need localmount + after bootmisc network + keyword -jail -prefix -stop +} + +start_pre() { + sysctl hw.bus.devctl_disable=0 >/dev/null +} + +stop_post() { + sysctl hw.bus.devctl_disable=1 >/dev/null +} + +start() { + ebegin "Starting $name" + start-stop-daemon --start --exec ${BIN} -b -m -p ${pid} -- ${args} >/var/log/devd.log 2>/var/log/devd.log + eend $? +} + +stop() { + ebegin "Stopping $name" + start-stop-daemon --stop --exec ${BIN} -p ${pid} + eend $? +} Index: libexec/rc/etc.init.d/devfs =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/devfs @@ -0,0 +1,259 @@ +#!/sbin/openrc-run + +name="devfs" +devfs_rulesets="/etc/defaults/devfs.rules /etc/devfs.rules" + +depend() { + need localmount + keyword -jail -prefix -stop +} + +# devfs_rulesets_from_file file +# Reads a set of devfs commands from file, and creates +# the specified rulesets with their rules. Returns non-zero +# if there was an error. +# +devfs_rulesets_from_file() +{ + local file _err _me _opts + file="$1" + _me="devfs_rulesets_from_file" + _err=0 + + if [ -z "$file" ]; then + ewarn "$_me: you must specify a file" + return 1 + fi + if [ ! -e "$file" ]; then + einfo "$_me: no such file ($file)" + return 0 + fi + + # Disable globbing so that the rule patterns are not expanded + # by accident with matching filesystem entries. + _opts=$-; set -f + + #einfo "reading rulesets from file ($file)" + { while read line + do + case $line in + \#*) + continue + ;; + \[*\]*) + rulenum=`expr "$line" : "\[.*=\([0-9]*\)\]"` + if [ -z "$rulenum" ]; then + ewarn "$_me: cannot extract rule number ($line)" + _err=1 + break + fi + rulename=`expr "$line" : "\[\(.*\)=[0-9]*\]"` + if [ -z "$rulename" ]; then + ewarn "$_me: cannot extract rule name ($line)" + _err=1 + break; + fi + eval $rulename=\$rulenum + #einfo "found ruleset: $rulename=$rulenum" + + if ! /sbin/devfs rule -s $rulenum delset; then + _err=1 + break + fi + ;; + *) + rulecmd="${line%%"\#*"}" + # evaluate the command incase it includes + # other rules + if [ -n "$rulecmd" ]; then + #einfo "adding rule ($rulecmd)" + if ! eval /sbin/devfs rule -s $rulenum $rulecmd + then + _err=1 + break + fi + fi + ;; + esac + if [ $_err -ne 0 ]; then + ewarn "error in $_me" + break + fi + done } < $file + case $_opts in *f*) ;; *) set +f ;; esac + return $_err +} + +# devfs_init_rulesets +# Initializes rulesets from configuration files. Returns +# non-zero if there was an error. +# +devfs_init_rulesets() +{ + local file _me + _me="devfs_init_rulesets" + + # Go through this only once + if [ -n "$devfs_rulesets_init" ]; then + einfo "$_me: devfs rulesets already initialized" + return + fi + for file in $devfs_rulesets; do + if ! devfs_rulesets_from_file $file; then + ewarn "$_me: could not read rules from $file" + return 1 + fi + done + devfs_rulesets_init=1 + #einfo "$_me: devfs rulesets initialized" + return 0 +} + +# devfs_set_ruleset ruleset [dir] +# Sets the default ruleset of dir to ruleset. The ruleset argument +# must be a ruleset name as specified in devfs.rules(5) file. +# Returns non-zero if it could not set it successfully. +# +devfs_set_ruleset() +{ + local devdir rs _me + [ -n "$1" ] && rs=$1 || rs= + [ -n "$2" ] && devdir="-m "$2"" || devdir= + _me="devfs_set_ruleset" + + # Get the ruleset number + rs=`grep "^\[${1}=" /etc/devfs.rules | cut -d = -f 2 | sed 's|]||g' | tr -d ' '` + + if [ -z "$rs" ]; then + ewarn "$_me: you must specify a ruleset number" + return 1 + fi + #einfo "$_me: setting ruleset ($rs) on mount-point (${devdir#-m })" + if ! /sbin/devfs $devdir ruleset $rs; then + ewarn "$_me: unable to set ruleset $rs to ${devdir#-m }" + return 1 + fi + return 0 +} + +# devfs_apply_ruleset ruleset [dir] +# Apply ruleset number $ruleset to the devfs mountpoint $dir. +# The ruleset argument must be a ruleset name as specified +# in a devfs.rules(5) file. Returns 0 on success or non-zero +# if it could not apply the ruleset. +# +devfs_apply_ruleset() +{ + local devdir rs _me + [ -n "$2" ] && devdir="-m "$2"" || devdir= + _me="devfs_apply_ruleset" + + # Get the ruleset number + rs=`grep "^\[${1}=" /etc/devfs.rules | cut -d = -f 2 | sed 's|]||g' | tr -d ' '` + + if [ -z "$rs" ]; then + ewarn "$_me: you must specify a ruleset" + return 1 + fi + #einfo "$_me: applying ruleset ($rs) to mount-point (${devdir#-m })" + if ! /sbin/devfs $devdir rule -s $rs applyset; then + ewarn "$_me: unable to apply ruleset $rs to ${devdir#-m }" + return 1 + fi + return 0 +} + +# devfs_domount dir [ruleset] +# Mount devfs on dir. If ruleset is specified it is set +# on the mount-point. It must also be a ruleset name as specified +# in a devfs.rules(5) file. Returns 0 on success. +# +devfs_domount() +{ + local devdir rs _me + devdir="$1" + [ -n "$2" ] && rs=$2 || rs= + _me="devfs_domount()" + + if [ -z "$devdir" ]; then + ewarn "$_me: you must specify a mount-point" + return 1 + fi + einfo "$_me: mount-point is ($devdir), ruleset is ($rs)" + if ! mount -t devfs dev "$devdir"; then + ewarn "$_me: Unable to mount devfs on $devdir" + return 1 + fi + if [ -n "$rs" ]; then + devfs_init_rulesets + devfs_set_ruleset $rs $devdir + devfs -m $devdir rule applyset + fi + return 0 +} + +devfs_apply() +{ + if [ ! -e /etc/devfs.rules ] ; then return 0 ; fi + if [ -z "$devfs_system_ruleset" ] ; then devfs_system_ruleset="devfsrules_common"; fi + if [ -n "$devfs_system_ruleset" -o -n "$devfs_set_rulesets" ]; then + devfs_init_rulesets + if [ -n "$devfs_system_ruleset" ]; then + devfs_set_ruleset $devfs_system_ruleset /dev + devfs_apply_ruleset $devfs_system_ruleset /dev + fi + if [ -n "$devfs_set_rulesets" ]; then + local _dir_set + local _dir + local _set + for _dir_set in $devfs_set_rulesets; do + _dir=${_dir_set%=*} + _set=${_dir_set#*=} + devfs_set_ruleset $_set $_dir + devfs_apply_ruleset $_set $_dir + done + fi + fi + read_devfs_conf +} + +read_devfs_conf() +{ + if [ -r /etc/devfs.conf ]; then + cd /dev + while read action devicelist parameter; do + case "${action}" in + l*) for device in ${devicelist}; do + if [ ! -e ${parameter} ]; then + ln -fs ${device} ${parameter} + fi + done + ;; + o*) for device in ${devicelist}; do + if [ -c ${device} ]; then + chown ${parameter} ${device} + fi + done + ;; + p*) for device in ${devicelist}; do + if [ -c ${device} ]; then + chmod ${parameter} ${device} + fi + done + ;; + esac + done < /etc/devfs.conf + fi +} + +start() +{ + ebegin "Starting $name" + devfs_apply + eend $? +} + +stop() { + ebegin "Stopping $name" + eend $? +} Index: libexec/rc/etc.init.d/devmatch =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/devmatch @@ -0,0 +1,63 @@ +#!/sbin/openrc-run + +# Copyright (c) 2018 M. Warner Losh +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +name="devmatch" +desc="Use devmatch(8) to load kernel modules" +rcvar="${name}_enable" + +one_nomatch="$devd_args" + +start() +{ + local x + + if [ -n "$one_nomatch" ]; then + x=$(devmatch -p "${one_nomatch}") + else + x=$(devmatch) + fi + + [ -n "$x" ] || return + + # While kldload can accept multiple modules + # on the line at once, we loop here in case + # there's some weird error with one of them. + # We also optimize against the false positives + # or drivers that have symbolic links that + # confuse devmatch by running it -n. + for m in ${x}; do + einfo "Autoloading module: ${m}" + kldload -n ${m} + done + return 0 +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/dmesg =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/dmesg @@ -0,0 +1,23 @@ +#!/sbin/openrc-run +# + +depend() +{ + after mountcritremote + keyword -jail +} + +name="dmesg" +desc="Save kernel boot messages to disk" +dmesg_file="/var/run/dmesg.boot" + +start() +{ + rm -f ${dmesg_file} + ( umask 022 ; /sbin/dmesg $rc_flags > ${dmesg_file} ) +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/dumpon =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/dumpon @@ -0,0 +1,32 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Configures a specific kernel dump device." + +depend() { + need swap + keyword -jail -prefix +} + +start() { + # Setup any user requested dump device + if [ -n "$dump_device" ]; then + ebegin "Activating kernel core dump device ($dump_device)" + dumpon ${dump_device} + eend $? + fi +} + +stop() { + ebegin "Deactivating kernel core dump device" + dumpon off + eend $? +} Index: libexec/rc/etc.init.d/earlykld =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/earlykld @@ -0,0 +1,46 @@ +#!/sbin/openrc-run + +# Copyright (c) 2011 Douglas Barton +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +name="earlykld" + +depend() +{ + before fsck localmount + keyword -jail -prefix +} + +start() +{ + [ -n "$early_kld_list" ] || return + + local _kld + + einfo 'Loading early kernel modules:' + for _kld in $early_kld_list ; do + load_kld -e ${_kld}.ko $_kld + done +} Index: libexec/rc/etc.init.d/encswap =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/encswap @@ -0,0 +1,43 @@ +#!/sbin/openrc-run +# Copyright 1992-2012 FreeBSD Project +# Released under the 2-clause BSD license + +depend() { + before swap +} + +start() { + while read device mountpoint type options rest ; do + case ":${device}:${type}:${options}" in + :#*) + ;; + *.bde:swap:sw) + passphrase=$(dd if=/dev/random count=1 2>/dev/null | md5 -q) + device="${device%.bde}" + gbde init "${device}" -P "${passphrase}" || return 1 + gbde attach "${device}" -p "${passphrase}" || return 1 + ;; + *.eli:swap:sw) + device="${device%.eli}" + geli onetime ${geli_swap_flags} "${device}" || return 1 + ;; + esac + done < /etc/fstab +} + +stop() { + while read device mountpoint type options rest ; do + case ":${device}:${type}:${options}" in + :#*) + ;; + *.bde:swap:sw) + device="${device%.bde}" + gbde detach "${device}" + ;; + *.eli:swap:sw) + # Nothing here, because geli swap devices should be + # created with the auto-detach-on-last-close option. + ;; + esac + done < /etc/fstab +} Index: libexec/rc/etc.init.d/fsck =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/fsck @@ -0,0 +1,132 @@ +#!/sbin/openrc-run +# Copyright (c) 2016 - Kris Moore +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. +# + +description="Check and repair filesystems according to /etc/fstab" +_IFS=" +" + +depend() +{ + use dev clock modules + keyword -jail -prefix -timeout -uml +} + +_abort() { + yesno ${fsck_abort_on_errors:-yes} && rc-abort + return 1 +} + +# We should only reboot when first booting +_reboot() { + if [ "$RC_RUNLEVEL" = "$RC_BOOTLEVEL" ]; then + reboot "$@" + _abort || return 1 + fi +} + +_forcefsck() +{ + [ -e /forcefsck ] || get_bootparam forcefsck +} + +start() +{ + local fsck_opts= p= check_extra= + + if [ -e /fastboot ]; then + ewarn "Skipping fsck due to /fastboot" + return 0 + fi + if _forcefsck; then + fsck_opts="$fsck_opts -f" + check_extra="(check forced)" + elif ! yesno ${fsck_on_battery:-YES} && ! on_ac_power; then + ewarn "Skipping fsck due to not being on AC power" + return 0 + fi + + if [ -n "$fsck_passno" ]; then + check_extra="[passno $fsck_passno] $check_extra" + if [ -n "$fsck_mnt" ]; then + eerror "Only 1 of fsck_passno and fsck_mnt must be set!" + return 1 + fi + fi + ebegin "Checking local filesystems $check_extra" + # Append passno mounts + for p in $fsck_passno; do + local IFS="$_IFS" + case "$p" in + [0-9]*) p="=$p";; + esac + set -- "$@" $(fstabinfo --passno "$p") + unset IFS + done + # Append custom mounts + for m in $fsck_mnt ; do + local IFS="$_IFS" + set -- "$@" "$m" + unset IFS + done + + if [ "$RC_UNAME" = Linux ]; then + local skiptypes + skiptypes=$(printf 'no%s,' ${net_fs_list} ${extra_net_fs_list}) + [ "${skiptypes}" = "no," ] && skiptypes="" + fsck_opts="$fsck_opts -C0 -T -t ${skiptypes}noopts=_netdev" + if [ -z "$fsck_passno" -a -z "$fsck_mnt" ]; then + fsck_args=${fsck_args:--A -p} + if echo 2>/dev/null >/.test.$$; then + rm -f /.test.$$ + fsck_opts="$fsck_opts -R" + fi + fi + fi + + trap : INT QUIT + fsck ${fsck_args:--p} $fsck_opts "$@" + case $? in + 0) eend 0; return 0;; + 1) ewend 1 "Filesystems repaired"; return 0;; + 2|3) if [ "$RC_UNAME" = Linux ]; then + ewend 1 "Filesystems repaired, but reboot needed" + _reboot -f + else + ewend 1 "Filesystems still have errors;" \ + "manual fsck required" + _abort + fi;; + 4) if [ "$RC_UNAME" = Linux ]; then + ewend 1 "Fileystem errors left uncorrected, aborting" + _abort + else + ewend 1 "Filesystems repaired, but reboot needed" + _reboot + fi;; + 8) ewend 1 "Operational error"; return 0;; + 12) ewend 1 "fsck interrupted";; + *) eend 2 "Filesystems couldn't be fixed";; + esac + _abort || return 1 +} + +stop() +{ + # Fake function so we always shutdown correctly. + _abort() { return 0; } + _reboot() { return 0; } + _forcefsck() { return 1; } + + yesno $fsck_shutdown && start + return 0 +} Index: libexec/rc/etc.init.d/ftp-proxy =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ftp-proxy @@ -0,0 +1,20 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +name="ftpproxy" +desc="Internet File Transfer Protocol proxy daemon" +command="/usr/sbin/ftp-proxy" + +depend() +{ + need localmount pf + use net +} Index: libexec/rc/etc.init.d/ftpd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ftpd @@ -0,0 +1,13 @@ +#!/sbin/openrc-run + +command=/usr/libexec/ftpd +command_args="-D $ftpd_args" +pidfile=/var/run/ftpd.pid +name="Internet File Transfer Protocol daemon" + +depend() +{ + need localmount + use net logger + keyword -stop +} Index: libexec/rc/etc.init.d/gbde =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/gbde @@ -0,0 +1,121 @@ +#!/sbin/openrc-run +# +# This file, originally written by Garrett A. Wollman, is in the public +# domain. +# + +depend() +{ + keyword -jail +} + +name="gbde" +desc="GEOM Based Disk Encryption" + +start_pre() +{ + find_gbde_devices start +} + +stop_pre() +{ + find_gbde_devices stop +} + +find_gbde_devices() +{ + case "${gbde_devices-auto}" in + [Aa][Uu][Tt][Oo]) + gbde_devices="" + ;; + *) + return 0 + ;; + esac + + case "$1" in + start) + fstab="/etc/fstab" + ;; + stop) + fstab=$(mktemp /tmp/mtab.XXXXXX) + mount -p >${fstab} + ;; + esac + + # + # We can't use "mount -p | while ..." because when a shell loop + # is the target of a pipe it executes in a subshell, and so can't + # modify variables in the script. + # + while read device mountpt type options dump pass; do + case "$device" in + *.bde) + # Ignore swap devices + case "$type" in + swap) + continue + ;; + esac + + case "$options" in + *noauto*) + if checkyesno gbde_autoattach_all; then + gbde_devices="${gbde_devices} ${device}" + fi + ;; + *) + gbde_devices="${gbde_devices} ${device}" + ;; + esac + ;; + esac + done <${fstab} + + case "$1" in + stop) + rm -f ${fstab} + ;; + esac + + return 0 +} + +start() +{ + for device in $gbde_devices; do + parent=${device%.bde} + parent=${parent#/dev/} + parent_=`ltr ${parent} '/' '_'` + eval "lock=\${gbde_lock_${parent_}-\"${gbde_lockdir}/${parent_}.lock\"}" + if [ -e "/dev/${parent}" -a ! -e "/dev/${parent}.bde" ]; then + einfo "Configuring Disk Encryption for ${parent}." + + count=1 + while [ ${count} -le ${gbde_attach_attempts} ]; do + if [ -e "${lock}" ]; then + gbde attach ${parent} -l ${lock} + else + gbde attach ${parent} + fi + if [ -e "/dev/${parent}.bde" ]; then + break + fi + ewarn "Attach failed; attempt ${count} of ${gbde_attach_attempts}." + count=$((${count} + 1)) + done + fi + done +} + +stop() +{ + for device in $gbde_devices; do + parent=${device%.bde} + parent=${parent#/dev/} + if [ -e "/dev/${parent}.bde" ]; then + umount "/dev/${parent}.bde" 2>/dev/null + gbde detach "${parent}" + fi + done +} Index: libexec/rc/etc.init.d/gptboot =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/gptboot @@ -0,0 +1,76 @@ +#!/sbin/openrc-run +# +# Copyright (c) 2010 Pawel Jakub Dawidek +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +depend() +{ + keyword -jail +} + +. /etc/rc.subr + +name="gptboot" + +start() +{ + gpart show | \ + egrep '(^=>| freebsd-ufs .*(\[|,)(bootfailed|bootonce)(,|\]))' | \ + sed 's/^=>//' | \ + egrep -v '(\[|,)bootme(,|\])' | \ + while read start size pos type attrs rest; do + case "${pos}" in + [0-9]*) + if [ -n "${disk}" ]; then + part="${disk}p${pos}" + echo "${attrs}" | egrep -q '(\[|,)bootfailed(,|\])' + bootfailed=$? + echo "${attrs}" | egrep -q '(\[|,)bootonce(,|\])' + bootonce=$? + if [ ${bootfailed} -eq 0 ]; then + logger -t gptboot -p local0.notice "Boot from ${part} failed." + gpart unset -a bootfailed -i ${pos} ${disk} >/dev/null + elif [ ${bootonce} -eq 0 ]; then + # We want to log success after all failures. + einfo "Boot from ${part} succeeded." + gpart unset -a bootonce -i ${pos} ${disk} >/dev/null + fi + fi + ;; + *) + if [ "${type}" = "GPT" ]; then + disk="${pos}" + else + disk="" + fi + ;; + esac + done | logger -t gptboot -p local0.notice +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/growfs =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/growfs @@ -0,0 +1,100 @@ +#!/sbin/openrc-run +# +# Copyright 2014 John-Mark Gurney +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +depend() +{ + before sysctl +} + +# This allows us to distribute a image +# and have it work on essentially any size drive. +# +# TODO: Figure out where this should really be ordered. +# I suspect it should go just after fsck but before mountcritlocal. +# + +name="growfs" +desc="Grow root partition to fill device" + +start() +{ + # If flag exists, skip the growfs run + if [ -e "/var/.growfs-firstrun" ] ; then + return 0 + fi + + einfo "Growing root partition to fill device" + rootdev=$(df / | tail -n 1 | awk '{ sub("/dev/", "", $1); print $1 }') + if [ x"$rootdev" = x"${rootdev%/*}" ]; then + # raw device + rawdev="$rootdev" + else + rawdev=$(glabel status | awk '$1 == "'"$rootdev"'" { print $3 }') + if [ x"$rawdev" = x"" ]; then + ewarn "Can't figure out device for: $rootdev" + return 1 + fi + fi + + sysctl -b kern.geom.conftxt | awk ' +{ + lvl=$1 + device[lvl] = $3 + type[lvl] = $2 + idx[lvl] = $7 + parttype[lvl] = $13 + if (dev == $3) { + for (i = 1; i <= lvl; i++) { + # resize + if (type[i] == "PART") { + pdev = device[i - 1] + cmd[i] = "gpart resize -i " idx[i] " " pdev + if (parttype[i] == "GPT") + cmd[i] = "gpart recover " pdev " ; " cmd[i] + } else if (type[i] == "LABEL") { + continue + } else { + print "unhandled type: " type[i] + exit 1 + } + } + for (i = 1; i <= lvl; i++) { + if (cmd[i]) + system(cmd[i]) + } + exit 0 + } +}' dev="$rawdev" + gpart commit "$rootdev" + growfs -y /dev/"$rootdev" + touch /var/.growfs-firstrun +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/gssd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/gssd @@ -0,0 +1,9 @@ +#!/sbin/openrc-run + +command=/usr/sbin/gssd +name="Generic Security Services Daemon" + +depend() +{ + need localmount +} Index: libexec/rc/etc.init.d/hastd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/hastd @@ -0,0 +1,22 @@ +#!/sbin/openrc-run +# + +depend() +{ + need syslogd + keyword -jail -shutdown +} + +name="hastd" +desc="Highly Available Storage daemon" +pidfile="/var/run/${name}.pid" +command="/sbin/${name}" +hastctl="/sbin/hastctl" +required_files="/etc/hast.conf" +required_modules="geom_gate:g_gate" + +stop_pre() +{ + + ${hastctl} role init all +} Index: libexec/rc/etc.init.d/hcsecd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/hcsecd @@ -0,0 +1,48 @@ +#!/sbin/openrc-run +################################### +# OpenRC service file for the "hcsecd" daemon +# Written by Ken Moore 4/10/2018 +# Available under the 2-clause BSD license +# +################################### +#General Info/Settings +name="hcsecd" +description="Control link keys and PIN codes for Bluetooth devices" +command="/usr/sbin/${name}" +pidfile="/var/run/${name}.pid" +required_modules="ng_btsocket" +supervisor="supervise-daemon" +output_file="/var/log/${name}.log" +error_file="/var/log/${name}.log" + +#Respect config file +config="${hcsecd_config:-/etc/bluetooth/${name}.conf}" +command_args="-d -f ${config}" +required_files="${config}" + +depend(){ + before devd + keyword -jail -shutdown +} + +extra_started_commands="reload" +description_reload="Prompt the service to reload its configuration files" + +reload(){ + #Send the HUP signal to the daemon to reload the configs + local _pid + _pid=`cat ${pidfile}` + kill -s HUP ${_pid} +} + +start_pre(){ + for i in ${required_modules} + do + kldload -n "${i}" >/dev/null 2>/dev/null + if [ $? -ne 0 ] ; then + eerror "Could not load required kernel module: ${i}" + return 1 + fi + done + return 0 +} Index: libexec/rc/etc.init.d/hostapd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/hostapd @@ -0,0 +1,30 @@ +#!/sbin/openrc-run + +name="hostapd" +description="Authenticator for IEEE 802.11 networks" +command=/usr/sbin/hostapd +ifn="$2" +if [ -z "$ifn" ]; then + rcvar="hostapd_enable" + conf_file="/etc/${name}.conf" + pidfile="/var/run/${name}.pid" +else + rcvar= + conf_file="/etc/${name}-${ifn}.conf" + pidfile="/var/run/${name}-${ifn}.pid" +fi +command_args="-P ${pidfile} -B ${conf_file}" +required_files="${conf_file}" + + +depend() +{ + need localmount + use net + keyword -shutdown -jail +} + +start_pre() +{ + load_kld wlan_xauth wlan_wep wlan_tkip wlan_ccmp +} Index: libexec/rc/etc.init.d/hostid =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/hostid @@ -0,0 +1,85 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +extra_commands="reset" +: ${hostid_file:=/etc/hostid} + +depend() +{ + use root + before devd net + keyword -jail -prefix +} + +_set() +{ + local id=0 + + if [ -n "$1" ]; then + id=$(echo "$1" | md5) + id="0x${id%????????????????????????}" + fi + sysctl -w kern.hostid="$id" >/dev/null + if [ $? -ne 0 ] ; then return 1 ; fi + + if sysctl -n kern.hostuuid >/dev/null 2>&1; then + [ -n "$1" ] && id=$1 + sysctl kern.hostuuid="$id" >/dev/null + if [ $? -ne 0 ] ; then return 1 ; fi + fi + +} + +# First we check to see if there is a system UUID +# If so then we use that and erase the hostid file, +# otherwise we generate a random UUID. +reset() +{ + local uuid= x="[0-9a-f]" y="$x$x$x$x" + + if command -v kenv >/dev/null 2>&1; then + uuid=$(kenv smbios.system.uuid 2>/dev/null) + fi + case "$uuid" in + $y$y-$y-$y-$y-$y$y$y);; + *) uuid=;; + esac + + if [ -n "$uuid" ]; then + rm -f "$hostid_file" + else + uuid=$(uuidgen) + if [ -z "$uuid" ]; then + eerror "Unable to generate a UUID" + return 1 + fi + if ! echo "$uuid" >"$hostid_file"; then + eerror "Failed to store UUID in \`$hostid_file'" + return 1 + fi + fi + + _set "$uuid" +} + +start() +{ + if [ -r "$hostid_file" ]; then + _set $(cat "$hostid_file") + else + reset + fi +} + +stop() +{ + _set +} Index: libexec/rc/etc.init.d/hostid_save =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/hostid_save @@ -0,0 +1,30 @@ +#!/sbin/openrc-run +# + +provide() +{ + need hostid + keyword -jail +} + +SYSCTL_N="sysctl -n" + +name="hostid_save" +desc="Save unique host ID to disk" + +start() +{ + current_hostid=`$SYSCTL_N kern.hostuuid` + + if [ -r ${hostid_file} ]; then + read saved_hostid < ${hostid_file} + if [ ${saved_hostid} = ${current_hostid} ]; then + exit 0 + fi + fi + + echo ${current_hostid} > ${hostid_file} + if [ $? -ne 0 ]; then + ewarn "could not store hostuuid in ${hostid_file}." + fi +} Index: libexec/rc/etc.init.d/hostname =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/hostname @@ -0,0 +1,36 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Sets the hostname of the machine." + +depend() { + keyword -prefix +} + +start() +{ + local h source x + if [ -s /etc/hostname ] && [ -r /etc/hostname ]; then + read h x /dev/null + fi + done +} + +start() +{ + run_iovctl -C +} + +stop() +{ + run_iovctl -D +} Index: libexec/rc/etc.init.d/ipfs =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ipfs @@ -0,0 +1,42 @@ +#!/sbin/openrc-run +# + +depend() +{ + keyword -jail -shutdown +} + +name="ipfs" +desc="Saves and restores information for NAT and state tables" + +start_pre() +{ + # Do not continue if either ipnat or ipfilter is not enabled or + # if the ipfilter module is not loaded. + # + if ! checkyesno ipfilter_enable -o ! checkyesno ipnat_enable ; then + eend 1 "${name} requires either ipfilter or ipnat enabled" + fi + if ! ${ipfilter_program:-/sbin/ipf} -V | grep -q 'Running: yes' >/dev/null 2>&1; then + eend 1 "ipfilter module is not loaded" + fi + return 0 +} + +start() +{ + if [ -r /var/db/ipf/ipstate.ipf -a -r /var/db/ipf/ipnat.ipf ]; then + ${ipfs_program} -R ${rc_flags} + rm -f /var/db/ipf/ipstate.ipf /var/db/ipf/ipnat.ipf + fi +} + +stop() +{ + if [ ! -d /var/db/ipf ]; then + mkdir /var/db/ipf + chmod 700 /var/db/ipf + chown root:wheel /var/db/ipf + fi + ${ipfs_program} -W ${rc_flags} +} Index: libexec/rc/etc.init.d/ipfw =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ipfw @@ -0,0 +1,114 @@ +#!/sbin/openrc-run + +name="ipfw" +description="Firewall, traffic shaper, packet scheduler, in-kernel NAT" +firewall_coscripts="natd ${firewall_coscripts}" +SYSCTL="/sbin/sysctl" + +. /etc/rc.subr +. /etc/network.subr + +depend() { + before net + provide firewall + keyword -jail -stop -shutdown +} + +start_pre() +{ + load_kld ipfw + if yesno dummynet_enable; then + load_kld "dummynet" + fi + if yesno natd_enable; then + load_kld "ipdivert" + fi + if yesno firewall_nat_enable; then + load_kld "ipfw_nat" + fi +} + +start() +{ + local _firewall_type + + _firewall_type=$1 + + ebegin "Starting $name" + # set the firewall rules script if none was specified + [ -z "${firewall_script}" ] && firewall_script=/etc/ipfw.rules + + if [ -r "${firewall_script}" ]; then + /bin/sh "${firewall_script}" "${_firewall_type}" + elif [ "`ipfw list 65535`" = "65535 deny ip from any to any" ]; then + ewarn 'Warning: kernel has firewall functionality, but' \ + ' firewall rules are not enabled.' + ewarn ' All ip services are disabled.' + fi + + # Firewall logging + # + if yesno firewall_logging; then + sysctl net.inet.ip.fw.verbose=1 >/dev/null + fi + if yesno firewall_logif; then + ifconfig ipfw0 create + fi + eend 0 +} + +start_post() +{ + local _coscript + + # Start firewall coscripts + # + for _coscript in ${firewall_coscripts} ; do + if [ -f "${_coscript}" ]; then + service ${_coscript} start >/dev/null 2>/dev/null + fi + done + + # Enable the firewall + # + if ! ${SYSCTL} net.inet.ip.fw.enable=1 1>/dev/null 2>&1; then + ewarn "failed to enable IPv4 firewall" + fi + if afexists inet6; then + if ! ${SYSCTL} net.inet6.ip6.fw.enable=1 1>/dev/null 2>&1 + then + ewarn "failed to enable IPv6 firewall" + fi + fi +} + +reverse_list() +{ + _revlist= + for _revfile; do + _revlist="$_revfile $_revlist" + done + echo $_revlist +} + +stop() +{ + local _coscript + + # Disable the firewall + # + ebegin "Stopping $name" + ${SYSCTL} net.inet.ip.fw.enable=0 + if afexists inet6; then + ${SYSCTL} net.inet6.ip6.fw.enable=0 + fi + + # Stop firewall coscripts + # + for _coscript in `reverse_list ${firewall_coscripts}` ; do + if [ -f "${_coscript}" ]; then + service ${_coscript} stop >/dev/null 2>/dev/null + fi + done + eend 0 +} Index: libexec/rc/etc.init.d/ipfw_netflow =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ipfw_netflow @@ -0,0 +1,74 @@ +#!/sbin/openrc-run +# + +depend() +{ + need ipfw + keyword -jail +} + +. /etc/rc.subr +. /etc/network.subr + +name="ipfw_netflow" +desc="firewall, ipfw, netflow" +required_modules="ipfw ng_netflow ng_ipfw" + +: ${ipfw_netflow_hook:=9995} +: ${ipfw_netflow_rule:=01000} +: ${ipfw_netflow_ip:=127.0.0.1} +: ${ipfw_netflow_port:=9995} +: ${ipfw_netflow_version:=} + +start_pre() +{ + if [ "${ipfw_netflow_version}" != "" ] && [ "${ipfw_netflow_version}" != 9 ]; then + eend 1 "Unknown netflow version \'${ipfw_netflow_version}\'" + fi + case "${ipfw_netflow_hook}" in + [!0-9]*) + eend 1 "Bad value \"${ipfw_netflow_hook}\": Hook must be numerical" + esac + case "${ipfw_netflow_rule}" in + [!0-9]*) + eend 1 "Bad value \"${ipfw_netflow_rule}\": Rule number must be numerical" + esac +} + +ipfw_netflow_is_running() +{ + ngctl show netflow: > /dev/null 2>&1 && return 0 || return 1 +} + +status() +{ + if ipfw_netflow_is_running + then + einfo "ipfw_netflow is active" + return 0 + else + ewarn "ipfw_netflow is not active" + return 1 + fi +} + +start() +{ + ipfw_netflow_is_running && err 1 "ipfw_netflow is already active" + ipfw add ${ipfw_netflow_rule} ngtee ${ipfw_netflow_hook} ip from any to any ${ipfw_netflow_fib:+fib ${ipfw_netflow_fib}} + ngctl -f - <<-EOF + mkpeer ipfw: netflow ${ipfw_netflow_hook} iface0 + name ipfw:${ipfw_netflow_hook} netflow + mkpeer netflow: ksocket export${ipfw_netflow_version} inet/dgram/udp + msg netflow: setdlt {iface=0 dlt=12} + name netflow:export${ipfw_netflow_version} netflow_export + msg netflow:export${ipfw_netflow_version} connect inet/${ipfw_netflow_ip}:${ipfw_netflow_port} +EOF +} + +stop() +{ + ipfw_netflow_is_running || err 1 "ipfw_netflow is not active" + ngctl shutdown netflow: + ipfw delete ${ipfw_netflow_rule} +} Index: libexec/rc/etc.init.d/ipropd_master =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ipropd_master @@ -0,0 +1,33 @@ +#!/sbin/openrc-run +# + +depend() +{ + need kdc + keyword -shutdown +} + +name=ipropd_master +command="/usr/libexec/ipropd-master" +required_files="$ipropd_master_keytab" + +start_pre() +{ + + if [ -z "$ipropd_master_slaves" ]; then + ewarn "\$ipropd_master_slaves is empty." + return 1 + fi + for _slave in $ipropd_master_slaves; do + echo $_slave + done > /var/heimdal/slaves || return 1 + command_args="$command_args \ + --keytab=\"$ipropd_master_keytab\" \ + --detach \ + " +} +start_post() +{ + + einfo "${name}: slave nodes: $ipropd_master_slaves" +} Index: libexec/rc/etc.init.d/ipropd_slave =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ipropd_slave @@ -0,0 +1,25 @@ +#!/sbin/openrc-run +# + +depend() +{ + need kdc + keyword -shutdown +} + +name=ipropd_slave +command="/usr/libexec/ipropd-slave" +required_files="$ipropd_slave_keytab" + +start_pre() +{ + if [ -z "$ipropd_slave_master" ]; then + warn "\$ipropd_slave_master is empty." + return 1 + fi + command_args=" \ + $command_args \ + --keytab=\"$ipropd_slave_keytab\" \ + --detach \ + $ipropd_slave_master" +} Index: libexec/rc/etc.init.d/ipsec =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ipsec @@ -0,0 +1,52 @@ +#!/sbin/openrc-run +# + +depend() +{ + before mountlate + keyword -jail +} + +name="ipsec" +desc="Internet Protocol Security protocol" +extra_commands="reload" +ipsec_program="/sbin/setkey" +# ipsec_file is set by rc.conf + +start_pre() +{ + if [ ! -f "$ipsec_file" ]; then + ewarn "$ipsec_file not readable; ipsec start aborted." + return 1 + fi + return 0 +} + +stop_pre() +{ + test -f ${ipsec_file} +} + +start() +{ + einfo "Installing ipsec manual keys/policies." + ${ipsec_program} -f $ipsec_file +} + +stop() +{ + einfo "Clearing ipsec manual keys/policies." + + # Still not 100% sure if we would like to do this. + # It is very questionable to do this during shutdown session + # since it can hang any of the remaining IPv4/v6 sessions. + # + ${ipsec_program} -F + ${ipsec_program} -FP +} + +reload() +{ + echo "Reloading ipsec manual keys/policies." + ${ipsec_program} -f "$ipsec_file" +} Index: libexec/rc/etc.init.d/iscsictl =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/iscsictl @@ -0,0 +1,12 @@ +#!/sbin/openrc-run + +name="iscsictl" +command="/usr/bin/${name}" +command_args="${iscsictl_flags}" +required_modules="iscsi" + +depend() +{ + use net + need iscsid +} Index: libexec/rc/etc.init.d/iscsid =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/iscsid @@ -0,0 +1,12 @@ +#!/sbin/openrc-run + +depend() +{ + use net +} + +name="iscsid" +desc="iSCSI initiator daemon" +pidfile="/var/run/${name}.pid" +command="/usr/sbin/${name}" +required_modules="iscsi" Index: libexec/rc/etc.init.d/jail =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/jail @@ -0,0 +1,495 @@ +#!/sbin/openrc-run +# Copyright 1992-2016 FreeBSD Project +# Released under the 2-clause BSD license + +name="jail" +description="Manage system jails" + +jail=${RC_SVCNAME##*.} +if [ -n "$jail" -a "$jail" != "jail" ]; then + jail_target="$jail" +fi +[ -n "$jail_target" ] && name="$name ($jail_target)" + +depend() +{ + after network + keyword -shutdown -stop -jail -prefix +} + +# Needed for check_kern_features +. /etc/rc.subr + +extra_commands="jail_status" +: ${jail_conf:=/etc/jail.conf} +: ${jail_program:=/usr/sbin/jail} +: ${jail_jexec:=/usr/sbin/jexec} +: ${jail_jls:=/usr/sbin/jls} + +need_dad_wait= + +# extract_var jv name param num defval +# Extract value from ${jail_$jv_$name} or ${jail_$name} and +# set it to $param. If not defined, $defval is used. +# When $num is [0-9]*, ${jail_$jv_$name$num} are looked up and +# $param is set by using +=. $num=0 is optional (params may start at 1). +# When $num is YN or NY, the value is interpreted as boolean. +# When $num is @, the value is interpreted as an array separted by IFS. +extract_var() +{ + local i _jv _name _param _num _def _name1 _name2 + _jv=$1 + _name=$2 + _param=$3 + _num=$4 + _def=$5 + + case $_num in + YN) + _name1=jail_${_jv}_${_name} + _name2=jail_${_name} + eval $_name1=\"\${$_name1:-\${$_name2:-$_def}}\" + if yesno $_name1; then + echo " $_param = 1;" + else + echo " $_param = 0;" + fi + ;; + NY) + _name1=jail_${_jv}_${_name} + _name2=jail_${_name} + eval $_name1=\"\${$_name1:-\${$_name2:-$_def}}\" + if yesno $_name1; then + echo " $_param = 0;" + else + echo " $_param = 1;" + fi + ;; + [0-9]*) + i=$_num + while : ; do + _name1=jail_${_jv}_${_name}${i} + _name2=jail_${_name}${i} + eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\" + if [ -n "$_tmpargs" ]; then + echo " $_param += \"$_tmpargs\";" + elif [ $i != 0 ]; then + break; + fi + i=$(($i + 1)) + done + ;; + @) + _name1=jail_${_jv}_${_name} + _name2=jail_${_name} + eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\" + set -- $_tmpargs + if [ $# -gt 0 ]; then + echo -n " $_param = " + while [ $# -gt 1 ]; do + echo -n "\"$1\", " + shift + done + echo "\"$1\";" + fi + ;; + *) + _name1=jail_${_jv}_${_name} + _name2=jail_${_name} + eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\" + if [ -n "$_tmpargs" ]; then + echo " $_param = \"$_tmpargs\";" + fi + ;; + esac +} + +# parse_options _j _jv +# Parse options and create a temporary configuration file if necessary. +# +parse_options() +{ + local _j _jv _p + _j=$1 + _jv=$2 + + _confwarn=0 + if [ -z "$_j" ]; then + ewarn "parse_options: you must specify a jail" + return + fi + eval _jconf=\"\${jail_${_jv}_conf:-/etc/jail.${_j}.conf}\" + eval _rootdir=\"\$jail_${_jv}_rootdir\" + eval _hostname=\"\$jail_${_jv}_hostname\" + if [ -z "$_rootdir" -o \ + -z "$_hostname" ]; then + if [ -r "$_jconf" ]; then + _conf="$_jconf" + return 0 + elif [ -r "$jail_conf" ]; then + _conf="$jail_conf" + return 0 + else + ewarn "Invalid configuration for $_j " \ + "(no jail.conf, no hostname, or no path). " \ + "Jail $_j was ignored." + fi + return 1 + fi + eval _ip=\"\$jail_${_jv}_ip\" + if [ -z "$_ip" ] && ! check_kern_features vimage; then + ewarn "no ipaddress specified and no vimage support. " \ + "Jail $_j was ignored." + return 1 + fi + _conf=/var/run/jail.${_j}.conf + # + # To relieve confusion, show a warning message. + # + : ${jail_confwarn:=YES} + yesno jail_confwarn && _confwarn=1 + if [ -r "$jail_conf" -o -r "$_jconf" ]; then + if ! yesno jail_parallel_start; then + ewarn "$_conf is created and used for jail $_j." + fi + fi + /usr/bin/install -m 0644 -o root -g wheel /dev/null $_conf || return 1 + + eval : \${jail_${_jv}_flags:=${jail_flags}} + eval _exec=\"\$jail_${_jv}_exec\" + eval _exec_start=\"\$jail_${_jv}_exec_start\" + eval _exec_stop=\"\$jail_${_jv}_exec_stop\" + if [ -n "${_exec}" ]; then + # simple/backward-compatible execution + _exec_start="${_exec}" + _exec_stop="" + else + # flexible execution + if [ -z "${_exec_start}" ]; then + _exec_start="/bin/sh /etc/rc" + if [ -z "${_exec_stop}" ]; then + _exec_stop="/bin/sh /etc/rc.shutdown" + fi + fi + fi + eval _interface=\"\${jail_${_jv}_interface:-${jail_interface}}\" + eval _parameters=\"\${jail_${_jv}_parameters:-${jail_parameters}}\" + eval _fstab=\"\${jail_${_jv}_fstab:-${jail_fstab:-/etc/fstab.$_j}}\" + ( + date +"# Generated by rc.d/jail at %Y-%m-%d %H:%M:%S" + echo "$_j {" + extract_var $_jv hostname host.hostname - "" + extract_var $_jv rootdir path - "" + if [ -n "$_ip" ]; then + extract_var $_jv interface interface - "" + jail_handle_ips_option $_ip $_interface + alias=0 + while : ; do + eval _x=\"\$jail_${_jv}_ip_multi${alias}\" + [ -z "$_x" ] && break + + jail_handle_ips_option $_x $_interface + alias=$(($alias + 1)) + done + case $need_dad_wait in + 1) + # Sleep to let DAD complete before + # starting services. + echo " exec.start += \"sleep " \ + $(($(${SYSCTL_N} net.inet6.ip6.dad_count) + 1)) \ + "\";" + ;; + esac + # These are applicable only to non-vimage jails. + extract_var $_jv fib exec.fib - "" + extract_var $_jv socket_unixiproute_only \ + allow.raw_sockets NY YES + else + echo " vnet;" + extract_var $_jv vnet_interface vnet.interface @ "" + fi + + echo " exec.clean;" + echo " exec.system_user = \"root\";" + echo " exec.jail_user = \"root\";" + extract_var $_jv exec_prestart exec.prestart 0 "" + extract_var $_jv exec_poststart exec.poststart 0 "" + extract_var $_jv exec_prestop exec.prestop 0 "" + extract_var $_jv exec_poststop exec.poststop 0 "" + + echo " exec.start += \"$_exec_start\";" + extract_var $_jv exec_afterstart exec.start 0 "" + echo " exec.stop = \"$_exec_stop\";" + + extract_var $_jv consolelog exec.consolelog - \ + /var/log/jail_${_j}_console.log + + if [ -r $_fstab ]; then + echo " mount.fstab = \"$_fstab\";" + fi + + eval : \${jail_${_jv}_devfs_enable:=${jail_devfs_enable:-NO}} + if yesno jail_${_jv}_devfs_enable; then + echo " mount.devfs;" + eval _ruleset=\${jail_${_jv}_devfs_ruleset:-${jail_devfs_ruleset}} + case $_ruleset in + "") ;; + [0-9]*) echo " devfs_ruleset = \"$_ruleset\";" ;; + devfsrules_jail) + # XXX: This is the default value, + # Let jail(8) to use the default because + # mount(8) only accepts an integer. + # This should accept a ruleset name. + ;; + *) ewarn "devfs_ruleset must be an integer." ;; + esac + fi + eval : \${jail_${_jv}_fdescfs_enable:=${jail_fdescfs_enable:-NO}} + if yesno jail_${_jv}_fdescfs_enable; then + echo " mount.fdescfs;" + fi + eval : \${jail_${_jv}_procfs_enable:=${jail_procfs_enable:-NO}} + if yesno jail_${_jv}_procfs_enable; then + echo " mount.procfs;" + fi + + eval : \${jail_${_jv}_mount_enable:=${jail_mount_enable:-NO}} + if yesno jail_${_jv}_mount_enable; then + echo " allow.mount;" + fi + + extract_var $_jv set_hostname_allow allow.set_hostname YN NO + extract_var $_jv sysvipc_allow allow.sysvipc YN NO + extract_var $_jv enforce_statfs enforce_statfs - 2 + extract_var $_jv osreldate osreldate + extract_var $_jv osrelease osrelease + for _p in $_parameters; do + echo " ${_p%\;};" + done + echo "}" + ) >> $_conf + + return 0 +} + +# jail_extract_address argument iface +# The second argument is the string from one of the _ip +# or the _multi variables. In case of a comma separated list +# only one argument must be passed in at a time. +# The function alters the _type, _iface, _addr and _mask variables. +# +jail_extract_address() +{ + local _i _interface + _i=$1 + _interface=$2 + + if [ -z "${_i}" ]; then + ewarn "jail_extract_address: called without input" + return + fi + + # Check if we have an interface prefix given and split into + # iFace and rest. + case "${_i}" in + *\|*) # ifN|.. prefix there + _iface=${_i%%|*} + _r=${_i##*|} + ;; + *) _iface="" + _r=${_i} + ;; + esac + + # In case the IP has no interface given, check if we have a global one. + _iface=${_iface:-${_interface}} + + # Set address, cut off any prefix/netmask/prefixlen. + _addr=${_r} + _addr=${_addr%%[/ ]*} + + # Theoretically we can return here if interface is not set, + # as we only care about the _mask if we call ifconfig. + # This is not done because we may want to santize IP addresses + # based on _type later, and optionally change the type as well. + + # Extract the prefix/netmask/prefixlen part by cutting off the address. + _mask=${_r} + _mask=`expr "${_mask}" : "${_addr}\(.*\)"` + + # Identify type {inet,inet6}. + case "${_addr}" in + *\.*\.*\.*) _type="inet" ;; + *:*) _type="inet6" ;; + *) ewarn "jail_extract_address: type not identified" + ;; + esac + + # Handle the special /netmask instead of /prefix or + # "netmask xxx" case for legacy IP. + # We do NOT support shortend class-full netmasks. + if [ "${_type}" = "inet" ]; then + case "${_mask}" in + /*\.*\.*\.*) _mask=" netmask ${_mask#/}" ;; + *) ;; + esac + + # In case _mask is still not set use /32. + _mask=${_mask:-/32} + + elif [ "${_type}" = "inet6" ]; then + # In case _mask is not set for IPv6, use /128. + _mask=${_mask:-/128} + fi +} + +# jail_handle_ips_option input iface +# Handle a single argument imput which can be a comma separated +# list of addresses (theoretically with an option interface and +# prefix/netmask/prefixlen). +# +jail_handle_ips_option() +{ + local _x _type _i _defif + _x=$1 + _defif=$2 + + if [ -z "${_x}" ]; then + # No IP given. This can happen for the primary address + # of each address family. + return + fi + + # Loop, in case we find a comma separated list, we need to handle + # each argument on its own. + while [ ${#_x} -gt 0 ]; do + case "${_x}" in + *,*) # Extract the first argument and strip it off the list. + _i=`expr "${_x}" : '^\([^,]*\)'` + _x=`expr "${_x}" : "^[^,]*,\(.*\)"` + ;; + *) _i=${_x} + _x="" + ;; + esac + + _type="" + _addr="" + _mask="" + _iface="" + jail_extract_address $_i $_defif + + # make sure we got an address. + case $_addr in + "") continue ;; + *) ;; + esac + + # Append address to list of addresses for the jail command. + case $_type in + inet) + echo " ip4.addr += \"${_iface:+${_iface}|}${_addr}${_mask}\";" + ;; + inet6) + echo " ip6.addr += \"${_iface:+${_iface}|}${_addr}${_mask}\";" + need_dad_wait=1 + ;; + esac + done +} + +jail_status() +{ + + $jail_jls -N +} + +start() +{ + local _j _jv _jid _id _name + + # Start the specific jail sub-service + if [ -n "$jail_target" ] ; then + start_jail_target "$jail_target" + return $? + fi + + # Start the jail sub-services + for _j in $jail_list; do + if [ -e "/etc/init.d/jail.${_j}" ] ; then + rm /etc/init.d/jail.${_j} + fi + sh /etc/rc.devd jail.${_j} start + done + +} + +start_jail_target() +{ + ebegin "Starting $name" + _j="$1" + _j=$(echo $_j | tr /. _) + _jv=$(echo -n $_j | tr -c '[:alnum:]' _) + parse_options $_j $_jv || continue + + eval rc_flags=\${jail_${_jv}_flags:-$jail_flags} + eval command=\${jail_${_jv}_program:-$jail_program} + command_args="-i -f $_conf -c $_j" + _tmp=`mktemp -t jail` || exit 3 + if $command $rc_flags $command_args \ + >> $_tmp 2>&1 /var/run/jail_${_j}.id + else + ewarn " cannot start jail " \ + "\"${_hostname:-${_j}}\": " + cat $_tmp + fi + rm -f $_tmp + eend 0 +} + +stop() +{ + local _j _jv + + # Start the specific jail sub-service + if [ -n "$jail_target" ] ; then + stop_jail_target "$jail_target" + return $? + fi + + # Stop the jails + yesno jail_reverse_stop && set -- $(reverse_list $jail_list) + for _j in $jail_list; do + if [ -e "/etc/init.d/jail.${_j}" ] ; then + rm /etc/init.d/jail.${_j} + fi + sh /etc/rc.devd jail.${_j} stop + done + return 0 +} + +stop_jail_target() +{ + ebegin "Stopping $name" + _j="$1" + _j=$(echo $_j | tr /. _) + _jv=$(echo -n $_j | tr -c '[:alnum:]' _) + parse_options $_j $_jv || continue + if ! $jail_jls -j $_j > /dev/null 2>&1; then + return 0 + fi + eval command=\${jail_${_jv}_program:-$jail_program} + echo -n " ${_hostname:-${_j}}" + _tmp=`mktemp -t jail` || exit 3 + $command -q -f $_conf -r $_j >> $_tmp 2>&1 + if $jail_jls -j $_j > /dev/null 2>&1; then + cat $_tmp + else + rm -f /var/run/jail_${_j}.id + fi + rm -f $_tmp + eend 0 +} Index: libexec/rc/etc.init.d/kadmind =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/kadmind @@ -0,0 +1,22 @@ +#!/sbin/openrc-run + +name=kadmind + +depend() { + need kdc + keyword -shutdown +} + + +start_pre() { + + command_args="$command_args &" +} + +start() { + return 0 +} + +stop() { + return 0 +} Index: libexec/rc/etc.init.d/kdc =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/kdc @@ -0,0 +1,22 @@ +#!/sbin/openrc-run + +name=kdc + +depend() { + after network + before login + keyword -shutdown +} + +start_pre() +{ + command_args="$command_args --detach" +} + +start() { + return 0 +} + +stop() { + return 0 +} Index: libexec/rc/etc.init.d/keyserv =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/keyserv @@ -0,0 +1,9 @@ +#!/sbin/openrc-run + +name="keyserv" +command="/usr/sbin/${name}" + +depend() { + need ypset rpcbind + keyword -shutdown +} Index: libexec/rc/etc.init.d/kfd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/kfd @@ -0,0 +1,19 @@ +#!/sbin/openrc-run + +name=kfd + +depend() +{ + after network + keyword -shutdown +} + +start() +{ + return 0 +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/kldxref =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/kldxref @@ -0,0 +1,34 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +depend() +{ + before network + keyword -jail +} + +name="kldxref" +desc="Generate hints for the kernel loader" + +start() { + if [ -n "$kldxref_module_path" ]; then + MODULE_PATHS="$kldxref_module_path" + else + MODULE_PATHS=`sysctl -n kern.module_path` + fi + IFS=';' + for MODULE_DIR in $MODULE_PATHS; do + if checkyesno kldxref_clobber || + [ ! -f "$MODULE_DIR/linker.hints" ] && + [ `echo ${MODULE_DIR}/*.ko` != "${MODULE_DIR}/*.ko" ]; then + echo "Building $MODULE_DIR/linker.hints" + kldxref "$MODULE_DIR" + fi + done +} + +stop() { + return 0 +} Index: libexec/rc/etc.init.d/kpasswdd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/kpasswdd @@ -0,0 +1,27 @@ +#!/sbin/openrc-run + +name=kpasswdd + +depend() +{ + provide kpasswd + need kdc + keyword -shutdown +} + + +start_pre() +{ + + command_args="$command_args &" +} + +start() +{ + return 0 +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/ldconfig =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ldconfig @@ -0,0 +1,115 @@ +#!/sbin/openrc-run +name="ldconfig" +command=/sbin/ldconfig + +depend() { + need localmount + after bootmisc + keyword -jail -prefix -stop +} + + +start() +{ + local retval=0 + case "${ldconfig_insecure}" in + [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) + _ins="-i" + ;; + [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + _ins= + ;; + *) + ewarn "Insecure mode should be yes or no" + return 1 + ;; + esac + + ebegin "Setting up ldconfig paths" + eindent + if [ -x "${command}" ]; then + _LDC="/lib /usr/lib" + for i in ${ldconfig_local_dirs}; do + if [ -d "${i}" ]; then + _files=`find ${i} -type f` + if [ -n "${_files}" ]; then + ldconfig_paths="${ldconfig_paths} `cat ${_files} | sort -u`" + fi + fi + done + for i in ${ldconfig_paths} /etc/ld-elf.so.conf; do + if [ -r "${i}" ]; then + _LDC="${_LDC} ${i}" + fi + done + ebegin "ELF ldconfig path: ${_LDC}" + ${command} -elf ${_ins} ${_LDC} + + case `sysctl -n hw.machine_arch` in + amd64) + for i in ${ldconfig_local32_dirs}; do + if [ -d "${i}" ]; then + _files=`find ${i} -type f` + if [ -n "${_files}" ]; then + ldconfig32_paths="${ldconfig32_paths} `cat ${_files} | sort -u`" + fi + fi + done + _LDC="" + for i in ${ldconfig32_paths}; do + if [ -r "${i}" ]; then + _LDC="${_LDC} ${i}" + fi + done + ebegin "32-bit compatibility ldconfig path: ${_LDC}" + ${command} -32 -m ${_ins} ${_LDC} + ;; + esac + +case `sysctl -n hw.machine_arch` in + armv6) + for i in ${ldconfig_localsoft_dirs}; do + if [ -d "${i}" ]; then + _files=`find ${i} -type f` + if [ -n "${_files}" ]; then + ldconfigsoft_paths="${ldconfigsoft_paths} `cat ${_files} | sort -u`" + fi + fi + done + _LDC="" + for i in ${ldconfigsoft_paths}; do + if [ -r "${i}" ]; then + _LDC="${_LDC} ${i}" + fi + done + check_startmsgs && + ebegin 'Soft Float compatibility ldconfig path:' ${_LDC} + ${command} -soft -m ${_ins} ${_LDC} + ;; + esac + + # Legacy aout support for i386 only + case `sysctl -n hw.machine_arch` in + i386) + # Default the a.out ldconfig path. + : ${ldconfig_paths_aout=${ldconfig_paths}} + _LDC="" + for i in /usr/lib/aout ${ldconfig_paths_aout} /etc/ld.so.conf; do + if [ -r "${i}" ]; then + _LDC="${_LDC} ${i}" + fi + done + ebegin 'a.out ldconfig path:' ${_LDC} + ${lcommand} -aout ${_ins} ${_LDC} + ;; + esac + fi + eoutdent + eend $retval "Some errors were encountered" +} + +stop() +{ + # Fake function so we always shutdown correctly. + return 0 +} Index: libexec/rc/etc.init.d/local =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/local @@ -0,0 +1,28 @@ +#!/sbin/openrc-run + +name="local" +desc="Run /etc/rc.local and /etc/shutdown.local" + +depend() +{ + after * + keyword -timeout +} + +start() +{ + if [ -f /etc/rc.local ]; then + ebegin 'Starting local daemons:' + . /etc/rc.local + eend $? + fi +} + +stop() +{ + if [ -f /etc/rc.shutdown.local ]; then + ebegin 'Shutting down local daemons:' + . /etc/rc.shutdown.local + eend $? + fi +} Index: libexec/rc/etc.init.d/local_unbound =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/local_unbound @@ -0,0 +1,99 @@ +#!/sbin/openrc-run + +command="/usr/sbin/unbound" +name="local_unbound" +description="Local caching forwarding resolver" +pidfile="/var/run/${name}.pid" + +depend() +{ + need localmount + use net logger + keyword -shutdown -stop +} + +extra_commands="anchor configtest setup" + +: ${local_unbound_workdir:=/var/unbound} +: ${local_unbound_config:=${local_unbound_workdir}/unbound.conf} +: ${local_unbound_flags:="-c ${local_unbound_config}"} +: ${local_unbound_forwardconf:=${local_unbound_workdir}/forward.conf} +: ${local_unbound_controlconf:=${local_unbound_workdir}/control.conf} +: ${local_unbound_anchor:=${local_unbound_workdir}/root.key} +: ${local_unbound_forwarders:=} + +do_as_unbound() +{ + echo "$@" | su -m unbound +} + +# +# Retrieve or update the DNSSEC root anchor +# +anchor() +{ + do_as_unbound /usr/sbin/unbound-anchor -a ${local_unbound_anchor} + # we can't trust the exit code - check if the file exists + [ -f ${local_unbound_anchor} ] +} + +# +# Check the unbound configuration file +# +configtest() +{ + do_as_unbound /usr/sbin/unbound-checkconf ${local_unbound_config} +} + +# +# Create the unbound configuration file and update resolv.conf to +# point to unbound. +# +setup() +{ + einfo "Performing initial setup." + /usr/sbin/local-unbound-setup -n \ + -u unbound \ + -w ${local_unbound_workdir} \ + -c ${local_unbound_config} \ + -f ${local_unbound_forwardconf} \ + -o ${local_unbound_controlconf} \ + -a ${local_unbound_anchor} \ + ${local_unbound_forwarders} +} + +# +# Before starting, check that the configuration file and root anchor +# exist. If not, attempt to generate them. +# +start_pre() +{ + # Create configuration file + if [ ! -f ${local_unbound_config} ] ; then + setup + fi + + # Retrieve DNSSEC root key + if [ ! -f ${local_unbound_anchor} ] ; then + anchor + fi +} + +# +# After starting, wait for Unbound to report that it is ready to avoid +# race conditions with services which require functioning DNS. +# +start_post() +{ + local retry=5 + + ebegin "Waiting for nameserver to start..." + until "${command}-control" status | grep -q "is running" ; do + if [ $((retry -= 1)) -eq 0 ] ; then + eend 1 + fi + echo -n "." + sleep 1 + done + eend 0 +} Index: libexec/rc/etc.init.d/localmount =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/localmount @@ -0,0 +1,64 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mounts disks and swap according to /etc/fstab." + +depend() +{ + need fsck + use modules mtab + after modules + keyword -jail -prefix +} + +start() +{ + # Mount local filesystems in /etc/fstab. + local critical= types="noproc" x= no_netdev= rc= + for x in $net_fs_list $extra_net_fs_list; do + types="${types},${x}" + done + + if [ "$RC_UNAME" = Linux ]; then + no_netdev="-O no_netdev" + if mountinfo -q /usr; then + touch "$RC_SVCDIR"/usr_premounted + fi + fi + ebegin "Mounting local filesystems" + mount -at "$types" $no_netdev + eend $? "Some local filesystem failed to mount" + rc=$? + if [ -z "$critical_mounts" ]; then + rc=0 + else + for x in ${critical_mounts}; do + fstabinfo -q $x || continue + if ! mountinfo -q $x; then + critical=x + eerror "Failed to mount $x" + fi + done + [ -z "$critical" ] && rc=0 + fi + return $rc +} + +stop() +{ + yesno $RC_GOINGDOWN || return 0 + # We never unmount / or /dev or $RC_SVCDIR + + # Flush all pending disk writes now + sync + + return 0 +} Index: libexec/rc/etc.init.d/lockd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/lockd @@ -0,0 +1,12 @@ +#!/sbin/openrc-run + +command=/usr/sbin/rpc.lockd +command_args=$lockd_args +name="lockd" + +depend() +{ + need localmount rpcbind statd + use net logger dns + before inetd xinetd +} Index: libexec/rc/etc.init.d/lpd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/lpd @@ -0,0 +1,29 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +name="lpd" +desc="Line printer spooler daemon" +command="/usr/sbin/${name}" +required_files="/etc/printcap" + +depend() +{ + need localmount + use logger + before inetd xinetd +} + +start_pre() +{ + if [ "$chkprintcap_enable" = "YES" ] ; then + /usr/sbin/chkprintcap ${chkprintcap_flags} + fi +} Index: libexec/rc/etc.init.d/mixer =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/mixer @@ -0,0 +1,54 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +extra_commands="restore" + +depend() +{ + need localmount + keyword -jail -prefix +} + +restore() +{ + local mixer= retval=0 + ebegin "Restoring mixer settings" + eindent + for mixer in /dev/mixer*; do + if [ -r "/var/db/${mixer#/dev/}-state" ]; then + vebegin "$mixer" + mixer -f "$mixer" \ + $(cat "/var/db/${mixer#/dev/}-state") >/dev/null + veend $? + : $(( retval += $? )) + fi + done +} + +start() +{ + restore +} + +stop() +{ + local mixer= retval=0 + ebegin "Saving mixer settings" + eindent + for mixer in /dev/mixer*; do + vebegin "$mixer" + mixer -f "$mixer" -s >/var/db/"${mixer#/dev/}"-state + veend $? + : $(( retval += $? )) + done + eoutdent + eend $retval +} Index: libexec/rc/etc.init.d/modules =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/modules @@ -0,0 +1,53 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Loads a user defined list of kernel modules." + +depend() +{ + before sysctl + keyword -jail -prefix +} + +FreeBSD_modules() +{ + local cnt=0 x + for x in $modules; do + if [ !`kldstat -q -m ${x}` ] ; then + #ebegin "Loading module $x" + load_kld "$x" + #eend $? "Failed to load $x" && : $(( cnt += 1 )) + : $(( cnt += 1 )) + fi + done + # Load dynamicly listed KLDs + for dynkld in `set | grep "^kldload_" | sed 's/kldload_.*=//g' | sed "s|'||g"`; do + if [ -n "$kld_list" ] ; then + kld_list="$kld_list $dynkld" + else + kld_list="$dynkld" + fi + done + for x in $kld_list; do + if [ !`kldstat -q -m ${x}` ] ; then + #ebegin "Loading module $x" + load_kld "$x" + #eend $? "Failed to load $x" && : $(( cnt += 1 )) + : $(( cnt += 1 )) + fi + done +} + +start() +{ + FreeBSD_modules + return 0 +} Index: libexec/rc/etc.init.d/motd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/motd @@ -0,0 +1,50 @@ +#!/sbin/openrc-run + +name="motd" +desc="Update /etc/motd" +rcvar="update_motd" +start_cmd="motd_start" +stop_cmd=":" + +depend() { + need localmount + after bootmisc + keyword -jail -prefix +} + +PERMS="644" + +start() +{ + # Update kernel info in /etc/motd + # Must be done *before* interactive logins are possible + # to prevent possible race conditions. + # + ebegin "Updating motd:" + if [ ! -f /etc/motd ]; then + install -c -o root -g wheel -m ${PERMS} /dev/null /etc/motd + fi + + if [ ! -w /etc/motd ]; then + ewarn "/etc/motd is not writable, update failed." + return + fi + + T=`mktemp -t motd` + uname -v | sed -e 's,^\([^#]*\) #\(.* [1-2][0-9][0-9][0-9]\).*/\([^\]*\) $,\1 (\3) #\2,' > ${T} + awk '{if (NR == 1) {if ($1 == "FreeBSD") {next} else {print "\n"$0}} else {print}}' < /etc/motd >> ${T} + + cmp -s $T /etc/motd || { + cp $T /etc/motd + chmod ${PERMS} /etc/motd + } + rm -f $T + eend 0 +} + +stop() +{ + # Fake function so we always shutdown correctly. + return 0 +} + Index: libexec/rc/etc.init.d/mountd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/mountd @@ -0,0 +1,47 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/mountd +command_args=$mountd_flags +name="Service remote NFS mount requests" + +depend() +{ + need localmount rpcbind + use net logger + keyword -stop +} + +start_pre() +{ + rc-update show | grep -q "nfsd" + if [ $? -eq 0 ] ; then + if yesno weak_mountd_authentication; then + command_args="${command_args} -n" + fi + else + rc-update show | grep -q "mountd" + if [ $? -eq 0 ]; then + yesno weak_mountd_authentication && command_args="${command_args} -n" + fi + fi + + if [ -e /etc/zfs/exports ]; then + command_args="${command_args} /etc/exports /etc/zfs/exports" + else + einfo "/etc/exports does not exist, creating!" + touch /etc/exports + fi + + rm -f /var/db/mountdtab + ( umask 022 ; > /var/db/mountdtab ) || + eerror 'Cannot create /var/db/mountdtab' +} Index: libexec/rc/etc.init.d/mountlate =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/mountlate @@ -0,0 +1,37 @@ +#!/sbin/openrc-run +# + +depend() +{ + keyword -jail +} + +name="mountlate" +desc="Mount filesystems with \"late\" option from /etc/fstab" + +start() +{ + local err latefs + + # Mount "late" filesystems. + # + err=0 + mount -a -L + err=$? + + case ${err} in + 0) + ;; + *) + ewarn 'Mounting /etc/fstab filesystems failed,' \ + ' startup aborted' + stop_boot true + ;; + esac + + # If we booted a special kernel remove the record + # so we will boot the default kernel next time. + if [ -x /sbin/nextboot ]; then + /sbin/nextboot -D + fi +} Index: libexec/rc/etc.init.d/moused =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/moused @@ -0,0 +1,107 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. +# +# + +depend() +{ + need localmount + after bootmisc + keyword -jail -prefix -stop -shutdown + provide mouse +} + +mouse=${RC_SVCNAME##*.} + +if [ -n "$mouse" -a "$mouse" != "moused" ]; then + moused_device=/dev/"$mouse" + pidfile=/var/run/moused-"$mouse".pid +else + pidfile=/var/run/moused.pid +fi +name="Console Mouse Daemon" +[ -n "$moused_device" ] && name="$name ($moused_device)" + + +start() +{ + # When started in 'master' mode, search for available + # mouse devices, and start them as sub-services + if [ -z "$moused_device" ]; then + export OPENRC_SILENT=TRUE + local founddev=0 + local dev= + for dev in /dev/psm[0-9]* /dev/ums[0-9]*; do + [ -c "$dev" ] || continue + [ -e /var/run/moused-"${dev##*/}".pid ] && continue + sh /etc/rc.devd moused.${dev##*/} start + done + if [ $founddev ] ; then + return 0 + else + mark_service_inactive + return 0 + fi + fi + + if [ -z "$OPENRC_SILENT" ] ; then + ebegin "Starting $name" + fi + + if [ -z "$moused_device" ]; then + mark_service_inactive + eend 1 "No mouse device found" + return 1 + fi + + local args= + eval args=\$moused_args_${moused_device##*/} + [ -z "$args" ] && args=$moused_flags + + start-stop-daemon --start --exec /usr/sbin/moused \ + --pidfile "$pidfile" \ + -- $args -p "$moused_device" -I "$pidfile" + local retval=$? + + if [ $retval = 0 ]; then + local ttyv= + for ttyv in /dev/ttyv*; do + vidcontrol < "$ttyv" -m on + : $(( retval += $? )) + done + fi + + if [ -z "$OPENRC_SILENT" ] ; then + eend $retval "Failed to start moused" + fi +} + +stop() +{ + if [ -z "$moused_device" ]; then + # Loop through and stop all sub-services + for dev in /dev/psm[0-9]* /dev/ums[0-9]*; do + [ -c "$dev" ] || continue + [ -e /var/run/moused-"${dev##*/}".pid ] || continue + sh /etc/rc.devd moused.${dev##*/} stop + done + return 0 + fi + + if [ -z "$OPENRC_SILENT" ] ; then + ebegin "Stopping $name" + fi + start-stop-daemon --stop --exec /usr/sbin/moused \ + -p $pidfile + if [ -z "$OPENRC_SILENT" ] ; then + eend $? + fi +} Index: libexec/rc/etc.init.d/natd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/natd @@ -0,0 +1,43 @@ +#!/sbin/openrc-run + +name="natd" +description="Network Address Translation daemon" +command=/sbin/natd +pidfile="/var/run/${name}.pid" +sigstop="SIGKILL" +retry="30" + +# Needed for network scripts +. /etc/network.subr + +depend() +{ + need localmount + use net + keyword -jail -shutdown +} + +start_pre() +{ + # Make sure our modules are loaded + load_kld ipdivert + + if [ -n "${natd_interface}" ]; then + dhcp_list="`list_net_interfaces dhcp`" + for ifn in ${dhcp_list}; do + case "${natd_interface}" in + ${ifn}) + command_args="$command_args -dynamic" + ;; + esac + done + + if echo "${natd_interface}" | \ + grep -q -E '^[0-9]+(\.[0-9]+){0,3}$'; then + command_args="$command_args -a ${natd_interface}" + else + command_args="$command_args -n ${natd_interface}" + fi + fi + return 0 +} Index: libexec/rc/etc.init.d/netmount =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/netmount @@ -0,0 +1,89 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mounts network shares according to /etc/fstab." + +depend() +{ + local opts mywant="" + for opts in $(fstabinfo -o -t nfs,nfs4); do + case $opts in + noauto) ;; + *) mywant="$mywant nfsclient"; break ;; + esac + done + config /etc/fstab + want $mywant + use afc-client amd openvpn + use dns + keyword -jail -prefix -shutdown +} + +start() +{ + local x= fs= rc= + for x in $net_fs_list $extra_net_fs_list; do + fs="$fs${fs:+,}$x" + done + + ebegin "Mounting network filesystems" + mount -alt $fs + rc=$? + if [ "$RC_UNAME" = Linux ] && [ $rc = 0 ]; then + mount -a -O _netdev + rc=$? + fi + ewend $rc "Could not mount all network filesystems" + if [ -z "$critical_mounts" ]; then + rc=0 + else + for x in ${critical_mounts}; do + fstabinfo -q $x || continue + if ! mountinfo -q $x; then + critical=x + eerror "Failed to mount $x" + fi + done + [ -z "$critical" ] && rc=0 + fi + return $rc +} + +stop() +{ + local x= fs= + + ebegin "Unmounting network filesystems" + . "$RC_LIBEXECDIR"/sh/rc-mount.sh + + for x in $net_fs_list $extra_net_fs_list; do + fs="$fs${fs:+,}$x" + done + if [ -n "$fs" ]; then + umount -at $fs || eerror "Failed to simply unmount filesystems" + fi + + eindent + fs= + for x in $net_fs_list $extra_net_fs_list; do + fs="$fs${fs:+|}$x" + done + [ -n "$fs" ] && fs="^($fs)$" + do_unmount umount ${fs:+--fstype-regex} $fs --netdev + retval=$? + + eoutdent + if [ "$RC_UNAME" = Linux ] && [ $retval = 0 ]; then + umount -a -O _netdev + retval=$? + fi + eend $retval "Failed to unmount network filesystems" +} Index: libexec/rc/etc.init.d/network =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/network @@ -0,0 +1,268 @@ +#!/sbin/openrc-run +# Copyright (c) 2016 - Kris Moore +# Copyright (c) 2009-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. +# +# This script was inspired by the equivalent rc.d network from NetBSD. +# +# 2016-12-11 - Kris Moore - Improved to support per-interface sub-services +# + +netif=${RC_SVCNAME##*.} +if [ -n "$netif" -a "$netif" != "network" ]; then + ifconfig $netif >/dev/null 2>/dev/null + if [ $? -ne 0 ] ; then exit 0; fi + network_device="$netif" +fi + +# Until we can determine why devd is throwing some bogus +# $cdev = '' variables +if [ "${RC_SVCNAME}" = "network." ] ; then + exit 1 +fi +name="network" +[ -n "$network_device" ] && name="$name ($network_device)" + + +description="Configures network interfaces." +__nl=" +" +IFCONFIG_CMD="/sbin/ifconfig" + +# Needed for network scripts +. /etc/rc.subr +. /etc/network.subr + +depend() +{ + provide net + need localmount + after bootmisc modules + keyword -jail -prefix -vserver -stop +} + +start() +{ + local _if + + # Set the list of interfaces to work on. + cmdifn=$network_device + + # Create IEEE802.11 interface + wlan_up $cmdifn + + # Create cloned interfaces + clone_up $cmdifn + + # Rename interfaces. + ifnet_rename $cmdifn + + # Configure the interface(s). + netif_common ifn_start $cmdifn + + #if [ -f /etc/rc.d/ipfilter ] ; then + # Resync ipfilter + # /etc/rc.d/ipfilter quietresync + #fi + if [ -n "$cmdifn" ] ; then + export BRIDGE_IFLIST="${cmdifn}" + service bridge static + fi + if [ -n "$cmdifn" ] ; then + for _if in $cmdifn; do + export ROUTE_AF="any" + export ROUTE_IF="$_if" + service routing static + done + fi +} + +stop() +{ + netif_stop0 $* +} + +stop_pre() +{ + if [ "$RC_CMD" = "restart" ]; then + _clone_down= + _wlan_down= + else + _clone_down=1 + _wlan_down=1 + fi +} + +netif_stop0() +{ + local _if + + # Set the list of interfaces to work on. + # + cmdifn=$network_device + + # Deconfigure the interface(s) + netif_common ifn_stop $cmdifn + + # Destroy wlan interfaces + if [ -n "$_wlan_down" ]; then + wlan_down $cmdifn + fi + + # Destroy cloned interfaces + if [ -n "$_clone_down" ]; then + clone_down $cmdifn + fi + + if [ -n "$cmdifn" ] ; then + for _if in $cmdifn; do + export ROUTE_AF="any" + export ROUTE_IF="$_if" + service routing staticstop + done + fi +} + +vnet_up() +{ + cmdifn=$* + + netif_common ifn_vnetup $cmdifn +} + +vnet_down() +{ + cmdifn=$* + + netif_common ifn_vnetdown $cmdifn +} + +# netif_common routine +# Common configuration subroutine for network interfaces. This +# routine takes all the preparatory steps needed for configuriing +# an interface and then calls $routine. +netif_common() +{ + local _cooked_list _tmp_list _fail _func _ok _str _cmdifn + + _func= + + if [ -z "$1" ]; then + eerror "netif_common(): No function name specified." + exit 1 + else + _func="$1" + shift + fi + + # Set the scope of the command (all interfaces or just one). + # + _cooked_list= + _tmp_list= + _cmdifn=$* + if [ -n "$_cmdifn" ]; then + # Don't check that the interface(s) exist. We need to run + # the down code even when the interface doesn't exist to + # kill off wpa_supplicant. + # XXXBED: is this really true or does wpa_supplicant die? + # if so, we should get rid of the devd entry + _cooked_list="$_cmdifn" + else + _cooked_list="`list_net_interfaces`" + fi + + # Expand epair[0-9] to epair[0-9][ab]. + for ifn in $_cooked_list; do + case ${ifn#epair} in + [0-9]*[ab]) ;; # Skip epair[0-9]*[ab]. + [0-9]*) + for _str in $_cooked_list; do + case $_str in + $ifn) _tmp_list="$_tmp_list ${ifn}a ${ifn}b" ;; + *) _tmp_list="$_tmp_list ${ifn}" ;; + esac + done + _cooked_list=${_tmp_list# } + ;; + esac + done + + _dadwait= + _fail= + _ok= + for ifn in ${_cooked_list# }; do + # Skip if ifn does not exist. + case $_func in + ifn_stop) + if ! ${IFCONFIG_CMD} $ifn > /dev/null 2>&1; then + ewarn "$ifn does not exist. Skipped." + _fail="${_fail} ${ifn}" + continue + fi + ;; + esac + if ${_func} ${ifn} $2; then + _ok="${_ok} ${ifn}" + if ipv6if ${ifn}; then + _dadwait=1 + fi + else + _fail="${_fail} ${ifn}" + fi + done + + # inet6 address configuration needs sleep for DAD. + case ${_func}:${_dadwait} in + ifn_start:1|ifn_vnetup:1|ifn_vnetdown:1) + sleep `${SYSCTL_N} net.inet6.ip6.dad_count` + sleep 1 + ;; + esac + + _str= + if [ -n "${_ok}" ]; then + case ${_func} in + ifn_start) + _str='Starting' + ;; + ifn_stop) + _str='Stopping' + ;; + ifn_vnetup) + _str='Moving' + ;; + ifn_vnetdown) + _str='Reclaiming' + ;; + esac + einfo "${_str} Network:${_ok}." + case ${_func} in + ifn_vnetup) + # Clear _ok not to do "ifconfig $ifn" + # because $ifn is no longer in the current vnet. + _ok= + ;; + esac + if check_startmsgs; then + for ifn in ${_ok}; do + /sbin/ifconfig ${ifn} >/dev/null 2>/dev/null + done + fi + fi + + if [ -n "$_fail" ] ; then + ewarn "The following interfaces were not configured: $_fail" + fi +} + +# Load the old "network" config file also for compatibility. +# This is needed for mfsBSD at least. +#load_rc_config network +#load_rc_config $name Index: libexec/rc/etc.init.d/newsyslog =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/newsyslog @@ -0,0 +1,30 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +name="newsyslog" +required_files="/etc/newsyslog.conf" +command="/usr/sbin/${name}" + + +depend() +{ + need localmount + after root zfs + keyword -prefix -shutdown -stop +} + +start() +{ + ebegin "Creating and/or trimming log files" + ${command} ${newsyslog_flags} + newsyslog -CCN + eend $? +} Index: libexec/rc/etc.init.d/nfscbd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/nfscbd @@ -0,0 +1,10 @@ +#!/sbin/openrc-run +# + +name="nfscbd" +command="/usr/sbin/${name}" + +depend() { + need nfsuserd + keyword -jail -shutdown +} Index: libexec/rc/etc.init.d/nfsclient =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/nfsclient @@ -0,0 +1,50 @@ +#!/sbin/openrc-run + +command=/usr/sbin/rpc.statd +command_args=$lockd_args +name="nfsclient" + +depend() +{ + need localmount rpcbind + use net logger dns + before inetd xinetd + keyword -stop -shutdown +} + +nfsclient_start() +{ + # + # Set some nfs client related sysctls + # + + if [ -n "${nfs_access_cache}" ]; then + if ! sysctl vfs.nfs.access_cache_timeout=${nfs_access_cache} >/dev/null; then + ewarn "failed to set access cache timeout" + fi + fi + if [ -n "${nfs_bufpackets}" ]; then + if ! sysctl vfs.nfs.bufpackets=${nfs_bufpackets} > /dev/null; then + ewarn "failed to set vfs.nfs.bufpackets" + fi + fi + + unmount_all +} + +unmount_all() +{ + # If /var/db/mounttab exists, some nfs-server has not been + # successfully notified about a previous client shutdown. + # If there is no /var/db/mounttab, we do nothing. + if [ -f /var/db/mounttab ]; then + rpc.umntall -k + fi +} + +start() +{ + ebegin "Starting ${name}" + nfsclient_start + eend $? +} Index: libexec/rc/etc.init.d/nfsd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/nfsd @@ -0,0 +1,53 @@ +#!/sbin/openrc-run + +name="NFS Daemon" +stopsig="USR1" + +depend() +{ + need localmount rpcbind mountd gssd + use net logger + keyword -stop +} + +start_pre() +{ + # Load the nfsd kernel module + kldstat | grep -q "nfsd" + if [ $? -ne 0 ] ; then + kldload nfsd 2>/dev/null + fi + + if yesno nfs_reserved_port_only; then + einfo 'NFS on reserved port only=YES' + sysctl vfs.nfsd.nfs_privport=1 > /dev/null + else + sysctl vfs.nfsd.nfs_privport=0 > /dev/null + fi + + if yesno nfsv4_server_enable || \ + yesno nfs_server_managegids; then + need nfsuserd + fi + + if yesno nfsv4_server_enable; then + sysctl vfs.nfsd.server_max_nfsvers=4 > /dev/null + else + einfo 'NFSv4 is disabled' + sysctl vfs.nfsd.server_max_nfsvers=3 > /dev/null + fi +} + +start() +{ + ebegin "Starting NFSd" + /usr/sbin/nfsd $nfs_server_flags + eend $? +} + +stop() +{ + ebegin "Stopping NFSd" + killall -9 nfsd + eend $? +} Index: libexec/rc/etc.init.d/nfsuserd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/nfsuserd @@ -0,0 +1,30 @@ +#!/sbin/openrc-run + +name="NFSv4 User Services" + +depend() +{ + need localmount rpcbind + use net logger +} + +start_pre() +{ + if yesno nfs_server_managegids; then + nfsuserd_flags="-manage-gids ${nfsuserd_flags}" + fi +} + +start() +{ + ebegin "Starting NFS user services" + /usr/sbin/nfsuserd -force $nfsuserd_flags + eend $? +} + +stop() +{ + ebegin "Stopping NFS user services" + killall -9 nfsuserd + eend $? +} Index: libexec/rc/etc.init.d/nisdomain =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/nisdomain @@ -0,0 +1,29 @@ +#!/sbin/openrc-run + +name="nisdomain" +description="Set NIS domain name" + +depend() +{ + need localmount rpcbind + use net logger + before ypset ypbind ypserv ypxfrd + keyword -shutdown -stop +} + +start() +{ + # Set the domainname if we're using NIS + # + case ${nisdomainname} in + [Nn][Oo]|'') + return 0 + ;; + *) + ebegin "Starting $name" + domainname ${nisdomainname} + einfo "Setting NIS domain: `/bin/domainname`." + eend 0 + ;; + esac +} Index: libexec/rc/etc.init.d/nscd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/nscd @@ -0,0 +1,29 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/nscd +command_args=$nscd_args +pidfile=/var/run/nscd.pid +name="Name Service Cache Daemon" + +extra_started_commands="flush" + +depend() { + need localmount + use net dns ldap ypbind + after bootmisc +} + +flush() { + ebegin "Flushing $name" + nscd -I all >/dev/null + eend $? +} Index: libexec/rc/etc.init.d/nsswitch =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/nsswitch @@ -0,0 +1,78 @@ +#!/sbin/openrc-run + +name="nsswitch" +description="Name-service switch" + +depend() +{ + need localmount + before network + keyword -shutdown -stop +} + +generate_host_conf() +{ + local _cont _sources + + nsswitch_conf=$1; shift; + host_conf=$1; shift; + + _cont=0 + _sources="" + while read line; do + line=${line##[ ]} + case $line in + hosts:*) + ;; + *) + if [ $_cont -ne 1 ]; then + continue + fi + ;; + esac + if [ "${line%\\}" = "${line}\\" ]; then + _cont=1 + fi + line=${line#hosts:} + line=${line%\\} + line=${line%%#*} + _sources="${_sources}${_sources:+ }$line" + done < $nsswitch_conf + + echo "# Auto-generated from nsswitch.conf" > $host_conf + for _s in ${_sources}; do + case $_s in + files) + echo "hosts" >> $host_conf + ;; + dns) + echo "dns" >> $host_conf + ;; + nis) + echo "nis" >> $host_conf + ;; + cache | *=*) + ;; + *) + echo "Warning: unrecognized source [$_s]" >&2 + ;; + esac + done +} + +start() +{ + # Generate host.conf for compatibility + # + if [ ! -f "/etc/host.conf" -o \ + "/etc/host.conf" -ot "/etc/nsswitch.conf" ] + then + ebegin "Starting $name" + einfo 'Generating host.conf.' + generate_host_conf /etc/nsswitch.conf /etc/host.conf + eend 0 + else + mark_service_inactive + return 0 + fi +} Index: libexec/rc/etc.init.d/ntpd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ntpd @@ -0,0 +1,153 @@ +#!/sbin/openrc-run +# +# $FreeBSD$ +# + +depend() +{ + need ntpdate devfs + keyword -jail -shutdown +} + +name="ntpd" +desc="Network Time Protocol daemon" +command="/usr/sbin/${name}" +command_args="-n" +supervisor=supervise-daemon +supervise_daemon_args="-1 /var/log/ntpd.log -2 /var/log/ntpd.err" +pidfile="/var/run/${name}-run.pid" +extra_commands="ntpd-fetch needfetch" +start_precmd="ntpd_precmd" + +ntp_tmp_leapfile="/var/run/ntpd.leap-seconds.list" + +start_pre() +{ + rc_flags="-c ${ntpd_config} ${ntpd_flags}" + + if checkyesno ntpd_sync_on_start; then + rc_flags="-g $rc_flags" + fi + + ntpd_init_leapfile + + if [ ! -f $ntp_db_leapfile ]; then + ntpd-fetch + fi + + if [ -z "$ntpd_chrootdir" ]; then + return 0; + fi + + # If running in a chroot cage, ensure that the appropriate files + # exist inside the cage, as well as helper symlinks into the cage + # from outside. + # + # As this is called after the is_running and required_dir checks + # are made in run_rc_command(), we can safely assume ${ntpd_chrootdir} + # exists and ntpd isn't running at this point (unless forcestart + # is used). + # + if [ ! -c "${ntpd_chrootdir}/dev/clockctl" ]; then + rm -f "${ntpd_chrootdir}/dev/clockctl" + ( cd /dev ; /bin/pax -rw -pe clockctl "${ntpd_chrootdir}/dev" ) + fi + ln -fs "${ntpd_chrootdir}/var/db/ntp.drift" /var/db/ntp.drift + ln -fs "${ntpd_chrootdir}${ntp_tmp_leapfile}" ${ntp_tmp_leapfile} + + # Change run_rc_commands()'s internal copy of $ntpd_flags + # + rc_flags="-u ntpd:ntpd -i ${ntpd_chrootdir} $rc_flags" +} + +current_ntp_ts() { + # Seconds between 1900-01-01 and 1970-01-01 + # echo $(((70*365+17)*86400)) + ntp_to_unix=2208988800 + + echo $(($(date -u +%s)+$ntp_to_unix)) +} + +get_ntp_leapfile_ver() { + # Leapfile update date (version number). + expr "$(awk '$1 == "#$" { print $2 }' "$1" 2>/dev/null)" : \ + '^\([1-9][0-9]*\)$' \| 0 +} + +get_ntp_leapfile_expiry() { + # Leapfile expiry date. + expr "$(awk '$1 == "#@" { print $2 }' "$1" 2>/dev/null)" : \ + '^\([1-9][0-9]*\)$' \| 0 +} + +ntpd_init_leapfile() { + # Refresh working leapfile with an invalid hash due to + # FreeBSD id header. Ntpd will ignore leapfiles with a + # mismatch hash. The file must be the virgin file from + # the source. + if [ ! -f $ntp_db_leapfile ]; then + cp -p $ntp_src_leapfile $ntp_db_leapfile + fi +} + +needfetch() { + local rc verbose + + if checkyesno ntp_leapfile_fetch_verbose; then + verbose=echo + else + verbose=: + fi + + ntp_ver_no_src=$(get_ntp_leapfile_ver $ntp_src_leapfile) + ntp_expiry_src=$(get_ntp_leapfile_expiry $ntp_src_leapfile) + ntp_ver_no_db=$(get_ntp_leapfile_ver $ntp_db_leapfile) + ntp_expiry_db=$(get_ntp_leapfile_expiry $ntp_db_leapfile) + $verbose ntp_src_leapfile version is $ntp_ver_no_src + $verbose ntp_db_leapfile version is $ntp_ver_no_db + + if [ "$ntp_ver_no_src" -gt "$ntp_ver_no_db" -o \ + "$ntp_ver_no_src" -eq "$ntp_ver_no_db" -a \ + "$ntp_expiry_src" -gt "$ntp_expiry_db" ]; then + $verbose replacing $ntp_db_leapfile with $ntp_src_leapfile + cp -p $ntp_src_leapfile $ntp_db_leapfile + ntp_ver_no_db=$ntp_ver_no_src + else + $verbose not replacing $ntp_db_leapfile with $ntp_src_leapfile + fi + ntp_leapfile_expiry_seconds=$((ntp_leapfile_expiry_days*86400)) + ntp_leap_expiry=$(get_ntp_leapfile_expiry $ntp_db_leapfile) + ntp_leap_fetch_date=$((ntp_leap_expiry-ntp_leapfile_expiry_seconds)) + if [ $(current_ntp_ts) -ge $ntp_leap_fetch_date ]; then + $verbose Within ntp leapfile expiry limit, initiating fetch + # Return code 0: ntp leapfile fetch needed + return 0 + fi + # Return code 1: ntp leapfile fetch not needed + return 1 +} + +ntpd-fetch() { + if checkyesno ntp_leapfile_fetch_verbose; then + verbose=echo + else + verbose=: + fi + + if needfetch ; then + for url in $ntp_leapfile_sources ; do + $verbose fetching $url + fetch $ntp_leapfile_fetch_opts -o $ntp_tmp_leapfile $url && break + done + ntp_ver_no_tmp=$(get_ntp_leapfile_ver $ntp_tmp_leapfile) + ntp_expiry_tmp=$(get_ntp_leapfile_expiry $ntp_tmp_leapfile) + if [ "$ntp_expiry_tmp" -gt "$ntp_expiry_db" -o \ + "$ntp_expiry_tmp" -eq "$ntp_expiry_db" -a \ + "$ntp_ver_no_tmp" -gt "$ntp_ver_no_db" ]; then + $verbose using $url as $ntp_db_leapfile + mv $ntp_tmp_leapfile $ntp_db_leapfile + else + $verbose using existing $ntp_db_leapfile + fi + fi +} Index: libexec/rc/etc.init.d/ntpdate =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ntpdate @@ -0,0 +1,32 @@ +#!/sbin/openrc-run + +name="ntpdate" +desc="Set the date and time via NTP" + +depend() +{ + use net logger + keyword -stop -jail +} + +start() +{ + if [ -z "$ntpdate_hosts" -a -f "$ntpdate_config" ]; then + ntpdate_hosts=`awk ' + /^server[ \t]*127.127/ {next} + /^(server|peer|pool)/ { + if ($2 ~/^-/) {print $3} + else {print $2}} + ' < "$ntpdate_config"` + fi + if [ -n "$ntpdate_hosts" -o -n "$rc_flags" ]; then + einfo "Setting date via ntp." + ${ntpdate_program:-ntpdate} $rc_flags $ntpdate_hosts + fi + return 0 +} + +stop() +{ + return 0 +} Index: libexec/rc/etc.init.d/pf =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/pf @@ -0,0 +1,64 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +name="Packet Filter" +: ${pf_conf:=${pf_rules:-/etc/pf.conf}} +required_files=$pf_conf + +extra_commands="checkconfig showstatus" +extra_started_commands="reload" + +depend() { + need localmount + keyword -jail -prefix -stop -shutdown +} + +start() +{ + ebegin "Starting $name" + load_kld pf 2>/dev/null + pfctl -q -F all + pfctl -q -f "$pf_conf" $pf_args + pfctl -q -e + eend $? +} + +stop() +{ + ebegin "Stopping $name" + pfctl -q -d + eend $? +} + +checkconfig() +{ + ebegin "Checking $name configuration" + pfctl -n -f "$pf_conf" + eend $? +} + +reload() +{ + ebegin "Reloading $name rules." + pfctl -q -n -f "$pf_conf" && \ + { + # Flush everything but existing state entries that way when + # rules are read in, it doesn't break established connections. + pfctl -q -Fnat -Fqueue -Frules -FSources -Finfo -FTables -Fosfp + pfctl -q -f "$pf_conf" $pf_args + } + eend $? +} + +showstatus() +{ + pfctl -s info +} Index: libexec/rc/etc.init.d/pflog =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/pflog @@ -0,0 +1,139 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +name="pflog" +description="Packet filter logging interface" +: ${pflog_dev:="pflog0"} +: ${pidfile:="/var/run/pflogd.pid"} +: ${pflog_logfile:="/var/log/pflog"} +: ${pflog_flags:=""} +export pflog_dev pflog_logfile pidfile pflog_flags + +extra_started_commands="reload resync" + +depend() +{ + need localmount network + before pf + keyword -jail +} + +execution_sequence() +{ + # Check if spawning multiple pflogd and not told what to spawn + if [ "${pflog_instances}" ] && [ -n "${pflog_instances}" ]; then + # Interate through requested instances. + for instance in ${pflog_instances}; do + # Set required variables + eval pflog_dev=\$pflog_${instance}_dev + eval pflog_logfile=\$pflog_${instance}_logfile + eval pflog_flags=\$pflog_${instance}_flags + # Check that required vars have non-zero length, warn if not. + if [ -z ${pflog_dev} ]; then + ewarn "pflog_dev not set" + continue + fi + if [ -z ${pflog_logfile} ]; then + ewarn "pflog_logfile not set" + continue + fi + + # Provide a unique pidfile name for pflogd -p flag + pidfile="/var/run/pflogd.${instance}.pid" + export pflog_dev pflog_logfile pidfile pflog_flags + if [ "${RC_CMD}" = "stop" -o "${RC_CMD}" = "restart" ]; then + if ! ifconfig ${pflog_dev} down; then + ewarn "could not bring down ${pflog_dev}." + return 1 + fi + + kill `cat ${pidfile}` + rm ${pidfile} + fi + if [ "${RC_CMD}" = "start" -o "${RC_CMD}" = "restart" ]; then + pflog_prestart + # veinfo "Invoking /sbin/pflogd ${command_flags}" + /sbin/pflogd ${command_flags} + fi + done + else + # Typical case, spawn single instance only. + if [ "${RC_CMD}" = "stop" -o "${RC_CMD}" = "restart" ]; then + if ! ifconfig ${pflog_dev} down; then + ewarn "could not bring down ${pflog_dev}." + return 1 + fi + + kill `cat ${pidfile}` + rm ${pidfile} + fi + if [ "${RC_CMD}" = "start" -o "${RC_CMD}" = "restart" ]; then + pflog_prestart + # veinfo "Invoking /sbin/pflogd ${command_flags}" + /sbin/pflogd ${command_flags} + fi + fi + if [ "${RC_CMD}" = "stop" ]; then + kldunload pflog 2>/dev/null + fi + return 0 +} + +start() +{ + ebegin "Starting ${name}" + execution_sequence + eend $? +} + +stop() +{ + ebegin "Stopping ${name}" + execution_sequence + eend $? +} + +reload() +{ + ewarn "This is a no-op" +} + +resync() +{ + reload +} + +pflog_prestart() +{ + load_kld pflog 2>/dev/null || return 1 + if ! ifconfig ${pflog_dev} > /dev/null 2>&1; then + if ! ifconfig ${pflog_dev} create; then + ewarn "could not create ${pflog_dev}." + return 1 + fi + fi + + # set pflog_dev interface to up state + if ! ifconfig ${pflog_dev} up; then + ewarn "could not bring up ${pflog_dev}." + return 1 + fi + + # -p flag requires stripping pidfile's leading /var/run and trailing .pid + pidfile_base=$(echo ${pidfile} | sed -e 's|/var/run/||' -e 's|.pid$||') + + # prepare the command line for pflogd + command_flags="-p ${pidfile_base} -f ${pflog_logfile} -i ${pflog_dev} ${pflog_flags}" + export command_flags + + # report we're ready to run pflogd + return 0 +} Index: libexec/rc/etc.init.d/powerd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/powerd @@ -0,0 +1,33 @@ +#!/sbin/openrc-run + +command=/usr/sbin/powerd +command_args=$powerd_args +pidfile=/var/run/powerd.pid +name="Power Control Daemon" + +depend() +{ + need localmount + use logger + after bootmisc + keyword -jail -prefix +} + +start_pre() +{ + if [ -n "$powerd_battery_mode" ]; then + command_args="$command_args -b $powerd_battery_mode" + fi + if [ -n "${powerd_ac_mode}" ]; then + command_args="$command_args -a $powerd_ac_mode" + fi +} + +stop_post() +{ + local level=$(sysctl -n dev.cpu.0.freq_levels | + sed -e 's:/.*::') + if [ -n "$level" ]; then + sysctl dev.cpu.0.freq="$level" >/dev/null + fi +} Index: libexec/rc/etc.init.d/ppp =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ppp @@ -0,0 +1,98 @@ +#!/sbin/openrc-run +name="ppp" +description="Point to point protocol connections" + +depend() +{ + after localmount boot + keyword -jail +} + +#Determine the system install prefix +SERVICEDIR="/etc/init.d" #Base system service + +#Get the sub-service profile +profile=${RC_SVCNAME##*.} +if [ "${profile}" == "ppp" ] ; then + profile="" #invalid profile - make sure it is cleared +fi + +if [ -n "${profile}" ] ; then + #only set these for the subservices (profiles) + #in_background="true" + #pidfile="/var/run/ppp-${profile}.pid" + command="/usr/sbin/ppp" + #determine the settings for this profile + mode=$(eval "echo \$ppp_${profile}_mode" ) + if [ -z "${mode}" ] ; then + mode="${ppp_mode:-auto}" #default mode + fi + user=$(eval "echo \$ppp_${profile}_user" ) + if [ -z "${user}" ] ; then + user="${ppp_user:-root}" #default user + fi + nat=$(eval "echo \$ppp_${profile}_nat" ) + if [ -z "${nat}" ] ; then + nat="${ppp_nat:-yes}" #default nat type + fi + #now setup the commands for this profile based on the settings + if yesno "${nat}" ; then + command_args="-${mode} -nat ${profile}" + else + command_args="-${mode} ${profile}" + fi + command_user="${user}" + #ppp is weird in that it *always* backgrounds itself automatically + # - need to keep tabs on it by the full process name because the pidfiles are all the daemon process + #procname="${command} ${command_args}" +fi + +cleanup_sessions() { + #Quick function for removing any of the subservice symlinks + for subservice in `ls ${SERVICEDIR}/ppp.* 2> /dev/null` + do + rm "${subservice}" + done + return 0 +} + +start_pre() { + if [ -z "${profile}" ] ; then + #Base service - need to create/start all the subservices + export OPENRC_SILENT=TRUE + cleanup_sessions #ensure things are cleaned up ahead of time + for _profile in ${ppp_profile} + do + if [ ! -f "${SERVICEDIR}/ppp.${_profile}" ] ; then + rm "${SERVICEDIR}/ppp.${_profile}" >/dev/null 2>/dev/null + cp "${SERVICEDIR}/ppp" "${SERVICEDIR}/ppp.${_profile}" + fi + if service_stopped ppp.${_profile} ; then + einfo "Starting ppp profile: ${_profile}" + /sbin/service ppp.${_profile} start -q + fi + done + exit 0 #ensure we stop here for the base service - no actual "start" for the meta-service + fi + einfo "Starting Profile with command: ${procname}" +} + +stop() { + if [ -z "${profile}" ] ; then + for subservice in `ls ${SERVICEDIR}/ppp.* 2> /dev/null` + do + _profile=${subservice##*.} + if service_started ppp.${_profile} ; then + einfo "Stopping ppp profile: ${_profile}" + /sbin/service ppp.${_profile} stop -q + fi + rm ${subservice} #Now remove the subservice symlink + done + else + # ppp is weird in that it *always* backgrounds itself automatically + # - need to keep tabs on it by the full process name because the pidfiles are all the daemon process + p_name="${command} ${command_args}" + /bin/pkill -f "^${command}.*[[:space:]]${profile}\$" + return 0 + fi +} Index: libexec/rc/etc.init.d/rarpd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/rarpd @@ -0,0 +1,30 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/rarpd +command_args="-f $rarpd_args" +pidfile=/var/run/rarpd.pid +name="Reverse ARP Daemon" +required_files=/etc/ethers + +if [ -z "$rarpd_interface" ]; then + command_args="$command_args -a" +else + command_args="$command_args $rarpd_interface" +fi +command_background=YES + +depend() +{ + need localmount + after bootmisc + need net +} Index: libexec/rc/etc.init.d/rc-enabled =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/rc-enabled @@ -0,0 +1,60 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() +{ + need localmount net + after * + before local + keyword -prefix +} + +start() +{ + ebegin "Starting local rc services" + local svc= enabled= retval=0 service= pkgdir= + [ -n "/usr/local" ] && pkgdir="/usr/local/etc/rc.d/*" + for svc in $(rcorder /etc/rc.d/* $pkgdir 2>/dev/null); do + [ -x "$svc" ] || continue + service=${svc##*/} + + # Skip these services + for s in cleartmp moused; do + [ "$s" = "$service" ] && continue 2 + done + + # If we have an init script for this service, continue + rc-service --exists "$service" && continue + + # Ensure that the users rc.conf will start us + eval enabled=\$${svc##*/}_enable + yesno $enabled || yesno ${svc##*/} || continue + + # Good to go! + "$svc" start && started="$started $svc" + : $(( retval += $? )) + done + service_set_value started "$started" + eend $retval "Some local rc services failed to start" + return 0 +} + +stop() +{ + ebegin "Stopping local rc services" + local svc= retval=0 + for svc in $(rcorder $(service_get_value started) 2>/dev/null | sort -r); do + "$svc" stop + : $(( retval += $? )) + done + eend $retval "Some local rc services failed to stop" + return 0 +} Index: libexec/rc/etc.init.d/resolv =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/resolv @@ -0,0 +1,58 @@ +#!/sbin/openrc-run +# +# Copyright (c) 1999 Matt Dillon +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +name="resolv" +desc="Create /etc/resolv.conf from kenv" + +depend() +{ + need network + keyword -jail +} + +# if the info is available via dhcp/kenv +# build the resolv.conf +# +start() +{ + if [ -n "`/bin/kenv dhcp.domain-name-servers 2> /dev/null`" ]; then + interface="`/bin/kenv boot.netif.name`" + ( + if [ -n "`/bin/kenv dhcp.domain-name 2> /dev/null`" ]; then + echo domain `/bin/kenv dhcp.domain-name` + fi + + set -- `/bin/kenv dhcp.domain-name-servers` + for ns in `IFS=','; echo $*`; do + echo nameserver $ns + done + ) | /sbin/resolvconf -a ${interface}:dhcp4 + fi +} + Index: libexec/rc/etc.init.d/root =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/root @@ -0,0 +1,48 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Mount the root fs read/write" + +depend() +{ + need fsck + keyword -jail -prefix +} + +start() +{ + case ",$(fstabinfo -o /)," in + *,ro,*) + ;; + *) + # Check if the rootfs isn't already writable. + if checkpath -W /; then + rm -f /fastboot /forcefsck + else + ebegin "Remounting root filesystem read/write" + case "$RC_UNAME" in + Linux) + mount -n -o remount,rw / + ;; + *) + mount -u -o rw / + ;; + esac + eend $? "Root filesystem could not be mounted read/write" + if [ $? -eq 0 ]; then + rm -f /fastboot /forcefsck + fi + fi + ;; + esac + + return 0 +} Index: libexec/rc/etc.init.d/routing =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/routing @@ -0,0 +1,420 @@ +#!/sbin/openrc-run + +name="routing" +description="Routing setup" +ROUTE_CMD="/sbin/route" + +depend() +{ + need localmount + need net + keyword -jail -shutdown -stop +} + +. /etc/rc.subr +. /etc/network.subr + +extra_commands="options static staticstop" + +start() +{ + routing_start doall +} + +stop() +{ + routing_stop +} + +static() +{ + routing_start static +} + +staticstop() +{ + routing_stop +} + +options() +{ + routing_start options +} + +routing_start() +{ + local _cmd _af _if _a _ret + _cmd=$1 + _af=$ROUTE_AF + _if=$ROUTE_IF + _ret=0 + + ebegin "Starting $name" + + case $_if in + ""|[Aa][Ll][Ll]|[Aa][Nn][Yy]) _if="" ;; + esac + + case $_af in + ""|[Aa][Ll][Ll]|[Aa][Nn][Yy]) + for _a in inet inet6; do + afexists $_a || continue + setroutes $_cmd $_a $_if || _ret=1 + done + ;; + *) + if afexists $_af; then + setroutes $_cmd $_af $_if || _ret=1 + else + eerror "Unsupported address family: $_af." + fi + ;; + esac + + eend 0 +} + +routing_stop() +{ + local _af _if _a + _af=$ROUTE_AF + _if=$ROUTE_IF + + case $_if in + ""|[Aa][Ll][Ll]|[Aa][Nn][Yy]) _if="" ;; + esac + + case $_af in + ""|[Aa][Ll][Ll]|[Aa][Nn][Yy]) + for _a in inet inet6; do + afexists $_a || continue + eval static_${_a} delete $_if + # When $_if is specified, do not flush routes. + if ! [ -n "$_if" ]; then + eval routing_stop_${_a} + fi + done + ;; + *) + if afexists $_af; then + eval static_${_af} delete $_if + # When $_if is specified, do not flush routes. + if ! [ -n "$_if" ]; then + eval routing_stop_${_af} + fi + else + eerror "Unsupported address family: $_af." + fi + ;; + esac +} + +setroutes() +{ + local _ret + _ret=0 + case $1 in + static) + static_$2 add $3 >/dev/null 2>/dev/null + _ret=$? + ;; + options) + options_$2 + ;; + doall) + static_$2 add $3 >/dev/null + _ret=$? + options_$2 + ;; + esac + return $_ret +} + +routing_stop_inet() +{ + ${ROUTE_CMD} -n flush -inet >/dev/null 2>/dev/null +} + +routing_stop_inet6() +{ + local i + + ${ROUTE_CMD} -n flush -inet6 + for i in `list_net_interfaces`; do + if ipv6if $i; then + ifconfig $i inet6 -defaultif >/dev/null 2>/dev/null + fi + done +} + +routing_stop_atm() +{ + return 0 +} + +get_fibmod() +{ + local _fibs + + _fibs=$((`${SYSCTL_N} net.fibs` - 1)) + if [ ${_fibs} -gt 0 ]; then + echo "-fib 0-${_fibs}" + else + echo + fi +} + +static_inet() +{ + local _action _if _skip _fibmod + _action=$1 + _if=$2 + + _fibmod=`get_fibmod` + + # Provide loopback route in all routing tables. This has to come + # first so that any following routes can be added. + static_routes="_loopback ${static_routes}" + route__loopback="-inet 127.0.0.1 -iface lo0 ${_fibmod}" + + # Add default route. + case ${defaultrouter} in + [Nn][Oo] | '') + ;; + *) + static_routes="${static_routes} _default" + route__default="default ${defaultrouter}" + ;; + esac + + # Install configured routes. + if [ -n "${static_routes}" ]; then + for i in ${static_routes}; do + _skip=0 + if [ -n "$_if" ]; then + case $i in + *:$_if) ;; + *) _skip=1 ;; + esac + fi + if [ $_skip = 0 ]; then + route_args=`get_if_var ${i%:*} route_IF` + if [ -n "$route_args" ]; then + ${ROUTE_CMD} ${_action} ${route_args} + else + ewarn "route_${i%:*} not found." + fi + fi + done + fi +} + +static_inet6() +{ + local _action _if _skip fibmod allfibs + _action=$1 + _if=$2 + + fibmod=`get_fibmod` + + # Add pre-defined static routes first. + ipv6_static_routes="_v4mapped _v4compat ${ipv6_static_routes}" + ipv6_static_routes="_lla _llma ${ipv6_static_routes}" + ipv6_static_routes="_loopback ${ipv6_static_routes}" + + # disallow "internal" addresses to appear on the wire + ipv6_route__v4mapped="::ffff:0.0.0.0 -prefixlen 96 ::1 -reject ${fibmod}" + ipv6_route__v4compat="::0.0.0.0 -prefixlen 96 ::1 -reject ${fibmod}" + + # Create a loopback route in every fib + ipv6_route__loopback="::1 -prefixlen 128 -iface lo0 ${fibmod}" + + # Disallow link-local unicast packets without outgoing scope + # identifiers. However, if you set "ipv6_default_interface", + # for the host case, you will allow to omit the identifiers. + # Under this configuration, the packets will go to the default + # interface. + ipv6_route__lla="fe80:: -prefixlen 10 ::1 -reject ${fibmod}" + ipv6_route__llma="ff02:: -prefixlen 16 ::1 -reject ${fibmod}" + + # Add default route. + case ${ipv6_defaultrouter} in + [Nn][Oo] | '') + ;; + *) + ipv6_static_routes="${ipv6_static_routes} _default" + ipv6_route__default="default ${ipv6_defaultrouter}" + ;; + esac + + # Install configured routes. + if [ -n "${ipv6_static_routes}" ]; then + for i in ${ipv6_static_routes}; do + _skip=0 + if [ -n "$_if" ]; then + case $i in + *:$_if) ;; + *) _skip=1 ;; + esac + fi + if [ $_skip = 0 ]; then + ipv6_route_args=`get_if_var ${i%:*} ipv6_route_IF` + if [ -n "$ipv6_route_args" ]; then + ${ROUTE_CMD} ${_action} \ + -inet6 ${ipv6_route_args} + else + ewarn "route_${i%:*} not found" + fi + fi + done + fi + + # Install the "default interface" to kernel, which will be used + # as the default route when there's no router. + + # Disable installing the default interface when we act + # as router to avoid conflict between the default + # router list and the manual configured default route. + if checkyesno ipv6_gateway_enable; then + return + fi + + case "${ipv6_default_interface}" in + [Nn][Oo] | [Nn][Oo][Nn][Ee]) + return + ;; + [Aa][Uu][Tt][Oo] | "") + for i in ${ipv6_network_interfaces}; do + case $i in + [Nn][Oo][Nn][Ee]) + return + ;; + lo0) + continue + ;; + esac + laddr=`network6_getladdr $i exclude_tentative` + case ${laddr} in + '') + ;; + *) + ipv6_default_interface=$i + break + ;; + esac + done + ;; + esac + + ifconfig ${ipv6_default_interface} inet6 defaultif + sysctl net.inet6.ip6.use_defaultzone=1 +} + +static_atm() +{ + local _action i route_args + _action=$1 + + if [ -n "${natm_static_routes}" ]; then + for i in ${natm_static_routes}; do + route_args=`get_if_var $i route_IF` + if [ -n "$route_args" ]; then + atmconfig natm ${_action} ${route_args} + else + ewarn "route_${i} not found." + fi + done + fi +} + +ropts_init() +{ + if [ -z "${_ropts_initdone}" ]; then + echo -n "Additional $1 routing options:" + _ropts_initdone=yes + fi +} + +options_inet() +{ + _ropts_initdone= + if checkyesno icmp_bmcastecho; then + ropts_init inet + echo -n ' broadcast ping responses=YES' + ${SYSCTL} net.inet.icmp.bmcastecho=1 > /dev/null + else + ${SYSCTL} net.inet.icmp.bmcastecho=0 > /dev/null + fi + + if checkyesno icmp_drop_redirect; then + ropts_init inet + echo -n ' ignore ICMP redirect=YES' + ${SYSCTL} net.inet.icmp.drop_redirect=1 > /dev/null + else + ${SYSCTL} net.inet.icmp.drop_redirect=0 > /dev/null + fi + + if checkyesno icmp_log_redirect; then + ropts_init inet + echo -n ' log ICMP redirect=YES' + ${SYSCTL} net.inet.icmp.log_redirect=1 > /dev/null + else + ${SYSCTL} net.inet.icmp.log_redirect=0 > /dev/null + fi + + if checkyesno gateway_enable; then + ropts_init inet + echo -n ' gateway=YES' + ${SYSCTL} net.inet.ip.forwarding=1 > /dev/null + else + ${SYSCTL} net.inet.ip.forwarding=0 > /dev/null + fi + + if checkyesno forward_sourceroute; then + ropts_init inet + echo -n ' do source routing=YES' + ${SYSCTL} net.inet.ip.sourceroute=1 > /dev/null + else + ${SYSCTL} net.inet.ip.sourceroute=0 > /dev/null + fi + + if checkyesno accept_sourceroute; then + ropts_init inet + echo -n ' accept source routing=YES' + ${SYSCTL} net.inet.ip.accept_sourceroute=1 > /dev/null + else + ${SYSCTL} net.inet.ip.accept_sourceroute=0 > /dev/null + fi + + if checkyesno arpproxy_all; then + ropts_init inet + echo -n ' ARP proxyall=YES' + ${SYSCTL} net.link.ether.inet.proxyall=1 > /dev/null + else + ${SYSCTL} net.link.ether.inet.proxyall=0 > /dev/null + fi + + [ -n "${_ropts_initdone}" ] && echo '.' +} + +options_inet6() +{ + _ropts_initdone= + + if checkyesno ipv6_gateway_enable; then + ropts_init inet6 + echo -n ' gateway=YES' + ${SYSCTL} net.inet6.ip6.forwarding=1 > /dev/null + else + ${SYSCTL} net.inet6.ip6.forwarding=0 > /dev/null + fi + + [ -n "${_ropts_initdone}" ] && echo '.' +} + +options_atm() +{ + _ropts_initdone= + + [ -n "${_ropts_initdone}" ] && echo '.' +} Index: libexec/rc/etc.init.d/rpcbind =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/rpcbind @@ -0,0 +1,28 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/rpcbind +command_args=$rpcbind_args +name="RPC program number mapper" + +depend() +{ + provide rpc + need localmount + use net logger dns + before inetd xinetd +} + +stop_post() +{ + # rpcbind returns too fast, so sleep for a second + sleep 1 +} Index: libexec/rc/etc.init.d/runsvdir =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/runsvdir @@ -0,0 +1,20 @@ +#!/sbin/openrc-run +# Copyright (c) 2016 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/bin/runsvdir +command_background=yes +pidfile=/var/run/runsvdir.pid +command_args="-P $RC_SVCDIR/sv 'log: ...........................................................................................................................................................................................................................................................................................................................................................................................................'" + +start_pre() +{ + checkpath -m 0755 -o root:root -d ${RC_SVCDIR}/sv +} Index: libexec/rc/etc.init.d/rwho =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/rwho @@ -0,0 +1,10 @@ +#!/sbin/openrc-run + +name="rwhod" +rcvar="rwhod_enable" +command="/usr/sbin/${name}" + +depend() { + before login + keyword -shutdown +} Index: libexec/rc/etc.init.d/s6-svscan =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/s6-svscan @@ -0,0 +1,38 @@ +#!/sbin/openrc-run +# Copyright (c) 2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/bin/s6-svscan +command_args="${RC_SVCDIR}"/s6-scan +command_background=yes +pidfile=/var/run/s6-svscan.pid + +depend() +{ + need localmount +} + +start_pre() +{ + einfo "Creating s6 scan directory" + checkpath -d -m 0755 "$RC_SVCDIR"/s6-scan + return $? +} + +stop_post() +{ + ebegin "Stopping any remaining s6 services" + s6-svc -dx "${RC_SVCDIR}"/s6-scan/* 2>/dev/null || true + eend $? + + ebegin "Stopping any remaining s6 service loggers" + s6-svc -dx "${RC_SVCDIR}"/s6-scan/*/log 2>/dev/null || true + eend $? +} Index: libexec/rc/etc.init.d/savecache =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/savecache @@ -0,0 +1,66 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Saves the caches OpenRC uses to non volatile storage" + +start() +{ + if [ -e "$RC_SVCDIR"/clock-skewed ]; then + ewarn "Clock skew detected!" + if ! yesno "${RC_GOINGDOWN}"; then + eerror "Not saving deptree cache" + return 1 + fi + fi + if [ ! -d "$RC_LIBEXECDIR"/cache ]; then + if ! checkpath -W "$RC_LIBEXECDIR"; then + eerror "${RC_LIBEXECDIR} is not writable!" + eerror "Unable to save dependency cache" + if yesno "${RC_GOINGDOWN}"; then + return 0 + fi + return 1 + fi + rm -rf "$RC_LIBEXECDIR"/cache + if ! mkdir -p "$RC_LIBEXECDIR"/cache; then + eerror "Unable to create $RC_LIBEXECDIR/cache" + eerror "Unable to save dependency cache" + if yesno "${RC_GOINGDOWN}"; then + return 0 + fi + return 1 + fi + fi + if ! checkpath -W "$RC_LIBEXECDIR"/cache; then + eerror "${RC_LIBEXECDIR}/cache is not writable!" + eerror "Unable to save dependency cache" + if yesno "${RC_GOINGDOWN}"; then + return 0 + fi + return 1 + fi + ebegin "Saving dependency cache" + local rc=0 save= + for x in depconfig deptree shutdowntime softlevel rc.log; do + [ -e "$RC_SVCDIR/$x" ] && save="$save $RC_SVCDIR/$x" + done + if [ -n "$save" ]; then + cp -p $save "$RC_LIBEXECDIR"/cache + rc=$? + fi + if yesno "${RC_GOINGDOWN}"; then + if [ $rc -ne 0 ]; then + eerror "Unable to save dependency cache" + fi + eend 0 + fi + eend $rc "Unable to save dependency cache" +} Index: libexec/rc/etc.init.d/savecore =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/savecore @@ -0,0 +1,44 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +description="Saves a kernel dump." + +depend() +{ + need dumpon localmount + before encswap + keyword -jail -prefix +} + +start() +{ + : ${dump_dir:=/var/crash} + if ! [ -d "$dump_dir" ]; then + mkdir -p "$dump_dir" + chmod 700 "$dump_dir" + fi + + if [ "$RC_UNAME" = FreeBSD ]; then + # Don't quote ${dump_device}, so that if it's unset, + # savecore will check on the partitions listed in fstab + # without errors in the output + savecore -C $dump_device >/dev/null + else + ls "$dump_dir"/bsd* > /dev/null 2>&1 + fi + [ $? = 0 ] || return 0 + + local sopts="$dump_dir $dump_device" + yesno $dump_compress && sopts="-z $sopts" + ebegin "Saving kernel core dump in $dump_dir" + savecore $sopts >/dev/null + eend $? +} Index: libexec/rc/etc.init.d/sdpd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/sdpd @@ -0,0 +1,39 @@ +#!/sbin/openrc-run +################################### +# OpenRC service file for the "sdpd" daemon +# Written by Ken Moore 4/10/2018 +# Available under the 2-clause BSD license +################################### +#General Info/Settings +name="sdpd" +description="Bluetooth Service Discovery Protocol daemon " +command="/usr/sbin/sdpd" +required_modules="ng_btsocket" +pidfile="/var/run/${name}.pid" +command_background="true" +output_log="/var/log/${name}.log" +error_log="/var/log/${name}.log" + +depend(){ + before bluetooth + keyword -jail -shutdown +} + +#Respect config knobs +control="${sdpd_control:-/var/run/sdp}" +group="${sdpd_groupname:-nobody}" +user="${sdpd_username:-nobody}" +command_args="-d -c ${control} -g ${group} -u ${user}" + +#Make sure any kernel modules are loaded first +start_pre(){ + for i in ${required_modules} + do + kldload -n "${i}" >/dev/null 2>/dev/null + if [ $? -ne 0 ] ; then + eerror "Could not load required kernel module: ${i}" + return 1 + fi + done + return 0 +} Index: libexec/rc/etc.init.d/sendmail =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/sendmail @@ -0,0 +1,233 @@ +#!/sbin/openrc-run +# OpenRC version of FreeBSD rc.sendmail +# Copyright (c) 2016 +# 2 Clause BSD license +# +# Copyright (c) 2002 Gregory Neil Shapiro. All Rights Reserved. +# Copyright (c) 2000, 2002 The FreeBSD Project +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +# This script is used by /etc/rc at boot time to start sendmail. It +# is meant to be sendmail specific and not a generic script for all +# MTAs. It is only called by /etc/rc if the rc.conf mta_start_script is +# set to /etc/rc.sendmail. This provides the opportunity for other MTAs +# to provide their own startup script. + +# The script is also used by /etc/mail/Makefile to enable the +# start/stop/restart targets. + +# The source for the script can be found in src/etc/sendmail/rc.sendmail. + +description="Sendmail startup script" +name="sendmail" + +# The sendmail binary +sendmail_program=${sendmail_program:-/usr/sbin/sendmail} +extra_commands="start-mta stop-mta restart-mta start-mspq stop-mspq restart-mspq" + +# The pid is used to stop and restart the running daemon(s). +sendmail_pidfile=${sendmail_pidfile:-/var/run/sendmail.pid} +sendmail_mspq_pidfile=${sendmail_mspq_pidfile:-/var/spool/clientmqueue/sm-client.pid} +depend() +{ + need net +} +start_mta() +{ + case ${sendmail_enable} in + [Nn][Oo][Nn][Ee]) + ;; + [Yy][Ee][Ss]) + ebegin "Starting ${SVCNAME}" + start-stop-daemon --start --pidfile ${sendmail_pidfile} \ + --exec ${sendmail_program} -- ${sendmail_flags} + eend $? + ;; + *) + case ${sendmail_submit_enable} in + [Yy][Ee][Ss]) + ebegin "Starting sendmail-submit" + start-stop-daemon --start --pidfile ${sendmail_pidfile} \ + --exec ${sendmail_program} -- ${sendmail_submit_flags} + eend $? + ;; + *) + case ${sendmail_outbound_enable} in + [Yy][Ee][Ss]) + ebegin "Starting sendmail-outbound" + start-stop-daemon --start --pidfile ${sendmail_pidfile} \ + --exec ${sendmail_program} -- ${sendmail_outbound_flags} + eend $? + ;; + esac + ;; + esac + ;; + esac +} + +stop_mta() +{ + # Check to make sure we are configured to start an MTA + case ${sendmail_enable} in + [Nn][Oo][Nn][Ee]) + return + ;; + [Yy][Ee][Ss]) + ;; + *) + case ${sendmail_submit_enable} in + [Yy][Ee][Ss]) + ;; + *) + case ${sendmail_outbound_enable} in + [Yy][Ee][Ss]) + ;; + *) + return + ;; + esac + ;; + esac + ;; + esac + + ebegin "Stopping ${SVCNAME}" + start-stop-daemon --stop --pidfile ${sendmail_pidfile} + eend $? +} + +restart_mta() +{ + # Check to make sure we are configured to start an MTA + case ${sendmail_enable} in + [Nn][Oo][Nn][Ee]) + return + ;; + [Yy][Ee][Ss]) + ;; + *) + case ${sendmail_submit_enable} in + [Yy][Ee][Ss]) + ;; + *) + case ${sendmail_outbound_enable} in + [Yy][Ee][Ss]) + ;; + *) + return + ;; + esac + ;; + esac + ;; + esac + ebegin "Restart-mta" + start-stop-daemon --signal HUP --pidfile ${sendmail_pidfile} + eend $? +} + +start_mspq() +{ + case ${sendmail_enable} in + [Nn][Oo][Nn][Ee]) + ;; + *) + if [ -r /etc/mail/submit.cf ]; then + case ${sendmail_msp_queue_enable} in + [Yy][Ee][Ss]) + ebegin "Starting sendmail-clientmqueue" + start-stop-daemon --start --pidfile ${sendmail_mspq_pidfile} \ + --exec ${sendmail_program} -- ${sendmail_msp_queue_flags} + ;; + esac + fi + ;; + esac +} + +stop_mspq() +{ + # Check to make sure we are configured to start an MSP queue runner + case ${sendmail_enable} in + [Nn][Oo][Nn][Ee]) + return + ;; + *) + if [ -r /etc/mail/submit.cf ]; then + case ${sendmail_msp_queue_enable} in + [Yy][Ee][Ss]) + ;; + *) + return + ;; + esac + fi + ;; + esac + + ebegin "Stopping sendmail-clientmqueue" + start-stop-daemon --stop --pidfile ${sendmail_mspq_pidfile} + eend $? +} + +restart_mspq() +{ + # Check to make sure we are configured to start an MSP queue runner + case ${sendmail_enable} in + [Nn][Oo][Nn][Ee]) + return + ;; + *) + if [ -r /etc/mail/submit.cf ]; then + case ${sendmail_msp_queue_enable} in + [Yy][Ee][Ss]) + ;; + *) + return + ;; + esac + fi + ;; + esac + + ebegin "restarting sendmail-clientmqueue" + start-stop-daemon --signal HUP --pidfile ${sendmail_mspq_pidfile} + eend $? +} + +start() +{ + start_mta + start_mspq +} + +stop() +{ + stop_mta + stop_mspq +} Index: libexec/rc/etc.init.d/sshd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/sshd @@ -0,0 +1,75 @@ +#!/sbin/openrc-run + +name="sshd" +command=/usr/sbin/sshd +command_args=$sshd_args +pidfile=/var/run/sshd.pid +required_files=/etc/ssh/sshd_config +extra_commands="keygen configtest" + +: ${sshd_rsa1_enable:="no"} +: ${sshd_rsa_enable:="yes"} +: ${sshd_dsa_enable:="no"} +: ${sshd_ecdsa_enable:="yes"} +: ${sshd_ed25519_enable:="yes"} + + +depend() +{ + use logger dns net +} + +sshd_keygen_alg() +{ + local alg=$1 + local ALG="$(echo $alg | tr a-z A-Z)" + local keyfile + + if ! yesno "sshd_${alg}_enable" ; then + return 0 + fi + + case $alg in + rsa1) + keyfile="/etc/ssh/ssh_host_key" + ;; + rsa|dsa|ecdsa|ed25519) + keyfile="/etc/ssh/ssh_host_${alg}_key" + ;; + *) + return 1 + ;; + esac + + if [ ! -x /usr/bin/ssh-keygen ] ; then + ewarn "/usr/bin/ssh-keygen does not exist." + return 1 + fi + + if [ ! -f "${keyfile}" ] ; then + einfo "Generating $ALG host key." + /usr/bin/ssh-keygen -q -t $alg -f "$keyfile" -N "" + /usr/bin/ssh-keygen -l -f "$keyfile.pub" + fi +} + +keygen() +{ + sshd_keygen_alg rsa1 + sshd_keygen_alg rsa + sshd_keygen_alg dsa + sshd_keygen_alg ecdsa + sshd_keygen_alg ed25519 +} + +configtest() +{ + einfo "Performing sanity check on ${name} configuration." + eval ${command} ${command_args} -t +} + +start_pre() +{ + keygen + configtest +} Index: libexec/rc/etc.init.d/statd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/statd @@ -0,0 +1,20 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/rpc.statd +command_args=$lockd_args +name="statd" + +depend() +{ + need localmount rpcbind + use net logger dns +} Index: libexec/rc/etc.init.d/staticroute =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/staticroute @@ -0,0 +1,111 @@ +#!/sbin/openrc-run +# Copyright (c) 2009-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# This script was inspired by the equivalent rc.d staticroute from NetBSD. + +description="Configures static routes." +__nl=" +" + +depend() +{ + provide net + use network + keyword -jail -prefix +} + +pre_flight_checks() +{ + route=route + [ -s /etc/route.conf ] && return 0 + + if [ -n "$staticiproute" ]; then + route="ip route" + staticroute="$staticiproute" + fi +} + +dump_args() +{ + # Route configuration file, as used by the NetBSD RC system + if [ -s /etc/route.conf ]; then + cat /etc/route.conf + return $? + fi + + case "$staticroute" in + *"$__nl"*) + echo "$staticroute" + ;; + *) + ( + set -o noglob + IFS=';'; set -- $staticroute + IFS="$__nl"; echo "$*" + ) + ;; + esac +} + +do_routes() +{ + local xtra= family= + [ "$RC_UNAME" != Linux ] && xtra=-q + + ebegin "$1 static routes" + eindent + pre_flight_checks + dump_args | while read args; do + [ -z "$args" ] && continue + case "$args" in + "#"*) + ;; + "+"*) + [ $2 = "add" ] && eval ${args#*+} + ;; + "-"*) + [ $2 = "del" -o $2 = "delete" ] && eval ${args#*-} + ;; + *) + veinfo "$args" + case "$route" in + "ip route") + ip route $2 $args + ;; + *) + # Linux route does cannot work it out ... + if [ "$RC_UNAME" = Linux ]; then + case "$args" in + *:*) family="-A inet6";; + *) family=;; + esac + fi + route $family $xtra $2 -$args + ;; + esac + veend $? + esac + done + eoutdent + eend 0 +} + +start() +{ + do_routes "Adding" "add" +} + +stop() +{ + local cmd="delete" + [ "$RC_UNAME" = Linux ] && cmd="del" + do_routes "Deleting" "$cmd" +} Index: libexec/rc/etc.init.d/swap =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/swap @@ -0,0 +1,36 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() +{ + before localmount + keyword -jail -prefix +} + +start() +{ + ebegin "Activating swap devices" + case "$RC_UNAME" in + NetBSD|OpenBSD) swapctl -A -t noblk >/dev/null;; + *) swapon -a >/dev/null;; + esac + eend 0 # If swapon has nothing todo it errors, so always return 0 +} + +stop() +{ + ebegin "Deactivating swap devices" + case "$RC_UNAME" in + NetBSD|OpenBSD) swapctl -U -t noblk >/dev/null;; + *) swapoff -a >/dev/null;; + esac + eend 0 +} Index: libexec/rc/etc.init.d/syscons =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/syscons @@ -0,0 +1,90 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +depend() { + need localmount + keyword -jail -prefix +} + +start() { + if [ -n "$allscreen_flags" ]; then + ebegin "Setting mode to $allscreen_flags for all screens" + for v in /dev/ttyv*; do + vidcontrol $allscreen_flags <$v + done + eend $? + fi + + if [ -n "$keymap" -a "$keymap" != "NO" ]; then + ebegin "Setting keymap to $keymap" + kbdcontrol -l $keymap \`$2'" + kbdcontrol -f "$1" "$2" /dev/null || retval=1 + done < "$conf" + veend $retval + fi + done + eoutdent + return $retval +} + +start() +{ + local rc=0 + + ebegin "Configuring kernel parameters" + case "$RC_UNAME" in + *BSD|GNU) BSD_sysctl; rc=$? ;; + esac + eend $rc "Unable to configure some kernel parameters" +} Index: libexec/rc/etc.init.d/syslogd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/syslogd @@ -0,0 +1,24 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +command=/usr/sbin/syslogd +command_args="$syslogd_args ${syslogd_flags}" +pidfile=/var/run/syslog.pid +name="System Logger Daemon" + +depend() +{ + provide logger + use net newsyslog + need localmount + after bootmisc root zfs + keyword -prefix +} Index: libexec/rc/etc.init.d/timed =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/timed @@ -0,0 +1,10 @@ +#!/sbin/openrc-run + +name="timed" +desc="Time server daemon" +command="/usr/sbin/${name}" + +depend() { + before login + keyword -jail -shutdown +} Index: libexec/rc/etc.init.d/tmp =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/tmp @@ -0,0 +1,84 @@ +#!/sbin/openrc-run +# +# Copyright (c) 1999 Matt Dillon +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +. /etc/rc.subr + +name="tmp" +desc="Configure tmpfs" + +load_rc_config $name + +depend() +{ + need localmount + before logger + after clock root sysctl + keyword -prefix -timeout +} + +start() +{ + return 0 +} + +mount_tmpmfs() +{ + if ! /bin/df /tmp | grep -q "^/dev/md[0-9].* /tmp"; then + mount_md ${tmpsize} /tmp "${tmpmfs_flags}" + chmod 01777 /tmp + fi +} + +start_pre() +{ +# If we do not have a writable /tmp, create a memory +# filesystem for /tmp. If /tmp is a symlink (e.g. to /var/tmp, +# then it should already be writable). +# +case "${tmpmfs}" in +[Aa][Uu][Tt][Oo]) + if _tmpdir=$(mktemp -d -q /tmp/.diskless.XXXXXX); then + rmdir ${_tmpdir} + else + if [ -h /tmp ]; then + ewarn "*** /tmp is a symlink to a non-writable area!" + ewarn "dropping into shell, ^D to continue anyway." + /bin/sh + else + mount_tmpmfs + fi + fi + ;; +*) + if checkyesno tmpmfs; then + mount_tmpmfs + fi + ;; +esac +} Index: libexec/rc/etc.init.d/tmpfiles.setup =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/tmpfiles.setup @@ -0,0 +1,19 @@ +#!/sbin/openrc-run +# Copyright 1999-2012 Gentoo Foundation +# Released under the 2-clause BSD license. + +description="Set up tmpfiles.d entries" + +depend() +{ + need localmount +} + +start() +{ + ebegin "Setting up tmpfiles.d entries" + /libexec/rc/sh/tmpfiles.sh --exclude-prefix=/dev --create --remove --boot \ + ${tmpfiles_opts} + eend $? + return 0 +} Index: libexec/rc/etc.init.d/ubthidhci =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ubthidhci @@ -0,0 +1,23 @@ +#!/sbin/openrc-run + +name="ubthidhci" +command="/usr/sbin/usbconfig" +command_args="-u ${ubthidhci_busnum} -a ${ubthidhci_addr} do_request 0x40 0 0 0 0 > /dev/null 2>&1" + +depend() { + before bluetooth + keyword -jail -shutdown +} + +start_pre() +{ + + if [ -z ${ubthidhci_busnum} ]; then + warn ubthidhci_busnum is not set + return 1 + fi + if [ -z ${ubthidhci_addr} ]; then + warn ubthidhci_addr is not set + return 1 + fi +} Index: libexec/rc/etc.init.d/urandom =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/urandom @@ -0,0 +1,53 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +: ${urandom_seed:=${URANDOM_SEED:-/var/db/entropy-file}} +description="Initializes the random number generator." + +depend() +{ + need localmount + after root + keyword -jail -prefix +} + +save_seed() +{ + local psz=1 + + if [ -e /proc/sys/kernel/random/poolsize ]; then + : $(( psz = $(cat /proc/sys/kernel/random/poolsize) / 4096 )) + fi + + ( # sub shell to prevent umask pollution + umask 077 + dd if=/dev/urandom of="$urandom_seed" count=${psz} 2>/dev/null + ) +} + +start() +{ + [ -c /dev/urandom ] || return + if [ -f "$urandom_seed" ]; then + ebegin "Initializing random number generator" + cat "$urandom_seed" > /dev/urandom + eend $? "Error initializing random number generator" + fi + rm -f "$urandom_seed" && save_seed + return 0 +} + +stop() +{ + ebegin "Saving random seed" + save_seed + eend $? "Failed to save random seed" +} Index: libexec/rc/etc.init.d/var =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/var @@ -0,0 +1,117 @@ +#!/sbin/openrc-run +# +# Copyright (c) 1999 Matt Dillon +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +# NFS /var is not supported, unless NFS /var is part of diskless NFS / + +. /etc/rc.subr + +name="var" +desc="Populate /var directory" + +depend() +{ + need localmount + before logger + after clock root sysctl + keyword -prefix -timeout +} + +populate_var() +{ + /usr/sbin/mtree -deiU -f /etc/mtree/BSD.var.dist -p /var > /dev/null + case ${sendmail_enable} in + [Nn][Oo][Nn][Ee]) + ;; + *) + /usr/sbin/mtree -deiU -f /etc/mtree/BSD.sendmail.dist -p / > /dev/null + ;; + esac +} + +start() +{ +# If we do not have a writable /var, create a memory filesystem for /var +# unless told otherwise by rc.conf. We don't have /usr yet so use mkdir +# instead of touch to test. We want mount to record its mounts so we +# have to make sure /var/db exists before doing the mount -a. +# +case "${varmfs}" in +[Yy][Ee][Ss]) + mount_md ${varsize} /var "${varmfs_flags}" + ;; +[Nn][Oo]) + ;; +*) + if /bin/mkdir -p /var/.diskless 2> /dev/null; then + rmdir /var/.diskless + else + mount_md ${varsize} /var "${varmfs_flags}" + fi +esac + + +# If we have an empty looking /var, populate it, but only if we have +# /usr available. Hopefully, we'll eventually find a workaround, but +# in realistic diskless setups, we're probably ok. +case "${populate_var}" in +[Yy][Ee][Ss]) + populate_var + ;; +[Nn][Oo]) + exit 0 + ;; +*) + if [ -d /var/run -a -d /var/db -a -d /var/empty ] ; then + true + elif [ -x /usr/sbin/mtree ] ; then + populate_var + else + # We need mtree to populate /var so try mounting /usr. + # If this does not work, we can not boot so it is OK to + # try to mount out of order. + mount /usr + if [ ! -x /usr/sbin/mtree ] ; then + exit 1 + else + populate_var + fi + fi + ;; +esac + +# Make sure we have /var/log/utx.lastlogin and /var/log/utx.log files +if [ ! -f /var/log/utx.lastlogin ]; then + cp /dev/null /var/log/utx.lastlogin + chmod 644 /var/log/utx.lastlogin +fi +if [ ! -f /var/log/utx.log ]; then + cp /dev/null /var/log/utx.log + chmod 644 /var/log/utx.log +fi +} Index: libexec/rc/etc.init.d/watchdogd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/watchdogd @@ -0,0 +1,10 @@ +#!/sbin/openrc-run + +name="watchdogd" +command="/usr/sbin/${name}" +pidfile="/var/run/${name}.pid" + +depend() { + after syslogd + keyword -jail -shutdown +} Index: libexec/rc/etc.init.d/wpa_supplicant =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/wpa_supplicant @@ -0,0 +1,111 @@ +#!/sbin/openrc-run +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +BIN=/usr/sbin/wpa_supplicant +: ${wpa_supplicant_conf:=/etc/wpa_supplicant.conf} + +wpa=${RC_SVCNAME##*.} +if [ -n "$wpa" -a "$wpa" != "wpa_supplicant" ]; then + wpa_device="$wpa" + pidfile="/var/run/wpa_supplicant-${wpa_device}.pid" +fi + +wpa_args="$wpa_supplicant_args -B -c$wpa_supplicant_conf" +name="wpa_supplicant" +[ -n "$wpa_device" ] && name="$name ($wpa_device)" + +. /etc/network.subr + +depend() +{ + keyword -shutdown -stop -jail +} + +find_wireless() +{ + local _devs + for i in `ifconfig -l 2>/dev/null` + do + echo $i | grep -q "^wlan" + if [ $? -ne 0 ] ; then continue; fi + if wpaif $i; then + _devs="$_devs $i" + fi + done + + echo "$_devs" +} + +start_wpa_service() +{ + device="$1" + if [ ! -e "/etc/wpa_supplicant.conf" ] ; then + echo "ctrl_interface=/var/run/wpa_supplicant" > /etc/wpa_supplicant.conf + chmod 600 /etc/wpa_supplicant.conf + fi + + wpa_args="$wpa_args -i${device} -P ${pidfile}" + + start-stop-daemon --start --exec $BIN -p ${pidfile} -- ${wpa_args} +} + +start() +{ + if [ -n "$wpa_device" ] ; then + if [ -z "$OPENRC_SILENT" ] ; then + ebegin "Starting $name" + fi + start_wpa_service "$wpa_device" + stat=$? + if [ -z "$OPENRC_SILENT" ] ; then + eend $stat + fi + return $stat + fi + + # Start any sub-devices + for i in $(find_wireless) + do + export OPENRC_SILENT=TRUE + sh /etc/rc.devd wpa_supplicant.$i start + done + return 0 +} + +stop_wpa_service() +{ + # Stop DHCPCD for the wireless device + service dhcpcd.${1} stop >/dev/null 2>/dev/null + start-stop-daemon --stop --exec $BIN -p ${pidfile} -- ${wpa_args} +} + +stop() +{ + if [ -n "$wpa_device" ] ; then + if [ -z "$OPENRC_SILENT" ] ; then + ebegin "Stopping $name" + fi + stop_wpa_service "$wpa_device" + stat=$? + if [ -z "$OPENRC_SILENT" ] ; then + eend $stat + fi + return $stat + fi + + # Stopping any sub-devices + for i in $(find_wireless) + do + export OPENRC_SILENT=TRUE + sh /etc/rc.devd wpa_supplicant.$i stop + done + return 0 +} Index: libexec/rc/etc.init.d/ypbind =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ypbind @@ -0,0 +1,42 @@ +#!/sbin/openrc-run + +name="ypbind" +description="NIS domain binding daemon" + +command="/usr/sbin/$name" +command_args="${nis_client_flags}" + +depend() +{ + after modules + need localmount net rpcbind + keyword -shutdown -stop +} + +start_pre() +{ + +# wait for network to be available +# Previously this check has been provided by the net-online service, which has +# been removed in TrueOS-18.03. +# To avoid breakage of NIS in the future, we perform this check directly here + + local infinite + + timeout=${timeout:-60} + ebegin "ypbind waiting for network to become available" + [ "$timeout" -eq 0 ] && infinite=true || infinite=false + while $infinite || [ "$timeout" -gt 0 ]; do + nc -uz 0.0.0.255 111 && break + sleep 1 + : $((timeout -= 1)) + done + + local _domain + + _domain=`domainname` + if [ -z "$_domain" ]; then + ewarn "NIS domainname(1) is not set." + return 1 + fi +} Index: libexec/rc/etc.init.d/ypldap =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ypldap @@ -0,0 +1,14 @@ +#!/sbin/openrc-run + +name="ypldap" +description="NIS LDAP binding daemon" + +command="/usr/sbin/${name}" +command_args="${nis_ypldap_flags}" + +depend() +{ + need localmount + want ypserv + keyword -shutdown -stop +} Index: libexec/rc/etc.init.d/yppasswdd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/yppasswdd @@ -0,0 +1,25 @@ +#!/sbin/openrc-run + +name="yppasswdd" +description="Server for updating NIS passwords" + +command="/usr/sbin/rpc.${name}" +command_args="${nis_yppasswdd_flags}" + +depend() +{ + need localmount rpcbind + want ypserv ypset + keyword -shutdown -stop +} + +start_pre() +{ + local _domain + + _domain=`domainname` + if [ -z "$_domain" ]; then + ewarn "NIS domainname(1) is not set." + return 1 + fi +} Index: libexec/rc/etc.init.d/ypserv =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ypserv @@ -0,0 +1,28 @@ +#!/sbin/openrc-run + +name="ypserv" +description="NIS database server" + +command="/usr/sbin/${name}" +command_args="${nis_server_flags}" + +depend() +{ + need localmount rpcbind + keyword -shutdown -stop +} + +start_pre() +{ + local _domain + + _domain=`domainname` + if [ -z "$_domain" ]; then + ewarn "NIS domainname(1) is not set." + return 1 + fi + if [ ! -d /var/yp/$_domain/. ]; then + ewarn "/var/yp/$_domain is not a directory." + return 1 + fi +} Index: libexec/rc/etc.init.d/ypset =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ypset @@ -0,0 +1,33 @@ +#!/sbin/openrc-run + +name="ypset" +description="tell ypbind(8) which YP server process to use" + +command="/usr/sbin/${name}" +command_args="${nis_ypset_flags}" + +depend() +{ + need localmount ypbind rpcbind + keyword -shutdown -stop + after ypbind +} + +start_pre() +{ + local _domain + + _domain=`domainname` + if [ -z "$_domain" ]; then + ewarn "NIS domainname(1) is not set." + return 1 + fi +} +# without a dedicated (even if empty!) start() block, ypset is reported as crashed. +# This is most likely a bug in OpenRC, so this ugly workaround should be removed ASAP +start() +{ + ebegin "starting ypset" + ${command} ${command_args} + return 0 +} Index: libexec/rc/etc.init.d/ypupdated =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ypupdated @@ -0,0 +1,22 @@ +#!/sbin/openrc-run + +name="ypupdated" + +command="/usr/sbin/rpc.${name}" + +depend() +{ + need localmount ypserv rpcbind + keyword -shutdown -stop +} + +start_pre() +{ + local _domain + + _domain=`domainname` + if [ -z "$_domain" ]; then + ewarn "NIS domainname(1) is not set." + return 1 + fi +} Index: libexec/rc/etc.init.d/ypxfrd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/ypxfrd @@ -0,0 +1,24 @@ +#!/sbin/openrc-run + +name="ypxfrd" +description="NIS map transfer server" + +command="/usr/sbin/rpc.${name}" +command_args="${nis_ypxfrd_flags}" + +depend() +{ + need localmount rpcbind ypserv + keyword -shutdown -stop +} + +start_pre() +{ + local _domain + + _domain=`domainname` + if [ -z "$_domain" ]; then + ewarn "NIS domainname(1) is not set." + return 1 + fi +} Index: libexec/rc/etc.init.d/zfs =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/zfs @@ -0,0 +1,97 @@ +#!/sbin/openrc-run +# Copyright 1999-2011 Gentoo Foundation +# Released under the 2-clause BSD license. +# $Header: /var/cvsroot/gentoo-x86/sys-fs/zfs/files/zfs,v 0.9 2011/04/30 10:13:43 devsk Exp $ + +depend() +{ + before bootmisc logger network + keyword -jail -prefix -stop +} + +ZFS="/sbin/zfs" +ZPOOL="/sbin/zpool" +ZPOOL_CACHE="/boot/zfs/zpool.cache" +ZFS_MODULE=zfs + +checksystem() { + if [ ! -c /dev/zfs ]; then + if [ ! -x /boot/kernel/zfs.ko ]; then + eerror "$ZFS_MODULE not found. Is the kernel built with ZFS support" + return 1 + fi + fi + if [ ! -x $ZPOOL ]; then + eerror "$ZPOOL binary not found." + return 1 + fi + if [ ! -x $ZFS ]; then + eerror "$ZFS binary not found." + return 1 + fi + return 0 +} + +start() { + ebegin "Starting ZFS" + checksystem || return 1 + + if [ ! -c /dev/zfs ]; then + load_kld $ZFS_MODULE + rv=$? + if [ $rv -ne 0 ]; then + eerror "Failed to load the $ZFS_MODULE module, check 'dmesg|tail'." + eend $rv + return $rv + fi + fi + + # Import all pools described by the cache file, and then mount + # all filesystem based on their properties. + if [ -f $ZPOOL_CACHE ]; then + # as per fedora script, import can fail if all pools are already imported + # The check for $rv makes no sense...but someday, it will work right. + $ZPOOL import -c $ZPOOL_CACHE -aN 2>/dev/null || true + rv=$? + if [ $rv -ne 0 ]; then + eerror "Failed to import not-yet imported pools." + eend $rv + return $rv + fi + fi + + $ZFS mount -a + rv=$? + if [ $rv -ne 0 ]; then + eerror "Failed to mount ZFS filesystems." + eend $rv + return $rv + fi + + $ZFS share -a + rv=$? + if [ $rv -ne 0 ]; then + eerror "Failed to export ZFS filesystems." + eend $rv + return $rv + fi + + eend 0 + return 0 +} + +stop() +{ + ebegin "Unsharing ZFS filesystems" + timeout -s SIGKILL -k 6 5 $ZFS unshare -a + + # Don't fail if we couldn't umount everything. /usr might be in use. + eend 0 + return 0 +} + +status() +{ + # show pool status and list + $ZPOOL status && echo && $ZPOOL list +} Index: libexec/rc/etc.init.d/zfsd =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/zfsd @@ -0,0 +1,9 @@ +#!/sbin/openrc-run + +name="zfsd" +command="/usr/sbin/${name}" + +depend() { + after devd zfs + keyword -shutdown +} Index: libexec/rc/etc.init.d/zvol =================================================================== --- /dev/null +++ libexec/rc/etc.init.d/zvol @@ -0,0 +1,40 @@ +#!/sbin/openrc-run +# Copyright 1999-2011 Gentoo Foundation +# Released under the 2-clause BSD license. +# $Header: /var/cvsroot/gentoo-x86/sys-fs/zfs/files/zfs,v 0.9 2011/04/30 10:13:43 devsk Exp $ + +depend() +{ + after zfs + keyword -jail -prefix +} + +ZFS="/sbin/zfs" + +start() { + ebegin "Starting ZFS swap" + # Enable swap on ZVOLs with property org.freebsd:swap=on. + ${ZFS} list -H -o org.freebsd:swap,name -t volume | \ + while read state name; do + case "${state}" in + [oO][nN]) + swapon /dev/zvol/${name} + ;; + esac + done + eend 0 +} + +stop() +{ + ebegin "Stopping ZFS swap" + ${ZFS} list -H -o org.freebsd:swap,name -t volume | \ + while read state name; do + case "${state}" in + [oO][nN]) + swapoff /dev/zvol/${name} + ;; + esac + done + eend 0 +} Index: libexec/rc/init.d/Makefile =================================================================== --- /dev/null +++ libexec/rc/init.d/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +PACKAGE= runtime +BINDIR=/libexec/rc/init.d + +.include + Index: libexec/rc/network.subr =================================================================== --- libexec/rc/network.subr +++ libexec/rc/network.subr @@ -27,6 +27,14 @@ IFCONFIG_CMD="/sbin/ifconfig" : ${netif_ipexpand_max:=2048} +# Set which rc system we are using +if [ -z "$RC_SYSTEM" ] ; then + RC_SYSTEM="$(/bin/kenv rc_system 2>/dev/null)" + if [ -z "$RC_SYSTEM" ] ; then + RC_SYSTEM="rc" + fi +fi + # # Subroutines commonly used from network startup scripts. # Requires that rc.conf be loaded first. @@ -122,7 +130,7 @@ # ifconfig_up() { - local _cfg _ifconfig_descr _ipv6_opts ifconfig_args + local _cfg _ifconfig_descr _ipv6_opts ifconfig_args _cfg=1 # Make sure lo0 always comes up. @@ -220,7 +228,11 @@ fi if wpaif $1; then - /etc/rc.d/wpa_supplicant start $1 + if [ "$RC_SYSTEM" = "openrc" ] ; then + sh /etc/rc.devd wpa_supplicant.${1} start + else + /etc/rc.d/wpa_supplicant start $1 + fi _cfg=0 # XXX: not sure this should count elif hostapif $1; then /etc/rc.d/hostapd start $1 @@ -234,7 +246,11 @@ ${IFCONFIG_CMD} $1 up fi if syncdhcpif $1; then - /etc/rc.d/dhclient start $1 + if [ "$RC_SYSTEM" = "openrc" ] ; then + sh /etc/rc.devd dhcpcd.${1} start + else + /etc/rc.d/dhclient start $1 + fi fi _cfg=0 fi @@ -252,7 +268,11 @@ _cfg=1 if wpaif $1; then - /etc/rc.d/wpa_supplicant stop $1 + if [ "$RC_SYSTEM" = "openrc" ] ; then + sh /etc/rc.devd wpa_supplicant.${1} stop + else + /etc/rc.d/wpa_supplicant stop $1 + fi _cfg=0 elif hostapif $1; then /etc/rc.d/hostapd stop $1 @@ -260,7 +280,11 @@ fi if dhcpif $1; then - /etc/rc.d/dhclient stop $1 + if [ "$RC_SYSTEM" = "openrc" ] ; then + sh /etc/rc.devd dhcpcd.${1} stop + else + /etc/rc.d/dhclient stop $1 + fi _cfg=0 fi @@ -330,6 +354,9 @@ for _arg in $_tmpargs; do case $_arg:$_vnet in [Dd][Hh][Cc][Pp]:0) ;; + [Aa][Ll][Ll]:0) ;; + [Ii][Pp][Vv][4]:0) ;; + [Ii][Pp][Vv][6]:0) ;; [Nn][Oo][Aa][Uu][Tt][Oo]:0) ;; [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]:0) ;; [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]:0) ;; @@ -389,6 +416,15 @@ [Dd][Hh][Cc][Pp]) return 0 ;; + [Aa][Ll][Ll]) + return 0 + ;; + [Ii][Pp][Vv][4]) + return 0 + ;; + [Ii][Pp][Vv][6]) + return 0 + ;; [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]) return 0 ;; @@ -421,6 +457,15 @@ [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]) return 0 ;; + [Aa][Ll][Ll]) + return 0 + ;; + [Ii][Pp][Vv][4]) + return 0 + ;; + [Ii][Pp][Vv][6]) + return 0 + ;; esac done @@ -1282,9 +1327,8 @@ done done if [ -n "${_list# }" ]; then - echo "Created wlan(4) interfaces: ${_list# }." + debug "Created wlan(4)s: ${_list# }" fi - debug "Created wlan(4)s: ${_list# }" } # wlan_down @@ -1755,4 +1799,33 @@ return done +} + + +# ltr str src dst [var] +# Change every $src in $str to $dst. +# Useful when /usr is not yet mounted and we cannot use tr(1), sed(1) nor +# awk(1). If var is non-NULL, set it to the result. +ltr() +{ + local _str _src _dst _out _com _var + _str="$1" + _src="$2" + _dst="$3" + _var="$4" + _out="" + + local IFS="${_src}" + for _com in ${_str}; do + if [ -z "${_out}" ]; then + _out="${_com}" + else + _out="${_out}${_dst}${_com}" + fi + done + if [ -n "${_var}" ]; then + setvar "${_var}" "${_out}" + else + echo "${_out}" + fi } Index: libexec/rc/openrc =================================================================== --- /dev/null +++ libexec/rc/openrc @@ -0,0 +1,35 @@ +#!/bin/sh +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# If $TERM is not set then assume default of cons25 +# This gives us a nice colour boot :) +[ -z "$TERM" -o "$TERM" = "dumb" ] && TERM="cons25" && export TERM + +# Handle interrupts +trap : SIGINT +trap "echo 'Boot interrupted'; exit 1" SIGQUIT + +dlv=`/sbin/sysctl -n vfs.nfs.diskless_valid 2> /dev/null` +if [ ${dlv:=0} -ne 0 -o -f /etc/diskless ]; then + sh /etc/rc.initdiskless +fi + +# Start OpenRC Now +/sbin/openrc sysinit || exit 1 +/sbin/openrc boot || exit 1 +/sbin/openrc default || exit 1 + +# Sleep a tick first, which prevents from odd services from crashing +sleep 1 + +# We don't actually care if rc default worked or not, we should exit 0 +# to allow logins +exit 0 Index: libexec/rc/openrc.shutdown =================================================================== --- /dev/null +++ libexec/rc/openrc.shutdown @@ -0,0 +1,25 @@ +#!/bin/sh +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Handle interrupts +trap : SIGINT SIGQUIT + +# Try and use stuff in /lib over anywhere else so we can shutdown +# local mounts correctly. +LD_LIBRARY_PATH="/lib${LD_LIBRARY_PATH:+:}${LDLIBRARY_PATH}" ; export LD_LIBRARY_PATH + +# If $TERM is not set then assume default of cons25 +# This gives us a nice colour boot :) +[ -z "$TERM" -o "$TERM" = "dumb" ] && TERM="cons25" && export TERM + +action=${1:-shutdown} +exec /sbin/openrc "${action}" +exit 0 Index: libexec/rc/rc =================================================================== --- libexec/rc/rc +++ libexec/rc/rc @@ -28,6 +28,17 @@ # $FreeBSD$ # +# Do we want to do a dynamic diskless setup? +if [ -f /etc/dynamicdiskless ]; then + sh /etc/rc.dynamicdiskless +fi + +# Are we using OpenRC instead of RC? +if [ "$(/bin/kenv rc_system 2>/dev/null)" = "openrc" ]; then + sh /etc/openrc + exit $? +fi + # System startup script run by init on autoboot # or after single-user. # Output and error are redirected to console by init, Index: libexec/rc/rc.bsdextended =================================================================== --- /dev/null +++ libexec/rc/rc.bsdextended @@ -0,0 +1,138 @@ +#!/bin/sh +# +# Copyright (c) 2004 Tom Rhodes +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#### +# Sample startup policy for the mac_bsdextended(4) security module. +# +# Suck in the system configuration variables. +#### +if [ -z "${source_rc_confs_defined}" ]; then + if [ -r /etc/defaults/rc.conf ]; then + . /etc/defaults/rc.conf + source_rc_confs + elif [ -r /etc/rc.conf ]; then + . /etc/rc.conf + fi +fi + +#### +# Set ugidfw(8) to CMD: +#### +CMD=/usr/sbin/ugidfw + +#### +# WARNING: recommended reading is the handbook's MAC +# chapter and the ugidfw(8) manual page. You can +# lock yourself out of the system very quickly by setting +# incorrect values here. These are only examples. +#### + +#### +# Build a generic list of rules here, these should be +# modified before using this script. +# +# For apache to read user files, the ruleadd must give +# it permissions by default. +#### +#${CMD} add subject uid 80 object not uid 80 mode rxws; +#${CMD} add subject gid 80 object not gid 80 mode rxws; + +#### +# majordomo compat: +#${CMD} add subject uid 54 object not uid 54 mode rxws; +#${CMD} add subject gid 26 object gid 54 mode rxws; + +#### +# This is for root: +${CMD} add subject uid 0 object not uid 0 mode arxws; +${CMD} add subject gid 0 object not gid 0 mode arxws; + +#### +# And for majordomo: +#${CMD} add subject uid 54 object not uid 54 mode rxws; +#${CMD} add subject gid 54 object not gid 54 mode rxws; + +#### +# And for bin: +${CMD} add subject uid 3 object not uid 3 mode rxws; +${CMD} add subject gid 7 object not gid 7 mode rxws; + +#### +# And for mail/pop: +#${CMD} add subject uid 68 object not uid 68 mode rxws; +#${CMD} add subject gid 6 object not gid 6 mode arxws; + +#### +# And for smmsp: +${CMD} add subject uid 25 object not uid 25 mode rxws; +${CMD} add subject gid 25 object not gid 25 mode rxws; + +#### +# And for mailnull: +${CMD} add subject uid 26 object not uid 26 mode rxws; +${CMD} add subject gid 26 object not gid 26 mode rxws; + +#### +# For cyrus: +#${CMD} add subject uid 60 object not uid 60 mode rxws; +#${CMD} add subject gid 60 object not gid 60 mode rxws; + +#### +# For stunnel: +#${CMD} add subject uid 1018 object not uid 1018 mode rxws; +#${CMD} add subject gid 1018 object not gid 1018 mode rxws; + +#### +# For the nobody account: +${CMD} add subject uid 65534 object not uid 65534 mode rxws; +${CMD} add subject gid 65534 object not gid 65534 mode rxws; + +#### +# NOTICE: The next script adds a rule to allow +# access their mailbox which is owned by GID `6'. +# Removing this will give mailbox lock issues. +for x in `awk -F: '($3 >= 1001) && ($3 != 65534) { print $1 }' /etc/passwd`; + do ${CMD} add subject uid $x object gid 6 mode arwxs; +done; + +#### +# Use some script to get a list of users and +# add all users to mode n for all other users. This +# will isolate all users from other user home directories while +# permitting them to use commands and browse the system. +for x in `awk -F: '($3 >= 1001) && ($3 != 65534) { print $1 }' /etc/passwd`; + do ${CMD} add subject not uid $x object uid $x mode n; +done; + +### +# Do the same thing but only for group ids in place of +# user IDs. +for x in `awk -F: '($3 >= 1001) && ($3 != 65534) { print $3 }' /etc/passwd`; + do ${CMD} add subject not gid $x object uid $x mode n; +done; Index: libexec/rc/rc.devd =================================================================== --- /dev/null +++ libexec/rc/rc.devd @@ -0,0 +1,60 @@ +#!/bin/sh +# Copyright (c) 2007-2015 The OpenRC Authors. +# See the Authors file at the top-level directory of this distribution and +# https://github.com/OpenRC/openrc/blob/master/AUTHORS +# +# This file is part of OpenRC. It is subject to the license terms in +# the LICENSE file found in the top-level directory of this +# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE +# This file may not be copied, modified, propagated, or distributed +# except according to the terms contained in the LICENSE file. + +# Inform RC that we are in the background and hotplugged +IN_BACKGROUND=yes +IN_HOTPLUG=yes +export IN_BACKGROUND IN_HOTPLUG + +# If we have additional args coming from devd, capture them here +devd_args="${3-0}" +export devd_args + +getmedia() { + ifconfig "$1" | while read line; do + case "${line}" in + media:" "*) echo "${line}"; return;; + esac + done +} + +# Try and create an init script for network interfaces +base=${1%%.*} +if [ "${base}" = "network" ]; then + # We only create links for pyhsical interfaces + [ -n "$(getmedia ${1#*.})" ] || exit 1 + base="network.lo0" +fi +if [ -e /etc/init.d/"${base}" -a "${base}" != "$1" ]; then + if [ ! -e "/etc/init.d/${1}" ] ; then + ln -f /etc/init.d/"${base}" /etc/init.d/"$1" + fi + # Symlinks Broken in OpenRC 0.35 + if [ -h "/etc/init.d/${1}" ] ; then + rm /etc/init.d/"$1" + ln /etc/init.d/"${base}" /etc/init.d/"$1" + fi + rundir=/etc/init.d +fi +if [ -e "/usr/local/etc/init.d/${base}" -a "${base}" != "$1" ]; then + if [ ! -e "/usr/local/etc/init.d/${1}" ] ; then + ln -f /usr/local/etc/init.d/"${base}" /usr/local/etc/init.d/"$1" + fi + # Symlinks Broken in OpenRC 0.35 + if [ -h "/usr/local/etc/init.d/${1}" ] ; then + rm /usr/local/etc/init.d/"$1" + ln /usr/local/etc/init.d/"${base}" /usr/local/etc/init.d/"$1" + fi + rundir=/usr/local/etc/init.d +fi + +# Run the init script +exec "$rundir/$1" "$2" Index: libexec/rc/rc.dynamicdiskless =================================================================== --- /dev/null +++ libexec/rc/rc.dynamicdiskless @@ -0,0 +1,126 @@ +#!/bin/sh +# +# Copyright (c) 2018 Kris Moore +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +# This script is similar in concept to rc.initdiskless (Read that file!) +# +# It specifically probes the directories /conf/base/SUBDIR looking +# for directories the user wishes to copy into tmpfs backed file-systems +# and re-mounted on top of the base. +# +# Some key differences: +# +# /conf/base/SUBDIR directories do not have # to be pre-populated. Just +# having a blank directory there indicates the # desire to convert that +# directory to a tmpfs backed FS. Contents from the original location +# will be copied over on boot, and then moved back into the tmpfs location +# of the existing directory. +# +# /conf/base/DIR__DIR__SUBDIR is allowed. An example would be wanting to +# use /conf/base/usr__local__etc which would make /usr/local/etc +# a tmpfs backed FS. + +DEFAULT_TMPFS_SIZE=$(($(/sbin/sysctl -n hw.physmem) / 1536)) + +copy_subdir() +{ + CDIR=$(basename $1) + TDIR=$(basename $1 | sed 's|__|/|g') + if [ ! -d "/$TDIR" ] ; then + echo "ERROR: /conf/base/$CDIR was specified but /$TDIR does not exist" + return 1 + fi + + # Check if we have a md_size specificed for this FS + unset MDSIZE + if [ -e "/conf/base/$CDIR/md_size" ] ; then + MDSIZE=$(cat /conf/base/$CDIR/md_size) + fi + + create_md /conf/base/$CDIR $CDIR $MDSIZE + if [ $? -ne 0 ] ; then + echo "ERROR: Failed mounting tmpfs on /conf/base/$CDIR" + return 1 + fi + + cp -a /${TDIR}/ /conf/base/${CDIR}/ + if [ $? -ne 0 ] ; then + echo "ERROR: Failed copying $TDIR -> /conf/base/$CDIR" + return 1 + fi + + create_md /$TDIR ${CDIR}_real $MDSIZE + if [ $? -ne 0 ] ; then + echo "ERROR: Failed mounting tmpfs on /$TDIR" + return 1 + fi + + cp -a /conf/base/${CDIR}/ /${TDIR}/ + if [ $? -ne 0 ] ; then + echo "ERROR: Failed copying /conf/base/$CDIR -> /$TDIR" + return 1 + fi +} + +# Create a generic memory disk. +# The 'auto' parameter will attempt to use tmpfs(5), falls back to md(4). +# $1 is size in 512-byte sectors, $2 is the mount point. +mount_md() { + /sbin/mdmfs -s $1 auto $2 +} + +# Create the memory filesystem if it has not already been created +# +create_md() { + [ "x`eval echo \\$md_created_$2`" = "x" ] || return # only once + if [ -z "$3" ]; then + md_size=${DEFAULT_TMPFS_SIZE} + else + md_size="$3" + fi + md_size=$((${md_size} * 512)) + mount_md $md_size /$1 + /bin/chmod 755 /$1 + eval md_created_$2=created +} + +# Do we have anything to do? +if [ ! -d "/conf/base/" ] ; then + return 0 +fi + +# Make sure tmpfs is loaded +kldload tmpfs 2>/dev/null + +# Lets grab a list of dirs to work on +for SUBDIR in $(find /conf/base -type d -depth 1 | tr -s '\n' ' ') +do + copy_subdir ${SUBDIR} +done + +# DONE +exit 0 Index: libexec/rc/sbin/Makefile =================================================================== --- /dev/null +++ libexec/rc/sbin/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +SUBDIR= mark_service_starting +SUBDIR+= rc-abort +SUBDIR+= swclock +SUBDIR_PARALLEL= + +.include + Index: libexec/rc/sbin/Makefile.inc =================================================================== --- /dev/null +++ libexec/rc/sbin/Makefile.inc @@ -0,0 +1,7 @@ +# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93 +# $FreeBSD$ + +BINDIR?= /libexec/rc/sbin + +WARNS?= 6 +WFORMAT?= 1 Index: libexec/rc/sbin/mark_service_starting/Makefile =================================================================== --- /dev/null +++ libexec/rc/sbin/mark_service_starting/Makefile @@ -0,0 +1,33 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= mark_service_starting + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +LINKS= ${BINDIR}/mark_service_starting ${BINDIR}/mark_service_started \ + ${BINDIR}/mark_service_starting ${BINDIR}/mark_service_stopping \ + ${BINDIR}/mark_service_starting ${BINDIR}/mark_service_stopped \ + ${BINDIR}/mark_service_starting ${BINDIR}/mark_service_inactive \ + ${BINDIR}/mark_service_starting ${BINDIR}/mark_service_wasinactive \ + ${BINDIR}/mark_service_starting ${BINDIR}/mark_service_hotplugged \ + ${BINDIR}/mark_service_starting ${BINDIR}/mark_service_failed +SRCS= do_mark_service.c \ + rc-misc.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR?=/libexec/rc/sbin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/sbin/mark_service_starting/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/sbin/mark_service_starting/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/sbin/rc-abort/Makefile =================================================================== --- /dev/null +++ libexec/rc/sbin/rc-abort/Makefile @@ -0,0 +1,25 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= rc-abort + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= rc-abort.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR?=/libexec/rc/sbin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/sbin/rc-abort/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/sbin/rc-abort/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/sbin/swclock/Makefile =================================================================== --- /dev/null +++ libexec/rc/sbin/swclock/Makefile @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= swclock + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= swclock.c \ + rc-misc.c \ + _usage.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 + +BINDIR?=/libexec/rc/sbin +LIBADD= einfo kvm rc util +MAN= + +.include Index: libexec/rc/sbin/swclock/Makefile.depend =================================================================== --- /dev/null +++ libexec/rc/sbin/swclock/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/libkvm \ + lib/librc \ + lib/libutil + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: libexec/rc/sh/Makefile =================================================================== --- /dev/null +++ libexec/rc/sh/Makefile @@ -0,0 +1,86 @@ +# $FreeBSD$ +# +# + +SHSRC= ${SRCTOP}/contrib/openrc/ + +.PATH: ${SHSRC}/sh + +SFILES= functions \ + gendepends \ + openrc-run \ + rc-functions + +FILES+= rc-mount.sh \ + runit.sh \ + s6.sh \ + start-stop-daemon.sh \ + supervise-daemon.sh \ + init.sh \ + functions.sh \ + gendepends.sh \ + openrc-run.sh \ + rc-functions.sh + +CLEANFILES+= functions.sh init.sh gendepends.sh openrc-run.sh rc-functions.sh + + +functions.sh: + sed 's|@SHELL@|/bin/sh|g' ${SRCTOP}/contrib/openrc/sh/functions.sh.in >${.TARGET} + sed -i '' 's|@LIBEXECDIR@|/libexec/rc|g' ${.TARGET} + sed -i '' 's|@BINDIR@|/usr/local/bin|g' ${.TARGET} + sed -i '' 's|@SBINDIR@|/usr/local/sbin|g' ${.TARGET} + sed -i '' 's|@PKG_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@LOCAL_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@SYSCONFDIR@|/etc|g' ${.TARGET} + sed -i '' 's|@LIB@|/lib|g' ${.TARGET} + sed -i '' 's|@PREFIX@||g' ${.TARGET} + +gendepends.sh: + sed 's|@SHELL@|/bin/sh|g' ${SRCTOP}/contrib/openrc/sh/gendepends.sh.in >${.TARGET} + sed -i '' 's|@LIBEXECDIR@|/libexec/rc|g' ${.TARGET} + sed -i '' 's|@BINDIR@|/usr/local/bin|g' ${.TARGET} + sed -i '' 's|@SBINDIR@|/usr/local/sbin|g' ${.TARGET} + sed -i '' 's|@PKG_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@LOCAL_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@SYSCONFDIR@|/etc|g' ${.TARGET} + sed -i '' 's|@LIB@|/lib|g' ${.TARGET} + sed -i '' 's|@PREFIX@||g' ${.TARGET} + +openrc-run.sh: + sed 's|@SHELL@|/bin/sh|g' ${SRCTOP}/contrib/openrc/sh/openrc-run.sh.in >${.TARGET} + sed -i '' 's|@LIBEXECDIR@|/libexec/rc|g' ${.TARGET} + sed -i '' 's|@BINDIR@|/usr/local/bin|g' ${.TARGET} + sed -i '' 's|@SBINDIR@|/usr/local/sbin|g' ${.TARGET} + sed -i '' 's|@PKG_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@LOCAL_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@SYSCONFDIR@|/etc|g' ${.TARGET} + sed -i '' 's|@LIB@|/lib|g' ${.TARGET} + sed -i '' 's|@PREFIX@||g' ${.TARGET} + +rc-functions.sh: + sed 's|@SHELL@|/bin/sh|g' ${SRCTOP}/contrib/openrc/sh/rc-functions.sh.in >${.TARGET} + sed -i '' 's|@LIBEXECDIR@|/libexec/rc|g' ${.TARGET} + sed -i '' 's|@BINDIR@|/usr/local/bin|g' ${.TARGET} + sed -i '' 's|@SBINDIR@|/usr/local/sbin|g' ${.TARGET} + sed -i '' 's|@PKG_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@LOCAL_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@SYSCONFDIR@|/etc|g' ${.TARGET} + sed -i '' 's|@LIB@|/lib|g' ${.TARGET} + sed -i '' 's|@PREFIX@||g' ${.TARGET} + +init.sh: + sed 's|@SHELL@|/bin/sh|g' ${SRCTOP}/contrib/openrc/sh/init.sh.BSD.in >${.TARGET} + sed -i '' 's|@LIBEXECDIR@|/libexec/rc|g' ${.TARGET} + sed -i '' 's|@BINDIR@|/usr/local/bin|g' ${.TARGET} + sed -i '' 's|@SBINDIR@|/usr/local/sbin|g' ${.TARGET} + sed -i '' 's|@PKG_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@LOCAL_PREFIX@|/usr/local|g' ${.TARGET} + sed -i '' 's|@SYSCONFDIR@|/etc|g' ${.TARGET} + sed -i '' 's|@LIB@|/lib|g' ${.TARGET} + sed -i '' 's|@PREFIX@||g' ${.TARGET} + +FILESDIR= /libexec/rc/sh +FILESMODE= 755 + +.include Index: release/release.sh =================================================================== --- release/release.sh +++ release/release.sh @@ -261,7 +261,7 @@ cp /etc/resolv.conf ${CHROOTDIR}/etc/resolv.conf # Run ldconfig(8) in the chroot directory so /var/run/ld-elf*.so.hints # is created. This is needed by ports-mgmt/pkg. - eval chroot ${CHROOTDIR} /etc/rc.d/ldconfig forcerestart + eval chroot ${CHROOTDIR} /etc/init.d/ldconfig start # If MAKE_CONF and/or SRC_CONF are set and not character devices # (/dev/null), copy them to the chroot. Index: sbin/Makefile =================================================================== --- sbin/Makefile +++ sbin/Makefile @@ -52,8 +52,12 @@ newfs_msdos \ nfsiod \ nos-tun \ + openrc \ + openrc-run \ ping \ rcorder \ + rc-service \ + rc-update \ reboot \ recoverdisk \ resolvconf \ @@ -63,6 +67,8 @@ setkey \ shutdown \ spppcontrol \ + start-stop-daemon \ + supervise-daemon \ swapon \ sysctl \ tunefs \ Index: sbin/devd/Makefile =================================================================== --- sbin/devd/Makefile +++ sbin/devd/Makefile @@ -4,28 +4,34 @@ WARNS?= 3 PACKAGE=runtime -CONFGROUPS= CONFS DEVD -CONFS= devd.conf +CONFGROUPS= CONFS DEVD DEVDOPENRC +CONFS= devd.conf devd-openrc.conf DEVD= devmatch.conf +DEVDOPENRC= devmatch-openrc.conf DEVDDIR= /etc/devd +DEVDOPENRCDIR= /etc/devd-openrc .if ${MK_ACPI} != "no" DEVD+= asus.conf +DEVDOPENRC+= asus.conf .endif .if ${MK_HYPERV} != "no" DEVD+= hyperv.conf +DEVDOPENRC+= hyperv.conf .endif .if ${MK_USB} != "no" DEVD+= uath.conf ulpt.conf +DEVDOPENRC+= uath.conf ulpt.conf .endif .if ${MACHINE_ARCH} == "powerpc" DEVD+= apple.conf +DEVDOPENRC+= apple.conf .endif .if ${MK_ZFS} != "no" -DEVD+= zfs.conf +DEVDOPENRC+= zfs.conf .endif PROG_CXX=devd Index: sbin/devd/devd-openrc.conf =================================================================== --- /dev/null +++ sbin/devd/devd-openrc.conf @@ -0,0 +1,371 @@ +# $FreeBSD$ +# +# Refer to devd.conf(5) and devd(8) man pages for the details on how to +# run and configure devd. +# + +# NB: All regular expressions have an implicit ^$ around them. +# NB: device-name is shorthand for 'match device-name' + +options { + # Each "directory" directive adds a directory to the list of + # directories that we scan for files. Files are loaded in the order + # that they are returned from readdir(3). The rule-sets are combined + # to create a DFA that's used to match events to actions. + directory "/etc/devd-openrc"; + directory "/usr/local/etc/devd-openrc"; + pid-file "/var/run/devd-openrc.pid"; + + # Setup some shorthand for regex that we use later in the file. + #XXX Yes, these are gross -- imp + set scsi-controller-regex + "(aac|adv|adw|aha|ahc|ahd|aic|amr|bt|ciss|dpt|\ + esp|ida|iir|ips|isp|mlx|mly|mpr|mps|mpt|ncr|ncv|nsp|stg|sym|\ + trm)\ + [0-9]+"; + set wifi-driver-regex + "(ath|bwi|bwn|ipw|iwi|iwm|iwn|malo|mwl|ral|rsu|rum|run|uath|\ + upgt|ural|urtw|rtwn_usb|wi|wpi|wtap|zyd)[0-9]+"; +}; + +# Note that the attach/detach with the highest value wins, so that one can +# override these general rules. + +# +# Configure the interface on attach. Due to a historical accident, this +# script is called pccard_ether. +# +# NB: DETACH events are ignored; the kernel should handle all cleanup +# (routes, arp cache). Beware of races against immediate create +# of a device with the same name; e.g. +# ifconfig bridge0 destroy; ifconfig bridge0 create +# +notify 0 { + match "system" "IFNET"; + match "subsystem" "!usbus[0-9]+"; + match "type" "ATTACH"; + + action "sh /etc/rc.devd network.$subsystem start"; +}; + +notify 0 { + match "system" "IFNET"; + match "subsystem" "!usbus[0-9]+"; + match "type" "DETACH"; + + action "sh /etc/rc.devd network.$subsystem stop"; +}; + +# +# Try to start dhclient on Ethernet-like interfaces when the link comes +# up. Only devices that are configured to support DHCP will actually +# run it. No link down rule exists because dhclient automatically exits +# when the link goes down. +# +notify 0 { + match "system" "IFNET"; + match "type" "LINK_UP"; + media-type "ethernet"; + + action "sleep 3 ; sh /etc/rc.devd dhcpcd.$subsystem restart"; +}; + +notify 0 { + match "system" "IFNET"; + match "type" "LINK_DOWN"; + + action "sh /etc/rc.devd dhcpcd.$subsystem stop"; +}; + +# +# Like Ethernet devices, but separate because 802.11 require spawning +# wlan(4) interface. +# +attach 0 { + device-name "$wifi-driver-regex"; + action "sh /etc/rc.devd network.$device-name start"; +}; +detach 0 { + device-name "$wifi-driver-regex"; + action "sh /etc/rc.devd network.$device-name stop"; +}; +notify 0 { + match "system" "IFNET"; + match "type" "LINK_UP"; + media-type "802.11"; + + action "sleep 3 ; sh /etc/rc.devd dhcpcd.$subsystem restart"; +}; + +# An entry like this might be in a different file, but is included here +# as an example of how to override things. Normally 'ed50' would match +# the above attach/detach stuff, but the value of 100 makes it +# hard wired to 1.2.3.4. +attach 100 { + device-name "ed50"; + action "ifconfig $device-name inet 1.2.3.4 netmask 0xffff0000"; +}; +detach 100 { + device-name "ed50"; +}; + +# When a USB Bluetooth dongle appears, activate it +attach 100 { + device-name "ubt[0-9]+"; + action "sh /etc/rc.devd bluetooth.$device-name start"; +}; +detach 100 { + device-name "ubt[0-9]+"; + action "sh /etc/rc.devd bluetooth.$device-name stop"; +}; + +# Firmware downloader for Atheros AR3011 based USB Bluetooth devices +#attach 100 { +# match "vendor" "0x0cf3"; +# match "product" "0x3000"; +# action "sleep 2 && /usr/sbin/ath3kfw -d $device-name -f /usr/local/etc/ath3k-1.fw"; +#}; + +# When a USB keyboard arrives, attach it as the console keyboard. +attach 100 { + device-name "ukbd0"; + action "/sbin/service syscons restart"; +}; +detach 100 { + device-name "ukbd0"; + action "/sbin/service syscons restart"; +}; + +notify 100 { + match "system" "DEVFS"; + match "subsystem" "CDEV"; + match "type" "CREATE"; + match "cdev" "atp[0-9]+"; + + action "sh /etc/rc.devd moused.$cdev start"; +}; + +notify 100 { + match "system" "DEVFS"; + match "subsystem" "CDEV"; + match "type" "CREATE"; + match "cdev" "ums[0-9]+"; + + action "sh /etc/rc.devd moused.$cdev start"; +}; + +notify 100 { + match "system" "DEVFS"; + match "subsystem" "CDEV"; + match "type" "CREATE"; + match "cdev" "wsp[0-9]+"; + + action "sh /etc/rc.devd moused.$cdev start"; +}; + +notify 100 { + match "system" "DEVFS"; + match "subsystem" "CDEV"; + match "type" "DESTROY"; + match "cdev" "ums[0-9]+"; + + action "sh /etc/rc.devd moused.$cdev start"; +}; + +# Firmware download into the ActiveWire board. After the firmware download is +# done, the device detaches and reappears as something new and shiny +# automatically. +attach 100 { + match "vendor" "0x0854"; + match "product" "0x0100"; + match "release" "0x0000"; + action "/usr/local/bin/ezdownload -f /usr/local/share/usb/firmware/0854.0100.0_01.hex $device-name"; +}; + +# Firmware download for Entrega Serial DB25 adapter. +attach 100 { + match "vendor" "0x1645"; + match "product" "0x8001"; + match "release" "0x0101"; + action "if ! kldstat -n usio > /dev/null 2>&1 ; then kldload usio; fi; /usr/sbin/ezdownload -v -f /usr/share/usb/firmware/1645.8001.0101 /dev/$device-name"; +}; + +# This entry starts the ColdSync tool in daemon mode. Make sure you have an up +# to date /usr/local/etc/palms. We override the 'listen' settings for port and +# type in /usr/local/etc/coldsync.conf. +notify 100 { + match "system" "USB"; + match "subsystem" "DEVICE"; + match "type" "ATTACH"; + match "vendor" "0x082d"; + match "product" "0x0100"; + match "release" "0x0100"; + action "/usr/local/bin/coldsync -md -p /dev/$cdev -t usb"; +}; + +# +# Rescan SCSI device-names on attach, but not detach. However, it is +# disabled by default due to reports of problems. +# +attach 0 { + device-name "$scsi-controller-regex"; +// action "camcontrol rescan all"; +}; + +# Don't even try to second guess what to do about drivers that don't +# match here. Instead, pass it off to syslog. Commented out for the +# moment, as the pnpinfo variable isn't set in devd yet. Individual +# variables within the bus supplied pnpinfo are set. +nomatch 0 { +# action "logger Unknown device: $pnpinfo $location $bus"; +}; + +# Various logging of unknown devices. +nomatch 10 { + match "bus" "uhub[0-9]+"; + action "logger Unknown USB device: vendor $vendor product $product \ + bus $bus"; +}; + +# Some PC-CARDs don't offer numerical manufacturer/product IDs, just +# show the CIS info there. +nomatch 20 { + match "bus" "pccard[0-9]+"; + match "manufacturer" "0xffffffff"; + match "product" "0xffffffff"; + action "logger Unknown PCCARD device: CISproduct $cisproduct \ + CIS-vendor $cisvendor bus $bus"; +}; + +nomatch 10 { + match "bus" "pccard[0-9]+"; + action "logger Unknown PCCARD device: manufacturer $manufacturer \ + product $product CISproduct $cisproduct CIS-vendor \ + $cisvendor bus $bus"; +}; + +nomatch 10 { + match "bus" "cardbus[0-9]+"; + action "logger Unknown Cardbus device: device $device class $class \ + vendor $vendor bus $bus"; +}; + +# Switch power profiles when the AC line state changes. +#notify 10 { +# match "system" "ACPI"; +# match "subsystem" "ACAD"; +# action "service power_profile $notify"; +#}; + +# Notify all users before beginning emergency shutdown when we get +# a _CRT or _HOT thermal event and we're going to power down the system +# very soon. +notify 10 { + match "system" "ACPI"; + match "subsystem" "Thermal"; + match "notify" "0xcc"; + action "logger -p kern.emerg 'WARNING: system temperature too high, shutting down soon!'"; +}; + +# User requested suspend, so perform preparation steps and then execute +# the actual suspend process. +notify 10 { + match "system" "ACPI"; + match "subsystem" "Suspend"; + action "/etc/rc.suspend acpi $notify"; +}; +notify 10 { + match "system" "ACPI"; + match "subsystem" "Resume"; + action "/etc/rc.resume acpi $notify"; +}; + +/* EXAMPLES TO END OF FILE + +# An example of something that a vendor might install if you were to +# add their device. This might reside in /usr/local/etc/devd/deqna.conf. +# A deqna is, in this hypothetical example, a pccard ethernet-like device. +# Students of history may know other devices by this name, and will get +# the in-jokes in this entry. +nomatch 10 { + match "bus" "pccard[0-9]+"; + match "manufacturer" "0x1234"; + match "product" "0x2323"; + action "kldload -n if_deqna"; +}; +attach 10 { + device-name "deqna[0-9]+"; + action "sh /etc/rc.devd network.$device-name start"; +}; +detach 10 { + device-name "deqna[0-9]+"; + action "sh /etc/rc.devd network.$device-name stop"; +}; + +# Examples of notify hooks. A notify is a generic way for a kernel +# subsystem to send event notification to userland. + +# Here are some examples of ACPI notify handlers. ACPI subsystems that +# generate notifies include the AC adapter, power/sleep buttons, +# control method batteries, lid switch, and thermal zones. +# +# Information returned is not always the same as the ACPI notify +# events. See the ACPI specification for more information about +# notifies. Here is the information returned for each subsystem: +# +# ACAD: AC line state (0 is offline, 1 is online) +# Button: Button pressed (0 for power, 1 for sleep) +# CMBAT: ACPI battery events +# Lid: Lid state (0 is closed, 1 is open) +# Suspend, Resume: Suspend and resume notification +# Thermal: ACPI thermal zone events +# +# This example calls a script when the AC state changes, passing the +# notify value as the first argument. If the state is 0x00, it might +# call some sysctls to implement economy mode. If 0x01, it might set +# the mode to performance. +notify 10 { + match "system" "ACPI"; + match "subsystem" "ACAD"; + action "/etc/acpi_ac $notify"; +}; + +# This example works around a memory leak in PostgreSQL, restarting +# it when the "user:postgres:swap:devctl=1G" rctl(8) rule gets triggered. +notify 0 { + match "system" "RCTL"; + match "rule" "user:770:swap:.*"; + action "service postgresql restart"; +}; + +# Discard autofs caches, useful for the -media special map. +notify 100 { + match "system" "GEOM"; + match "subsystem" "DEV"; + action "/usr/sbin/automount -c"; +}; + +# Handle userland coredumps. +# This commented out handler makes it possible to run an +# automated debugging session after the core dump is generated. +# Replace action with a proper coredump handler, but be aware that +# it will run with elevated privileges. +notify 10 { + match "system" "kernel"; + match "subsystem" "signal"; + match "type" "coredump"; + action "logger $comm $core"; +}; + +# Let the init(8) know there's a new USB serial interface it might +# want to run getty(8) for. This includes device-side tty created +# by usb_template(4). +notify 100 { + match "system" "DEVFS"; + match "subsystem" "CDEV"; + match "type" "CREATE"; + match "cdev" "ttyU[0-9]+"; + action "/sbin/init q"; +}; + +*/ Index: sbin/devd/devmatch-openrc.conf =================================================================== --- /dev/null +++ sbin/devd/devmatch-openrc.conf @@ -0,0 +1,20 @@ +# +# $FreeBSD$ +# + +# +# Example devd configuration file for automatically +# loading what modules we can based on nomatch +# events. +# +# Generic NOMATCH event +nomatch 100 { + action "sh /etc/rc.devd devmatch start.'?'$_ '?'$_"; +}; + +# Add the following to devd.conf to prevent this from running: +# nomatch 1000 { +# action "true"; +# }; +# it replaces the generic event with one of higher priority that +# does nothing. You can also set 'devmatch_enable=NO' in /etc/rc.conf Index: sbin/devfs/devfs.rules =================================================================== --- sbin/devfs/devfs.rules +++ sbin/devfs/devfs.rules @@ -86,3 +86,39 @@ add include $devfsrules_unhide_login add path fuse unhide add path zfs unhide + +[devfsrules_common=7] + +# cd*/acd* drives need user read access for +# DVD video playback and audio CD playback +add path 'acd[0-9]*' mode 664 +add path 'cd[0-9]*' mode 664 + +# Digital TV devices need read/write for all +add path 'dvb/*' mode 666 + +# Video device access (webcams and such) +add path 'video[0-9]*' mode 666 + +# DRM-enabled video driver access +add path 'dri/*' mode 666 +add path 'drm/*' mode 666 + +# USB Human Interface Devices +add path 'uhid[0-9]' mode 666 + +#Scanners (xsane?) +#add path 'uscan[0-9]*' mode 666 + +#printers (hplip?) +#add path 'lpt[0-9]*' mode 666 +#add path 'ulpt[0-9]*' mode 666 +#add path 'unlpt[0-9]*' mode 666 + +#K3B/cdrecord passthrough +#add path 'pass[0-9]*' mode 666 + +# raw disk devices +#add path 'ad[0-9]*' mode 666 +#add path 'da[0-9]*' mode 666 +#add path 'mmcsd[0-9]*' mode 666 Index: sbin/openrc-run/Makefile =================================================================== --- /dev/null +++ sbin/openrc-run/Makefile @@ -0,0 +1,26 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= openrc-run +LINKS= ${BINDIR}/openrc-run ${BINDIR}/runscript + +OPENRC= ${.CURDIR}/../../contrib/openrc + +RC= ${OPENRC}/src/rc +EINFO= ${OPENRC}/src/libeinfo +LIBRC= ${OPENRC}/src/librc +OLIBRC= ${.OBJDIR}/../../lib/librc/contrib/openrc/src/librc +INC= ${OPENRC}/src/includes + +SRCS= openrc-run.c rc-misc.c rc-plugin.c _usage.c +CFLAGS+= -I${RC} -I${EINFO} -I${LIBRC} -I${OLIBRC} -I${INC} + +WARNS?= 3 +MAN= openrc-run.8 + +LIBADD= einfo rc util + +.PATH: ${RC} +.PATH: ${OPENRC}/man + +.include Index: sbin/openrc-run/Makefile.depend =================================================================== --- /dev/null +++ sbin/openrc-run/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/librc \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: sbin/openrc/Makefile =================================================================== --- /dev/null +++ sbin/openrc/Makefile @@ -0,0 +1,30 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= openrc +LINKS= ${BINDIR}/openrc ${BINDIR}/rc + +OPENRC= ${.CURDIR}/../../contrib/openrc + +RC= ${OPENRC}/src/rc +EINFO= ${OPENRC}/src/libeinfo +LIBRC= ${OPENRC}/src/librc +OLIBRC= ${.OBJDIR}/../../lib/librc/contrib/openrc/src/librc +INC= ${OPENRC}/src/includes + +SRCS= rc.c rc-logger.c rc-misc.c rc-plugin.c _usage.c rc-logger.h +CFLAGS+= -I${RC} -I${EINFO} -I${LIBRC} -I${OLIBRC} -I${INC} + +WARNS?= 3 +MAN= openrc.8 + +LIBADD= einfo rc util + +.PATH: ${RC} +.PATH: ${OPENRC}/man + +SUBDIR+= conf.d +SUBDIR+= local.d +SUBDIR+= sysctl.d + +.include Index: sbin/openrc/Makefile.depend =================================================================== --- /dev/null +++ sbin/openrc/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/librc \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: sbin/openrc/conf.d/Makefile =================================================================== --- /dev/null +++ sbin/openrc/conf.d/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +PACKAGE=runtime + +CONFS= bootmisc fsck ipfw ldconfig localmount moused netmount powerd rarpd \ + savecore staticroute swap syscons tmpfiles urandom + +NO_OBJ= +CONFDIR= /etc/conf.d +CONFMODE= 755 + +.include + Index: sbin/openrc/conf.d/bootmisc =================================================================== --- /dev/null +++ sbin/openrc/conf.d/bootmisc @@ -0,0 +1,15 @@ +# List of /tmp directories we should clean up +clean_tmp_dirs="/tmp" + +# Should we wipe the tmp paths completely or just selectively remove known +# locks / files / etc... ? +wipe_tmp="YES" + +# Write the initial dmesg log into /var/log/dmesg after boot +# This may be useful if you need the kernel boot log afterwards +log_dmesg="YES" + +# Save the previous dmesg log to dmesg.old +# This may be useful if you need to compare the current boot to the +# previous one. +#previous_dmesg=no Index: sbin/openrc/conf.d/fsck =================================================================== --- /dev/null +++ sbin/openrc/conf.d/fsck @@ -0,0 +1,40 @@ +# Pass any arguments to fsck. +# By default we preen. +# Linux systems also force -C0 and -T. +# If fsck_args is not specified then Linux systems also use -A +# (and -R if / is rw) +#fsck_args="-p" + +# We can also specify the passno in /etc/fstab to check +# If you multiplex fsck (ie ln -s fsck /etc/init.d/fsck.late) then you can +# do an fsck outside of the normal scope, say for /home. +# Here are some exampes:- +#fsck_passno="=1 =2" +#fsck_passno=">1" +#fsck_passno="<2" + +# If passno is not enough granularity, you can also specify mountpoints to +# check. This should NOT be used for the default non-multiplexed fsck, or your +# system might not be checked. Additionally, it is mutually exclusive with +# the fsck_passno setting. +#fsck_mnt="" +#fsck_mnt="/home" + +# Most modern fs's don't require a full fsck on boot, but for those that do +# it may be advisable to skip this when running on battery. +# WARNING: Do not turn this off if you have any JFS partitions. +fsck_on_battery="YES" + +# fsck_shutdown causes fsck to trigger during shutdown as well as startup. +# The end result of this is that if any periodic non-root filesystem checks are +# scheduled, under normal circumstances the actual check will happen during +# shutdown rather than at next boot. +# This is useful when periodic filesystem checks are causing undesirable +# delays at startup, but such delays at shutdown are acceptable. +fsck_shutdown="NO" + +# fsck_abort_on_errors can be set to no to cause fsck to not abort on +# errors. +# This is useful when periodic filesystem checks are causing undesirable +# aborts. +fsck_abort_on_errors="YES" Index: sbin/openrc/conf.d/hostname =================================================================== --- /dev/null +++ sbin/openrc/conf.d/hostname @@ -0,0 +1,2 @@ +# Set to the hostname of this machine +hostname="localhost" Index: sbin/openrc/conf.d/ipfw =================================================================== --- /dev/null +++ sbin/openrc/conf.d/ipfw @@ -0,0 +1,14 @@ +# ipfw provides a stateful firewall. +# This means we allow everything out, and if we have a connection we allow it +# back in. This is very flexable and quite secure. + +# For ease of use, we allow auth and ssh ports through as well. +# To override the list of allowed ports +#ipfw_ports_in="auth ssh" + +# You may want to enable logging of denied connections +#ipfw_log_deny="YES" + +# This ports not logged +#ipfw_ports_nolog="135-139,445 1026,1027 1433,1434" + Index: sbin/openrc/conf.d/ldconfig =================================================================== --- /dev/null +++ sbin/openrc/conf.d/ldconfig @@ -0,0 +1,14 @@ +## Set to YES to disable ldconfig security checks +ldconfig_insecure="NO" + +## ldconfig paths and directories +ldconfig_paths="/usr/lib/compat /usr/local/lib /usr/local/lib/compat/pkg" +ldconfig32_paths="/usr/lib32 /usr/lib32/compat" +ldconfigsoft_paths="/usr/libsoft /usr/libsoft/compat /usr/local/libsoft" +ldconfig_paths_aout="/usr/lib/compat/aout /usr/local/lib/aout" + +## ldconfig directories +ldconfig_local_dirs="/usr/libdata/ldconfig /usr/local/libdata/ldconfig" +ldconfig_local32_dirs="/usr/local/libdata/ldconfig32" +ldconfig_localsoft_dirs="/usr/local/libdata/ldconfigsoft" + Index: sbin/openrc/conf.d/local =================================================================== --- /dev/null +++ sbin/openrc/conf.d/local @@ -0,0 +1 @@ +rc_verbose="YES" Index: sbin/openrc/conf.d/localmount =================================================================== --- /dev/null +++ sbin/openrc/conf.d/localmount @@ -0,0 +1,10 @@ +# Stop the unmounting of certain points. +# This could be useful for some NFS related work. +#no_umounts="/dir1:/var/dir2" +# +# Mark certain mount points as critical. +# This contains aspace separated list of mount points which should be +# considered critical. If one of these mount points cannot be mounted, +# localmount will fail. +# By default, this is empty. +#critical_mounts="/home /var" Index: sbin/openrc/conf.d/modules =================================================================== --- /dev/null +++ sbin/openrc/conf.d/modules @@ -0,0 +1,30 @@ +# Linux users can define a list of modules for a specific kernel version, +# a released kernel version, a main kernel version or all kernel versions. +# The most specific versioned variable will take precedence. +# FreeBSD users can only use the modules="foo bar" setting. +#modules_2_6_23_gentoo_r5="ieee1394 ohci1394" +#modules_2_6_23="tun ieee1394" +#modules_2_6="tun" +#modules_2="ipv6" +#modules="ohci1394" + +# Linux users can give modules a different name when they load - the new name +# will also be used to pick arguments below. +# This is not supported on FreeBSD. +#modules="dummy:dummy1" + +# Linux users can give the modules some arguments if needed, per version +# if necessary. +# Again, the most specific versioned variable will take precedence. +# This is not supported on FreeBSD. +#module_ieee1394_args="debug" +#module_ieee1394_args_2_6_23_gentoo_r5="debug2" +#module_ieee1394_args_2_6_23="debug3" +#module_ieee1394_args_2_6="debug4" +#module_ieee1394_args_2="debug5" + +# You should consult your kernel documentation and configuration +# for a list of modules and their options. + +# These modules will be loaded at startup +modules="" Index: sbin/openrc/conf.d/moused =================================================================== --- /dev/null +++ sbin/openrc/conf.d/moused @@ -0,0 +1,16 @@ +# See the moused man page for available settings. + +# Set to your mouse device psm[0-9] for PS/2 ports, ums[0-9] for USB ports +# Leave blank to try to autodetect it +#moused_device="/dev/psm0" + +# Any additional arguments required for a specific port +#moused_args_psm0="" +# or for all mice +#moused_args="" + +# You can also multiplex the init script for each device like so +# ln -s moused /etc/init.d/moused.ums0 +# This enables you to have a config file per mouse (forces moused_device +# to ums0 in this case) and control each mouse. +# devd can also start and stop these mice, which laptop users will find handy. Index: sbin/openrc/conf.d/netmount =================================================================== --- /dev/null +++ sbin/openrc/conf.d/netmount @@ -0,0 +1,47 @@ +# You will need to set the dependencies in the netmount script to match +# the network configuration tools you are using. This should be done in +# this file by following the examples below, and not by changing the +# service script itself. +# +# Each of these examples is meant to be used separately. So, for +# example, do not set rc_need to something like "net.eth0 dhcpcd". +# +# If you are using newnet and configuring your interfaces with static +# addresses with the network script, you should use this setting. +# +#rc_need="network" +# +# If you are using oldnet, you must list the specific net.* services you +# need. +# +# This example assumes all of your netmounts can be reached on +# eth0. +# +#rc_need="net.eth0" +# +# This example assumes some of your netmounts are on eth1 and some +# are on eth2. +# +#rc_need="net.eth1 net.eth2" +# +# If you are using a dynamic network management tool like +# NetworkManager, dhcpcd in standalone mode, wicd, badvpn-ncd, etc, to +# manage the network interfaces with the routes to your netmounts, you +# should list that tool. +# +#rc_need="NetworkManager" +#rc_need="dhcpcd" +#rc_need="wicd" +# +# The default setting is designed to be backward compatible with our +# current setup, but you are highly discouraged from using this. In +# other words, please change it to be more suited to your system. +# +rc_need="net" +# +# Mark certain mount points as critical. +# This contains aspace separated list of mount points which should be +# considered critical. If one of these mount points cannot be mounted, +# netmount will fail. +# By default, this is empty. +#critical_mounts="/home /var" Index: sbin/openrc/conf.d/network =================================================================== --- /dev/null +++ sbin/openrc/conf.d/network @@ -0,0 +1,80 @@ +# Assign static IP addresses and run custom scripts per interface. +# Separate commands with ; +# Prefix with ! to run a shell script. +# Use \$int to represent the interface +#ifconfig_eth0="192.168.0.10 netmask 255.255.255.0" + +# You also have ifup_eth0 and ifdown_eth0 to run other commands when +# eth0 is started and stopped. +# You should note that we don't stop the network at system shutdown by default. +# If you really need this, then set keep_network=NO + +# Lastly, the interfaces variable pulls in virtual interfaces that cannot +# be automatically detected. +#interfaces="br0 bond0 vlan0" + +# You can also use files instead of variables here if you like: +# /etc/ifconfig.eth0 is equivalent to ifconfig_eth0 +# /etc/ip.eth0 is equivalent to ifconfig_eth0 +# /etc/ifup.eth0 is equivalent to ifup_eth0 +# /etc/ifdown.eth0 is equivalent to ifdown_eth0 +# Any files found will automatically be put into the interfaces variable. +# You don't need to escape variables in files, so use $int instead of \$int. + +# If you require DHCP, you should install dhcpcd and add it to the boot or +# default runlevel. + +# NIS users can set the domain name here +#domainname="foobar" + +# You can add a default route. +# The way this is done is slightly different depending on the operating system. +# +# *BSD: +#defaultroute="192.168.0.1" +#defaultroute6="2001:a:b:c" +#Hurd/Linux (ifconfig): +#defaultroute="gw 192.168.0.1" +#defaultroute6="gw 2001:a:b:c" + +# The remainder of this file applies to Linux only and shows how +# iproute2 is supported along with other examples. + +# ifconfig under Linux is not that powerful and doesn't easily handle +# multiple addresses +# On the other hand, iproute2 is quite powerful and is also supported +#ip_eth0="192.168.0.10/24; 192.168.10.10/24" + +# You can also use iproute2 to add the default route. +#defaultiproute="via 192.168.0.1" +#defaultiproute6="via 2001:a:b:c" + +# ip doesn't handle MTU like ifconfig, but we can do it like so +#ifup_eth0="ip link set \$int mtu 1500" + +# Create a bonded interface +#interfaces="bond0" +#ifup_bond0="modprobe bonding; ifconfig \$int up; ifenslave \$int bge0" +#ifconfig_bond0="192.168.0.10 netmask 255.255.255.0" +#ifdown_bond0="rmmod bonding" + +# Create tap interface and a bridge interface. +# We add the tap to the bridge. +# An external program, like dhcpcd, will configure the IP on the bridge +#interfaces="tun0 br0" +#ifup_tun0="tunctl -t \$int" +#ifdown_tun0="tunctl -d \$int" +#ifup_br0="brctl addbr \$int; brctl add \$int eth1; brtctl add \$int eth2" +#ifdown_br0="ifconfig \$int down; btctl delbr \$int" + +# Create VLAN +#interfaces="eth0_2 eth0_3 eth0_4" +#ifup_eth0="vconfig add \$int 2; vconfig add \$int 3; vconfig add \$int 4" +#ifconfig_eth0_2="192.168.2.10 netmask 255.255.255.0" +#ifconfig_eth0_3="192.168.3.10 netmask 255.255.255.0" +#ifconfig_eth0_4="192.168.4.10 netmask 255.255.255.0" +#ifdown_eth0="vconfig rem \$int.2; vconfig rem \$int.3; vconfig rem \$int.4" + +# Normally you would use wpa_supplicant to configure wireless, but you can +# use iwconfig also +#ifup_wlan0="iwconfig \$int key s:secretkey enc open essid foobar" Index: sbin/openrc/conf.d/powerd =================================================================== --- /dev/null +++ sbin/openrc/conf.d/powerd @@ -0,0 +1,7 @@ +# Mode allowed: maximum, minimum, adaptive +# Default unless specified is adaptive +powerd_ac_mode="maximum" +#powerd_battery_mode="minimum" + +# Addiditonal arguments for powerd - see the man page for details +powerd_args="" Index: sbin/openrc/conf.d/rarpd =================================================================== --- /dev/null +++ sbin/openrc/conf.d/rarpd @@ -0,0 +1,3 @@ +# To start rarpd only for a given interface, set the +# following variable. Otherwise we listen on all interfaces. +#rarpd_interface="rl0" Index: sbin/openrc/conf.d/savecore =================================================================== --- /dev/null +++ sbin/openrc/conf.d/savecore @@ -0,0 +1,25 @@ +# Unless you're a kernel developer or driver writer then this won't +# be of any interest to you at all. +# The following options allow to configure the kernel's core dump +# facilities. + +# The dump_device variable is used to specify which device will be +# used by the kernel to write the dump down. This has to be a swap +# partition, and has to be at least big enough to contain the whole +# physical memory (see hw.physmem sysctl(8) variable). +# When the variable is commented out, no core dump will be enabled for +# the kernel. +#dump_device=/dev/ad0s1b + +# The dump_dir variable is used to tell savecore(8) utility where +# to save the kernel core dump once it's restored from the dump +# device. If unset, /var/crash will be used, as the default of +# FreeBSD. +#dump_dir=/var/crash + +# The dump_compress variable decide whether to compress with +# gzip(1) the dump or leave it of its original size (the size of the +# physical memory present on the system). If set to yes, the -z option +# will be passed to savecore(8) that will proceed on compressing the +# dump. +#dump_compress=NO Index: sbin/openrc/conf.d/staticroute =================================================================== --- /dev/null +++ sbin/openrc/conf.d/staticroute @@ -0,0 +1,26 @@ +# Static routes are defined differently depending on your operating +# system, so please be sure to use the correct syntax. +# Do not use this file to define the default route. +# In all settings, multiple routes should be separated using ; or new lines. + +# Define static routes on Linux using route. See route(8) for syntax. +#staticroute="net 192.168.0.0 netmask 255.255.255.0 gw 10.73.1.1 +#net 192.168.1.0 netmask 255.255.255.0 gw 10.73.1.1" + +# Define static routes on Linux using iproute2. See ip(8) for syntax. +#staticiproute="192.168.0.0/24 via 10.73.1.1; 192.168.1.0/24 via 10.73.1.1" + +# Define static routes on GNU/Hurd. See route(8) for syntax. +# /etc/route.conf(5) takes precedence over this configuration. +# FIXME: "net ..." not supported +#staticroute="net 192.168.0.0 -netmask 255.255.255.0 --address 10.73.1.1 +#net 192.168.1.0 -netmask 255.255.255.0 --address 10.73.1.1" + +# Define static routes on GNU/KFreeBSD. See route(8) for syntax. +#staticroute="net 192.168.0.0 10.73.1.1 netmask 255.255.255.0 +#net 192.168.1.0 10.73.1.1 netmask 255.255.255.0" + +# Define static routes on other BSD systems. See route(8) for syntax. +# /etc/route.conf(5) takes precedence over this configuration. +#staticroute="net 192.168.0.0 -netmask 255.255.255.0 10.73.1.1 +#net 192.168.1.0 -netmask 255.255.255.0 10.73.1.1" Index: sbin/openrc/conf.d/swap =================================================================== --- /dev/null +++ sbin/openrc/conf.d/swap @@ -0,0 +1,13 @@ +# If you are only using local swap partitions, you should not change +# this file. Otherwise, you need to uncomment the below rc_before line +# followed by the appropriate rc_need line. +#rc_before="!localmount" +# +# If you are using swap files stored on local file systems, uncomment +# this line. +#rc_need="localmount" +# +# If you are using swap files stored on network file systems or swap +# partitions stored on network block devices such as iSCSI, uncomment +# this line. +#rc_need="netmount" Index: sbin/openrc/conf.d/syscons =================================================================== --- /dev/null +++ sbin/openrc/conf.d/syscons @@ -0,0 +1,19 @@ +# Example syscons config file. This is the place to set things like keymap, etc. + +# Set the video mode - you should check the vidcontrol man page for valid modes +# NOTE:- This will blank the screen after this command is run +# NOTE:- You can get more modes if you load the vesa kernel module, but this +# may require the SC_PIXEL_MODE kernel option +#allscreen_flags="VGA_80x30" + +# Set the keymap to "uk.iso". +#keymap="uk.iso" + +# Set the keyboard rate to 250ms delay, and 34 repeat rate. +#keyrate="250.34" + +# Change the behaviour of F-unction keys (see kbdcontrol(1)). +#keychange="10 'ssh myhost'" + +# See vidcontrol(1) -t +#blanktime="off" Index: sbin/openrc/conf.d/tmpfiles =================================================================== --- /dev/null +++ sbin/openrc/conf.d/tmpfiles @@ -0,0 +1,3 @@ +# Extra options for tmpfiles.sh +#tmpfiles_opts="--verbose" +tmpfiles_opts="" Index: sbin/openrc/conf.d/urandom =================================================================== --- /dev/null +++ sbin/openrc/conf.d/urandom @@ -0,0 +1,5 @@ +# Sometimes you want to have urandom start before "localmount" +# (say for crypt swap), so you will need to customize this +# behavior. If you have /var on a separate partition, then +# make sure this path lives on your root device somewhere. +urandom_seed="/var/db/entropy-file" Index: sbin/openrc/local.d/Makefile =================================================================== --- /dev/null +++ sbin/openrc/local.d/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +FILES= README + +NO_OBJ= +FILESDIR= /etc/local.d +FILESMODE= 755 + +.include + Index: sbin/openrc/local.d/README =================================================================== --- /dev/null +++ sbin/openrc/local.d/README @@ -0,0 +1,14 @@ +This directory should contain programs or scripts which are to be run +when the local service is started or stopped. + +If a file in this directory is executable and it has a .start extension, +it will be run when the local service is started. If a file is +executable and it has a .stop extension, it will be run when the local +service is stopped. + +All files are processed in lexical order. + +Keep in mind that files in this directory are processed sequentially, +and the local service is not considered started or stopped until +everything is processed, so if you have a process which takes a long +time to run, it can delay your boot or shutdown processing. Index: sbin/openrc/sysctl.d/Makefile =================================================================== --- /dev/null +++ sbin/openrc/sysctl.d/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +FILES= README + +NO_OBJ= +FILESDIR= /etc/sysctl.d +FILESMODE= 755 + +.include + Index: sbin/openrc/sysctl.d/README =================================================================== --- /dev/null +++ sbin/openrc/sysctl.d/README @@ -0,0 +1,13 @@ +Kernel system variables configuration files + +Files found under the /etc/sysctl.d directory that end with .conf are +parsed within sysctl(8) at boot time. If you want to set kernel variables +you can either edit /etc/sysctl.conf or make a new file. + +The filename isn't important, but don't make it a package name as it may clash +with something the package builder needs later. The file name must end +with .conf, or it will not be read. + +The recommended location for local system settings is /etc/sysctl.d/local.conf +but as long as you follow the rules for the name of the file, anything will +work. see the sysctl.conf(5) man page for details of the format. Index: sbin/rc-service/Makefile =================================================================== --- /dev/null +++ sbin/rc-service/Makefile @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= rc-service + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= rc-service.c \ + rc-misc.c \ + _usage.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 +MAN= ${.CURDIR}/../../contrib/openrc/man/rc-service.8 \ + ${.CURDIR}/../../contrib/openrc/man/service.8 + +LIBADD= einfo rc util + +.include Index: sbin/rc-service/Makefile.depend =================================================================== --- /dev/null +++ sbin/rc-service/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/librc \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: sbin/rc-update/Makefile =================================================================== --- /dev/null +++ sbin/rc-update/Makefile @@ -0,0 +1,26 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= rc-update + +.include + +ORSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${ORSRC}/rc + +SRCS= rc-update.c \ + rc-misc.c \ + _usage.c +CFLAGS+= -I${ORSRC}/rc \ + -I${ORSRC}/libeinfo \ + -I${ORSRC}/librc \ + -I${.OBJDIR}/../../lib/librc/contrib/openrc/src/librc \ + -I${ORSRC}/includes + +WARNS?= 3 +MAN= ${.CURDIR}/../../contrib/openrc/man/rc-update.8 + +LIBADD= einfo rc util + +.include Index: sbin/rc-update/Makefile.depend =================================================================== --- /dev/null +++ sbin/rc-update/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/librc \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: sbin/start-stop-daemon/Makefile =================================================================== --- /dev/null +++ sbin/start-stop-daemon/Makefile @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= start-stop-daemon + +.include + +SDSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${SDSRC}/rc + +SRCS= start-stop-daemon.c \ + rc-misc.c \ + rc-schedules.c \ + _usage.c +CFLAGS+= -I${SDSRC}/rc \ + -I${SDSRC}/libeinfo \ + -I${SDSRC}/librc \ + -I${.OBJDIR}/../../lib/librc/contrib/openrc/src/librc \ + -I${SDSRC}/includes + +WARNS?= 3 +MAN= ${.CURDIR}/../../contrib/openrc/man/start-stop-daemon.8 + +LIBADD= einfo rc util + +.include Index: sbin/start-stop-daemon/Makefile.depend =================================================================== --- /dev/null +++ sbin/start-stop-daemon/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/librc \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: sbin/supervise-daemon/Makefile =================================================================== --- /dev/null +++ sbin/supervise-daemon/Makefile @@ -0,0 +1,27 @@ +# $FreeBSD$ + +PACKAGE=runtime +PROG= supervise-daemon + +.include + +SDSRC= ${SRCTOP}/contrib/openrc/src + +.PATH: ${SDSRC}/rc + +SRCS= supervise-daemon.c \ + rc-misc.c \ + rc-schedules.c \ + _usage.c +CFLAGS+= -I${SDSRC}/rc \ + -I${SDSRC}/libeinfo \ + -I${SDSRC}/librc \ + -I${.OBJDIR}/../../lib/librc/contrib/openrc/src/librc \ + -I${SDSRC}/includes + +WARNS?= 3 +MAN= ${.CURDIR}/../../contrib/openrc/man/supervise-daemon.8 + +LIBADD= einfo rc util + +.include Index: sbin/supervise-daemon/Makefile.depend =================================================================== --- /dev/null +++ sbin/supervise-daemon/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + lib/libeinfo \ + lib/librc \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif Index: share/mk/bsd.libnames.mk =================================================================== --- share/mk/bsd.libnames.mk +++ share/mk/bsd.libnames.mk @@ -58,6 +58,7 @@ LIBDWARF?= ${LIBDESTDIR}${LIBDIR_BASE}/libdwarf.a LIBEDIT?= ${LIBDESTDIR}${LIBDIR_BASE}/libedit.a LIBEFIVAR?= ${LIBDESTDIR}${LIBDIR_BASE}/libefivar.a +LIBEINFO?= ${LIBDESTDIR}${LIBDIR_BASE}/libeinfo.a LIBELF?= ${LIBDESTDIR}${LIBDIR_BASE}/libelf.a LIBEXECINFO?= ${LIBDESTDIR}${LIBDIR_BASE}/libexecinfo.a LIBFETCH?= ${LIBDESTDIR}${LIBDIR_BASE}/libfetch.a @@ -130,6 +131,7 @@ LIBRDMACM?= ${LIBDESTDIR}${LIBDIR_BASE}/librdmacm.a LIBREGEX?= ${LIBDESTDIR}${LIBDIR_BASE}/libregex.a LIBROKEN?= ${LIBDESTDIR}${LIBDIR_BASE}/libroken.a +LIBRC?= ${LIBDESTDIR}${LIBDIR_BASE}/librc.a LIBRPCSEC_GSS?= ${LIBDESTDIR}${LIBDIR_BASE}/librpcsec_gss.a LIBRPCSVC?= ${LIBDESTDIR}${LIBDIR_BASE}/librpcsvc.a LIBRT?= ${LIBDESTDIR}${LIBDIR_BASE}/librt.a Index: share/mk/src.libnames.mk =================================================================== --- share/mk/src.libnames.mk +++ share/mk/src.libnames.mk @@ -98,6 +98,7 @@ dtrace \ dwarf \ edit \ + einfo \ efivar \ elf \ execinfo \ @@ -151,6 +152,7 @@ procstat \ pthread \ radius \ + rc \ regex \ roken \ rpcsec_gss \ @@ -234,6 +236,7 @@ .if ${MK_OPENSSL} != "no" _DP_bsnmp= crypto .endif +_DP_einfo= kvm _DP_geom= bsdxml sbuf _DP_cam= sbuf _DP_kvm= elf @@ -250,6 +253,7 @@ .endif _DP_pjdlog= util _DP_opie= md +_DP_rc= kvm _DP_usb= pthread _DP_unbound= ssl crypto pthread _DP_rt= pthread @@ -553,6 +557,7 @@ LIBKVMDIR= ${OBJTOP}/lib/libkvm LIBPTHREADDIR= ${OBJTOP}/lib/libthr LIBMDIR= ${OBJTOP}/lib/msun +LIBEINFODIR= ${OBJTOP}/lib/libeinfo LIBFORMDIR= ${OBJTOP}/lib/ncurses/form LIBFORMLIBWDIR= ${OBJTOP}/lib/ncurses/formw LIBMENUDIR= ${OBJTOP}/lib/ncurses/menu @@ -562,6 +567,7 @@ LIBPANELDIR= ${OBJTOP}/lib/ncurses/panel LIBPANELWDIR= ${OBJTOP}/lib/ncurses/panelw LIBCRYPTODIR= ${OBJTOP}/secure/lib/libcrypto +LIBRCDIR= ${OBJTOP}/lib/librc LIBSSHDIR= ${OBJTOP}/secure/lib/libssh LIBSSLDIR= ${OBJTOP}/secure/lib/libssl LIBTEKENDIR= ${OBJTOP}/sys/teken/libteken Index: usr.sbin/service/service.sh =================================================================== --- usr.sbin/service/service.sh +++ usr.sbin/service/service.sh @@ -28,6 +28,12 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. +# Are we using OpenRC instead of RC? +if [ "$(/bin/kenv rc_system 2>/dev/null)" = "openrc" ]; then + /sbin/rc-service ${@} + exit $? +fi + . /etc/rc.subr load_rc_config 'XXX'