19ddb49cbSWarner Losh /*- 24b88c807SRodney W. Grimes * Copyright (c) 1989, 1993 34b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 44b88c807SRodney W. Grimes * 54b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 64b88c807SRodney W. Grimes * Kevin Fall. 74b88c807SRodney W. Grimes * 84b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 94b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 104b88c807SRodney W. Grimes * are met: 114b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 124b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 134b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 144b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 154b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 164b88c807SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 174b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 184b88c807SRodney W. Grimes * without specific prior written permission. 194b88c807SRodney W. Grimes * 204b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 214b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 244b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304b88c807SRodney W. Grimes * SUCH DAMAGE. 314b88c807SRodney W. Grimes */ 324b88c807SRodney W. Grimes 330d22cdf0SDavid E. O'Brien #if 0 344b88c807SRodney W. Grimes #ifndef lint 35890acb95SSteve Price static char const copyright[] = 364b88c807SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\ 374b88c807SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 384b88c807SRodney W. Grimes #endif /* not lint */ 390d22cdf0SDavid E. O'Brien #endif 404b88c807SRodney W. Grimes 414b88c807SRodney W. Grimes #ifndef lint 424c95995fSPhilippe Charnier #if 0 4312f93eb9SPhilippe Charnier static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; 444c95995fSPhilippe Charnier #endif 454b88c807SRodney W. Grimes #endif /* not lint */ 465eb43ac2SDavid E. O'Brien #include <sys/cdefs.h> 475eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 484b88c807SRodney W. Grimes 494b88c807SRodney W. Grimes #include <sys/param.h> 504b88c807SRodney W. Grimes #include <sys/stat.h> 51cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 52cbf2d71fSMatthew Dillon #include <sys/socket.h> 53cbf2d71fSMatthew Dillon #include <sys/un.h> 54cbf2d71fSMatthew Dillon #include <errno.h> 55cbf2d71fSMatthew Dillon #endif 564b88c807SRodney W. Grimes 574b88c807SRodney W. Grimes #include <ctype.h> 584b88c807SRodney W. Grimes #include <err.h> 594b88c807SRodney W. Grimes #include <fcntl.h> 603043192bSAndrey A. Chernov #include <locale.h> 614b88c807SRodney W. Grimes #include <stdio.h> 624b88c807SRodney W. Grimes #include <stdlib.h> 63cafefe8cSDima Dorfman #include <string.h> 644b88c807SRodney W. Grimes #include <unistd.h> 65cbf2d71fSMatthew Dillon #include <stddef.h> 664b88c807SRodney W. Grimes 67*f9d4afb4SEd Schouten static int bflag, eflag, nflag, sflag, tflag, vflag; 68*f9d4afb4SEd Schouten static int rval; 69*f9d4afb4SEd Schouten static const char *filename; 704b88c807SRodney W. Grimes 71ca2be2ffSJuli Mallett static void usage(void); 729d32ecfcSMark Murray static void scanfiles(char *argv[], int cooked); 7378a3801dSWarner Losh static void cook_cat(FILE *); 7478a3801dSWarner Losh static void raw_cat(int); 75cbf2d71fSMatthew Dillon 76cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 7778a3801dSWarner Losh static int udom_open(const char *path, int flags); 78cbf2d71fSMatthew Dillon #endif 794b88c807SRodney W. Grimes 80e9cbc9a7SIvan Voras /* Memory strategy threshold, in pages: if physmem is larger then this, use a 81e9cbc9a7SIvan Voras * large buffer */ 82e9cbc9a7SIvan Voras #define PHYSPAGES_THRESHOLD (32*1024) 83e9cbc9a7SIvan Voras 84e9cbc9a7SIvan Voras /* Maximum buffer size in bytes - do not allow it to grow larger than this */ 85e9cbc9a7SIvan Voras #define BUFSIZE_MAX (2*1024*1024) 86e9cbc9a7SIvan Voras 87e9cbc9a7SIvan Voras /* Small (default) buffer size in bytes. It's inefficient for this to be 88e9cbc9a7SIvan Voras * smaller than MAXPHYS */ 89e9cbc9a7SIvan Voras #define BUFSIZE_SMALL (MAXPHYS) 90e9cbc9a7SIvan Voras 914b88c807SRodney W. Grimes int 9278a3801dSWarner Losh main(int argc, char *argv[]) 934b88c807SRodney W. Grimes { 944b88c807SRodney W. Grimes int ch; 954b88c807SRodney W. Grimes 963043192bSAndrey A. Chernov setlocale(LC_CTYPE, ""); 973043192bSAndrey A. Chernov 9893ef08afSWarner Losh while ((ch = getopt(argc, argv, "benstuv")) != -1) 994b88c807SRodney W. Grimes switch (ch) { 1004b88c807SRodney W. Grimes case 'b': 1014b88c807SRodney W. Grimes bflag = nflag = 1; /* -b implies -n */ 1024b88c807SRodney W. Grimes break; 1034b88c807SRodney W. Grimes case 'e': 1044b88c807SRodney W. Grimes eflag = vflag = 1; /* -e implies -v */ 1054b88c807SRodney W. Grimes break; 1064b88c807SRodney W. Grimes case 'n': 1074b88c807SRodney W. Grimes nflag = 1; 1084b88c807SRodney W. Grimes break; 1094b88c807SRodney W. Grimes case 's': 1104b88c807SRodney W. Grimes sflag = 1; 1114b88c807SRodney W. Grimes break; 1124b88c807SRodney W. Grimes case 't': 1134b88c807SRodney W. Grimes tflag = vflag = 1; /* -t implies -v */ 1144b88c807SRodney W. Grimes break; 1154b88c807SRodney W. Grimes case 'u': 1162192b407SJeroen Ruigrok van der Werven setbuf(stdout, NULL); 1174b88c807SRodney W. Grimes break; 1184b88c807SRodney W. Grimes case 'v': 1194b88c807SRodney W. Grimes vflag = 1; 1204b88c807SRodney W. Grimes break; 1218d72a3d7SWarner Losh default: 122ca2be2ffSJuli Mallett usage(); 1234b88c807SRodney W. Grimes } 1244b88c807SRodney W. Grimes argv += optind; 1254b88c807SRodney W. Grimes 1264b88c807SRodney W. Grimes if (bflag || eflag || nflag || sflag || tflag || vflag) 127cbf2d71fSMatthew Dillon scanfiles(argv, 1); 1284b88c807SRodney W. Grimes else 129cbf2d71fSMatthew Dillon scanfiles(argv, 0); 1304b88c807SRodney W. Grimes if (fclose(stdout)) 1314b88c807SRodney W. Grimes err(1, "stdout"); 1324b88c807SRodney W. Grimes exit(rval); 1339f82c1d3SMark Murray /* NOTREACHED */ 1344b88c807SRodney W. Grimes } 1354b88c807SRodney W. Grimes 136ca2be2ffSJuli Mallett static void 137ca2be2ffSJuli Mallett usage(void) 138ca2be2ffSJuli Mallett { 139ca2be2ffSJuli Mallett fprintf(stderr, "usage: cat [-benstuv] [file ...]\n"); 140ca2be2ffSJuli Mallett exit(1); 1419f82c1d3SMark Murray /* NOTREACHED */ 142ca2be2ffSJuli Mallett } 143ca2be2ffSJuli Mallett 1449d32ecfcSMark Murray static void 1459d32ecfcSMark Murray scanfiles(char *argv[], int cooked) 1464b88c807SRodney W. Grimes { 147cbf2d71fSMatthew Dillon int i = 0; 148cbf2d71fSMatthew Dillon char *path; 1491b00c916SRuslan Ermilov FILE *fp; 1504b88c807SRodney W. Grimes 151cbf2d71fSMatthew Dillon while ((path = argv[i]) != NULL || i == 0) { 152cbf2d71fSMatthew Dillon int fd; 153cbf2d71fSMatthew Dillon 154cbf2d71fSMatthew Dillon if (path == NULL || strcmp(path, "-") == 0) { 1554b88c807SRodney W. Grimes filename = "stdin"; 1561b00c916SRuslan Ermilov fd = STDIN_FILENO; 157cbf2d71fSMatthew Dillon } else { 158cbf2d71fSMatthew Dillon filename = path; 159cbf2d71fSMatthew Dillon fd = open(path, O_RDONLY); 160cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 161cbf2d71fSMatthew Dillon if (fd < 0 && errno == EOPNOTSUPP) 16243e09ab2SRuslan Ermilov fd = udom_open(path, O_RDONLY); 163cbf2d71fSMatthew Dillon #endif 164cbf2d71fSMatthew Dillon } 165cbf2d71fSMatthew Dillon if (fd < 0) { 166cbf2d71fSMatthew Dillon warn("%s", path); 167001aff9fSBruce Evans rval = 1; 168cbf2d71fSMatthew Dillon } else if (cooked) { 1691b00c916SRuslan Ermilov if (fd == STDIN_FILENO) 1701b00c916SRuslan Ermilov cook_cat(stdin); 1711b00c916SRuslan Ermilov else { 1721b00c916SRuslan Ermilov fp = fdopen(fd, "r"); 173cbf2d71fSMatthew Dillon cook_cat(fp); 174cbf2d71fSMatthew Dillon fclose(fp); 1751b00c916SRuslan Ermilov } 176cbf2d71fSMatthew Dillon } else { 177cbf2d71fSMatthew Dillon raw_cat(fd); 1781b00c916SRuslan Ermilov if (fd != STDIN_FILENO) 179cbf2d71fSMatthew Dillon close(fd); 1804b88c807SRodney W. Grimes } 181cbf2d71fSMatthew Dillon if (path == NULL) 182cbf2d71fSMatthew Dillon break; 183cbf2d71fSMatthew Dillon ++i; 1844b88c807SRodney W. Grimes } 1854b88c807SRodney W. Grimes } 1864b88c807SRodney W. Grimes 187cbf2d71fSMatthew Dillon static void 18878a3801dSWarner Losh cook_cat(FILE *fp) 1894b88c807SRodney W. Grimes { 19078a3801dSWarner Losh int ch, gobble, line, prev; 1914b88c807SRodney W. Grimes 1921b00c916SRuslan Ermilov /* Reset EOF condition on stdin. */ 1931b00c916SRuslan Ermilov if (fp == stdin && feof(stdin)) 1941b00c916SRuslan Ermilov clearerr(stdin); 1951b00c916SRuslan Ermilov 1964b88c807SRodney W. Grimes line = gobble = 0; 1974b88c807SRodney W. Grimes for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 1984b88c807SRodney W. Grimes if (prev == '\n') { 1994b88c807SRodney W. Grimes if (sflag) { 2004b88c807SRodney W. Grimes if (ch == '\n') { 201bf5f0c44STim J. Robbins if (gobble) 202bf5f0c44STim J. Robbins continue; 203bf5f0c44STim J. Robbins gobble = 1; 204bf5f0c44STim J. Robbins } else 205bf5f0c44STim J. Robbins gobble = 0; 206bf5f0c44STim J. Robbins } 207bf5f0c44STim J. Robbins if (nflag && (!bflag || ch != '\n')) { 208bf5f0c44STim J. Robbins (void)fprintf(stdout, "%6d\t", ++line); 209bf5f0c44STim J. Robbins if (ferror(stdout)) 210bf5f0c44STim J. Robbins break; 211bf5f0c44STim J. Robbins } 212bf5f0c44STim J. Robbins } 213bf5f0c44STim J. Robbins if (ch == '\n') { 214bf5f0c44STim J. Robbins if (eflag && putchar('$') == EOF) 2154b88c807SRodney W. Grimes break; 2164b88c807SRodney W. Grimes } else if (ch == '\t') { 2174b88c807SRodney W. Grimes if (tflag) { 2184b88c807SRodney W. Grimes if (putchar('^') == EOF || putchar('I') == EOF) 2194b88c807SRodney W. Grimes break; 2204b88c807SRodney W. Grimes continue; 2214b88c807SRodney W. Grimes } 2224b88c807SRodney W. Grimes } else if (vflag) { 2233043192bSAndrey A. Chernov if (!isascii(ch) && !isprint(ch)) { 2244b88c807SRodney W. Grimes if (putchar('M') == EOF || putchar('-') == EOF) 2254b88c807SRodney W. Grimes break; 2264b88c807SRodney W. Grimes ch = toascii(ch); 2274b88c807SRodney W. Grimes } 2284b88c807SRodney W. Grimes if (iscntrl(ch)) { 2294b88c807SRodney W. Grimes if (putchar('^') == EOF || 2304b88c807SRodney W. Grimes putchar(ch == '\177' ? '?' : 2314b88c807SRodney W. Grimes ch | 0100) == EOF) 2324b88c807SRodney W. Grimes break; 2334b88c807SRodney W. Grimes continue; 2344b88c807SRodney W. Grimes } 2354b88c807SRodney W. Grimes } 2364b88c807SRodney W. Grimes if (putchar(ch) == EOF) 2374b88c807SRodney W. Grimes break; 2384b88c807SRodney W. Grimes } 2394b88c807SRodney W. Grimes if (ferror(fp)) { 2404b88c807SRodney W. Grimes warn("%s", filename); 241001aff9fSBruce Evans rval = 1; 2424b88c807SRodney W. Grimes clearerr(fp); 2434b88c807SRodney W. Grimes } 2444b88c807SRodney W. Grimes if (ferror(stdout)) 2454b88c807SRodney W. Grimes err(1, "stdout"); 2464b88c807SRodney W. Grimes } 2474b88c807SRodney W. Grimes 248cbf2d71fSMatthew Dillon static void 24978a3801dSWarner Losh raw_cat(int rfd) 2504b88c807SRodney W. Grimes { 25178a3801dSWarner Losh int off, wfd; 252a5da0999SWarner Losh ssize_t nr, nw; 253a5da0999SWarner Losh static size_t bsize; 2549afa09cdSMark Murray static char *buf = NULL; 2554b88c807SRodney W. Grimes struct stat sbuf; 2564b88c807SRodney W. Grimes 2574b88c807SRodney W. Grimes wfd = fileno(stdout); 2584b88c807SRodney W. Grimes if (buf == NULL) { 2594b88c807SRodney W. Grimes if (fstat(wfd, &sbuf)) 2604b88c807SRodney W. Grimes err(1, "%s", filename); 261e9cbc9a7SIvan Voras if (S_ISREG(sbuf.st_mode)) { 262e9cbc9a7SIvan Voras /* If there's plenty of RAM, use a large copy buffer */ 263e9cbc9a7SIvan Voras if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) 264e9cbc9a7SIvan Voras bsize = MIN(BUFSIZE_MAX, MAXPHYS*8); 265e9cbc9a7SIvan Voras else 266e9cbc9a7SIvan Voras bsize = BUFSIZE_SMALL; 267e9cbc9a7SIvan Voras } else 268e9cbc9a7SIvan Voras bsize = MAX(sbuf.st_blksize, 269e9cbc9a7SIvan Voras (blksize_t)sysconf(_SC_PAGESIZE)); 270d1762d1fSWarner Losh if ((buf = malloc(bsize)) == NULL) 271e9cbc9a7SIvan Voras err(1, "malloc() failure of IO buffer"); 2724b88c807SRodney W. Grimes } 2734b88c807SRodney W. Grimes while ((nr = read(rfd, buf, bsize)) > 0) 2744b88c807SRodney W. Grimes for (off = 0; nr; nr -= nw, off += nw) 275a5da0999SWarner Losh if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 2764b88c807SRodney W. Grimes err(1, "stdout"); 277001aff9fSBruce Evans if (nr < 0) { 2784b88c807SRodney W. Grimes warn("%s", filename); 279001aff9fSBruce Evans rval = 1; 280001aff9fSBruce Evans } 2814b88c807SRodney W. Grimes } 282cbf2d71fSMatthew Dillon 283cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 284cbf2d71fSMatthew Dillon 285cbf2d71fSMatthew Dillon static int 28678a3801dSWarner Losh udom_open(const char *path, int flags) 287cbf2d71fSMatthew Dillon { 288cbf2d71fSMatthew Dillon struct sockaddr_un sou; 289cbf2d71fSMatthew Dillon int fd; 2909afa09cdSMark Murray unsigned int len; 291cbf2d71fSMatthew Dillon 292cbf2d71fSMatthew Dillon bzero(&sou, sizeof(sou)); 293cbf2d71fSMatthew Dillon 294cbf2d71fSMatthew Dillon /* 295cbf2d71fSMatthew Dillon * Construct the unix domain socket address and attempt to connect 296cbf2d71fSMatthew Dillon */ 2979afa09cdSMark Murray fd = socket(AF_UNIX, SOCK_STREAM, 0); 2989afa09cdSMark Murray if (fd >= 0) { 299cbf2d71fSMatthew Dillon sou.sun_family = AF_UNIX; 30088485b4aSTim J. Robbins if ((len = strlcpy(sou.sun_path, path, 30188485b4aSTim J. Robbins sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) { 30288485b4aSTim J. Robbins errno = ENAMETOOLONG; 30388485b4aSTim J. Robbins return (-1); 30488485b4aSTim J. Robbins } 305cbf2d71fSMatthew Dillon len = offsetof(struct sockaddr_un, sun_path[len+1]); 306cbf2d71fSMatthew Dillon 307cbf2d71fSMatthew Dillon if (connect(fd, (void *)&sou, len) < 0) { 308cbf2d71fSMatthew Dillon close(fd); 309cbf2d71fSMatthew Dillon fd = -1; 310cbf2d71fSMatthew Dillon } 311cbf2d71fSMatthew Dillon } 312cbf2d71fSMatthew Dillon 313cbf2d71fSMatthew Dillon /* 314cbf2d71fSMatthew Dillon * handle the open flags by shutting down appropriate directions 315cbf2d71fSMatthew Dillon */ 316cbf2d71fSMatthew Dillon if (fd >= 0) { 317cbf2d71fSMatthew Dillon switch(flags & O_ACCMODE) { 318cbf2d71fSMatthew Dillon case O_RDONLY: 3199afa09cdSMark Murray if (shutdown(fd, SHUT_WR) == -1) 3202c61418dSTim J. Robbins warn(NULL); 321cbf2d71fSMatthew Dillon break; 322cbf2d71fSMatthew Dillon case O_WRONLY: 3239afa09cdSMark Murray if (shutdown(fd, SHUT_RD) == -1) 3242c61418dSTim J. Robbins warn(NULL); 325cbf2d71fSMatthew Dillon break; 326cbf2d71fSMatthew Dillon default: 327cbf2d71fSMatthew Dillon break; 328cbf2d71fSMatthew Dillon } 329cbf2d71fSMatthew Dillon } 330cbf2d71fSMatthew Dillon return(fd); 331cbf2d71fSMatthew Dillon } 332cbf2d71fSMatthew Dillon 333cbf2d71fSMatthew Dillon #endif 334