xref: /freebsd/bin/cat/cat.c (revision ca23e64eb4a39c14ca57a5b08954163e4f4a4384)
19ddb49cbSWarner Losh /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
44b88c807SRodney W. Grimes  * Copyright (c) 1989, 1993
54b88c807SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
64b88c807SRodney W. Grimes  *
74b88c807SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
84b88c807SRodney W. Grimes  * Kevin Fall.
94b88c807SRodney W. Grimes  *
104b88c807SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
114b88c807SRodney W. Grimes  * modification, are permitted provided that the following conditions
124b88c807SRodney W. Grimes  * are met:
134b88c807SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
144b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
154b88c807SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
164b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
174b88c807SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
194b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
204b88c807SRodney W. Grimes  *    without specific prior written permission.
214b88c807SRodney W. Grimes  *
224b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
234b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
244b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
254b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
264b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
274b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
284b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
294b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
304b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
314b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
324b88c807SRodney W. Grimes  * SUCH DAMAGE.
334b88c807SRodney W. Grimes  */
344b88c807SRodney W. Grimes 
350d22cdf0SDavid E. O'Brien #if 0
364b88c807SRodney W. Grimes #ifndef lint
37890acb95SSteve Price static char const copyright[] =
384b88c807SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\
394b88c807SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
404b88c807SRodney W. Grimes #endif /* not lint */
410d22cdf0SDavid E. O'Brien #endif
424b88c807SRodney W. Grimes 
434b88c807SRodney W. Grimes #ifndef lint
444c95995fSPhilippe Charnier #if 0
4512f93eb9SPhilippe Charnier static char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
464c95995fSPhilippe Charnier #endif
474b88c807SRodney W. Grimes #endif /* not lint */
485eb43ac2SDavid E. O'Brien #include <sys/cdefs.h>
495eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$");
504b88c807SRodney W. Grimes 
514b88c807SRodney W. Grimes #include <sys/param.h>
524b88c807SRodney W. Grimes #include <sys/stat.h>
53cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
54cbf2d71fSMatthew Dillon #include <sys/socket.h>
55cbf2d71fSMatthew Dillon #include <sys/un.h>
561c9fbb5aSHiroki Sato #include <netdb.h>
57cbf2d71fSMatthew Dillon #endif
584b88c807SRodney W. Grimes 
594b88c807SRodney W. Grimes #include <ctype.h>
604b88c807SRodney W. Grimes #include <err.h>
614be62405SEd Maste #include <errno.h>
624b88c807SRodney W. Grimes #include <fcntl.h>
633043192bSAndrey A. Chernov #include <locale.h>
6467bf019bSJaakko Heinonen #include <stddef.h>
654b88c807SRodney W. Grimes #include <stdio.h>
664b88c807SRodney W. Grimes #include <stdlib.h>
67cafefe8cSDima Dorfman #include <string.h>
684b88c807SRodney W. Grimes #include <unistd.h>
692aa6b16fSAndrey A. Chernov #include <wchar.h>
702aa6b16fSAndrey A. Chernov #include <wctype.h>
714b88c807SRodney W. Grimes 
72aece80a2SBrooks Davis static int bflag, eflag, lflag, nflag, sflag, tflag, vflag;
73f9d4afb4SEd Schouten static int rval;
74f9d4afb4SEd Schouten static const char *filename;
754b88c807SRodney W. Grimes 
76e99f8bc0SEitan Adler static void usage(void) __dead2;
779d32ecfcSMark Murray static void scanfiles(char *argv[], int cooked);
7878a3801dSWarner Losh static void cook_cat(FILE *);
7978a3801dSWarner Losh static void raw_cat(int);
80cbf2d71fSMatthew Dillon 
81cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
8278a3801dSWarner Losh static int udom_open(const char *path, int flags);
83cbf2d71fSMatthew Dillon #endif
844b88c807SRodney W. Grimes 
8567bf019bSJaakko Heinonen /*
8667bf019bSJaakko Heinonen  * Memory strategy threshold, in pages: if physmem is larger than this,
8767bf019bSJaakko Heinonen  * use a large buffer.
8867bf019bSJaakko Heinonen  */
89e9cbc9a7SIvan Voras #define	PHYSPAGES_THRESHOLD (32 * 1024)
90e9cbc9a7SIvan Voras 
9167bf019bSJaakko Heinonen /* Maximum buffer size in bytes - do not allow it to grow larger than this. */
92e9cbc9a7SIvan Voras #define	BUFSIZE_MAX (2 * 1024 * 1024)
93e9cbc9a7SIvan Voras 
9467bf019bSJaakko Heinonen /*
9567bf019bSJaakko Heinonen  * Small (default) buffer size in bytes. It's inefficient for this to be
9667bf019bSJaakko Heinonen  * smaller than MAXPHYS.
9767bf019bSJaakko Heinonen  */
98e9cbc9a7SIvan Voras #define	BUFSIZE_SMALL (MAXPHYS)
99e9cbc9a7SIvan Voras 
1004b88c807SRodney W. Grimes int
10178a3801dSWarner Losh main(int argc, char *argv[])
1024b88c807SRodney W. Grimes {
1034b88c807SRodney W. Grimes 	int ch;
104aece80a2SBrooks Davis 	struct flock stdout_lock;
1054b88c807SRodney W. Grimes 
1063043192bSAndrey A. Chernov 	setlocale(LC_CTYPE, "");
1073043192bSAndrey A. Chernov 
108aece80a2SBrooks Davis 	while ((ch = getopt(argc, argv, "belnstuv")) != -1)
1094b88c807SRodney W. Grimes 		switch (ch) {
1104b88c807SRodney W. Grimes 		case 'b':
1114b88c807SRodney W. Grimes 			bflag = nflag = 1;	/* -b implies -n */
1124b88c807SRodney W. Grimes 			break;
1134b88c807SRodney W. Grimes 		case 'e':
1144b88c807SRodney W. Grimes 			eflag = vflag = 1;	/* -e implies -v */
1154b88c807SRodney W. Grimes 			break;
116aece80a2SBrooks Davis 		case 'l':
117aece80a2SBrooks Davis 			lflag = 1;
118aece80a2SBrooks Davis 			break;
1194b88c807SRodney W. Grimes 		case 'n':
1204b88c807SRodney W. Grimes 			nflag = 1;
1214b88c807SRodney W. Grimes 			break;
1224b88c807SRodney W. Grimes 		case 's':
1234b88c807SRodney W. Grimes 			sflag = 1;
1244b88c807SRodney W. Grimes 			break;
1254b88c807SRodney W. Grimes 		case 't':
1264b88c807SRodney W. Grimes 			tflag = vflag = 1;	/* -t implies -v */
1274b88c807SRodney W. Grimes 			break;
1284b88c807SRodney W. Grimes 		case 'u':
1292192b407SJeroen Ruigrok van der Werven 			setbuf(stdout, NULL);
1304b88c807SRodney W. Grimes 			break;
1314b88c807SRodney W. Grimes 		case 'v':
1324b88c807SRodney W. Grimes 			vflag = 1;
1334b88c807SRodney W. Grimes 			break;
1348d72a3d7SWarner Losh 		default:
135ca2be2ffSJuli Mallett 			usage();
1364b88c807SRodney W. Grimes 		}
1374b88c807SRodney W. Grimes 	argv += optind;
1384b88c807SRodney W. Grimes 
139aece80a2SBrooks Davis 	if (lflag) {
140aece80a2SBrooks Davis 		stdout_lock.l_len = 0;
141aece80a2SBrooks Davis 		stdout_lock.l_start = 0;
142aece80a2SBrooks Davis 		stdout_lock.l_type = F_WRLCK;
143aece80a2SBrooks Davis 		stdout_lock.l_whence = SEEK_SET;
144aece80a2SBrooks Davis 		if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1)
145aece80a2SBrooks Davis 			err(EXIT_FAILURE, "stdout");
146aece80a2SBrooks Davis 	}
147aece80a2SBrooks Davis 
1484b88c807SRodney W. Grimes 	if (bflag || eflag || nflag || sflag || tflag || vflag)
149cbf2d71fSMatthew Dillon 		scanfiles(argv, 1);
1504b88c807SRodney W. Grimes 	else
151cbf2d71fSMatthew Dillon 		scanfiles(argv, 0);
1524b88c807SRodney W. Grimes 	if (fclose(stdout))
1534b88c807SRodney W. Grimes 		err(1, "stdout");
1544b88c807SRodney W. Grimes 	exit(rval);
1559f82c1d3SMark Murray 	/* NOTREACHED */
1564b88c807SRodney W. Grimes }
1574b88c807SRodney W. Grimes 
158ca2be2ffSJuli Mallett static void
159ca2be2ffSJuli Mallett usage(void)
160ca2be2ffSJuli Mallett {
161e99f8bc0SEitan Adler 
162aece80a2SBrooks Davis 	fprintf(stderr, "usage: cat [-belnstuv] [file ...]\n");
163ca2be2ffSJuli Mallett 	exit(1);
1649f82c1d3SMark Murray 	/* NOTREACHED */
165ca2be2ffSJuli Mallett }
166ca2be2ffSJuli Mallett 
1679d32ecfcSMark Murray static void
1689d32ecfcSMark Murray scanfiles(char *argv[], int cooked)
1694b88c807SRodney W. Grimes {
17067bf019bSJaakko Heinonen 	int fd, i;
171cbf2d71fSMatthew Dillon 	char *path;
1721b00c916SRuslan Ermilov 	FILE *fp;
1734b88c807SRodney W. Grimes 
17467bf019bSJaakko Heinonen 	i = 0;
17519271eb4SBryan Drewery 	fd = -1;
176cbf2d71fSMatthew Dillon 	while ((path = argv[i]) != NULL || i == 0) {
177cbf2d71fSMatthew Dillon 		if (path == NULL || strcmp(path, "-") == 0) {
1784b88c807SRodney W. Grimes 			filename = "stdin";
1791b00c916SRuslan Ermilov 			fd = STDIN_FILENO;
180cbf2d71fSMatthew Dillon 		} else {
181cbf2d71fSMatthew Dillon 			filename = path;
182cbf2d71fSMatthew Dillon 			fd = open(path, O_RDONLY);
183cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
184cbf2d71fSMatthew Dillon 			if (fd < 0 && errno == EOPNOTSUPP)
18543e09ab2SRuslan Ermilov 				fd = udom_open(path, O_RDONLY);
186cbf2d71fSMatthew Dillon #endif
187cbf2d71fSMatthew Dillon 		}
188cbf2d71fSMatthew Dillon 		if (fd < 0) {
189cbf2d71fSMatthew Dillon 			warn("%s", path);
190001aff9fSBruce Evans 			rval = 1;
191cbf2d71fSMatthew Dillon 		} else if (cooked) {
1921b00c916SRuslan Ermilov 			if (fd == STDIN_FILENO)
1931b00c916SRuslan Ermilov 				cook_cat(stdin);
1941b00c916SRuslan Ermilov 			else {
1951b00c916SRuslan Ermilov 				fp = fdopen(fd, "r");
196cbf2d71fSMatthew Dillon 				cook_cat(fp);
197cbf2d71fSMatthew Dillon 				fclose(fp);
1981b00c916SRuslan Ermilov 			}
199cbf2d71fSMatthew Dillon 		} else {
200cbf2d71fSMatthew Dillon 			raw_cat(fd);
2011b00c916SRuslan Ermilov 			if (fd != STDIN_FILENO)
202cbf2d71fSMatthew Dillon 				close(fd);
2034b88c807SRodney W. Grimes 		}
204cbf2d71fSMatthew Dillon 		if (path == NULL)
205cbf2d71fSMatthew Dillon 			break;
206cbf2d71fSMatthew Dillon 		++i;
2074b88c807SRodney W. Grimes 	}
2084b88c807SRodney W. Grimes }
2094b88c807SRodney W. Grimes 
210cbf2d71fSMatthew Dillon static void
21178a3801dSWarner Losh cook_cat(FILE *fp)
2124b88c807SRodney W. Grimes {
21378a3801dSWarner Losh 	int ch, gobble, line, prev;
2142aa6b16fSAndrey A. Chernov 	wint_t wch;
2154b88c807SRodney W. Grimes 
2161b00c916SRuslan Ermilov 	/* Reset EOF condition on stdin. */
2171b00c916SRuslan Ermilov 	if (fp == stdin && feof(stdin))
2181b00c916SRuslan Ermilov 		clearerr(stdin);
2191b00c916SRuslan Ermilov 
2204b88c807SRodney W. Grimes 	line = gobble = 0;
2214b88c807SRodney W. Grimes 	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
2224b88c807SRodney W. Grimes 		if (prev == '\n') {
2234b88c807SRodney W. Grimes 			if (sflag) {
2244b88c807SRodney W. Grimes 				if (ch == '\n') {
225bf5f0c44STim J. Robbins 					if (gobble)
226bf5f0c44STim J. Robbins 						continue;
227bf5f0c44STim J. Robbins 					gobble = 1;
228bf5f0c44STim J. Robbins 				} else
229bf5f0c44STim J. Robbins 					gobble = 0;
230bf5f0c44STim J. Robbins 			}
2316d2e5f3dSSevan Janiyan 			if (nflag) {
2326d2e5f3dSSevan Janiyan 				if (!bflag || ch != '\n') {
233bf5f0c44STim J. Robbins 					(void)fprintf(stdout, "%6d\t", ++line);
234bf5f0c44STim J. Robbins 					if (ferror(stdout))
235bf5f0c44STim J. Robbins 						break;
2366d2e5f3dSSevan Janiyan 				} else if (eflag) {
2376d2e5f3dSSevan Janiyan 					(void)fprintf(stdout, "%6s\t", "");
2386d2e5f3dSSevan Janiyan 					if (ferror(stdout))
2396d2e5f3dSSevan Janiyan 						break;
2406d2e5f3dSSevan Janiyan 				}
241bf5f0c44STim J. Robbins 			}
242bf5f0c44STim J. Robbins 		}
243bf5f0c44STim J. Robbins 		if (ch == '\n') {
244bf5f0c44STim J. Robbins 			if (eflag && putchar('$') == EOF)
2454b88c807SRodney W. Grimes 				break;
2464b88c807SRodney W. Grimes 		} else if (ch == '\t') {
2474b88c807SRodney W. Grimes 			if (tflag) {
2484b88c807SRodney W. Grimes 				if (putchar('^') == EOF || putchar('I') == EOF)
2494b88c807SRodney W. Grimes 					break;
2504b88c807SRodney W. Grimes 				continue;
2514b88c807SRodney W. Grimes 			}
2524b88c807SRodney W. Grimes 		} else if (vflag) {
2532aa6b16fSAndrey A. Chernov 			(void)ungetc(ch, fp);
2542aa6b16fSAndrey A. Chernov 			/*
2552aa6b16fSAndrey A. Chernov 			 * Our getwc(3) doesn't change file position
2562aa6b16fSAndrey A. Chernov 			 * on error.
2572aa6b16fSAndrey A. Chernov 			 */
2582aa6b16fSAndrey A. Chernov 			if ((wch = getwc(fp)) == WEOF) {
2592aa6b16fSAndrey A. Chernov 				if (ferror(fp) && errno == EILSEQ) {
2602aa6b16fSAndrey A. Chernov 					clearerr(fp);
2612aa6b16fSAndrey A. Chernov 					/* Resync attempt. */
2622aa6b16fSAndrey A. Chernov 					memset(&fp->_mbstate, 0, sizeof(mbstate_t));
2632aa6b16fSAndrey A. Chernov 					if ((ch = getc(fp)) == EOF)
2642aa6b16fSAndrey A. Chernov 						break;
2652aa6b16fSAndrey A. Chernov 					wch = ch;
2662aa6b16fSAndrey A. Chernov 					goto ilseq;
2672aa6b16fSAndrey A. Chernov 				} else
2682aa6b16fSAndrey A. Chernov 					break;
2692aa6b16fSAndrey A. Chernov 			}
2702aa6b16fSAndrey A. Chernov 			if (!iswascii(wch) && !iswprint(wch)) {
2712aa6b16fSAndrey A. Chernov ilseq:
2724b88c807SRodney W. Grimes 				if (putchar('M') == EOF || putchar('-') == EOF)
2734b88c807SRodney W. Grimes 					break;
2742aa6b16fSAndrey A. Chernov 				wch = toascii(wch);
2754b88c807SRodney W. Grimes 			}
2762aa6b16fSAndrey A. Chernov 			if (iswcntrl(wch)) {
2772aa6b16fSAndrey A. Chernov 				ch = toascii(wch);
2782aa6b16fSAndrey A. Chernov 				ch = (ch == '\177') ? '?' : (ch | 0100);
2792aa6b16fSAndrey A. Chernov 				if (putchar('^') == EOF || putchar(ch) == EOF)
2804b88c807SRodney W. Grimes 					break;
2814b88c807SRodney W. Grimes 				continue;
2824b88c807SRodney W. Grimes 			}
2832aa6b16fSAndrey A. Chernov 			if (putwchar(wch) == WEOF)
2842aa6b16fSAndrey A. Chernov 				break;
2852aa6b16fSAndrey A. Chernov 			ch = -1;
2862aa6b16fSAndrey A. Chernov 			continue;
2874b88c807SRodney W. Grimes 		}
2884b88c807SRodney W. Grimes 		if (putchar(ch) == EOF)
2894b88c807SRodney W. Grimes 			break;
2904b88c807SRodney W. Grimes 	}
2914b88c807SRodney W. Grimes 	if (ferror(fp)) {
2924b88c807SRodney W. Grimes 		warn("%s", filename);
293001aff9fSBruce Evans 		rval = 1;
2944b88c807SRodney W. Grimes 		clearerr(fp);
2954b88c807SRodney W. Grimes 	}
2964b88c807SRodney W. Grimes 	if (ferror(stdout))
2974b88c807SRodney W. Grimes 		err(1, "stdout");
2984b88c807SRodney W. Grimes }
2994b88c807SRodney W. Grimes 
300cbf2d71fSMatthew Dillon static void
30178a3801dSWarner Losh raw_cat(int rfd)
3024b88c807SRodney W. Grimes {
303*ca23e64eSWarner Losh 	long pagesize;
30478a3801dSWarner Losh 	int off, wfd;
305a5da0999SWarner Losh 	ssize_t nr, nw;
306a5da0999SWarner Losh 	static size_t bsize;
3079afa09cdSMark Murray 	static char *buf = NULL;
3084b88c807SRodney W. Grimes 	struct stat sbuf;
3094b88c807SRodney W. Grimes 
3104b88c807SRodney W. Grimes 	wfd = fileno(stdout);
3114b88c807SRodney W. Grimes 	if (buf == NULL) {
3124b88c807SRodney W. Grimes 		if (fstat(wfd, &sbuf))
313e3481b29SJaakko Heinonen 			err(1, "stdout");
314e9cbc9a7SIvan Voras 		if (S_ISREG(sbuf.st_mode)) {
315e9cbc9a7SIvan Voras 			/* If there's plenty of RAM, use a large copy buffer */
316e9cbc9a7SIvan Voras 			if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD)
317e9cbc9a7SIvan Voras 				bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
318e9cbc9a7SIvan Voras 			else
319e9cbc9a7SIvan Voras 				bsize = BUFSIZE_SMALL;
320*ca23e64eSWarner Losh 		} else {
321*ca23e64eSWarner Losh 			bsize = sbuf.st_blksize;
322*ca23e64eSWarner Losh 			pagesize = sysconf(_SC_PAGESIZE);
323*ca23e64eSWarner Losh 			if (pagesize > 0)
324*ca23e64eSWarner Losh 				bsize = MAX(bsize, (size_t)pagesize);
325*ca23e64eSWarner Losh 		}
326d1762d1fSWarner Losh 		if ((buf = malloc(bsize)) == NULL)
327e9cbc9a7SIvan Voras 			err(1, "malloc() failure of IO buffer");
3284b88c807SRodney W. Grimes 	}
3294b88c807SRodney W. Grimes 	while ((nr = read(rfd, buf, bsize)) > 0)
3304b88c807SRodney W. Grimes 		for (off = 0; nr; nr -= nw, off += nw)
331a5da0999SWarner Losh 			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
3324b88c807SRodney W. Grimes 				err(1, "stdout");
333001aff9fSBruce Evans 	if (nr < 0) {
3344b88c807SRodney W. Grimes 		warn("%s", filename);
335001aff9fSBruce Evans 		rval = 1;
336001aff9fSBruce Evans 	}
3374b88c807SRodney W. Grimes }
338cbf2d71fSMatthew Dillon 
339cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
340cbf2d71fSMatthew Dillon 
341cbf2d71fSMatthew Dillon static int
34278a3801dSWarner Losh udom_open(const char *path, int flags)
343cbf2d71fSMatthew Dillon {
3441c9fbb5aSHiroki Sato 	struct addrinfo hints, *res, *res0;
3451c9fbb5aSHiroki Sato 	char rpath[PATH_MAX];
34664c7af10SSean Bruno 	int fd = -1;
34764c7af10SSean Bruno 	int error;
348cbf2d71fSMatthew Dillon 
349cbf2d71fSMatthew Dillon 	/*
3501c9fbb5aSHiroki Sato 	 * Construct the unix domain socket address and attempt to connect.
351cbf2d71fSMatthew Dillon 	 */
3521c9fbb5aSHiroki Sato 	bzero(&hints, sizeof(hints));
3531c9fbb5aSHiroki Sato 	hints.ai_family = AF_LOCAL;
3541c9fbb5aSHiroki Sato 	if (realpath(path, rpath) == NULL)
3551c9fbb5aSHiroki Sato 		return (-1);
3561c9fbb5aSHiroki Sato 	error = getaddrinfo(rpath, NULL, &hints, &res0);
3571c9fbb5aSHiroki Sato 	if (error) {
3581c9fbb5aSHiroki Sato 		warn("%s", gai_strerror(error));
3591c9fbb5aSHiroki Sato 		errno = EINVAL;
36088485b4aSTim J. Robbins 		return (-1);
36188485b4aSTim J. Robbins 	}
3621c9fbb5aSHiroki Sato 	for (res = res0; res != NULL; res = res->ai_next) {
3631c9fbb5aSHiroki Sato 		fd = socket(res->ai_family, res->ai_socktype,
3641c9fbb5aSHiroki Sato 		    res->ai_protocol);
3651c9fbb5aSHiroki Sato 		if (fd < 0) {
3661c9fbb5aSHiroki Sato 			freeaddrinfo(res0);
3671c9fbb5aSHiroki Sato 			return (-1);
3681c9fbb5aSHiroki Sato 		}
3691c9fbb5aSHiroki Sato 		error = connect(fd, res->ai_addr, res->ai_addrlen);
3701c9fbb5aSHiroki Sato 		if (error == 0)
3711c9fbb5aSHiroki Sato 			break;
3721c9fbb5aSHiroki Sato 		else {
373cbf2d71fSMatthew Dillon 			close(fd);
374cbf2d71fSMatthew Dillon 			fd = -1;
375cbf2d71fSMatthew Dillon 		}
376cbf2d71fSMatthew Dillon 	}
3771c9fbb5aSHiroki Sato 	freeaddrinfo(res0);
378cbf2d71fSMatthew Dillon 
379cbf2d71fSMatthew Dillon 	/*
380cbf2d71fSMatthew Dillon 	 * handle the open flags by shutting down appropriate directions
381cbf2d71fSMatthew Dillon 	 */
382cbf2d71fSMatthew Dillon 	if (fd >= 0) {
383cbf2d71fSMatthew Dillon 		switch(flags & O_ACCMODE) {
384cbf2d71fSMatthew Dillon 		case O_RDONLY:
3859afa09cdSMark Murray 			if (shutdown(fd, SHUT_WR) == -1)
3862c61418dSTim J. Robbins 				warn(NULL);
387cbf2d71fSMatthew Dillon 			break;
388cbf2d71fSMatthew Dillon 		case O_WRONLY:
3899afa09cdSMark Murray 			if (shutdown(fd, SHUT_RD) == -1)
3902c61418dSTim J. Robbins 				warn(NULL);
391cbf2d71fSMatthew Dillon 			break;
392cbf2d71fSMatthew Dillon 		default:
393cbf2d71fSMatthew Dillon 			break;
394cbf2d71fSMatthew Dillon 		}
395cbf2d71fSMatthew Dillon 	}
396cbf2d71fSMatthew Dillon 	return (fd);
397cbf2d71fSMatthew Dillon }
398cbf2d71fSMatthew Dillon 
399cbf2d71fSMatthew Dillon #endif
400