uint8_t parse_arguments(int argc, const char *argv[]) { uint8_t use_hashes = 0; int i; if (argc < 2) { usage_quit(argv[0]); } for (i = 1; i < argc; i++) { if ((strcmp(argv[i], "-h") == 0) || strcmp(argv[i], "--help") == 0) { usage_quit(argv[0]); } else if (strcmp(argv[i], "fnv") == 0) { use_hashes |= FNV; } else if (strcmp(argv[i], "jenkins") == 0) { use_hashes |= JENKINS; } else if (strcmp(argv[i], "murmur64") == 0) { use_hashes |= MURMUR64; } else if (strcmp(argv[i], "bernstein") == 0) { use_hashes |= BERNSTEIN; } else if (strcmp(argv[i], "elf") == 0) { use_hashes |= ELF; } else { usage_quit(argv[0]); } } return use_hashes; }
/** * Read the config file, determine if we should daemonize or not, * and set up libevent dispatches. */ int main(int argc, char *argv[]) { int cmdline_debug_level = 0; int foreground = 0; int option; pid_t pid; int kill=0; int ret; /* set some sane config defaults */ memset((void*)&config, 0, sizeof(gopher_conf_t)); config.port = 70; config.base_dir = "."; config.socket_backlog = 5; config.config_file = DEFAULT_CONFIGFILE; while((option = getopt(argc, argv, "d:c:fp:s:k")) != -1) { switch(option) { case 'd': cmdline_debug_level = atoi(optarg); if(cmdline_debug_level < 1 || cmdline_debug_level > 5) { ERROR("Debug level must be 1-5 (default %d)", DEFAULT_DEBUGLEVEL); usage_quit(argv[0]); } break; case 'c': config.config_file = optarg; break; case 'f': foreground = 1; break; case 'p': config.port = atoi(optarg); break; case 's': config.base_dir = optarg; case 'k': kill = 1; break; default: usage_quit(argv[0]); } } debug_level(cmdline_debug_level ? cmdline_debug_level : DEFAULT_DEBUGLEVEL); /* kill before config, so we don't have to specify a config file */ daemon_pid_file_ident = daemon_ident_from_argv0(argv[0]); /* kill? */ if(kill) { if((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0) { ERROR("Failed to kill daemon: %s", strerror(errno)); } exit(ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS); } if((pid = daemon_pid_file_is_running()) >= 0) { ERROR("Daemon already running as pid %u", pid); exit(EXIT_FAILURE); } /* TODO: read the config file and verify sufficient config */ debug_level(cmdline_debug_level); /* daemonize, or check for background daemon */ if(!foreground) { debug_output(DBG_OUTPUT_SYSLOG, "evgopherd"); if(daemon_retval_init() < 0) { ERROR("Could not set up daemon pipe"); exit(EXIT_FAILURE); } if((pid = daemon_fork()) < 0) { daemon_retval_done(); ERROR("Forking error: %s", strerror(errno)); exit(EXIT_FAILURE); } else if (pid) { /* parent */ if((ret = daemon_retval_wait(5)) < 0) { ERROR("Could not receive startup retval from daemon process: %s", strerror(errno)); exit(EXIT_FAILURE); } if(ret > 0) ERROR("Daemon declined to start. Error: %d\n", ret); exit(ret == 0 ? EXIT_SUCCESS :EXIT_FAILURE); } } if(daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGPIPE, 0) < 0) { ERROR("Could not set up signal handlers: %s", strerror(errno)); goto finish; } if(!foreground) { if(daemon_pid_file_create() < 0) { ERROR("Could not create pidfile: %s", strerror(errno)); if(!foreground) daemon_retval_send(2); goto finish; } /* should close handles here */ daemon_retval_send(0); /* started up to the point that we can rely on syslog */ } WARN("Daemon started"); /* need to fork off a watchdog process */ while(!g_quitflag) { /* fork and wait */ pid_t pid = fork(); if(pid == -1) { ERROR("Error forking child process. Aborting"); g_quitflag = 1; } else if(pid == 0) { /* child */ do_child_process(); } else { /* parent */ int status; waitpid(pid, &status, 0); if(WIFEXITED(status) && WEXITSTATUS(status)) { /* exited with error */ ERROR("Error initializing child process. Aborting"); g_quitflag=1; } else if(!WIFEXITED(status)) { ERROR("Child process (%d) crashed. Restarting.", pid); } else { /* graceful exit... we've obviously terminated */ g_quitflag = 1; } } } WARN("Daemon exiting gracefully"); finish: daemon_signal_done(); daemon_pid_file_remove(); return EXIT_SUCCESS; }