/* forkaftergrep (C) 2017 Tobias Girstmair, GPLv3 */
-//TODO: supply user arguments to grep
-//demo: ./fag -e -V "MPD server running at" mopidy
+//TODO: EX_UNAVAILABLE is wrongly used three times
#define _XOPEN_SOURCE 500
#define _DEFAULT_SOURCE
#include <unistd.h>
#include "fag.h"
-struct opt opts = {0, 0, 0, NULL, NULL, STDOUT_FILENO};
-
int main (int argc, char** argv) {
+ struct opt opts = {0, 0, 0, NULL, NULL, STDOUT_FILENO};
+ struct grepopt optg = {basic_regexp, 0, 0, 0, 0};
int opt;
opterr = 0;
/* the `+' forces getopt to stop at the first non-option */
- while ((opt = getopt (argc, argv, "+t:k::eVhv")) != -1) {
+ while ((opt = getopt (argc, argv, "+t:k::eVhvEFGPiwxyU")) != -1) {
switch (opt) {
case 't':
opts.timeout = atoi (optarg);
case 'v':
fprintf (stderr, VERTEXT);
return EX_OK;
+ /* `grep' options (Note: missing `-e:', `-f:') */
+ case 'E': optg.regex = extended_regexp; break;
+ case 'F': optg.regex = fixed_strings ; break;
+ case 'G': optg.regex = basic_regexp ; break; /* default */
+ case 'P': optg.regex = perl_regexp ; break;
+ case 'i': /* fall thru */
+ case 'y': optg.ignore_case = 1; break;
+ case 'w': optg.word_regexp = 1; break;
+ case 'x': optg.line_regexp = 1; break;
+ case 'U': optg.binary = 1; break;
+
default:
fprintf (stderr, "Unrecognized option: %c\n" USAGE, optopt, argv[0]);
return EX_USAGE;
return EX_USAGE;
}
- int retval = fork_after_grep (opts);
+ int retval = fork_after_grep (opts, optg);
return retval;
}
-int fork_after_grep (struct opt opts) {
+int fork_after_grep (struct opt opts, struct grepopt optg) {
int pipefd[2];
pid_t cpid;
int status;
_exit (EX_UNAVAILABLE);
} else {
pid_t grep_cpid;
- int pipefd_togrep[2];
+ int grep_pipefd[2];
int grep_status;
- /* `-q': don't print anything; exit with 0 on match; with 1 on error */
- char* grepargv[] = {"grep", "-q", opts.pattern, NULL};
close (pipefd[1]);
fcntl (pipefd[0], F_SETFL, fcntl (pipefd[0], F_GETFL, 0) | O_NONBLOCK);
gettimeofday (&begin, NULL); /* for timeout */
- if (pipe(pipefd_togrep) == -1) {
+ if (pipe(grep_pipefd) == -1) {
fprintf (stderr, "pipe error (grep)\n");
close (pipefd[0]);
close (pipefd[1]);
fprintf (stderr, "fork error (grep): %s", strerror (errno));
close (pipefd[0]);
close (pipefd[1]);
- close (pipefd_togrep[0]);
- close (pipefd_togrep[1]);
+ close (grep_pipefd[0]);
+ close (grep_pipefd[1]);
return EX_OSERR;
}
if (grep_cpid == 0) {
- close (pipefd_togrep[1]);
- dup2 (pipefd_togrep[0], STDIN_FILENO);
- close (pipefd_togrep[0]);
+ close (grep_pipefd[1]);
+ dup2 (grep_pipefd[0], STDIN_FILENO);
+ close (grep_pipefd[0]);
close (STDERR_FILENO);
close (STDOUT_FILENO);
- execvp (grepargv[0], grepargv);
+ /* generate argument list on the fly (TODO: ugly) */
+ /* `-q': don't print anything; exit with 0 on match; with 1 on error */
+ char grep_options[16] = "-q";
+ char* p = grep_options+2;
+ if (optg.regex == extended_regexp) *(p++)='E';
+ if (optg.regex == fixed_strings) *(p++)='F';
+ if (optg.regex == basic_regexp) *(p++)='G';
+ if (optg.regex == perl_regexp) *(p++)='P';
+ if (optg.ignore_case) *(p++)='i';
+ if (optg.word_regexp) *(p++)='w';
+ if (optg.line_regexp) *(p++)='x';
+ if (optg.binary) *(p++)='U';
+ *p = '\0';
+
+ execlp ("grep", "grep", grep_options, opts.pattern, NULL);
fprintf (stderr, "exec error (grep): %s", strerror (errno));
_exit (EX_UNAVAILABLE);
} else {
- close (pipefd_togrep[0]);
+ close (grep_pipefd[0]);
for (;;) {
usleep (20000);
- memset (buf, 0, BUF_SIZE); /* necessary for opts.verbose */
nbytes = read (pipefd[0], buf, BUF_SIZE);
if (nbytes == -1) {
switch (errno) {
fprintf (stderr, "read error (userprog): %s", strerror (errno));
close (pipefd[0]);
close (pipefd[1]);
- close (pipefd_togrep[1]);
+ close (grep_pipefd[1]);
//TODO: kill grep?
return EX_IOERR;
}
fprintf (stderr, "Child program exited prematurely (userprog).\n");
close (pipefd[0]);
close (pipefd[1]);
- close (pipefd_togrep[1]);
+ close (grep_pipefd[1]);
//TODO: kill grep?
if (waitpid (cpid, &status, WNOHANG) > 0 && WIFEXITED (status)) {
return WEXITSTATUS (status);
/* have new userprog-data, send it to grep */
if (opts.verbose) {
fputs (buf, stderr);
+ write(STDERR_FILENO, buf, nbytes);
}
- write(pipefd_togrep[1], buf, strlen(buf));
+ write(grep_pipefd[1], buf, nbytes);
}
if (waitpid (grep_cpid, &grep_status, WNOHANG) > 0 && WIFEXITED (grep_status)) {
- close (pipefd_togrep[1]);
+ close (grep_pipefd[1]);
if (WEXITSTATUS(grep_status) == 0) {
/* grep exited with match found */
fprintf (stderr, "grep exited due to an error.");
close (pipefd[0]);
close (pipefd[1]);
- close (pipefd_togrep[1]);
+ close (grep_pipefd[1]);
return EX_IOERR;
}
}
if (opts.kill_sig > 0) kill (cpid, opts.kill_sig);
close (pipefd[0]);
close (pipefd[1]);
- close (pipefd_togrep[1]);
+ close (grep_pipefd[1]);
//TODO: kill grep?
return EX_UNAVAILABLE;
}