output.c revision 1556
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
351556Srgrimes */
361556Srgrimes
371556Srgrimes#ifndef lint
381556Srgrimesstatic char sccsid[] = "@(#)output.c	8.1 (Berkeley) 5/31/93";
391556Srgrimes#endif /* not lint */
401556Srgrimes
411556Srgrimes/*
421556Srgrimes * Shell output routines.  We use our own output routines because:
431556Srgrimes *	When a builtin command is interrupted we have to discard
441556Srgrimes *		any pending output.
451556Srgrimes *	When a builtin command appears in back quotes, we want to
461556Srgrimes *		save the output of the command in a region obtained
471556Srgrimes *		via malloc, rather than doing a fork and reading the
481556Srgrimes *		output of the command via a pipe.
491556Srgrimes *	Our output routines may be smaller than the stdio routines.
501556Srgrimes */
511556Srgrimes
521556Srgrimes#include <stdio.h>	/* defines BUFSIZ */
531556Srgrimes#include "shell.h"
541556Srgrimes#include "syntax.h"
551556Srgrimes#include "output.h"
561556Srgrimes#include "memalloc.h"
571556Srgrimes#include "error.h"
581556Srgrimes#ifdef __STDC__
591556Srgrimes#include "stdarg.h"
601556Srgrimes#else
611556Srgrimes#include <varargs.h>
621556Srgrimes#endif
631556Srgrimes#include <errno.h>
641556Srgrimes
651556Srgrimes
661556Srgrimes#define OUTBUFSIZ BUFSIZ
671556Srgrimes#define BLOCK_OUT -2		/* output to a fixed block of memory */
681556Srgrimes#define MEM_OUT -3		/* output to dynamically allocated memory */
691556Srgrimes#define OUTPUT_ERR 01		/* error occurred on output */
701556Srgrimes
711556Srgrimes
721556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
731556Srgrimesstruct output errout = {NULL, 0, NULL, 100, 2, 0};;
741556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
751556Srgrimesstruct output *out1 = &output;
761556Srgrimesstruct output *out2 = &errout;
771556Srgrimes
781556Srgrimes
791556Srgrimes
801556Srgrimes#ifdef mkinit
811556Srgrimes
821556SrgrimesINCLUDE "output.h"
831556SrgrimesINCLUDE "memalloc.h"
841556Srgrimes
851556SrgrimesRESET {
861556Srgrimes	out1 = &output;
871556Srgrimes	out2 = &errout;
881556Srgrimes	if (memout.buf != NULL) {
891556Srgrimes		ckfree(memout.buf);
901556Srgrimes		memout.buf = NULL;
911556Srgrimes	}
921556Srgrimes}
931556Srgrimes
941556Srgrimes#endif
951556Srgrimes
961556Srgrimes
971556Srgrimes#ifdef notdef	/* no longer used */
981556Srgrimes/*
991556Srgrimes * Set up an output file to write to memory rather than a file.
1001556Srgrimes */
1011556Srgrimes
1021556Srgrimesvoid
1031556Srgrimesopen_mem(block, length, file)
1041556Srgrimes	char *block;
1051556Srgrimes	int length;
1061556Srgrimes	struct output *file;
1071556Srgrimes	{
1081556Srgrimes	file->nextc = block;
1091556Srgrimes	file->nleft = --length;
1101556Srgrimes	file->fd = BLOCK_OUT;
1111556Srgrimes	file->flags = 0;
1121556Srgrimes}
1131556Srgrimes#endif
1141556Srgrimes
1151556Srgrimes
1161556Srgrimesvoid
1171556Srgrimesout1str(p)
1181556Srgrimes	char *p;
1191556Srgrimes	{
1201556Srgrimes	outstr(p, out1);
1211556Srgrimes}
1221556Srgrimes
1231556Srgrimes
1241556Srgrimesvoid
1251556Srgrimesout2str(p)
1261556Srgrimes	char *p;
1271556Srgrimes	{
1281556Srgrimes	outstr(p, out2);
1291556Srgrimes}
1301556Srgrimes
1311556Srgrimes
1321556Srgrimesvoid
1331556Srgrimesoutstr(p, file)
1341556Srgrimes	register char *p;
1351556Srgrimes	register struct output *file;
1361556Srgrimes	{
1371556Srgrimes	while (*p)
1381556Srgrimes		outc(*p++, file);
1391556Srgrimes	if (file == out2)
1401556Srgrimes		flushout(file);
1411556Srgrimes}
1421556Srgrimes
1431556Srgrimes
1441556Srgrimeschar out_junk[16];
1451556Srgrimes
1461556Srgrimes
1471556Srgrimesvoid
1481556Srgrimesemptyoutbuf(dest)
1491556Srgrimes	struct output *dest;
1501556Srgrimes	{
1511556Srgrimes	int offset;
1521556Srgrimes
1531556Srgrimes	if (dest->fd == BLOCK_OUT) {
1541556Srgrimes		dest->nextc = out_junk;
1551556Srgrimes		dest->nleft = sizeof out_junk;
1561556Srgrimes		dest->flags |= OUTPUT_ERR;
1571556Srgrimes	} else if (dest->buf == NULL) {
1581556Srgrimes		INTOFF;
1591556Srgrimes		dest->buf = ckmalloc(dest->bufsize);
1601556Srgrimes		dest->nextc = dest->buf;
1611556Srgrimes		dest->nleft = dest->bufsize;
1621556Srgrimes		INTON;
1631556Srgrimes	} else if (dest->fd == MEM_OUT) {
1641556Srgrimes		offset = dest->bufsize;
1651556Srgrimes		INTOFF;
1661556Srgrimes		dest->bufsize <<= 1;
1671556Srgrimes		dest->buf = ckrealloc(dest->buf, dest->bufsize);
1681556Srgrimes		dest->nleft = dest->bufsize - offset;
1691556Srgrimes		dest->nextc = dest->buf + offset;
1701556Srgrimes		INTON;
1711556Srgrimes	} else {
1721556Srgrimes		flushout(dest);
1731556Srgrimes	}
1741556Srgrimes	dest->nleft--;
1751556Srgrimes}
1761556Srgrimes
1771556Srgrimes
1781556Srgrimesvoid
1791556Srgrimesflushall() {
1801556Srgrimes	flushout(&output);
1811556Srgrimes	flushout(&errout);
1821556Srgrimes}
1831556Srgrimes
1841556Srgrimes
1851556Srgrimesvoid
1861556Srgrimesflushout(dest)
1871556Srgrimes	struct output *dest;
1881556Srgrimes	{
1891556Srgrimes
1901556Srgrimes	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
1911556Srgrimes		return;
1921556Srgrimes	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
1931556Srgrimes		dest->flags |= OUTPUT_ERR;
1941556Srgrimes	dest->nextc = dest->buf;
1951556Srgrimes	dest->nleft = dest->bufsize;
1961556Srgrimes}
1971556Srgrimes
1981556Srgrimes
1991556Srgrimesvoid
2001556Srgrimesfreestdout() {
2011556Srgrimes	INTOFF;
2021556Srgrimes	if (output.buf) {
2031556Srgrimes		ckfree(output.buf);
2041556Srgrimes		output.buf = NULL;
2051556Srgrimes		output.nleft = 0;
2061556Srgrimes	}
2071556Srgrimes	INTON;
2081556Srgrimes}
2091556Srgrimes
2101556Srgrimes
2111556Srgrimes#ifdef __STDC__
2121556Srgrimesvoid
2131556Srgrimesoutfmt(struct output *file, char *fmt, ...) {
2141556Srgrimes	va_list ap;
2151556Srgrimes
2161556Srgrimes	va_start(ap, fmt);
2171556Srgrimes	doformat(file, fmt, ap);
2181556Srgrimes	va_end(ap);
2191556Srgrimes}
2201556Srgrimes
2211556Srgrimes
2221556Srgrimesvoid
2231556Srgrimesout1fmt(char *fmt, ...) {
2241556Srgrimes	va_list ap;
2251556Srgrimes
2261556Srgrimes	va_start(ap, fmt);
2271556Srgrimes	doformat(out1, fmt, ap);
2281556Srgrimes	va_end(ap);
2291556Srgrimes}
2301556Srgrimes
2311556Srgrimesvoid
2321556Srgrimesdprintf(char *fmt, ...) {
2331556Srgrimes	va_list ap;
2341556Srgrimes
2351556Srgrimes	va_start(ap, fmt);
2361556Srgrimes	doformat(out2, fmt, ap);
2371556Srgrimes	va_end(ap);
2381556Srgrimes	flushout(out2);
2391556Srgrimes}
2401556Srgrimes
2411556Srgrimesvoid
2421556Srgrimesfmtstr(char *outbuf, int length, char *fmt, ...) {
2431556Srgrimes	va_list ap;
2441556Srgrimes	struct output strout;
2451556Srgrimes
2461556Srgrimes	va_start(ap, fmt);
2471556Srgrimes	strout.nextc = outbuf;
2481556Srgrimes	strout.nleft = length;
2491556Srgrimes	strout.fd = BLOCK_OUT;
2501556Srgrimes	strout.flags = 0;
2511556Srgrimes	doformat(&strout, fmt, ap);
2521556Srgrimes	outc('\0', &strout);
2531556Srgrimes	if (strout.flags & OUTPUT_ERR)
2541556Srgrimes		outbuf[length - 1] = '\0';
2551556Srgrimes}
2561556Srgrimes
2571556Srgrimes#else /* not __STDC__ */
2581556Srgrimes
2591556Srgrimesvoid
2601556Srgrimesoutfmt(va_alist)
2611556Srgrimes	va_dcl
2621556Srgrimes	{
2631556Srgrimes	va_list ap;
2641556Srgrimes	struct output *file;
2651556Srgrimes	char *fmt;
2661556Srgrimes
2671556Srgrimes	va_start(ap);
2681556Srgrimes	file = va_arg(ap, struct output *);
2691556Srgrimes	fmt = va_arg(ap, char *);
2701556Srgrimes	doformat(file, fmt, ap);
2711556Srgrimes	va_end(ap);
2721556Srgrimes}
2731556Srgrimes
2741556Srgrimes
2751556Srgrimesvoid
2761556Srgrimesout1fmt(va_alist)
2771556Srgrimes	va_dcl
2781556Srgrimes	{
2791556Srgrimes	va_list ap;
2801556Srgrimes	char *fmt;
2811556Srgrimes
2821556Srgrimes	va_start(ap);
2831556Srgrimes	fmt = va_arg(ap, char *);
2841556Srgrimes	doformat(out1, fmt, ap);
2851556Srgrimes	va_end(ap);
2861556Srgrimes}
2871556Srgrimes
2881556Srgrimesvoid
2891556Srgrimesdprintf(va_alist)
2901556Srgrimes	va_dcl
2911556Srgrimes	{
2921556Srgrimes	va_list ap;
2931556Srgrimes	char *fmt;
2941556Srgrimes
2951556Srgrimes	va_start(ap);
2961556Srgrimes	fmt = va_arg(ap, char *);
2971556Srgrimes	doformat(out2, fmt, ap);
2981556Srgrimes	va_end(ap);
2991556Srgrimes	flushout(out2);
3001556Srgrimes}
3011556Srgrimes
3021556Srgrimesvoid
3031556Srgrimesfmtstr(va_alist)
3041556Srgrimes	va_dcl
3051556Srgrimes	{
3061556Srgrimes	va_list ap;
3071556Srgrimes	struct output strout;
3081556Srgrimes	char *outbuf;
3091556Srgrimes	int length;
3101556Srgrimes	char *fmt;
3111556Srgrimes
3121556Srgrimes	va_start(ap);
3131556Srgrimes	outbuf = va_arg(ap, char *);
3141556Srgrimes	length = va_arg(ap, int);
3151556Srgrimes	fmt = va_arg(ap, char *);
3161556Srgrimes	strout.nextc = outbuf;
3171556Srgrimes	strout.nleft = length;
3181556Srgrimes	strout.fd = BLOCK_OUT;
3191556Srgrimes	strout.flags = 0;
3201556Srgrimes	doformat(&strout, fmt, ap);
3211556Srgrimes	outc('\0', &strout);
3221556Srgrimes	if (strout.flags & OUTPUT_ERR)
3231556Srgrimes		outbuf[length - 1] = '\0';
3241556Srgrimes}
3251556Srgrimes#endif /* __STDC__ */
3261556Srgrimes
3271556Srgrimes
3281556Srgrimes/*
3291556Srgrimes * Formatted output.  This routine handles a subset of the printf formats:
3301556Srgrimes * - Formats supported: d, u, o, X, s, and c.
3311556Srgrimes * - The x format is also accepted but is treated like X.
3321556Srgrimes * - The l modifier is accepted.
3331556Srgrimes * - The - and # flags are accepted; # only works with the o format.
3341556Srgrimes * - Width and precision may be specified with any format except c.
3351556Srgrimes * - An * may be given for the width or precision.
3361556Srgrimes * - The obsolete practice of preceding the width with a zero to get
3371556Srgrimes *   zero padding is not supported; use the precision field.
3381556Srgrimes * - A % may be printed by writing %% in the format string.
3391556Srgrimes */
3401556Srgrimes
3411556Srgrimes#define TEMPSIZE 24
3421556Srgrimes
3431556Srgrimes#ifdef __STDC__
3441556Srgrimesstatic const char digit[16] = "0123456789ABCDEF";
3451556Srgrimes#else
3461556Srgrimesstatic const char digit[17] = "0123456789ABCDEF";
3471556Srgrimes#endif
3481556Srgrimes
3491556Srgrimes
3501556Srgrimesvoid
3511556Srgrimesdoformat(dest, f, ap)
3521556Srgrimes	register struct output *dest;
3531556Srgrimes	register char *f;		/* format string */
3541556Srgrimes	va_list ap;
3551556Srgrimes	{
3561556Srgrimes	register char c;
3571556Srgrimes	char temp[TEMPSIZE];
3581556Srgrimes	int flushleft;
3591556Srgrimes	int sharp;
3601556Srgrimes	int width;
3611556Srgrimes	int prec;
3621556Srgrimes	int islong;
3631556Srgrimes	char *p;
3641556Srgrimes	int sign;
3651556Srgrimes	long l;
3661556Srgrimes	unsigned long num;
3671556Srgrimes	unsigned base;
3681556Srgrimes	int len;
3691556Srgrimes	int size;
3701556Srgrimes	int pad;
3711556Srgrimes
3721556Srgrimes	while ((c = *f++) != '\0') {
3731556Srgrimes		if (c != '%') {
3741556Srgrimes			outc(c, dest);
3751556Srgrimes			continue;
3761556Srgrimes		}
3771556Srgrimes		flushleft = 0;
3781556Srgrimes		sharp = 0;
3791556Srgrimes		width = 0;
3801556Srgrimes		prec = -1;
3811556Srgrimes		islong = 0;
3821556Srgrimes		for (;;) {
3831556Srgrimes			if (*f == '-')
3841556Srgrimes				flushleft++;
3851556Srgrimes			else if (*f == '#')
3861556Srgrimes				sharp++;
3871556Srgrimes			else
3881556Srgrimes				break;
3891556Srgrimes			f++;
3901556Srgrimes		}
3911556Srgrimes		if (*f == '*') {
3921556Srgrimes			width = va_arg(ap, int);
3931556Srgrimes			f++;
3941556Srgrimes		} else {
3951556Srgrimes			while (is_digit(*f)) {
3961556Srgrimes				width = 10 * width + digit_val(*f++);
3971556Srgrimes			}
3981556Srgrimes		}
3991556Srgrimes		if (*f == '.') {
4001556Srgrimes			if (*++f == '*') {
4011556Srgrimes				prec = va_arg(ap, int);
4021556Srgrimes				f++;
4031556Srgrimes			} else {
4041556Srgrimes				prec = 0;
4051556Srgrimes				while (is_digit(*f)) {
4061556Srgrimes					prec = 10 * prec + digit_val(*f++);
4071556Srgrimes				}
4081556Srgrimes			}
4091556Srgrimes		}
4101556Srgrimes		if (*f == 'l') {
4111556Srgrimes			islong++;
4121556Srgrimes			f++;
4131556Srgrimes		}
4141556Srgrimes		switch (*f) {
4151556Srgrimes		case 'd':
4161556Srgrimes			if (islong)
4171556Srgrimes				l = va_arg(ap, long);
4181556Srgrimes			else
4191556Srgrimes				l = va_arg(ap, int);
4201556Srgrimes			sign = 0;
4211556Srgrimes			num = l;
4221556Srgrimes			if (l < 0) {
4231556Srgrimes				num = -l;
4241556Srgrimes				sign = 1;
4251556Srgrimes			}
4261556Srgrimes			base = 10;
4271556Srgrimes			goto number;
4281556Srgrimes		case 'u':
4291556Srgrimes			base = 10;
4301556Srgrimes			goto uns_number;
4311556Srgrimes		case 'o':
4321556Srgrimes			base = 8;
4331556Srgrimes			goto uns_number;
4341556Srgrimes		case 'x':
4351556Srgrimes			/* we don't implement 'x'; treat like 'X' */
4361556Srgrimes		case 'X':
4371556Srgrimes			base = 16;
4381556Srgrimesuns_number:	  /* an unsigned number */
4391556Srgrimes			sign = 0;
4401556Srgrimes			if (islong)
4411556Srgrimes				num = va_arg(ap, unsigned long);
4421556Srgrimes			else
4431556Srgrimes				num = va_arg(ap, unsigned int);
4441556Srgrimesnumber:		  /* process a number */
4451556Srgrimes			p = temp + TEMPSIZE - 1;
4461556Srgrimes			*p = '\0';
4471556Srgrimes			while (num) {
4481556Srgrimes				*--p = digit[num % base];
4491556Srgrimes				num /= base;
4501556Srgrimes			}
4511556Srgrimes			len = (temp + TEMPSIZE - 1) - p;
4521556Srgrimes			if (prec < 0)
4531556Srgrimes				prec = 1;
4541556Srgrimes			if (sharp && *f == 'o' && prec <= len)
4551556Srgrimes				prec = len + 1;
4561556Srgrimes			pad = 0;
4571556Srgrimes			if (width) {
4581556Srgrimes				size = len;
4591556Srgrimes				if (size < prec)
4601556Srgrimes					size = prec;
4611556Srgrimes				size += sign;
4621556Srgrimes				pad = width - size;
4631556Srgrimes				if (flushleft == 0) {
4641556Srgrimes					while (--pad >= 0)
4651556Srgrimes						outc(' ', dest);
4661556Srgrimes				}
4671556Srgrimes			}
4681556Srgrimes			if (sign)
4691556Srgrimes				outc('-', dest);
4701556Srgrimes			prec -= len;
4711556Srgrimes			while (--prec >= 0)
4721556Srgrimes				outc('0', dest);
4731556Srgrimes			while (*p)
4741556Srgrimes				outc(*p++, dest);
4751556Srgrimes			while (--pad >= 0)
4761556Srgrimes				outc(' ', dest);
4771556Srgrimes			break;
4781556Srgrimes		case 's':
4791556Srgrimes			p = va_arg(ap, char *);
4801556Srgrimes			pad = 0;
4811556Srgrimes			if (width) {
4821556Srgrimes				len = strlen(p);
4831556Srgrimes				if (prec >= 0 && len > prec)
4841556Srgrimes					len = prec;
4851556Srgrimes				pad = width - len;
4861556Srgrimes				if (flushleft == 0) {
4871556Srgrimes					while (--pad >= 0)
4881556Srgrimes						outc(' ', dest);
4891556Srgrimes				}
4901556Srgrimes			}
4911556Srgrimes			prec++;
4921556Srgrimes			while (--prec != 0 && *p)
4931556Srgrimes				outc(*p++, dest);
4941556Srgrimes			while (--pad >= 0)
4951556Srgrimes				outc(' ', dest);
4961556Srgrimes			break;
4971556Srgrimes		case 'c':
4981556Srgrimes			c = va_arg(ap, int);
4991556Srgrimes			outc(c, dest);
5001556Srgrimes			break;
5011556Srgrimes		default:
5021556Srgrimes			outc(*f, dest);
5031556Srgrimes			break;
5041556Srgrimes		}
5051556Srgrimes		f++;
5061556Srgrimes	}
5071556Srgrimes}
5081556Srgrimes
5091556Srgrimes
5101556Srgrimes
5111556Srgrimes/*
5121556Srgrimes * Version of write which resumes after a signal is caught.
5131556Srgrimes */
5141556Srgrimes
5151556Srgrimesint
5161556Srgrimesxwrite(fd, buf, nbytes)
5171556Srgrimes	int fd;
5181556Srgrimes	char *buf;
5191556Srgrimes	int nbytes;
5201556Srgrimes	{
5211556Srgrimes	int ntry;
5221556Srgrimes	int i;
5231556Srgrimes	int n;
5241556Srgrimes
5251556Srgrimes	n = nbytes;
5261556Srgrimes	ntry = 0;
5271556Srgrimes	for (;;) {
5281556Srgrimes		i = write(fd, buf, n);
5291556Srgrimes		if (i > 0) {
5301556Srgrimes			if ((n -= i) <= 0)
5311556Srgrimes				return nbytes;
5321556Srgrimes			buf += i;
5331556Srgrimes			ntry = 0;
5341556Srgrimes		} else if (i == 0) {
5351556Srgrimes			if (++ntry > 10)
5361556Srgrimes				return nbytes - n;
5371556Srgrimes		} else if (errno != EINTR) {
5381556Srgrimes			return -1;
5391556Srgrimes		}
5401556Srgrimes	}
5411556Srgrimes}
5421556Srgrimes
5431556Srgrimes
5441556Srgrimes/*
5451556Srgrimes * Version of ioctl that retries after a signal is caught.
5461556Srgrimes */
5471556Srgrimes
5481556Srgrimesint
5491556Srgrimesxioctl(fd, request, arg) {
5501556Srgrimes	int i;
5511556Srgrimes
5521556Srgrimes	while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
5531556Srgrimes	return i;
5541556Srgrimes}
555