Skip to content

Commit 8547aea

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 8547aea

7 files changed

Lines changed: 54 additions & 7 deletions

File tree

man/openrc-run.8

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,22 @@ 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
169169
variable is set.
170+
.It Ar output_log
171+
The same thing as
172+
.Pa input_file
173+
but for the standard output.
170174
.It Ar error_log
171175
The same thing as
172-
.Pa output_log
176+
.Pa input_file
173177
but for the standard error output.
174178
.It Ar output_logger
175179
This is a process which will be used to log the standard output from the

man/start-stop-daemon.8

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ 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 logfile Must be an absolute pathname, but relative to the path
150+
optionally given with
151+
.Fl r , -chroot .
152+
The logfile can also be a named pipe.
146153
.It Fl 1 , -stdout Ar logfile
147154
Redirect the standard output of the process to logfile when started with
148155
.Fl background .

man/supervise-daemon.8

Lines changed: 8 additions & 2 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,15 @@ 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 .
161163
The logfile can also be a named pipe.
164+
.It Fl 1 , -stdout Ar logfile
165+
The same thing as
166+
.Fl 0 , -stdin
167+
but with the standard output.
162168
.It Fl 2 , -stderr Ar logfile
163169
The same thing as
164170
.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)