cat.c revision 240408
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/9/bin/cat/cat.c 240408 2012-09-12 16:01:48Z jh $"); 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 671556Srgrimesint bflag, eflag, nflag, sflag, tflag, vflag; 681556Srgrimesint rval; 6939065Simpconst 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; 991556Srgrimes 10018578Sache setlocale(LC_CTYPE, ""); 10118578Sache 10224348Simp while ((ch = getopt(argc, argv, "benstuv")) != -1) 1031556Srgrimes switch (ch) { 1041556Srgrimes case 'b': 1051556Srgrimes bflag = nflag = 1; /* -b implies -n */ 1061556Srgrimes break; 1071556Srgrimes case 'e': 1081556Srgrimes eflag = vflag = 1; /* -e implies -v */ 1091556Srgrimes break; 1101556Srgrimes case 'n': 1111556Srgrimes nflag = 1; 1121556Srgrimes break; 1131556Srgrimes case 's': 1141556Srgrimes sflag = 1; 1151556Srgrimes break; 1161556Srgrimes case 't': 1171556Srgrimes tflag = vflag = 1; /* -t implies -v */ 1181556Srgrimes break; 1191556Srgrimes case 'u': 12059239Sasmodai setbuf(stdout, NULL); 1211556Srgrimes break; 1221556Srgrimes case 'v': 1231556Srgrimes vflag = 1; 1241556Srgrimes break; 12518546Simp default: 12698216Sjmallett usage(); 1271556Srgrimes } 1281556Srgrimes argv += optind; 1291556Srgrimes 1301556Srgrimes if (bflag || eflag || nflag || sflag || tflag || vflag) 13183482Sdillon scanfiles(argv, 1); 1321556Srgrimes else 13383482Sdillon scanfiles(argv, 0); 1341556Srgrimes if (fclose(stdout)) 1351556Srgrimes err(1, "stdout"); 1361556Srgrimes exit(rval); 137101092Smarkm /* NOTREACHED */ 1381556Srgrimes} 1391556Srgrimes 14098216Sjmallettstatic void 14198216Sjmallettusage(void) 14298216Sjmallett{ 14398216Sjmallett fprintf(stderr, "usage: cat [-benstuv] [file ...]\n"); 14498216Sjmallett exit(1); 145101092Smarkm /* NOTREACHED */ 14698216Sjmallett} 14798216Sjmallett 148105781Smarkmstatic void 149105781Smarkmscanfiles(char *argv[], int cooked) 1501556Srgrimes{ 151240407Sjh int fd, i; 15283482Sdillon char *path; 15383961Sru FILE *fp; 1541556Srgrimes 155240407Sjh i = 0; 15683482Sdillon while ((path = argv[i]) != NULL || i == 0) { 15783482Sdillon if (path == NULL || strcmp(path, "-") == 0) { 15883482Sdillon filename = "stdin"; 15983961Sru fd = STDIN_FILENO; 16083482Sdillon } else { 16183482Sdillon filename = path; 16283482Sdillon fd = open(path, O_RDONLY); 16383482Sdillon#ifndef NO_UDOM_SUPPORT 16483482Sdillon if (fd < 0 && errno == EOPNOTSUPP) 16583962Sru fd = udom_open(path, O_RDONLY); 16683482Sdillon#endif 1671556Srgrimes } 16883482Sdillon if (fd < 0) { 16983482Sdillon warn("%s", path); 17083482Sdillon rval = 1; 17183482Sdillon } else if (cooked) { 17283961Sru if (fd == STDIN_FILENO) 17383961Sru cook_cat(stdin); 17483961Sru else { 17583961Sru fp = fdopen(fd, "r"); 17683961Sru cook_cat(fp); 17783961Sru fclose(fp); 17883961Sru } 17983482Sdillon } else { 18083482Sdillon raw_cat(fd); 18183961Sru if (fd != STDIN_FILENO) 18283961Sru close(fd); 18383482Sdillon } 18483482Sdillon if (path == NULL) 18583482Sdillon break; 18683482Sdillon ++i; 18783482Sdillon } 1881556Srgrimes} 1891556Srgrimes 19083482Sdillonstatic void 19190106Simpcook_cat(FILE *fp) 1921556Srgrimes{ 19390106Simp int ch, gobble, line, prev; 1941556Srgrimes 19583961Sru /* Reset EOF condition on stdin. */ 19683961Sru if (fp == stdin && feof(stdin)) 19783961Sru clearerr(stdin); 19883961Sru 1991556Srgrimes line = gobble = 0; 2001556Srgrimes for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 2011556Srgrimes if (prev == '\n') { 20298169Stjr if (sflag) { 20398169Stjr if (ch == '\n') { 20498169Stjr if (gobble) 20598169Stjr continue; 2061556Srgrimes gobble = 1; 20798169Stjr } else 20898169Stjr gobble = 0; 20998169Stjr } 21098169Stjr if (nflag && (!bflag || ch != '\n')) { 21198169Stjr (void)fprintf(stdout, "%6d\t", ++line); 2121556Srgrimes if (ferror(stdout)) 2131556Srgrimes break; 2141556Srgrimes } 2151556Srgrimes } 2161556Srgrimes if (ch == '\n') { 21798169Stjr if (eflag && putchar('$') == EOF) 21898169Stjr break; 2191556Srgrimes } else if (ch == '\t') { 2201556Srgrimes if (tflag) { 2211556Srgrimes if (putchar('^') == EOF || putchar('I') == EOF) 2221556Srgrimes break; 2231556Srgrimes continue; 2241556Srgrimes } 2251556Srgrimes } else if (vflag) { 22618578Sache if (!isascii(ch) && !isprint(ch)) { 2271556Srgrimes if (putchar('M') == EOF || putchar('-') == EOF) 2281556Srgrimes break; 2291556Srgrimes ch = toascii(ch); 2301556Srgrimes } 2311556Srgrimes if (iscntrl(ch)) { 2321556Srgrimes if (putchar('^') == EOF || 2331556Srgrimes putchar(ch == '\177' ? '?' : 2341556Srgrimes ch | 0100) == EOF) 2351556Srgrimes break; 2361556Srgrimes continue; 2371556Srgrimes } 2381556Srgrimes } 2391556Srgrimes if (putchar(ch) == EOF) 2401556Srgrimes break; 2411556Srgrimes } 2421556Srgrimes if (ferror(fp)) { 2431556Srgrimes warn("%s", filename); 24411145Sbde rval = 1; 2451556Srgrimes clearerr(fp); 2461556Srgrimes } 2471556Srgrimes if (ferror(stdout)) 2481556Srgrimes err(1, "stdout"); 2491556Srgrimes} 2501556Srgrimes 25183482Sdillonstatic void 25290106Simpraw_cat(int rfd) 2531556Srgrimes{ 25490106Simp int off, wfd; 25539065Simp ssize_t nr, nw; 25639065Simp static size_t bsize; 25791079Smarkm static char *buf = NULL; 2581556Srgrimes struct stat sbuf; 2591556Srgrimes 2601556Srgrimes wfd = fileno(stdout); 2611556Srgrimes if (buf == NULL) { 2621556Srgrimes if (fstat(wfd, &sbuf)) 263240408Sjh err(1, "stdout"); 264184471Sivoras if (S_ISREG(sbuf.st_mode)) { 265184471Sivoras /* If there's plenty of RAM, use a large copy buffer */ 266184471Sivoras if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) 267240407Sjh bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 268184471Sivoras else 269184471Sivoras bsize = BUFSIZE_SMALL; 270184471Sivoras } else 271240407Sjh bsize = MAX(sbuf.st_blksize, 272240407Sjh (blksize_t)sysconf(_SC_PAGESIZE)); 27339138Simp if ((buf = malloc(bsize)) == NULL) 274184471Sivoras err(1, "malloc() failure of IO buffer"); 2751556Srgrimes } 2761556Srgrimes while ((nr = read(rfd, buf, bsize)) > 0) 2771556Srgrimes for (off = 0; nr; nr -= nw, off += nw) 27839138Simp if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 2791556Srgrimes err(1, "stdout"); 28011145Sbde if (nr < 0) { 2811556Srgrimes warn("%s", filename); 28211145Sbde rval = 1; 28311145Sbde } 2841556Srgrimes} 28583482Sdillon 28683482Sdillon#ifndef NO_UDOM_SUPPORT 28783482Sdillon 28883482Sdillonstatic int 28990106Simpudom_open(const char *path, int flags) 29083482Sdillon{ 29183482Sdillon struct sockaddr_un sou; 29283482Sdillon int fd; 29391079Smarkm unsigned int len; 29483482Sdillon 29583482Sdillon bzero(&sou, sizeof(sou)); 29683482Sdillon 29783482Sdillon /* 29883482Sdillon * Construct the unix domain socket address and attempt to connect 29983482Sdillon */ 30091079Smarkm fd = socket(AF_UNIX, SOCK_STREAM, 0); 30191079Smarkm if (fd >= 0) { 30283482Sdillon sou.sun_family = AF_UNIX; 30399022Stjr if ((len = strlcpy(sou.sun_path, path, 30499022Stjr sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) { 30599022Stjr errno = ENAMETOOLONG; 30699022Stjr return (-1); 30799022Stjr } 30883482Sdillon len = offsetof(struct sockaddr_un, sun_path[len+1]); 30983482Sdillon 31083482Sdillon if (connect(fd, (void *)&sou, len) < 0) { 31183482Sdillon close(fd); 31283482Sdillon fd = -1; 31383482Sdillon } 31483482Sdillon } 31583482Sdillon 31683482Sdillon /* 31783482Sdillon * handle the open flags by shutting down appropriate directions 31883482Sdillon */ 31983482Sdillon if (fd >= 0) { 32083482Sdillon switch(flags & O_ACCMODE) { 32183482Sdillon case O_RDONLY: 32291079Smarkm if (shutdown(fd, SHUT_WR) == -1) 323132433Stjr warn(NULL); 32483482Sdillon break; 32583482Sdillon case O_WRONLY: 32691079Smarkm if (shutdown(fd, SHUT_RD) == -1) 327132433Stjr warn(NULL); 32883482Sdillon break; 32983482Sdillon default: 33083482Sdillon break; 33183482Sdillon } 33283482Sdillon } 333240407Sjh return (fd); 33483482Sdillon} 33583482Sdillon 33683482Sdillon#endif 337