1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1997-2005
5  *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 /*
36  * Shell output routines.  We use our own output routines because:
37  *	When a builtin command is interrupted we have to discard
38  *		any pending output.
39  *	When a builtin command appears in back quotes, we want to
40  *		save the output of the command in a region obtained
41  *		via malloc, rather than doing a fork and reading the
42  *		output of the command via a pipe.
43  *	Our output routines may be smaller than the stdio routines.
44  */
45 
46 #include <sys/types.h>		/* quad_t */
47 #include <sys/param.h>		/* BSD4_4 */
48 #include <sys/ioctl.h>
49 
50 #include <stdio.h>	/* defines BUFSIZ */
51 #include <string.h>
52 #include <unistd.h>
53 #include <stdlib.h>
54 #ifdef USE_GLIBC_STDIO
55 #include <fcntl.h>
56 #endif
57 #include <limits.h>
58 
59 #include "shell.h"
60 #include "syntax.h"
61 #include "options.h"
62 #include "output.h"
63 #include "memalloc.h"
64 #include "error.h"
65 #include "main.h"
66 #include "system.h"
67 
68 
69 #define OUTBUFSIZ BUFSIZ
70 #define MEM_OUT -3		/* output to dynamically allocated memory */
71 
72 
73 #ifdef USE_GLIBC_STDIO
74 struct output output = {
75 	stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 1, flags: 0
76 };
77 struct output errout = {
78 	stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0
79 }
80 #ifdef notyet
81 struct output memout = {
82 	stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0
83 };
84 #endif
85 #else
86 struct output output = {
87 	nextc: 0, end: 0, buf: 0, bufsize: OUTBUFSIZ, fd: 1, flags: 0
88 };
89 struct output errout = {
90 	nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0
91 };
92 struct output preverrout;
93 #ifdef notyet
94 struct output memout = {
95 	nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0
96 };
97 #endif
98 #endif
99 struct output *out1 = &output;
100 struct output *out2 = &errout;
101 
102 
103 static int xvsnprintf(char *, size_t, const char *, va_list);
104 
105 
106 #ifdef mkinit
107 
108 INCLUDE "output.h"
109 INCLUDE "memalloc.h"
110 
111 INIT {
112 #ifdef USE_GLIBC_STDIO
113 	initstreams();
114 #endif
115 }
116 
117 RESET {
118 #ifdef notyet
119 	out1 = &output;
120 	out2 = &errout;
121 #ifdef USE_GLIBC_STDIO
122 	if (memout.stream != NULL)
123 		__closememout();
124 #endif
125 	if (memout.buf != NULL) {
126 		ckfree(memout.buf);
127 		memout.buf = NULL;
128 	}
129 #endif
130 }
131 
132 #endif
133 
134 
135 void
outmem(const char * p,size_t len,struct output * dest)136 outmem(const char *p, size_t len, struct output *dest)
137 {
138 #ifdef USE_GLIBC_STDIO
139 	INTOFF;
140 	fwrite(p, 1, len, dest->stream);
141 	INTON;
142 #else
143 	size_t bufsize;
144 	size_t offset;
145 	size_t nleft;
146 
147 	nleft = dest->end - dest->nextc;
148 	if (likely(nleft >= len)) {
149 buffered:
150 		dest->nextc = mempcpy(dest->nextc, p, len);
151 		return;
152 	}
153 
154 	bufsize = dest->bufsize;
155 	if (!bufsize) {
156 		;
157 	} else if (dest->buf == NULL) {
158 #ifdef notyet
159 		if (dest->fd == MEM_OUT && len > bufsize) {
160 			bufsize = len;
161 		}
162 #endif
163 		offset = 0;
164 #ifdef notyet
165 		goto alloc;
166 	} else if (dest->fd == MEM_OUT) {
167 		offset = bufsize;
168 		if (bufsize >= len) {
169 			bufsize <<= 1;
170 		} else {
171 			bufsize += len;
172 		}
173 		if (bufsize < offset)
174 			goto err;
175 alloc:
176 #endif
177 		INTOFF;
178 		dest->buf = ckrealloc(dest->buf, bufsize);
179 		dest->bufsize = bufsize;
180 		dest->end = dest->buf + bufsize;
181 		dest->nextc = dest->buf + offset;
182 		INTON;
183 	} else {
184 		flushout(dest);
185 	}
186 
187 	nleft = dest->end - dest->nextc;
188 	if (nleft > len)
189 		goto buffered;
190 
191 	if ((xwrite(dest->fd, p, len))) {
192 #ifdef notyet
193 err:
194 #endif
195 		dest->flags |= OUTPUT_ERR;
196 	}
197 #endif
198 }
199 
200 
201 void
outstr(const char * p,struct output * file)202 outstr(const char *p, struct output *file)
203 {
204 #ifdef USE_GLIBC_STDIO
205 	INTOFF;
206 	fputs(p, file->stream);
207 	INTON;
208 #else
209 	size_t len;
210 
211 	len = strlen(p);
212 	outmem(p, len, file);
213 #endif
214 }
215 
216 
217 #ifndef USE_GLIBC_STDIO
218 
219 
220 void
outcslow(int c,struct output * dest)221 outcslow(int c, struct output *dest)
222 {
223 	char buf = c;
224 	outmem(&buf, 1, dest);
225 }
226 #endif
227 
228 
229 void
flushall(void)230 flushall(void)
231 {
232 	flushout(&output);
233 #ifdef FLUSHERR
234 	flushout(&errout);
235 #endif
236 }
237 
238 
239 void
flushout(struct output * dest)240 flushout(struct output *dest)
241 {
242 #ifdef USE_GLIBC_STDIO
243 	INTOFF;
244 	fflush(dest->stream);
245 	INTON;
246 #else
247 	size_t len;
248 
249 	len = dest->nextc - dest->buf;
250 	if (!len || dest->fd < 0)
251 		return;
252 	dest->nextc = dest->buf;
253 	if ((xwrite(dest->fd, dest->buf, len)))
254 		dest->flags |= OUTPUT_ERR;
255 #endif
256 }
257 
258 
259 void
outfmt(struct output * file,const char * fmt,...)260 outfmt(struct output *file, const char *fmt, ...)
261 {
262 	va_list ap;
263 
264 	va_start(ap, fmt);
265 	doformat(file, fmt, ap);
266 	va_end(ap);
267 }
268 
269 
270 void
out1fmt(const char * fmt,...)271 out1fmt(const char *fmt, ...)
272 {
273 	va_list ap;
274 
275 	va_start(ap, fmt);
276 	doformat(out1, fmt, ap);
277 	va_end(ap);
278 }
279 
280 
281 int
fmtstr(char * outbuf,size_t length,const char * fmt,...)282 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
283 {
284 	va_list ap;
285 	int ret;
286 
287 	va_start(ap, fmt);
288 	ret = xvsnprintf(outbuf, length, fmt, ap);
289 	va_end(ap);
290 	return ret;
291 }
292 
293 
xvasprintf(char ** sp,size_t size,const char * f,va_list ap)294 static int xvasprintf(char **sp, size_t size, const char *f, va_list ap)
295 {
296 	char *s;
297 	int len;
298 	va_list ap2;
299 
300 	va_copy(ap2, ap);
301 	len = xvsnprintf(*sp, size, f, ap2);
302 	va_end(ap2);
303 	if (len < 0)
304 		sh_error("xvsnprintf failed");
305 	if (len < size)
306 		return len;
307 
308 	s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
309 	*sp = s;
310 	len = xvsnprintf(s, len + 1, f, ap);
311 	return len;
312 }
313 
314 
xasprintf(char ** sp,const char * f,...)315 int xasprintf(char **sp, const char *f, ...)
316 {
317 	va_list ap;
318 	int ret;
319 
320 	va_start(ap, f);
321 	ret = xvasprintf(sp, 0, f, ap);
322 	va_end(ap);
323 	return ret;
324 }
325 
326 
327 #ifndef USE_GLIBC_STDIO
328 void
doformat(struct output * dest,const char * f,va_list ap)329 doformat(struct output *dest, const char *f, va_list ap)
330 {
331 	struct stackmark smark;
332 	char *s;
333 	int len;
334 	int olen;
335 
336 	setstackmark(&smark);
337 	s = dest->nextc;
338 	olen = dest->end - dest->nextc;
339 	len = xvasprintf(&s, olen, f, ap);
340 	if (likely(olen > len)) {
341 		dest->nextc += len;
342 		goto out;
343 	}
344 	outmem(s, len, dest);
345 out:
346 	popstackmark(&smark);
347 }
348 #endif
349 
350 
settitle(const char * title)351 void settitle(const char* title) {
352 	if (!iflag || !isatty(0))
353 		return;
354 	char *term = getenv("TERM");
355 	if (term == NULL || strcmp(term, "dumb") == 0 || strcmp(term, "uart") == 0) {
356 		return;
357 	}
358 	char str[16];
359 	int n = snprintf(str, sizeof(str) - 1, "\033]2;%s", title);
360 	if (n < 0) {
361 		return; // error
362 	} else if ((size_t)n >= sizeof(str) - 1) {
363 		n = sizeof(str) - 2; // truncated
364 	}
365 	str[n] = '\007';
366 	str[n+1] = '\0';
367 	out2str(str);
368 }
369 
370 
371 /*
372  * Version of write which resumes after a signal is caught.
373  */
374 
375 int
xwrite(int fd,const void * p,size_t n)376 xwrite(int fd, const void *p, size_t n)
377 {
378 	const char *buf = p;
379 
380 	while (n) {
381 		ssize_t i;
382 		size_t m;
383 
384 		m = n;
385 		if (m > SSIZE_MAX)
386 			m = SSIZE_MAX;
387 		do {
388 			i = write(fd, buf, m);
389 		} while (i < 0 && errno == EINTR);
390 		if (i < 0)
391 			return -1;
392 		buf += i;
393 		n -= i;
394 	}
395 	return 0;
396 }
397 
398 
399 #ifdef notyet
400 #ifdef USE_GLIBC_STDIO
initstreams()401 void initstreams() {
402 	output.stream = stdout;
403 	errout.stream = stderr;
404 }
405 
406 
407 void
openmemout(void)408 openmemout(void) {
409 	INTOFF;
410 	memout.stream = open_memstream(&memout.buf, &memout.bufsize);
411 	INTON;
412 }
413 
414 
415 int
__closememout(void)416 __closememout(void) {
417 	int error;
418 	error = fclose(memout.stream);
419 	memout.stream = NULL;
420 	return error;
421 }
422 #endif
423 #endif
424 
425 
426 static int
xvsnprintf(char * outbuf,size_t length,const char * fmt,va_list ap)427 xvsnprintf(char *outbuf, size_t length, const char *fmt, va_list ap)
428 {
429 	int ret;
430 
431 #ifdef __sun
432 	/*
433 	 * vsnprintf() on older versions of Solaris returns -1 when
434 	 * passed a length of 0.  To avoid this, use a dummy
435 	 * 1-character buffer instead.
436 	 */
437 	char dummy[1];
438 
439 	if (length == 0) {
440 		outbuf = dummy;
441 		length = sizeof(dummy);
442 	}
443 #endif
444 
445 	INTOFF;
446 	ret = vsnprintf(outbuf, length, fmt, ap);
447 	INTON;
448 	return ret;
449 }
450