diff mbox

[OpenWrt-Devel,procd] service: start apps with LD_PRELOAD & lib disabling buffering

Message ID 1434755017-8442-1-git-send-email-zajec5@gmail.com
State Changes Requested
Headers show

Commit Message

Rafał Miłecki June 19, 2015, 11:03 p.m. UTC
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.
This adds a tiny libsetnbf.so that disables stdout buffering and uses it
for every service started by procd.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
 CMakeLists.txt     |  7 +++++++
 service/instance.c | 12 +++++++++++-
 service/setnbf.c   |  6 ++++++
 3 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 service/setnbf.c

Comments

Paul Fertser June 20, 2015, 6 a.m. UTC | #1
Hey Rafał,

Rafał Miłecki <zajec5@gmail.com> writes:
> +	char ld_preload[64] = {}; /* Has to be big enough for all cases */
...
> +		if (ld_preload[0])
> +			strcat(ld_preload, ":");
> +		strcat(ld_preload, "/lib/libpreload-seccomp.so");

I understand C is often like that but still using strcat here makes me
feel uneasy. Proper range-checking would require a bit more code, but
it's a one-time coding/reviewing and a neglectable runtime cost.

> +static void __attribute__((constructor)) setnbf(void)
> +{
> +	setbuf(stdout, NULL);
> +}

Not sure if no buffering or line buffering would be the best choice
here.
John Crispin June 20, 2015, 7:07 a.m. UTC | #2
i dont like this idea at all. calling ld-preload on every started app
just seems wrong


On 20/06/2015 01:03, Rafał Miłecki 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.
> This adds a tiny libsetnbf.so that disables stdout buffering and uses it
> for every service started by procd.
> 
> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
> ---
>  CMakeLists.txt     |  7 +++++++
>  service/instance.c | 12 +++++++++++-
>  service/setnbf.c   |  6 ++++++
>  3 files changed, 24 insertions(+), 1 deletion(-)
>  create mode 100644 service/setnbf.c
> 
> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index dfa9413..c3b7c1e 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -10,6 +10,13 @@ IF(APPLE)
>    LINK_DIRECTORIES(/opt/local/lib)
>  ENDIF()
>  
> +
> +ADD_LIBRARY(setnbf SHARED service/setnbf.c)
> +INSTALL(TARGETS setnbf
> +	LIBRARY DESTINATION lib
> +)
> +
> +
>  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)
> diff --git a/service/instance.c b/service/instance.c
> index 35b2def..726f859 100644
> --- a/service/instance.c
> +++ b/service/instance.c
> @@ -224,6 +224,7 @@ instance_run(struct service_instance *in, int _stdout, int _stderr)
>  	struct blobmsg_list_node *var;
>  	struct blob_attr *cur;
>  	char **argv;
> +	char ld_preload[64] = {}; /* Has to be big enough for all cases */
>  	int argc = 1; /* NULL terminated */
>  	int rem, _stdin;
>  
> @@ -238,8 +239,17 @@ instance_run(struct service_instance *in, int _stdout, int _stderr)
>  
>  	if (!in->trace && !in->has_jail && in->seccomp) {
>  		setenv("SECCOMP_FILE", in->seccomp, 1);
> -		setenv("LD_PRELOAD", "/lib/libpreload-seccomp.so", 1);
> +		if (ld_preload[0])
> +			strcat(ld_preload, ":");
> +		strcat(ld_preload, "/lib/libpreload-seccomp.so");
>  	}
> +	if (_stdout >= 0) {
> +		if (ld_preload[0])
> +			strcat(ld_preload, ":");
> +		strcat(ld_preload, "/lib/libsetnbf.so");
> +	}
> +	if (ld_preload[0])
> +		setenv("LD_PRELOAD", ld_preload, 1);
>  
>  	blobmsg_list_for_each(&in->limits, var)
>  		instance_limits(blobmsg_name(var->data), blobmsg_data(var->data));
> diff --git a/service/setnbf.c b/service/setnbf.c
> new file mode 100644
> index 0000000..7b5f3bd
> --- /dev/null
> +++ b/service/setnbf.c
> @@ -0,0 +1,6 @@
> +#include <stdio.h>
> +
> +static void __attribute__((constructor)) setnbf(void)
> +{
> +	setbuf(stdout, NULL);
> +}
>
Jo-Philipp Wich June 20, 2015, 11:56 a.m. UTC | #3
Hi John,

