|
32 | 32 |
|
33 | 33 | #include "libqrexec-utils.h"
|
34 | 34 | #include "remote.h"
|
| 35 | +#include "private.h" |
35 | 36 |
|
36 | 37 | static _Noreturn void handle_vchan_error(const char *op)
|
37 | 38 | {
|
@@ -79,15 +80,23 @@ enum {
|
79 | 80 | };
|
80 | 81 |
|
81 | 82 | int process_io(const struct process_io_request *req) {
|
| 83 | + return qrexec_process_io(req, NULL); |
| 84 | +} |
| 85 | + |
| 86 | +int qrexec_process_io(const struct process_io_request *req, |
| 87 | + const struct qrexec_parsed_command *cmd) { |
82 | 88 | libvchan_t *vchan = req->vchan;
|
83 | 89 | int stdin_fd = req->stdin_fd;
|
84 | 90 | int stdout_fd = req->stdout_fd;
|
85 | 91 | int stderr_fd = req->stderr_fd;
|
86 | 92 | struct buffer *stdin_buf = req->stdin_buf;
|
87 | 93 |
|
88 |
| - bool is_service = req->is_service; |
| 94 | + bool const is_service = req->is_service; |
| 95 | + assert(is_service == (cmd != NULL)); |
89 | 96 | bool replace_chars_stdout = req->replace_chars_stdout;
|
90 | 97 | bool replace_chars_stderr = req->replace_chars_stderr;
|
| 98 | + bool const exit_on_stdin_eof = cmd != NULL && cmd->exit_on_stdin_eof; |
| 99 | + bool const exit_on_stdout_eof = cmd != NULL && cmd->exit_on_stdout_eof; |
91 | 100 | const int data_protocol_version = req->data_protocol_version;
|
92 | 101 | const size_t max_chunk_size = max_data_chunk_size(data_protocol_version);
|
93 | 102 | pid_t local_pid = req->local_pid;
|
@@ -119,19 +128,41 @@ int process_io(const struct process_io_request *req) {
|
119 | 128 | set_nonblock(stdin_fd);
|
120 | 129 | if (stdout_fd != stdin_fd)
|
121 | 130 | set_nonblock(stdout_fd);
|
| 131 | + if (is_service && local_pid == 0) { |
| 132 | + assert(stdin_fd == stdout_fd); |
| 133 | + assert(stderr_fd == -1); |
| 134 | + } |
122 | 135 | if (stderr_fd >= 0) {
|
123 | 136 | assert(is_service); // if this is a client, stderr_fd is *always* -1
|
124 | 137 | set_nonblock(stderr_fd);
|
125 | 138 | }
|
| 139 | + if (exit_on_stdin_eof || exit_on_stdout_eof) { |
| 140 | + assert(is_service); // only valid for socket services |
| 141 | + assert(local_pid == 0); // ditto |
| 142 | + } |
126 | 143 |
|
127 | 144 | /* Convenience macros that eliminate a ton of error-prone boilerplate */
|
128 |
| -#define close_stdin() do { \ |
129 |
| - close_stdio(stdin_fd, stdout_fd, SHUT_WR); \ |
130 |
| - stdin_fd = -1; \ |
| 145 | +#define close_stdin() do { \ |
| 146 | + if (exit_on_stdin_eof) { \ |
| 147 | + /* Set stdin_fd and stdout_fd to -1. \ |
| 148 | + * No need to close them as the process \ |
| 149 | + * will soon exit. */ \ |
| 150 | + stdin_fd = stdout_fd = -1; \ |
| 151 | + } else { \ |
| 152 | + close_stdio(stdin_fd, stdout_fd, SHUT_WR); \ |
| 153 | + stdin_fd = -1; \ |
| 154 | + } \ |
131 | 155 | } while (0)
|
132 |
| -#define close_stdout() do { \ |
133 |
| - close_stdio(stdout_fd, stdin_fd, SHUT_RD); \ |
134 |
| - stdout_fd = -1; \ |
| 156 | +#define close_stdout() do { \ |
| 157 | + if (exit_on_stdout_eof) { \ |
| 158 | + /* Set stdin_fd and stdout_fd to -1. \ |
| 159 | + * No need to close them as the process \ |
| 160 | + * will soon exit. */ \ |
| 161 | + stdin_fd = stdout_fd = -1; \ |
| 162 | + } else { \ |
| 163 | + close_stdio(stdout_fd, stdin_fd, SHUT_RD); \ |
| 164 | + stdout_fd = -1; \ |
| 165 | + } \ |
135 | 166 | } while (0)
|
136 | 167 | #pragma GCC poison close_stdio
|
137 | 168 |
|
|
0 commit comments