[OpenWrt-Devel] [PATCH procd] service: use PTY (instead of a pipe) for reading service output
Yousong Zhou
yszhou4tech at gmail.com
Fri Jun 19 08:44:06 EDT 2015
On 19 June 2015 at 19:34, Rafał Miłecki <zajec5 at gmail.com> wrote:
> Using pipe automatically switches service to block buffering which kind
> of breaks our logging. We won't get anything from FD until the buffer
> gets filled fully or the service exits. This makes log messages appear
> with an unwanted delay.
> Switching to PTY fixes this issue. Service prints to the "standard"
> stdout (no piping) but the messages go (line buffered) to the master FD
> anyway.
> It was successfully tested with all 4 variants of "stdout" and "stderr"
> ubus arguments.
>
I do not like this because
- Conventionally, services will drop their inherited controlling
terminal for preparation of becoming a daemon. Adding back that
controlling terminal by login_tty() for alleviating possible delay
when logging stdio sounds not right.
- I am biased... in that the ossherd [1] package depends on the fact
processes started by procd do not have controlling terminals and this
will unattended password login with ssh :)
Anyway, the implementation is not complete.
- epipe[] is still there.
- aslave needs to be closed when login_pty() failed
- login_pty() and dup2() used together
- aslave should be closed in parent
Cheers
yousong
> Signed-off-by: Rafał Miłecki <zajec5 at gmail.com>
> ---
> CMakeLists.txt | 2 +-
> service/instance.c | 35 +++++++++++++++++++++++++----------
> 2 files changed, 26 insertions(+), 11 deletions(-)
>
> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index dfa9413..7e1fad3 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -14,7 +14,7 @@ SET(SOURCES procd.c signal.c watchdog.c state.c inittab.c rcS.c ubus.c system.c
> service/service.c service/instance.c service/validate.c service/trigger.c service/watch.c
> plug/coldplug.c plug/hotplug.c utils/utils.c)
>
> -SET(LIBS ubox ubus json-c blobmsg_json json_script)
> +SET(LIBS util ubox ubus json-c blobmsg_json json_script)
>
> IF(DEBUG)
> ADD_DEFINITIONS(-DDEBUG -g3)
> diff --git a/service/instance.c b/service/instance.c
> index 35b2def..110db36 100644
> --- a/service/instance.c
> +++ b/service/instance.c
> @@ -23,6 +23,8 @@
> #include <pwd.h>
> #include <libgen.h>
> #include <unistd.h>
> +#include <pty.h>
> +#include <utmp.h>
>
> #include <libubox/md5.h>
>
> @@ -273,7 +275,7 @@ instance_run(struct service_instance *in, int _stdout, int _stderr)
> dup2(_stdin, STDIN_FILENO);
> closefd(_stdin);
> }
> - if (_stdout > -1) {
> + if (_stdout > -1 && _stdout != STDOUT_FILENO) {
> dup2(_stdout, STDOUT_FILENO);
> closefd(_stdout);
> }
> @@ -314,8 +316,9 @@ instance_free_stdio(struct service_instance *in)
> void
> instance_start(struct service_instance *in)
> {
> + int amaster = -1, aslave = -1;
> int pid;
> - int opipe[2] = { -1, -1 };
> + int _stdout = -1;
> int epipe[2] = { -1, -1 };
>
> if (!avl_is_empty(&in->errors.avl)) {
> @@ -327,13 +330,19 @@ instance_start(struct service_instance *in)
> return;
>
> instance_free_stdio(in);
> +
> + /* We don't want block buffered stdout so use PTY instead of a pipe */
> if (in->_stdout.fd.fd > -2) {
> - if (pipe(opipe)) {
> - ULOG_WARN("pipe() failed: %d (%s)\n", errno, strerror(errno));
> - opipe[0] = opipe[1] = -1;
> + if (openpty(&amaster, &aslave, NULL, NULL, NULL)) {
> + ULOG_WARN("openpty() failed: %d (%s)\n", errno, strerror(errno));
> + amaster = aslave = -1;
> + } else {
> + /* Child should just use stdout which will go to the master */
> + _stdout = STDOUT_FILENO;
> }
> }
>
> + /* Use pipe as stderr is always unbuffered by default */
> if (in->_stderr.fd.fd > -2) {
> if (pipe(epipe)) {
> ULOG_WARN("pipe() failed: %d (%s)\n", errno, strerror(errno));
> @@ -353,9 +362,15 @@ instance_start(struct service_instance *in)
>
> if (!pid) {
> uloop_done();
> - closefd(opipe[0]);
> + close(amaster);
> closefd(epipe[0]);
> - instance_run(in, opipe[1], epipe[1]);
> + if (aslave > -1) {
> + if (login_tty(aslave)) {
> + ULOG_WARN("login_tty() failed: %d (%s)\n", errno, strerror(errno));
> + _stdout = -1;
> + }
> + }
> + instance_run(in, _stdout, epipe[1]);
> return;
> }
>
> @@ -364,9 +379,9 @@ instance_start(struct service_instance *in)
> clock_gettime(CLOCK_MONOTONIC, &in->start);
> uloop_process_add(&in->proc);
>
> - if (opipe[0] > -1) {
> - ustream_fd_init(&in->_stdout, opipe[0]);
> - closefd(opipe[1]);
> + if (amaster > -1) {
> + ustream_fd_init(&in->_stdout, amaster);
> + closefd(aslave);
> }
>
> if (epipe[0] > -1) {
> --
> 1.8.4.5
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel at lists.openwrt.org
> https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list