> i dont like this idea at all. calling ld-preload on every started app
> just seems wrong

I was the one suggesting the idea since we needed a solution which does
not require modification of downstream programs. We could restrict the
preloading to programs which requested stdio relaying support from procd
and not preload for the rest.

~ Jow
Rafał Miłecki June 20, 2015, 6:53 p.m. UTC | #4
On 20 June 2015 at 13:56, Jo-Philipp Wich <jow@openwrt.org> wrote:
>> i dont like this idea at all. calling ld-preload on every started app
>> just seems wrong
>
> I was the one suggesting the idea since we needed a solution which does
> not require modification of downstream programs. We could restrict the
> preloading to programs which requested stdio relaying support from procd
> and not preload for the rest.

AFAIK there are 3 solutions to this:
1) Modifying every app we want to support with procd + logging
2) Using PTY which I tried in https://patchwork.ozlabs.org/patch/486670/
3) Using LD_PRELOAD

The PTY was pointed as not the best choice, so that's why I continued
with LD_PRELOAD. As Jo-Philipp pointed, it's the same solution
"stdbuf" uses. I'm afraid there isn't any better alternative :(
John Crispin June 20, 2015, 7:35 p.m. UTC | #5
On 20/06/2015 20:53, Rafał Miłecki wrote:
> On 20 June 2015 at 13:56, Jo-Philipp Wich <jow@openwrt.org> wrote:
>>> i dont like this idea at all. calling ld-preload on every started app
>>> just seems wrong
>>
>> I was the one suggesting the idea since we needed a solution which does
>> not require modification of downstream programs. We could restrict the
>> preloading to programs which requested stdio relaying support from procd
>> and not preload for the rest.
> 
> AFAIK there are 3 solutions to this:
> 1) Modifying every app we want to support with procd + logging
> 2) Using PTY which I tried in https://patchwork.ozlabs.org/patch/486670/
> 3) Using LD_PRELOAD
> 
> The PTY was pointed as not the best choice, so that's why I continued
> with LD_PRELOAD. As Jo-Philipp pointed, it's the same solution
> "stdbuf" uses. I'm afraid there isn't any better alternative :(
> 

oh well, i still dont like it but that is not really relevant i guess ... :)
Etienne Champetier June 20, 2015, 7:46 p.m. UTC | #6
Hi,

2015-06-20 21:35 GMT+02:00 John Crispin <blogic@openwrt.org>:

