]>
git.gir.st - forkaftergrep.git/blob - fag.c
80f5c2a1b11e209fc463356843b3aacc7f55ea1e
1 /* forkaftergrep (C) 2017 Tobias Girstmair, GPLv3 */
2 //TODO: supply user arguments to grep
3 //demo: ./fag -e -V "MPD server running at" mopidy
5 #define _XOPEN_SOURCE 500
6 #define _DEFAULT_SOURCE
18 struct opt opts
= {0, 0, 0, NULL
, NULL
, STDOUT_FILENO
};
20 int main (int argc
, char** argv
) {
24 /* the `+' forces getopt to stop at the first non-option */
25 while ((opt
= getopt (argc
, argv
, "+t:k::eVhv")) != -1) {
28 opts
.timeout
= atoi (optarg
);
31 opts
.kill_sig
= optarg
? atoi (optarg
) : SIGTERM
;
34 opts
.stream
= STDERR_FILENO
;
40 fprintf (stderr
, VERTEXT USAGE
42 "\t-t N\ttimeout after N seconds\n"
43 "\t-k [M]\tsend signal M to child after timeout (default: 15/SIGTERM)\n"
44 "\t-e\tgrep on stderr instead of stdout\n"
45 "\t-V\tbe verbose; print PROGRAM's stdout/stderr to stderr\n", argv
[0]);
48 fprintf (stderr
, VERTEXT
);
51 fprintf (stderr
, "Unrecognized option: %c\n" USAGE
, optopt
, argv
[0]);
56 /* the first non-option argument is the search string */
58 opts
.pattern
= argv
[optind
++];
60 fprintf (stderr
, USAGE
"(Missing PATTERN)\n", argv
[0]);
64 /* the remaining are the program to be run */
66 opts
.argv
= &(argv
[optind
]);
68 fprintf (stderr
, USAGE
"(Missing PROGRAM)\n", argv
[0]);
72 int retval
= fork_after_grep (opts
);
77 int fork_after_grep (struct opt opts
) {
85 struct timeval begin
, now
, diff
;
87 if (pipe(pipefd
) == -1) {
88 fprintf (stderr
, "pipe error (userprog)\n");
92 if ((cpid
= fork()) == -1) {
93 fprintf (stderr
, "fork error (userprog): %s", strerror (errno
));
101 dup2 (pipefd
[1], opts
.stream
);
103 close (opts
.stream
==STDOUT_FILENO
?STDERR_FILENO
:STDOUT_FILENO
);
105 if (setsid () == -1) {
106 fprintf (stderr
, "setsid error (userprog): %s", strerror (errno
));
110 execvp (opts
.argv
[0], opts
.argv
);
111 fprintf (stderr
, "exec error (userprog): %s", strerror (errno
));
112 _exit (EX_UNAVAILABLE
);
115 int pipefd_togrep
[2];
117 /* `-q': don't print anything; exit with 0 on match; with 1 on error */
118 char* grepargv
[] = {"grep", "-q", opts
.pattern
, NULL
};
121 fcntl (pipefd
[0], F_SETFL
, fcntl (pipefd
[0], F_GETFL
, 0) | O_NONBLOCK
);
123 gettimeofday (&begin
, NULL
); /* for timeout */
125 if (pipe(pipefd_togrep
) == -1) {
126 fprintf (stderr
, "pipe error (grep)\n");
132 if ((grep_cpid
= fork()) == -1) {
133 fprintf (stderr
, "fork error (grep): %s", strerror (errno
));
136 close (pipefd_togrep
[0]);
137 close (pipefd_togrep
[1]);
141 if (grep_cpid
== 0) {
142 close (pipefd_togrep
[1]);
143 dup2 (pipefd_togrep
[0], STDIN_FILENO
);
144 close (pipefd_togrep
[0]);
146 close (STDERR_FILENO
);
147 close (STDOUT_FILENO
);
149 execvp (grepargv
[0], grepargv
);
150 fprintf (stderr
, "exec error (grep): %s", strerror (errno
));
151 _exit (EX_UNAVAILABLE
);
153 close (pipefd_togrep
[0]);
156 memset (buf
, 0, BUF_SIZE
); /* necessary for opts.verbose */
157 nbytes
= read (pipefd
[0], buf
, BUF_SIZE
);
163 fprintf (stderr
, "read error (userprog): %s", strerror (errno
));
166 close (pipefd_togrep
[1]);
170 } else if (nbytes
== 0) {
171 fprintf (stderr
, "Child program exited prematurely (userprog).\n");
174 close (pipefd_togrep
[1]);
176 if (waitpid (cpid
, &status
, WNOHANG
) > 0 && WIFEXITED (status
)) {
177 return WEXITSTATUS (status
);
179 return EX_UNAVAILABLE
;
181 /* have new userprog-data, send it to grep */
186 write(pipefd_togrep
[1], buf
, strlen(buf
));
189 if (waitpid (grep_cpid
, &grep_status
, WNOHANG
) > 0 && WIFEXITED (grep_status
)) {
190 close (pipefd_togrep
[1]);
192 if (WEXITSTATUS(grep_status
) == 0) {
193 /* grep exited with match found */
194 printf ("%d\n", cpid
);
196 /* create a new child to keep pipe alive (will exit with exec'd program) */
198 while (kill(cpid
, 0) != -1 && errno
!= ESRCH
) sleep (1);
207 /* grep exited due to an error */
208 fprintf (stderr
, "grep exited due to an error.");
211 close (pipefd_togrep
[1]);
216 if (opts
.timeout
> 0) {
217 gettimeofday (&now
, NULL
);
218 timersub (&now
, &begin
, &diff
);
219 if (diff
.tv_sec
>= opts
.timeout
) {
220 fprintf (stderr
, "Timeout reached. \n");
221 if (opts
.kill_sig
> 0) kill (cpid
, opts
.kill_sig
);
224 close (pipefd_togrep
[1]);
226 return EX_UNAVAILABLE
;