Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Feb 2012 18:00:31 GMT
From:      Jeremie Le Hen <jeremie@le-hen.org>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/154915: [libc] [patch] Force stdio output streams to line-buffered mode
Message-ID:  <201202171800.q1HI0VrW090362@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/154915; it has been noted by GNATS.

From: Jeremie Le Hen <jeremie@le-hen.org>
To: Oliver Fromme <olli@lurza.secnetix.de>
Cc: bug-followup@FreeBSD.org, jeremie@le-hen.org
Subject: Re: kern/154915: [libc] [patch] Force stdio output streams to
 line-buffered mode
Date: Fri, 17 Feb 2012 18:53:06 +0100

 --n8g4imXOkfNTN/H1
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 Hi Oliver,
 
 On Thu, Feb 16, 2012 at 02:49:50PM +0100, Oliver Fromme wrote:
 > I think introducing an environment variable for this purpose
 > is a bad hack.  I would advise against this.
 > 
 > Many tools already have options for unbuffered or line-buffered
 > output (for example cat -u), and there are also other ways to
 > circumvent such problems.
 > 
 > For example, the problem quoted in the PR can be solved like this,
 > using the -u option of cat:
 > 
 >     $ iostat -x 1 | cat -un | grep ad1
 
 This doesn't help if you enclose a command that doesn't have such an
 option between pipes.  For instance:
 
 $ iostat -x 1 | cat -u | tr MG mg | cat -u | grep -n ad1
 
 > or avoiding cat completely (also might be more efficient,
 > saving one process and one pipe, though I haven't benchmarked
 > this):
 > 
 >     $ iostat -x 1 | awk '{n+=1} /ad1/{print n, $0}'
 
 Right we can almost always replace a pipeline of commands with an awk
 (or whatever) script.  But besides being sometimes inconvenient, saving
 a process or pipe does not always leads to performance benefits.  The
 very example you took is a good illustration of my point: I sometimes
 have to dig into big log files and awk is naturally very powerful.  Yet
 I noticed a *huge* performance gap between (gnu) grep and awk:
 
 $ time grep -n 'include.*stdio' 'FreeNode/##c.log' > /dev/null
 	1.10 real         0.97 user         0.12 sys
 $ time awk '{n+=1} /include.*stdio/{print n, $0}' 'FreeNode/##c.log' > /dev/null
 	3.74 real         3.63 user         0.08 sys
     
 > For certain other cases, I have the following alias in my ~/.zshrc
 > that simulates a TTY environment for a tool so it is forced to
 > use line-buffered output:
 > 
 >     alias intty='script -qt0 /dev/null'
 > 
 > So I can write:
 > 
 >     $ intty sometool -args | grep ...
 > 
 > However, the intty alias only works when it is the first command
 > in a pipeline (this is a limitation of the "script" command).
 
 I wasn't aware of that.  Out of curiosity, I tried the following
 command in order to test this:
 
 $ vmstat  1 | script -qt 0 /dev/null grep . | cat
 
 And each line in output is printed twice.  I didn't have time to
 investigate though.
 
 > In the above example, the cat command is not the first, but a
 > subshell can be used to work around this:
 > 
 >     $ intty sh -c 'iostat -x 1 | cat -n' | grep ad1
 > 
 > (It should work with any shell that supports aliases, not just
 > zsh, of course.)
 > 
 > I suggest closing this PR.
 
 Well, an evil hack VS an even eviler workaround which is not as powerful
 IMHO ;).
 
 In fact, I made a far more better of version of my patch which doesn't
 modify libc.  Instead it introduces a new shared library (libstdbuf.so)
 which is still controlled by environment variables, and an helper
 command (stdbuf(1)) is provided to do the environment-fu (including
 LD_PRELOAD) in your stead.
 
 Unfortuntately I forgot to update it in the PR database.  You will find
 it attached to this email, I think the bug tracker will show it in the
 PR afterward.
 
 Can you tell me if it better fits your expectations in matter of
 "low-hackiness"?  The standard code path is not modified at all.
 
 I would be glad if we could proceed with this, this is a feature I often
 miss.
 
 Thanks a lot for taking time to answer.
 Regards,
 -- 
 Jeremie Le Hen
 
 Men are born free and equal.  Later on, they're on their own.
 				Jean Yanne
 
 --n8g4imXOkfNTN/H1
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="stdbuf.diff"
 
 diff -urNp src.HEAD_20111506/lib/libc/stdio/setbuf.3 src/lib/libc/stdio/setbuf.3
 --- src.HEAD_20111506/lib/libc/stdio/setbuf.3	2007-01-09 01:28:07.000000000 +0100
 +++ src/lib/libc/stdio/setbuf.3	2011-08-04 19:00:49.000000000 +0200
 @@ -30,7 +30,7 @@
  .\" SUCH DAMAGE.
  .\"
  .\"     @(#)setbuf.3	8.1 (Berkeley) 6/4/93
 -.\" $FreeBSD: src/lib/libc/stdio/setbuf.3,v 1.17 2007/01/09 00:28:07 imp Exp $
 +.\" $FreeBSD: src/lib/libc/stdio/setbuf.3,v 1.17.10.1 2009/08/03 08:13:06 kensmith Exp $
  .\"
  .Dd June 4, 1993
  .Dt SETBUF 3
 @@ -83,6 +83,9 @@ normally does) it is line buffered.
  The standard error stream
  .Dv stderr
  is always unbuffered.
 +Note that these defaults maybe be altered using the
 +.Xr stdbuf 1
 +utility.
  .Pp
  The
  .Fn setvbuf
 @@ -177,6 +180,7 @@ function returns what the equivalent
  .Fn setvbuf
  would have returned.
  .Sh SEE ALSO
 +.Xr stdbuf 1 ,
  .Xr fclose 3 ,
  .Xr fopen 3 ,
  .Xr fread 3 ,
 diff -urNp src.HEAD_20111506/lib/libstdbuf/Makefile src/lib/libstdbuf/Makefile
 --- src.HEAD_20111506/lib/libstdbuf/Makefile	1970-01-01 01:00:00.000000000 +0100
 +++ src/lib/libstdbuf/Makefile	2011-08-04 18:49:59.000000000 +0200
 @@ -0,0 +1,15 @@
 +# $FreeBSD: src/lib/libftpio/Makefile,v 1.17.2.1 2009/08/03 08:13:06 kensmith Exp $
 +
 +.include <bsd.own.mk>
 +
 +LIB=		stdbuf
 +SRCS=		stdbuf.c
 +SHLIB_MAJOR=	1
 +MAN=		libstdbuf.3
 +
 +CFLAGS+=	-I${.CURDIR}
 +LDADD=		-lutil
 +
 +WARNS?=		6
 +
 +.include <bsd.lib.mk>
 diff -urNp src.HEAD_20111506/lib/libstdbuf/libstdbuf.3 src/lib/libstdbuf/libstdbuf.3
 --- src.HEAD_20111506/lib/libstdbuf/libstdbuf.3	1970-01-01 01:00:00.000000000 +0100
 +++ src/lib/libstdbuf/libstdbuf.3	2011-08-04 18:47:04.000000000 +0200
 @@ -0,0 +1,111 @@
 +.\" Copyright (c) 2011 Jeremie Le Hen
 +.\" All rights reserved.
 +.\"
 +.\" Redistribution and use in source and binary forms, with or without
 +.\" modification, are permitted provided that the following conditions
 +.\" are met:
 +.\" 1. Redistributions of source code must retain the above copyright
 +.\"    notice, this list of conditions and the following disclaimer.
 +.\" 2. Redistributions in binary form must reproduce the above copyright
 +.\"    notice, this list of conditions and the following disclaimer in the
 +.\"    documentation and/or other materials provided with the distribution.
 +.\"
 +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 +.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 +.\" SUCH DAMAGE.
 +.\"
 +.\" $FreeBSD$
 +.\"
 +.Dd August 4, 2011
 +.Dt LIBSTDBUF 3
 +.Os
 +.Sh NAME
 +.Nm libstdbuf
 +.Nd preloaded library to change standard streams initial buffering
 +.Sh DESCRIPTION
 +The
 +.Nm
 +library is meant to be preloaded with the
 +.Ev LD_PRELOAD
 +environment variable to as to change the initial buffering
 +of standard input, standard output and standard error streams.
 +.Pp
 +Although you may load and configure this library manually,
 +an utility,
 +.Xr stdbuf 1 ,
 +can be used to run a command with the appropriate environment variables.
 +.Sh ENVIRONMENT
 +Each stream can be configured indepentently through the following
 +environment variables (values are defined below):
 +.Bl -tag -width size -offset indent
 +.It Ev STDBUF_0
 +Initial buffering definition for the standard input stream
 +.It Ev STDBUF_1
 +Initial buffering definition for the standard output stream
 +.It Ev STDBUF_2
 +Initial buffering definition for the standard error stream
 +.It Ev _STDBUF_I
 +GNU-compatible variable for
 +.Ev STDBUF_0
 +.It Ev _STDBUF_O
 +GNU-compatible variable equivalent to
 +.Ev STDBUF_1
 +.It Ev _STDBUF_E
 +GNU-compatible variable equivalent to
 +.Ev STDBUF_2
 +.El
 +.Pp
 +Each variable may take one of the following values:
 +.Bl -tag -width size -offset indent
 +.It Qq 0
 +unbuffered
 +.It Qq L
 +line buffered
 +.It Qq B
 +fully buffered with the default buffer size
 +.It Ar size
 +fully buffered with a buffer of
 +.Ar size
 +bytes
 +.El
 +.Sh EXAMPLE
 +In the following example, the stdout stream of the
 +.Xr awk 1
 +command
 +will be fully buffered by default because it does not refer
 +to a terminal.
 +.Nm
 +is used to force it to be line-buffered so
 +.Xr vmstat 8 Ns 's
 +output will not stall until the full buffer fills.
 +.Bd -literal -offset indent
 +# vmstat 1 | LD_PRELOAD=/usr/lib/libstdbuf.so \\
 +    STDBUF_1=L awk '$2 > 1 || $3 > 1' | cat -n
 +.Ed
 +.Pp
 +See also the manpage of
 +.Xr stdbuf 1
 +for a simpler way to do this.
 +.Sh HISTORY
 +The
 +.Nm
 +library first appeared in
 +.Fx 9.0 .
 +.Sh AUTHORS
 +.An -nosplit
 +The original idea of the
 +.Nm
 +command comes from
 +.An Padraig Brady
 +who implemented it in the GNU coreutils.
 +.An Jeremie Le Hen
 +implemented it on
 +.Fx .
 diff -urNp src.HEAD_20111506/lib/libstdbuf/stdbuf.c src/lib/libstdbuf/stdbuf.c
 --- src.HEAD_20111506/lib/libstdbuf/stdbuf.c	1970-01-01 01:00:00.000000000 +0100
 +++ src/lib/libstdbuf/stdbuf.c	2011-08-04 18:17:07.000000000 +0200
 @@ -0,0 +1,105 @@
 +/*-
 + * Copyright (c) 2011 Jeremie Le Hen
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 + * SUCH DAMAGE.
 + *
 + * $FreeBSD$
 + */
 +
 +#include <err.h>
 +#include <errno.h>
 +#include <limits.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <libutil.h>
 +
 +static const char *
 +stream_name(FILE *s)
 +{
 +	if (s == stdin)
 +		return "stdin";
 +	if (s == stdout)
 +		return "stdout";
 +	if (s == stderr)
 +		return "stderr";
 +	/* This should not happen. */
 +	abort();
 +}
 +
 +static void
 +change_buf(FILE *s, const char *bufmode)
 +{
 +	size_t bufsiz;
 +	uint64_t sizearg;
 +	int mode;
 +
 +	bufsiz = 0;
 +	if (bufmode[0] == '0' && bufmode[1] == '\0')
 +		mode = _IONBF;
 +	else if (bufmode[0] == 'L' && bufmode[1] == '\0')
 +		mode = _IOLBF;
 +	else if (bufmode[0] == 'B' && bufmode[1] == '\0') {
 +		mode = _IOFBF;
 +		bufsiz = 0;
 +	} else {
 +		errno = 0;
 +		if (expand_number(bufmode, &sizearg) == -1) {
 +			warn("Wrong buffer mode '%s' for %s", bufmode,
 +			    stream_name(s));
 +			return;
 +		}
 +		if (sizearg > SIZE_T_MAX) {
 +			warn("Buffer size too big for %s", stream_name(s));
 +			return;
 +		}
 +		mode = _IOFBF;
 +		bufsiz = (size_t)sizearg;
 +	}
 +	if (setvbuf(s, NULL, mode, bufsiz) != 0)
 +		warn("Cannot set buffer mode '%s' for %s", bufmode,
 +		    stream_name(s));
 +}
 +
 +__attribute__ ((constructor)) static void
 +stdbuf(void)
 +{
 +	char *i_mode, *o_mode, *e_mode;
 +
 +	i_mode = getenv("STDBUF_0");
 +	if (i_mode == NULL)
 +		i_mode = getenv("_STDBUF_I");
 +	o_mode = getenv("STDBUF_1");
 +	if (o_mode == NULL)
 +		o_mode = getenv("_STDBUF_O");
 +	e_mode = getenv("STDBUF_2");
 +	if (e_mode == NULL)
 +		e_mode = getenv("_STDBUF_E");
 +
 +	if (e_mode)
 +		change_buf(stderr, e_mode);
 +	if (i_mode)
 +		change_buf(stdin, i_mode);
 +	if (o_mode)
 +		change_buf(stdout, o_mode);
 +}
 diff -urNp src.HEAD_20111506/usr.bin/stdbuf/Makefile src/usr.bin/stdbuf/Makefile
 --- src.HEAD_20111506/usr.bin/stdbuf/Makefile	1970-01-01 01:00:00.000000000 +0100
 +++ src/usr.bin/stdbuf/Makefile	2011-08-02 19:16:30.000000000 +0200
 @@ -0,0 +1,8 @@
 +# $Id$
 +
 +PROG=   stdbuf
 +SRCS=   stdbuf.c
 +
 +WARNS?=	6
 +
 +.include <bsd.prog.mk>
 Files src.HEAD_20111506/usr.bin/stdbuf/sh.core and src/usr.bin/stdbuf/sh.core differ
 diff -urNp src.HEAD_20111506/usr.bin/stdbuf/stdbuf.1 src/usr.bin/stdbuf/stdbuf.1
 --- src.HEAD_20111506/usr.bin/stdbuf/stdbuf.1	1970-01-01 01:00:00.000000000 +0100
 +++ src/usr.bin/stdbuf/stdbuf.1	2011-08-04 18:46:35.000000000 +0200
 @@ -0,0 +1,124 @@
 +.\" Copyright (C) 2011 Jeremie Le Hen
 +.\" All rights reserved.
 +.\"
 +.\" Redistribution and use in source and binary forms, with or without
 +.\" modification, are permitted provided that the following conditions
 +.\" are met:
 +.\" 1. Redistributions of source code and documentation must retain the above
 +.\"    copyright notice, this list of conditions and the following disclaimer.
 +.\" 2. Redistributions in binary form must reproduce the above copyright
 +.\"    notice, this list of conditions and the following disclaimer in the
 +.\"    documentation and/or other materials provided with the distribution.
 +.\" 3. All advertising materials mentioning features or use of this software
 +.\"    must display the following acknowledgement:
 +.\"	This product includes software developed or owned by Caldera
 +.\"	International, Inc.
 +.\" 4. Neither the name of Caldera International, Inc. nor the names of other
 +.\"    contributors may be used to endorse or promote products derived from
 +.\"    this software without specific prior written permission.
 +.\"
 +.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
 +.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
 +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 +.\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
 +.\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 +.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 +.\" POSSIBILITY OF SUCH DAMAGE.
 +.\"
 +.\"	$FreeBSD: src/usr.bin/dc/dc.1,v 1.2 2010/01/22 23:50:46 delphij Exp $
 +.\"
 +.Dd August 4, 2011
 +.Dt STDBUF 1
 +.Os
 +.Sh NAME
 +.Nm stdbuf
 +.Nd change standard streams initial buffering
 +.Sh SYNOPSIS
 +.Nm
 +.Op Fl e Ar bufdef
 +.Op Fl i Ar bufdef
 +.Op Fl o Ar bufdef
 +.Op Ar command Op ...
 +.Sh DESCRIPTION
 +.Nm
 +is used to change the initial buffering of standard input,
 +standard output and/or standard error streams for
 +.Ar command .
 +It relies on
 +.Xr libstdbuf 3
 +which is loaded and configured by
 +.Nm
 +through environment variables.
 +.Pp
 +The options are as follows:
 +.Bl -tag -width Ds
 +.It Fl e Ar bufdef
 +Set initial buffering of the standard error stream for
 +.Ar command
 +as defined by
 +.Ar bufdef
 +.Pq see Sx BUFFER DEFINITION .
 +.It Fl i Ar bufdef
 +Set initial buffering of the standard input stream for
 +.Ar command
 +as defined by
 +.Ar bufdef
 +.Pq see Sx BUFFER DEFINITION .
 +.It Fl o Ar bufdef
 +Set initial buffering of the standard output stream for
 +.Ar command
 +as defined by
 +.Ar bufdef
 +.Pq see Sx BUFFER DEFINITION .
 +.El
 +.Sh BUFFER DEFINITION
 +Buffer definition is the same as in
 +.Xr libstdbuf 3 :
 +.Bl -tag -width size -offset indent
 +.It Qq 0
 +unbuffered
 +.It Qq L
 +line buffered
 +.It Qq B
 +fully buffered with the default buffer size
 +.It Ar size
 +fully buffered with a buffer of
 +.Ar size
 +bytes
 +.El
 +.Sh EXAMPLES
 +In the following example, the stdout stream of the
 +.Xr awk 1
 +command
 +will be fully buffered by default because it does not refer
 +to a terminal.
 +.Nm
 +is used to force it to be line-buffered so
 +.Xr vmstat 8 Ns 's
 +output will not stall until the full buffer fills.
 +.Bd -literal -offset indent
 +# vmstat 1 | stdbuf -o L awk '$2 > 1 || $3 > 1' | cat -n
 +.Ed
 +.Sh SEE ALSO
 +.Xr libstdbuf 3 ,
 +.Xr setvbuf 3
 +.Sh HISTORY
 +The
 +.Nm
 +utility first appeared in
 +.Fx 9.0 .
 +.Sh AUTHORS
 +.An -nosplit
 +The original idea of the
 +.Nm
 +command comes from 
 +.An Padraig Brady
 +who implemented it in the GNU coreutils.
 +.An Jeremie Le Hen
 +implemented it on
 +.Fx .
 diff -urNp src.HEAD_20111506/usr.bin/stdbuf/stdbuf.c src/usr.bin/stdbuf/stdbuf.c
 --- src.HEAD_20111506/usr.bin/stdbuf/stdbuf.c	1970-01-01 01:00:00.000000000 +0100
 +++ src/usr.bin/stdbuf/stdbuf.c	2011-08-04 18:17:50.000000000 +0200
 @@ -0,0 +1,107 @@
 +/*-
 + * Copyright (c) 2011 Jeremie Le Hen
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 + * SUCH DAMAGE.
 + *
 + * $FreeBSD$
 + */
 +
 +#include <err.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <unistd.h>
 +
 +#define	LIBSTDBUF	"/usr/lib/libstdbuf.so"
 +
 +extern char *__progname;
 +
 +static void usage(int);
 +
 +static void
 +usage(int s)
 +{
 +	
 +	fprintf(stderr, "Usage: %s [-e bufdef] [-i bufdef] [-o bufdef] "
 +	    "<command> [args ...]\n", __progname);
 +	fprintf(stderr, "  ``bufdef'' being:\n");
 +	fprintf(stderr, "    - \"0\" to disable buffering;\n");
 +	fprintf(stderr, "    - \"L\" to set line-buffering;\n");
 +	fprintf(stderr, "    - <size> to set full-buffering.\n");
 +	exit(s);
 +}
 +
 +int
 +main(int argc, char *argv[])
 +{
 +	int i;
 +	char *ibuf = NULL, *obuf = NULL, *ebuf = NULL;
 +	char *preload0, *preload1;
 +
 +	while ((i = getopt(argc, argv, ":e:i:o:")) != -1) {
 +		switch (i) {
 +		case 'e':
 +			ebuf = optarg;
 +			break;
 +		case 'i':
 +			ibuf = optarg;
 +			break;
 +		case 'o':
 +			obuf = optarg;
 +			break;
 +		case ':':
 +			warnx("Missing argument for option -%c", optopt);
 +			usage(1);
 +			break;
 +		case '?':
 +		default:
 +			warnx("Unknown option -%c", optopt);
 +			usage(1);
 +			break;
 +		}
 +	}
 +	argc -= optind;
 +	argv += optind;
 +
 +	if (ibuf != NULL && setenv("STDBUF_0", ibuf, 1) == -1)
 +		warn("Failed to set environment variable: %s=%s",
 +		    "STDBUF_0", ibuf);
 +	if (obuf != NULL && setenv("STDBUF_1", obuf, 1) == -1)
 +		warn("Failed to set environment variable: %s=%s",
 +		    "STDBUF_1", obuf);
 +	if (ebuf != NULL && setenv("STDBUF_2", ebuf, 1) == -1)
 +		warn("Failed to set environment variable: %s=%s",
 +		    "STDBUF_2", ebuf);
 +
 +	preload0 = getenv("LD_PRELOAD");
 +	if (preload0 == NULL)
 +		i = asprintf(&preload1, "LD_PRELOAD=" LIBSTDBUF);
 +	else
 +		i = asprintf(&preload1, "LD_PRELOAD=%s:%s", preload0,
 +		    LIBSTDBUF);
 +
 +	if (i < 0 || putenv(preload1) == -1)
 +		warn("Failed to set environment variable: %s", preload1);
 +
 +	execvp(argv[0], argv);
 +	err(2, "%s", argv[0]);
 +}
 
 --n8g4imXOkfNTN/H1--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202171800.q1HI0VrW090362>