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$"); 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#include <errno.h> 5583482Sdillon#endif 561556Srgrimes 571556Srgrimes#include <ctype.h> 581556Srgrimes#include <err.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> 661556Srgrimes 67246083Sbrooksstatic int bflag, eflag, lflag, nflag, sflag, tflag, vflag; 68226961Sedstatic int rval; 69226961Sedstatic const char *filename; 701556Srgrimes 71249804Seadlerstatic void usage(void) __dead2; 72105781Smarkmstatic void scanfiles(char *argv[], int cooked); 7390106Simpstatic void cook_cat(FILE *); 7490106Simpstatic void raw_cat(int); 751556Srgrimes 7683482Sdillon#ifndef NO_UDOM_SUPPORT 7790106Simpstatic int udom_open(const char *path, int flags); 7883482Sdillon#endif 7983482Sdillon 80238652Sjh/* 81238652Sjh * Memory strategy threshold, in pages: if physmem is larger than this, 82238652Sjh * use a large buffer. 83238652Sjh */ 84238652Sjh#define PHYSPAGES_THRESHOLD (32 * 1024) 85184471Sivoras 86238652Sjh/* Maximum buffer size in bytes - do not allow it to grow larger than this. */ 87238652Sjh#define BUFSIZE_MAX (2 * 1024 * 1024) 88184471Sivoras 89238652Sjh/* 90238652Sjh * Small (default) buffer size in bytes. It's inefficient for this to be 91238652Sjh * smaller than MAXPHYS. 92238652Sjh */ 93238652Sjh#define BUFSIZE_SMALL (MAXPHYS) 94184471Sivoras 951556Srgrimesint 9690106Simpmain(int argc, char *argv[]) 971556Srgrimes{ 981556Srgrimes int ch; 99246083Sbrooks struct flock stdout_lock; 1001556Srgrimes 10118578Sache setlocale(LC_CTYPE, ""); 10218578Sache 103246083Sbrooks while ((ch = getopt(argc, argv, "belnstuv")) != -1) 1041556Srgrimes switch (ch) { 1051556Srgrimes case 'b': 1061556Srgrimes bflag = nflag = 1; /* -b implies -n */ 1071556Srgrimes break; 1081556Srgrimes case 'e': 1091556Srgrimes eflag = vflag = 1; /* -e implies -v */ 1101556Srgrimes break; 111246083Sbrooks case 'l': 112246083Sbrooks lflag = 1; 113246083Sbrooks break; 1141556Srgrimes case 'n': 1151556Srgrimes nflag = 1; 1161556Srgrimes break; 1171556Srgrimes case 's': 1181556Srgrimes sflag = 1; 1191556Srgrimes break; 1201556Srgrimes case 't': 1211556Srgrimes tflag = vflag = 1; /* -t implies -v */ 1221556Srgrimes break; 1231556Srgrimes case 'u': 12459239Sasmodai setbuf(stdout, NULL); 1251556Srgrimes break; 1261556Srgrimes case 'v': 1271556Srgrimes vflag = 1; 1281556Srgrimes break; 12918546Simp default: 13098216Sjmallett usage(); 1311556Srgrimes } 1321556Srgrimes argv += optind; 1331556Srgrimes 134246083Sbrooks if (lflag) { 135246083Sbrooks stdout_lock.l_len = 0; 136246083Sbrooks stdout_lock.l_start = 0; 137246083Sbrooks stdout_lock.l_type = F_WRLCK; 138246083Sbrooks stdout_lock.l_whence = SEEK_SET; 139246083Sbrooks if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) 140246083Sbrooks err(EXIT_FAILURE, "stdout"); 141246083Sbrooks } 142246083Sbrooks 1431556Srgrimes if (bflag || eflag || nflag || sflag || tflag || vflag) 14483482Sdillon scanfiles(argv, 1); 1451556Srgrimes else 14683482Sdillon scanfiles(argv, 0); 1471556Srgrimes if (fclose(stdout)) 1481556Srgrimes err(1, "stdout"); 1491556Srgrimes exit(rval); 150101092Smarkm /* NOTREACHED */ 1511556Srgrimes} 1521556Srgrimes 15398216Sjmallettstatic void 15498216Sjmallettusage(void) 15598216Sjmallett{ 156249804Seadler 157246083Sbrooks fprintf(stderr, "usage: cat [-belnstuv] [file ...]\n"); 15898216Sjmallett exit(1); 159101092Smarkm /* NOTREACHED */ 16098216Sjmallett} 16198216Sjmallett 162105781Smarkmstatic void 163105781Smarkmscanfiles(char *argv[], int cooked) 1641556Srgrimes{ 165238652Sjh int fd, i; 16683482Sdillon char *path; 16783961Sru FILE *fp; 1681556Srgrimes 169238652Sjh i = 0; 17083482Sdillon while ((path = argv[i]) != NULL || i == 0) { 17183482Sdillon if (path == NULL || strcmp(path, "-") == 0) { 17283482Sdillon filename = "stdin"; 17383961Sru fd = STDIN_FILENO; 17483482Sdillon } else { 17583482Sdillon filename = path; 17683482Sdillon fd = open(path, O_RDONLY); 17783482Sdillon#ifndef NO_UDOM_SUPPORT 17883482Sdillon if (fd < 0 && errno == EOPNOTSUPP) 17983962Sru fd = udom_open(path, O_RDONLY); 18083482Sdillon#endif 1811556Srgrimes } 18283482Sdillon if (fd < 0) { 18383482Sdillon warn("%s", path); 18483482Sdillon rval = 1; 18583482Sdillon } else if (cooked) { 18683961Sru if (fd == STDIN_FILENO) 18783961Sru cook_cat(stdin); 18883961Sru else { 18983961Sru fp = fdopen(fd, "r"); 19083961Sru cook_cat(fp); 19183961Sru fclose(fp); 19283961Sru } 19383482Sdillon } else { 19483482Sdillon raw_cat(fd); 19583961Sru if (fd != STDIN_FILENO) 19683961Sru close(fd); 19783482Sdillon } 19883482Sdillon if (path == NULL) 19983482Sdillon break; 20083482Sdillon ++i; 20183482Sdillon } 2021556Srgrimes} 2031556Srgrimes 20483482Sdillonstatic void 20590106Simpcook_cat(FILE *fp) 2061556Srgrimes{ 20790106Simp int ch, gobble, line, prev; 2081556Srgrimes 20983961Sru /* Reset EOF condition on stdin. */ 21083961Sru if (fp == stdin && feof(stdin)) 21183961Sru clearerr(stdin); 21283961Sru 2131556Srgrimes line = gobble = 0; 2141556Srgrimes for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 2151556Srgrimes if (prev == '\n') { 21698169Stjr if (sflag) { 21798169Stjr if (ch == '\n') { 21898169Stjr if (gobble) 21998169Stjr continue; 2201556Srgrimes gobble = 1; 22198169Stjr } else 22298169Stjr gobble = 0; 22398169Stjr } 22498169Stjr if (nflag && (!bflag || ch != '\n')) { 22598169Stjr (void)fprintf(stdout, "%6d\t", ++line); 2261556Srgrimes if (ferror(stdout)) 2271556Srgrimes break; 2281556Srgrimes } 2291556Srgrimes } 2301556Srgrimes if (ch == '\n') { 23198169Stjr if (eflag && putchar('$') == EOF) 23298169Stjr break; 2331556Srgrimes } else if (ch == '\t') { 2341556Srgrimes if (tflag) { 2351556Srgrimes if (putchar('^') == EOF || putchar('I') == EOF) 2361556Srgrimes break; 2371556Srgrimes continue; 2381556Srgrimes } 2391556Srgrimes } else if (vflag) { 24018578Sache if (!isascii(ch) && !isprint(ch)) { 2411556Srgrimes if (putchar('M') == EOF || putchar('-') == EOF) 2421556Srgrimes break; 2431556Srgrimes ch = toascii(ch); 2441556Srgrimes } 2451556Srgrimes if (iscntrl(ch)) { 2461556Srgrimes if (putchar('^') == EOF || 2471556Srgrimes putchar(ch == '\177' ? '?' : 2481556Srgrimes ch | 0100) == EOF) 2491556Srgrimes break; 2501556Srgrimes continue; 2511556Srgrimes } 2521556Srgrimes } 2531556Srgrimes if (putchar(ch) == EOF) 2541556Srgrimes break; 2551556Srgrimes } 2561556Srgrimes if (ferror(fp)) { 2571556Srgrimes warn("%s", filename); 25811145Sbde rval = 1; 2591556Srgrimes clearerr(fp); 2601556Srgrimes } 2611556Srgrimes if (ferror(stdout)) 2621556Srgrimes err(1, "stdout"); 2631556Srgrimes} 2641556Srgrimes 26583482Sdillonstatic void 26690106Simpraw_cat(int rfd) 2671556Srgrimes{ 26890106Simp int off, wfd; 26939065Simp ssize_t nr, nw; 27039065Simp static size_t bsize; 27191079Smarkm static char *buf = NULL; 2721556Srgrimes struct stat sbuf; 2731556Srgrimes 2741556Srgrimes wfd = fileno(stdout); 2751556Srgrimes if (buf == NULL) { 2761556Srgrimes if (fstat(wfd, &sbuf)) 277238653Sjh err(1, "stdout"); 278184471Sivoras if (S_ISREG(sbuf.st_mode)) { 279184471Sivoras /* If there's plenty of RAM, use a large copy buffer */ 280184471Sivoras if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) 281238652Sjh bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 282184471Sivoras else 283184471Sivoras bsize = BUFSIZE_SMALL; 284184471Sivoras } else 285238652Sjh bsize = MAX(sbuf.st_blksize, 286238652Sjh (blksize_t)sysconf(_SC_PAGESIZE)); 28739138Simp if ((buf = malloc(bsize)) == NULL) 288184471Sivoras err(1, "malloc() failure of IO buffer"); 2891556Srgrimes } 2901556Srgrimes while ((nr = read(rfd, buf, bsize)) > 0) 2911556Srgrimes for (off = 0; nr; nr -= nw, off += nw) 29239138Simp if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 2931556Srgrimes err(1, "stdout"); 29411145Sbde if (nr < 0) { 2951556Srgrimes warn("%s", filename); 29611145Sbde rval = 1; 29711145Sbde } 2981556Srgrimes} 29983482Sdillon 30083482Sdillon#ifndef NO_UDOM_SUPPORT 30183482Sdillon 30283482Sdillonstatic int 30390106Simpudom_open(const char *path, int flags) 30483482Sdillon{ 30583482Sdillon struct sockaddr_un sou; 30683482Sdillon int fd; 30791079Smarkm unsigned int len; 30883482Sdillon 30983482Sdillon bzero(&sou, sizeof(sou)); 31083482Sdillon 31183482Sdillon /* 31283482Sdillon * Construct the unix domain socket address and attempt to connect 31383482Sdillon */ 31491079Smarkm fd = socket(AF_UNIX, SOCK_STREAM, 0); 31591079Smarkm if (fd >= 0) { 31683482Sdillon sou.sun_family = AF_UNIX; 31799022Stjr if ((len = strlcpy(sou.sun_path, path, 31899022Stjr sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) { 31999022Stjr errno = ENAMETOOLONG; 32099022Stjr return (-1); 32199022Stjr } 32283482Sdillon len = offsetof(struct sockaddr_un, sun_path[len+1]); 32383482Sdillon 32483482Sdillon if (connect(fd, (void *)&sou, len) < 0) { 32583482Sdillon close(fd); 32683482Sdillon fd = -1; 32783482Sdillon } 32883482Sdillon } 32983482Sdillon 33083482Sdillon /* 33183482Sdillon * handle the open flags by shutting down appropriate directions 33283482Sdillon */ 33383482Sdillon if (fd >= 0) { 33483482Sdillon switch(flags & O_ACCMODE) { 33583482Sdillon case O_RDONLY: 33691079Smarkm if (shutdown(fd, SHUT_WR) == -1) 337132433Stjr warn(NULL); 33883482Sdillon break; 33983482Sdillon case O_WRONLY: 34091079Smarkm if (shutdown(fd, SHUT_RD) == -1) 341132433Stjr warn(NULL); 34283482Sdillon break; 34383482Sdillon default: 34483482Sdillon break; 34583482Sdillon } 34683482Sdillon } 347238652Sjh return (fd); 34883482Sdillon} 34983482Sdillon 35083482Sdillon#endif 351