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/10/bin/cat/cat.c 337734 2018-08-14 01:57:11Z 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> 5483482Sdillon#endif 551556Srgrimes 561556Srgrimes#include <ctype.h> 571556Srgrimes#include <err.h> 58337734Skevans#include <errno.h> 591556Srgrimes#include <fcntl.h> 6018578Sache#include <locale.h> 61238652Sjh#include <stddef.h> 621556Srgrimes#include <stdio.h> 631556Srgrimes#include <stdlib.h> 6478732Sdd#include <string.h> 651556Srgrimes#include <unistd.h> 66306200Sache#include <wchar.h> 67306200Sache#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; 17283482Sdillon while ((path = argv[i]) != NULL || i == 0) { 17383482Sdillon if (path == NULL || strcmp(path, "-") == 0) { 17483482Sdillon filename = "stdin"; 17583961Sru fd = STDIN_FILENO; 17683482Sdillon } else { 17783482Sdillon filename = path; 17883482Sdillon fd = open(path, O_RDONLY); 17983482Sdillon#ifndef NO_UDOM_SUPPORT 18083482Sdillon if (fd < 0 && errno == EOPNOTSUPP) 18183962Sru fd = udom_open(path, O_RDONLY); 18283482Sdillon#endif 1831556Srgrimes } 18483482Sdillon if (fd < 0) { 18583482Sdillon warn("%s", path); 18683482Sdillon rval = 1; 18783482Sdillon } else if (cooked) { 18883961Sru if (fd == STDIN_FILENO) 18983961Sru cook_cat(stdin); 19083961Sru else { 19183961Sru fp = fdopen(fd, "r"); 19283961Sru cook_cat(fp); 19383961Sru fclose(fp); 19483961Sru } 19583482Sdillon } else { 19683482Sdillon raw_cat(fd); 19783961Sru if (fd != STDIN_FILENO) 19883961Sru close(fd); 19983482Sdillon } 20083482Sdillon if (path == NULL) 20183482Sdillon break; 20283482Sdillon ++i; 20383482Sdillon } 2041556Srgrimes} 2051556Srgrimes 20683482Sdillonstatic void 20790106Simpcook_cat(FILE *fp) 2081556Srgrimes{ 20990106Simp int ch, gobble, line, prev; 210306200Sache wint_t wch; 2111556Srgrimes 21283961Sru /* Reset EOF condition on stdin. */ 21383961Sru if (fp == stdin && feof(stdin)) 21483961Sru clearerr(stdin); 21583961Sru 2161556Srgrimes line = gobble = 0; 2171556Srgrimes for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 2181556Srgrimes if (prev == '\n') { 21998169Stjr if (sflag) { 22098169Stjr if (ch == '\n') { 22198169Stjr if (gobble) 22298169Stjr continue; 2231556Srgrimes gobble = 1; 22498169Stjr } else 22598169Stjr gobble = 0; 22698169Stjr } 22798169Stjr if (nflag && (!bflag || ch != '\n')) { 22898169Stjr (void)fprintf(stdout, "%6d\t", ++line); 2291556Srgrimes if (ferror(stdout)) 2301556Srgrimes break; 2311556Srgrimes } 2321556Srgrimes } 2331556Srgrimes if (ch == '\n') { 23498169Stjr if (eflag && putchar('$') == EOF) 23598169Stjr break; 2361556Srgrimes } else if (ch == '\t') { 2371556Srgrimes if (tflag) { 2381556Srgrimes if (putchar('^') == EOF || putchar('I') == EOF) 2391556Srgrimes break; 2401556Srgrimes continue; 2411556Srgrimes } 2421556Srgrimes } else if (vflag) { 243306200Sache (void)ungetc(ch, fp); 244306200Sache /* 245306200Sache * Our getwc(3) doesn't change file position 246306200Sache * on error. 247306200Sache */ 248306200Sache if ((wch = getwc(fp)) == WEOF) { 249306200Sache if (ferror(fp) && errno == EILSEQ) { 250306200Sache clearerr(fp); 251306200Sache /* Resync attempt. */ 252306200Sache memset(&fp->_mbstate, 0, sizeof(mbstate_t)); 253306200Sache if ((ch = getc(fp)) == EOF) 254306200Sache break; 255306200Sache wch = ch; 256306200Sache goto ilseq; 257306200Sache } else 258306200Sache break; 259306200Sache } 260306200Sache if (!iswascii(wch) && !iswprint(wch)) { 261306200Sacheilseq: 2621556Srgrimes if (putchar('M') == EOF || putchar('-') == EOF) 2631556Srgrimes break; 264306200Sache wch = toascii(wch); 2651556Srgrimes } 266306200Sache if (iswcntrl(wch)) { 267306200Sache ch = toascii(wch); 268306200Sache ch = (ch == '\177') ? '?' : (ch | 0100); 269306200Sache if (putchar('^') == EOF || putchar(ch) == EOF) 2701556Srgrimes break; 2711556Srgrimes continue; 2721556Srgrimes } 273306200Sache if (putwchar(wch) == WEOF) 274306200Sache break; 275306200Sache ch = -1; 276306200Sache continue; 2771556Srgrimes } 2781556Srgrimes if (putchar(ch) == EOF) 2791556Srgrimes break; 2801556Srgrimes } 2811556Srgrimes if (ferror(fp)) { 2821556Srgrimes warn("%s", filename); 28311145Sbde rval = 1; 2841556Srgrimes clearerr(fp); 2851556Srgrimes } 2861556Srgrimes if (ferror(stdout)) 2871556Srgrimes err(1, "stdout"); 2881556Srgrimes} 2891556Srgrimes 29083482Sdillonstatic void 29190106Simpraw_cat(int rfd) 2921556Srgrimes{ 29390106Simp int off, wfd; 29439065Simp ssize_t nr, nw; 29539065Simp static size_t bsize; 29691079Smarkm static char *buf = NULL; 2971556Srgrimes struct stat sbuf; 2981556Srgrimes 2991556Srgrimes wfd = fileno(stdout); 3001556Srgrimes if (buf == NULL) { 3011556Srgrimes if (fstat(wfd, &sbuf)) 302238653Sjh err(1, "stdout"); 303184471Sivoras if (S_ISREG(sbuf.st_mode)) { 304184471Sivoras /* If there's plenty of RAM, use a large copy buffer */ 305184471Sivoras if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) 306238652Sjh bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 307184471Sivoras else 308184471Sivoras bsize = BUFSIZE_SMALL; 309184471Sivoras } else 310238652Sjh bsize = MAX(sbuf.st_blksize, 311238652Sjh (blksize_t)sysconf(_SC_PAGESIZE)); 31239138Simp if ((buf = malloc(bsize)) == NULL) 313184471Sivoras err(1, "malloc() failure of IO buffer"); 3141556Srgrimes } 3151556Srgrimes while ((nr = read(rfd, buf, bsize)) > 0) 3161556Srgrimes for (off = 0; nr; nr -= nw, off += nw) 31739138Simp if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 3181556Srgrimes err(1, "stdout"); 31911145Sbde if (nr < 0) { 3201556Srgrimes warn("%s", filename); 32111145Sbde rval = 1; 32211145Sbde } 3231556Srgrimes} 32483482Sdillon 32583482Sdillon#ifndef NO_UDOM_SUPPORT 32683482Sdillon 32783482Sdillonstatic int 32890106Simpudom_open(const char *path, int flags) 32983482Sdillon{ 33083482Sdillon struct sockaddr_un sou; 33183482Sdillon int fd; 33291079Smarkm unsigned int len; 33383482Sdillon 33483482Sdillon bzero(&sou, sizeof(sou)); 33583482Sdillon 33683482Sdillon /* 33783482Sdillon * Construct the unix domain socket address and attempt to connect 33883482Sdillon */ 33991079Smarkm fd = socket(AF_UNIX, SOCK_STREAM, 0); 34091079Smarkm if (fd >= 0) { 34183482Sdillon sou.sun_family = AF_UNIX; 34299022Stjr if ((len = strlcpy(sou.sun_path, path, 34399022Stjr sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) { 34499022Stjr errno = ENAMETOOLONG; 34599022Stjr return (-1); 34699022Stjr } 34783482Sdillon len = offsetof(struct sockaddr_un, sun_path[len+1]); 34883482Sdillon 34983482Sdillon if (connect(fd, (void *)&sou, len) < 0) { 35083482Sdillon close(fd); 35183482Sdillon fd = -1; 35283482Sdillon } 35383482Sdillon } 35483482Sdillon 35583482Sdillon /* 35683482Sdillon * handle the open flags by shutting down appropriate directions 35783482Sdillon */ 35883482Sdillon if (fd >= 0) { 35983482Sdillon switch(flags & O_ACCMODE) { 36083482Sdillon case O_RDONLY: 36191079Smarkm if (shutdown(fd, SHUT_WR) == -1) 362132433Stjr warn(NULL); 36383482Sdillon break; 36483482Sdillon case O_WRONLY: 36591079Smarkm if (shutdown(fd, SHUT_RD) == -1) 366132433Stjr warn(NULL); 36783482Sdillon break; 36883482Sdillon default: 36983482Sdillon break; 37083482Sdillon } 37183482Sdillon } 372238652Sjh return (fd); 37383482Sdillon} 37483482Sdillon 37583482Sdillon#endif 376