Skip to content

Commit 654a5f4

Browse files
committed
openrc-run: Support standard input redirection too
OpenRC already supports redirecting standard output/error of services. This patch adds support for redirecting standard input as well. I encountered the lack of this feature while working on a user service for a Wayland compositor status bar which reads status text to be displayed from stdin. Input redirection allows me to connect this user services to another user service providing the status text via a named pipe. Note that input redirection is also supported by SystemD (and potentially other service supervisors) through the `StandardInput=` directive [1]. [1]: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#StandardInput=
1 parent 0e5faa8 commit 654a5f4

7 files changed

Lines changed: 64 additions & 9 deletions

File tree

man/openrc-run.8

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,23 @@ use this to change the user id, and optionally group id, before
158158
or
159159
.Xr supervise-daemon 8
160160
launches the daemon.
161-
.It Ar output_log
162-
This is the path to a file or named pipe where the standard output from
161+
.It Ar input_file
162+
This is the path to a file or named pipe where the standard input from
163163
the service will be redirected. If you are starting this service with
164164
.Xr start-stop-daemon 8 ,
165165
, you must set
166166
.Pa command_background
167167
to true. Keep in mind that this path will be inside the chroot if the
168168
.Pa chroot
169-
variable is set.
169+
variable is set. Input redirection only opens the file for reading and
170+
(contrary to output redirection) doesn't create it, if it doesn't exist.
171+
.It Ar output_log
172+
The same thing as
173+
.Pa input_file
174+
but for the standard output.
170175
.It Ar error_log
171176
The same thing as
172-
.Pa output_log
177+
.Pa input_file
173178
but for the standard error output.
174179
.It Ar output_logger
175180
This is a process which will be used to log the standard output from the

man/start-stop-daemon.8

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ on POSIX systems and, additionally, batch and idle on Linux. If
143143
is an integer, it is passed directly to pthread_setschedparam(3).
144144
.It Fl -scheduler-priority Ar priority
145145
Sets the priority parameter of the scheduling policy of the daemon. See sched(7) for details.
146+
.It Fl 0 , -stdin Ar file
147+
Redirect the standard input of the process to file when started with
148+
.Fl background .
149+
The file Must be an absolute pathname, but relative to the path
150+
optionally given with
151+
.Fl r , -chroot .
152+
The file can also be a named pipe. The file is only opened for reading and
153+
not created if it doesn't exist yet.
146154
.It Fl 1 , -stdout Ar logfile
147155
Redirect the standard output of the process to logfile when started with
148156
.Fl background .

