/* This file is part of Kismet Kismet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kismet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include "config.h" /* Blob of globals since sighandler needs them */ vector postcli_err; pid_t srvpid = -1, clipid = -1; int rpipe[2], epipe[2], max_fd; fd_set rset; FILE *out, *err; struct timeval tim; int check_err = 0, check_out = 0; char ret[2048]; int reap_pending = 0; /* Sighandler/Reaper */ void reap(int sig) { check_err = 1; check_out = 1; reap_pending++; if (clipid > 0) { kill(clipid, SIGTERM); if (reap_pending <= 1) wait4(clipid, NULL, 0, NULL); } if (srvpid > 0) { kill(srvpid, SIGTERM); } while (1) { FD_ZERO(&rset); if (check_out == 0 && check_err == 0) break; if (check_out) FD_SET(rpipe[0], &rset); if (check_err) FD_SET(epipe[0], &rset); tim.tv_sec = 0; tim.tv_usec = 500000; if (select(max_fd + 1, &rset, NULL, NULL, &tim) < 0) { fprintf(stderr, "Select failed: %s\n", strerror(errno)); break; } if (FD_ISSET(epipe[0], &rset)) { if (fgets(ret, 2048, err) == NULL || feof(err)) { if (feof(out)) break; fclose(err); close(epipe[0]); check_err = 0; continue; } if (clipid == -1) { fprintf(stderr, "%s", ret); } else { postcli_err.push_back(ret); } } if (FD_ISSET(rpipe[0], &rset)) { if (fgets(ret, 2048, out) == NULL || feof(out)) { if (feof(err)) break; fclose(out); close(rpipe[0]); check_out = 0; continue; } fprintf(stdout, "%s", ret); } } for (unsigned int x = 0; x < postcli_err.size(); x++) { fprintf(stderr, "%s", postcli_err[x].c_str()); } if (reap_pending <= 1) wait4(srvpid, NULL, 0, NULL); printf("Done.\n"); } int main(int argc, char *argv[], char *envp[]) { vector server_opt, cli_opt; char **eargv; int optmode = 0; for (int x = 1; x < argc; x++) { if (strcmp(argv[x], "-h") == 0 || strcmp(argv[x], "--help") == 0) { printf("Kismet wrapper script\n\n" "Usage:\n" " kismet (server options) -- (client options)\n" "\n" "For server and client specific options, use:\n" " kismet_server --help\n" " kismet_client --help\n"); exit(0); } if (strcmp(argv[x], "--") == 0) { optmode = 1; continue; } if (optmode == 0) { server_opt.push_back(string(argv[x])); } else { cli_opt.push_back(string(argv[x])); } } if (pipe(rpipe) != 0 || pipe(epipe) != 0) { fprintf(stderr, "Error creating pipe: %s\n", strerror(errno)); exit(5); } fcntl(rpipe[1], F_SETFD, fcntl(rpipe[1], F_GETFD) & ~1); fcntl(epipe[1], F_SETFD, fcntl(epipe[1], F_GETFD) & ~1); if ((srvpid = fork()) < 0) { fprintf(stderr, "Error forking: %s\n", strerror(errno)); exit(5); } else if (srvpid == 0) { /* eargv bumped by 2 to make room for the --silent and argv[0] */ eargv = (char **) malloc(sizeof(char *) * (server_opt.size() + 3)); for (unsigned int x = 0; x < server_opt.size(); x++) { eargv[x + 2] = strdup(server_opt[x].c_str()); } snprintf(ret, 2048, "%s/%s", BIN_LOC, "kismet_server"); eargv[0] = strdup(ret); eargv[1] = strdup("--silent"); eargv[server_opt.size() + 2] = NULL; printf("Launching kismet_server: %s\n", eargv[0]); fflush(stdout); /* Dup over stdout/stderr so we can hijack the output */ close(STDOUT_FILENO); close(STDERR_FILENO); dup2(rpipe[1], STDOUT_FILENO); dup2(epipe[1], STDERR_FILENO); /* We don't need these anymore */ close(rpipe[0]); close(rpipe[1]); close(epipe[0]); close(epipe[1]); execv(eargv[0], eargv); fprintf(stderr, "Failed to launch %s: %s\n", eargv[0], strerror(errno)); exit(255); } signal(SIGINT, &reap); signal(SIGTERM, &reap); signal(SIGQUIT, &reap); signal(SIGHUP, &reap); close(rpipe[1]); close(epipe[1]); out = fdopen(rpipe[0], "r"); err = fdopen(epipe[0], "r"); max_fd = 0; if (rpipe[0] > max_fd) max_fd = rpipe[0]; if (epipe[0] > max_fd) max_fd = epipe[0]; while (1) { FD_ZERO(&rset); FD_SET(rpipe[0], &rset); FD_SET(epipe[0], &rset); tim.tv_sec = 0; tim.tv_usec = 500000; if (clipid > -1 && wait4(clipid, NULL, WNOHANG, NULL) < 0) { break; } if (clipid == -1 && wait4(srvpid, NULL, WNOHANG, NULL) < 0) { break; } int sel; if ((sel = select(max_fd + 1, &rset, NULL, NULL, &tim)) < 0) { fprintf(stderr, "Select failed: %s\n", strerror(errno)); break; } if (FD_ISSET(epipe[0], &rset)) { if (fgets(ret, 2048, err) == NULL || feof(err)) { break; } /* Capture stderr if the client is running */ if (clipid == -1) { fprintf(stderr, "%s", ret); } else { postcli_err.push_back(ret); } continue; } if (clipid >= 0 && check_err == 0) check_err = 1; if (FD_ISSET(rpipe[0], &rset)) { if (fgets(ret, 2048, out) == NULL || feof(out)) { break; } /* Squelch stdout if we're running the client */ if (clipid == -1) { fprintf(stdout, "%s", ret); } /* Kismet actually launched */ if (strstr(ret, "Gathering packets...") != NULL && clipid == -1) { sleep(1); if ((clipid = fork()) < 0) { fprintf(stderr, "Failed to fork for client: %s\n", strerror(errno)); break; } else if (clipid == 0) { close(rpipe[0]); close(epipe[0]); eargv = (char **) malloc(sizeof(char *) * (server_opt.size() + 2)); for (unsigned int x = 0; x < cli_opt.size(); x++) { eargv[x + 2] = strdup(cli_opt[x].c_str()); } snprintf(ret, 2048, "%s/%s", BIN_LOC, "kismet_client"); eargv[0] = strdup(ret); eargv[server_opt.size() + 1] = NULL; printf("Launching kismet_client: %s\n", eargv[0]); execv(eargv[0], eargv); fprintf(stderr, "Failed to launch kismet_client\n"); exit(255); } fprintf(stderr, "Launched client, pid %d\n", clipid); } } } wait4(clipid, NULL, 0, NULL); reap(0); }