/*
** CONF: Configuration option / file handling module
** Copyright (C) 2002 Michael W. Shaffer <mwshaffer@angrypot.com>
**
** 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program (see the file COPYING). If not, write to:
**
** The Free Software Foundation, Inc.
** 59 Temple Place, Suite 330,
** Boston, MA 02111-1307 USA
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "getopt.h"
#include "list.h"
#include "hash.h"
#include "config_file.h"
#include "ssync.h"
#include "conf.h"
extern char *conf_path_default;
static struct hash_table conf;
char * get_config_string (char *key)
{
struct datum d;
struct datum *dd;
if (!key)
return NULL;
memset (&d, 0, sizeof (struct datum));
d.key = key;
d.ksize = strlen (key);
dd = hash_table_search (&conf, &d);
if (!dd)
return NULL;
return (dd->val);
}
long get_config_long (char *key)
{
long lval = 0;
char *val = NULL;
val = get_config_string (key);
if (!val)
return (0);
if ((strlen (val) > 2) && (val[0] == '0') && (val[1] == 'x')) {
lval = (int) strtoul (val, NULL, 16);
} else {
lval = (int) strtoul (val, NULL, 10);
}
return lval;
}
double get_config_double (char *key)
{
char *val = NULL;
val = get_config_string (key);
if (!val)
return ((double) 0);
return strtod (val, NULL);
}
void config_write (int fd)
{
int i = 0;
struct datum *d = NULL;
struct list_item *curr = NULL;
char msg[256];
for (i = 0 ; i < conf.size ; i++) {
for (curr = conf.tbl[i].head ; curr ; curr = curr->next) {
d = (struct datum *) curr->data;
if (d) {
memset (msg, 0, sizeof (msg));
snprintf (msg, (sizeof (msg) - 1),
"%s: %s\n",
(char *) d->key,
(char *) d->val);
write (fd, msg, strlen (msg));
}
}
}
return;
}
enum options {
o_help = 0,
o_interval,
o_work_file,
o_src_path,
o_dst_path,
o_priority,
o_no_detach,
o_no_sync_data,
o_no_sync_time,
o_no_sync_meta,
o_update_only,
o_test,
o_pid_path,
o_log_mode,
o_log_path,
o_log_ident,
o_log_level,
o_conf_path
};
static struct option long_options[] = {
{ "help", 0, 0, 'h' },
{ "interval", 1, 0, 'i' },
{ "work-file", 1, 0, 'w' },
{ "src-path", 1, 0, 'f' },
{ "dst-path", 1, 0, 't' },
{ "priority", 1, 0, 'n' },
{ "no-detach", 0, 0, 'F' },
{ "no-sync-data", 0, 0, 'D' },
{ "no-sync-time", 0, 0, 'T' },
{ "no-sync-meta", 0, 0, 'M' },
{ "update-only", 0, 0, 'U' },
{ "test", 0, 0, 'X' },
{ "pid-path", 1, 0, 'p' },
{ "log-mode", 1, 0, 'm' },
{ "log-path", 1, 0, 'l' },
{ "log-ident", 1, 0, 's' },
{ "log-level", 1, 0, 'v' },
{ "conf-path", 1, 0, 'c' },
{ 0, 0, 0, 0 }
};
static void parse_command_line (int argc, char **argv, struct hash_table *conf)
{
int c = '\0';
int optind = 0;
struct datum d;
if (!((argc > 0) && argv && conf))
return;
opterr = 0;
memset (&d, 0, sizeof (struct datum));
d.key = "conf-path";
d.ksize = strlen ("conf-path");
d.val = conf_path_default;
d.vsize = strlen (conf_path_default);
hash_table_insert (conf, &d);
while (1) {
memset (&d, 0, sizeof (struct datum));
c = getopt_long (argc, argv, "hi:w:f:t:n:FDTMUXp:m:l:s:v:c:",
long_options, &optind);
if (c == -1)
goto EXIT;
switch (c) {
case 'h':
print_usage (argv[0], 2);
exit (0);
break;
case 'i':
d.key = (char *) long_options[o_interval].name;
d.ksize = strlen (long_options[o_interval].name);
d.val = optarg;
break;
case 'w':
d.key = (char *) long_options[o_work_file].name;
d.ksize = strlen (long_options[o_work_file].name);
d.val = optarg;
break;
case 'f':
d.key = (char *) long_options[o_src_path].name;
d.ksize = strlen (long_options[o_src_path].name);
d.val = optarg;
break;
case 't':
d.key = (char *) long_options[o_dst_path].name;
d.ksize = strlen (long_options[o_dst_path].name);
d.val = optarg;
break;
case 'n':
d.key = (char *) long_options[o_priority].name;
d.ksize = strlen (long_options[o_priority].name);
d.val = optarg;
break;
case 'F':
d.key = (char *) long_options[o_no_detach].name;
d.ksize = strlen (long_options[o_no_detach].name);
d.val = "yes";
break;
case 'D':
d.key = (char *) long_options[o_no_sync_data].name;
d.ksize = strlen (long_options[o_no_sync_data].name);
d.val = "yes";
break;
case 'T':
d.key = (char *) long_options[o_no_sync_time].name;
d.ksize = strlen (long_options[o_no_sync_time].name);
d.val = "yes";
break;
case 'M':
d.key = (char *) long_options[o_no_sync_meta].name;
d.ksize = strlen (long_options[o_no_sync_meta].name);
d.val = "yes";
break;
case 'U':
d.key = (char *) long_options[o_update_only].name;
d.ksize = strlen (long_options[o_update_only].name);
d.val = "yes";
break;
case 'X':
d.key = (char *) long_options[o_test].name;
d.ksize = strlen (long_options[o_test].name);
d.val = "yes";
break;
case 'p':
d.key = (char *) long_options[o_pid_path].name;
d.ksize = strlen (long_options[o_pid_path].name);
d.val = optarg;
break;
case 'm':
d.key = (char *) long_options[o_log_mode].name;
d.ksize = strlen (long_options[o_log_mode].name);
d.val = optarg;
break;
case 'l':
d.key = (char *) long_options[o_log_path].name;
d.ksize = strlen (long_options[o_log_path].name);
d.val = optarg;
break;
case 's':
d.key = (char *) long_options[o_log_ident].name;
d.ksize = strlen (long_options[o_log_ident].name);
d.val = optarg;
break;
case 'v':
d.key = (char *) long_options[o_log_level].name;
d.ksize = strlen (long_options[o_log_level].name);
d.val = optarg;
break;
case 'c':
d.key = (char *) long_options[o_conf_path].name;
d.ksize = strlen (long_options[o_conf_path].name);
d.val = optarg;
break;
default:
print_usage (argv[0], 2);
exit (0);
break;
}
if (d.key && d.ksize > 0) {
d.vsize = strlen (d.val);
hash_table_insert (conf, &d);
}
}
EXIT:
return;
}
void config_load (int argc, char **argv)
{
memset (&conf, 0, sizeof (struct hash_table));
conf.size = 32;
hash_table_init (&conf);
parse_command_line (argc, argv, &conf);
parse_config_file (get_config_string ("conf-path"), &conf);
return;
}
void config_free (void)
{
hash_table_free (&conf);
return;
}
void print_usage (char *name, int fd)
{
char msg[4096];
if (!name || (fd < 0))
goto EXIT;
memset (msg, 0, sizeof (msg));
snprintf (msg, (sizeof (msg) - 1),
" \n"
" ssync version %s \n"
" \n"
" Usage: \n"
" \n"
" %s [OPTIONS] \n"
" \n"
" Option Argument Comment \n"
" ----------------------------------------------------------------------\n"
" -h | --help display this message \n"
" -c | --conf-path PATH alternative config file \n"
" -i | --interval NUM seconds between runs \n"
" -w | --work-file PATH file containing work list\n"
" -f | --src-path PATH source path \n"
" -t | --dst-path PATH destination path \n"
" -n | --priority (-20 - +20) scheduling priority \n"
" -F | --no-detach no detach from terminal \n"
" -D | --no-sync-data no sync data in files \n"
" -T | --no-sync-time no sync atime / mtime \n"
" -M | --no-sync-meta no sync uid / gid / mode \n"
" -U | --update-only only if source is newer \n"
" -X | --test don't modify anything \n"
" -p | --pid-path PATH path for pid file \n"
" -m | --log-mode (file|syslog|stderr) path for log file \n"
" -l | --log-path PATH path for log file \n"
" -s | --log-ident STRING ident string for syslog \n"
" -v | --log-level (0 - 5) verboseness \n"
" \n",
SSYNC_VERSION, name);
write (fd, msg, strlen (msg));
EXIT:
return;
}
syntax highlighted by Code2HTML, v. 0.9.1