diff --git a/bin/cat/cat.1 b/bin/cat/cat.1 index a8eead6f8556..df7d2e199ea6 100644 --- a/bin/cat/cat.1 +++ b/bin/cat/cat.1 @@ -58,7 +58,12 @@ is a single dash .Pq Sq \&- or absent, .Nm -reads from the standard input. +reads from the standard input. If +.Ar file +is a unix domain socket, +.Nm +connects to it and then reads it until EOF. This complements the unix-domain +binding capability available in inetd. .Pp The options are as follows: .Bl -tag -width indent diff --git a/bin/cat/cat.c b/bin/cat/cat.c index 30ab5bf9b85d..2bfac6c7b9ec 100644 --- a/bin/cat/cat.c +++ b/bin/cat/cat.c @@ -50,6 +50,11 @@ static const char rcsid[] = #include #include +#ifndef NO_UDOM_SUPPORT +#include +#include +#include +#endif #include #include @@ -59,16 +64,21 @@ static const char rcsid[] = #include #include #include +#include int bflag, eflag, nflag, sflag, tflag, vflag; int rval; const char *filename; -void cook_args __P((char *argv[])); -void cook_buf __P((FILE *)); int main __P((int argc, char *argv[])); -void raw_args __P((char *argv[])); -void raw_cat __P((int)); + +static void scanfiles __P((char **argv, int cooked)); +static void cook_cat __P((FILE *)); +static void raw_cat __P((int)); + +#ifndef NO_UDOM_SUPPORT +static int udom_open __P((const char *path, int flags, int modes)); +#endif int main(argc, argv) @@ -110,42 +120,55 @@ main(argc, argv) argv += optind; if (bflag || eflag || nflag || sflag || tflag || vflag) - cook_args(argv); + scanfiles(argv, 1); else - raw_args(argv); + scanfiles(argv, 0); if (fclose(stdout)) err(1, "stdout"); exit(rval); } void -cook_args(argv) - char **argv; +scanfiles(argv, cooked) + char **argv; + int cooked; { - register FILE *fp; + int i = 0; + char *path; - fp = stdin; - filename = "stdin"; - do { - if (*argv) { - if (!strcmp(*argv, "-")) - fp = stdin; - else if ((fp = fopen(*argv, "r")) == NULL) { - warn("%s", *argv); - rval = 1; - ++argv; - continue; - } - filename = *argv++; + while ((path = argv[i]) != NULL || i == 0) { + int fd; + + if (path == NULL || strcmp(path, "-") == 0) { + filename = "stdin"; + fd = 0; + } else { + filename = path; + fd = open(path, O_RDONLY); +#ifndef NO_UDOM_SUPPORT + if (fd < 0 && errno == EOPNOTSUPP) + fd = udom_open(path, O_RDONLY, 0); +#endif } - cook_buf(fp); - if (fp != stdin) - (void)fclose(fp); - } while (*argv); + if (fd < 0) { + warn("%s", path); + rval = 1; + } else if (cooked) { + FILE *fp = fdopen(fd, "r"); + cook_cat(fp); + fclose(fp); + } else { + raw_cat(fd); + close(fd); + } + if (path == NULL) + break; + ++i; + } } -void -cook_buf(fp) +static void +cook_cat(fp) register FILE *fp; { register int ch, gobble, line, prev; @@ -208,33 +231,7 @@ cook_buf(fp) err(1, "stdout"); } -void -raw_args(argv) - char **argv; -{ - register int fd; - - fd = fileno(stdin); - filename = "stdin"; - do { - if (*argv) { - if (!strcmp(*argv, "-")) - fd = fileno(stdin); - else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { - warn("%s", *argv); - rval = 1; - ++argv; - continue; - } - filename = *argv++; - } - raw_cat(fd); - if (fd != fileno(stdin)) - (void)close(fd); - } while (*argv); -} - -void +static void raw_cat(rfd) register int rfd; { @@ -261,3 +258,53 @@ raw_cat(rfd) rval = 1; } } + +#ifndef NO_UDOM_SUPPORT + +static int +udom_open(path, flags, modes) + const char *path; + int flags; + int modes; +{ + struct sockaddr_un sou; + int fd; + int len; + + bzero(&sou, sizeof(sou)); + + /* + * Construct the unix domain socket address and attempt to connect + */ + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) { + sou.sun_family = AF_UNIX; + snprintf(sou.sun_path, sizeof(sou.sun_path), "%s", path); + len = strlen(sou.sun_path); + len = offsetof(struct sockaddr_un, sun_path[len+1]); + + if (connect(fd, (void *)&sou, len) < 0) { + close(fd); + fd = -1; + } + } + + /* + * handle the open flags by shutting down appropriate directions + */ + if (fd >= 0) { + switch(flags & O_ACCMODE) { + case O_RDONLY: + shutdown(fd, SHUT_WR); + break; + case O_WRONLY: + shutdown(fd, SHUT_RD); + break; + default: + break; + } + } + return(fd); +} + +#endif +