xref: /freebsd/bin/cat/cat.c (revision aefe30c5437159a5399bdbc1974d6fbf40f2ba0f)
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 
51*aefe30c5SMariusz Zaborski #include <sys/capsicum.h>
524b88c807SRodney W. Grimes #include <sys/param.h>
534b88c807SRodney W. Grimes #include <sys/stat.h>
54cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
55cbf2d71fSMatthew Dillon #include <sys/socket.h>
56cbf2d71fSMatthew Dillon #include <sys/un.h>
571c9fbb5aSHiroki Sato #include <netdb.h>
58cbf2d71fSMatthew Dillon #endif
594b88c807SRodney W. Grimes 
60*aefe30c5SMariusz Zaborski #include <capsicum_helpers.h>
614b88c807SRodney W. Grimes #include <ctype.h>
624b88c807SRodney W. Grimes #include <err.h>
634be62405SEd Maste #include <errno.h>
644b88c807SRodney W. Grimes #include <fcntl.h>
653043192bSAndrey A. Chernov #include <locale.h>
664b88c807SRodney W. Grimes #include <stdio.h>
674b88c807SRodney W. Grimes #include <stdlib.h>
68cafefe8cSDima Dorfman #include <string.h>
694b88c807SRodney W. Grimes #include <unistd.h>
702aa6b16fSAndrey A. Chernov #include <wchar.h>
712aa6b16fSAndrey A. Chernov #include <wctype.h>
724b88c807SRodney W. Grimes 
73*aefe30c5SMariusz Zaborski #include <libcasper.h>
74*aefe30c5SMariusz Zaborski #include <casper/cap_fileargs.h>
75*aefe30c5SMariusz Zaborski #include <casper/cap_net.h>
76*aefe30c5SMariusz Zaborski 
77aece80a2SBrooks Davis static int bflag, eflag, lflag, nflag, sflag, tflag, vflag;
78f9d4afb4SEd Schouten static int rval;
79f9d4afb4SEd Schouten static const char *filename;
80*aefe30c5SMariusz Zaborski static fileargs_t *fa;
814b88c807SRodney W. Grimes 
82e99f8bc0SEitan Adler static void usage(void) __dead2;
839d32ecfcSMark Murray static void scanfiles(char *argv[], int cooked);
84ed845580SAlex Richardson #ifndef BOOTSTRAP_CAT
8578a3801dSWarner Losh static void cook_cat(FILE *);
86ed845580SAlex Richardson #endif
8778a3801dSWarner Losh static void raw_cat(int);
88cbf2d71fSMatthew Dillon 
89cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
90*aefe30c5SMariusz Zaborski static cap_channel_t *capnet;
91*aefe30c5SMariusz Zaborski 
9278a3801dSWarner Losh static int udom_open(const char *path, int flags);
93cbf2d71fSMatthew Dillon #endif
944b88c807SRodney W. Grimes 
9567bf019bSJaakko Heinonen /*
9667bf019bSJaakko Heinonen  * Memory strategy threshold, in pages: if physmem is larger than this,
9767bf019bSJaakko Heinonen  * use a large buffer.
9867bf019bSJaakko Heinonen  */
99e9cbc9a7SIvan Voras #define	PHYSPAGES_THRESHOLD (32 * 1024)
100e9cbc9a7SIvan Voras 
10167bf019bSJaakko Heinonen /* Maximum buffer size in bytes - do not allow it to grow larger than this. */
102e9cbc9a7SIvan Voras #define	BUFSIZE_MAX (2 * 1024 * 1024)
103e9cbc9a7SIvan Voras 
10467bf019bSJaakko Heinonen /*
10567bf019bSJaakko Heinonen  * Small (default) buffer size in bytes. It's inefficient for this to be
10667bf019bSJaakko Heinonen  * smaller than MAXPHYS.
10767bf019bSJaakko Heinonen  */
108e9cbc9a7SIvan Voras #define	BUFSIZE_SMALL (MAXPHYS)
109e9cbc9a7SIvan Voras 
110a33ee411SAlex Richardson 
111a33ee411SAlex Richardson /*
112a33ee411SAlex Richardson  * For the bootstrapped cat binary (needed for locked appending to METALOG), we
113a33ee411SAlex Richardson  * disable all flags except -l and -u to avoid non-portable function calls.
114a33ee411SAlex Richardson  * In the future we may instead want to write a small portable bootstrap tool
115a33ee411SAlex Richardson  * that locks the output file before writing to it. However, for now
116a33ee411SAlex Richardson  * bootstrapping cat without multibyte support is the simpler solution.
117a33ee411SAlex Richardson  */
118a33ee411SAlex Richardson #ifdef BOOTSTRAP_CAT
119a33ee411SAlex Richardson #define SUPPORTED_FLAGS "lu"
120a33ee411SAlex Richardson #else
121a33ee411SAlex Richardson #define SUPPORTED_FLAGS "belnstuv"
122a33ee411SAlex Richardson #endif
123a33ee411SAlex Richardson 
124*aefe30c5SMariusz Zaborski #ifndef NO_UDOM_SUPPORT
125*aefe30c5SMariusz Zaborski static void
126*aefe30c5SMariusz Zaborski init_casper_net(cap_channel_t *casper)
127*aefe30c5SMariusz Zaborski {
128*aefe30c5SMariusz Zaborski 	cap_net_limit_t *limit;
129*aefe30c5SMariusz Zaborski 	int familylimit;
130*aefe30c5SMariusz Zaborski 
131*aefe30c5SMariusz Zaborski 	capnet = cap_service_open(casper, "system.net");
132*aefe30c5SMariusz Zaborski 	if (capnet == NULL)
133*aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to create network service");
134*aefe30c5SMariusz Zaborski 
135*aefe30c5SMariusz Zaborski 	limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR |
136*aefe30c5SMariusz Zaborski 	    CAPNET_CONNECTDNS);
137*aefe30c5SMariusz Zaborski 	if (limit == NULL)
138*aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to create limits");
139*aefe30c5SMariusz Zaborski 
140*aefe30c5SMariusz Zaborski 	familylimit = AF_LOCAL;
141*aefe30c5SMariusz Zaborski 	cap_net_limit_name2addr_family(limit, &familylimit, 1);
142*aefe30c5SMariusz Zaborski 
143*aefe30c5SMariusz Zaborski 	if (cap_net_limit(limit) < 0)
144*aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to apply limits");
145*aefe30c5SMariusz Zaborski }
146*aefe30c5SMariusz Zaborski #endif
147*aefe30c5SMariusz Zaborski 
148*aefe30c5SMariusz Zaborski static void
149*aefe30c5SMariusz Zaborski init_casper(int argc, char *argv[])
150*aefe30c5SMariusz Zaborski {
151*aefe30c5SMariusz Zaborski 	cap_channel_t *casper;
152*aefe30c5SMariusz Zaborski 	cap_rights_t rights;
153*aefe30c5SMariusz Zaborski 
154*aefe30c5SMariusz Zaborski 	casper = cap_init();
155*aefe30c5SMariusz Zaborski 	if (casper == NULL)
156*aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to create Casper");
157*aefe30c5SMariusz Zaborski 
158*aefe30c5SMariusz Zaborski 	fa = fileargs_cinit(casper, argc, argv, O_RDONLY, 0,
159*aefe30c5SMariusz Zaborski 	    cap_rights_init(&rights, CAP_READ | CAP_FSTAT | CAP_FCNTL),
160*aefe30c5SMariusz Zaborski 	    FA_OPEN | FA_REALPATH);
161*aefe30c5SMariusz Zaborski 	if (fa == NULL)
162*aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to create fileargs");
163*aefe30c5SMariusz Zaborski 
164*aefe30c5SMariusz Zaborski #ifndef NO_UDOM_SUPPORT
165*aefe30c5SMariusz Zaborski 	init_casper_net(casper);
166*aefe30c5SMariusz Zaborski #endif
167*aefe30c5SMariusz Zaborski 
168*aefe30c5SMariusz Zaborski 	cap_close(casper);
169*aefe30c5SMariusz Zaborski }
170*aefe30c5SMariusz Zaborski 
1714b88c807SRodney W. Grimes int
17278a3801dSWarner Losh main(int argc, char *argv[])
1734b88c807SRodney W. Grimes {
1744b88c807SRodney W. Grimes 	int ch;
175aece80a2SBrooks Davis 	struct flock stdout_lock;
1764b88c807SRodney W. Grimes 
1773043192bSAndrey A. Chernov 	setlocale(LC_CTYPE, "");
1783043192bSAndrey A. Chernov 
179a33ee411SAlex Richardson 	while ((ch = getopt(argc, argv, SUPPORTED_FLAGS)) != -1)
1804b88c807SRodney W. Grimes 		switch (ch) {
1814b88c807SRodney W. Grimes 		case 'b':
1824b88c807SRodney W. Grimes 			bflag = nflag = 1;	/* -b implies -n */
1834b88c807SRodney W. Grimes 			break;
1844b88c807SRodney W. Grimes 		case 'e':
1854b88c807SRodney W. Grimes 			eflag = vflag = 1;	/* -e implies -v */
1864b88c807SRodney W. Grimes 			break;
187aece80a2SBrooks Davis 		case 'l':
188aece80a2SBrooks Davis 			lflag = 1;
189aece80a2SBrooks Davis 			break;
1904b88c807SRodney W. Grimes 		case 'n':
1914b88c807SRodney W. Grimes 			nflag = 1;
1924b88c807SRodney W. Grimes 			break;
1934b88c807SRodney W. Grimes 		case 's':
1944b88c807SRodney W. Grimes 			sflag = 1;
1954b88c807SRodney W. Grimes 			break;
1964b88c807SRodney W. Grimes 		case 't':
1974b88c807SRodney W. Grimes 			tflag = vflag = 1;	/* -t implies -v */
1984b88c807SRodney W. Grimes 			break;
1994b88c807SRodney W. Grimes 		case 'u':
2002192b407SJeroen Ruigrok van der Werven 			setbuf(stdout, NULL);
2014b88c807SRodney W. Grimes 			break;
2024b88c807SRodney W. Grimes 		case 'v':
2034b88c807SRodney W. Grimes 			vflag = 1;
2044b88c807SRodney W. Grimes 			break;
2058d72a3d7SWarner Losh 		default:
206ca2be2ffSJuli Mallett 			usage();
2074b88c807SRodney W. Grimes 		}
2084b88c807SRodney W. Grimes 	argv += optind;
209*aefe30c5SMariusz Zaborski 	argc -= optind;
2104b88c807SRodney W. Grimes 
211aece80a2SBrooks Davis 	if (lflag) {
212aece80a2SBrooks Davis 		stdout_lock.l_len = 0;
213aece80a2SBrooks Davis 		stdout_lock.l_start = 0;
214aece80a2SBrooks Davis 		stdout_lock.l_type = F_WRLCK;
215aece80a2SBrooks Davis 		stdout_lock.l_whence = SEEK_SET;
216aece80a2SBrooks Davis 		if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1)
217aece80a2SBrooks Davis 			err(EXIT_FAILURE, "stdout");
218aece80a2SBrooks Davis 	}
219aece80a2SBrooks Davis 
220*aefe30c5SMariusz Zaborski 	init_casper(argc, argv);
221*aefe30c5SMariusz Zaborski 
222*aefe30c5SMariusz Zaborski 	caph_cache_catpages();
223*aefe30c5SMariusz Zaborski 
224*aefe30c5SMariusz Zaborski 	if (caph_enter_casper() < 0)
225*aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "capsicum");
226*aefe30c5SMariusz Zaborski 
2274b88c807SRodney W. Grimes 	if (bflag || eflag || nflag || sflag || tflag || vflag)
228cbf2d71fSMatthew Dillon 		scanfiles(argv, 1);
2294b88c807SRodney W. Grimes 	else
230cbf2d71fSMatthew Dillon 		scanfiles(argv, 0);
2314b88c807SRodney W. Grimes 	if (fclose(stdout))
2324b88c807SRodney W. Grimes 		err(1, "stdout");
2334b88c807SRodney W. Grimes 	exit(rval);
2349f82c1d3SMark Murray 	/* NOTREACHED */
2354b88c807SRodney W. Grimes }
2364b88c807SRodney W. Grimes 
237ca2be2ffSJuli Mallett static void
238ca2be2ffSJuli Mallett usage(void)
239ca2be2ffSJuli Mallett {
240e99f8bc0SEitan Adler 
241a33ee411SAlex Richardson 	fprintf(stderr, "usage: cat [-" SUPPORTED_FLAGS "] [file ...]\n");
242ca2be2ffSJuli Mallett 	exit(1);
2439f82c1d3SMark Murray 	/* NOTREACHED */
244ca2be2ffSJuli Mallett }
245ca2be2ffSJuli Mallett 
2469d32ecfcSMark Murray static void
247ed845580SAlex Richardson scanfiles(char *argv[], int cooked __unused)
2484b88c807SRodney W. Grimes {
24967bf019bSJaakko Heinonen 	int fd, i;
250cbf2d71fSMatthew Dillon 	char *path;
251ed845580SAlex Richardson #ifndef BOOTSTRAP_CAT
2521b00c916SRuslan Ermilov 	FILE *fp;
253ed845580SAlex Richardson #endif
2544b88c807SRodney W. Grimes 
25567bf019bSJaakko Heinonen 	i = 0;
25619271eb4SBryan Drewery 	fd = -1;
257cbf2d71fSMatthew Dillon 	while ((path = argv[i]) != NULL || i == 0) {
258cbf2d71fSMatthew Dillon 		if (path == NULL || strcmp(path, "-") == 0) {
2594b88c807SRodney W. Grimes 			filename = "stdin";
2601b00c916SRuslan Ermilov 			fd = STDIN_FILENO;
261cbf2d71fSMatthew Dillon 		} else {
262cbf2d71fSMatthew Dillon 			filename = path;
263*aefe30c5SMariusz Zaborski 			fd = fileargs_open(fa, path);
264cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
265cbf2d71fSMatthew Dillon 			if (fd < 0 && errno == EOPNOTSUPP)
26643e09ab2SRuslan Ermilov 				fd = udom_open(path, O_RDONLY);
267cbf2d71fSMatthew Dillon #endif
268cbf2d71fSMatthew Dillon 		}
269cbf2d71fSMatthew Dillon 		if (fd < 0) {
270cbf2d71fSMatthew Dillon 			warn("%s", path);
271001aff9fSBruce Evans 			rval = 1;
272a33ee411SAlex Richardson #ifndef BOOTSTRAP_CAT
273cbf2d71fSMatthew Dillon 		} else if (cooked) {
2741b00c916SRuslan Ermilov 			if (fd == STDIN_FILENO)
2751b00c916SRuslan Ermilov 				cook_cat(stdin);
2761b00c916SRuslan Ermilov 			else {
2771b00c916SRuslan Ermilov 				fp = fdopen(fd, "r");
278cbf2d71fSMatthew Dillon 				cook_cat(fp);
279cbf2d71fSMatthew Dillon 				fclose(fp);
2801b00c916SRuslan Ermilov 			}
281a33ee411SAlex Richardson #endif
282cbf2d71fSMatthew Dillon 		} else {
283cbf2d71fSMatthew Dillon 			raw_cat(fd);
2841b00c916SRuslan Ermilov 			if (fd != STDIN_FILENO)
285cbf2d71fSMatthew Dillon 				close(fd);
2864b88c807SRodney W. Grimes 		}
287cbf2d71fSMatthew Dillon 		if (path == NULL)
288cbf2d71fSMatthew Dillon 			break;
289cbf2d71fSMatthew Dillon 		++i;
2904b88c807SRodney W. Grimes 	}
2914b88c807SRodney W. Grimes }
2924b88c807SRodney W. Grimes 
293a33ee411SAlex Richardson #ifndef BOOTSTRAP_CAT
294cbf2d71fSMatthew Dillon static void
29578a3801dSWarner Losh cook_cat(FILE *fp)
2964b88c807SRodney W. Grimes {
29778a3801dSWarner Losh 	int ch, gobble, line, prev;
2982aa6b16fSAndrey A. Chernov 	wint_t wch;
2994b88c807SRodney W. Grimes 
3001b00c916SRuslan Ermilov 	/* Reset EOF condition on stdin. */
3011b00c916SRuslan Ermilov 	if (fp == stdin && feof(stdin))
3021b00c916SRuslan Ermilov 		clearerr(stdin);
3031b00c916SRuslan Ermilov 
3044b88c807SRodney W. Grimes 	line = gobble = 0;
3054b88c807SRodney W. Grimes 	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
3064b88c807SRodney W. Grimes 		if (prev == '\n') {
3074b88c807SRodney W. Grimes 			if (sflag) {
3084b88c807SRodney W. Grimes 				if (ch == '\n') {
309bf5f0c44STim J. Robbins 					if (gobble)
310bf5f0c44STim J. Robbins 						continue;
311bf5f0c44STim J. Robbins 					gobble = 1;
312bf5f0c44STim J. Robbins 				} else
313bf5f0c44STim J. Robbins 					gobble = 0;
314bf5f0c44STim J. Robbins 			}
3156d2e5f3dSSevan Janiyan 			if (nflag) {
3166d2e5f3dSSevan Janiyan 				if (!bflag || ch != '\n') {
317bf5f0c44STim J. Robbins 					(void)fprintf(stdout, "%6d\t", ++line);
318bf5f0c44STim J. Robbins 					if (ferror(stdout))
319bf5f0c44STim J. Robbins 						break;
3206d2e5f3dSSevan Janiyan 				} else if (eflag) {
3216d2e5f3dSSevan Janiyan 					(void)fprintf(stdout, "%6s\t", "");
3226d2e5f3dSSevan Janiyan 					if (ferror(stdout))
3236d2e5f3dSSevan Janiyan 						break;
3246d2e5f3dSSevan Janiyan 				}
325bf5f0c44STim J. Robbins 			}
326bf5f0c44STim J. Robbins 		}
327bf5f0c44STim J. Robbins 		if (ch == '\n') {
328bf5f0c44STim J. Robbins 			if (eflag && putchar('$') == EOF)
3294b88c807SRodney W. Grimes 				break;
3304b88c807SRodney W. Grimes 		} else if (ch == '\t') {
3314b88c807SRodney W. Grimes 			if (tflag) {
3324b88c807SRodney W. Grimes 				if (putchar('^') == EOF || putchar('I') == EOF)
3334b88c807SRodney W. Grimes 					break;
3344b88c807SRodney W. Grimes 				continue;
3354b88c807SRodney W. Grimes 			}
3364b88c807SRodney W. Grimes 		} else if (vflag) {
3372aa6b16fSAndrey A. Chernov 			(void)ungetc(ch, fp);
3382aa6b16fSAndrey A. Chernov 			/*
3392aa6b16fSAndrey A. Chernov 			 * Our getwc(3) doesn't change file position
3402aa6b16fSAndrey A. Chernov 			 * on error.
3412aa6b16fSAndrey A. Chernov 			 */
3422aa6b16fSAndrey A. Chernov 			if ((wch = getwc(fp)) == WEOF) {
3432aa6b16fSAndrey A. Chernov 				if (ferror(fp) && errno == EILSEQ) {
3442aa6b16fSAndrey A. Chernov 					clearerr(fp);
3452aa6b16fSAndrey A. Chernov 					/* Resync attempt. */
3462aa6b16fSAndrey A. Chernov 					memset(&fp->_mbstate, 0, sizeof(mbstate_t));
3472aa6b16fSAndrey A. Chernov 					if ((ch = getc(fp)) == EOF)
3482aa6b16fSAndrey A. Chernov 						break;
3492aa6b16fSAndrey A. Chernov 					wch = ch;
3502aa6b16fSAndrey A. Chernov 					goto ilseq;
3512aa6b16fSAndrey A. Chernov 				} else
3522aa6b16fSAndrey A. Chernov 					break;
3532aa6b16fSAndrey A. Chernov 			}
3542aa6b16fSAndrey A. Chernov 			if (!iswascii(wch) && !iswprint(wch)) {
3552aa6b16fSAndrey A. Chernov ilseq:
3564b88c807SRodney W. Grimes 				if (putchar('M') == EOF || putchar('-') == EOF)
3574b88c807SRodney W. Grimes 					break;
3582aa6b16fSAndrey A. Chernov 				wch = toascii(wch);
3594b88c807SRodney W. Grimes 			}
3602aa6b16fSAndrey A. Chernov 			if (iswcntrl(wch)) {
3612aa6b16fSAndrey A. Chernov 				ch = toascii(wch);
3622aa6b16fSAndrey A. Chernov 				ch = (ch == '\177') ? '?' : (ch | 0100);
3632aa6b16fSAndrey A. Chernov 				if (putchar('^') == EOF || putchar(ch) == EOF)
3644b88c807SRodney W. Grimes 					break;
3654b88c807SRodney W. Grimes 				continue;
3664b88c807SRodney W. Grimes 			}
3672aa6b16fSAndrey A. Chernov 			if (putwchar(wch) == WEOF)
3682aa6b16fSAndrey A. Chernov 				break;
3692aa6b16fSAndrey A. Chernov 			ch = -1;
3702aa6b16fSAndrey A. Chernov 			continue;
3714b88c807SRodney W. Grimes 		}
3724b88c807SRodney W. Grimes 		if (putchar(ch) == EOF)
3734b88c807SRodney W. Grimes 			break;
3744b88c807SRodney W. Grimes 	}
3754b88c807SRodney W. Grimes 	if (ferror(fp)) {
3764b88c807SRodney W. Grimes 		warn("%s", filename);
377001aff9fSBruce Evans 		rval = 1;
3784b88c807SRodney W. Grimes 		clearerr(fp);
3794b88c807SRodney W. Grimes 	}
3804b88c807SRodney W. Grimes 	if (ferror(stdout))
3814b88c807SRodney W. Grimes 		err(1, "stdout");
3824b88c807SRodney W. Grimes }
383a33ee411SAlex Richardson #endif /* BOOTSTRAP_CAT */
3844b88c807SRodney W. Grimes 
385cbf2d71fSMatthew Dillon static void
38678a3801dSWarner Losh raw_cat(int rfd)
3874b88c807SRodney W. Grimes {
388ca23e64eSWarner Losh 	long pagesize;
38978a3801dSWarner Losh 	int off, wfd;
390a5da0999SWarner Losh 	ssize_t nr, nw;
391a5da0999SWarner Losh 	static size_t bsize;
3929afa09cdSMark Murray 	static char *buf = NULL;
3934b88c807SRodney W. Grimes 	struct stat sbuf;
3944b88c807SRodney W. Grimes 
3954b88c807SRodney W. Grimes 	wfd = fileno(stdout);
3964b88c807SRodney W. Grimes 	if (buf == NULL) {
3974b88c807SRodney W. Grimes 		if (fstat(wfd, &sbuf))
398e3481b29SJaakko Heinonen 			err(1, "stdout");
399e9cbc9a7SIvan Voras 		if (S_ISREG(sbuf.st_mode)) {
400e9cbc9a7SIvan Voras 			/* If there's plenty of RAM, use a large copy buffer */
401e9cbc9a7SIvan Voras 			if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD)
402e9cbc9a7SIvan Voras 				bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
403e9cbc9a7SIvan Voras 			else
404e9cbc9a7SIvan Voras 				bsize = BUFSIZE_SMALL;
405ca23e64eSWarner Losh 		} else {
406ca23e64eSWarner Losh 			bsize = sbuf.st_blksize;
407ca23e64eSWarner Losh 			pagesize = sysconf(_SC_PAGESIZE);
408ca23e64eSWarner Losh 			if (pagesize > 0)
409ca23e64eSWarner Losh 				bsize = MAX(bsize, (size_t)pagesize);
410ca23e64eSWarner Losh 		}
411d1762d1fSWarner Losh 		if ((buf = malloc(bsize)) == NULL)
412e9cbc9a7SIvan Voras 			err(1, "malloc() failure of IO buffer");
4134b88c807SRodney W. Grimes 	}
4144b88c807SRodney W. Grimes 	while ((nr = read(rfd, buf, bsize)) > 0)
4154b88c807SRodney W. Grimes 		for (off = 0; nr; nr -= nw, off += nw)
416a5da0999SWarner Losh 			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
4174b88c807SRodney W. Grimes 				err(1, "stdout");
418001aff9fSBruce Evans 	if (nr < 0) {
4194b88c807SRodney W. Grimes 		warn("%s", filename);
420001aff9fSBruce Evans 		rval = 1;
421001aff9fSBruce Evans 	}
4224b88c807SRodney W. Grimes }
423cbf2d71fSMatthew Dillon 
424cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
425cbf2d71fSMatthew Dillon 
426cbf2d71fSMatthew Dillon static int
42778a3801dSWarner Losh udom_open(const char *path, int flags)
428cbf2d71fSMatthew Dillon {
4291c9fbb5aSHiroki Sato 	struct addrinfo hints, *res, *res0;
4301c9fbb5aSHiroki Sato 	char rpath[PATH_MAX];
43164c7af10SSean Bruno 	int fd = -1;
43264c7af10SSean Bruno 	int error;
433*aefe30c5SMariusz Zaborski 	cap_rights_t rights;
434cbf2d71fSMatthew Dillon 
435cbf2d71fSMatthew Dillon 	/*
4361c9fbb5aSHiroki Sato 	 * Construct the unix domain socket address and attempt to connect.
437cbf2d71fSMatthew Dillon 	 */
4381c9fbb5aSHiroki Sato 	bzero(&hints, sizeof(hints));
4391c9fbb5aSHiroki Sato 	hints.ai_family = AF_LOCAL;
440*aefe30c5SMariusz Zaborski 
441*aefe30c5SMariusz Zaborski 	if (fileargs_realpath(fa, path, rpath) == NULL)
4421c9fbb5aSHiroki Sato 		return (-1);
443*aefe30c5SMariusz Zaborski 
444*aefe30c5SMariusz Zaborski 	error = cap_getaddrinfo(capnet, rpath, NULL, &hints, &res0);
4451c9fbb5aSHiroki Sato 	if (error) {
4461c9fbb5aSHiroki Sato 		warn("%s", gai_strerror(error));
4471c9fbb5aSHiroki Sato 		errno = EINVAL;
44888485b4aSTim J. Robbins 		return (-1);
44988485b4aSTim J. Robbins 	}
450*aefe30c5SMariusz Zaborski 	cap_rights_init(&rights, CAP_CONNECT, CAP_READ, CAP_WRITE,
451*aefe30c5SMariusz Zaborski 	    CAP_SHUTDOWN, CAP_FSTAT, CAP_FCNTL);
4521c9fbb5aSHiroki Sato 	for (res = res0; res != NULL; res = res->ai_next) {
4531c9fbb5aSHiroki Sato 		fd = socket(res->ai_family, res->ai_socktype,
4541c9fbb5aSHiroki Sato 		    res->ai_protocol);
4551c9fbb5aSHiroki Sato 		if (fd < 0) {
4561c9fbb5aSHiroki Sato 			freeaddrinfo(res0);
4571c9fbb5aSHiroki Sato 			return (-1);
4581c9fbb5aSHiroki Sato 		}
459*aefe30c5SMariusz Zaborski 		if (caph_rights_limit(fd, &rights) < 0) {
460*aefe30c5SMariusz Zaborski 			close(fd);
461*aefe30c5SMariusz Zaborski 			return (-1);
462*aefe30c5SMariusz Zaborski 		}
463*aefe30c5SMariusz Zaborski 		error = cap_connect(capnet, fd, res->ai_addr, res->ai_addrlen);
4641c9fbb5aSHiroki Sato 		if (error == 0)
4651c9fbb5aSHiroki Sato 			break;
4661c9fbb5aSHiroki Sato 		else {
467cbf2d71fSMatthew Dillon 			close(fd);
468cbf2d71fSMatthew Dillon 			fd = -1;
469cbf2d71fSMatthew Dillon 		}
470cbf2d71fSMatthew Dillon 	}
4711c9fbb5aSHiroki Sato 	freeaddrinfo(res0);
472cbf2d71fSMatthew Dillon 
473cbf2d71fSMatthew Dillon 	/*
474cbf2d71fSMatthew Dillon 	 * handle the open flags by shutting down appropriate directions
475cbf2d71fSMatthew Dillon 	 */
476cbf2d71fSMatthew Dillon 	if (fd >= 0) {
477cbf2d71fSMatthew Dillon 		switch(flags & O_ACCMODE) {
478cbf2d71fSMatthew Dillon 		case O_RDONLY:
479*aefe30c5SMariusz Zaborski 			cap_rights_clear(&rights, CAP_WRITE);
4809afa09cdSMark Murray 			if (shutdown(fd, SHUT_WR) == -1)
4812c61418dSTim J. Robbins 				warn(NULL);
482cbf2d71fSMatthew Dillon 			break;
483cbf2d71fSMatthew Dillon 		case O_WRONLY:
484*aefe30c5SMariusz Zaborski 			cap_rights_clear(&rights, CAP_READ);
4859afa09cdSMark Murray 			if (shutdown(fd, SHUT_RD) == -1)
4862c61418dSTim J. Robbins 				warn(NULL);
487cbf2d71fSMatthew Dillon 			break;
488cbf2d71fSMatthew Dillon 		default:
489cbf2d71fSMatthew Dillon 			break;
490cbf2d71fSMatthew Dillon 		}
491*aefe30c5SMariusz Zaborski 
492*aefe30c5SMariusz Zaborski 		cap_rights_clear(&rights, CAP_CONNECT, CAP_SHUTDOWN);
493*aefe30c5SMariusz Zaborski 		if (caph_rights_limit(fd, &rights) < 0) {
494*aefe30c5SMariusz Zaborski 			close(fd);
495*aefe30c5SMariusz Zaborski 			return (-1);
496*aefe30c5SMariusz Zaborski 		}
497cbf2d71fSMatthew Dillon 	}
498cbf2d71fSMatthew Dillon 	return (fd);
499cbf2d71fSMatthew Dillon }
500cbf2d71fSMatthew Dillon 
501cbf2d71fSMatthew Dillon #endif
502