1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* Copyright (c) 1987, 1988 Microsoft Corporation */ 31 /* All Rights Reserved */ 32 33 /* Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ 34 35 /* 36 * grep -- print lines matching (or not matching) a pattern 37 * 38 * status returns: 39 * 0 - ok, and some matches 40 * 1 - ok, but no matches 41 * 2 - some error 42 */ 43 44 #include <sys/types.h> 45 46 #include <ctype.h> 47 #include <fcntl.h> 48 #include <locale.h> 49 #include <memory.h> 50 #include <regexpr.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 #include <ftw.h> 56 #include <limits.h> 57 #include <sys/param.h> 58 59 static const char *errstr[] = { 60 "Range endpoint too large.", 61 "Bad number.", 62 "``\\digit'' out of range.", 63 "No remembered search string.", 64 "\\( \\) imbalance.", 65 "Too many \\(.", 66 "More than 2 numbers given in \\{ \\}.", 67 "} expected after \\.", 68 "First number exceeds second in \\{ \\}.", 69 "[ ] imbalance.", 70 "Regular expression overflow.", 71 "Illegal byte sequence.", 72 "Unknown regexp error code!!", 73 NULL 74 }; 75 76 #define STDIN_FILENAME gettext("(standard input)") 77 78 #define errmsg(msg, arg) (void) fprintf(stderr, gettext(msg), arg) 79 #define BLKSIZE 512 80 #define GBUFSIZ 8192 81 #define MAX_DEPTH 1000 82 83 static int temp; 84 static long long lnum; 85 static char *linebuf; 86 static char *prntbuf = NULL; 87 static long fw_lPrntBufLen = 0; 88 static int nflag; 89 static int bflag; 90 static int lflag; 91 static int cflag; 92 static int rflag; 93 static int Rflag; 94 static int vflag; 95 static int sflag; 96 static int iflag; 97 static int wflag; 98 static int hflag; 99 static int Hflag; 100 static int qflag; 101 static int errflg; 102 static int nfile; 103 static long long tln; 104 static int nsucc; 105 static int outfn = 0; 106 static int nlflag; 107 static char *ptr, *ptrend; 108 static char *expbuf; 109 110 static void execute(const char *, int); 111 static void regerr(int); 112 static void prepare(const char *); 113 static int recursive(const char *, const struct stat *, int, struct FTW *); 114 static int succeed(const char *); 115 116 int 117 main(int argc, char **argv) 118 { 119 int c; 120 char *arg; 121 extern int optind; 122 123 (void) setlocale(LC_ALL, ""); 124 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 125 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 126 #endif 127 (void) textdomain(TEXT_DOMAIN); 128 129 while ((c = getopt(argc, argv, "hHqblcnRrsviyw")) != -1) 130 switch (c) { 131 /* based on options order h or H is set as in GNU grep */ 132 case 'h': 133 hflag++; 134 Hflag = 0; /* h excludes H */ 135 break; 136 case 'H': 137 if (!lflag) /* H is excluded by l */ 138 Hflag++; 139 hflag = 0; /* H excludes h */ 140 break; 141 case 'q': /* POSIX: quiet: status only */ 142 qflag++; 143 break; 144 case 'v': 145 vflag++; 146 break; 147 case 'c': 148 cflag++; 149 break; 150 case 'n': 151 nflag++; 152 break; 153 case 'R': 154 Rflag++; 155 /* FALLTHROUGH */ 156 case 'r': 157 rflag++; 158 break; 159 case 'b': 160 bflag++; 161 break; 162 case 's': 163 sflag++; 164 break; 165 case 'l': 166 lflag++; 167 Hflag = 0; /* l excludes H */ 168 break; 169 case 'y': 170 case 'i': 171 iflag++; 172 break; 173 case 'w': 174 wflag++; 175 break; 176 case '?': 177 errflg++; 178 } 179 180 if (errflg || (optind >= argc)) { 181 errmsg("Usage: grep [-c|-l|-q] [-r|-R] -hHbnsviw " 182 "pattern file . . .\n", 183 (char *)NULL); 184 exit(2); 185 } 186 187 argv = &argv[optind]; 188 argc -= optind; 189 nfile = argc - 1; 190 191 if (strrchr(*argv, '\n') != NULL) 192 regerr(41); 193 194 if (iflag) { 195 for (arg = *argv; *arg != NULL; ++arg) 196 *arg = (char)tolower((int)((unsigned char)*arg)); 197 } 198 199 if (wflag) { 200 unsigned int wordlen; 201 char *wordbuf; 202 203 wordlen = strlen(*argv) + 5; /* '\\' '<' *argv '\\' '>' '\0' */ 204 if ((wordbuf = malloc(wordlen)) == NULL) { 205 errmsg("grep: Out of memory for word\n", (char *)NULL); 206 exit(2); 207 } 208 209 (void) strcpy(wordbuf, "\\<"); 210 (void) strcat(wordbuf, *argv); 211 (void) strcat(wordbuf, "\\>"); 212 *argv = wordbuf; 213 } 214 215 expbuf = compile(*argv, (char *)0, (char *)0); 216 if (regerrno) 217 regerr(regerrno); 218 219 if (--argc == 0) 220 execute(NULL, 0); 221 else 222 while (argc-- > 0) 223 prepare(*++argv); 224 225 return (nsucc == 2 ? 2 : (nsucc == 0 ? 1 : 0)); 226 } 227 228 static void 229 prepare(const char *path) 230 { 231 struct stat st; 232 int walkflags = FTW_CHDIR; 233 char *buf = NULL; 234 235 if (rflag) { 236 if (stat(path, &st) != -1 && 237 (st.st_mode & S_IFMT) == S_IFDIR) { 238 outfn = 1; 239 240 /* 241 * Add trailing slash if arg 242 * is directory, to resolve symlinks. 243 */ 244 if (path[strlen(path) - 1] != '/') { 245 (void) asprintf(&buf, "%s/", path); 246 if (buf != NULL) 247 path = buf; 248 } 249 250 /* 251 * Search through subdirs if path is directory. 252 * Don't follow symlinks if Rflag is not set. 253 */ 254 if (!Rflag) 255 walkflags |= FTW_PHYS; 256 257 if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) { 258 if (!sflag) 259 errmsg("grep: can't open %s\n", path); 260 nsucc = 2; 261 } 262 return; 263 } 264 } 265 execute(path, 0); 266 } 267 268 static int 269 recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw) 270 { 271 /* 272 * process files and follow symlinks if Rflag set. 273 */ 274 if (info != FTW_F) { 275 if (!sflag && 276 (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) { 277 /* report broken symlinks and unreadable files */ 278 errmsg("grep: can't open %s\n", name); 279 } 280 return (0); 281 } 282 283 /* skip devices and pipes if Rflag is not set */ 284 if (!Rflag && !S_ISREG(statp->st_mode)) 285 return (0); 286 287 /* pass offset to relative name from FTW_CHDIR */ 288 execute(name, ftw->base); 289 return (0); 290 } 291 292 static void 293 execute(const char *file, int base) 294 { 295 char *lbuf, *p; 296 long count; 297 long offset = 0; 298 char *next_ptr = NULL; 299 long next_count = 0; 300 301 tln = 0; 302 303 if (prntbuf == NULL) { 304 fw_lPrntBufLen = GBUFSIZ + 1; 305 if ((prntbuf = malloc(fw_lPrntBufLen)) == NULL) { 306 exit(2); /* out of memory - BAIL */ 307 } 308 if ((linebuf = malloc(fw_lPrntBufLen)) == NULL) { 309 exit(2); /* out of memory - BAIL */ 310 } 311 } 312 313 if (file == NULL) { 314 temp = 0; 315 file = STDIN_FILENAME; 316 } else if ((temp = open(file + base, O_RDONLY)) == -1) { 317 if (!sflag) 318 errmsg("grep: can't open %s\n", file); 319 nsucc = 2; 320 return; 321 } 322 323 /* read in first block of bytes */ 324 if ((count = read(temp, prntbuf, GBUFSIZ)) <= 0) { 325 (void) close(temp); 326 327 if (cflag && !qflag) { 328 if (Hflag || (nfile > 1 && !hflag)) 329 (void) fprintf(stdout, "%s:", file); 330 if (!rflag) 331 (void) fprintf(stdout, "%lld\n", tln); 332 } 333 return; 334 } 335 336 lnum = 0; 337 ptr = prntbuf; 338 for (;;) { 339 /* look for next newline */ 340 if ((ptrend = memchr(ptr + offset, '\n', count)) == NULL) { 341 offset += count; 342 343 /* 344 * shift unused data to the beginning of the buffer 345 */ 346 if (ptr > prntbuf) { 347 (void) memmove(prntbuf, ptr, offset); 348 ptr = prntbuf; 349 } 350 351 /* 352 * re-allocate a larger buffer if this one is full 353 */ 354 if (offset + GBUFSIZ > fw_lPrntBufLen) { 355 /* 356 * allocate a new buffer and preserve the 357 * contents... 358 */ 359 fw_lPrntBufLen += GBUFSIZ; 360 if ((prntbuf = realloc(prntbuf, 361 fw_lPrntBufLen)) == NULL) 362 exit(2); 363 364 /* 365 * set up a bigger linebuffer (this is only used 366 * for case insensitive operations). Contents do 367 * not have to be preserved. 368 */ 369 free(linebuf); 370 if ((linebuf = malloc(fw_lPrntBufLen)) == NULL) 371 exit(2); 372 373 ptr = prntbuf; 374 } 375 376 p = prntbuf + offset; 377 if ((count = read(temp, p, GBUFSIZ)) > 0) 378 continue; 379 380 if (offset == 0) 381 /* end of file already reached */ 382 break; 383 384 /* last line of file has no newline */ 385 ptrend = ptr + offset; 386 nlflag = 0; 387 } else { 388 next_ptr = ptrend + 1; 389 next_count = offset + count - (next_ptr - ptr); 390 nlflag = 1; 391 } 392 lnum++; 393 *ptrend = '\0'; 394 395 if (iflag) { 396 /* 397 * Make a lower case copy of the record 398 */ 399 p = ptr; 400 for (lbuf = linebuf; p < ptrend; ) 401 *lbuf++ = (char)tolower((int) 402 (unsigned char)*p++); 403 *lbuf = '\0'; 404 lbuf = linebuf; 405 } else 406 /* 407 * Use record as is 408 */ 409 lbuf = ptr; 410 411 /* lflag only once */ 412 if ((step(lbuf, expbuf) ^ vflag) && succeed(file) == 1) 413 break; 414 415 if (!nlflag) 416 break; 417 418 ptr = next_ptr; 419 count = next_count; 420 offset = 0; 421 } 422 (void) close(temp); 423 424 if (cflag && !qflag) { 425 if (Hflag || (!hflag && ((nfile > 1) || 426 (rflag && outfn)))) 427 (void) fprintf(stdout, "%s:", file); 428 (void) fprintf(stdout, "%lld\n", tln); 429 } 430 } 431 432 static int 433 succeed(const char *f) 434 { 435 int nchars; 436 nsucc = (nsucc == 2) ? 2 : 1; 437 438 if (qflag) { 439 /* no need to continue */ 440 return (1); 441 } 442 443 if (cflag) { 444 tln++; 445 return (0); 446 } 447 448 if (lflag) { 449 (void) fprintf(stdout, "%s\n", f); 450 return (1); 451 } 452 453 if (Hflag || (!hflag && (nfile > 1 || (rflag && outfn)))) { 454 /* print filename */ 455 (void) fprintf(stdout, "%s:", f); 456 } 457 458 if (bflag) 459 /* print block number */ 460 (void) fprintf(stdout, "%lld:", (offset_t) 461 ((lseek(temp, (off_t)0, SEEK_CUR) - 1) / BLKSIZE)); 462 463 if (nflag) 464 /* print line number */ 465 (void) fprintf(stdout, "%lld:", lnum); 466 467 if (nlflag) { 468 /* newline at end of line */ 469 *ptrend = '\n'; 470 nchars = ptrend - ptr + 1; 471 } else { 472 /* don't write sentinel \0 */ 473 nchars = ptrend - ptr; 474 } 475 476 (void) fwrite(ptr, 1, nchars, stdout); 477 return (0); 478 } 479 480 static void 481 regerr(int err) 482 { 483 errmsg("grep: RE error %d: ", err); 484 switch (err) { 485 case 11: 486 err = 0; 487 break; 488 case 16: 489 err = 1; 490 break; 491 case 25: 492 err = 2; 493 break; 494 case 41: 495 err = 3; 496 break; 497 case 42: 498 err = 4; 499 break; 500 case 43: 501 err = 5; 502 break; 503 case 44: 504 err = 6; 505 break; 506 case 45: 507 err = 7; 508 break; 509 case 46: 510 err = 8; 511 break; 512 case 49: 513 err = 9; 514 break; 515 case 50: 516 err = 10; 517 break; 518 case 67: 519 err = 11; 520 break; 521 default: 522 err = 12; 523 break; 524 } 525 526 errmsg("%s\n", gettext(errstr[err])); 527 exit(2); 528 }