diff options
Diffstat (limited to 'usr/src/cmd/grep/grep.c')
| -rw-r--r-- | usr/src/cmd/grep/grep.c | 105 |
1 files changed, 94 insertions, 11 deletions
diff --git a/usr/src/cmd/grep/grep.c b/usr/src/cmd/grep/grep.c index 62a4527529..edc83be3e6 100644 --- a/usr/src/cmd/grep/grep.c +++ b/usr/src/cmd/grep/grep.c @@ -52,6 +52,9 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <ftw.h> +#include <limits.h> +#include <sys/param.h> static const char *errstr[] = { "Range endpoint too large.", @@ -73,6 +76,7 @@ static const char *errstr[] = { #define errmsg(msg, arg) (void) fprintf(stderr, gettext(msg), arg) #define BLKSIZE 512 #define GBUFSIZ 8192 +#define MAX_DEPTH 1000 static int temp; static long long lnum; @@ -83,6 +87,8 @@ static int nflag; static int bflag; static int lflag; static int cflag; +static int rflag; +static int Rflag; static int vflag; static int sflag; static int iflag; @@ -93,13 +99,16 @@ static int errflg; static int nfile; static long long tln; static int nsucc; +static int outfn = 0; static int nlflag; static char *ptr, *ptrend; static char *expbuf; -static void execute(char *); +static void execute(const char *, int); static void regerr(int); -static int succeed(char *); +static void prepare(const char *); +static int recursive(const char *, const struct stat *, int, struct FTW *); +static int succeed(const char *); int main(int argc, char **argv) @@ -114,7 +123,7 @@ main(int argc, char **argv) #endif (void) textdomain(TEXT_DOMAIN); - while ((c = getopt(argc, argv, "hqblcnsviyw")) != -1) + while ((c = getopt(argc, argv, "hqblcnRrsviyw")) != -1) switch (c) { case 'h': hflag++; @@ -131,6 +140,12 @@ main(int argc, char **argv) case 'n': nflag++; break; + case 'R': + Rflag++; + /* FALLTHROUGH */ + case 'r': + rflag++; + break; case 'b': bflag++; break; @@ -152,7 +167,8 @@ main(int argc, char **argv) } if (errflg || (optind >= argc)) { - errmsg("Usage: grep [-c|-l|-q] -hbnsviw pattern file . . .\n", + errmsg("Usage: grep [-c|-l|-q] [-r|-R] -hbnsviw " + "pattern file . . .\n", (char *)NULL); exit(2); } @@ -190,16 +206,80 @@ main(int argc, char **argv) regerr(regerrno); if (--argc == 0) - execute(NULL); + execute(NULL, 0); else while (argc-- > 0) - execute(*++argv); + prepare(*++argv); return (nsucc == 2 ? 2 : (nsucc == 0 ? 1 : 0)); } static void -execute(char *file) +prepare(const char *path) +{ + struct stat st; + int walkflags = FTW_CHDIR; + char *buf = NULL; + + if (rflag) { + if (stat(path, &st) != -1 && + (st.st_mode & S_IFMT) == S_IFDIR) { + outfn = 1; + + /* + * Add trailing slash if arg + * is directory, to resolve symlinks. + */ + if (path[strlen(path) - 1] != '/') { + (void) asprintf(&buf, "%s/", path); + if (buf != NULL) + path = buf; + } + + /* + * Search through subdirs if path is directory. + * Don't follow symlinks if Rflag is not set. + */ + if (!Rflag) + walkflags |= FTW_PHYS; + + if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) { + if (!sflag) + errmsg("grep: can't open %s\n", path); + nsucc = 2; + } + return; + } + } + execute(path, 0); +} + +static int +recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw) +{ + /* + * process files and follow symlinks if Rflag set. + */ + if (info != FTW_F) { + if (!sflag && + (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) { + /* report broken symlinks and unreadable files */ + errmsg("grep: can't open %s\n", name); + } + return (0); + } + + /* skip devices and pipes if Rflag is not set */ + if (!Rflag && !S_ISREG(statp->st_mode)) + return (0); + + /* pass offset to relative name from FTW_CHDIR */ + execute(name, ftw->base); + return (0); +} + +static void +execute(const char *file, int base) { char *lbuf, *p; long count; @@ -221,7 +301,7 @@ execute(char *file) if (file == NULL) temp = 0; - else if ((temp = open(file, O_RDONLY)) == -1) { + else if ((temp = open(file + base, O_RDONLY)) == -1) { if (!sflag) errmsg("grep: can't open %s\n", file); nsucc = 2; @@ -235,6 +315,7 @@ execute(char *file) if (cflag && !qflag) { if (nfile > 1 && !hflag && file) (void) fprintf(stdout, "%s:", file); + if (!rflag) (void) fprintf(stdout, "%lld\n", tln); } return; @@ -329,14 +410,15 @@ execute(char *file) (void) close(temp); if (cflag && !qflag) { - if (nfile > 1 && !hflag && file) + if (!hflag && file && (nfile > 1 || + (rflag && outfn))) (void) fprintf(stdout, "%s:", file); (void) fprintf(stdout, "%lld\n", tln); } } static int -succeed(char *f) +succeed(const char *f) { int nchars; nsucc = (nsucc == 2) ? 2 : 1; @@ -359,9 +441,10 @@ succeed(char *f) return (1); } - if (nfile > 1 && !hflag) + if (!hflag && (nfile > 1 || (rflag && outfn))) { /* print filename */ (void) fprintf(stdout, "%s:", f); + } if (bflag) /* print block number */ |
