diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-19 13:30:35 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-19 13:30:35 +0000 |
commit | 32d5cff1b7c2266779b63fb97eb6b91cab34e7ad (patch) | |
tree | a6334d3ceff71716e9e1399fb376963782a5404b | |
parent | 106472e9039e46a5468ed15f118a2cf7d74f6ec8 (diff) | |
download | wydawca-32d5cff1b7c2266779b63fb97eb6b91cab34e7ad.tar.gz wydawca-32d5cff1b7c2266779b63fb97eb6b91cab34e7ad.tar.bz2 |
New module: wydawca
git-svn-id: file:///svnroot/wydawca/trunk@279 6bb4bd81-ecc2-4fd4-a2d4-9571d19c0d33
-rw-r--r-- | src/Makefile.am | 16 | ||||
-rw-r--r-- | src/config.c | 357 | ||||
-rw-r--r-- | src/gpg.c | 188 | ||||
-rw-r--r-- | src/method.c | 115 | ||||
-rw-r--r-- | src/process.c | 179 | ||||
-rw-r--r-- | src/register.c | 152 | ||||
-rw-r--r-- | src/sql.c | 150 | ||||
-rw-r--r-- | src/sql.h | 38 | ||||
-rw-r--r-- | src/triplet.c | 156 | ||||
-rw-r--r-- | src/verify.c | 188 | ||||
-rw-r--r-- | src/wydawca.c | 153 | ||||
-rw-r--r-- | src/wydawca.h | 123 | ||||
-rw-r--r-- | src/wydawca.rc | 22 |
13 files changed, 1837 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..7d8c00e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,16 @@ +sbin_PROGRAMS=@MODULE_WYDAWCA@ +EXTRA_PROGRAMS=wydawca +wydawca_SOURCES=\ + config.c\ + gpg.c\ + method.c\ + process.c\ + sql.c\ + sql.h\ + triplet.c\ + verify.c\ + wydawca.c\ + wydawca.h +LDADD=../lib/libgsc.a ../gnu/libgnu.a @SQLLIB@ @GPGMELIB@ +INCLUDES = -I../lib -I../gnu +AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\"
\ No newline at end of file diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..31ff99c --- /dev/null +++ b/src/config.c @@ -0,0 +1,357 @@ +/* wydawca - FTP release synchronisation daemon + Copyright (C) 2007 Sergey Poznyakoff + + 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 3 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. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" +#include "sql.h" + +/* Configuration file handling (application-specific) */ + +static struct access_method default_verify_method; +static struct access_method default_gpg_key_method; + +static void +cfg_syslog_tag (gsc_config_file_t *file, char *kw, char *val, void *unused) +{ + syslog_tag = strdup (val); +} + +static void +cfg_syslog_facility (gsc_config_file_t *file, char *kw, char *val, + void *unused) +{ + if (gsc_str_to_syslog_facility (val, &log_facility)) + file->error_msg (file->file_name, file->line, "Unknown facility `%s'", + val); +} + +static void +cfg_source (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct directory_pair *dp = data; + dp->source_dir = xstrdup (val); +} + +static void +cfg_destination (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct directory_pair *dp = data; + dp->dest_dir = xstrdup (val); +} + +static void +cfg_file_sweep_time (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct directory_pair *dp = data; + time_t interval; + const char *endp; + + if (parse_time_interval (val, &interval, &endp)) + file->error_msg (file->file_name, file->line, + "unrecognized time format (near `%s')", + endp); + if (data) + dp->file_sweep_time = interval; + else + file_sweep_time = interval; +} + +static char * +get_word (char **pstr) +{ + char *word; + char *str = *pstr; + + while (*str && isspace (*str)) + str++; + + word = str; + if (*word) + { + while (*str && !isspace (*str)) + str++; + + if (*str) + { + *str++ = 0; + while (*str && isspace (*str)) + str++; + } + } + *pstr = str; + return word; +} + +static enum access_method_type +str_to_access_method (const char *str) +{ + if (strcmp (str, "sql") == 0) + return method_sql; + else if (strcmp (str, "builtin") == 0) + return method_builtin; + else if (strcmp (str, "external") == 0) + return method_external; + else + return method_none; +} + +static void +_cfg_access_method (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct access_method *ap = data; + char *word = get_word (&val); + + if (*word == 0) + { + file->error_msg (file->file_name, file->line, + "access method not specified"); + return; + } + ap->type = str_to_access_method (word); + switch (ap->type) + { + case method_none: + file->error_msg (file->file_name, file->line, + "unknown access method: %s", word); + return; + + case method_sql: + word = get_word (&val); + if (!sql_connection_exists_p (word)) + { + file->error_msg (file->file_name, file->line, + "SQL connection `%s' not declared", word); + ap->type = method_none; + return; + } + ap->param[0] = xstrdup (word); + ap->param[1] = xstrdup (val); + break; + + case method_builtin: + case method_external: + ap->param[0] = xstrdup (val); + break; + } +} + +static void +cfg_verify_user (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct directory_pair *dp = data; + _cfg_access_method (file, kw, val, + dp ? &dp->verify_method : &default_verify_method); +} + +static void +cfg_gpg_key (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct directory_pair *dp = data; + _cfg_access_method (file, kw, val, + dp ? &dp->gpg_key_method : &default_gpg_key_method); +} + +static void +cfg_directory (gsc_config_file_t *file, char *kw, char *val, void *unused) +{ + int ec; + struct directory_pair dpair; + static struct gsc_config_keyword keywords[] = { + { "source", cfg_source }, + { "destination", cfg_destination }, + { "file-sweep-time", cfg_file_sweep_time }, + { "verify-user", cfg_verify_user }, + { "gpg-key", cfg_gpg_key }, + { NULL } + }; + + if (val) + file->error_msg (file->file_name, file->line, "junk in line ignored"); + + memset (&dpair, 0, sizeof dpair); + dpair.file_sweep_time = file_sweep_time; + dpair.verify_method = default_verify_method; + dpair.gpg_key_method = default_gpg_key_method; + gsc_config_parse_block (file, &dpair, keywords, "end"); + + if (test_dir (dpair.source_dir, &ec)) + { + if (ec) + file->error_msg (file->file_name, file->line, + "cannot access %s: %s", + dpair.source_dir, strerror (ec)); + else + file->error_msg (file->file_name, file->line, + "%s is not a directory", + dpair.source_dir); + } + else if (test_dir (dpair.dest_dir, &ec)) + { + if (ec) + file->error_msg (file->file_name, file->line, + "cannot access %s: %s", + dpair.dest_dir, strerror (ec)); + else + file->error_msg (file->file_name, file->line, + "%s is not a directory", + dpair.dest_dir); + } + else if (dpair.verify_method.type != method_none + && dpair.gpg_key_method.type != method_none) + register_directory_pair (&dpair); +} + +static int +get_bool (char *str, int *pval) +{ + if (strcmp (str, "yes") == 0 + || strcmp (str, "t") == 0) + *pval = 1; + else if (strcmp (str, "no") == 0 + || strcmp (str, "nil") == 0) + *pval = 0; + else + { + char *p; + int n = strtoul (str, &p, 10); + if (*p == 0) + *pval = n; + else + return 1; + } + return 0; +} + +static void +cfg_unlink_invalid_files (gsc_config_file_t *file, char *kw, char *val, + void *unused) +{ + if (get_bool (val, &unlink_invalid_files)) + file->error_msg (file->file_name, file->line, "invalid boolean value"); +} + +static void +cfg_sql_host (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct sqlconn *pconn = data; + char *p = strchr (val, ':'); + if (p) + { + *p++ = 0; + if (p[0] == '/') + { + pconn->socket = xstrdup (p); + pconn->host = xstrdup ("localhost"); + } + else + { + char *end; + unsigned long n = strtoul (p, &end, 10); + if (*end) + { + file->error_msg (file->file_name, file->line, + "invalid port number (near %s)", end); + return; + } + if (n == 0 || n > USHRT_MAX) + { + file->error_msg (file->file_name, file->line, + "port number out of range 1..%d", USHRT_MAX); + return; + } + pconn->port = n; + /* Save host name */ + pconn->host = xstrdup (val); + } + } + else + pconn->host = xstrdup (val); +} + +static void +cfg_sql_database (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct sqlconn *pconn = data; + pconn->database = xstrdup (val); +} + +static void +cfg_sql_user (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct sqlconn *pconn = data; + pconn->user = xstrdup (val); +} + +static void +cfg_sql_password (gsc_config_file_t *file, char *kw, char *val, void *data) +{ + struct sqlconn *pconn = data; + pconn->password = xstrdup (val); +} + +static void +cfg_sql (gsc_config_file_t *file, char *kw, char *val, void *unused) +{ + struct sqlconn sql; + static struct gsc_config_keyword keywords[] = { + { "host", cfg_sql_host }, + { "database", cfg_sql_database }, + { "user", cfg_sql_user }, + { "password", cfg_sql_password }, + { NULL } + }; + + memset (&sql, 0, sizeof sql); + if (!val) + file->error_msg (file->file_name, file->line, "missing block identifier"); + else + sql.ident = xstrdup (val); + + gsc_config_parse_block (file, &sql, keywords, "end"); + if (sql.ident) + sql_register_conn (&sql); +} + +static struct gsc_config_keyword kw_handler[] = { + { "syslog-tag", cfg_syslog_tag }, + { "syslog-facility", cfg_syslog_facility }, + { "directory", cfg_directory }, + { "unlink-invalid-files", cfg_unlink_invalid_files }, + { "file-sweep-time", cfg_file_sweep_time }, + { "sql", cfg_sql }, + { "verify-user", cfg_verify_user }, + { "gpg-key", cfg_gpg_key }, + { NULL } +}; + +void +parse_config () +{ + default_verify_method.type = method_builtin; + default_gpg_key_method.type = method_builtin; + + switch (gsc_config_parse (conffile, NULL, kw_handler)) + { + case gsc_config_success: + break; + + case gsc_config_open: + error (1, errno, "cannot open config file `%s'", conffile); + + case gsc_config_error: + exit (1); + } +} + diff --git a/src/gpg.c b/src/gpg.c new file mode 100644 index 0000000..ae81989 --- /dev/null +++ b/src/gpg.c @@ -0,0 +1,188 @@ +/* wydawca - FTP release synchronisation daemon + Copyright (C) 2007 Sergey Poznyakoff + + 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 3 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. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" +#include "save-cwd.h" +#include <gpgme.h> + +#define fail_if_err(expr) \ + do \ + { \ + int a = expr; \ + if (a) \ + { \ + logmsg (LOG_ERR, "%s: GPGME error: %s", #expr, gpgme_strerror (a)); \ + return 1; \ + } \ + } \ + while (0) + +static char *homedir; + +static int rmdir_r (const char *name); + +static int +recursive_rmdir (const char *name) +{ + int rc; + DIR *dir; + struct dirent *ent; + + if (chdir (name)) + { + logmsg (LOG_ERR, "cannot change to directory %s: %s", + name, strerror (errno)); + return 1; + } + + dir = opendir ("."); + if (!dir) + { + logmsg (LOG_ERR, "cannot open directory %s: %s", + name, strerror (errno)); + return 1; + } + + for (rc = 0; rc == 0 && (ent = readdir (dir));) + { + struct stat st; + + if (strcmp (ent->d_name, ".") == 0 + || strcmp (ent->d_name, "..") == 0) + continue; + + if (stat (ent->d_name, &st) && errno != ENOENT) + { + logmsg (LOG_ERR, "cannot stat file `%s': %s", + name, strerror (errno)); + rc = 1; + } + else if (S_ISDIR (st.st_mode)) + rc = rmdir_r (ent->d_name); + else if ((rc = unlink (ent->d_name)) != 0 && errno != ENOENT) + logmsg (LOG_ERR, "cannot unlink %s: %s", + ent->d_name, strerror (errno)); + } + closedir (dir); + return rc; +} + +static int +rmdir_r (const char *name) +{ + int rc; + struct saved_cwd cwd; + + if (save_cwd (&cwd)) + { + logmsg (LOG_ERR, "cannot save current directory: %s", + strerror (errno)); + return 1; + } + rc = recursive_rmdir (name); + if (restore_cwd (&cwd)) + { + logmsg (LOG_ERR, "cannot restore current directory: %s", + strerror (errno)); + rc = 1; + } + + if (rc == 0 && rmdir (name)) + { + logmsg (LOG_ERR, "cannot remove directory %s: %s", + name, strerror (errno)); + return 1; + } + + return rc; +} + +static void +remove_homedir () +{ + if (debug_level > 1) + logmsg (LOG_DEBUG, "Removing GNUPG home directory: %s", homedir); + if (rmdir_r (homedir)) + logmsg (LOG_CRIT, "Failed to remove GPG directory %s", homedir); +} + +int +wydawca_gpg_homedir () +{ + if (homedir) + return; + + homedir = xstrdup ("/tmp/wydawca-XXXXXX"); + if (!mkdtemp (homedir)) + { + logmsg (LOG_CRIT, "cannot create GPG home directory (%s): %s", + homedir, strerror (errno)); + return 1; + } + atexit (remove_homedir); + if (debug_level > 1) + logmsg (LOG_DEBUG, "GNUPG home directory: %s", homedir); + setenv ("GNUPGHOME", homedir, 1); +} + +int +verify_signature (struct file_register *reg, struct directory_pair *dpair, + const char *pubkey) +{ + gpgme_ctx_t ctx; + gpgme_data_t key_data, directive_data, plain; + off_t size; + size_t dcount, i; + char *p; + + wydawca_gpg_homedir (); + fail_if_err (gpgme_new (&ctx)); + fail_if_err (gpgme_data_new_from_mem (&key_data, pubkey, strlen (pubkey), 0)); + fail_if_err (gpgme_op_import (ctx, key_data)); + + fail_if_err (gpgme_data_new_from_file (&directive_data, + reg->file[file_directive].name, 1)); + gpgme_data_new (&plain); + fail_if_err (gpgme_op_verify (ctx, directive_data, NULL, plain)); + + gpgme_data_release (directive_data); + gpgme_data_release (key_data); + + size = gpgme_data_seek (plain, 0, SEEK_END); + gpgme_data_seek (plain, 0, SEEK_SET); + reg->blurb = xmalloc (size + 1); + gpgme_data_read (plain, reg->blurb, size); + reg->blurb[size] = 0; + + dcount = 1; + for (p = reg->blurb; *p; p++) + if (*p == '\n') + dcount++; + + reg->directive = xcalloc (dcount, sizeof reg->directive[0]); + p = reg->blurb; + for (i = 0; i < dcount; i++) + { + reg->directive[i] = p; + p = strchr (p, '\n'); + if (!p) + break; + *p++ = 0; + } + reg->directive[i] = NULL; + + return 0; +} diff --git a/src/method.c b/src/method.c new file mode 100644 index 0000000..433bf6a --- /dev/null +++ b/src/method.c @@ -0,0 +1,115 @@ +/* wydawca - FTP release synchronisation daemon + Copyright (C) 2007 Sergey Poznyakoff + + 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 3 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. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" +#include "sql.h" + +struct method_descr +{ + const char *name; + int (*init) (struct access_method *); + int (*done) (struct access_method *); + int (*run) (struct access_method *, const char *); +}; + +static struct method_descr method_tab[] = { + { "none", NULL, NULL, NULL }, + { "sql", sql_init_method, sql_done_method, sql_run_method }, + { "builtin", NULL, NULL, NULL }, + { "external", NULL, NULL, NULL } +}; + +int +method_init (struct access_method *method) +{ + struct method_descr *mp = method_tab + method->type; + int rc = 0; + + if (debug_level > 1) + logmsg (LOG_DEBUG, "Initializing method: %s \"%s\" \"%s\"", + mp->name, method->param[0], + method->param[1] ? method->param[1] : ""); + if (method->init_passed) + return 0; + if (mp->init) + rc = mp->init (method); + if (rc == 0) + method->init_passed = 1; + return rc; +} + +int +method_done (struct access_method *method) +{ + struct method_descr *mp = method_tab + method->type; + int rc = 0; + + if (debug_level > 1) + logmsg (LOG_DEBUG, "Closing method: %s \"%s\" \"%s\"", + mp->name, method->param[0], + method->param[1] ? method->param[1] : ""); + if (!method->init_passed) + return 0; + if (mp->done) + rc = mp->done (method); + free (method->result); + method->result = NULL; + method->result_size = 0; + if (rc == 0) + method->init_passed = 0; + return rc; +} + +int +method_run (struct access_method *method, const char *cmd) +{ + struct method_descr *mp = method_tab + method->type; + + if (debug_level > 1) + logmsg (LOG_DEBUG, "Running method: %s \"%s\"", mp->name, cmd); + if (!method->init_passed) + { + logmsg (LOG_CRIT, "INTERNAL ERROR: Method %s \"%s\" not initialized", + mp->name, method->param[0]); + return 1; + } + if (!mp->run) + { + logmsg (LOG_CRIT, "INTERNAL ERROR: No run function for method %s \"%s\"", + mp->name, method->param[0]); + return 1; + } + + return mp->run (method, cmd); +} + +const char * +method_result (struct access_method *method) +{ + return method->result; +} + +void +method_copy_result (struct access_method *method, const char *res, size_t size) +{ + if (method->result_size < size + 1) + { + method->result_size = size + 1; + method->result = x2realloc (method->result, &method->result_size); + } + memcpy (method->result, res, size); + method->result[size] = 0; +} diff --git a/src/process.c b/src/process.c new file mode 100644 index 0000000..afb985d --- /dev/null +++ b/src/process.c @@ -0,0 +1,179 @@ +/* wydawca - FTP release synchronisation daemon + Copyright (C) 2007 Sergey Poznyakoff + + 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 3 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. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" + +struct directory_list +{ + struct directory_list *next; + struct directory_pair pair; +}; + +static struct directory_list *dlist; + +void +register_directory_pair (struct directory_pair *dpair) +{ + struct directory_list *dl = xmalloc (sizeof *dl); + dl->pair = *dpair; + dl->next = dlist; + dlist = dl; +} + +int +test_dir (const char *name, int *ec) +{ + struct stat st; + + *ec = 0; + if (stat (name, &st)) + { + *ec = errno; + return 1; + } + return S_ISDIR (st.st_mode) == 0; +} + +const char * +file_type_str (enum file_type type) +{ + switch (type) + { + case file_dist: + return "distributive"; + + case file_signature: + return "detached signature"; + + case file_directive: + return "signed upload directive"; + } +} + +#define SUF_SIG ".sig" +#define SUF_DIR ".directive.asc" + +int +parse_file_name (const char *name, struct file_info *finfo) +{ + static struct suffix + { + const char *suf; + unsigned len; + enum file_type type; + } suftab[] = { + { SUF_SIG, sizeof SUF_SIG - 1, file_signature }, + { SUF_DIR, sizeof SUF_DIR - 1, file_directive }, + { "", 0, file_dist } + }; + int i; + unsigned len = strlen (name); + + for (i = 0; i < sizeof suftab / sizeof suftab[0]; i++) + { + if (len >= suftab[i].len + && memcmp (name + len - suftab[i].len, + suftab[i].suf, suftab[i].len) == 0) + { + finfo->name = xstrdup (name); + finfo->type = suftab[i].type; + finfo->root_len = len - suftab[i].len; + return; + } + } + abort (); /* should not happen */ +} + +void +scan_directory_pair (struct directory_pair *dpair) +{ + DIR *dir; + struct dirent *ent; + + if (debug_level) + logmsg (LOG_DEBUG, "%s -> %s", dpair->source_dir, dpair->dest_dir); + + if (chdir (dpair->source_dir)) + { + logmsg (LOG_ERR, "cannot chdir to %s: %s", dpair->source_dir, + strerror (errno)); + return; + } + + dir = opendir ("."); + if (!dir) + { + logmsg (LOG_ERR, "cannot open directory %s: %s", dpair->source_dir, + strerror (errno)); + return; + } + + while ((ent = readdir (dir))) + { + struct stat st; + struct file_info finfo; + + if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) + continue; + + if (stat (ent->d_name, &st)) + { + logmsg (LOG_ERR, "cannot stat file %s/%s: %s", + dpair->source_dir, ent->d_name, + strerror (errno)); + continue; + } + + if (!S_ISREG (st.st_mode)) + { + logmsg (LOG_NOTICE, "not a regular file: %s/%s", + dpair->source_dir, ent->d_name); + continue; + } + + finfo.mtime = st.st_mtime; + finfo.uid = st.st_uid; + parse_file_name (ent->d_name, &finfo); + + if (debug_level) + { + const char *s = file_type_str (finfo.type); + logmsg (LOG_DEBUG, "file %s is %s %s, root %.*s", ent->d_name, + strchr ("aeiou", s[0]) ? "an" : "a", s, + finfo.root_len, finfo.name); + } + + register_file (&finfo); + } + + closedir (dir); + + if (method_init (&dpair->verify_method) == 0 + && method_init (&dpair->gpg_key_method) == 0) + enumerate_triplets (dpair); + + method_done (&dpair->verify_method); + method_done (&dpair->gpg_key_method); +} + +void +scan_directories () +{ + struct directory_list *dp; + for (dp = dlist; dp; dp = dp->next) + scan_directory_pair (&dp->pair); +} + diff --git a/src/register.c b/src/register.c new file mode 100644 index 0000000..2529a79 --- /dev/null +++ b/src/register.c @@ -0,0 +1,152 @@ +/* wydawca - FTP release synchronisation daemon + Copyright (C) 2007 Sergey Poznyakoff + + 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 3 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. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" +#include "hash.h" + +static Hash_table *file_table; + +static size_t +hash_symbol_hasher (void const *data, unsigned n_buckets) +{ + struct file_register const *t = data; + return hash_string (t->name, n_buckets); +} + +/* Compare two strings for equality. */ +static bool +hash_symbol_compare (void const *data1, void const *data2) +{ + struct file_register const *t1 = data1; + struct file_register const *t2 = data2; + return t1->name && t2->name && strcmp (t1->name, t2->name) == 0; +} + +void +register_file (struct file_info *finfo) +{ + struct file_register *tp, *ret; + + tp = xmalloc (sizeof(*tp) + finfo->root_len + 1); + memset (tp, 0, sizeof (*tp)); + tp->name = (char*)(tp + 1); + memcpy (tp->name, finfo->name, finfo->root_len); + tp->name[finfo->root_len] = 0; + + if (! ((file_table + || (file_table = hash_initialize (0, 0, + hash_symbol_hasher, + hash_symbol_compare, 0))) + && (ret = hash_insert (file_table, tp)))) + xalloc_die (); + + if (ret != tp) + free (tp); + ret->file[finfo->type] = *finfo; +} + +#define SP(s) ((s) ? (s) : "NONE") + +static bool +triplet_expired_p (struct file_register *reg, time_t file_sweep_time) +{ + int i; + time_t now = time (NULL); + + if (file_sweep_time == 0) + return false; + + for (i = 0; i < FILE_TYPE_COUNT; i++) + { + if (reg->file[i].name + && (now - reg->file[i].mtime) > file_sweep_time) + { + if (debug_level) + logmsg (LOG_DEBUG, "File %s expired", reg->file[i].name); + return true; + } + } + return false; +} + +static bool +valid_triplet_p (struct file_register *reg) +{ + if (reg->file[file_dist].name + && reg->file[file_signature].name + && reg->file[file_directive].name) + { + if (reg->file[file_dist].uid == reg->file[file_signature].uid + && reg->file[file_dist].uid == reg->file[file_directive].uid) + return true; + else if (debug_level) + logmsg (LOG_DEBUG, "%s: invalid triplet: UIDs differ", reg->name); + } + else if (debug_level) + logmsg (LOG_DEBUG, "%s: incomplete triplet", reg->name); + return false; +} + +static void +remove_triplet (struct file_register *reg) +{ + int i; + + for (i = 0; i < FILE_TYPE_COUNT; i++) + { + if (reg->file[i].name) + { + if (unlink (reg->file[i].name)) + logmsg (LOG_ERR, "Cannot remove %s: %s", + reg->file[i].name, strerror (errno)); + else + logmsg (LOG_NOTICE, "Removed %s", reg->file[i].name); + } + } +} + +static bool +file_processor (void *data, void *proc_data) +{ + struct file_register *reg = data; + const struct directory_pair *dpair = proc_data; + + if (debug_level) + logmsg (LOG_DEBUG, "FILE %s, DIST=%s, SIG=%s, DIRECTIVE=%s", + reg->name, + SP (reg->file[file_dist].name), + SP (reg->file[file_signature].name), + SP (reg->file[file_directive].name)); + + if (valid_triplet_p (reg)) + { + if (debug_level) + logmsg (LOG_DEBUG, "Processing triplet `%s'", reg->name); + /* FIXME */ + } + else if (triplet_expired_p (reg, dpair->file_sweep_time)) + remove_triplet (reg); + + return true; +} + +void +enumerate_files (const struct directory_pair *dpair) +{ + if (debug_level) + logmsg (LOG_DEBUG, "Processing files for %s", dpair->dest_dir); + hash_do_for_each (file_table, file_processor, (void*)dpair); +} diff --git a/src/sql.c b/src/sql.c new file mode 100644 index 0000000..2ceb724 --- /dev/null +++ b/src/sql.c @@ -0,0 +1,150 @@ +/* wydawca - FTP release synchronisation daemon + Copyright (C) 2007 Sergey Poznyakoff + + 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 3 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. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" +#include "sql.h" + +struct sql_list +{ + struct sql_list *next; + struct sqlconn conn; +}; + +static struct sql_list *sql_list; + +void +sql_register_conn (struct sqlconn *conn) +{ + struct sql_list *ent = xmalloc (sizeof *ent); + ent->conn = *conn; + ent->next = sql_list; + sql_list = ent; +} + +struct sqlconn * +sql_find_connection (const char *ident) +{ + struct sql_list *p; + for (p = sql_list; p; p = p->next) + if (strcmp (p->conn.ident, ident) == 0) + return &p->conn; + return NULL; +} + +int +sql_connection_exists_p (const char *ident) +{ + return sql_find_connection (ident) != NULL; +} + +int +sql_init_method (struct access_method *method) +{ + struct sqlconn *conn = sql_find_connection (method->param[0]); + + if (!conn) + { + logmsg (LOG_EMERG, "INTERNAL ERROR: cannot find SQL connection %s", + method->param[0]); + abort (); + } + + mysql_init (&conn->mysql); + if (!mysql_real_connect (&conn->mysql, conn->host, conn->user, + conn->password, conn->database, conn->port, + conn->socket, 0)) + { + logmsg (LOG_ERR, "Failed to connect to database %s: Error: %s\n", + method->param[0], mysql_error (&conn->mysql)); + return 1; + } + method->v.sqlconn = conn; + return 0; +} + +int +sql_done_method (struct access_method *method) +{ + mysql_close (&method->v.sqlconn->mysql); + return 0; |