Changeset View
Changeset View
Standalone View
Standalone View
usr.bin/grep/grep.c
Show All 26 Lines | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/stat.h> | |||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/stat.h> | |||||
#include <capsicum_helpers.h> | |||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <getopt.h> | #include <getopt.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
#include <libgen.h> | #include <libgen.h> | ||||
#include <locale.h> | #include <locale.h> | ||||
Show All 30 Lines | |||||
/* Flags passed to regcomp() and regexec() */ | /* Flags passed to regcomp() and regexec() */ | ||||
int cflags = REG_NOSUB; | int cflags = REG_NOSUB; | ||||
int eflags = REG_STARTEND; | int eflags = REG_STARTEND; | ||||
/* Shortcut for matching all cases like empty regex */ | /* Shortcut for matching all cases like empty regex */ | ||||
bool matchall; | bool matchall; | ||||
/* Capsicum */ | |||||
cap_rights_t ro_rights; | |||||
bool do_cap_enter = false; | |||||
/* Searching patterns */ | /* Searching patterns */ | ||||
unsigned int patterns; | unsigned int patterns; | ||||
static unsigned int pattern_sz; | static unsigned int pattern_sz; | ||||
struct pat *pattern; | struct pat *pattern; | ||||
regex_t *r_pattern; | regex_t *r_pattern; | ||||
fastmatch_t *fg_pattern; | fastmatch_t *fg_pattern; | ||||
/* Filename exclusion/inclusion patterns */ | /* Filename exclusion/inclusion patterns */ | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | enum { | ||||
NULL_OPT, | NULL_OPT, | ||||
R_EXCLUDE_OPT, | R_EXCLUDE_OPT, | ||||
R_INCLUDE_OPT, | R_INCLUDE_OPT, | ||||
R_DEXCLUDE_OPT, | R_DEXCLUDE_OPT, | ||||
R_DINCLUDE_OPT | R_DINCLUDE_OPT | ||||
}; | }; | ||||
static inline const char *init_color(const char *); | static inline const char *init_color(const char *); | ||||
static int last_included_file(int, char *[]); | |||||
/* Housekeeping */ | /* Housekeeping */ | ||||
bool first = true; /* flag whether we are processing the first match */ | bool first = true; /* flag whether we are processing the first match */ | ||||
bool prev; /* flag whether or not the previous line matched */ | bool prev; /* flag whether or not the previous line matched */ | ||||
int tail; /* lines left to print */ | int tail; /* lines left to print */ | ||||
bool file_err; /* file reading error */ | bool file_err; /* file reading error */ | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | read_patterns(const char *fn) | ||||
struct stat st; | struct stat st; | ||||
FILE *f; | FILE *f; | ||||
char *line; | char *line; | ||||
size_t len; | size_t len; | ||||
ssize_t rlen; | ssize_t rlen; | ||||
if ((f = fopen(fn, "r")) == NULL) | if ((f = fopen(fn, "r")) == NULL) | ||||
err(2, "%s", fn); | err(2, "%s", fn); | ||||
if (cap_rights_limit(fileno(f), &ro_rights) < 0 && | |||||
errno != ENOSYS) | |||||
err(2, "unable to limit rights on: %s", fn); | |||||
if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { | if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { | ||||
fclose(f); | fclose(f); | ||||
return; | return; | ||||
} | } | ||||
len = 0; | len = 0; | ||||
line = NULL; | line = NULL; | ||||
while ((rlen = getline(&line, &len, f)) != -1) | while ((rlen = getline(&line, &len, f)) != -1) | ||||
add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen); | add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen); | ||||
free(line); | free(line); | ||||
if (ferror(f)) | if (ferror(f)) | ||||
err(2, "%s", fn); | err(2, "%s", fn); | ||||
fclose(f); | fclose(f); | ||||
} | } | ||||
static inline const char * | static inline const char * | ||||
init_color(const char *d) | init_color(const char *d) | ||||
{ | { | ||||
char *c; | char *c; | ||||
c = getenv("GREP_COLOR"); | c = getenv("GREP_COLOR"); | ||||
return (c != NULL && c[0] != '\0' ? c : d); | return (c != NULL && c[0] != '\0' ? c : d); | ||||
} | } | ||||
/** | |||||
* Returns the last argv index used as an input file, or just past the end if none are used | |||||
*/ | |||||
static int | |||||
last_included_file(int argc, char *argv[]) | |||||
{ | |||||
int lastidx = argc, c; | |||||
if (!finclude && !fexclude) | |||||
return argc - 1; | |||||
for (c = 0; argc--; ++argv) { | |||||
if (!file_matching(*argv)) | |||||
continue; | |||||
lastidx = c; | |||||
} | |||||
return lastidx; | |||||
} | |||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
char **aargv, **eargv, *eopts; | char **aargv, **eargv, *eopts; | ||||
char *ep; | char *ep; | ||||
const char *pn; | const char *pn; | ||||
unsigned long long l; | unsigned long long l; | ||||
unsigned int aargc, eargc, i; | unsigned int aargc, eargc, i, largc; | ||||
int c, lastc, needpattern, newarg, prevoptind; | int c, lastc, needpattern, newarg, prevoptind; | ||||
setlocale(LC_ALL, ""); | setlocale(LC_ALL, ""); | ||||
cap_rights_init(&ro_rights, CAP_FSTAT, CAP_READ); | |||||
#ifndef WITHOUT_NLS | #ifndef WITHOUT_NLS | ||||
catalog = catopen("grep", NL_CAT_LOCALE); | catalog = catopen("grep", NL_CAT_LOCALE); | ||||
#endif | #endif | ||||
/* Check what is the program name of the binary. In this | /* Check what is the program name of the binary. In this | ||||
emaste: It's preferable I think to declare the capsicum rights in the two places cap_rights_limit is… | |||||
way we can have all the funcionalities in one binary | way we can have all the funcionalities in one binary | ||||
without the need of scripting and using ugly hacks. */ | without the need of scripting and using ugly hacks. */ | ||||
pn = getprogname(); | pn = getprogname(); | ||||
if (pn[0] == 'b' && pn[1] == 'z') { | if (pn[0] == 'b' && pn[1] == 'z') { | ||||
filebehave = FILE_BZIP; | filebehave = FILE_BZIP; | ||||
pn += 2; | pn += 2; | ||||
} else if (pn[0] == 'x' && pn[1] == 'z') { | } else if (pn[0] == 'x' && pn[1] == 'z') { | ||||
filebehave = FILE_XZ; | filebehave = FILE_XZ; | ||||
▲ Show 20 Lines • Show All 361 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
if (lbflag) | if (lbflag) | ||||
setlinebuf(stdout); | setlinebuf(stdout); | ||||
if ((aargc == 0 || aargc == 1) && !Hflag) | if ((aargc == 0 || aargc == 1) && !Hflag) | ||||
hflag = true; | hflag = true; | ||||
if (aargc == 0) | if (caph_limit_stdio() == -1) | ||||
err(2, "unable to limit stdio"); | |||||
if (aargc == 0) { | |||||
if (cap_enter() < 0 && errno != ENOSYS) | |||||
err(2, "unable to enter capability mode"); | |||||
exit(!procfile("-")); | exit(!procfile("-")); | ||||
} | |||||
/* | |||||
* The recursive case does not currently enter capabilities mode | |||||
* at all due to the lack of casper file service. We should revise | |||||
* this to encompas all recursive and non-recursive cases later | |||||
* when a casper file service or similar approach becomes available. | |||||
*/ | |||||
if (dirbehave == DIR_RECURSE) | if (dirbehave == DIR_RECURSE) | ||||
c = grep_tree(aargv); | c = grep_tree(aargv); | ||||
else | else { | ||||
for (c = 0; aargc--; ++aargv) { | largc = last_included_file(aargc, aargv); | ||||
for (c = 0; aargc--; ++aargv, --largc) { | |||||
if ((finclude || fexclude) && !file_matching(*aargv)) | if ((finclude || fexclude) && !file_matching(*aargv)) | ||||
continue; | continue; | ||||
/* Upon the last usable file argument, we enter capabilities mode */ | |||||
if (largc == 0) | |||||
do_cap_enter = true; | |||||
c+= procfile(*aargv); | c+= procfile(*aargv); | ||||
} | |||||
} | } | ||||
#ifndef WITHOUT_NLS | #ifndef WITHOUT_NLS | ||||
catclose(catalog); | catclose(catalog); | ||||
#endif | #endif | ||||
/* Find out the correct return value according to the | /* Find out the correct return value according to the | ||||
results and the command line option. */ | results and the command line option. */ | ||||
exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); | exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); | ||||
} | } |
It's preferable I think to declare the capsicum rights in the two places cap_rights_limit is called, perhaps using the idiom from the man page, something like:
(with appropriate rights of course)