xref: /freebsd/bin/cat/cat.c (revision 1c9fbb5a262aa41623d9eaaf28b331016d36c8dc)
19ddb49cbSWarner Losh /*-
24b88c807SRodney W. Grimes  * Copyright (c) 1989, 1993
34b88c807SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
44b88c807SRodney W. Grimes  *
54b88c807SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
64b88c807SRodney W. Grimes  * Kevin Fall.
74b88c807SRodney W. Grimes  *
84b88c807SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
94b88c807SRodney W. Grimes  * modification, are permitted provided that the following conditions
104b88c807SRodney W. Grimes  * are met:
114b88c807SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
124b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
134b88c807SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
144b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
154b88c807SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
164b88c807SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
174b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
184b88c807SRodney W. Grimes  *    without specific prior written permission.
194b88c807SRodney W. Grimes  *
204b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
214b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
244b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304b88c807SRodney W. Grimes  * SUCH DAMAGE.
314b88c807SRodney W. Grimes  */
324b88c807SRodney W. Grimes 
330d22cdf0SDavid E. O'Brien #if 0
344b88c807SRodney W. Grimes #ifndef lint
35890acb95SSteve Price static char const copyright[] =
364b88c807SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\
374b88c807SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
384b88c807SRodney W. Grimes #endif /* not lint */
390d22cdf0SDavid E. O'Brien #endif
404b88c807SRodney W. Grimes 
414b88c807SRodney W. Grimes #ifndef lint
424c95995fSPhilippe Charnier #if 0
4312f93eb9SPhilippe Charnier static char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
444c95995fSPhilippe Charnier #endif
454b88c807SRodney W. Grimes #endif /* not lint */
465eb43ac2SDavid E. O'Brien #include <sys/cdefs.h>
475eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$");
484b88c807SRodney W. Grimes 
494b88c807SRodney W. Grimes #include <sys/param.h>
504b88c807SRodney W. Grimes #include <sys/stat.h>
51cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
52cbf2d71fSMatthew Dillon #include <sys/socket.h>
53cbf2d71fSMatthew Dillon #include <sys/un.h>
54cbf2d71fSMatthew Dillon #include <errno.h>
55*1c9fbb5aSHiroki Sato #include <netdb.h>
56cbf2d71fSMatthew Dillon #endif
574b88c807SRodney W. Grimes 
584b88c807SRodney W. Grimes #include <ctype.h>
594b88c807SRodney W. Grimes #include <err.h>
604b88c807SRodney W. Grimes #include <fcntl.h>
613043192bSAndrey A. Chernov #include <locale.h>
6267bf019bSJaakko Heinonen #include <stddef.h>
634b88c807SRodney W. Grimes #include <stdio.h>
644b88c807SRodney W. Grimes #include <stdlib.h>
65cafefe8cSDima Dorfman #include <string.h>
664b88c807SRodney W. Grimes #include <unistd.h>
674b88c807SRodney W. Grimes 
68aece80a2SBrooks Davis static int bflag, eflag, lflag, nflag, sflag, tflag, vflag;
69f9d4afb4SEd Schouten static int rval;
70f9d4afb4SEd Schouten static const char *filename;
714b88c807SRodney W. Grimes 
72e99f8bc0SEitan Adler static void usage(void) __dead2;
739d32ecfcSMark Murray static void scanfiles(char *argv[], int cooked);
7478a3801dSWarner Losh static void cook_cat(FILE *);
7578a3801dSWarner Losh static void raw_cat(int);
76cbf2d71fSMatthew Dillon 
77cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
7878a3801dSWarner Losh static int udom_open(const char *path, int flags);
79cbf2d71fSMatthew Dillon #endif
804b88c807SRodney W. Grimes 
8167bf019bSJaakko Heinonen /*
8267bf019bSJaakko Heinonen  * Memory strategy threshold, in pages: if physmem is larger than this,
8367bf019bSJaakko Heinonen  * use a large buffer.
8467bf019bSJaakko Heinonen  */
85e9cbc9a7SIvan Voras #define	PHYSPAGES_THRESHOLD (32 * 1024)
86e9cbc9a7SIvan Voras 
8767bf019bSJaakko Heinonen /* Maximum buffer size in bytes - do not allow it to grow larger than this. */
88e9cbc9a7SIvan Voras #define	BUFSIZE_MAX (2 * 1024 * 1024)
89e9cbc9a7SIvan Voras 
9067bf019bSJaakko Heinonen /*
9167bf019bSJaakko Heinonen  * Small (default) buffer size in bytes. It's inefficient for this to be
9267bf019bSJaakko Heinonen  * smaller than MAXPHYS.
9367bf019bSJaakko Heinonen  */
94e9cbc9a7SIvan Voras #define	BUFSIZE_SMALL (MAXPHYS)
95e9cbc9a7SIvan Voras 
964b88c807SRodney W. Grimes int
9778a3801dSWarner Losh main(int argc, char *argv[])
984b88c807SRodney W. Grimes {
994b88c807SRodney W. Grimes 	int ch;
100aece80a2SBrooks Davis 	struct flock stdout_lock;
1014b88c807SRodney W. Grimes 
1023043192bSAndrey A. Chernov 	setlocale(LC_CTYPE, "");
1033043192bSAndrey A. Chernov 
104aece80a2SBrooks Davis 	while ((ch = getopt(argc, argv, "belnstuv")) != -1)
1054b88c807SRodney W. Grimes 		switch (ch) {
1064b88c807SRodney W. Grimes 		case 'b':
1074b88c807SRodney W. Grimes 			bflag = nflag = 1;	/* -b implies -n */
1084b88c807SRodney W. Grimes 			break;
1094b88c807SRodney W. Grimes 		case 'e':
1104b88c807SRodney W. Grimes 			eflag = vflag = 1;	/* -e implies -v */
1114b88c807SRodney W. Grimes 			break;
112aece80a2SBrooks Davis 		case 'l':
113aece80a2SBrooks Davis 			lflag = 1;
114aece80a2SBrooks Davis 			break;
1154b88c807SRodney W. Grimes 		case 'n':
1164b88c807SRodney W. Grimes 			nflag = 1;
1174b88c807SRodney W. Grimes 			break;
1184b88c807SRodney W. Grimes 		case 's':
1194b88c807SRodney W. Grimes 			sflag = 1;
1204b88c807SRodney W. Grimes 			break;
1214b88c807SRodney W. Grimes 		case 't':
1224b88c807SRodney W. Grimes 			tflag = vflag = 1;	/* -t implies -v */
1234b88c807SRodney W. Grimes 			break;
1244b88c807SRodney W. Grimes 		case 'u':
1252192b407SJeroen Ruigrok van der Werven 			setbuf(stdout, NULL);
1264b88c807SRodney W. Grimes 			break;
1274b88c807SRodney W. Grimes 		case 'v':
1284b88c807SRodney W. Grimes 			vflag = 1;
1294b88c807SRodney W. Grimes 			break;
1308d72a3d7SWarner Losh 		default:
131ca2be2ffSJuli Mallett 			usage();
1324b88c807SRodney W. Grimes 		}
1334b88c807SRodney W. Grimes 	argv += optind;
1344b88c807SRodney W. Grimes 
135aece80a2SBrooks Davis 	if (lflag) {
136aece80a2SBrooks Davis 		stdout_lock.l_len = 0;
137aece80a2SBrooks Davis 		stdout_lock.l_start = 0;
138aece80a2SBrooks Davis 		stdout_lock.l_type = F_WRLCK;
139aece80a2SBrooks Davis 		stdout_lock.l_whence = SEEK_SET;
140aece80a2SBrooks Davis 		if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1)
141aece80a2SBrooks Davis 			err(EXIT_FAILURE, "stdout");
142aece80a2SBrooks Davis 	}
143aece80a2SBrooks Davis 
1444b88c807SRodney W. Grimes 	if (bflag || eflag || nflag || sflag || tflag || vflag)
145cbf2d71fSMatthew Dillon 		scanfiles(argv, 1);
1464b88c807SRodney W. Grimes 	else
147cbf2d71fSMatthew Dillon 		scanfiles(argv, 0);
1484b88c807SRodney W. Grimes 	if (fclose(stdout))
1494b88c807SRodney W. Grimes 		err(1, "stdout");
1504b88c807SRodney W. Grimes 	exit(rval);
1519f82c1d3SMark Murray 	/* NOTREACHED */
1524b88c807SRodney W. Grimes }
1534b88c807SRodney W. Grimes 
154ca2be2ffSJuli Mallett static void
155ca2be2ffSJuli Mallett usage(void)
156ca2be2ffSJuli Mallett {
157e99f8bc0SEitan Adler 
158aece80a2SBrooks Davis 	fprintf(stderr, "usage: cat [-belnstuv] [file ...]\n");
159ca2be2ffSJuli Mallett 	exit(1);
1609f82c1d3SMark Murray 	/* NOTREACHED */
161ca2be2ffSJuli Mallett }
162ca2be2ffSJuli Mallett 
1639d32ecfcSMark Murray static void
1649d32ecfcSMark Murray scanfiles(char *argv[], int cooked)
1654b88c807SRodney W. Grimes {
16667bf019bSJaakko Heinonen 	int fd, i;
167cbf2d71fSMatthew Dillon 	char *path;
1681b00c916SRuslan Ermilov 	FILE *fp;
1694b88c807SRodney W. Grimes 
17067bf019bSJaakko Heinonen 	i = 0;
171cbf2d71fSMatthew Dillon 	while ((path = argv[i]) != NULL || i == 0) {
172cbf2d71fSMatthew Dillon 		if (path == NULL || strcmp(path, "-") == 0) {
1734b88c807SRodney W. Grimes 			filename = "stdin";
1741b00c916SRuslan Ermilov 			fd = STDIN_FILENO;
175cbf2d71fSMatthew Dillon 		} else {
176cbf2d71fSMatthew Dillon 			filename = path;
177cbf2d71fSMatthew Dillon 			fd = open(path, O_RDONLY);
178cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
179cbf2d71fSMatthew Dillon 			if (fd < 0 && errno == EOPNOTSUPP)
18043e09ab2SRuslan Ermilov 				fd = udom_open(path, O_RDONLY);
181cbf2d71fSMatthew Dillon #endif
182cbf2d71fSMatthew Dillon 		}
183cbf2d71fSMatthew Dillon 		if (fd < 0) {
184cbf2d71fSMatthew Dillon 			warn("%s", path);
185001aff9fSBruce Evans 			rval = 1;
186cbf2d71fSMatthew Dillon 		} else if (cooked) {
1871b00c916SRuslan Ermilov 			if (fd == STDIN_FILENO)
1881b00c916SRuslan Ermilov 				cook_cat(stdin);
1891b00c916SRuslan Ermilov 			else {
1901b00c916SRuslan Ermilov 				fp = fdopen(fd, "r");
191cbf2d71fSMatthew Dillon 				cook_cat(fp);
192cbf2d71fSMatthew Dillon 				fclose(fp);
1931b00c916SRuslan Ermilov 			}
194cbf2d71fSMatthew Dillon 		} else {
195cbf2d71fSMatthew Dillon 			raw_cat(fd);
1961b00c916SRuslan Ermilov 			if (fd != STDIN_FILENO)
197cbf2d71fSMatthew Dillon 				close(fd);
1984b88c807SRodney W. Grimes 		}
199cbf2d71fSMatthew Dillon 		if (path == NULL)
200cbf2d71fSMatthew Dillon 			break;
201cbf2d71fSMatthew Dillon 		++i;
2024b88c807SRodney W. Grimes 	}
2034b88c807SRodney W. Grimes }
2044b88c807SRodney W. Grimes 
205cbf2d71fSMatthew Dillon static void
20678a3801dSWarner Losh cook_cat(FILE *fp)
2074b88c807SRodney W. Grimes {
20878a3801dSWarner Losh 	int ch, gobble, line, prev;
2094b88c807SRodney W. Grimes 
2101b00c916SRuslan Ermilov 	/* Reset EOF condition on stdin. */
2111b00c916SRuslan Ermilov 	if (fp == stdin && feof(stdin))
2121b00c916SRuslan Ermilov 		clearerr(stdin);
2131b00c916SRuslan Ermilov 
2144b88c807SRodney W. Grimes 	line = gobble = 0;
2154b88c807SRodney W. Grimes 	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
2164b88c807SRodney W. Grimes 		if (prev == '\n') {
2174b88c807SRodney W. Grimes 			if (sflag) {
2184b88c807SRodney W. Grimes 				if (ch == '\n') {
219bf5f0c44STim J. Robbins 					if (gobble)
220bf5f0c44STim J. Robbins 						continue;
221bf5f0c44STim J. Robbins 					gobble = 1;
222bf5f0c44STim J. Robbins 				} else
223bf5f0c44STim J. Robbins 					gobble = 0;
224bf5f0c44STim J. Robbins 			}
225bf5f0c44STim J. Robbins 			if (nflag && (!bflag || ch != '\n')) {
226bf5f0c44STim J. Robbins 				(void)fprintf(stdout, "%6d\t", ++line);
227bf5f0c44STim J. Robbins 				if (ferror(stdout))
228bf5f0c44STim J. Robbins 					break;
229bf5f0c44STim J. Robbins 			}
230bf5f0c44STim J. Robbins 		}
231bf5f0c44STim J. Robbins 		if (ch == '\n') {
232bf5f0c44STim J. Robbins 			if (eflag && putchar('$') == EOF)
2334b88c807SRodney W. Grimes 				break;
2344b88c807SRodney W. Grimes 		} else if (ch == '\t') {
2354b88c807SRodney W. Grimes 			if (tflag) {
2364b88c807SRodney W. Grimes 				if (putchar('^') == EOF || putchar('I') == EOF)
2374b88c807SRodney W. Grimes 					break;
2384b88c807SRodney W. Grimes 				continue;
2394b88c807SRodney W. Grimes 			}
2404b88c807SRodney W. Grimes 		} else if (vflag) {
2413043192bSAndrey A. Chernov 			if (!isascii(ch) && !isprint(ch)) {
2424b88c807SRodney W. Grimes 				if (putchar('M') == EOF || putchar('-') == EOF)
2434b88c807SRodney W. Grimes 					break;
2444b88c807SRodney W. Grimes 				ch = toascii(ch);
2454b88c807SRodney W. Grimes 			}
2464b88c807SRodney W. Grimes 			if (iscntrl(ch)) {
2474b88c807SRodney W. Grimes 				if (putchar('^') == EOF ||
2484b88c807SRodney W. Grimes 				    putchar(ch == '\177' ? '?' :
2494b88c807SRodney W. Grimes 				    ch | 0100) == EOF)
2504b88c807SRodney W. Grimes 					break;
2514b88c807SRodney W. Grimes 				continue;
2524b88c807SRodney W. Grimes 			}
2534b88c807SRodney W. Grimes 		}
2544b88c807SRodney W. Grimes 		if (putchar(ch) == EOF)
2554b88c807SRodney W. Grimes 			break;
2564b88c807SRodney W. Grimes 	}
2574b88c807SRodney W. Grimes 	if (ferror(fp)) {
2584b88c807SRodney W. Grimes 		warn("%s", filename);
259001aff9fSBruce Evans 		rval = 1;
2604b88c807SRodney W. Grimes 		clearerr(fp);
2614b88c807SRodney W. Grimes 	}
2624b88c807SRodney W. Grimes 	if (ferror(stdout))
2634b88c807SRodney W. Grimes 		err(1, "stdout");
2644b88c807SRodney W. Grimes }
2654b88c807SRodney W. Grimes 
266cbf2d71fSMatthew Dillon static void
26778a3801dSWarner Losh raw_cat(int rfd)
2684b88c807SRodney W. Grimes {
26978a3801dSWarner Losh 	int off, wfd;
270a5da0999SWarner Losh 	ssize_t nr, nw;
271a5da0999SWarner Losh 	static size_t bsize;
2729afa09cdSMark Murray 	static char *buf = NULL;
2734b88c807SRodney W. Grimes 	struct stat sbuf;
2744b88c807SRodney W. Grimes 
2754b88c807SRodney W. Grimes 	wfd = fileno(stdout);
2764b88c807SRodney W. Grimes 	if (buf == NULL) {
2774b88c807SRodney W. Grimes 		if (fstat(wfd, &sbuf))
278e3481b29SJaakko Heinonen 			err(1, "stdout");
279e9cbc9a7SIvan Voras 		if (S_ISREG(sbuf.st_mode)) {
280e9cbc9a7SIvan Voras 			/* If there's plenty of RAM, use a large copy buffer */
281e9cbc9a7SIvan Voras 			if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD)
282e9cbc9a7SIvan Voras 				bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
283e9cbc9a7SIvan Voras 			else
284e9cbc9a7SIvan Voras 				bsize = BUFSIZE_SMALL;
285e9cbc9a7SIvan Voras 		} else
286e9cbc9a7SIvan Voras 			bsize = MAX(sbuf.st_blksize,
287e9cbc9a7SIvan Voras 			    (blksize_t)sysconf(_SC_PAGESIZE));
288d1762d1fSWarner Losh 		if ((buf = malloc(bsize)) == NULL)
289e9cbc9a7SIvan Voras 			err(1, "malloc() failure of IO buffer");
2904b88c807SRodney W. Grimes 	}
2914b88c807SRodney W. Grimes 	while ((nr = read(rfd, buf, bsize)) > 0)
2924b88c807SRodney W. Grimes 		for (off = 0; nr; nr -= nw, off += nw)
293a5da0999SWarner Losh 			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
2944b88c807SRodney W. Grimes 				err(1, "stdout");
295001aff9fSBruce Evans 	if (nr < 0) {
2964b88c807SRodney W. Grimes 		warn("%s", filename);
297001aff9fSBruce Evans 		rval = 1;
298001aff9fSBruce Evans 	}
2994b88c807SRodney W. Grimes }
300cbf2d71fSMatthew Dillon 
301cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
302cbf2d71fSMatthew Dillon 
303cbf2d71fSMatthew Dillon static int
30478a3801dSWarner Losh udom_open(const char *path, int flags)
305cbf2d71fSMatthew Dillon {
306*1c9fbb5aSHiroki Sato 	struct addrinfo hints, *res, *res0;
307*1c9fbb5aSHiroki Sato 	char rpath[PATH_MAX];
308*1c9fbb5aSHiroki Sato 	int fd, error;
309cbf2d71fSMatthew Dillon 
310cbf2d71fSMatthew Dillon 	/*
311*1c9fbb5aSHiroki Sato 	 * Construct the unix domain socket address and attempt to connect.
312cbf2d71fSMatthew Dillon 	 */
313*1c9fbb5aSHiroki Sato 	bzero(&hints, sizeof(hints));
314*1c9fbb5aSHiroki Sato 	hints.ai_family = AF_LOCAL;
315*1c9fbb5aSHiroki Sato 	if (realpath(path, rpath) == NULL)
316*1c9fbb5aSHiroki Sato 		return (-1);
317*1c9fbb5aSHiroki Sato 	error = getaddrinfo(rpath, NULL, &hints, &res0);
318*1c9fbb5aSHiroki Sato 	if (error) {
319*1c9fbb5aSHiroki Sato 		warn("%s", gai_strerror(error));
320*1c9fbb5aSHiroki Sato 		errno = EINVAL;
32188485b4aSTim J. Robbins 		return (-1);
32288485b4aSTim J. Robbins 	}
323*1c9fbb5aSHiroki Sato 	for (res = res0; res != NULL; res = res->ai_next) {
324*1c9fbb5aSHiroki Sato 		fd = socket(res->ai_family, res->ai_socktype,
325*1c9fbb5aSHiroki Sato 		    res->ai_protocol);
326*1c9fbb5aSHiroki Sato 		if (fd < 0) {
327*1c9fbb5aSHiroki Sato 			freeaddrinfo(res0);
328*1c9fbb5aSHiroki Sato 			return (-1);
329*1c9fbb5aSHiroki Sato 		}
330*1c9fbb5aSHiroki Sato 		error = connect(fd, res->ai_addr, res->ai_addrlen);
331*1c9fbb5aSHiroki Sato 		if (error == 0)
332*1c9fbb5aSHiroki Sato 			break;
333*1c9fbb5aSHiroki Sato 		else {
334cbf2d71fSMatthew Dillon 			close(fd);
335cbf2d71fSMatthew Dillon 			fd = -1;
336cbf2d71fSMatthew Dillon 		}
337cbf2d71fSMatthew Dillon 	}
338*1c9fbb5aSHiroki Sato 	freeaddrinfo(res0);
339cbf2d71fSMatthew Dillon 
340cbf2d71fSMatthew Dillon 	/*
341cbf2d71fSMatthew Dillon 	 * handle the open flags by shutting down appropriate directions
342cbf2d71fSMatthew Dillon 	 */
343cbf2d71fSMatthew Dillon 	if (fd >= 0) {
344cbf2d71fSMatthew Dillon 		switch(flags & O_ACCMODE) {
345cbf2d71fSMatthew Dillon 		case O_RDONLY:
3469afa09cdSMark Murray 			if (shutdown(fd, SHUT_WR) == -1)
3472c61418dSTim J. Robbins 				warn(NULL);
348cbf2d71fSMatthew Dillon 			break;
349cbf2d71fSMatthew Dillon 		case O_WRONLY:
3509afa09cdSMark Murray 			if (shutdown(fd, SHUT_RD) == -1)
3512c61418dSTim J. Robbins 				warn(NULL);
352cbf2d71fSMatthew Dillon 			break;
353cbf2d71fSMatthew Dillon 		default:
354cbf2d71fSMatthew Dillon 			break;
355cbf2d71fSMatthew Dillon 		}
356cbf2d71fSMatthew Dillon 	}
357cbf2d71fSMatthew Dillon 	return (fd);
358cbf2d71fSMatthew Dillon }
359cbf2d71fSMatthew Dillon 
360cbf2d71fSMatthew Dillon #endif
361