1*ec21d9fbSAaron LI /*-
2*ec21d9fbSAaron LI * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*ec21d9fbSAaron LI *
4*ec21d9fbSAaron LI * Copyright (c) 2012 Jeremie Le Hen <jlh@FreeBSD.org>
5*ec21d9fbSAaron LI * All rights reserved.
6*ec21d9fbSAaron LI *
7*ec21d9fbSAaron LI * Redistribution and use in source and binary forms, with or without
8*ec21d9fbSAaron LI * modification, are permitted provided that the following conditions
9*ec21d9fbSAaron LI * are met:
10*ec21d9fbSAaron LI * 1. Redistributions of source code must retain the above copyright
11*ec21d9fbSAaron LI * notice, this list of conditions and the following disclaimer.
12*ec21d9fbSAaron LI * 2. Redistributions in binary form must reproduce the above copyright
13*ec21d9fbSAaron LI * notice, this list of conditions and the following disclaimer in the
14*ec21d9fbSAaron LI * documentation and/or other materials provided with the distribution.
15*ec21d9fbSAaron LI *
16*ec21d9fbSAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*ec21d9fbSAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*ec21d9fbSAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*ec21d9fbSAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*ec21d9fbSAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*ec21d9fbSAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*ec21d9fbSAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*ec21d9fbSAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*ec21d9fbSAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*ec21d9fbSAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*ec21d9fbSAaron LI * SUCH DAMAGE.
27*ec21d9fbSAaron LI *
28*ec21d9fbSAaron LI * $FreeBSD$
29*ec21d9fbSAaron LI */
30*ec21d9fbSAaron LI
31*ec21d9fbSAaron LI #include <err.h>
32*ec21d9fbSAaron LI #include <errno.h>
33*ec21d9fbSAaron LI #include <limits.h>
34*ec21d9fbSAaron LI #include <stdio.h>
35*ec21d9fbSAaron LI #include <stdlib.h>
36*ec21d9fbSAaron LI #include <string.h>
37*ec21d9fbSAaron LI
38*ec21d9fbSAaron LI static const char *
stream_name(FILE * s)39*ec21d9fbSAaron LI stream_name(FILE *s)
40*ec21d9fbSAaron LI {
41*ec21d9fbSAaron LI
42*ec21d9fbSAaron LI if (s == stdin)
43*ec21d9fbSAaron LI return "stdin";
44*ec21d9fbSAaron LI if (s == stdout)
45*ec21d9fbSAaron LI return "stdout";
46*ec21d9fbSAaron LI if (s == stderr)
47*ec21d9fbSAaron LI return "stderr";
48*ec21d9fbSAaron LI /* This should not happen. */
49*ec21d9fbSAaron LI abort();
50*ec21d9fbSAaron LI }
51*ec21d9fbSAaron LI
52*ec21d9fbSAaron LI static void
change_buf(FILE * s,const char * bufmode)53*ec21d9fbSAaron LI change_buf(FILE *s, const char *bufmode)
54*ec21d9fbSAaron LI {
55*ec21d9fbSAaron LI char *unit;
56*ec21d9fbSAaron LI size_t bufsize;
57*ec21d9fbSAaron LI int mode;
58*ec21d9fbSAaron LI
59*ec21d9fbSAaron LI bufsize = 0;
60*ec21d9fbSAaron LI if (bufmode[0] == '0' && bufmode[1] == '\0')
61*ec21d9fbSAaron LI mode = _IONBF;
62*ec21d9fbSAaron LI else if (bufmode[0] == 'L' && bufmode[1] == '\0')
63*ec21d9fbSAaron LI mode = _IOLBF;
64*ec21d9fbSAaron LI else if (bufmode[0] == 'B' && bufmode[1] == '\0') {
65*ec21d9fbSAaron LI mode = _IOFBF;
66*ec21d9fbSAaron LI bufsize = 0;
67*ec21d9fbSAaron LI } else {
68*ec21d9fbSAaron LI /*
69*ec21d9fbSAaron LI * This library being preloaded, depending on libutil
70*ec21d9fbSAaron LI * would lead to excessive namespace pollution.
71*ec21d9fbSAaron LI * Thus we do not use expand_number().
72*ec21d9fbSAaron LI */
73*ec21d9fbSAaron LI errno = 0;
74*ec21d9fbSAaron LI bufsize = strtol(bufmode, &unit, 0);
75*ec21d9fbSAaron LI if (errno == EINVAL || errno == ERANGE || unit == bufmode)
76*ec21d9fbSAaron LI warn("Wrong buffer mode '%s' for %s", bufmode,
77*ec21d9fbSAaron LI stream_name(s));
78*ec21d9fbSAaron LI switch (*unit) {
79*ec21d9fbSAaron LI case 'G':
80*ec21d9fbSAaron LI bufsize *= 1024 * 1024 * 1024;
81*ec21d9fbSAaron LI break;
82*ec21d9fbSAaron LI case 'M':
83*ec21d9fbSAaron LI bufsize *= 1024 * 1024;
84*ec21d9fbSAaron LI break;
85*ec21d9fbSAaron LI case 'k':
86*ec21d9fbSAaron LI bufsize *= 1024;
87*ec21d9fbSAaron LI break;
88*ec21d9fbSAaron LI case '\0':
89*ec21d9fbSAaron LI break;
90*ec21d9fbSAaron LI default:
91*ec21d9fbSAaron LI warnx("Unknown suffix '%c' for %s", *unit,
92*ec21d9fbSAaron LI stream_name(s));
93*ec21d9fbSAaron LI return;
94*ec21d9fbSAaron LI }
95*ec21d9fbSAaron LI mode = _IOFBF;
96*ec21d9fbSAaron LI }
97*ec21d9fbSAaron LI if (setvbuf(s, NULL, mode, bufsize) != 0)
98*ec21d9fbSAaron LI warn("Cannot set buffer mode '%s' for %s", bufmode,
99*ec21d9fbSAaron LI stream_name(s));
100*ec21d9fbSAaron LI }
101*ec21d9fbSAaron LI
102*ec21d9fbSAaron LI __attribute__ ((constructor)) static void
stdbuf(void)103*ec21d9fbSAaron LI stdbuf(void)
104*ec21d9fbSAaron LI {
105*ec21d9fbSAaron LI char *i_mode, *o_mode, *e_mode;
106*ec21d9fbSAaron LI
107*ec21d9fbSAaron LI i_mode = getenv("_STDBUF_I");
108*ec21d9fbSAaron LI o_mode = getenv("_STDBUF_O");
109*ec21d9fbSAaron LI e_mode = getenv("_STDBUF_E");
110*ec21d9fbSAaron LI
111*ec21d9fbSAaron LI if (e_mode != NULL)
112*ec21d9fbSAaron LI change_buf(stderr, e_mode);
113*ec21d9fbSAaron LI if (i_mode != NULL)
114*ec21d9fbSAaron LI change_buf(stdin, i_mode);
115*ec21d9fbSAaron LI if (o_mode != NULL)
116*ec21d9fbSAaron LI change_buf(stdout, o_mode);
117*ec21d9fbSAaron LI }
118