>
>
> On 20/06/2015 20:53, Rafał Miłecki wrote:
> > On 20 June 2015 at 13:56, Jo-Philipp Wich <jow@openwrt.org> wrote:
> >>> i dont like this idea at all. calling ld-preload on every started app
> >>> just seems wrong
> >>
> >> I was the one suggesting the idea since we needed a solution which does
> >> not require modification of downstream programs. We could restrict the
> >> preloading to programs which requested stdio relaying support from procd
> >> and not preload for the rest.
> >
> > AFAIK there are 3 solutions to this:
> > 1) Modifying every app we want to support with procd + logging
> > 2) Using PTY which I tried in https://patchwork.ozlabs.org/patch/486670/
> > 3) Using LD_PRELOAD
> >
> > The PTY was pointed as not the best choice, so that's why I continued
> > with LD_PRELOAD. As Jo-Philipp pointed, it's the same solution
> > "stdbuf" uses. I'm afraid there isn't any better alternative :(
> >
>
> oh well, i still dont like it but that is not really relevant i guess ...
> :)
>
Aren't you using LD_PRELOAD for procd jailing stuff ?
John Crispin June 21, 2015, 9:38 a.m. UTC | #7
On 20/06/2015 21:46, Etienne Champetier wrote:
> Hi,
> 
> 2015-06-20 21:35 GMT+02:00 John Crispin <blogic@openwrt.org
> <mailto:blogic@openwrt.org>>:
> 
> 
> 
>     On 20/06/2015 20:53, Rafał Miłecki wrote:
>     > On 20 June 2015 at 13:56, Jo-Philipp Wich <jow@openwrt.org <mailto:jow@openwrt.org>> wrote:
>     >>> i dont like this idea at all. calling ld-preload on every started app
>     >>> just seems wrong
>     >>
>     >> I was the one suggesting the idea since we needed a solution which does
>     >> not require modification of downstream programs. We could restrict the
>     >> preloading to programs which requested stdio relaying support from procd
>     >> and not preload for the rest.
>     >
>     > AFAIK there are 3 solutions to this:
>     > 1) Modifying every app we want to support with procd + logging
>     > 2) Using PTY which I tried in https://patchwork.ozlabs.org/patch/486670/
>     > 3) Using LD_PRELOAD
>     >
>     > The PTY was pointed as not the best choice, so that's why I continued
>     > with LD_PRELOAD. As Jo-Philipp pointed, it's the same solution
>     > "stdbuf" uses. I'm afraid there isn't any better alternative :(
>     >
> 
>     oh well, i still dont like it but that is not really relevant i
>     guess ... :)
> 
> Aren't you using LD_PRELOAD for procd jailing stuff ?

yes, i do. you simply did not understood what i said. i dont have a
problem with preloading per-se but with the solution for setting the
buffering. however if there really is no saner way then so be it.

> 
> 
> 
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
>
diff mbox

Patch

diff --git a/CMakeLists.txt b/CMakeLists.txt
index dfa9413..c3b7c1e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,6 +10,13 @@  IF(APPLE)
   LINK_DIRECTORIES(/opt/local/lib)
 ENDIF()
 
+
+ADD_LIBRARY(setnbf SHARED service/setnbf.c)
+INSTALL(TARGETS setnbf
+	LIBRARY DESTINATION lib
+)
+
+
 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)
diff --git a/service/instance.c b/service/instance.c
index 35b2def..726f859 100644
--- a/service/instance.c
+++ b/service/instance.c
@@ -224,6 +224,7 @@  instance_run(struct service_instance *in, int _stdout, int _stderr)
 	struct blobmsg_list_node *var;
 	struct blob_attr *cur;
 	char **argv;
+	char ld_preload[64] = {}; /* Has to be big enough for all cases */
 	int argc = 1; /* NULL terminated */
 	int rem, _stdin;
 
@@ -238,8 +239,17 @@  instance_run(struct service_instance *in, int _stdout, int _stderr)
 
 	if (!in->trace && !in->has_jail && in->seccomp) {
 		setenv("SECCOMP_FILE", in->seccomp, 1);
-		setenv("LD_PRELOAD", "/lib/libpreload-seccomp.so", 1);
+		if (ld_preload[0])
+			strcat(ld_preload, ":");
+		strcat(ld_preload, "/lib/libpreload-seccomp.so");
 	}
+	if (_stdout >= 0) {
+		if (ld_preload[0])
+			strcat(ld_preload, ":");
+		strcat(ld_preload, "/lib/libsetnbf.so");
+	}
+	if (ld_preload[0])
+		setenv("LD_PRELOAD", ld_preload, 1);
 
 	blobmsg_list_for_each(&in->limits, var)
 		instance_limits(blobmsg_name(var->data), blobmsg_data(var->data));
diff --git a/service/setnbf.c b/service/setnbf.c
new file mode 100644
index 0000000..7b5f3bd
--- /dev/null
+++ b/service/setnbf.c
@@ -0,0 +1,6 @@ 
+#include <stdio.h>
+
+static void __attribute__((constructor)) setnbf(void)
+{
+	setbuf(stdout, NULL);
+}