Add systemd-openbsd: a joke, a game inspired by ungleich
This commit is contained in:
commit
b0cf4a0124
15 changed files with 3173 additions and 0 deletions
32
LICENSE.md
Normal file
32
LICENSE.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
* The files `init.c`, `init.8`, and `pathnames.h` are licensed as 3-clause-BSD.
|
||||||
|
* The `systemd*.*` files are licensed under the following ISC-style license:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/*
|
||||||
|
* This file is part of the satirical systemd-init for OpenBSD.
|
||||||
|
*
|
||||||
|
* DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
* DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
*
|
||||||
|
* Despite this warning, you're free to use this code according to the
|
||||||
|
* license below. Parts of it might be useful in other places after all.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Reyk Floeter <contact@reykfloeter.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
```
|
3
Makefile
Normal file
3
Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
SUBDIR= init
|
||||||
|
|
||||||
|
.include <bsd.subdir.mk>
|
92
README.md
Normal file
92
README.md
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
systemd-openbsd
|
||||||
|
===============
|
||||||
|
|
||||||
|
See [hack4glarus-2019-summer #6751](https://redmine.ungleich.ch/issues/6751).
|
||||||
|
This stupid little joke evolved into a game. See the DISCLAIMER and
|
||||||
|
rules below.
|
||||||
|
|
||||||
|
`systemd-openbsd` is a [systemd]- style init for [OpenBSD]. It does
|
||||||
|
not support services, no integrated DHCP server and no support for
|
||||||
|
[emacs.service], but it implements the most important features that
|
||||||
|
are commonly expected from Linux' systemd. The goal is to ensure that
|
||||||
|
the system is working continuously and reliably.
|
||||||
|
|
||||||
|
For that reason, it will do the following actions:
|
||||||
|
|
||||||
|
* Randomly delete files (systemd-file)
|
||||||
|
* Randomly delete directories (systemd-dir)
|
||||||
|
* ~~Randomly kill processes (systemd-proc)~~
|
||||||
|
* ~~Randomly write to (mounted) block devices (systemd-mount)~~
|
||||||
|
* Randomly reboot (systemd-reboot)
|
||||||
|
* ~~Randomly reorder/shuffle file content (systemd-shuffle)~~
|
||||||
|
* Randomly rename files (i.e. replace /etc/passwd with /lib/libc.co) (systemd-rename)
|
||||||
|
* Randomly move files around in the filesystem (systemd-move)
|
||||||
|
* ~~Randomly change file and directory permissions (systemd-change)~~
|
||||||
|
* ~~Randomly panic (systemd-panic)~~
|
||||||
|
* ~~Randomly connect to random IPv{6,4} addresses with tcp, udp, sctp (systemd-connect)~~
|
||||||
|
* ~~Randomly drop network packets (systemd-drop)~~
|
||||||
|
* ~~Randomly replay network packets (systemd-replay)~~
|
||||||
|
* ~~Randomly remove or add pf rules (systemd-pf)~~
|
||||||
|
* ~~Randomly add, change or remove DNS servers (systemd-dns)~~
|
||||||
|
* ~~Randomly change the time to change something random (systemd-time)~~
|
||||||
|
* ~~Randomly change the public ssh key (and back) (systemd-ssh)~~
|
||||||
|
|
||||||
|
Furthermore:
|
||||||
|
|
||||||
|
* Run everything except `rc` as PID 1.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
----------
|
||||||
|
|
||||||
|
> DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
> DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
|
||||||
|
Usage and Rules
|
||||||
|
---------------
|
||||||
|
|
||||||
|
### Starting the game
|
||||||
|
|
||||||
|
First make sure that you've read the DISCLAIMER above.
|
||||||
|
Now install `systemd-openbsd` on a dedicated machine:
|
||||||
|
|
||||||
|
1. Check out the code, edit `init/Makefile` and enable the
|
||||||
|
`-DDANGEROUS` flag, and compile it with `make` under OpenBSD.
|
||||||
|
2. Install and configure a new stock OpenBSD machine, preferably a VM.
|
||||||
|
3. Replace the shipped `/sbin/init` with the binary of this init.
|
||||||
|
4. Reboot!
|
||||||
|
|
||||||
|
### Playing the game
|
||||||
|
|
||||||
|
Keep the system running. You can also use it, turn it into a server,
|
||||||
|
but just make sure that you don't accidentally revert `/sbin/init` to
|
||||||
|
the OpenBSD version (e.g. by via `sysupgrade`).
|
||||||
|
|
||||||
|
1. Run the machine and watch the reliability features in action.
|
||||||
|
2. If the system becomes unusable, check `/systemd-score.txt`.
|
||||||
|
|
||||||
|
The system is unusable if there is enough damage that it fails to
|
||||||
|
reboot into multi-user mode.
|
||||||
|
|
||||||
|
### Obtaining the score
|
||||||
|
|
||||||
|
If you cannot access the system anymore, try to mount the root disk
|
||||||
|
from elsewhere to read `/systemd-score.txt`. The goal of the game is
|
||||||
|
to run the system as long as possible and to obtain the highest
|
||||||
|
possible score. You can try to make your personal records, play the
|
||||||
|
game with others, or share your results on Mastodon or Twitter using
|
||||||
|
the `#systemdrocksopenbsd` hash tag.
|
||||||
|
|
||||||
|
### Joker
|
||||||
|
|
||||||
|
You automatically won the game if you've obtained a Joker. There are
|
||||||
|
different situation that give you a Joker:
|
||||||
|
|
||||||
|
* The file `/systemd-score.txt` got corrupted. You won.
|
||||||
|
* The file `/sbin/init` got corrupted. You won.
|
||||||
|
|
||||||
|
|
||||||
|
[systemd]: https://freedesktop.org/wiki/Software/systemd/
|
||||||
|
[OpenBSD]: https://www.openbsd.org/
|
||||||
|
[emacs.service]: https://datko.net/2015/10/08/emacs-systemd-service/
|
||||||
|
|
||||||
|
|
36
init/Makefile
Normal file
36
init/Makefile
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# $OpenBSD: Makefile,v 1.10 2018/01/06 16:26:12 millert Exp $
|
||||||
|
|
||||||
|
PROG= init
|
||||||
|
MAN= init.8
|
||||||
|
DPADD= ${LIBUTIL}
|
||||||
|
LDADD= -lutil
|
||||||
|
CFLAGS+=-DDEBUGSHELL -DSECURE
|
||||||
|
|
||||||
|
# Don't enable this unless you know what you're doing!
|
||||||
|
#CFLAGS+=-DDANGEROUS
|
||||||
|
|
||||||
|
# Set this flag to enable regress tests.
|
||||||
|
#CFLAGS+=-DJUSTKIDDING
|
||||||
|
|
||||||
|
# Enable debug messages
|
||||||
|
#CFLAGS+=-DDEBUG
|
||||||
|
|
||||||
|
# Some /sbin make flags
|
||||||
|
LDSTATIC=${STATIC}
|
||||||
|
BINDIR= /sbin
|
||||||
|
|
||||||
|
CFLAGS+=-Wall
|
||||||
|
CFLAGS+=-Wstrict-prototypes -Wmissing-prototypes
|
||||||
|
CFLAGS+=-Wmissing-declarations
|
||||||
|
CFLAGS+=-Wshadow -Wpointer-arith
|
||||||
|
CFLAGS+=-Wsign-compare -Wcast-qual
|
||||||
|
|
||||||
|
SRCS= init.c
|
||||||
|
SRCS+= systemd.c
|
||||||
|
SRCS+= systemd-file.c
|
||||||
|
SRCS+= systemd-dir.c
|
||||||
|
SRCS+= systemd-reboot.c
|
||||||
|
SRCS+= systemd-move.c
|
||||||
|
SRCS+= systemd-rename.c
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
115
init/NOTES
Normal file
115
init/NOTES
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
$OpenBSD: NOTES,v 1.2 1996/06/23 14:30:49 deraadt Exp $
|
||||||
|
$NetBSD: NOTES,v 1.2 1995/03/18 14:56:29 cgd Exp $
|
||||||
|
|
||||||
|
POSIX and init:
|
||||||
|
--------------
|
||||||
|
|
||||||
|
POSIX.1 does not define 'init' but it mentions it in a few places.
|
||||||
|
|
||||||
|
B.2.2.2, p205 line 873:
|
||||||
|
|
||||||
|
This is part of the extensive 'job control' glossary entry.
|
||||||
|
This specific reference says that 'init' must by default provide
|
||||||
|
protection from job control signals to jobs it starts --
|
||||||
|
it sets SIGTSTP, SIGTTIN and SIGTTOU to SIG_IGN.
|
||||||
|
|
||||||
|
B.2.2.2, p206 line 889:
|
||||||
|
|
||||||
|
Here is a reference to 'vhangup'. It says, 'POSIX.1 does
|
||||||
|
not specify how controlling terminal access is affected by
|
||||||
|
a user logging out (that is, by a controlling process
|
||||||
|
terminating).' vhangup() is recognized as one way to handle
|
||||||
|
the problem. I'm not clear what happens in Reno; I have
|
||||||
|
the impression that when the controlling process terminates,
|
||||||
|
references to the controlling terminal are converted to
|
||||||
|
references to a 'dead' vnode. I don't know whether vhangup()
|
||||||
|
is required.
|
||||||
|
|
||||||
|
B.2.2.2, p206 line 921:
|
||||||
|
|
||||||
|
Orphaned process groups bear indirectly on this issue. A
|
||||||
|
session leader's process group is considered to be orphaned;
|
||||||
|
that is, it's immune to job control signals from the terminal.
|
||||||
|
|
||||||
|
B.2.2.2, p233 line 2055:
|
||||||
|
|
||||||
|
'Historically, the implementation-dependent process that
|
||||||
|
inherits children whose parents have terminated without
|
||||||
|
waiting on them is called "init" and has a process ID of 1.'
|
||||||
|
|
||||||
|
It goes on to note that it used to be the case that 'init'
|
||||||
|
was responsible for sending SIGHUP to the foreground process
|
||||||
|
group of a tty whose controlling process has exited, using
|
||||||
|
vhangup(). It is now the responsibility of the kernel to
|
||||||
|
do this when the controlling process calls _exit(). The
|
||||||
|
kernel is also responsible for sending SIGCONT to stopped
|
||||||
|
process groups that become orphaned. This is like old BSD
|
||||||
|
but entire process groups are signaled instead of individual
|
||||||
|
processes.
|
||||||
|
|
||||||
|
In general it appears that the kernel now automatically
|
||||||
|
takes care of orphans, relieving 'init' of any responsibility.
|
||||||
|
Specifics are listed on the _exit() page (p50).
|
||||||
|
|
||||||
|
On setsid():
|
||||||
|
-----------
|
||||||
|
|
||||||
|
It appears that neither getty nor login call setsid(), so init must
|
||||||
|
do this -- seems reasonable. B.4.3.2 p 248 implies that this is the
|
||||||
|
way that 'init' should work; it says that setsid() should be called
|
||||||
|
after forking.
|
||||||
|
|
||||||
|
Process group leaders cannot call setsid() -- another reason to
|
||||||
|
fork! Of course setsid() causes the current process to become a
|
||||||
|
process group leader, so we can only call setsid() once. Note that
|
||||||
|
the controlling terminal acquires the session leader's process
|
||||||
|
group when opened.
|
||||||
|
|
||||||
|
Controlling terminals:
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
B.7.1.1.3 p276: 'POSIX.1 does not specify a mechanism by which to
|
||||||
|
allocate a controlling terminal. This is normally done by a system
|
||||||
|
utility (such as 'getty') and is considered ... outside the scope
|
||||||
|
of POSIX.1.' It goes on to say that historically the first open()
|
||||||
|
of a tty in a session sets the controlling terminal. P130 has the
|
||||||
|
full details; nothing particularly surprising.
|
||||||
|
|
||||||
|
The glossary p12 describes a 'controlling process' as the first
|
||||||
|
process in a session that acquires a controlling terminal. Access
|
||||||
|
to the terminal from the session is revoked if the controlling
|
||||||
|
process exits (see p50, in the discussion of process termination).
|
||||||
|
|
||||||
|
Design notes:
|
||||||
|
------------
|
||||||
|
|
||||||
|
your generic finite state machine
|
||||||
|
we are fascist about which signals we elect to receive,
|
||||||
|
even signals purportedly generated by hardware
|
||||||
|
handle fatal errors gracefully if possible (we reboot if we goof!!)
|
||||||
|
if we get a segmentation fault etc., print a message on the console
|
||||||
|
and spin for a while before rebooting
|
||||||
|
(this at least decreases the amount of paper consumed :-)
|
||||||
|
apply hysteresis to rapidly exiting gettys
|
||||||
|
check wait status of children we reap
|
||||||
|
don't wait for stopped children
|
||||||
|
don't use SIGCHILD, it's too expensive
|
||||||
|
but it may close windows and avoid races, sigh
|
||||||
|
look for EINTR in case we need to change state
|
||||||
|
init is responsible for utmp and wtmp maintenance (ick)
|
||||||
|
maybe now we can consider replacements? maintain them in parallel
|
||||||
|
init only removes utmp and closes out wtmp entries...
|
||||||
|
|
||||||
|
necessary states and state transitions (gleaned from the man page):
|
||||||
|
1: single user shell (with password checking?); on exit, go to 2
|
||||||
|
2: rc script: on exit 0, go to 3; on exit N (error), go to 1
|
||||||
|
3: read ttys file: on completion, go to 4
|
||||||
|
4: multi-user operation: on SIGTERM, go to 7; on SIGHUP, go to 5;
|
||||||
|
on SIGTSTP, go to 6
|
||||||
|
5: clean up mode (re-read ttys file, killing off controlling processes
|
||||||
|
on lines that are now 'off', starting them on lines newly 'on')
|
||||||
|
on completion, go to 4
|
||||||
|
6: boring mode (no new sessions); signals as in 4
|
||||||
|
7: death: send SIGHUP to all controlling processes, reap for 30 seconds,
|
||||||
|
then go to 1 (warn if not all processes died, i.e. wait blocks)
|
||||||
|
Given the -s flag, we start at state 1; otherwise state 2
|
329
init/init.8
Normal file
329
init/init.8
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
.\" $OpenBSD: init.8,v 1.50 2018/01/16 15:57:51 cheloha Exp $
|
||||||
|
.\" $NetBSD: init.8,v 1.6 1995/03/18 14:56:31 cgd Exp $
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 1980, 1991, 1993
|
||||||
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" This code is derived from software contributed to Berkeley by
|
||||||
|
.\" Donn Seeley at Berkeley Software Design, Inc.
|
||||||
|
.\"
|
||||||
|
.\" 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.
|
||||||
|
.\"
|
||||||
|
.\" @(#)init.8 8.6 (Berkeley) 5/26/95
|
||||||
|
.\"
|
||||||
|
.Dd $Mdocdate: January 16 2018 $
|
||||||
|
.Dt INIT 8
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm init
|
||||||
|
.Nd process control initialization
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm init
|
||||||
|
.Op Fl fs
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
program
|
||||||
|
is the last stage of the boot process.
|
||||||
|
It normally executes the sequence of events described in
|
||||||
|
.Xr rc 8
|
||||||
|
and begins multi-user operation.
|
||||||
|
.Pp
|
||||||
|
The kernel may pass the following options to
|
||||||
|
.Nm ,
|
||||||
|
usually when requested by the
|
||||||
|
.Xr boot 8
|
||||||
|
program:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl f
|
||||||
|
Activate fastboot mode.
|
||||||
|
This is not currently supported by the
|
||||||
|
.Ox
|
||||||
|
kernel.
|
||||||
|
Instead, use the
|
||||||
|
.Pa /fastboot
|
||||||
|
file as explained in the
|
||||||
|
.Xr rc 8
|
||||||
|
manual.
|
||||||
|
.It Fl s
|
||||||
|
Boot directly into single-user mode.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Single-user mode is also entered if the boot scripts fail.
|
||||||
|
.Pp
|
||||||
|
In single-user mode, the
|
||||||
|
.Xr rc 8
|
||||||
|
script is not run and normal daemons are not started,
|
||||||
|
but instead a super-user shell is started on the system console.
|
||||||
|
If the
|
||||||
|
.Ar console
|
||||||
|
entry in the
|
||||||
|
.Xr ttys 5
|
||||||
|
file does not contain the
|
||||||
|
.Dq secure
|
||||||
|
flag, then
|
||||||
|
.Nm
|
||||||
|
will require that the superuser password be
|
||||||
|
entered before the system will start a single-user shell.
|
||||||
|
The password check is skipped if the
|
||||||
|
.Ar console
|
||||||
|
is marked as
|
||||||
|
.Dq secure .
|
||||||
|
.Pp
|
||||||
|
In single-user mode, the system is quiescent for maintenance work and may
|
||||||
|
later be made to go to multi-user by exiting the
|
||||||
|
single-user shell (with ^D).
|
||||||
|
This
|
||||||
|
causes
|
||||||
|
.Nm
|
||||||
|
to run the
|
||||||
|
.Xr rc 8
|
||||||
|
startup command file in fastboot mode (skipping disk checks).
|
||||||
|
.Pp
|
||||||
|
The kernel
|
||||||
|
.Xr securelevel 7
|
||||||
|
is normally set to 0 while in single-user mode, and raised to 1 when
|
||||||
|
the system begins multi-user operations.
|
||||||
|
This action will not take
|
||||||
|
place if the securelevel is \-1, and can be modified via the
|
||||||
|
.Pa /etc/rc.securelevel
|
||||||
|
script.
|
||||||
|
.Pp
|
||||||
|
In multi-user operation,
|
||||||
|
.Nm
|
||||||
|
maintains
|
||||||
|
processes for the terminal ports found in the file
|
||||||
|
.Xr ttys 5 .
|
||||||
|
.Nm
|
||||||
|
reads this file, and executes the command found in the second field.
|
||||||
|
This command is usually
|
||||||
|
.Xr getty 8 ;
|
||||||
|
.Em getty
|
||||||
|
opens and initializes the tty line
|
||||||
|
and
|
||||||
|
executes the
|
||||||
|
.Em login
|
||||||
|
program.
|
||||||
|
The
|
||||||
|
.Em login
|
||||||
|
program, when a valid user logs in,
|
||||||
|
executes a shell for that user.
|
||||||
|
When this shell dies, either because the user logged out
|
||||||
|
or an abnormal termination occurred (a signal),
|
||||||
|
the
|
||||||
|
.Nm
|
||||||
|
program wakes up, deletes the user
|
||||||
|
from the
|
||||||
|
.Xr utmp 5
|
||||||
|
file of current users and records the logout in the
|
||||||
|
.Em wtmp
|
||||||
|
file.
|
||||||
|
The cycle is
|
||||||
|
then restarted by
|
||||||
|
.Nm
|
||||||
|
executing a new
|
||||||
|
.Em getty
|
||||||
|
for the line.
|
||||||
|
.Pp
|
||||||
|
Line status (on, off, secure, getty, or window information)
|
||||||
|
may be changed in the
|
||||||
|
.Em ttys
|
||||||
|
file without a reboot by sending the signal
|
||||||
|
.Dv SIGHUP
|
||||||
|
to
|
||||||
|
.Nm
|
||||||
|
with the command
|
||||||
|
.Dq Li "kill \-s HUP 1" .
|
||||||
|
On receipt of this signal,
|
||||||
|
.Nm
|
||||||
|
re-reads the
|
||||||
|
.Em ttys
|
||||||
|
file.
|
||||||
|
When a line is turned off in
|
||||||
|
.Em ttys ,
|
||||||
|
.Nm
|
||||||
|
will send a
|
||||||
|
.Dv SIGHUP
|
||||||
|
signal to the controlling process
|
||||||
|
for the session associated with the line.
|
||||||
|
For any lines that were previously turned off in the
|
||||||
|
.Em ttys
|
||||||
|
file and are now on,
|
||||||
|
.Nm
|
||||||
|
executes a new
|
||||||
|
.Em getty
|
||||||
|
to enable a new login.
|
||||||
|
If the getty or window field for a line is changed,
|
||||||
|
the change takes effect at the end of the current
|
||||||
|
login session (e.g., the next time
|
||||||
|
.Nm
|
||||||
|
starts a process on the line).
|
||||||
|
If a line is commented out or deleted from
|
||||||
|
.Em ttys ,
|
||||||
|
.Nm
|
||||||
|
will not do anything at all to that line.
|
||||||
|
However, it will complain that the relationship between lines
|
||||||
|
in the
|
||||||
|
.Em ttys
|
||||||
|
file and records in the
|
||||||
|
.Em utmp
|
||||||
|
file is out of sync,
|
||||||
|
so this practice is not recommended.
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
will terminate multi-user operations and resume single-user mode
|
||||||
|
if sent a terminate
|
||||||
|
.Pq Dv TERM
|
||||||
|
signal, for example,
|
||||||
|
.Dq Li "kill \-s TERM 1" .
|
||||||
|
If there are processes outstanding that are deadlocked (because of
|
||||||
|
hardware or software failure),
|
||||||
|
.Nm
|
||||||
|
will not wait for them all to die (which might take forever), but
|
||||||
|
will time out after 30 seconds and print a warning message.
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
will cease creating new
|
||||||
|
.Xr getty 8
|
||||||
|
and allow the system to slowly die away, if it is sent a terminal stop
|
||||||
|
.Pq Dv TSTP
|
||||||
|
signal, i.e.,
|
||||||
|
.Dq Li "kill \-s TSTP 1" .
|
||||||
|
A later hangup will resume full
|
||||||
|
multi-user operations, or a terminate will start a single-user shell.
|
||||||
|
This hook is used by
|
||||||
|
.Xr reboot 8
|
||||||
|
and
|
||||||
|
.Xr halt 8 .
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
will terminate multi-user operations, kill all
|
||||||
|
.Xr getty 8 ,
|
||||||
|
and run
|
||||||
|
.Pa /etc/rc.shutdown
|
||||||
|
if a user-defined signal 1
|
||||||
|
.Pq Dv USR1 ,
|
||||||
|
user-defined signal 2
|
||||||
|
.Pq Dv USR2 ,
|
||||||
|
or interrupt
|
||||||
|
.Pq Dv INT
|
||||||
|
signal is received.
|
||||||
|
Following this,
|
||||||
|
.Dv USR1
|
||||||
|
will halt the system;
|
||||||
|
.Dv USR2
|
||||||
|
will request a powerdown; and
|
||||||
|
.Dv INT
|
||||||
|
will cause a reboot.
|
||||||
|
.Pa /etc/rc.shutdown
|
||||||
|
can specify that a powerdown is requested instead of the action
|
||||||
|
specified by the signal.
|
||||||
|
.Pp
|
||||||
|
The role of
|
||||||
|
.Nm
|
||||||
|
is so critical that if it dies, the system will reboot itself
|
||||||
|
automatically.
|
||||||
|
If, at bootstrap time, the
|
||||||
|
.Nm
|
||||||
|
process cannot be located, the system will panic with the message
|
||||||
|
.Dq panic: "init died (signal %d, exit %d)" .
|
||||||
|
.Sh RESOURCES
|
||||||
|
When
|
||||||
|
.Nm
|
||||||
|
spawns a process it sets the process priority, umask, and resource
|
||||||
|
limits based on
|
||||||
|
.Pa /etc/login.conf .
|
||||||
|
When starting the
|
||||||
|
.Xr rc 8
|
||||||
|
files, the login class
|
||||||
|
.Dq daemon
|
||||||
|
is used.
|
||||||
|
When starting a window system or
|
||||||
|
.Xr getty 8 ,
|
||||||
|
the login class
|
||||||
|
.Dq default
|
||||||
|
is used.
|
||||||
|
No resource changes are made when entering single-user mode.
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width /etc/rc.securelevel -compact
|
||||||
|
.It Pa /dev/console
|
||||||
|
system console device
|
||||||
|
.It Pa /dev/tty*
|
||||||
|
terminal ports found in
|
||||||
|
.Em ttys
|
||||||
|
.It Pa /etc/rc
|
||||||
|
system startup commands
|
||||||
|
.It Pa /etc/rc.securelevel
|
||||||
|
commands that run before the security level changes
|
||||||
|
.It Pa /etc/rc.shutdown
|
||||||
|
script run at shutdown time
|
||||||
|
.It Pa /etc/ttys
|
||||||
|
terminal initialization information file
|
||||||
|
.It Pa /fastboot
|
||||||
|
tells
|
||||||
|
.Xr rc 8
|
||||||
|
not to run
|
||||||
|
.Xr fsck 8
|
||||||
|
during the next boot
|
||||||
|
.It Pa /var/run/utmp
|
||||||
|
record of users currently logged in
|
||||||
|
.It Pa /var/log/wtmp
|
||||||
|
record of all logins and logouts
|
||||||
|
.El
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
.Bl -diag
|
||||||
|
.It "getty repeating too quickly on port %s, sleeping"
|
||||||
|
A process being started to service a line is exiting quickly
|
||||||
|
each time it is started.
|
||||||
|
This is often caused by a ringing or noisy terminal line.
|
||||||
|
.Em "Init will sleep for 30 seconds" ,
|
||||||
|
.Em "then continue trying to start the process" .
|
||||||
|
.It "some processes would not die; ps axl advised."
|
||||||
|
A process
|
||||||
|
is hung and could not be killed when the system was shutting down.
|
||||||
|
This condition is usually caused by a process
|
||||||
|
that is stuck in a device driver because of
|
||||||
|
a persistent device error condition.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr kill 1 ,
|
||||||
|
.Xr login 1 ,
|
||||||
|
.Xr sh 1 ,
|
||||||
|
.Xr fbtab 5 ,
|
||||||
|
.Xr login.conf 5 ,
|
||||||
|
.Xr ttys 5 ,
|
||||||
|
.Xr securelevel 7 ,
|
||||||
|
.Xr crash 8 ,
|
||||||
|
.Xr getty 8 ,
|
||||||
|
.Xr halt 8 ,
|
||||||
|
.Xr rc 8 ,
|
||||||
|
.Xr rc.shutdown 8 ,
|
||||||
|
.Xr reboot 8 ,
|
||||||
|
.Xr shutdown 8
|
||||||
|
.Sh HISTORY
|
||||||
|
An
|
||||||
|
.Nm
|
||||||
|
command appeared in
|
||||||
|
.At v1 .
|
1448
init/init.c
Normal file
1448
init/init.c
Normal file
File diff suppressed because it is too large
Load diff
40
init/pathnames.h
Normal file
40
init/pathnames.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* $OpenBSD: pathnames.h,v 1.4 2003/06/02 20:06:15 millert Exp $ */
|
||||||
|
/* $NetBSD: pathnames.h,v 1.5 1995/03/18 14:56:35 cgd Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1991, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to Berkeley by
|
||||||
|
* Donn Seeley at Berkeley Software Design, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @(#)pathnames.h 8.1 (Berkeley) 6/5/93
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
|
#define _PATH_RUNCOM "/etc/rc"
|
47
init/systemd-dir.c
Normal file
47
init/systemd-dir.c
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the satirical systemd-init for OpenBSD.
|
||||||
|
*
|
||||||
|
* DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
* DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
*
|
||||||
|
* Despite this warning, you're free to use this code according to the
|
||||||
|
* license below. Parts of it might be useful in other places after all.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Reyk Floeter <contact@reykfloeter.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
systemd_dir(void (**cb)(void))
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
if (syslib_randomdir(path) != 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
syslib_log("dir %s", path);
|
||||||
|
|
||||||
|
/* Recursively remove the directory. */
|
||||||
|
if (syslib_rmtree(path) != 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
50
init/systemd-file.c
Normal file
50
init/systemd-file.c
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the satirical systemd-init for OpenBSD.
|
||||||
|
*
|
||||||
|
* DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
* DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
*
|
||||||
|
* Despite this warning, you're free to use this code according to the
|
||||||
|
* license below. Parts of it might be useful in other places after all.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Reyk Floeter <contact@reykfloeter.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
systemd_file(void (**cb)(void))
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
if (syslib_randomfile(path) != 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
syslib_log("file %s", path);
|
||||||
|
|
||||||
|
if (syslib_dangerous()) {
|
||||||
|
/* Remove the file */
|
||||||
|
if (unlink(path) == -1)
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
60
init/systemd-move.c
Normal file
60
init/systemd-move.c
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the satirical systemd-init for OpenBSD.
|
||||||
|
*
|
||||||
|
* DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
* DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
*
|
||||||
|
* Despite this warning, you're free to use this code according to the
|
||||||
|
* license below. Parts of it might be useful in other places after all.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Reyk Floeter <contact@reykfloeter.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
systemd_move(void (**cb)(void))
|
||||||
|
{
|
||||||
|
char dir[PATH_MAX], *dp;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
if (syslib_randomfile(path) != 0 ||
|
||||||
|
syslib_randomdir(dir) != 0 ||
|
||||||
|
(dp = dirname(path)) == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
if (strcmp(dir, dp) == 0) {
|
||||||
|
syslib_log("move %s skipped", path);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslib_log("move %s to %s", path, dir);
|
||||||
|
|
||||||
|
if (syslib_dangerous()) {
|
||||||
|
/* Move the file */
|
||||||
|
if (syslib_exec("mv", "-f", path, dir, NULL) != 0)
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
60
init/systemd-reboot.c
Normal file
60
init/systemd-reboot.c
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the satirical systemd-init for OpenBSD.
|
||||||
|
*
|
||||||
|
* DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
* DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
*
|
||||||
|
* Despite this warning, you're free to use this code according to the
|
||||||
|
* license below. Parts of it might be useful in other places after all.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Reyk Floeter <contact@reykfloeter.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
systemd_doreboot(void)
|
||||||
|
{
|
||||||
|
int sync;
|
||||||
|
|
||||||
|
sync = arc4random_uniform(2) ? RB_NOSYNC : 0;
|
||||||
|
syslib_log("reboot %s", sync ? "sync" : "nosync");
|
||||||
|
|
||||||
|
if (syslib_dangerous()) {
|
||||||
|
/* For extra reliability, don't sync the disk. */
|
||||||
|
(void)reboot(sync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
systemd_reboot(void (**cb)(void))
|
||||||
|
{
|
||||||
|
/* Decrease the chance that we're actually rebooting. */
|
||||||
|
if (arc4random_uniform(3) == 0)
|
||||||
|
*cb = systemd_doreboot;
|
||||||
|
else {
|
||||||
|
syslib_log("reboot skipped");
|
||||||
|
*cb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "1" means success but not actually executed. */
|
||||||
|
return (*cb == NULL ? 1 : 0);
|
||||||
|
}
|
68
init/systemd-rename.c
Normal file
68
init/systemd-rename.c
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the satirical systemd-init for OpenBSD.
|
||||||
|
*
|
||||||
|
* DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
* DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
*
|
||||||
|
* Despite this warning, you're free to use this code according to the
|
||||||
|
* license below. Parts of it might be useful in other places after all.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Reyk Floeter <contact@reykfloeter.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
systemd_rename(void (**cb)(void))
|
||||||
|
{
|
||||||
|
char file1[PATH_MAX];
|
||||||
|
char file2[PATH_MAX];
|
||||||
|
char file3[PATH_MAX];
|
||||||
|
|
||||||
|
if (syslib_randomfile(file1) != 0 ||
|
||||||
|
syslib_randomfile(file2) != 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
if (strcmp(file1, file2) == 0) {
|
||||||
|
syslib_log("rename %s skipped", file1);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlcpy(file3, file1, sizeof(file3)) >= sizeof(file3) ||
|
||||||
|
strlcat(file3, ".bak", sizeof(file3)) >= sizeof(file3))
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
syslib_log("rename %s and %s", file1, file2);
|
||||||
|
|
||||||
|
if (syslib_dangerous()) {
|
||||||
|
/* Move the file */
|
||||||
|
if (syslib_exec("mv", "-f", file1, file3, NULL) != 0)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/* Ignore subsequent errors as we already moved something ;) */
|
||||||
|
(void)syslib_exec("mv", "-f", file2, file1, NULL);
|
||||||
|
(void)syslib_exec("mv", "-f", file3, file2, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
671
init/systemd.c
Normal file
671
init/systemd.c
Normal file
|
@ -0,0 +1,671 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the satirical systemd-init for OpenBSD.
|
||||||
|
*
|
||||||
|
* DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
* DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
*
|
||||||
|
* Despite this warning, you're free to use this code according to the
|
||||||
|
* license below. Parts of it might be useful in other places after all.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Reyk Floeter <contact@reykfloeter.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <fts.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
|
static int systemd_truncate;
|
||||||
|
static long systemd_score;
|
||||||
|
static struct systemd_plugin plugins[] = SYSTEMD_PLUGINS;
|
||||||
|
static size_t nplugins = (sizeof(plugins) / sizeof(plugins[0]));
|
||||||
|
|
||||||
|
static void __dead
|
||||||
|
syslib_joker(const char *);
|
||||||
|
static long syslib_run(struct systemd_plugin *);
|
||||||
|
|
||||||
|
#ifdef JUSTKIDDING
|
||||||
|
/* Runs all plugins in non-dangerous mode for testing. */
|
||||||
|
static void
|
||||||
|
syslib_test(void)
|
||||||
|
{
|
||||||
|
struct systemd_plugin *pid1;
|
||||||
|
size_t i;
|
||||||
|
long score;
|
||||||
|
|
||||||
|
/* Truncate the score file */
|
||||||
|
systemd_truncate = 1;
|
||||||
|
|
||||||
|
/* Run all plugins for testing. */
|
||||||
|
for (i = 0; i < nplugins; i++) {
|
||||||
|
pid1 = &plugins[i];
|
||||||
|
if ((score = syslib_run(pid1)) == -1)
|
||||||
|
errx(1, "FAILED: %s", pid1->pid1_name);
|
||||||
|
else
|
||||||
|
warnx("SUCCESS: %s (score %ld)",
|
||||||
|
pid1->pid1_name, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void __dead
|
||||||
|
syslib_joker(const char *reason)
|
||||||
|
{
|
||||||
|
(void)unlink(SYSTEMD_SCORE);
|
||||||
|
if (reason == NULL)
|
||||||
|
reason = "fatal";
|
||||||
|
err(1, "%s", reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
syslib_run(struct systemd_plugin *pid1)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
struct timespec tv;
|
||||||
|
int fd = -1, i;
|
||||||
|
long score = 0;
|
||||||
|
sigset_t set, oset;
|
||||||
|
const char *errstr = NULL;
|
||||||
|
int flags;
|
||||||
|
void (*cb)(void) = NULL;
|
||||||
|
|
||||||
|
/* Block all signals. This is not nice but "WE ARE SYSTEMD". */
|
||||||
|
sigemptyset(&set);
|
||||||
|
for (i = 0; i < NSIG; i++)
|
||||||
|
sigaddset(&set, i);
|
||||||
|
sigprocmask(SIG_BLOCK, &set, &oset);
|
||||||
|
|
||||||
|
if (clock_gettime(CLOCK_UPTIME, &tv) == -1) {
|
||||||
|
errstr = "CLOCK_UPTIME";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (systemd_truncate) {
|
||||||
|
flags = O_RDWR|O_CREAT|O_TRUNC;
|
||||||
|
systemd_truncate = 0;
|
||||||
|
} else
|
||||||
|
flags = O_RDWR|O_CREAT;
|
||||||
|
|
||||||
|
/* Open the score file before we run the service. */
|
||||||
|
if ((fd = open(SYSTEMD_SCORE, flags)) != -1 &&
|
||||||
|
read(fd, buf, sizeof(buf)) > 0) {
|
||||||
|
if (lseek(fd, 0, SEEK_SET) == -1) {
|
||||||
|
errstr = "seek score";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
buf[strcspn(buf, "\n")] = '\0';
|
||||||
|
/* Read the previous score (it will be zero on error) */
|
||||||
|
systemd_score = score = strtonum(buf, 0, LONG_MAX, &errstr);
|
||||||
|
errstr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Engage! */
|
||||||
|
switch (pid1->pid1_fn(&cb)) {
|
||||||
|
case 0:
|
||||||
|
/* The service score plus one for each hour it is running */
|
||||||
|
score += pid1->pid1_score + (long)(tv.tv_sec / 60);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The score file might not be accessible if the filesystem
|
||||||
|
* is mounted read-only. Ignore the error.
|
||||||
|
*/
|
||||||
|
if (fd != -1 &&
|
||||||
|
dprintf(fd, "%ld\nsystemd/%u\n", score, SYSTEMD_REV) < 0) {
|
||||||
|
errstr = "lost score";
|
||||||
|
close(fd);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
systemd_score = score;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
score = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd != -1) {
|
||||||
|
/* We really try hard to write the score to disk. */
|
||||||
|
fsync(fd);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||||
|
|
||||||
|
/* The service might have returned a callback. */
|
||||||
|
if (cb != NULL)
|
||||||
|
cb();
|
||||||
|
|
||||||
|
return (score);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||||
|
|
||||||
|
/* This fatal error should not happen. But you won! */
|
||||||
|
syslib_joker(errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
syslib_init(void)
|
||||||
|
{
|
||||||
|
#ifdef JUSTKIDDING
|
||||||
|
syslib_test();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We could randomly fail here. */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
syslib_dangerous(void)
|
||||||
|
{
|
||||||
|
#ifdef DANGEROUS
|
||||||
|
/* Use with care! */
|
||||||
|
return (1);
|
||||||
|
#else
|
||||||
|
return (0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
syslib_watch(void)
|
||||||
|
{
|
||||||
|
struct systemd_plugin *pid1;
|
||||||
|
static int init = 0;
|
||||||
|
int seconds = 0;
|
||||||
|
size_t service;
|
||||||
|
long score;
|
||||||
|
|
||||||
|
if (!init)
|
||||||
|
init = 1;
|
||||||
|
else {
|
||||||
|
/* Randomly select a service. */
|
||||||
|
service = arc4random_uniform(nplugins);
|
||||||
|
pid1 = &plugins[service];
|
||||||
|
|
||||||
|
if ((score = syslib_run(pid1)) == -1)
|
||||||
|
syslib_log("failed to run %s", pid1->pid1_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
seconds = arc4random_uniform(SYSTEMD_WATCH) + 1;
|
||||||
|
|
||||||
|
DPRINTF("%s: waiting %d seconds", __func__, seconds);
|
||||||
|
|
||||||
|
/* Schedule next SIGALRM */
|
||||||
|
alarm(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
syslib_log(char *message, ...)
|
||||||
|
{
|
||||||
|
char *nmessage = NULL;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (asprintf(&nmessage, "systemd/%u (score %ld): %s",
|
||||||
|
SYSTEMD_REV, systemd_score, message) == -1)
|
||||||
|
nmessage = NULL;
|
||||||
|
else
|
||||||
|
message = nmessage;
|
||||||
|
|
||||||
|
va_start(ap, message);
|
||||||
|
#ifdef JUSTKIDDING
|
||||||
|
vwarnx(message, ap);
|
||||||
|
#else
|
||||||
|
vsyslog(LOG_INFO, message, ap);
|
||||||
|
#endif
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
free(nmessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
syslib_randomfile(char path[PATH_MAX])
|
||||||
|
{
|
||||||
|
char pbuf[PATH_MAX];
|
||||||
|
DIR *dirp;
|
||||||
|
struct dirent *dp;
|
||||||
|
long count, choice, files;
|
||||||
|
int panic = 0;
|
||||||
|
|
||||||
|
top:
|
||||||
|
/* Start in the system root directory */
|
||||||
|
(void)strlcpy(path, "/", PATH_MAX);
|
||||||
|
|
||||||
|
next:
|
||||||
|
dirp = NULL;
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
if (realpath(path, pbuf) == NULL ||
|
||||||
|
strlcpy(path, pbuf, PATH_MAX) >= PATH_MAX) {
|
||||||
|
DPRINTF("realpath \"%s\"", path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chdir(path) == -1) {
|
||||||
|
DPRINTF("chdir \"%s\"", path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dirp = opendir(".")) == NULL) {
|
||||||
|
DPRINTF("opendir \".\"");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (count = 0; (dp = readdir(dirp)) != NULL; count++)
|
||||||
|
;
|
||||||
|
rewinddir(dirp);
|
||||||
|
|
||||||
|
/* We would spin endlessly in an empty root directory */
|
||||||
|
if ((strcmp("/", path) == 0 && count <= 2) || panic++ >= INT_MAX) {
|
||||||
|
DPRINTF("not possible to find a file");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Randomly select a directory entry. This might cause a TOCTOU
|
||||||
|
* error but it is fast and this is all we care about in systemd :p
|
||||||
|
*/
|
||||||
|
choice = arc4random_uniform(count);
|
||||||
|
|
||||||
|
for (count = files = 0; (dp = readdir(dirp)) != NULL; count++) {
|
||||||
|
if (choice != count)
|
||||||
|
continue;
|
||||||
|
if (dp->d_type == DT_UNKNOWN) {
|
||||||
|
/* Randomly fail */
|
||||||
|
DPRINTF("unknown file %s", dp->d_name);
|
||||||
|
goto fail;
|
||||||
|
} else if (dp->d_type == DT_DIR) {
|
||||||
|
goto nextdir;
|
||||||
|
} else {
|
||||||
|
/* Everything else is some kind of a file */
|
||||||
|
if ((strcmp("/", path) != 0 &&
|
||||||
|
strlcat(path, "/", PATH_MAX) >= PATH_MAX) ||
|
||||||
|
strlcat(path, dp->d_name, PATH_MAX) >= PATH_MAX)
|
||||||
|
DPRINTF("path too long: %s", path);
|
||||||
|
closedir(dirp);
|
||||||
|
|
||||||
|
if (panic == 1)
|
||||||
|
/* Decrease the chance to select a file under / */
|
||||||
|
goto top;
|
||||||
|
else if (strcmp(SYSTEMD_SCORE, path) == 0)
|
||||||
|
/* This file is protected, try another file. */
|
||||||
|
goto top;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextdir:
|
||||||
|
if (strlcat(path, "/", PATH_MAX) >= PATH_MAX ||
|
||||||
|
strlcat(path, dp->d_name, PATH_MAX) >= PATH_MAX)
|
||||||
|
errx(1, "path too long: %s", path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dive into the next directory by calling this function again.
|
||||||
|
* We go to top as a recursive call would blow our stack.
|
||||||
|
*/
|
||||||
|
closedir(dirp);
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (errno == 0)
|
||||||
|
errno = EINVAL;
|
||||||
|
if (dirp != NULL)
|
||||||
|
closedir(dirp);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
syslib_randomdir(char path[PATH_MAX])
|
||||||
|
{
|
||||||
|
char pbuf[PATH_MAX];
|
||||||
|
DIR *dirp;
|
||||||
|
struct dirent *dp;
|
||||||
|
long count, choice, files;
|
||||||
|
int panic = 0, i, dice;
|
||||||
|
|
||||||
|
/* Start in the system root directory */
|
||||||
|
(void)strlcpy(path, "/", PATH_MAX);
|
||||||
|
|
||||||
|
next:
|
||||||
|
dirp = NULL;
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
if (realpath(path, pbuf) == NULL ||
|
||||||
|
strlcpy(path, pbuf, PATH_MAX) >= PATH_MAX) {
|
||||||
|
DPRINTF("realpath \"%s\"", path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chdir(path) == -1) {
|
||||||
|
DPRINTF("chdir \"%s\"", path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dirp = opendir(".")) == NULL) {
|
||||||
|
DPRINTF("opendir \".\"");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (count = 0; (dp = readdir(dirp)) != NULL;) {
|
||||||
|
if (dp->d_type != DT_DIR)
|
||||||
|
continue;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
rewinddir(dirp);
|
||||||
|
|
||||||
|
/* We would spin endlessly in an empty root directory */
|
||||||
|
if ((strcmp("/", path) == 0 && count <= 2) || panic++ >= INT_MAX) {
|
||||||
|
DPRINTF("not possible to find a directory");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Randomly select a directory entry. This might cause a TOCTOU
|
||||||
|
* error but it is fast and this is all we care about in systemd :p
|
||||||
|
*/
|
||||||
|
choice = arc4random_uniform(count);
|
||||||
|
|
||||||
|
for (count = files = 0; (dp = readdir(dirp)) != NULL;) {
|
||||||
|
if (dp->d_type != DT_DIR)
|
||||||
|
continue;
|
||||||
|
if (choice != count++)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((size_t)snprintf(pbuf, sizeof(pbuf), "%s/%s", path,
|
||||||
|
dp->d_name) >= PATH_MAX ||
|
||||||
|
realpath(pbuf, path) == NULL) {
|
||||||
|
DPRINTF("realpath \"%s\"", path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
closedir(dirp);
|
||||||
|
|
||||||
|
/* Increase the probability for deeper directories */
|
||||||
|
for (dice = 1200, i = 0; path[i] != '\0'; i++) {
|
||||||
|
if (path[i] != '/')
|
||||||
|
continue;
|
||||||
|
dice -= 200;
|
||||||
|
if (dice < 0) {
|
||||||
|
dice = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now roll a dice */
|
||||||
|
if ((int)arc4random_uniform(dice) == 0)
|
||||||
|
return (0);
|
||||||
|
else
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (errno == 0)
|
||||||
|
errno = EINVAL;
|
||||||
|
if (dirp != NULL)
|
||||||
|
closedir(dirp);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
syslib_rmtree(char *dir)
|
||||||
|
{
|
||||||
|
char *argv[2];
|
||||||
|
FTS *fts;
|
||||||
|
FTSENT *p;
|
||||||
|
|
||||||
|
argv[0] = dir;
|
||||||
|
argv[1] = NULL;
|
||||||
|
|
||||||
|
if (!(fts = fts_open(argv, FTS_PHYSICAL|FTS_NOSTAT, NULL))) {
|
||||||
|
DPRINTF("failed to open directory");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
while ((p = fts_read(fts)) != NULL) {
|
||||||
|
switch (p->fts_info) {
|
||||||
|
case FTS_ERR:
|
||||||
|
syslib_log("dir: rmtree %s error", p->fts_path);
|
||||||
|
case FTS_DNR:
|
||||||
|
case FTS_NS:
|
||||||
|
case FTS_D:
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (p->fts_info) {
|
||||||
|
case FTS_DP:
|
||||||
|
case FTS_DNR:
|
||||||
|
DPRINTF("dir rmdir %s", p->fts_path);
|
||||||
|
if (syslib_dangerous()) {
|
||||||
|
if (!rmdir(p->fts_accpath) || errno == ENOENT)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DPRINTF("dir unlink %s", p->fts_path);
|
||||||
|
if (syslib_dangerous()) {
|
||||||
|
if (strcmp(SYSTEMD_SCORE, p->fts_path) == 0 ||
|
||||||
|
!unlink(p->fts_accpath) || errno == ENOENT)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errno)
|
||||||
|
DPRINTF("fts_read");
|
||||||
|
fts_close(fts);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
syslib_exec(const char *arg, ...)
|
||||||
|
{
|
||||||
|
const char **argv, *a;
|
||||||
|
int argc, i = 0, status;
|
||||||
|
va_list ap;
|
||||||
|
pid_t pid, child_pid;
|
||||||
|
struct sigaction sigint, sigquit;
|
||||||
|
sigset_t mask, omask;
|
||||||
|
|
||||||
|
/* create arguments */
|
||||||
|
va_start(ap, arg);
|
||||||
|
for (argc = 2; va_arg(ap, const char *) != NULL; argc++)
|
||||||
|
;
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if ((argv = calloc(argc, sizeof(const char *))) == NULL) {
|
||||||
|
DPRINTF("calloc");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
argv[i++] = arg;
|
||||||
|
|
||||||
|
va_start(ap, arg);
|
||||||
|
while ((a = va_arg(ap, char *)) != NULL)
|
||||||
|
argv[i++] = a;
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGCHLD);
|
||||||
|
sigprocmask(SIG_BLOCK, &mask, &omask);
|
||||||
|
|
||||||
|
/* run command in forked process */
|
||||||
|
switch (child_pid = fork()) {
|
||||||
|
case -1:
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
free(argv);
|
||||||
|
return (-1);
|
||||||
|
case 0:
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
setenv("PATH", _PATH_STDPATH, 1);
|
||||||
|
execvp(argv[0], (char *const *)(caddr_t)argv);
|
||||||
|
_exit(127);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(argv);
|
||||||
|
sigaction(SIGINT, NULL, &sigint);
|
||||||
|
sigaction(SIGQUIT, NULL, &sigquit);
|
||||||
|
|
||||||
|
do {
|
||||||
|
pid = waitpid(child_pid, &status, 0);
|
||||||
|
} while (pid == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
sigaction(SIGINT, &sigint, NULL);
|
||||||
|
sigaction(SIGQUIT, &sigquit, NULL);
|
||||||
|
|
||||||
|
/* Simplified return value: returns 0 on success and -1 on error */
|
||||||
|
if (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
syslib_pexec(const char *in, char **out, const char *arg, ...)
|
||||||
|
{
|
||||||
|
const char **argv = NULL, *a;
|
||||||
|
int argc, i = 0, status;
|
||||||
|
va_list ap;
|
||||||
|
pid_t pid, child_pid;
|
||||||
|
struct sigaction sigint, sigquit;
|
||||||
|
sigset_t mask, omask;
|
||||||
|
FILE *outfp = NULL, *fp = NULL;
|
||||||
|
char *outbuf;
|
||||||
|
size_t outbufsz;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
int fdi[2], fdo[2];
|
||||||
|
|
||||||
|
if (out)
|
||||||
|
*out = NULL;
|
||||||
|
|
||||||
|
/* create arguments */
|
||||||
|
va_start(ap, arg);
|
||||||
|
for (argc = 2; va_arg(ap, const char *) != NULL; argc++)
|
||||||
|
;
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if ((argv = calloc(argc, sizeof(const char *))) == NULL) {
|
||||||
|
DPRINTF("calloc");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
argv[i++] = arg;
|
||||||
|
|
||||||
|
va_start(ap, arg);
|
||||||
|
while ((a = va_arg(ap, char *)) != NULL)
|
||||||
|
argv[i++] = a;
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (in && socketpair(AF_UNIX,
|
||||||
|
SOCK_STREAM|SOCK_CLOEXEC, AF_UNSPEC, fdi) == -1)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (out && socketpair(AF_UNIX,
|
||||||
|
SOCK_STREAM|SOCK_CLOEXEC, AF_UNSPEC, fdo) == -1)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGCHLD);
|
||||||
|
sigprocmask(SIG_BLOCK, &mask, &omask);
|
||||||
|
|
||||||
|
/* run command in forked process */
|
||||||
|
switch (child_pid = fork()) {
|
||||||
|
case -1:
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
goto fail;
|
||||||
|
case 0:
|
||||||
|
if (in) {
|
||||||
|
close(fdi[1]);
|
||||||
|
if (dup2(fdi[0], STDIN_FILENO) == -1)
|
||||||
|
_exit(127);
|
||||||
|
}
|
||||||
|
if (out) {
|
||||||
|
close(fdo[1]);
|
||||||
|
if (dup2(fdo[0], STDOUT_FILENO) == -1)
|
||||||
|
_exit(127);
|
||||||
|
}
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
setenv("PATH", _PATH_STDPATH, 1);
|
||||||
|
execvp(argv[0], (char *const *)(caddr_t)argv);
|
||||||
|
_exit(127);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(argv);
|
||||||
|
argv = NULL;
|
||||||
|
sigaction(SIGINT, NULL, &sigint);
|
||||||
|
sigaction(SIGQUIT, NULL, &sigquit);
|
||||||
|
|
||||||
|
if (in) {
|
||||||
|
close(fdi[0]);
|
||||||
|
if ((fp = fdopen(fdi[1], "w")) != NULL) {
|
||||||
|
fputs(in, fp);
|
||||||
|
fflush(fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
close(fdi[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out) {
|
||||||
|
close(fdo[0]);
|
||||||
|
if ((fp = fdopen(fdo[1], "r")) != NULL &&
|
||||||
|
(outfp = open_memstream(&outbuf, &outbufsz)) != NULL) {
|
||||||
|
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||||
|
fputs(buf, outfp);
|
||||||
|
}
|
||||||
|
fclose(outfp);
|
||||||
|
*out = outbuf;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
close(fdo[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
pid = waitpid(child_pid, &status, 0);
|
||||||
|
} while (pid == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
sigaction(SIGINT, &sigint, NULL);
|
||||||
|
sigaction(SIGQUIT, &sigquit, NULL);
|
||||||
|
|
||||||
|
/* Simplified return value: returns 0 on success and -1 on error */
|
||||||
|
if (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(argv);
|
||||||
|
if (out) {
|
||||||
|
free(*out);
|
||||||
|
*out = NULL;
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
122
init/systemd.h
Normal file
122
init/systemd.h
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the satirical systemd-init for OpenBSD.
|
||||||
|
*
|
||||||
|
* DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE!
|
||||||
|
* DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES.
|
||||||
|
*
|
||||||
|
* Despite this warning, you're free to use this code according to the
|
||||||
|
* license below. Parts of it might be useful in other places after all.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Reyk Floeter <contact@reykfloeter.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#ifndef SYSTEMD_LIB
|
||||||
|
#define SYSTEMD_LIB
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A note about the preprocessor definitions:
|
||||||
|
* -DDANGEROUS: Compile with this flag to make system_dangerous() succeed.
|
||||||
|
* -DDEBUG: Enable extra verbose debug printing.
|
||||||
|
* -DJUSTKIDDING: Compile with this flag to build the tests instead of init.
|
||||||
|
*/
|
||||||
|
#if defined(DANGEROUS) && defined(JUSTKIDDING)
|
||||||
|
#error "DANGEROUS and JUSTKIDDING are mutually exclusive"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
#define DPRINTF(x...) do {} while (0)
|
||||||
|
#else
|
||||||
|
#define DPRINTF syslib_log
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The revision (bumped for every new service or score alg change). */
|
||||||
|
#define SYSTEMD_REV 5
|
||||||
|
|
||||||
|
/* The score file. */
|
||||||
|
#define SYSTEMD_SCORE "/systemd-score.txt"
|
||||||
|
|
||||||
|
/* The maximum number of seconds systemd waits until the next action. */
|
||||||
|
#define SYSTEMD_WATCH 30
|
||||||
|
|
||||||
|
/* Init systemd service. To be called by the executable first. */
|
||||||
|
void syslib_init(void);
|
||||||
|
|
||||||
|
/* Returns a true value if dangerous mode is enabled. Use with care. */
|
||||||
|
int syslib_dangerous(void);
|
||||||
|
|
||||||
|
/* Runs the next random things. */
|
||||||
|
void syslib_watch(void);
|
||||||
|
|
||||||
|
/* For noisy logging. */
|
||||||
|
void syslib_log(char *, ...);
|
||||||
|
|
||||||
|
/* Select a random file. Pass a PATH_MAX buffer. */
|
||||||
|
int syslib_randomfile(char [PATH_MAX])
|
||||||
|
__attribute__ ((__bounded__(__minbytes__,1,PATH_MAX)));
|
||||||
|
|
||||||
|
/* Select a random directory. Pass a PATH_MAX buffer. */
|
||||||
|
int syslib_randomdir(char [PATH_MAX])
|
||||||
|
__attribute__ ((__bounded__(__minbytes__,1,PATH_MAX)));
|
||||||
|
|
||||||
|
/* Recursively delete a directory. */
|
||||||
|
int syslib_rmtree(char *);
|
||||||
|
|
||||||
|
/* Execute a program. */
|
||||||
|
int syslib_exec(const char *, ...);
|
||||||
|
|
||||||
|
/* Execute a program with optional stdin and stdout. */
|
||||||
|
int syslib_pexec(const char *, char **, const char *, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* systemd plugins. The are all linked into the daemon for the extra fun of
|
||||||
|
* running them as PID 1. Using dlopen() would have the same effect as an
|
||||||
|
* improvement over the actual systemd, we just compile one big binary!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* systemd-file randomly deletes files */
|
||||||
|
int systemd_file(void (**)(void));
|
||||||
|
|
||||||
|
/* systemd-file randomly deletes directories */
|
||||||
|
int systemd_dir(void (**)(void));
|
||||||
|
|
||||||
|
/* systemd-reboot randomly reboots the system */
|
||||||
|
int systemd_reboot(void (**)(void));
|
||||||
|
|
||||||
|
/* systemd-move move files around in the filesystem */
|
||||||
|
int systemd_move(void (**)(void));
|
||||||
|
|
||||||
|
/* systemd-rename rename files */
|
||||||
|
int systemd_rename(void (**)(void));
|
||||||
|
|
||||||
|
/* Definition of systemd plugins. */
|
||||||
|
struct systemd_plugin {
|
||||||
|
const char *pid1_name;
|
||||||
|
long pid1_score;
|
||||||
|
int (*pid1_fn)(void (**cb)(void));
|
||||||
|
};
|
||||||
|
#define SYSTEMD_PLUGINS { \
|
||||||
|
{ "systemd-file", 2, systemd_file }, \
|
||||||
|
{ "systemd-dir", 4, systemd_dir }, \
|
||||||
|
{ "systemd-reboot", 1, systemd_reboot }, \
|
||||||
|
{ "systemd-move", 2, systemd_move }, \
|
||||||
|
{ "systemd-rename", 3, systemd_rename }, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SYSTEMD_LIB */
|
Loading…
Reference in a new issue