+
+ pid_t child_pid = fork();
+ switch (child_pid) {
+ case 0: {
+ // Child.
+ close(pipefd[0]);
+ in_forked_child = true;
+ uint64_t matched = do_search_file(needles, filename);
+ int ret;
+ do {
+ ret = write(pipefd[1], &matched, sizeof(matched));
+ } while (ret == -1 && errno == EINTR);
+ if (ret != sizeof(matched)) {
+ perror("write");
+ _exit(EXIT_FAILURE);
+ }
+ fflush(stdout);
+ _exit(EXIT_SUCCESS);
+ }
+ case -1:
+ // Error.
+ perror("fork");
+ exit(EXIT_FAILURE);
+ default:
+ // Parent.
+ close(pipefd[1]);
+ break;
+ }
+
+ // Wait for the child to finish.
+ int wstatus;
+ pid_t err;
+ do {
+ err = waitpid(child_pid, &wstatus, 0);
+ } while (err == -1 && errno == EINTR);
+ if (err == -1) {
+ perror("waitpid");
+ exit(EXIT_FAILURE);
+ }
+ if (WIFEXITED(wstatus)) {
+ if (WEXITSTATUS(wstatus) != 0) {
+ // The child has probably already printed out its error, so just propagate the exit status.
+ exit(WEXITSTATUS(wstatus));
+ }
+ // Success!
+ } else if (!WIFEXITED(wstatus)) {
+ fprintf(stderr, "FATAL: Child died unexpectedly while processing %s\n", filename.c_str());
+ exit(1);
+ }
+
+ // Now get the number of matches from the child.
+ uint64_t matched;
+ int ret;
+ do {
+ ret = read(pipefd[0], &matched, sizeof(matched));
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1) {
+ perror("read");
+ exit(EXIT_FAILURE);
+ } else if (ret != sizeof(matched)) {
+ fprintf(stderr, "FATAL: Short read through pipe (got %d bytes)\n", ret);
+ exit(EXIT_FAILURE);
+ }
+ close(pipefd[0]);
+ return matched;
+}
+
+// Parses a colon-separated list of strings and appends them onto the given vector.
+// Backslash escapes whatever comes after it.
+void parse_dbpaths(const char *ptr, vector<string> *output)
+{
+ string str;
+ while (*ptr != '\0') {
+ if (*ptr == '\\') {
+ if (ptr[1] == '\0') {
+ fprintf(stderr, "ERROR: Escape character at the end of string\n");
+ exit(EXIT_FAILURE);
+ }
+ // Escape.
+ str.push_back(ptr[1]);
+ ptr += 2;
+ continue;
+ }
+ if (*ptr == ':') {
+ // Separator.
+ output->push_back(move(str));
+ ++ptr;
+ continue;
+ }
+ str.push_back(*ptr++);
+ }
+ output->push_back(move(str));