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