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> 55*1c9fbb5aSHiroki Sato #include <netdb.h> 56cbf2d71fSMatthew Dillon #endif 574b88c807SRodney W. Grimes 584b88c807SRodney W. Grimes #include <ctype.h> 594b88c807SRodney W. Grimes #include <err.h> 604b88c807SRodney W. Grimes #include <fcntl.h> 613043192bSAndrey A. Chernov #include <locale.h> 6267bf019bSJaakko Heinonen #include <stddef.h> 634b88c807SRodney W. Grimes #include <stdio.h> 644b88c807SRodney W. Grimes #include <stdlib.h> 65cafefe8cSDima Dorfman #include <string.h> 664b88c807SRodney W. Grimes #include <unistd.h> 674b88c807SRodney W. Grimes 68aece80a2SBrooks Davis static int bflag, eflag, lflag, nflag, sflag, tflag, vflag; 69f9d4afb4SEd Schouten static int rval; 70f9d4afb4SEd Schouten static const char *filename; 714b88c807SRodney W. Grimes 72e99f8bc0SEitan Adler static void usage(void) __dead2; 739d32ecfcSMark Murray static void scanfiles(char *argv[], int cooked); 7478a3801dSWarner Losh static void cook_cat(FILE *); 7578a3801dSWarner Losh static void raw_cat(int); 76cbf2d71fSMatthew Dillon 77cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 7878a3801dSWarner Losh static int udom_open(const char *path, int flags); 79cbf2d71fSMatthew Dillon #endif 804b88c807SRodney W. Grimes 8167bf019bSJaakko Heinonen /* 8267bf019bSJaakko Heinonen * Memory strategy threshold, in pages: if physmem is larger than this, 8367bf019bSJaakko Heinonen * use a large buffer. 8467bf019bSJaakko Heinonen */ 85e9cbc9a7SIvan Voras #define PHYSPAGES_THRESHOLD (32 * 1024) 86e9cbc9a7SIvan Voras 8767bf019bSJaakko Heinonen /* Maximum buffer size in bytes - do not allow it to grow larger than this. */ 88e9cbc9a7SIvan Voras #define BUFSIZE_MAX (2 * 1024 * 1024) 89e9cbc9a7SIvan Voras 9067bf019bSJaakko Heinonen /* 9167bf019bSJaakko Heinonen * Small (default) buffer size in bytes. It's inefficient for this to be 9267bf019bSJaakko Heinonen * smaller than MAXPHYS. 9367bf019bSJaakko Heinonen */ 94e9cbc9a7SIvan Voras #define BUFSIZE_SMALL (MAXPHYS) 95e9cbc9a7SIvan Voras 964b88c807SRodney W. Grimes int 9778a3801dSWarner Losh main(int argc, char *argv[]) 984b88c807SRodney W. Grimes { 994b88c807SRodney W. Grimes int ch; 100aece80a2SBrooks Davis struct flock stdout_lock; 1014b88c807SRodney W. Grimes 1023043192bSAndrey A. Chernov setlocale(LC_CTYPE, ""); 1033043192bSAndrey A. Chernov 104aece80a2SBrooks Davis while ((ch = getopt(argc, argv, "belnstuv")) != -1) 1054b88c807SRodney W. Grimes switch (ch) { 1064b88c807SRodney W. Grimes case 'b': 1074b88c807SRodney W. Grimes bflag = nflag = 1; /* -b implies -n */ 1084b88c807SRodney W. Grimes break; 1094b88c807SRodney W. Grimes case 'e': 1104b88c807SRodney W. Grimes eflag = vflag = 1; /* -e implies -v */ 1114b88c807SRodney W. Grimes break; 112aece80a2SBrooks Davis case 'l': 113aece80a2SBrooks Davis lflag = 1; 114aece80a2SBrooks Davis break; 1154b88c807SRodney W. Grimes case 'n': 1164b88c807SRodney W. Grimes nflag = 1; 1174b88c807SRodney W. Grimes break; 1184b88c807SRodney W. Grimes case 's': 1194b88c807SRodney W. Grimes sflag = 1; 1204b88c807SRodney W. Grimes break; 1214b88c807SRodney W. Grimes case 't': 1224b88c807SRodney W. Grimes tflag = vflag = 1; /* -t implies -v */ 1234b88c807SRodney W. Grimes break; 1244b88c807SRodney W. Grimes case 'u': 1252192b407SJeroen Ruigrok van der Werven setbuf(stdout, NULL); 1264b88c807SRodney W. Grimes break; 1274b88c807SRodney W. Grimes case 'v': 1284b88c807SRodney W. Grimes vflag = 1; 1294b88c807SRodney W. Grimes break; 1308d72a3d7SWarner Losh default: 131ca2be2ffSJuli Mallett usage(); 1324b88c807SRodney W. Grimes } 1334b88c807SRodney W. Grimes argv += optind; 1344b88c807SRodney W. Grimes 135aece80a2SBrooks Davis if (lflag) { 136aece80a2SBrooks Davis stdout_lock.l_len = 0; 137aece80a2SBrooks Davis stdout_lock.l_start = 0; 138aece80a2SBrooks Davis stdout_lock.l_type = F_WRLCK; 139aece80a2SBrooks Davis stdout_lock.l_whence = SEEK_SET; 140aece80a2SBrooks Davis if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) 141aece80a2SBrooks Davis err(EXIT_FAILURE, "stdout"); 142aece80a2SBrooks Davis } 143aece80a2SBrooks Davis 1444b88c807SRodney W. Grimes if (bflag || eflag || nflag || sflag || tflag || vflag) 145cbf2d71fSMatthew Dillon scanfiles(argv, 1); 1464b88c807SRodney W. Grimes else 147cbf2d71fSMatthew Dillon scanfiles(argv, 0); 1484b88c807SRodney W. Grimes if (fclose(stdout)) 1494b88c807SRodney W. Grimes err(1, "stdout"); 1504b88c807SRodney W. Grimes exit(rval); 1519f82c1d3SMark Murray /* NOTREACHED */ 1524b88c807SRodney W. Grimes } 1534b88c807SRodney W. Grimes 154ca2be2ffSJuli Mallett static void 155ca2be2ffSJuli Mallett usage(void) 156ca2be2ffSJuli Mallett { 157e99f8bc0SEitan Adler 158aece80a2SBrooks Davis fprintf(stderr, "usage: cat [-belnstuv] [file ...]\n"); 159ca2be2ffSJuli Mallett exit(1); 1609f82c1d3SMark Murray /* NOTREACHED */ 161ca2be2ffSJuli Mallett } 162ca2be2ffSJuli Mallett 1639d32ecfcSMark Murray static void 1649d32ecfcSMark Murray scanfiles(char *argv[], int cooked) 1654b88c807SRodney W. Grimes { 16667bf019bSJaakko Heinonen int fd, i; 167cbf2d71fSMatthew Dillon char *path; 1681b00c916SRuslan Ermilov FILE *fp; 1694b88c807SRodney W. Grimes 17067bf019bSJaakko Heinonen i = 0; 171cbf2d71fSMatthew Dillon while ((path = argv[i]) != NULL || i == 0) { 172cbf2d71fSMatthew Dillon if (path == NULL || strcmp(path, "-") == 0) { 1734b88c807SRodney W. Grimes filename = "stdin"; 1741b00c916SRuslan Ermilov fd = STDIN_FILENO; 175cbf2d71fSMatthew Dillon } else { 176cbf2d71fSMatthew Dillon filename = path; 177cbf2d71fSMatthew Dillon fd = open(path, O_RDONLY); 178cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 179cbf2d71fSMatthew Dillon if (fd < 0 && errno == EOPNOTSUPP) 18043e09ab2SRuslan Ermilov fd = udom_open(path, O_RDONLY); 181cbf2d71fSMatthew Dillon #endif 182cbf2d71fSMatthew Dillon } 183cbf2d71fSMatthew Dillon if (fd < 0) { 184cbf2d71fSMatthew Dillon warn("%s", path); 185001aff9fSBruce Evans rval = 1; 186cbf2d71fSMatthew Dillon } else if (cooked) { 1871b00c916SRuslan Ermilov if (fd == STDIN_FILENO) 1881b00c916SRuslan Ermilov cook_cat(stdin); 1891b00c916SRuslan Ermilov else { 1901b00c916SRuslan Ermilov fp = fdopen(fd, "r"); 191cbf2d71fSMatthew Dillon cook_cat(fp); 192cbf2d71fSMatthew Dillon fclose(fp); 1931b00c916SRuslan Ermilov } 194cbf2d71fSMatthew Dillon } else { 195cbf2d71fSMatthew Dillon raw_cat(fd); 1961b00c916SRuslan Ermilov if (fd != STDIN_FILENO) 197cbf2d71fSMatthew Dillon close(fd); 1984b88c807SRodney W. Grimes } 199cbf2d71fSMatthew Dillon if (path == NULL) 200cbf2d71fSMatthew Dillon break; 201cbf2d71fSMatthew Dillon ++i; 2024b88c807SRodney W. Grimes } 2034b88c807SRodney W. Grimes } 2044b88c807SRodney W. Grimes 205cbf2d71fSMatthew Dillon static void 20678a3801dSWarner Losh cook_cat(FILE *fp) 2074b88c807SRodney W. Grimes { 20878a3801dSWarner Losh int ch, gobble, line, prev; 2094b88c807SRodney W. Grimes 2101b00c916SRuslan Ermilov /* Reset EOF condition on stdin. */ 2111b00c916SRuslan Ermilov if (fp == stdin && feof(stdin)) 2121b00c916SRuslan Ermilov clearerr(stdin); 2131b00c916SRuslan Ermilov 2144b88c807SRodney W. Grimes line = gobble = 0; 2154b88c807SRodney W. Grimes for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { 2164b88c807SRodney W. Grimes if (prev == '\n') { 2174b88c807SRodney W. Grimes if (sflag) { 2184b88c807SRodney W. Grimes if (ch == '\n') { 219bf5f0c44STim J. Robbins if (gobble) 220bf5f0c44STim J. Robbins continue; 221bf5f0c44STim J. Robbins gobble = 1; 222bf5f0c44STim J. Robbins } else 223bf5f0c44STim J. Robbins gobble = 0; 224bf5f0c44STim J. Robbins } 225bf5f0c44STim J. Robbins if (nflag && (!bflag || ch != '\n')) { 226bf5f0c44STim J. Robbins (void)fprintf(stdout, "%6d\t", ++line); 227bf5f0c44STim J. Robbins if (ferror(stdout)) 228bf5f0c44STim J. Robbins break; 229bf5f0c44STim J. Robbins } 230bf5f0c44STim J. Robbins } 231bf5f0c44STim J. Robbins if (ch == '\n') { 232bf5f0c44STim J. Robbins if (eflag && putchar('$') == EOF) 2334b88c807SRodney W. Grimes break; 2344b88c807SRodney W. Grimes } else if (ch == '\t') { 2354b88c807SRodney W. Grimes if (tflag) { 2364b88c807SRodney W. Grimes if (putchar('^') == EOF || putchar('I') == EOF) 2374b88c807SRodney W. Grimes break; 2384b88c807SRodney W. Grimes continue; 2394b88c807SRodney W. Grimes } 2404b88c807SRodney W. Grimes } else if (vflag) { 2413043192bSAndrey A. Chernov if (!isascii(ch) && !isprint(ch)) { 2424b88c807SRodney W. Grimes if (putchar('M') == EOF || putchar('-') == EOF) 2434b88c807SRodney W. Grimes break; 2444b88c807SRodney W. Grimes ch = toascii(ch); 2454b88c807SRodney W. Grimes } 2464b88c807SRodney W. Grimes if (iscntrl(ch)) { 2474b88c807SRodney W. Grimes if (putchar('^') == EOF || 2484b88c807SRodney W. Grimes putchar(ch == '\177' ? '?' : 2494b88c807SRodney W. Grimes ch | 0100) == EOF) 2504b88c807SRodney W. Grimes break; 2514b88c807SRodney W. Grimes continue; 2524b88c807SRodney W. Grimes } 2534b88c807SRodney W. Grimes } 2544b88c807SRodney W. Grimes if (putchar(ch) == EOF) 2554b88c807SRodney W. Grimes break; 2564b88c807SRodney W. Grimes } 2574b88c807SRodney W. Grimes if (ferror(fp)) { 2584b88c807SRodney W. Grimes warn("%s", filename); 259001aff9fSBruce Evans rval = 1; 2604b88c807SRodney W. Grimes clearerr(fp); 2614b88c807SRodney W. Grimes } 2624b88c807SRodney W. Grimes if (ferror(stdout)) 2634b88c807SRodney W. Grimes err(1, "stdout"); 2644b88c807SRodney W. Grimes } 2654b88c807SRodney W. Grimes 266cbf2d71fSMatthew Dillon static void 26778a3801dSWarner Losh raw_cat(int rfd) 2684b88c807SRodney W. Grimes { 26978a3801dSWarner Losh int off, wfd; 270a5da0999SWarner Losh ssize_t nr, nw; 271a5da0999SWarner Losh static size_t bsize; 2729afa09cdSMark Murray static char *buf = NULL; 2734b88c807SRodney W. Grimes struct stat sbuf; 2744b88c807SRodney W. Grimes 2754b88c807SRodney W. Grimes wfd = fileno(stdout); 2764b88c807SRodney W. Grimes if (buf == NULL) { 2774b88c807SRodney W. Grimes if (fstat(wfd, &sbuf)) 278e3481b29SJaakko Heinonen err(1, "stdout"); 279e9cbc9a7SIvan Voras if (S_ISREG(sbuf.st_mode)) { 280e9cbc9a7SIvan Voras /* If there's plenty of RAM, use a large copy buffer */ 281e9cbc9a7SIvan Voras if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) 282e9cbc9a7SIvan Voras bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 283e9cbc9a7SIvan Voras else 284e9cbc9a7SIvan Voras bsize = BUFSIZE_SMALL; 285e9cbc9a7SIvan Voras } else 286e9cbc9a7SIvan Voras bsize = MAX(sbuf.st_blksize, 287e9cbc9a7SIvan Voras (blksize_t)sysconf(_SC_PAGESIZE)); 288d1762d1fSWarner Losh if ((buf = malloc(bsize)) == NULL) 289e9cbc9a7SIvan Voras err(1, "malloc() failure of IO buffer"); 2904b88c807SRodney W. Grimes } 2914b88c807SRodney W. Grimes while ((nr = read(rfd, buf, bsize)) > 0) 2924b88c807SRodney W. Grimes for (off = 0; nr; nr -= nw, off += nw) 293a5da0999SWarner Losh if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) 2944b88c807SRodney W. Grimes err(1, "stdout"); 295001aff9fSBruce Evans if (nr < 0) { 2964b88c807SRodney W. Grimes warn("%s", filename); 297001aff9fSBruce Evans rval = 1; 298001aff9fSBruce Evans } 2994b88c807SRodney W. Grimes } 300cbf2d71fSMatthew Dillon 301cbf2d71fSMatthew Dillon #ifndef NO_UDOM_SUPPORT 302cbf2d71fSMatthew Dillon 303cbf2d71fSMatthew Dillon static int 30478a3801dSWarner Losh udom_open(const char *path, int flags) 305cbf2d71fSMatthew Dillon { 306*1c9fbb5aSHiroki Sato struct addrinfo hints, *res, *res0; 307*1c9fbb5aSHiroki Sato char rpath[PATH_MAX]; 308*1c9fbb5aSHiroki Sato int fd, error; 309cbf2d71fSMatthew Dillon 310cbf2d71fSMatthew Dillon /* 311*1c9fbb5aSHiroki Sato * Construct the unix domain socket address and attempt to connect. 312cbf2d71fSMatthew Dillon */ 313*1c9fbb5aSHiroki Sato bzero(&hints, sizeof(hints)); 314*1c9fbb5aSHiroki Sato hints.ai_family = AF_LOCAL; 315*1c9fbb5aSHiroki Sato if (realpath(path, rpath) == NULL) 316*1c9fbb5aSHiroki Sato return (-1); 317*1c9fbb5aSHiroki Sato error = getaddrinfo(rpath, NULL, &hints, &res0); 318*1c9fbb5aSHiroki Sato if (error) { 319*1c9fbb5aSHiroki Sato warn("%s", gai_strerror(error)); 320*1c9fbb5aSHiroki Sato errno = EINVAL; 32188485b4aSTim J. Robbins return (-1); 32288485b4aSTim J. Robbins } 323*1c9fbb5aSHiroki Sato for (res = res0; res != NULL; res = res->ai_next) { 324*1c9fbb5aSHiroki Sato fd = socket(res->ai_family, res->ai_socktype, 325*1c9fbb5aSHiroki Sato res->ai_protocol); 326*1c9fbb5aSHiroki Sato if (fd < 0) { 327*1c9fbb5aSHiroki Sato freeaddrinfo(res0); 328*1c9fbb5aSHiroki Sato return (-1); 329*1c9fbb5aSHiroki Sato } 330*1c9fbb5aSHiroki Sato error = connect(fd, res->ai_addr, res->ai_addrlen); 331*1c9fbb5aSHiroki Sato if (error == 0) 332*1c9fbb5aSHiroki Sato break; 333*1c9fbb5aSHiroki Sato else { 334cbf2d71fSMatthew Dillon close(fd); 335cbf2d71fSMatthew Dillon fd = -1; 336cbf2d71fSMatthew Dillon } 337cbf2d71fSMatthew Dillon } 338*1c9fbb5aSHiroki Sato freeaddrinfo(res0); 339cbf2d71fSMatthew Dillon 340cbf2d71fSMatthew Dillon /* 341cbf2d71fSMatthew Dillon * handle the open flags by shutting down appropriate directions 342cbf2d71fSMatthew Dillon */ 343cbf2d71fSMatthew Dillon if (fd >= 0) { 344cbf2d71fSMatthew Dillon switch(flags & O_ACCMODE) { 345cbf2d71fSMatthew Dillon case O_RDONLY: 3469afa09cdSMark Murray if (shutdown(fd, SHUT_WR) == -1) 3472c61418dSTim J. Robbins warn(NULL); 348cbf2d71fSMatthew Dillon break; 349cbf2d71fSMatthew Dillon case O_WRONLY: 3509afa09cdSMark Murray if (shutdown(fd, SHUT_RD) == -1) 3512c61418dSTim J. Robbins warn(NULL); 352cbf2d71fSMatthew Dillon break; 353cbf2d71fSMatthew Dillon default: 354cbf2d71fSMatthew Dillon break; 355cbf2d71fSMatthew Dillon } 356cbf2d71fSMatthew Dillon } 357cbf2d71fSMatthew Dillon return (fd); 358cbf2d71fSMatthew Dillon } 359cbf2d71fSMatthew Dillon 360cbf2d71fSMatthew Dillon #endif 361