[813] | 1 | /*-
|
---|
| 2 | * Copyright (c) 1989, 1993
|
---|
| 3 | * The Regents of the University of California. All rights reserved.
|
---|
| 4 | *
|
---|
| 5 | * This code is derived from software contributed to Berkeley by
|
---|
| 6 | * Kevin Fall.
|
---|
| 7 | *
|
---|
| 8 | * Redistribution and use in source and binary forms, with or without
|
---|
| 9 | * modification, are permitted provided that the following conditions
|
---|
| 10 | * are met:
|
---|
| 11 | * 1. Redistributions of source code must retain the above copyright
|
---|
| 12 | * notice, this list of conditions and the following disclaimer.
|
---|
| 13 | * 2. Redistributions in binary form must reproduce the above copyright
|
---|
| 14 | * notice, this list of conditions and the following disclaimer in the
|
---|
| 15 | * documentation and/or other materials provided with the distribution.
|
---|
| 16 | * 4. Neither the name of the University nor the names of its contributors
|
---|
| 17 | * may be used to endorse or promote products derived from this software
|
---|
| 18 | * without specific prior written permission.
|
---|
| 19 | *
|
---|
| 20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
---|
| 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
| 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
| 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
---|
| 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
---|
| 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
---|
| 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
| 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
---|
| 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
---|
| 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
---|
| 30 | * SUCH DAMAGE.
|
---|
| 31 | */
|
---|
| 32 |
|
---|
| 33 | #if 0
|
---|
| 34 | #ifndef lint
|
---|
| 35 | static char const copyright[] =
|
---|
| 36 | "@(#) Copyright (c) 1989, 1993\n\
|
---|
| 37 | The Regents of the University of California. All rights reserved.\n";
|
---|
| 38 | #endif /* not lint */
|
---|
| 39 | #endif
|
---|
| 40 |
|
---|
| 41 | #ifndef lint
|
---|
| 42 | #if 0
|
---|
| 43 | static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95";
|
---|
| 44 | #endif
|
---|
| 45 | #endif /* not lint */
|
---|
| 46 | #if 0
|
---|
| 47 | #include <sys/cdefs.h>
|
---|
| 48 | __FBSDID("$FreeBSD: src/bin/cat/cat.c,v 1.32 2005/01/10 08:39:20 imp Exp $");
|
---|
| 49 | #endif
|
---|
| 50 |
|
---|
[3218] | 51 | /*********************************************************************************************************************************
|
---|
| 52 | * Header Files *
|
---|
| 53 | *********************************************************************************************************************************/
|
---|
| 54 | #define FAKES_NO_GETOPT_H /* bird */
|
---|
| 55 | #define NO_UDOM_SUPPORT /* kmk */
|
---|
[2113] | 56 | #include "config.h"
|
---|
[813] | 57 | #ifndef _MSC_VER
|
---|
| 58 | # include <sys/param.h>
|
---|
| 59 | #endif
|
---|
| 60 | #include <sys/stat.h>
|
---|
| 61 | #ifndef NO_UDOM_SUPPORT
|
---|
| 62 | # include <sys/socket.h>
|
---|
| 63 | # include <sys/un.h>
|
---|
| 64 | # include <errno.h>
|
---|
| 65 | #endif
|
---|
| 66 |
|
---|
| 67 | #include <ctype.h>
|
---|
| 68 | #include "err.h"
|
---|
| 69 | #include <fcntl.h>
|
---|
| 70 | #include <locale.h>
|
---|
| 71 | #include <stdio.h>
|
---|
| 72 | #include <stdlib.h>
|
---|
| 73 | #include <string.h>
|
---|
| 74 | #include <unistd.h>
|
---|
| 75 | #include <stddef.h>
|
---|
[3218] | 76 | #include "getopt_r.h"
|
---|
[813] | 77 | #ifdef __sun__
|
---|
| 78 | # include "solfakes.h"
|
---|
| 79 | #endif
|
---|
| 80 | #ifdef _MSC_VER
|
---|
| 81 | # include "mscfakes.h"
|
---|
| 82 | #endif
|
---|
[1183] | 83 | #include "kmkbuiltin.h"
|
---|
| 84 |
|
---|
| 85 |
|
---|
[3218] | 86 | /*********************************************************************************************************************************
|
---|
| 87 | * Structures and Typedefs *
|
---|
| 88 | *********************************************************************************************************************************/
|
---|
| 89 | typedef struct CATINSTANCE
|
---|
| 90 | {
|
---|
| 91 | PKMKBUILTINCTX pCtx;
|
---|
| 92 | int bflag, eflag, nflag, sflag, tflag, vflag;
|
---|
| 93 | /*int rval;*/
|
---|
| 94 | const char *filename;
|
---|
| 95 | /* function level statics from raw_cat (needs freeing): */
|
---|
| 96 | size_t bsize;
|
---|
| 97 | char *buf;
|
---|
| 98 | } CATINSTANCE;
|
---|
[813] | 99 |
|
---|
[3218] | 100 |
|
---|
| 101 | /*********************************************************************************************************************************
|
---|
| 102 | * Global Variables *
|
---|
| 103 | *********************************************************************************************************************************/
|
---|
[1183] | 104 | static struct option long_options[] =
|
---|
| 105 | {
|
---|
| 106 | { "help", no_argument, 0, 261 },
|
---|
| 107 | { "version", no_argument, 0, 262 },
|
---|
| 108 | { 0, 0, 0, 0 },
|
---|
| 109 | };
|
---|
| 110 |
|
---|
| 111 |
|
---|
[3192] | 112 | static int usage(PKMKBUILTINCTX pCtx, int fIsErr);
|
---|
[3218] | 113 | static int scanfiles(CATINSTANCE *pThis, char *argv[], int cooked);
|
---|
| 114 | static int cook_cat(CATINSTANCE *pThis, FILE *);
|
---|
| 115 | static int raw_cat(CATINSTANCE *pThis, int);
|
---|
[813] | 116 |
|
---|
| 117 | #ifndef NO_UDOM_SUPPORT
|
---|
[3192] | 118 | static int udom_open(PKMKBUILTINCTX pCtx, const char *path, int flags);
|
---|
[813] | 119 | #endif
|
---|
| 120 |
|
---|
| 121 | int
|
---|
[3192] | 122 | kmk_builtin_cat(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
|
---|
[813] | 123 | {
|
---|
[3218] | 124 | struct getopt_state_r gos;
|
---|
| 125 | CATINSTANCE This;
|
---|
[813] | 126 | int ch, rc;
|
---|
| 127 |
|
---|
| 128 | /* kmk: reinitialize globals */
|
---|
[3218] | 129 | This.pCtx = pCtx;
|
---|
| 130 | This.bflag = This.eflag = This.nflag = This.sflag = This.tflag = This.vflag = 0;
|
---|
| 131 | This.filename = NULL;
|
---|
| 132 | This.bsize = 0;
|
---|
| 133 | This.buf = 0;
|
---|
[813] | 134 |
|
---|
[3218] | 135 | getopt_initialize_r(&gos, argc, argv, "benstuv", long_options, envp, pCtx);
|
---|
| 136 | while ((ch = getopt_long_r(&gos, NULL)) != -1)
|
---|
[813] | 137 | switch (ch) {
|
---|
| 138 | case 'b':
|
---|
[3218] | 139 | This.bflag = This.nflag = 1; /* -b implies -n */
|
---|
[813] | 140 | break;
|
---|
| 141 | case 'e':
|
---|
[3218] | 142 | This.eflag = This.vflag = 1; /* -e implies -v */
|
---|
[813] | 143 | break;
|
---|
| 144 | case 'n':
|
---|
[3218] | 145 | This.nflag = 1;
|
---|
[813] | 146 | break;
|
---|
| 147 | case 's':
|
---|
[3218] | 148 | This.sflag = 1;
|
---|
[813] | 149 | break;
|
---|
| 150 | case 't':
|
---|
[3218] | 151 | This.tflag = This.vflag = 1; /* -t implies -v */
|
---|
[813] | 152 | break;
|
---|
| 153 | case 'u':
|
---|
[3192] | 154 | #ifdef KMK_BUILTIN_STANDALONE /* don't allow messing with stdout */
|
---|
[813] | 155 | setbuf(stdout, NULL);
|
---|
[3192] | 156 | #endif
|
---|
[813] | 157 | break;
|
---|
| 158 | case 'v':
|
---|
[3218] | 159 | This.vflag = 1;
|
---|
[813] | 160 | break;
|
---|
[1183] | 161 | case 261:
|
---|
[3192] | 162 | usage(pCtx, 0);
|
---|
[1183] | 163 | return 0;
|
---|
| 164 | case 262:
|
---|
| 165 | return kbuild_version(argv[0]);
|
---|
[813] | 166 | default:
|
---|
[3192] | 167 | return usage(pCtx, 1);
|
---|
[813] | 168 | }
|
---|
[3218] | 169 | argv += gos.optind;
|
---|
[813] | 170 |
|
---|
[3218] | 171 | if (This.bflag || This.eflag || This.nflag || This.sflag || This.tflag || This.vflag)
|
---|
| 172 | rc = scanfiles(&This, argv, 1);
|
---|
[813] | 173 | else
|
---|
[3218] | 174 | rc = scanfiles(&This, argv, 0);
|
---|
| 175 | if (This.buf) {
|
---|
| 176 | free(This.buf);
|
---|
| 177 | This.buf = NULL;
|
---|
| 178 | }
|
---|
[3192] | 179 | #ifdef KMK_BUILTIN_STANDALONE /* don't allow messing with stdout */
|
---|
[813] | 180 | if (fclose(stdout))
|
---|
[3192] | 181 | return err(pCtx, 1, "stdout");
|
---|
[813] | 182 | #endif
|
---|
| 183 | return rc;
|
---|
| 184 | }
|
---|
| 185 |
|
---|
[3192] | 186 | #ifdef KMK_BUILTIN_STANDALONE
|
---|
| 187 | int main(int argc, char **argv, char **envp)
|
---|
| 188 | {
|
---|
[3218] | 189 | KMKBUILTINCTX Ctx = { "kmk_cat", NULL };
|
---|
| 190 | setlocale(LC_CTYPE, "");
|
---|
| 191 | return kmk_builtin_cat(argc, argv, envp, &Ctx);
|
---|
[3192] | 192 | }
|
---|
| 193 | #endif
|
---|
| 194 |
|
---|
[813] | 195 | static int
|
---|
[3192] | 196 | usage(PKMKBUILTINCTX pCtx, int fIsErr)
|
---|
[813] | 197 | {
|
---|
[3192] | 198 | kmk_builtin_ctx_printf(pCtx, fIsErr,
|
---|
| 199 | "usage: %s [-benstuv] [file ...]\n"
|
---|
| 200 | " or: %s --help\n"
|
---|
| 201 | " or: %s --version\n",
|
---|
| 202 | pCtx->pszProgName, pCtx->pszProgName,
|
---|
| 203 | pCtx->pszProgName);
|
---|
[813] | 204 | return 1;
|
---|
| 205 | }
|
---|
| 206 |
|
---|
| 207 | static int
|
---|
[3218] | 208 | scanfiles(CATINSTANCE *pThis, char *argv[], int cooked)
|
---|
[813] | 209 | {
|
---|
| 210 | int i = 0;
|
---|
| 211 | char *path;
|
---|
| 212 | FILE *fp;
|
---|
| 213 | int rc2 = 0;
|
---|
| 214 | int rc = 0;
|
---|
| 215 |
|
---|
| 216 | while ((path = argv[i]) != NULL || i == 0) {
|
---|
| 217 | int fd;
|
---|
| 218 |
|
---|
| 219 | if (path == NULL || strcmp(path, "-") == 0) {
|
---|
[3218] | 220 | pThis->filename = "stdin";
|
---|
[813] | 221 | fd = STDIN_FILENO;
|
---|
| 222 | } else {
|
---|
[3218] | 223 | pThis->filename = path;
|
---|
[3219] | 224 | fd = open(path, O_RDONLY | KMK_OPEN_NO_INHERIT);
|
---|
[813] | 225 | #ifndef NO_UDOM_SUPPORT
|
---|
| 226 | if (fd < 0 && errno == EOPNOTSUPP)
|
---|
[3218] | 227 | fd = udom_open(pThis, path, O_RDONLY);
|
---|
[813] | 228 | #endif
|
---|
| 229 | }
|
---|
| 230 | if (fd < 0) {
|
---|
[3218] | 231 | warn(pThis->pCtx, "%s", path);
|
---|
[813] | 232 | rc2 = 1; /* non fatal */
|
---|
| 233 | } else if (cooked) {
|
---|
| 234 | if (fd == STDIN_FILENO)
|
---|
[3218] | 235 | rc = cook_cat(pThis, stdin);
|
---|
[813] | 236 | else {
|
---|
| 237 | fp = fdopen(fd, "r");
|
---|
[3218] | 238 | rc = cook_cat(pThis, fp);
|
---|
[813] | 239 | fclose(fp);
|
---|
| 240 | }
|
---|
| 241 | } else {
|
---|
[3218] | 242 | rc = raw_cat(pThis, fd);
|
---|
[813] | 243 | if (fd != STDIN_FILENO)
|
---|
| 244 | close(fd);
|
---|
| 245 | }
|
---|
| 246 | if (rc || path == NULL)
|
---|
| 247 | break;
|
---|
| 248 | ++i;
|
---|
| 249 | }
|
---|
| 250 | return !rc ? rc2 : rc;
|
---|
| 251 | }
|
---|
| 252 |
|
---|
[3218] | 253 | static int
|
---|
| 254 | cat_putchar(PKMKBUILTINCTX pCtx, char ch)
|
---|
[3192] | 255 | {
|
---|
| 256 | #ifndef KMK_BUILTIN_STANDALONE
|
---|
| 257 | if (pCtx->pOut) {
|
---|
| 258 | output_write_text(pCtx->pOut, 0, &ch, 1);
|
---|
| 259 | return 0;
|
---|
| 260 | }
|
---|
| 261 | #endif
|
---|
| 262 | return putchar(ch);
|
---|
| 263 | }
|
---|
| 264 |
|
---|
[813] | 265 | static int
|
---|
[3218] | 266 | cook_cat(CATINSTANCE *pThis, FILE *fp)
|
---|
[813] | 267 | {
|
---|
| 268 | int ch, gobble, line, prev;
|
---|
| 269 | int rc = 0;
|
---|
| 270 |
|
---|
| 271 | /* Reset EOF condition on stdin. */
|
---|
| 272 | if (fp == stdin && feof(stdin))
|
---|
| 273 | clearerr(stdin);
|
---|
| 274 |
|
---|
| 275 | line = gobble = 0;
|
---|
| 276 | for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
|
---|
| 277 | if (prev == '\n') {
|
---|
[3218] | 278 | if (pThis->sflag) {
|
---|
[813] | 279 | if (ch == '\n') {
|
---|
| 280 | if (gobble)
|
---|
| 281 | continue;
|
---|
| 282 | gobble = 1;
|
---|
| 283 | } else
|
---|
| 284 | gobble = 0;
|
---|
| 285 | }
|
---|
[3218] | 286 | if (pThis->nflag && (!pThis->bflag || ch != '\n')) {
|
---|
| 287 | kmk_builtin_ctx_printf(pThis->pCtx, 0, "%6d\t", ++line);
|
---|
[813] | 288 | if (ferror(stdout))
|
---|
| 289 | break;
|
---|
| 290 | }
|
---|
| 291 | }
|
---|
| 292 | if (ch == '\n') {
|
---|
[3218] | 293 | if (pThis->eflag && cat_putchar(pThis->pCtx, '$') == EOF)
|
---|
[813] | 294 | break;
|
---|
| 295 | } else if (ch == '\t') {
|
---|
[3218] | 296 | if (pThis->tflag) {
|
---|
| 297 | if (cat_putchar(pThis->pCtx, '^') == EOF || cat_putchar(pThis->pCtx, 'I') == EOF)
|
---|
[813] | 298 | break;
|
---|
| 299 | continue;
|
---|
| 300 | }
|
---|
[3218] | 301 | } else if (pThis->vflag) {
|
---|
[813] | 302 | if (!isascii(ch) && !isprint(ch)) {
|
---|
[3218] | 303 | if (cat_putchar(pThis->pCtx, 'M') == EOF || cat_putchar(pThis->pCtx, '-') == EOF)
|
---|
[813] | 304 | break;
|
---|
| 305 | ch = toascii(ch);
|
---|
| 306 | }
|
---|
| 307 | if (iscntrl(ch)) {
|
---|
[3218] | 308 | if (cat_putchar(pThis->pCtx, '^') == EOF ||
|
---|
| 309 | cat_putchar(pThis->pCtx, ch == '\177' ? '?' :
|
---|
[813] | 310 | ch | 0100) == EOF)
|
---|
| 311 | break;
|
---|
| 312 | continue;
|
---|
| 313 | }
|
---|
| 314 | }
|
---|
[3218] | 315 | if (cat_putchar(pThis->pCtx, ch) == EOF)
|
---|
[813] | 316 | break;
|
---|
| 317 | }
|
---|
| 318 | if (ferror(fp)) {
|
---|
[3218] | 319 | warn(pThis->pCtx, "%s", pThis->filename);
|
---|
[813] | 320 | rc = 1;
|
---|
| 321 | clearerr(fp);
|
---|
| 322 | }
|
---|
| 323 | if (ferror(stdout))
|
---|
[3218] | 324 | return err(pThis->pCtx, 1, "stdout");
|
---|
[813] | 325 | return rc;
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | static int
|
---|
[3218] | 329 | raw_cat(CATINSTANCE *pThis, int rfd)
|
---|
[813] | 330 | {
|
---|
[2900] | 331 | int off, wfd = fileno(stdout);
|
---|
[813] | 332 | ssize_t nr, nw;
|
---|
| 333 |
|
---|
| 334 | wfd = fileno(stdout);
|
---|
[3218] | 335 | if (pThis->buf == NULL) {
|
---|
| 336 | struct stat sbuf;
|
---|
[813] | 337 | if (fstat(wfd, &sbuf))
|
---|
[3218] | 338 | return err(pThis->pCtx, 1, "%s", pThis->filename);
|
---|
[2900] | 339 | #ifdef KBUILD_OS_WINDOWS
|
---|
[3218] | 340 | pThis->bsize = 16384;
|
---|
[813] | 341 | #else
|
---|
[3218] | 342 | pThis->bsize = MAX(sbuf.st_blksize, 1024);
|
---|
[813] | 343 | #endif
|
---|
[3218] | 344 | if ((pThis->buf = malloc(pThis->bsize)) == NULL)
|
---|
| 345 | return err(pThis->pCtx, 1, "buffer");
|
---|
[813] | 346 | }
|
---|
[3218] | 347 | while ((nr = read(rfd, pThis->buf, pThis->bsize)) > 0)
|
---|
[3192] | 348 | for (off = 0; nr; nr -= nw, off += nw) {
|
---|
| 349 | #ifndef KMK_BUILTIN_STANDALONE
|
---|
[3218] | 350 | if (pThis->pCtx->pOut)
|
---|
| 351 | nw = output_write_text(pThis->pCtx->pOut, 0, pThis->buf + off, nr);
|
---|
[3192] | 352 | else
|
---|
| 353 | #endif
|
---|
[3218] | 354 | nw = write(wfd, pThis->buf + off, (size_t)nr);
|
---|
[3192] | 355 | if (nw < 0)
|
---|
[3218] | 356 | return err(pThis->pCtx, 1, "stdout");
|
---|
[3192] | 357 | }
|
---|
[813] | 358 | if (nr < 0) {
|
---|
[3218] | 359 | warn(pThis->pCtx, "%s", pThis->filename);
|
---|
[813] | 360 | return 1;
|
---|
| 361 | }
|
---|
| 362 | return 0;
|
---|
| 363 | }
|
---|
| 364 |
|
---|
| 365 | #ifndef NO_UDOM_SUPPORT
|
---|
| 366 |
|
---|
| 367 | static int
|
---|
[3218] | 368 | udom_open(CATINSTANCE *pThis, const char *path, int flags)
|
---|
[813] | 369 | {
|
---|
| 370 | struct sockaddr_un sou;
|
---|
| 371 | int fd;
|
---|
| 372 | unsigned int len;
|
---|
| 373 |
|
---|
| 374 | bzero(&sou, sizeof(sou));
|
---|
| 375 |
|
---|
| 376 | /*
|
---|
| 377 | * Construct the unix domain socket address and attempt to connect
|
---|
| 378 | */
|
---|
| 379 | fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
---|
| 380 | if (fd >= 0) {
|
---|
| 381 | sou.sun_family = AF_UNIX;
|
---|
| 382 | if ((len = strlcpy(sou.sun_path, path,
|
---|
| 383 | sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) {
|
---|
| 384 | errno = ENAMETOOLONG;
|
---|
| 385 | return (-1);
|
---|
| 386 | }
|
---|
| 387 | len = offsetof(struct sockaddr_un, sun_path[len+1]);
|
---|
| 388 |
|
---|
| 389 | if (connect(fd, (void *)&sou, len) < 0) {
|
---|
| 390 | close(fd);
|
---|
| 391 | fd = -1;
|
---|
| 392 | }
|
---|
| 393 | }
|
---|
| 394 |
|
---|
| 395 | /*
|
---|
| 396 | * handle the open flags by shutting down appropriate directions
|
---|
| 397 | */
|
---|
| 398 | if (fd >= 0) {
|
---|
| 399 | switch(flags & O_ACCMODE) {
|
---|
| 400 | case O_RDONLY:
|
---|
| 401 | if (shutdown(fd, SHUT_WR) == -1)
|
---|
[3218] | 402 | warn(pThis->pCtx, NULL);
|
---|
[813] | 403 | break;
|
---|
| 404 | case O_WRONLY:
|
---|
| 405 | if (shutdown(fd, SHUT_RD) == -1)
|
---|
[3218] | 406 | warn(pThis->pCtx, NULL);
|
---|
[813] | 407 | break;
|
---|
| 408 | default:
|
---|
| 409 | break;
|
---|
| 410 | }
|
---|
| 411 | }
|
---|
| 412 | return(fd);
|
---|
| 413 | }
|
---|
| 414 |
|
---|
| 415 | #endif
|
---|
[3192] | 416 |
|
---|