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> 61240407Sjh#include <stddef.h> 621556Srgrimes#include <stdio.h> 631556Srgrimes#include <stdlib.h> 6478732Sdd#include <string.h> 651556Srgrimes#include <unistd.h> 661556Srgrimes 67248337Sbrooksstatic int bflag, eflag, lflag, nflag, sflag, tflag, vflag; 68248337Sbrooksstatic int rval; 69248337Sbrooksstatic const char *filename; 701556Srgrimes 7198216Sjmallettstatic void usage(void); 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 80240407Sjh/* 81240407Sjh * Memory strategy threshold, in pages: if physmem is larger than this, 82240407Sjh * use a large buffer. 83240407Sjh */ 84240407Sjh#define PHYSPAGES_THRESHOLD (32 * 1024) 85184471Sivoras 86240407Sjh/* Maximum buffer size in bytes - do not allow it to grow larger than this. */ 87240407Sjh#define BUFSIZE_MAX (2 * 1024 * 1024) 88184471Sivoras 89240407Sjh/* 90240407Sjh * Small (default) buffer size in bytes. It's inefficient for this to be 91240407Sjh * smaller than MAXPHYS. 92240407Sjh */ 93240407Sjh#define BUFSIZE_SMALL (MAXPHYS) 94184471Sivoras 951556Srgrimesint 9690106Simpmain(int argc, char *argv[]) 971556Srgrimes{ 981556Srgrimes int ch; 99248337Sbrooks struct flock stdout_lock; 1001556Srgrimes 10118578Sache setlocale(LC_CTYPE, ""); 10218578Sache 103248337Sbrooks 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; 111248337Sbrooks case 'l': 112248337Sbrooks lflag = 1; 113248337Sbrooks 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 134248337Sbrooks if (lflag) { 135248337Sbrooks stdout_lock.l_len = 0; 136248337Sbrooks stdout_lock.l_start = 0; 137248337Sbrooks stdout_lock.l_type = F_WRLCK; 138248337Sbrooks stdout_lock.l_whence = SEEK_SET; 139248337Sbrooks if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) 140248337Sbrooks err(EXIT_FAILURE, "stdout"); 141248337Sbrooks } 142248337Sbrooks 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{ 156248337Sbrooks fprintf(stderr, "usage: cat [-belnstuv] [file ...]\n"); 15798216Sjmallett exit(1); 158101092Smarkm /* NOTREACHED */ 15998216Sjmallett} 16098216Sjmallett 161105781Smarkmstatic void 162105781Smarkmscanfiles(char *argv[], int cooked) 1631556Srgrimes{ 164240407Sjh int fd, i; 16583482Sdillon char *path; 16683961Sru FILE *fp; 1671556Srgrimes 168240407Sjh i = 0; 16983482Sdillon while ((path = argv[i]) != NULL || i == 0) { 17083482Sdillon if (path == NULL || strcmp(path, "-") == 0) { 17183482Sdillon filename = "stdin"; 17283961Sru fd = STDIN_FILENO; 17383482Sdillon } else { 17483482Sdillon filename = path; 17583482Sdillon fd = open(path, O_RDONLY); 17683482Sdillon#ifndef NO_UDOM_SUPPORT 17783482Sdillon if (fd < 0 && errno == EOPNOTSUPP) 17883962Sru fd = udom_open(path, O_RDONLY); 17983482Sdillon#endif 1801556Srgrimes } 18183482Sdillon if (fd < 0) { 18283482Sdillon warn("%s", path); 18383482Sdillon rval = 1; 18483482Sdillon } else if (cooked) { 18583961Sru if (fd == STDIN_FILENO) 18683961Sru cook_cat(stdin); 18783961Sru else { 18883961Sru fp = fdopen(fd, "r"); 18983961Sru cook_cat(fp); 19083961Sru fclose(fp); 19183961Sru } 19283482Sdillon } else { 19383482Sdillon raw_cat(fd); 19483961Sru if (fd != STDIN_FILENO) 19583961Sru close(fd); 19683482Sdillon } 19783482Sdillon if (path == NULL) 19883482Sdillon break; 19983482Sdillon ++i; 20083482Sdillon } 2011556Srgrimes} 2021556Srgrimes 20383482Sdillonstatic void 20490106Simpcook_cat(FILE *fp) 2051556Srgrimes{ 20690106Simp int ch, gobble, line, prev; 2071556Srgrimes 20883961Sru /* Reset EOF condition on stdin. */ 20983961Sru if (fp == stdin && feof(stdin)) 21083961Sru clearerr(stdin); 21183961Sru 2121556Srgrimes line = gobble = 0; 2131556Srgrimes for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 2141556Srgrimes if (prev == '\n') { 21598169Stjr if (sflag) { 21698169Stjr if (ch == '\n') { 21798169Stjr if (gobble) 21898169Stjr continue; 2191556Srgrimes gobble = 1; 22098169Stjr } else 22198169Stjr gobble = 0; 22298169Stjr } 22398169Stjr if (nflag && (!bflag || ch != '\n')) { 22498169Stjr (void)fprintf(stdout, "%6d\t", ++line); 2251556Srgrimes if (ferror(stdout)) 2261556Srgrimes break; 2271556Srgrimes } 2281556Srgrimes } 2291556Srgrimes if (ch == '\n') { 23098169Stjr if (eflag && putchar('$') == EOF) 23198169Stjr break; 2321556Srgrimes } else if (ch == '\t') { 2331556Srgrimes if (tflag) { 2341556Srgrimes if (putchar('^') == EOF || putchar('I') == EOF) 2351556Srgrimes break; 2361556Srgrimes continue; 2371556Srgrimes } 2381556Srgrimes } else if (vflag) { 23918578Sache if (!isascii(ch) && !isprint(ch)) { 2401556Srgrimes if (putchar('M') == EOF || putchar('-') == EOF) 2411556Srgrimes break; 2421556Srgrimes ch = toascii(ch); 2431556Srgrimes } 2441556Srgrimes if (iscntrl(ch)) { 2451556Srgrimes if (putchar('^') == EOF || 2461556Srgrimes putchar(ch == '\177' ? '?' : 2471556Srgrimes ch | 0100) == EOF) 2481556Srgrimes break; 2491556Srgrimes continue; 2501556Srgrimes } 2511556Srgrimes } 2521556Srgrimes if (putchar(ch) == EOF) 2531556Srgrimes break; 2541556Srgrimes } 2551556Srgrimes if (ferror(fp)) { 2561556Srgrimes warn("%s", filename); 25711145Sbde rval = 1; 2581556Srgrimes clearerr(fp); 2591556Srgrimes } 2601556Srgrimes if (ferror(stdout)) 2611556Srgrimes err(1, "stdout"); 2621556Srgrimes} 2631556Srgrimes 26483482Sdillonstatic void 26590106Simpraw_cat(int rfd) 2661556Srgrimes{ 26790106Simp int off, wfd; 26839065Simp ssize_t nr, nw; 26939065Simp static size_t bsize; 27091079Smarkm static char *buf = NULL; 2711556Srgrimes struct stat sbuf; 2721556Srgrimes 2731556Srgrimes wfd = fileno(stdout); 2741556Srgrimes if (buf == NULL) { 2751556Srgrimes if (fstat(wfd, &sbuf)) 276240408Sjh err(1, "stdout"); 277184471Sivoras if (S_ISREG(sbuf.st_mode)) { 278184471Sivoras /* If there's plenty of RAM, use a large copy buffer */ 279184471Sivoras if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) 280240407Sjh bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 281184471Sivoras else 282184471Sivoras bsize = BUFSIZE_SMALL; 283184471Sivoras } else 284240407Sjh bsize = MAX(sbuf.st_blksize, 285240407Sjh (blksize_t)sysconf(_SC_PAGESIZE)); 28639138Simp if ((buf = malloc(bsize)) == NULL) 287184471Sivoras err(1, "malloc() failure of IO buffer"); 2881556Srgrimes } 2891556Srgrimes while ((nr = read(rfd, buf, bsize)) > 0) 2901556Srgrimes for (off = 0; nr; nr -= nw, off += nw) 29139138Simp if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 2921556Srgrimes err(1, "stdout"); 29311145Sbde if (nr < 0) { 2941556Srgrimes warn("%s", filename); 29511145Sbde rval = 1; 29611145Sbde } 2971556Srgrimes} 29883482Sdillon 29983482Sdillon#ifndef NO_UDOM_SUPPORT 30083482Sdillon 30183482Sdillonstatic int 30290106Simpudom_open(const char *path, int flags) 30383482Sdillon{ 30483482Sdillon struct sockaddr_un sou; 30583482Sdillon int fd; 30691079Smarkm unsigned int len; 30783482Sdillon 30883482Sdillon bzero(&sou, sizeof(sou)); 30983482Sdillon 31083482Sdillon /* 31183482Sdillon * Construct the unix domain socket address and attempt to connect 31283482Sdillon */ 31391079Smarkm fd = socket(AF_UNIX, SOCK_STREAM, 0); 31491079Smarkm if (fd >= 0) { 31583482Sdillon sou.sun_family = AF_UNIX; 31699022Stjr if ((len = strlcpy(sou.sun_path, path, 31799022Stjr sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) { 31899022Stjr errno = ENAMETOOLONG; 31999022Stjr return (-1); 32099022Stjr } 32183482Sdillon len = offsetof(struct sockaddr_un, sun_path[len+1]); 32283482Sdillon 32383482Sdillon if (connect(fd, (void *)&sou, len) < 0) { 32483482Sdillon close(fd); 32583482Sdillon fd = -1; 32683482Sdillon } 32783482Sdillon } 32883482Sdillon 32983482Sdillon /* 33083482Sdillon * handle the open flags by shutting down appropriate directions 33183482Sdillon */ 33283482Sdillon if (fd >= 0) { 33383482Sdillon switch(flags & O_ACCMODE) { 33483482Sdillon case O_RDONLY: 33591079Smarkm if (shutdown(fd, SHUT_WR) == -1) 336132433Stjr warn(NULL); 33783482Sdillon break; 33883482Sdillon case O_WRONLY: 33991079Smarkm if (shutdown(fd, SHUT_RD) == -1) 340132433Stjr warn(NULL); 34183482Sdillon break; 34283482Sdillon default: 34383482Sdillon break; 34483482Sdillon } 34583482Sdillon } 346240407Sjh return (fd); 34783482Sdillon} 34883482Sdillon 34983482Sdillon#endif 350