Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/src/libstdbuf.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||
---|---|---|---|---|---|---|---|---|
1 | /* libstdbuf -- a shared lib to preload to setup stdio buffering for a command | - | ||||||
2 | Copyright (C) 2009-2018 Free Software Foundation, Inc. | - | ||||||
3 | - | |||||||
4 | This program is free software: you can redistribute it and/or modify | - | ||||||
5 | it under the terms of the GNU General Public License as published by | - | ||||||
6 | the Free Software Foundation, either version 3 of the License, or | - | ||||||
7 | (at your option) any later version. | - | ||||||
8 | - | |||||||
9 | This program is distributed in the hope that it will be useful, | - | ||||||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | ||||||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | ||||||
12 | GNU General Public License for more details. | - | ||||||
13 | - | |||||||
14 | You should have received a copy of the GNU General Public License | - | ||||||
15 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ | - | ||||||
16 | - | |||||||
17 | /* Written by Pádraig Brady. LD_PRELOAD idea from Brian Dessent. */ | - | ||||||
18 | - | |||||||
19 | #include <config.h> | - | ||||||
20 | #include <stdio.h> | - | ||||||
21 | #include "system.h" | - | ||||||
22 | - | |||||||
23 | /* Deactivate config.h's "rpl_"-prefixed definition of malloc, | - | ||||||
24 | since we don't link gnulib here, and the replacement isn't | - | ||||||
25 | needed in this case as we don't malloc(0). */ | - | ||||||
26 | #undef malloc | - | ||||||
27 | - | |||||||
28 | /* Note currently for glibc (2.3.5) the following call does not change | - | ||||||
29 | the buffer size, and more problematically does not give any indication | - | ||||||
30 | that the new size request was ignored: | - | ||||||
31 | - | |||||||
32 | setvbuf (stdout, (char*)NULL, _IOFBF, 8192); | - | ||||||
33 | - | |||||||
34 | The ISO C99 standard section 7.19.5.6 on the setvbuf function says: | - | ||||||
35 | - | |||||||
36 | ... If buf is not a null pointer, the array it points to _may_ be used | - | ||||||
37 | instead of a buffer allocated by the setvbuf function and the argument | - | ||||||
38 | size specifies the size of the array; otherwise, size _may_ determine | - | ||||||
39 | the size of a buffer allocated by the setvbuf function. ... | - | ||||||
40 | - | |||||||
41 | Obviously some interpret the above to mean setvbuf(....,size) | - | ||||||
42 | is only a hint from the application which I don't agree with. | - | ||||||
43 | - | |||||||
44 | FreeBSD's libc seems more sensible in this regard. From the man page: | - | ||||||
45 | - | |||||||
46 | The size argument may be given as zero to obtain deferred optimal-size | - | ||||||
47 | buffer allocation as usual. If it is not zero, then except for | - | ||||||
48 | unbuffered files, the buf argument should point to a buffer at least size | - | ||||||
49 | bytes long; this buffer will be used instead of the current buffer. (If | - | ||||||
50 | the size argument is not zero but buf is NULL, a buffer of the given size | - | ||||||
51 | will be allocated immediately, and released on close. This is an extension | - | ||||||
52 | to ANSI C; portable code should use a size of 0 with any NULL buffer.) | - | ||||||
53 | -------------------- | - | ||||||
54 | Another issue is that on glibc-2.7 the following doesn't buffer | - | ||||||
55 | the first write if it's greater than 1 byte. | - | ||||||
56 | - | |||||||
57 | setvbuf(stdout,buf,_IOFBF,127); | - | ||||||
58 | - | |||||||
59 | Now the POSIX standard says that "allocating a buffer of size bytes does | - | ||||||
60 | not necessarily imply that all of size bytes are used for the buffer area". | - | ||||||
61 | However I think it's just a buggy implementation due to the various | - | ||||||
62 | inconsistencies with write sizes and subsequent writes. */ | - | ||||||
63 | - | |||||||
64 | static const char * | - | ||||||
65 | fileno_to_name (const int fd) | - | ||||||
66 | { | - | ||||||
67 | const char *ret = NULL; | - | ||||||
68 | - | |||||||
69 | switch (fd) | - | ||||||
70 | { | - | ||||||
71 | case 0: never executed: case 0: | 0 | ||||||
72 | ret = "stdin"; | - | ||||||
73 | break; never executed: break; | 0 | ||||||
74 | case 1: never executed: case 1: | 0 | ||||||
75 | ret = "stdout"; | - | ||||||
76 | break; never executed: break; | 0 | ||||||
77 | case 2: never executed: case 2: | 0 | ||||||
78 | ret = "stderr"; | - | ||||||
79 | break; never executed: break; | 0 | ||||||
80 | default: never executed: default: | 0 | ||||||
81 | ret = "unknown"; | - | ||||||
82 | break; never executed: break; | 0 | ||||||
83 | } | - | ||||||
84 | - | |||||||
85 | return ret; never executed: return ret; | 0 | ||||||
86 | } | - | ||||||
87 | - | |||||||
88 | static void | - | ||||||
89 | apply_mode (FILE *stream, const char *mode) | - | ||||||
90 | { | - | ||||||
91 | char *buf = NULL; | - | ||||||
92 | int setvbuf_mode; | - | ||||||
93 | size_t size = 0; | - | ||||||
94 | - | |||||||
95 | if (*mode == '0')
| 4 | ||||||
96 | setvbuf_mode = _IONBF; executed 4 times by 1 test: setvbuf_mode = 2 ; Executed by:
| 4 | ||||||
97 | else if (*mode == 'L')
| 2 | ||||||
98 | setvbuf_mode = _IOLBF; /* FIXME: should we allow 1ML */ executed 2 times by 1 test: setvbuf_mode = 1 ; Executed by:
| 2 | ||||||
99 | else | - | ||||||
100 | { | - | ||||||
101 | setvbuf_mode = _IOFBF; | - | ||||||
102 | verify (SIZE_MAX <= ULONG_MAX); | - | ||||||
103 | size = strtoul (mode, NULL, 10); | - | ||||||
104 | if (size > 0)
| 0-2 | ||||||
105 | { | - | ||||||
106 | if (!(buf = malloc (size))) /* will be freed by fclose() */
| 0-2 | ||||||
107 | { | - | ||||||
108 | /* We could defer the allocation to libc, however since | - | ||||||
109 | glibc currently ignores the combination of NULL buffer | - | ||||||
110 | with non zero size, we'll fail here. */ | - | ||||||
111 | fprintf (stderr, | - | ||||||
112 | _("failed to allocate a %" PRIuMAX | - | ||||||
113 | " byte stdio buffer\n"), (uintmax_t) size); | - | ||||||
114 | return; never executed: return; | 0 | ||||||
115 | } | - | ||||||
116 | } executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||
117 | else | - | ||||||
118 | { | - | ||||||
119 | fprintf (stderr, _("invalid buffering mode %s for %s\n"), | - | ||||||
120 | mode, fileno_to_name (fileno (stream))); | - | ||||||
121 | return; never executed: return; | 0 | ||||||
122 | } | - | ||||||
123 | } | - | ||||||
124 | - | |||||||
125 | if (setvbuf (stream, buf, setvbuf_mode, size) != 0)
| 0-8 | ||||||
126 | { | - | ||||||
127 | fprintf (stderr, _("could not set buffering of %s to mode %s\n"), | - | ||||||
128 | fileno_to_name (fileno (stream)), mode); | - | ||||||
129 | free (buf); | - | ||||||
130 | } never executed: end of block | 0 | ||||||
131 | } executed 8 times by 1 test: end of block Executed by:
| 8 | ||||||
132 | - | |||||||
133 | /* Use __attribute to avoid elision of __attribute__ on SUNPRO_C etc. */ | - | ||||||
134 | static void __attribute ((constructor)) | - | ||||||
135 | stdbuf (void) | - | ||||||
136 | { | - | ||||||
137 | char *e_mode = getenv ("_STDBUF_E"); | - | ||||||
138 | char *i_mode = getenv ("_STDBUF_I"); | - | ||||||
139 | char *o_mode = getenv ("_STDBUF_O"); | - | ||||||
140 | if (e_mode) /* Do first so can write errors to stderr */
| 1-5 | ||||||
141 | apply_mode (stderr, e_mode); executed 1 time by 1 test: apply_mode ( stderr , e_mode); Executed by:
| 1 | ||||||
142 | if (i_mode)
| 1-5 | ||||||
143 | apply_mode (stdin, i_mode); executed 1 time by 1 test: apply_mode ( stdin , i_mode); Executed by:
| 1 | ||||||
144 | if (o_mode)
| 0-6 | ||||||
145 | apply_mode (stdout, o_mode); executed 6 times by 1 test: apply_mode ( stdout , o_mode); Executed by:
| 6 | ||||||
146 | } executed 6 times by 1 test: end of block Executed by:
| 6 | ||||||
Source code | Switch to Preprocessed file |