/* * This program 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. * * This program 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 Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "daemon.h" #include "opendd.h" #include "globals.h" #include "./include/config_option.h" #include "./include/socket.h" #include "./include/util.h" void usage(const char *pgm) { /* ----------------------------------------------------------------------------- * Print usage and exit * * @param const char *, program name * -------------------------------------------------------------------------- */ printf("usage : %s [-c ] [-v] [-h]\n", pgm); printf(" -c : Define a config file path other than %s\n", CONFIG_FILE); printf(" -v : Verbose -> do not log to syslog, print to the stderr instead\n"); printf(" -h : Print this and exit\n"); exit(0); } /* MAIN PROGRAM */ int main(int argc, char **argv) { extern char *optarg; int opt, read_config = 0; char *config_file = NULL; char *current_dir = NULL; char *ip = NULL; int do_update = 0, force_update = 0; struct chain_string *hostnames = NULL; int day_lifetime = 0, second_lifetime = 0, tmp_val = 0; const char *ident = (const char *)basename(argv[0]); current_dir = get_currentdir(); #ifdef USE_SOCKET_SSL SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); #endif /* We check the runtime parameters */ while((opt = getopt(argc, argv, "c:vh")) != -1) { switch (opt) { case 'c': if (optarg[0] != '/') /* This is a relative path file */ asprintf(&config_file, "%s/%s", current_dir, optarg); else /* This is an absolute path file */ config_file = strdup(optarg); if (config_file == NULL) { fprintf(stderr, "%s : %s\n", ident, strerror(errno)); return -1; } break; case 'v': set_verbose_mode(1); break; case 'h': usage(ident); break; } } FREE(current_dir); if (config_file != NULL) { if (!check_config_file_mode(config_file)) /* If the file is not only owner readable, exit */ return -1; else if (parse_config_file(config_file)) { set_config_file(config_file); read_config = 1; } else if (errno != 0) { logmsg(LOG_ERR, "main() : cannot parse config file %s : %s", config_file, strerror(errno)); FREE(config_file); return -1; } } else { if (!check_config_file_mode(CONFIG_FILE)) /* If the file is not only owner readable, exit */ return -1; else if (parse_config_file(CONFIG_FILE)) read_config = 1; else if (errno != 0) { logmsg(LOG_ERR, "main() : cannot parse config file %s : %s", CONFIG_FILE, strerror(errno)); return -1; } } if (!read_config) { logmsg(LOG_ERR, "main() : cannot find a config file in %s", CONFIG_FILE); return -2; } /* A config file has been read */ if (!runasdaemon()) { if (use_syslog()) { /* Open syslog */ openlog(ident, LOG_PID, syslog_facility()); set_syslog_mode(1); } logmsg(LOG_INFO, "-- running OpenDD %s in normal mode", VERSION); /* Drop privileges (if possible) */ if (drop_privileges() == -1) return -1; /* Now get the IP address */ if (getifaceaddr(&ip)) { /* Do a dyndns update */ logmsg(LOG_INFO, "main() : getting my ip address : %s", ip); /* We must get the hostnames to be updated */ switch (getdyndnshostnames(ip, &hostnames, 0)) { case 0: case -1: logmsg(LOG_ERR, "main() : No hostname(s) to update"); break; default: /* Some hostnames must be updated */ tmp_val = dyndns(ip, hostnames); if (tmp_val) { if (tmp_val == EXIT_DYNDNS_FAILED) { /* DynDNS update failure */ logmsg(LOG_ERR, "main() : a dyndns() update error occurred. " "You should read the error message in mail report or syslog report"); } logmsg(LOG_INFO, "main() : dyndns() exit normally"); FREE(ip); drop_all_chain_string(hostnames); return 0; } drop_all_chain_string(hostnames); hostnames = NULL; FREE(ip); logmsg(LOG_ERR, "main() : dyndns() exit abnormally"); break; } } else logmsg(LOG_ERR, "main() : cannot get IP address for update"); if (ip != NULL) FREE(ip); } else { if (get_verbose_mode()) { logmsg(LOG_ERR, "main() : cannot run as daemon on verbose mode"); } else { /* Try to create the lock file */ switch (open_lock_pidfile()) { case -1: /* lock error : another opendd process is probably already running */ fprintf(stderr, "%s : an opendd daemon is already running\n", ident); return -1; break; case 0: /* any errors */ return -1; break; } close_lock_pidfile(); /* Run as daemon */ if (!setdaemon()) { /* Parent processus must exit * => return to the shell */ return 0; } /* Reopen syslog */ openlog(ident, LOG_PID, syslog_facility()); set_syslog_mode(1); /* Here, we are on the child process */ logmsg(LOG_INFO, "-- running OpenDD %s as daemon", VERSION); /* * Try to recreate the lock file. * We have to recreate the lock, because locks are not inherited after * a fork() done in setdaemon() */ switch (open_lock_pidfile()) { case -1: /* lock error : another opendd process is probably already running * We SHOULD not be here, as the test was successfully passed, above */ logmsg(LOG_ERR, "main() : an opendd daemon is already running"); return -1; break; case 0: /* any errors */ return -1; break; } /* Write the pid number in the lock file */ write_pid_lock_pidfile(); /* Drop privileges (if possible) */ if (drop_privileges() == -1) return -1; /* Here comes the infinite loop */ for(;;) { if (get_my_ip() == NULL) { /* This is the first time */ if (getifaceaddr(&ip)) { if (strcmp(ip, "0.0.0.0") == 0) { /* Ignore IP 0.0.0.0 * Do nothing */ } else do_update = 1; } } else { if (getifaceaddr(&ip)) { if (strcmp(ip, "0.0.0.0") == 0) { /* Ignore IP 0.0.0.0 * Do nothing */ } else if (strcmp(get_my_ip(), ip) != 0) { /* IP has changed */ do_update = 1; } else { if (day_lifetime >= get_domain_lifetime()) { set_force_update_status(1); logmsg(LOG_INFO, "main() : dyndns update must be done by force " "after %d days with no change", get_domain_lifetime()); } } } } /* Get force update status * It can be update by SIGUSR1 signal or limit reached lifetime */ force_update = get_force_update_status(); if (force_update) do_update = 1; if ((do_update) && (is_service_online())) { /* An Update must be done */ /* We must get the hostnames to be updated */ switch (getdyndnshostnames(ip, &hostnames, force_update)) { case -1: /* Errors ... do nothing */ FREE(ip); break; case 0: /* No need to update */ set_my_ip(ip); /* We copy the new IP address in cache */ break; default: /* Some hostnames must be updated */ if (force_update) { logmsg(LOG_INFO, "main() : dyndns update by force is processing ..."); } tmp_val = dyndns(ip, hostnames); if (tmp_val) { if (tmp_val == EXIT_DYNDNS_FAILED) { /* DynDNS update failure */ logmsg(LOG_ERR, "main() : a dyndns() update error occurred. " "You should read the error message in mail report or syslog report"); logmsg(LOG_ERR, "main() : OpenDD will stop processing updates " "until you solved the problem."); logmsg(LOG_ERR, "main() : Send a SIGHUP signal to restore the update process."); /* Set the OpenDD service offline */ set_service_online(0); } else { /* DynDNS successful * so we must keep the valid IP address */ set_my_ip(ip); /* We copy the new IP address in cache */ } logmsg(LOG_INFO, "main() : dyndns() exit normally"); } else { if (ip != NULL) FREE(ip); logmsg(LOG_ERR, "main() : dyndns() exit abnormally"); } drop_all_chain_string(hostnames); hostnames = NULL; /* Reinitialize the lifetime */ set_second_lifetime(0); update_proc_title(); break; } } else if (ip != NULL) FREE(ip); do_update = 0; set_force_update_status(0); tmp_val = getpollfrequency(); /* Sleep in second */ my_sleep(tmp_val); /* Increment the domain lifetime in second */ second_lifetime = get_second_lifetime(); second_lifetime += tmp_val; set_second_lifetime(second_lifetime); /* And get the lifetime in day */ day_lifetime = second_lifetime / (60 * 60 * 24); update_proc_title(); } /* Loop */ } } set_config_file(NULL); set_ssl_pathstore(NULL); if (get_syslog_mode()) closelog(); return 0; }