man/supervise-daemon.8

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ servicename
5050
.Ar chrootpath
5151
.Fl u , -user
5252
.Ar user
53+
.Fl 0 , -stdin
54+
.Ar file
5355
.Fl 1 , -stdout
5456
.Ar logfile
5557
.Fl 2 , -stderr
@@ -154,11 +156,21 @@ process to communicate with is determined by the name of the service
154156
taken from the RC_SVCNAME environment variable.
155157
.It Fl u , -user Ar user
156158
Start the daemon as the specified user.
157-
.It Fl 1 , -stdout Ar logfile
158-
Redirect the standard output of the process to logfile.
159+
.It Fl 0 , -stdin Ar file
160+
Redirect the standard input of the process to file.
159161
Must be an absolute pathname, but relative to the path optionally given with
160162
.Fl r , -chroot .
161-
The logfile can also be a named pipe.
163+
The file can also be a named pipe.
164+
Note that input redirection only opens the file for reading (and doesn't create
165+
it) while output redirection via
166+
.Fl 1 , -stdout
167+
or
168+
.Fl 1 , -stderr
169+
opens it for read/write and creates it (if it doesn't exist).
170+
.It Fl 1 , -stdout Ar logfile
171+
The same thing as
172+
.Fl 0 , -stdin
173+
but with the standard output.
162174
.It Fl 2 , -stderr Ar logfile
163175
The same thing as
164176
.Fl 1 , -stdout

sh/start-stop-daemon.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ ssd_start()
4545
--exec $command \
4646
${chroot:+--chroot} $chroot \
4747
${directory:+--chdir} $directory \
48+
${input_file+--stdin} $input_file \
4849
${output_log+--stdout} $output_log \
4950
${error_log+--stderr} $error_log \
5051
${output_logger:+--stdout-logger \"$output_logger\"} \

sh/supervise-daemon.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ supervise_start()
2828
${retry:+--retry} $retry \
2929
${directory:+--chdir} $directory \
3030
${chroot:+--chroot} $chroot \
31+
${input_file+--stdin} $input_file \
3132
${output_log+--stdout} ${output_log} \
3233
${error_log+--stderr} $error_log \
3334
${output_logger:+--stdout-logger \"$output_logger\"} \

src/start-stop-daemon/start-stop-daemon.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ enum {
9494

9595
const char *applet = NULL;
9696
const char *extraopts = NULL;
97-
const char getoptstring[] = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:3:4:" \
97+
const char getoptstring[] = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:0:1:2:3:4:" \
9898
getoptstring_COMMON;
9999
const struct option longopts[] = {
100100
{ "capabilities", 1, NULL, LONGOPT_CAPABILITIES},
@@ -124,6 +124,7 @@ const struct option longopts[] = {
124124
{ "chroot", 1, NULL, 'r'},
125125
{ "wait", 1, NULL, 'w'},
126126
{ "exec", 1, NULL, 'x'},
127+
{ "stdin", 1, NULL, '0'},
127128
{ "stdout", 1, NULL, '1'},
128129
{ "stderr", 1, NULL, '2'},
129130
{ "stdout-logger",1, NULL, '3'},
@@ -162,6 +163,7 @@ const char * const longopts_help[] = {
162163
"Chroot to this directory",
163164
"Milliseconds to wait for daemon start",
164165
"Binary to start/stop",
166+
"Redirect stdin to file",
165167
"Redirect stdout to file",
166168
"Redirect stderr to file",
167169
"Redirect stdout to process",
@@ -318,6 +320,7 @@ int main(int argc, char **argv)
318320
gid_t gid = 0;
319321
char *home = NULL;
320322
int tid = 0;
323+
char *redirect_stdin = NULL;
321324
char *redirect_stderr = NULL;
322325
char *redirect_stdout = NULL;
323326
char *stderr_process = NULL;
@@ -601,6 +604,10 @@ int main(int argc, char **argv)
601604
exec = optarg;
602605
break;
603606

607+
case '0': /* --stdin /path/to/stdin.input-file */
608+
redirect_stdin = optarg;
609+
break;
610+
604611
case '1': /* --stdout /path/to/stdout.lgfile */
605612
redirect_stdout = optarg;
606613
break;
@@ -1071,6 +1078,13 @@ int main(int argc, char **argv)
10711078
stdin_fd = devnull_fd;
10721079
stdout_fd = devnull_fd;
10731080
stderr_fd = devnull_fd;
1081+
if (redirect_stdin) {
1082+
if ((stdin_fd = open(redirect_stdin,
1083+
O_RDONLY)) == -1)
1084+
eerrorx("%s: unable to open the input file"
1085+
" for stdin `%s': %s",
1086+
applet, redirect_stdin, strerror(errno));
1087+
}
10741088
if (redirect_stdout) {
10751089
if ((stdout_fd = open(redirect_stdout,
10761090
O_WRONLY | O_CREAT | O_APPEND,

src/supervise-daemon/supervise-daemon.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ enum {
8787

8888
const char *applet = NULL;
8989
const char *extraopts = NULL;
90-
const char getoptstring[] = "A:a:D:d:e:g:H:I:Kk:m:N:p:R:r:s:Su:1:2:3" \
90+
const char getoptstring[] = "A:a:D:d:e:g:H:I:Kk:m:N:p:R:r:s:Su:0:1:2:3" \
9191
getoptstring_COMMON;
9292
const struct option longopts[] = {
9393
{ "healthcheck-timer", 1, NULL, 'a'},
@@ -112,6 +112,7 @@ const struct option longopts[] = {
112112
{ "signal", 1, NULL, 's'},
113113
{ "start", 0, NULL, 'S'},
114114
{ "user", 1, NULL, 'u'},
115+
{ "stdin", 1, NULL, '0'},
115116
{ "stdout", 1, NULL, '1'},
116117
{ "stderr", 1, NULL, '2'},
117118
{ "stdout-logger",1, NULL, LONGOPT_STDOUT_LOGGER},
@@ -143,6 +144,7 @@ const char * const longopts_help[] = {
143144
"Send a signal to the daemon",
144145
"Start daemon",
145146
"Change the process user",
147+
"Redirect stdin to file",
146148
"Redirect stdout to file",
147149
"Redirect stderr to file",
148150
"Redirect stdout to process",
@@ -168,6 +170,7 @@ static int stdin_fd;
168170
static int stdout_fd;
169171
static int stderr_fd;
170172
static struct ready ready;
173+
static char *redirect_stdin = NULL;
171174
static char *redirect_stderr = NULL;
172175
static char *redirect_stdout = NULL;
173176
static char *stderr_process = NULL;
@@ -554,6 +557,13 @@ RC_NORETURN static void child_process(char *exec, char **argv)
554557
stdin_fd = devnull_fd;
555558
stdout_fd = devnull_fd;
556559
stderr_fd = devnull_fd;
560+
if (redirect_stdin) {
561+
if ((stdin_fd = open(redirect_stdin,
562+
O_RDONLY)) == -1)
563+
eerrorx("%s: unable to open the input file"
564+
" for stdin `%s': %s",
565+
applet, redirect_stdin, strerror(errno));
566+
}
557567
if (redirect_stdout) {
558568
if ((stdout_fd = open(redirect_stdout,
559569
O_WRONLY | O_CREAT | O_APPEND,
@@ -1057,6 +1067,10 @@ int main(int argc, char **argv)
10571067
}
10581068
break;
10591069

1070+
case '0': /* --stdin /path/to/stdin.input-file */
1071+
redirect_stdin = optarg;
1072+
break;
1073+
10601074
case '1': /* --stdout /path/to/stdout.lgfile */
10611075
redirect_stdout = optarg;
10621076
break;

0 commit comments

Comments
 (0)