xref: /freebsd/bin/cat/cat.c (revision 86b4df97d0fc6980242e6d047390047c8c7be7dc)
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 
35aefe30c5SMariusz Zaborski #include <sys/capsicum.h>
364b88c807SRodney W. Grimes #include <sys/param.h>
374b88c807SRodney W. Grimes #include <sys/stat.h>
38cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
39cbf2d71fSMatthew Dillon #include <sys/socket.h>
40cbf2d71fSMatthew Dillon #include <sys/un.h>
411c9fbb5aSHiroki Sato #include <netdb.h>
42cbf2d71fSMatthew Dillon #endif
434b88c807SRodney W. Grimes 
44aefe30c5SMariusz Zaborski #include <capsicum_helpers.h>
454b88c807SRodney W. Grimes #include <ctype.h>
464b88c807SRodney W. Grimes #include <err.h>
474be62405SEd Maste #include <errno.h>
484b88c807SRodney W. Grimes #include <fcntl.h>
493043192bSAndrey A. Chernov #include <locale.h>
504b88c807SRodney W. Grimes #include <stdio.h>
514b88c807SRodney W. Grimes #include <stdlib.h>
52cafefe8cSDima Dorfman #include <string.h>
534b88c807SRodney W. Grimes #include <unistd.h>
542aa6b16fSAndrey A. Chernov #include <wchar.h>
552aa6b16fSAndrey A. Chernov #include <wctype.h>
564b88c807SRodney W. Grimes 
57aefe30c5SMariusz Zaborski #include <libcasper.h>
58aefe30c5SMariusz Zaborski #include <casper/cap_fileargs.h>
59aefe30c5SMariusz Zaborski #include <casper/cap_net.h>
60aefe30c5SMariusz Zaborski 
61aece80a2SBrooks Davis static int bflag, eflag, lflag, nflag, sflag, tflag, vflag;
62f9d4afb4SEd Schouten static int rval;
63f9d4afb4SEd Schouten static const char *filename;
64aefe30c5SMariusz Zaborski static fileargs_t *fa;
654b88c807SRodney W. Grimes 
66e99f8bc0SEitan Adler static void usage(void) __dead2;
679d32ecfcSMark Murray static void scanfiles(char *argv[], int cooked);
68ed845580SAlex Richardson #ifndef BOOTSTRAP_CAT
6978a3801dSWarner Losh static void cook_cat(FILE *);
708113cc82SMartin Matuska static ssize_t in_kernel_copy(int);
71ed845580SAlex Richardson #endif
7278a3801dSWarner Losh static void raw_cat(int);
73cbf2d71fSMatthew Dillon 
74cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
75aefe30c5SMariusz Zaborski static cap_channel_t *capnet;
76aefe30c5SMariusz Zaborski 
7778a3801dSWarner Losh static int udom_open(const char *path, int flags);
78cbf2d71fSMatthew Dillon #endif
794b88c807SRodney W. Grimes 
8067bf019bSJaakko Heinonen /*
8167bf019bSJaakko Heinonen  * Memory strategy threshold, in pages: if physmem is larger than this,
8267bf019bSJaakko Heinonen  * use a large buffer.
8367bf019bSJaakko Heinonen  */
84e9cbc9a7SIvan Voras #define	PHYSPAGES_THRESHOLD (32 * 1024)
85e9cbc9a7SIvan Voras 
8667bf019bSJaakko Heinonen /* Maximum buffer size in bytes - do not allow it to grow larger than this. */
87e9cbc9a7SIvan Voras #define	BUFSIZE_MAX (2 * 1024 * 1024)
88e9cbc9a7SIvan Voras 
8967bf019bSJaakko Heinonen /*
9067bf019bSJaakko Heinonen  * Small (default) buffer size in bytes. It's inefficient for this to be
9167bf019bSJaakko Heinonen  * smaller than MAXPHYS.
9267bf019bSJaakko Heinonen  */
93e9cbc9a7SIvan Voras #define	BUFSIZE_SMALL (MAXPHYS)
94e9cbc9a7SIvan Voras 
95a33ee411SAlex Richardson 
96a33ee411SAlex Richardson /*
97a33ee411SAlex Richardson  * For the bootstrapped cat binary (needed for locked appending to METALOG), we
98a33ee411SAlex Richardson  * disable all flags except -l and -u to avoid non-portable function calls.
99a33ee411SAlex Richardson  * In the future we may instead want to write a small portable bootstrap tool
100a33ee411SAlex Richardson  * that locks the output file before writing to it. However, for now
101a33ee411SAlex Richardson  * bootstrapping cat without multibyte support is the simpler solution.
102a33ee411SAlex Richardson  */
103a33ee411SAlex Richardson #ifdef BOOTSTRAP_CAT
104a33ee411SAlex Richardson #define SUPPORTED_FLAGS "lu"
105a33ee411SAlex Richardson #else
106a33ee411SAlex Richardson #define SUPPORTED_FLAGS "belnstuv"
107a33ee411SAlex Richardson #endif
108a33ee411SAlex Richardson 
109aefe30c5SMariusz Zaborski #ifndef NO_UDOM_SUPPORT
110aefe30c5SMariusz Zaborski static void
init_casper_net(cap_channel_t * casper)111aefe30c5SMariusz Zaborski init_casper_net(cap_channel_t *casper)
112aefe30c5SMariusz Zaborski {
113aefe30c5SMariusz Zaborski 	cap_net_limit_t *limit;
114aefe30c5SMariusz Zaborski 	int familylimit;
115aefe30c5SMariusz Zaborski 
116aefe30c5SMariusz Zaborski 	capnet = cap_service_open(casper, "system.net");
117aefe30c5SMariusz Zaborski 	if (capnet == NULL)
118aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to create network service");
119aefe30c5SMariusz Zaborski 
120aefe30c5SMariusz Zaborski 	limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR |
121aefe30c5SMariusz Zaborski 	    CAPNET_CONNECTDNS);
122aefe30c5SMariusz Zaborski 	if (limit == NULL)
123aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to create limits");
124aefe30c5SMariusz Zaborski 
125aefe30c5SMariusz Zaborski 	familylimit = AF_LOCAL;
126aefe30c5SMariusz Zaborski 	cap_net_limit_name2addr_family(limit, &familylimit, 1);
127aefe30c5SMariusz Zaborski 
128ad4f3bdfSDag-Erling Smørgrav 	if (cap_net_limit(limit) != 0)
129aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to apply limits");
130aefe30c5SMariusz Zaborski }
131aefe30c5SMariusz Zaborski #endif
132aefe30c5SMariusz Zaborski 
133aefe30c5SMariusz Zaborski static void
init_casper(int argc,char * argv[])134aefe30c5SMariusz Zaborski init_casper(int argc, char *argv[])
135aefe30c5SMariusz Zaborski {
136aefe30c5SMariusz Zaborski 	cap_channel_t *casper;
137aefe30c5SMariusz Zaborski 	cap_rights_t rights;
138aefe30c5SMariusz Zaborski 
139aefe30c5SMariusz Zaborski 	casper = cap_init();
140aefe30c5SMariusz Zaborski 	if (casper == NULL)
141aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to create Casper");
142aefe30c5SMariusz Zaborski 
143aefe30c5SMariusz Zaborski 	fa = fileargs_cinit(casper, argc, argv, O_RDONLY, 0,
14405f530f4SEd Maste 	    cap_rights_init(&rights, CAP_READ, CAP_FSTAT, CAP_FCNTL, CAP_SEEK),
145aefe30c5SMariusz Zaborski 	    FA_OPEN | FA_REALPATH);
146aefe30c5SMariusz Zaborski 	if (fa == NULL)
147aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "unable to create fileargs");
148aefe30c5SMariusz Zaborski 
149aefe30c5SMariusz Zaborski #ifndef NO_UDOM_SUPPORT
150aefe30c5SMariusz Zaborski 	init_casper_net(casper);
151aefe30c5SMariusz Zaborski #endif
152aefe30c5SMariusz Zaborski 
153aefe30c5SMariusz Zaborski 	cap_close(casper);
154aefe30c5SMariusz Zaborski }
155aefe30c5SMariusz Zaborski 
1564b88c807SRodney W. Grimes int
main(int argc,char * argv[])15778a3801dSWarner Losh main(int argc, char *argv[])
1584b88c807SRodney W. Grimes {
1594b88c807SRodney W. Grimes 	int ch;
160aece80a2SBrooks Davis 	struct flock stdout_lock;
1614b88c807SRodney W. Grimes 
1623043192bSAndrey A. Chernov 	setlocale(LC_CTYPE, "");
1633043192bSAndrey A. Chernov 
164a33ee411SAlex Richardson 	while ((ch = getopt(argc, argv, SUPPORTED_FLAGS)) != -1)
1654b88c807SRodney W. Grimes 		switch (ch) {
1664b88c807SRodney W. Grimes 		case 'b':
1674b88c807SRodney W. Grimes 			bflag = nflag = 1;	/* -b implies -n */
1684b88c807SRodney W. Grimes 			break;
1694b88c807SRodney W. Grimes 		case 'e':
1704b88c807SRodney W. Grimes 			eflag = vflag = 1;	/* -e implies -v */
1714b88c807SRodney W. Grimes 			break;
172aece80a2SBrooks Davis 		case 'l':
173aece80a2SBrooks Davis 			lflag = 1;
174aece80a2SBrooks Davis 			break;
1754b88c807SRodney W. Grimes 		case 'n':
1764b88c807SRodney W. Grimes 			nflag = 1;
1774b88c807SRodney W. Grimes 			break;
1784b88c807SRodney W. Grimes 		case 's':
1794b88c807SRodney W. Grimes 			sflag = 1;
1804b88c807SRodney W. Grimes 			break;
1814b88c807SRodney W. Grimes 		case 't':
1824b88c807SRodney W. Grimes 			tflag = vflag = 1;	/* -t implies -v */
1834b88c807SRodney W. Grimes 			break;
1844b88c807SRodney W. Grimes 		case 'u':
1852192b407SJeroen Ruigrok van der Werven 			setbuf(stdout, NULL);
1864b88c807SRodney W. Grimes 			break;
1874b88c807SRodney W. Grimes 		case 'v':
1884b88c807SRodney W. Grimes 			vflag = 1;
1894b88c807SRodney W. Grimes 			break;
1908d72a3d7SWarner Losh 		default:
191ca2be2ffSJuli Mallett 			usage();
1924b88c807SRodney W. Grimes 		}
1934b88c807SRodney W. Grimes 	argv += optind;
194aefe30c5SMariusz Zaborski 	argc -= optind;
1954b88c807SRodney W. Grimes 
196aece80a2SBrooks Davis 	if (lflag) {
197aece80a2SBrooks Davis 		stdout_lock.l_len = 0;
198aece80a2SBrooks Davis 		stdout_lock.l_start = 0;
199aece80a2SBrooks Davis 		stdout_lock.l_type = F_WRLCK;
200aece80a2SBrooks Davis 		stdout_lock.l_whence = SEEK_SET;
201c6f9df70SDag-Erling Smørgrav 		if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) != 0)
202aece80a2SBrooks Davis 			err(EXIT_FAILURE, "stdout");
203aece80a2SBrooks Davis 	}
204aece80a2SBrooks Davis 
205aefe30c5SMariusz Zaborski 	init_casper(argc, argv);
206aefe30c5SMariusz Zaborski 
207aefe30c5SMariusz Zaborski 	caph_cache_catpages();
208aefe30c5SMariusz Zaborski 
209ad4f3bdfSDag-Erling Smørgrav 	if (caph_enter_casper() != 0)
210aefe30c5SMariusz Zaborski 		err(EXIT_FAILURE, "capsicum");
211aefe30c5SMariusz Zaborski 
2124b88c807SRodney W. Grimes 	if (bflag || eflag || nflag || sflag || tflag || vflag)
213cbf2d71fSMatthew Dillon 		scanfiles(argv, 1);
2144b88c807SRodney W. Grimes 	else
215cbf2d71fSMatthew Dillon 		scanfiles(argv, 0);
2164b88c807SRodney W. Grimes 	if (fclose(stdout))
2174b88c807SRodney W. Grimes 		err(1, "stdout");
2184b88c807SRodney W. Grimes 	exit(rval);
2199f82c1d3SMark Murray 	/* NOTREACHED */
2204b88c807SRodney W. Grimes }
2214b88c807SRodney W. Grimes 
222ca2be2ffSJuli Mallett static void
usage(void)223ca2be2ffSJuli Mallett usage(void)
224ca2be2ffSJuli Mallett {
225e99f8bc0SEitan Adler 
226a33ee411SAlex Richardson 	fprintf(stderr, "usage: cat [-" SUPPORTED_FLAGS "] [file ...]\n");
227ca2be2ffSJuli Mallett 	exit(1);
2289f82c1d3SMark Murray 	/* NOTREACHED */
229ca2be2ffSJuli Mallett }
230ca2be2ffSJuli Mallett 
2319d32ecfcSMark Murray static void
scanfiles(char * argv[],int cooked __unused)232ed845580SAlex Richardson scanfiles(char *argv[], int cooked __unused)
2334b88c807SRodney W. Grimes {
23467bf019bSJaakko Heinonen 	int fd, i;
235cbf2d71fSMatthew Dillon 	char *path;
236ed845580SAlex Richardson #ifndef BOOTSTRAP_CAT
2371b00c916SRuslan Ermilov 	FILE *fp;
238ed845580SAlex Richardson #endif
2394b88c807SRodney W. Grimes 
24067bf019bSJaakko Heinonen 	i = 0;
24119271eb4SBryan Drewery 	fd = -1;
242cbf2d71fSMatthew Dillon 	while ((path = argv[i]) != NULL || i == 0) {
243cbf2d71fSMatthew Dillon 		if (path == NULL || strcmp(path, "-") == 0) {
2444b88c807SRodney W. Grimes 			filename = "stdin";
2451b00c916SRuslan Ermilov 			fd = STDIN_FILENO;
246cbf2d71fSMatthew Dillon 		} else {
247cbf2d71fSMatthew Dillon 			filename = path;
248aefe30c5SMariusz Zaborski 			fd = fileargs_open(fa, path);
249cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
250cbf2d71fSMatthew Dillon 			if (fd < 0 && errno == EOPNOTSUPP)
25143e09ab2SRuslan Ermilov 				fd = udom_open(path, O_RDONLY);
252cbf2d71fSMatthew Dillon #endif
253cbf2d71fSMatthew Dillon 		}
254cbf2d71fSMatthew Dillon 		if (fd < 0) {
255cbf2d71fSMatthew Dillon 			warn("%s", path);
256001aff9fSBruce Evans 			rval = 1;
257a33ee411SAlex Richardson #ifndef BOOTSTRAP_CAT
258cbf2d71fSMatthew Dillon 		} else if (cooked) {
2591b00c916SRuslan Ermilov 			if (fd == STDIN_FILENO)
2601b00c916SRuslan Ermilov 				cook_cat(stdin);
2611b00c916SRuslan Ermilov 			else {
2621b00c916SRuslan Ermilov 				fp = fdopen(fd, "r");
263cbf2d71fSMatthew Dillon 				cook_cat(fp);
264cbf2d71fSMatthew Dillon 				fclose(fp);
2651b00c916SRuslan Ermilov 			}
266a33ee411SAlex Richardson #endif
267cbf2d71fSMatthew Dillon 		} else {
2688113cc82SMartin Matuska #ifndef BOOTSTRAP_CAT
269c6f9df70SDag-Erling Smørgrav 			if (in_kernel_copy(fd) != 0) {
2703c773cadSMartin Matuska 				if (errno == EINVAL || errno == EBADF ||
2713c773cadSMartin Matuska 				    errno == EISDIR)
272cbf2d71fSMatthew Dillon 					raw_cat(fd);
2738113cc82SMartin Matuska 				else
274*86b4df97SKyle Evans 					err(1, "%s", filename);
2758113cc82SMartin Matuska 			}
2768113cc82SMartin Matuska #else
2778113cc82SMartin Matuska 			raw_cat(fd);
2788113cc82SMartin Matuska #endif
2791b00c916SRuslan Ermilov 			if (fd != STDIN_FILENO)
280cbf2d71fSMatthew Dillon 				close(fd);
2814b88c807SRodney W. Grimes 		}
282cbf2d71fSMatthew Dillon 		if (path == NULL)
283cbf2d71fSMatthew Dillon 			break;
284cbf2d71fSMatthew Dillon 		++i;
2854b88c807SRodney W. Grimes 	}
2864b88c807SRodney W. Grimes }
2874b88c807SRodney W. Grimes 
288a33ee411SAlex Richardson #ifndef BOOTSTRAP_CAT
289cbf2d71fSMatthew Dillon static void
cook_cat(FILE * fp)29078a3801dSWarner Losh cook_cat(FILE *fp)
2914b88c807SRodney W. Grimes {
29278a3801dSWarner Losh 	int ch, gobble, line, prev;
2932aa6b16fSAndrey A. Chernov 	wint_t wch;
2944b88c807SRodney W. Grimes 
2951b00c916SRuslan Ermilov 	/* Reset EOF condition on stdin. */
2961b00c916SRuslan Ermilov 	if (fp == stdin && feof(stdin))
2971b00c916SRuslan Ermilov 		clearerr(stdin);
2981b00c916SRuslan Ermilov 
2994b88c807SRodney W. Grimes 	line = gobble = 0;
3004b88c807SRodney W. Grimes 	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
3014b88c807SRodney W. Grimes 		if (prev == '\n') {
3024b88c807SRodney W. Grimes 			if (sflag) {
3034b88c807SRodney W. Grimes 				if (ch == '\n') {
304bf5f0c44STim J. Robbins 					if (gobble)
305bf5f0c44STim J. Robbins 						continue;
306bf5f0c44STim J. Robbins 					gobble = 1;
307bf5f0c44STim J. Robbins 				} else
308bf5f0c44STim J. Robbins 					gobble = 0;
309bf5f0c44STim J. Robbins 			}
3106d2e5f3dSSevan Janiyan 			if (nflag) {
3116d2e5f3dSSevan Janiyan 				if (!bflag || ch != '\n') {
312bf5f0c44STim J. Robbins 					(void)fprintf(stdout, "%6d\t", ++line);
313bf5f0c44STim J. Robbins 					if (ferror(stdout))
314bf5f0c44STim J. Robbins 						break;
3156d2e5f3dSSevan Janiyan 				} else if (eflag) {
3166d2e5f3dSSevan Janiyan 					(void)fprintf(stdout, "%6s\t", "");
3176d2e5f3dSSevan Janiyan 					if (ferror(stdout))
3186d2e5f3dSSevan Janiyan 						break;
3196d2e5f3dSSevan Janiyan 				}
320bf5f0c44STim J. Robbins 			}
321bf5f0c44STim J. Robbins 		}
322bf5f0c44STim J. Robbins 		if (ch == '\n') {
323bf5f0c44STim J. Robbins 			if (eflag && putchar('$') == EOF)
3244b88c807SRodney W. Grimes 				break;
3254b88c807SRodney W. Grimes 		} else if (ch == '\t') {
3264b88c807SRodney W. Grimes 			if (tflag) {
3274b88c807SRodney W. Grimes 				if (putchar('^') == EOF || putchar('I') == EOF)
3284b88c807SRodney W. Grimes 					break;
3294b88c807SRodney W. Grimes 				continue;
3304b88c807SRodney W. Grimes 			}
3314b88c807SRodney W. Grimes 		} else if (vflag) {
3322aa6b16fSAndrey A. Chernov 			(void)ungetc(ch, fp);
3332aa6b16fSAndrey A. Chernov 			/*
3342aa6b16fSAndrey A. Chernov 			 * Our getwc(3) doesn't change file position
3352aa6b16fSAndrey A. Chernov 			 * on error.
3362aa6b16fSAndrey A. Chernov 			 */
3372aa6b16fSAndrey A. Chernov 			if ((wch = getwc(fp)) == WEOF) {
3382aa6b16fSAndrey A. Chernov 				if (ferror(fp) && errno == EILSEQ) {
3392aa6b16fSAndrey A. Chernov 					clearerr(fp);
3402aa6b16fSAndrey A. Chernov 					/* Resync attempt. */
3412aa6b16fSAndrey A. Chernov 					memset(&fp->_mbstate, 0, sizeof(mbstate_t));
3422aa6b16fSAndrey A. Chernov 					if ((ch = getc(fp)) == EOF)
3432aa6b16fSAndrey A. Chernov 						break;
3442aa6b16fSAndrey A. Chernov 					wch = ch;
3452aa6b16fSAndrey A. Chernov 					goto ilseq;
3462aa6b16fSAndrey A. Chernov 				} else
3472aa6b16fSAndrey A. Chernov 					break;
3482aa6b16fSAndrey A. Chernov 			}
3492aa6b16fSAndrey A. Chernov 			if (!iswascii(wch) && !iswprint(wch)) {
3502aa6b16fSAndrey A. Chernov ilseq:
3514b88c807SRodney W. Grimes 				if (putchar('M') == EOF || putchar('-') == EOF)
3524b88c807SRodney W. Grimes 					break;
3532aa6b16fSAndrey A. Chernov 				wch = toascii(wch);
3544b88c807SRodney W. Grimes 			}
3552aa6b16fSAndrey A. Chernov 			if (iswcntrl(wch)) {
3562aa6b16fSAndrey A. Chernov 				ch = toascii(wch);
3572aa6b16fSAndrey A. Chernov 				ch = (ch == '\177') ? '?' : (ch | 0100);
3582aa6b16fSAndrey A. Chernov 				if (putchar('^') == EOF || putchar(ch) == EOF)
3594b88c807SRodney W. Grimes 					break;
3604b88c807SRodney W. Grimes 				continue;
3614b88c807SRodney W. Grimes 			}
3622aa6b16fSAndrey A. Chernov 			if (putwchar(wch) == WEOF)
3632aa6b16fSAndrey A. Chernov 				break;
3642aa6b16fSAndrey A. Chernov 			ch = -1;
3652aa6b16fSAndrey A. Chernov 			continue;
3664b88c807SRodney W. Grimes 		}
3674b88c807SRodney W. Grimes 		if (putchar(ch) == EOF)
3684b88c807SRodney W. Grimes 			break;
3694b88c807SRodney W. Grimes 	}
3704b88c807SRodney W. Grimes 	if (ferror(fp)) {
3714b88c807SRodney W. Grimes 		warn("%s", filename);
372001aff9fSBruce Evans 		rval = 1;
3734b88c807SRodney W. Grimes 		clearerr(fp);
3744b88c807SRodney W. Grimes 	}
3754b88c807SRodney W. Grimes 	if (ferror(stdout))
3764b88c807SRodney W. Grimes 		err(1, "stdout");
3774b88c807SRodney W. Grimes }
3788113cc82SMartin Matuska 
3798113cc82SMartin Matuska static ssize_t
in_kernel_copy(int rfd)3808113cc82SMartin Matuska in_kernel_copy(int rfd)
3818113cc82SMartin Matuska {
3828113cc82SMartin Matuska 	int wfd;
3838113cc82SMartin Matuska 	ssize_t ret;
3848113cc82SMartin Matuska 
3858113cc82SMartin Matuska 	wfd = fileno(stdout);
3868113cc82SMartin Matuska 	ret = 1;
3878113cc82SMartin Matuska 
3888113cc82SMartin Matuska 	while (ret > 0)
3898113cc82SMartin Matuska 		ret = copy_file_range(rfd, NULL, wfd, NULL, SSIZE_MAX, 0);
3908113cc82SMartin Matuska 
3918113cc82SMartin Matuska 	return (ret);
3928113cc82SMartin Matuska }
393a33ee411SAlex Richardson #endif /* BOOTSTRAP_CAT */
3944b88c807SRodney W. Grimes 
395cbf2d71fSMatthew Dillon static void
raw_cat(int rfd)39678a3801dSWarner Losh raw_cat(int rfd)
3974b88c807SRodney W. Grimes {
398ca23e64eSWarner Losh 	long pagesize;
39978a3801dSWarner Losh 	int off, wfd;
400a5da0999SWarner Losh 	ssize_t nr, nw;
401a5da0999SWarner Losh 	static size_t bsize;
4029afa09cdSMark Murray 	static char *buf = NULL;
4034b88c807SRodney W. Grimes 	struct stat sbuf;
4044b88c807SRodney W. Grimes 
4054b88c807SRodney W. Grimes 	wfd = fileno(stdout);
4064b88c807SRodney W. Grimes 	if (buf == NULL) {
4074b88c807SRodney W. Grimes 		if (fstat(wfd, &sbuf))
408e3481b29SJaakko Heinonen 			err(1, "stdout");
409e9cbc9a7SIvan Voras 		if (S_ISREG(sbuf.st_mode)) {
410e9cbc9a7SIvan Voras 			/* If there's plenty of RAM, use a large copy buffer */
411e9cbc9a7SIvan Voras 			if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD)
412e9cbc9a7SIvan Voras 				bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
413e9cbc9a7SIvan Voras 			else
414e9cbc9a7SIvan Voras 				bsize = BUFSIZE_SMALL;
415ca23e64eSWarner Losh 		} else {
416ca23e64eSWarner Losh 			bsize = sbuf.st_blksize;
417ca23e64eSWarner Losh 			pagesize = sysconf(_SC_PAGESIZE);
418ca23e64eSWarner Losh 			if (pagesize > 0)
419ca23e64eSWarner Losh 				bsize = MAX(bsize, (size_t)pagesize);
420ca23e64eSWarner Losh 		}
421d1762d1fSWarner Losh 		if ((buf = malloc(bsize)) == NULL)
422e9cbc9a7SIvan Voras 			err(1, "malloc() failure of IO buffer");
4234b88c807SRodney W. Grimes 	}
4244b88c807SRodney W. Grimes 	while ((nr = read(rfd, buf, bsize)) > 0)
4254b88c807SRodney W. Grimes 		for (off = 0; nr; nr -= nw, off += nw)
426a5da0999SWarner Losh 			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
4274b88c807SRodney W. Grimes 				err(1, "stdout");
428001aff9fSBruce Evans 	if (nr < 0) {
4294b88c807SRodney W. Grimes 		warn("%s", filename);
430001aff9fSBruce Evans 		rval = 1;
431001aff9fSBruce Evans 	}
4324b88c807SRodney W. Grimes }
433cbf2d71fSMatthew Dillon 
434cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT
435cbf2d71fSMatthew Dillon 
436cbf2d71fSMatthew Dillon static int
udom_open(const char * path,int flags)43778a3801dSWarner Losh udom_open(const char *path, int flags)
438cbf2d71fSMatthew Dillon {
4391c9fbb5aSHiroki Sato 	struct addrinfo hints, *res, *res0;
4401c9fbb5aSHiroki Sato 	char rpath[PATH_MAX];
4410614d739SMariusz Zaborski 	int error, fd, serrno;
442aefe30c5SMariusz Zaborski 	cap_rights_t rights;
443cbf2d71fSMatthew Dillon 
444cbf2d71fSMatthew Dillon 	/*
4451c9fbb5aSHiroki Sato 	 * Construct the unix domain socket address and attempt to connect.
446cbf2d71fSMatthew Dillon 	 */
4471c9fbb5aSHiroki Sato 	bzero(&hints, sizeof(hints));
4481c9fbb5aSHiroki Sato 	hints.ai_family = AF_LOCAL;
449aefe30c5SMariusz Zaborski 
450aefe30c5SMariusz Zaborski 	if (fileargs_realpath(fa, path, rpath) == NULL)
4511c9fbb5aSHiroki Sato 		return (-1);
452aefe30c5SMariusz Zaborski 
453aefe30c5SMariusz Zaborski 	error = cap_getaddrinfo(capnet, rpath, NULL, &hints, &res0);
4541c9fbb5aSHiroki Sato 	if (error) {
4551c9fbb5aSHiroki Sato 		warn("%s", gai_strerror(error));
4561c9fbb5aSHiroki Sato 		errno = EINVAL;
45788485b4aSTim J. Robbins 		return (-1);
45888485b4aSTim J. Robbins 	}
459aefe30c5SMariusz Zaborski 	cap_rights_init(&rights, CAP_CONNECT, CAP_READ, CAP_WRITE,
460aefe30c5SMariusz Zaborski 	    CAP_SHUTDOWN, CAP_FSTAT, CAP_FCNTL);
46138f57faaSAlfonso Gregory 
46238f57faaSAlfonso Gregory 	/* Default error if something goes wrong. */
46338f57faaSAlfonso Gregory 	serrno = EINVAL;
46438f57faaSAlfonso Gregory 
4651c9fbb5aSHiroki Sato 	for (res = res0; res != NULL; res = res->ai_next) {
4661c9fbb5aSHiroki Sato 		fd = socket(res->ai_family, res->ai_socktype,
4671c9fbb5aSHiroki Sato 		    res->ai_protocol);
4681c9fbb5aSHiroki Sato 		if (fd < 0) {
4696e8062c8SMariusz Zaborski 			serrno = errno;
4701c9fbb5aSHiroki Sato 			freeaddrinfo(res0);
4716e8062c8SMariusz Zaborski 			errno = serrno;
4721c9fbb5aSHiroki Sato 			return (-1);
4731c9fbb5aSHiroki Sato 		}
474ad4f3bdfSDag-Erling Smørgrav 		if (caph_rights_limit(fd, &rights) != 0) {
4756e8062c8SMariusz Zaborski 			serrno = errno;
476aefe30c5SMariusz Zaborski 			close(fd);
477c664d8dfSMariusz Zaborski 			freeaddrinfo(res0);
4786e8062c8SMariusz Zaborski 			errno = serrno;
479aefe30c5SMariusz Zaborski 			return (-1);
480aefe30c5SMariusz Zaborski 		}
481aefe30c5SMariusz Zaborski 		error = cap_connect(capnet, fd, res->ai_addr, res->ai_addrlen);
4821c9fbb5aSHiroki Sato 		if (error == 0)
4831c9fbb5aSHiroki Sato 			break;
4841c9fbb5aSHiroki Sato 		else {
4856e8062c8SMariusz Zaborski 			serrno = errno;
486cbf2d71fSMatthew Dillon 			close(fd);
487cbf2d71fSMatthew Dillon 		}
488cbf2d71fSMatthew Dillon 	}
4891c9fbb5aSHiroki Sato 	freeaddrinfo(res0);
490cbf2d71fSMatthew Dillon 
49138f57faaSAlfonso Gregory 	if (res == NULL) {
49238f57faaSAlfonso Gregory 		errno = serrno;
49338f57faaSAlfonso Gregory 		return (-1);
49438f57faaSAlfonso Gregory 	}
49538f57faaSAlfonso Gregory 
496cbf2d71fSMatthew Dillon 	/*
497cbf2d71fSMatthew Dillon 	 * handle the open flags by shutting down appropriate directions
498cbf2d71fSMatthew Dillon 	 */
49938f57faaSAlfonso Gregory 
500cbf2d71fSMatthew Dillon 	switch (flags & O_ACCMODE) {
501cbf2d71fSMatthew Dillon 	case O_RDONLY:
502aefe30c5SMariusz Zaborski 		cap_rights_clear(&rights, CAP_WRITE);
503c6f9df70SDag-Erling Smørgrav 		if (shutdown(fd, SHUT_WR) != 0)
5042c61418dSTim J. Robbins 			warn(NULL);
505cbf2d71fSMatthew Dillon 		break;
506cbf2d71fSMatthew Dillon 	case O_WRONLY:
507aefe30c5SMariusz Zaborski 		cap_rights_clear(&rights, CAP_READ);
508c6f9df70SDag-Erling Smørgrav 		if (shutdown(fd, SHUT_RD) != 0)
5092c61418dSTim J. Robbins 			warn(NULL);
510cbf2d71fSMatthew Dillon 		break;
511cbf2d71fSMatthew Dillon 	default:
512cbf2d71fSMatthew Dillon 		break;
513cbf2d71fSMatthew Dillon 	}
514aefe30c5SMariusz Zaborski 
515aefe30c5SMariusz Zaborski 	cap_rights_clear(&rights, CAP_CONNECT, CAP_SHUTDOWN);
516c6f9df70SDag-Erling Smørgrav 	if (caph_rights_limit(fd, &rights) != 0) {
5176e8062c8SMariusz Zaborski 		serrno = errno;
518aefe30c5SMariusz Zaborski 		close(fd);
5196e8062c8SMariusz Zaborski 		errno = serrno;
520aefe30c5SMariusz Zaborski 		return (-1);
521aefe30c5SMariusz Zaborski 	}
522cbf2d71fSMatthew Dillon 	return (fd);
523cbf2d71fSMatthew Dillon }
524cbf2d71fSMatthew Dillon 
525cbf2d71fSMatthew Dillon #endif
526