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