/*
* 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 <unistd.h>
#include <libgen.h>
#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 <configfile>] [-v] [-h]\n", pgm);
printf(" -c <configfile> : 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;
}
syntax highlighted by Code2HTML, v. 0.9.1