1139969Simp/*- 21556Srgrimes * Copyright (c) 1989, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kevin Fall. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 33114301Sobrien#if 0 341556Srgrimes#ifndef lint 3520412Sstevestatic char const copyright[] = 361556Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 371556Srgrimes The Regents of the University of California. All rights reserved.\n"; 381556Srgrimes#endif /* not lint */ 39114301Sobrien#endif 401556Srgrimes 411556Srgrimes#ifndef lint 4235772Scharnier#if 0 4336000Scharnierstatic char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; 4435772Scharnier#endif 451556Srgrimes#endif /* not lint */ 4699109Sobrien#include <sys/cdefs.h> 4799109Sobrien__FBSDID("$FreeBSD: stable/11/bin/cat/cat.c 337733 2018-08-14 01:45:22Z kevans $"); 481556Srgrimes 491556Srgrimes#include <sys/param.h> 501556Srgrimes#include <sys/stat.h> 5183482Sdillon#ifndef NO_UDOM_SUPPORT 5283482Sdillon#include <sys/socket.h> 5383482Sdillon#include <sys/un.h> 54288602Shrs#include <netdb.h> 5583482Sdillon#endif 561556Srgrimes 571556Srgrimes#include <ctype.h> 581556Srgrimes#include <err.h> 59337733Skevans#include <errno.h> 601556Srgrimes#include <fcntl.h> 6118578Sache#include <locale.h> 621556Srgrimes#include <stdio.h> 631556Srgrimes#include <stdlib.h> 6478732Sdd#include <string.h> 651556Srgrimes#include <unistd.h> 66306201Sache#include <wchar.h> 67306201Sache#include <wctype.h> 681556Srgrimes 69246083Sbrooksstatic int bflag, eflag, lflag, nflag, sflag, tflag, vflag; 70226961Sedstatic int rval; 71226961Sedstatic const char *filename; 721556Srgrimes 73249804Seadlerstatic void usage(void) __dead2; 74105781Smarkmstatic void scanfiles(char *argv[], int cooked); 7590106Simpstatic void cook_cat(FILE *); 7690106Simpstatic void raw_cat(int); 771556Srgrimes 7883482Sdillon#ifndef NO_UDOM_SUPPORT 7990106Simpstatic int udom_open(const char *path, int flags); 8083482Sdillon#endif 8183482Sdillon 82238652Sjh/* 83238652Sjh * Memory strategy threshold, in pages: if physmem is larger than this, 84238652Sjh * use a large buffer. 85238652Sjh */ 86238652Sjh#define PHYSPAGES_THRESHOLD (32 * 1024) 87184471Sivoras 88238652Sjh/* Maximum buffer size in bytes - do not allow it to grow larger than this. */ 89238652Sjh#define BUFSIZE_MAX (2 * 1024 * 1024) 90184471Sivoras 91238652Sjh/* 92238652Sjh * Small (default) buffer size in bytes. It's inefficient for this to be 93238652Sjh * smaller than MAXPHYS. 94238652Sjh */ 95238652Sjh#define BUFSIZE_SMALL (MAXPHYS) 96184471Sivoras 971556Srgrimesint 9890106Simpmain(int argc, char *argv[]) 991556Srgrimes{ 1001556Srgrimes int ch; 101246083Sbrooks struct flock stdout_lock; 1021556Srgrimes 10318578Sache setlocale(LC_CTYPE, ""); 10418578Sache 105246083Sbrooks while ((ch = getopt(argc, argv, "belnstuv")) != -1) 1061556Srgrimes switch (ch) { 1071556Srgrimes case 'b': 1081556Srgrimes bflag = nflag = 1; /* -b implies -n */ 1091556Srgrimes break; 1101556Srgrimes case 'e': 1111556Srgrimes eflag = vflag = 1; /* -e implies -v */ 1121556Srgrimes break; 113246083Sbrooks case 'l': 114246083Sbrooks lflag = 1; 115246083Sbrooks break; 1161556Srgrimes case 'n': 1171556Srgrimes nflag = 1; 1181556Srgrimes break; 1191556Srgrimes case 's': 1201556Srgrimes sflag = 1; 1211556Srgrimes break; 1221556Srgrimes case 't': 1231556Srgrimes tflag = vflag = 1; /* -t implies -v */ 1241556Srgrimes break; 1251556Srgrimes case 'u': 12659239Sasmodai setbuf(stdout, NULL); 1271556Srgrimes break; 1281556Srgrimes case 'v': 1291556Srgrimes vflag = 1; 1301556Srgrimes break; 13118546Simp default: 13298216Sjmallett usage(); 1331556Srgrimes } 1341556Srgrimes argv += optind; 1351556Srgrimes 136246083Sbrooks if (lflag) { 137246083Sbrooks stdout_lock.l_len = 0; 138246083Sbrooks stdout_lock.l_start = 0; 139246083Sbrooks stdout_lock.l_type = F_WRLCK; 140246083Sbrooks stdout_lock.l_whence = SEEK_SET; 141246083Sbrooks if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) 142246083Sbrooks err(EXIT_FAILURE, "stdout"); 143246083Sbrooks } 144246083Sbrooks 1451556Srgrimes if (bflag || eflag || nflag || sflag || tflag || vflag) 14683482Sdillon scanfiles(argv, 1); 1471556Srgrimes else 14883482Sdillon scanfiles(argv, 0); 1491556Srgrimes if (fclose(stdout)) 1501556Srgrimes err(1, "stdout"); 1511556Srgrimes exit(rval); 152101092Smarkm /* NOTREACHED */ 1531556Srgrimes} 1541556Srgrimes 15598216Sjmallettstatic void 15698216Sjmallettusage(void) 15798216Sjmallett{ 158249804Seadler 159246083Sbrooks fprintf(stderr, "usage: cat [-belnstuv] [file ...]\n"); 16098216Sjmallett exit(1); 161101092Smarkm /* NOTREACHED */ 16298216Sjmallett} 16398216Sjmallett 164105781Smarkmstatic void 165105781Smarkmscanfiles(char *argv[], int cooked) 1661556Srgrimes{ 167238652Sjh int fd, i; 16883482Sdillon char *path; 16983961Sru FILE *fp; 1701556Srgrimes 171238652Sjh i = 0; 172288630Sbdrewery fd = -1; 17383482Sdillon while ((path = argv[i]) != NULL || i == 0) { 17483482Sdillon if (path == NULL || strcmp(path, "-") == 0) { 17583482Sdillon filename = "stdin"; 17683961Sru fd = STDIN_FILENO; 17783482Sdillon } else { 17883482Sdillon filename = path; 17983482Sdillon fd = open(path, O_RDONLY); 18083482Sdillon#ifndef NO_UDOM_SUPPORT 18183482Sdillon if (fd < 0 && errno == EOPNOTSUPP) 18283962Sru fd = udom_open(path, O_RDONLY); 18383482Sdillon#endif 1841556Srgrimes } 18583482Sdillon if (fd < 0) { 18683482Sdillon warn("%s", path); 18783482Sdillon rval = 1; 18883482Sdillon } else if (cooked) { 18983961Sru if (fd == STDIN_FILENO) 19083961Sru cook_cat(stdin); 19183961Sru else { 19283961Sru fp = fdopen(fd, "r"); 19383961Sru cook_cat(fp); 19483961Sru fclose(fp); 19583961Sru } 19683482Sdillon } else { 19783482Sdillon raw_cat(fd); 19883961Sru if (fd != STDIN_FILENO) 19983961Sru close(fd); 20083482Sdillon } 20183482Sdillon if (path == NULL) 20283482Sdillon break; 20383482Sdillon ++i; 20483482Sdillon } 2051556Srgrimes} 2061556Srgrimes 20783482Sdillonstatic void 20890106Simpcook_cat(FILE *fp) 2091556Srgrimes{ 21090106Simp int ch, gobble, line, prev; 211306201Sache wint_t wch; 2121556Srgrimes 21383961Sru /* Reset EOF condition on stdin. */ 21483961Sru if (fp == stdin && feof(stdin)) 21583961Sru clearerr(stdin); 21683961Sru 2171556Srgrimes line = gobble = 0; 2181556Srgrimes for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 2191556Srgrimes if (prev == '\n') { 22098169Stjr if (sflag) { 22198169Stjr if (ch == '\n') { 22298169Stjr if (gobble) 22398169Stjr continue; 2241556Srgrimes gobble = 1; 22598169Stjr } else 22698169Stjr gobble = 0; 22798169Stjr } 228330738Seadler if (nflag && (!bflag || ch != '\n')) { 229330738Seadler (void)fprintf(stdout, "%6d\t", ++line); 230330738Seadler if (ferror(stdout)) 231330738Seadler break; 2321556Srgrimes } 2331556Srgrimes } 2341556Srgrimes if (ch == '\n') { 23598169Stjr if (eflag && putchar('$') == EOF) 23698169Stjr break; 2371556Srgrimes } else if (ch == '\t') { 2381556Srgrimes if (tflag) { 2391556Srgrimes if (putchar('^') == EOF || putchar('I') == EOF) 2401556Srgrimes break; 2411556Srgrimes continue; 2421556Srgrimes } 2431556Srgrimes } else if (vflag) { 244306201Sache (void)ungetc(ch, fp); 245306201Sache /* 246306201Sache * Our getwc(3) doesn't change file position 247306201Sache * on error. 248306201Sache */ 249306201Sache if ((wch = getwc(fp)) == WEOF) { 250306201Sache if (ferror(fp) && errno == EILSEQ) { 251306201Sache clearerr(fp); 252306201Sache /* Resync attempt. */ 253306201Sache memset(&fp->_mbstate, 0, sizeof(mbstate_t)); 254306201Sache if ((ch = getc(fp)) == EOF) 255306201Sache break; 256306201Sache wch = ch; 257306201Sache goto ilseq; 258306201Sache } else 259306201Sache break; 260306201Sache } 261306201Sache if (!iswascii(wch) && !iswprint(wch)) { 262306201Sacheilseq: 2631556Srgrimes if (putchar('M') == EOF || putchar('-') == EOF) 2641556Srgrimes break; 265306201Sache wch = toascii(wch); 2661556Srgrimes } 267306201Sache if (iswcntrl(wch)) { 268306201Sache ch = toascii(wch); 269306201Sache ch = (ch == '\177') ? '?' : (ch | 0100); 270306201Sache if (putchar('^') == EOF || putchar(ch) == EOF) 2711556Srgrimes break; 2721556Srgrimes continue; 2731556Srgrimes } 274306201Sache if (putwchar(wch) == WEOF) 275306201Sache break; 276306201Sache ch = -1; 277306201Sache continue; 2781556Srgrimes } 2791556Srgrimes if (putchar(ch) == EOF) 2801556Srgrimes break; 2811556Srgrimes } 2821556Srgrimes if (ferror(fp)) { 2831556Srgrimes warn("%s", filename); 28411145Sbde rval = 1; 2851556Srgrimes clearerr(fp); 2861556Srgrimes } 2871556Srgrimes if (ferror(stdout)) 2881556Srgrimes err(1, "stdout"); 2891556Srgrimes} 2901556Srgrimes 29183482Sdillonstatic void 29290106Simpraw_cat(int rfd) 2931556Srgrimes{ 29490106Simp int off, wfd; 29539065Simp ssize_t nr, nw; 29639065Simp static size_t bsize; 29791079Smarkm static char *buf = NULL; 2981556Srgrimes struct stat sbuf; 2991556Srgrimes 3001556Srgrimes wfd = fileno(stdout); 3011556Srgrimes if (buf == NULL) { 3021556Srgrimes if (fstat(wfd, &sbuf)) 303238653Sjh err(1, "stdout"); 304184471Sivoras if (S_ISREG(sbuf.st_mode)) { 305184471Sivoras /* If there's plenty of RAM, use a large copy buffer */ 306184471Sivoras if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) 307238652Sjh bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 308184471Sivoras else 309184471Sivoras bsize = BUFSIZE_SMALL; 310184471Sivoras } else 311238652Sjh bsize = MAX(sbuf.st_blksize, 312238652Sjh (blksize_t)sysconf(_SC_PAGESIZE)); 31339138Simp if ((buf = malloc(bsize)) == NULL) 314184471Sivoras err(1, "malloc() failure of IO buffer"); 3151556Srgrimes } 3161556Srgrimes while ((nr = read(rfd, buf, bsize)) > 0) 3171556Srgrimes for (off = 0; nr; nr -= nw, off += nw) 31839138Simp if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 3191556Srgrimes err(1, "stdout"); 32011145Sbde if (nr < 0) { 3211556Srgrimes warn("%s", filename); 32211145Sbde rval = 1; 32311145Sbde } 3241556Srgrimes} 32583482Sdillon 32683482Sdillon#ifndef NO_UDOM_SUPPORT 32783482Sdillon 32883482Sdillonstatic int 32990106Simpudom_open(const char *path, int flags) 33083482Sdillon{ 331288602Shrs struct addrinfo hints, *res, *res0; 332288602Shrs char rpath[PATH_MAX]; 333288645Ssbruno int fd = -1; 334288645Ssbruno int error; 33583482Sdillon 33683482Sdillon /* 337288602Shrs * Construct the unix domain socket address and attempt to connect. 33883482Sdillon */ 339288602Shrs bzero(&hints, sizeof(hints)); 340288602Shrs hints.ai_family = AF_LOCAL; 341288602Shrs if (realpath(path, rpath) == NULL) 342288602Shrs return (-1); 343288602Shrs error = getaddrinfo(rpath, NULL, &hints, &res0); 344288602Shrs if (error) { 345288602Shrs warn("%s", gai_strerror(error)); 346288602Shrs errno = EINVAL; 347288602Shrs return (-1); 348288602Shrs } 349288602Shrs for (res = res0; res != NULL; res = res->ai_next) { 350288602Shrs fd = socket(res->ai_family, res->ai_socktype, 351288602Shrs res->ai_protocol); 352288602Shrs if (fd < 0) { 353288602Shrs freeaddrinfo(res0); 35499022Stjr return (-1); 35599022Stjr } 356288602Shrs error = connect(fd, res->ai_addr, res->ai_addrlen); 357288602Shrs if (error == 0) 358288602Shrs break; 359288602Shrs else { 36083482Sdillon close(fd); 36183482Sdillon fd = -1; 36283482Sdillon } 36383482Sdillon } 364288602Shrs freeaddrinfo(res0); 36583482Sdillon 36683482Sdillon /* 36783482Sdillon * handle the open flags by shutting down appropriate directions 36883482Sdillon */ 36983482Sdillon if (fd >= 0) { 37083482Sdillon switch(flags & O_ACCMODE) { 37183482Sdillon case O_RDONLY: 37291079Smarkm if (shutdown(fd, SHUT_WR) == -1) 373132433Stjr warn(NULL); 37483482Sdillon break; 37583482Sdillon case O_WRONLY: 37691079Smarkm if (shutdown(fd, SHUT_RD) == -1) 377132433Stjr warn(NULL); 37883482Sdillon break; 37983482Sdillon default: 38083482Sdillon break; 38183482Sdillon } 38283482Sdillon } 383238652Sjh return (fd); 38483482Sdillon} 38583482Sdillon 38683482Sdillon#endif 387