19ddb49cbSWarner Losh /*- 24b88c807SRodney W. Grimes * Copyright (c) 1989, 1993 34b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 44b88c807SRodney W. Grimes * 54b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 64b88c807SRodney W. Grimes * Kevin Fall. 74b88c807SRodney W. Grimes * 84b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 94b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 104b88c807SRodney W. Grimes * are met: 114b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 124b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 134b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 144b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 154b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 164b88c807SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 174b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 184b88c807SRodney W. Grimes * without specific prior written permission. 194b88c807SRodney W. Grimes * 204b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 214b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 244b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304b88c807SRodney W. Grimes * SUCH DAMAGE. 314b88c807SRodney W. Grimes */ 324b88c807SRodney W. Grimes 330d22cdf0SDavid E. O'Brien #if 0 344b88c807SRodney W. Grimes #ifndef lint 35890acb95SSteve Price static char const copyright[] = 364b88c807SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\ 374b88c807SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 384b88c807SRodney W. Grimes #endif /* not lint */ 390d22cdf0SDavid E. O'Brien #endif 404b88c807SRodney W. Grimes 414b88c807SRodney W. Grimes #ifndef lint 424c95995fSPhilippe Charnier #if 0 4312f93eb9SPhilippe Charnier static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; 444c95995fSPhilippe Charnier #endif 454b88c807SRodney W. Grimes #endif /* not lint */ 465eb43ac2SDavid E. O'Brien #include <sys/cdefs.h> 475eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 484b88c807SRodney W. Grimes 494b88c807SRodney W. Grimes #include <sys/param.h> 504b88c807SRodney W. Grimes #include <sys/stat.h> 51cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 52cbf2d71fSMatthew Dillon #include <sys/socket.h> 53cbf2d71fSMatthew Dillon #include <sys/un.h> 54cbf2d71fSMatthew Dillon #include <errno.h> 55cbf2d71fSMatthew Dillon #endif 564b88c807SRodney W. Grimes 574b88c807SRodney W. Grimes #include <ctype.h> 584b88c807SRodney W. Grimes #include <err.h> 594b88c807SRodney W. Grimes #include <fcntl.h> 603043192bSAndrey A. Chernov #include <locale.h> 6167bf019bSJaakko Heinonen #include <stddef.h> 624b88c807SRodney W. Grimes #include <stdio.h> 634b88c807SRodney W. Grimes #include <stdlib.h> 64cafefe8cSDima Dorfman #include <string.h> 654b88c807SRodney W. Grimes #include <unistd.h> 664b88c807SRodney W. Grimes 67aece80a2SBrooks Davis static int bflag, eflag, lflag, nflag, sflag, tflag, vflag; 68f9d4afb4SEd Schouten static int rval; 69f9d4afb4SEd Schouten static const char *filename; 704b88c807SRodney W. Grimes 71*e99f8bc0SEitan Adler static void usage(void) __dead2; 729d32ecfcSMark Murray static void scanfiles(char *argv[], int cooked); 7378a3801dSWarner Losh static void cook_cat(FILE *); 7478a3801dSWarner Losh static void raw_cat(int); 75cbf2d71fSMatthew Dillon 76cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 7778a3801dSWarner Losh static int udom_open(const char *path, int flags); 78cbf2d71fSMatthew Dillon #endif 794b88c807SRodney W. Grimes 8067bf019bSJaakko Heinonen /* 8167bf019bSJaakko Heinonen * Memory strategy threshold, in pages: if physmem is larger than this, 8267bf019bSJaakko Heinonen * use a large buffer. 8367bf019bSJaakko Heinonen */ 84e9cbc9a7SIvan Voras #define PHYSPAGES_THRESHOLD (32 * 1024) 85e9cbc9a7SIvan Voras 8667bf019bSJaakko Heinonen /* Maximum buffer size in bytes - do not allow it to grow larger than this. */ 87e9cbc9a7SIvan Voras #define BUFSIZE_MAX (2 * 1024 * 1024) 88e9cbc9a7SIvan Voras 8967bf019bSJaakko Heinonen /* 9067bf019bSJaakko Heinonen * Small (default) buffer size in bytes. It's inefficient for this to be 9167bf019bSJaakko Heinonen * smaller than MAXPHYS. 9267bf019bSJaakko Heinonen */ 93e9cbc9a7SIvan Voras #define BUFSIZE_SMALL (MAXPHYS) 94e9cbc9a7SIvan Voras 954b88c807SRodney W. Grimes int 9678a3801dSWarner Losh main(int argc, char *argv[]) 974b88c807SRodney W. Grimes { 984b88c807SRodney W. Grimes int ch; 99aece80a2SBrooks Davis struct flock stdout_lock; 1004b88c807SRodney W. Grimes 1013043192bSAndrey A. Chernov setlocale(LC_CTYPE, ""); 1023043192bSAndrey A. Chernov 103aece80a2SBrooks Davis while ((ch = getopt(argc, argv, "belnstuv")) != -1) 1044b88c807SRodney W. Grimes switch (ch) { 1054b88c807SRodney W. Grimes case 'b': 1064b88c807SRodney W. Grimes bflag = nflag = 1; /* -b implies -n */ 1074b88c807SRodney W. Grimes break; 1084b88c807SRodney W. Grimes case 'e': 1094b88c807SRodney W. Grimes eflag = vflag = 1; /* -e implies -v */ 1104b88c807SRodney W. Grimes break; 111aece80a2SBrooks Davis case 'l': 112aece80a2SBrooks Davis lflag = 1; 113aece80a2SBrooks Davis break; 1144b88c807SRodney W. Grimes case 'n': 1154b88c807SRodney W. Grimes nflag = 1; 1164b88c807SRodney W. Grimes break; 1174b88c807SRodney W. Grimes case 's': 1184b88c807SRodney W. Grimes sflag = 1; 1194b88c807SRodney W. Grimes break; 1204b88c807SRodney W. Grimes case 't': 1214b88c807SRodney W. Grimes tflag = vflag = 1; /* -t implies -v */ 1224b88c807SRodney W. Grimes break; 1234b88c807SRodney W. Grimes case 'u': 1242192b407SJeroen Ruigrok van der Werven setbuf(stdout, NULL); 1254b88c807SRodney W. Grimes break; 1264b88c807SRodney W. Grimes case 'v': 1274b88c807SRodney W. Grimes vflag = 1; 1284b88c807SRodney W. Grimes break; 1298d72a3d7SWarner Losh default: 130ca2be2ffSJuli Mallett usage(); 1314b88c807SRodney W. Grimes } 1324b88c807SRodney W. Grimes argv += optind; 1334b88c807SRodney W. Grimes 134aece80a2SBrooks Davis if (lflag) { 135aece80a2SBrooks Davis stdout_lock.l_len = 0; 136aece80a2SBrooks Davis stdout_lock.l_start = 0; 137aece80a2SBrooks Davis stdout_lock.l_type = F_WRLCK; 138aece80a2SBrooks Davis stdout_lock.l_whence = SEEK_SET; 139aece80a2SBrooks Davis if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) 140aece80a2SBrooks Davis err(EXIT_FAILURE, "stdout"); 141aece80a2SBrooks Davis } 142aece80a2SBrooks Davis 1434b88c807SRodney W. Grimes if (bflag || eflag || nflag || sflag || tflag || vflag) 144cbf2d71fSMatthew Dillon scanfiles(argv, 1); 1454b88c807SRodney W. Grimes else 146cbf2d71fSMatthew Dillon scanfiles(argv, 0); 1474b88c807SRodney W. Grimes if (fclose(stdout)) 1484b88c807SRodney W. Grimes err(1, "stdout"); 1494b88c807SRodney W. Grimes exit(rval); 1509f82c1d3SMark Murray /* NOTREACHED */ 1514b88c807SRodney W. Grimes } 1524b88c807SRodney W. Grimes 153ca2be2ffSJuli Mallett static void 154ca2be2ffSJuli Mallett usage(void) 155ca2be2ffSJuli Mallett { 156*e99f8bc0SEitan Adler 157aece80a2SBrooks Davis fprintf(stderr, "usage: cat [-belnstuv] [file ...]\n"); 158ca2be2ffSJuli Mallett exit(1); 1599f82c1d3SMark Murray /* NOTREACHED */ 160ca2be2ffSJuli Mallett } 161ca2be2ffSJuli Mallett 1629d32ecfcSMark Murray static void 1639d32ecfcSMark Murray scanfiles(char *argv[], int cooked) 1644b88c807SRodney W. Grimes { 16567bf019bSJaakko Heinonen int fd, i; 166cbf2d71fSMatthew Dillon char *path; 1671b00c916SRuslan Ermilov FILE *fp; 1684b88c807SRodney W. Grimes 16967bf019bSJaakko Heinonen i = 0; 170cbf2d71fSMatthew Dillon while ((path = argv[i]) != NULL || i == 0) { 171cbf2d71fSMatthew Dillon if (path == NULL || strcmp(path, "-") == 0) { 1724b88c807SRodney W. Grimes filename = "stdin"; 1731b00c916SRuslan Ermilov fd = STDIN_FILENO; 174cbf2d71fSMatthew Dillon } else { 175cbf2d71fSMatthew Dillon filename = path; 176cbf2d71fSMatthew Dillon fd = open(path, O_RDONLY); 177cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 178cbf2d71fSMatthew Dillon if (fd < 0 && errno == EOPNOTSUPP) 17943e09ab2SRuslan Ermilov fd = udom_open(path, O_RDONLY); 180cbf2d71fSMatthew Dillon #endif 181cbf2d71fSMatthew Dillon } 182cbf2d71fSMatthew Dillon if (fd < 0) { 183cbf2d71fSMatthew Dillon warn("%s", path); 184001aff9fSBruce Evans rval = 1; 185cbf2d71fSMatthew Dillon } else if (cooked) { 1861b00c916SRuslan Ermilov if (fd == STDIN_FILENO) 1871b00c916SRuslan Ermilov cook_cat(stdin); 1881b00c916SRuslan Ermilov else { 1891b00c916SRuslan Ermilov fp = fdopen(fd, "r"); 190cbf2d71fSMatthew Dillon cook_cat(fp); 191cbf2d71fSMatthew Dillon fclose(fp); 1921b00c916SRuslan Ermilov } 193cbf2d71fSMatthew Dillon } else { 194cbf2d71fSMatthew Dillon raw_cat(fd); 1951b00c916SRuslan Ermilov if (fd != STDIN_FILENO) 196cbf2d71fSMatthew Dillon close(fd); 1974b88c807SRodney W. Grimes } 198cbf2d71fSMatthew Dillon if (path == NULL) 199cbf2d71fSMatthew Dillon break; 200cbf2d71fSMatthew Dillon ++i; 2014b88c807SRodney W. Grimes } 2024b88c807SRodney W. Grimes } 2034b88c807SRodney W. Grimes 204cbf2d71fSMatthew Dillon static void 20578a3801dSWarner Losh cook_cat(FILE *fp) 2064b88c807SRodney W. Grimes { 20778a3801dSWarner Losh int ch, gobble, line, prev; 2084b88c807SRodney W. Grimes 2091b00c916SRuslan Ermilov /* Reset EOF condition on stdin. */ 2101b00c916SRuslan Ermilov if (fp == stdin && feof(stdin)) 2111b00c916SRuslan Ermilov clearerr(stdin); 2121b00c916SRuslan Ermilov 2134b88c807SRodney W. Grimes line = gobble = 0; 2144b88c807SRodney W. Grimes for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 2154b88c807SRodney W. Grimes if (prev == '\n') { 2164b88c807SRodney W. Grimes if (sflag) { 2174b88c807SRodney W. Grimes if (ch == '\n') { 218bf5f0c44STim J. Robbins if (gobble) 219bf5f0c44STim J. Robbins continue; 220bf5f0c44STim J. Robbins gobble = 1; 221bf5f0c44STim J. Robbins } else 222bf5f0c44STim J. Robbins gobble = 0; 223bf5f0c44STim J. Robbins } 224bf5f0c44STim J. Robbins if (nflag && (!bflag || ch != '\n')) { 225bf5f0c44STim J. Robbins (void)fprintf(stdout, "%6d\t", ++line); 226bf5f0c44STim J. Robbins if (ferror(stdout)) 227bf5f0c44STim J. Robbins break; 228bf5f0c44STim J. Robbins } 229bf5f0c44STim J. Robbins } 230bf5f0c44STim J. Robbins if (ch == '\n') { 231bf5f0c44STim J. Robbins if (eflag && putchar('$') == EOF) 2324b88c807SRodney W. Grimes break; 2334b88c807SRodney W. Grimes } else if (ch == '\t') { 2344b88c807SRodney W. Grimes if (tflag) { 2354b88c807SRodney W. Grimes if (putchar('^') == EOF || putchar('I') == EOF) 2364b88c807SRodney W. Grimes break; 2374b88c807SRodney W. Grimes continue; 2384b88c807SRodney W. Grimes } 2394b88c807SRodney W. Grimes } else if (vflag) { 2403043192bSAndrey A. Chernov if (!isascii(ch) && !isprint(ch)) { 2414b88c807SRodney W. Grimes if (putchar('M') == EOF || putchar('-') == EOF) 2424b88c807SRodney W. Grimes break; 2434b88c807SRodney W. Grimes ch = toascii(ch); 2444b88c807SRodney W. Grimes } 2454b88c807SRodney W. Grimes if (iscntrl(ch)) { 2464b88c807SRodney W. Grimes if (putchar('^') == EOF || 2474b88c807SRodney W. Grimes putchar(ch == '\177' ? '?' : 2484b88c807SRodney W. Grimes ch | 0100) == EOF) 2494b88c807SRodney W. Grimes break; 2504b88c807SRodney W. Grimes continue; 2514b88c807SRodney W. Grimes } 2524b88c807SRodney W. Grimes } 2534b88c807SRodney W. Grimes if (putchar(ch) == EOF) 2544b88c807SRodney W. Grimes break; 2554b88c807SRodney W. Grimes } 2564b88c807SRodney W. Grimes if (ferror(fp)) { 2574b88c807SRodney W. Grimes warn("%s", filename); 258001aff9fSBruce Evans rval = 1; 2594b88c807SRodney W. Grimes clearerr(fp); 2604b88c807SRodney W. Grimes } 2614b88c807SRodney W. Grimes if (ferror(stdout)) 2624b88c807SRodney W. Grimes err(1, "stdout"); 2634b88c807SRodney W. Grimes } 2644b88c807SRodney W. Grimes 265cbf2d71fSMatthew Dillon static void 26678a3801dSWarner Losh raw_cat(int rfd) 2674b88c807SRodney W. Grimes { 26878a3801dSWarner Losh int off, wfd; 269a5da0999SWarner Losh ssize_t nr, nw; 270a5da0999SWarner Losh static size_t bsize; 2719afa09cdSMark Murray static char *buf = NULL; 2724b88c807SRodney W. Grimes struct stat sbuf; 2734b88c807SRodney W. Grimes 2744b88c807SRodney W. Grimes wfd = fileno(stdout); 2754b88c807SRodney W. Grimes if (buf == NULL) { 2764b88c807SRodney W. Grimes if (fstat(wfd, &sbuf)) 277e3481b29SJaakko Heinonen err(1, "stdout"); 278e9cbc9a7SIvan Voras if (S_ISREG(sbuf.st_mode)) { 279e9cbc9a7SIvan Voras /* If there's plenty of RAM, use a large copy buffer */ 280e9cbc9a7SIvan Voras if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) 281e9cbc9a7SIvan Voras bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 282e9cbc9a7SIvan Voras else 283e9cbc9a7SIvan Voras bsize = BUFSIZE_SMALL; 284e9cbc9a7SIvan Voras } else 285e9cbc9a7SIvan Voras bsize = MAX(sbuf.st_blksize, 286e9cbc9a7SIvan Voras (blksize_t)sysconf(_SC_PAGESIZE)); 287d1762d1fSWarner Losh if ((buf = malloc(bsize)) == NULL) 288e9cbc9a7SIvan Voras err(1, "malloc() failure of IO buffer"); 2894b88c807SRodney W. Grimes } 2904b88c807SRodney W. Grimes while ((nr = read(rfd, buf, bsize)) > 0) 2914b88c807SRodney W. Grimes for (off = 0; nr; nr -= nw, off += nw) 292a5da0999SWarner Losh if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 2934b88c807SRodney W. Grimes err(1, "stdout"); 294001aff9fSBruce Evans if (nr < 0) { 2954b88c807SRodney W. Grimes warn("%s", filename); 296001aff9fSBruce Evans rval = 1; 297001aff9fSBruce Evans } 2984b88c807SRodney W. Grimes } 299cbf2d71fSMatthew Dillon 300cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 301cbf2d71fSMatthew Dillon 302cbf2d71fSMatthew Dillon static int 30378a3801dSWarner Losh udom_open(const char *path, int flags) 304cbf2d71fSMatthew Dillon { 305cbf2d71fSMatthew Dillon struct sockaddr_un sou; 306cbf2d71fSMatthew Dillon int fd; 3079afa09cdSMark Murray unsigned int len; 308cbf2d71fSMatthew Dillon 309cbf2d71fSMatthew Dillon bzero(&sou, sizeof(sou)); 310cbf2d71fSMatthew Dillon 311cbf2d71fSMatthew Dillon /* 312cbf2d71fSMatthew Dillon * Construct the unix domain socket address and attempt to connect 313cbf2d71fSMatthew Dillon */ 3149afa09cdSMark Murray fd = socket(AF_UNIX, SOCK_STREAM, 0); 3159afa09cdSMark Murray if (fd >= 0) { 316cbf2d71fSMatthew Dillon sou.sun_family = AF_UNIX; 31788485b4aSTim J. Robbins if ((len = strlcpy(sou.sun_path, path, 31888485b4aSTim J. Robbins sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) { 31988485b4aSTim J. Robbins errno = ENAMETOOLONG; 32088485b4aSTim J. Robbins return (-1); 32188485b4aSTim J. Robbins } 322cbf2d71fSMatthew Dillon len = offsetof(struct sockaddr_un, sun_path[len+1]); 323cbf2d71fSMatthew Dillon 324cbf2d71fSMatthew Dillon if (connect(fd, (void *)&sou, len) < 0) { 325cbf2d71fSMatthew Dillon close(fd); 326cbf2d71fSMatthew Dillon fd = -1; 327cbf2d71fSMatthew Dillon } 328cbf2d71fSMatthew Dillon } 329cbf2d71fSMatthew Dillon 330cbf2d71fSMatthew Dillon /* 331cbf2d71fSMatthew Dillon * handle the open flags by shutting down appropriate directions 332cbf2d71fSMatthew Dillon */ 333cbf2d71fSMatthew Dillon if (fd >= 0) { 334cbf2d71fSMatthew Dillon switch(flags & O_ACCMODE) { 335cbf2d71fSMatthew Dillon case O_RDONLY: 3369afa09cdSMark Murray if (shutdown(fd, SHUT_WR) == -1) 3372c61418dSTim J. Robbins warn(NULL); 338cbf2d71fSMatthew Dillon break; 339cbf2d71fSMatthew Dillon case O_WRONLY: 3409afa09cdSMark Murray if (shutdown(fd, SHUT_RD) == -1) 3412c61418dSTim J. Robbins warn(NULL); 342cbf2d71fSMatthew Dillon break; 343cbf2d71fSMatthew Dillon default: 344cbf2d71fSMatthew Dillon break; 345cbf2d71fSMatthew Dillon } 346cbf2d71fSMatthew Dillon } 347cbf2d71fSMatthew Dillon return (fd); 348cbf2d71fSMatthew Dillon } 349cbf2d71fSMatthew Dillon 350cbf2d71fSMatthew Dillon #endif 351