aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-02-24 00:49:40 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-02-24 00:57:16 +0200
commit4213ec5ef9695aa504938c0e764ba9a4f08921b2 (patch)
tree88ac2b2eb01337f0924d687df38b2a163bc94e11
parent337a06f32fb530e0e0884fef2f5f630cca9911a1 (diff)
downloadwydawca-4213ec5ef9695aa504938c0e764ba9a4f08921b2.tar.gz
wydawca-4213ec5ef9695aa504938c0e764ba9a4f08921b2.tar.bz2
Initial implementation of daemon mode.
* gconf/gconf-gram.y (string_to_sockaddr_: Take struct gconf_sockaddr as the first argument. * gconf/gconf.h (struct gconf_sockaddr): New data type. * src/job.c, src/net.c, src/pidfile.c: New files. * src/Makefile.am (wydawca_SOURCES): Add job.c, net.c, pidfile.c * src/cmdline.opt: New options: --cron (change semantics), --force, --foreground, --single-process, --spool * src/wydawca.c: New daemon mode. * src/config.c: New statements: spool.alias, daemon, foreground, single-process, wakeup-interval, pidfile, listen * src/directive.c, src/diskio.c, src/gpg.c, src/mail.c, src/null.c, src/process.c, src/triplet.c, src/verify.c, src/vtab.c, src/wydawca.h: use static struct spool wherever feasible. * src/triplet.c: New meta-variable "spool" * tests/etc/wydawca.rcin: Update. * tests/upload-dry.at: Update.
-rw-r--r--gconf/gconf-gram.y20
-rw-r--r--gconf/gconf.h5
-rw-r--r--src/Makefile.am4
-rw-r--r--src/cmdline.opt48
-rw-r--r--src/config.c40
-rw-r--r--src/directive.c2
-rw-r--r--src/diskio.c14
-rw-r--r--src/gpg.c4
-rw-r--r--src/job.c278
-rw-r--r--src/mail.c15
-rw-r--r--src/net.c227
-rw-r--r--src/null.c22
-rw-r--r--src/pidfile.c90
-rw-r--r--src/process.c66
-rw-r--r--src/triplet.c18
-rw-r--r--src/verify.c4
-rw-r--r--src/vtab.c8
-rw-r--r--src/wydawca.c112
-rw-r--r--src/wydawca.h83
-rw-r--r--tests/etc/wydawca.rcin3
-rw-r--r--tests/mailstats.at2
-rw-r--r--tests/notify-upl.at2
-rw-r--r--tests/upload-dry.at10
-rw-r--r--tests/upload.at2
24 files changed, 913 insertions, 166 deletions
diff --git a/gconf/gconf-gram.y b/gconf/gconf-gram.y
index a1d9f2a..f7ee710 100644
--- a/gconf/gconf-gram.y
+++ b/gconf/gconf-gram.y
@@ -506,19 +506,23 @@ string_to_host (struct in_addr *in, const char *string)
}
static int
-string_to_sockaddr (sockaddr_union_t *s, const char *string)
+string_to_sockaddr (struct gconf_sockaddr *sp, const char *string)
{
if (string[0] == '/')
{
- if (strlen (string) >= sizeof (s->s_un.sun_path))
+ struct sockaddr_un s_un;
+ if (strlen (string) >= sizeof (s_un.sun_path))
{
gconf_error (&gconf_current_locus, 0,
_("%s: UNIX socket name too long"),
string);
return 1;
}
- s->s_un.sun_family = AF_UNIX;
- strcpy (s->s_un.sun_path, string);
+ s_un.sun_family = AF_UNIX;
+ strcpy (s_un.sun_path, string);
+ sp->len = sizeof (s_un);
+ sp->sa = xmalloc (sp->len);
+ memcpy (sp->sa, &s_un, sp->len);
}
else
{
@@ -583,7 +587,9 @@ string_to_sockaddr (sockaddr_union_t *s, const char *string)
gconf_error (&gconf_current_locus, 0, _("missing port number"));
return 1;
}
- s->s_in = sa;
+ sp->len = sizeof (sa);
+ sp->sa = xmalloc (sp->len);
+ memcpy (sp->sa, &sa, sp->len);
}
return 0;
}
@@ -689,7 +695,7 @@ string_convert (void *target, enum gconf_data_type type, const char *string)
break;
case gconf_type_sockaddr:
- return string_to_sockaddr ((sockaddr_union_t*)target, string);
+ return string_to_sockaddr ((struct gconf_sockaddr *)target, string);
/* FIXME: */
case gconf_type_cidr:
@@ -720,7 +726,7 @@ size_t gconf_type_size_tab[] = {
sizeof (struct in_addr) /* gconf_type_ipv4 */,
0 /* FIXME: gconf_type_cidr */,
sizeof (struct in_addr) /* gconf_type_host */,
- sizeof (sockaddr_union_t) /* gconf_type_sockaddr */,
+ sizeof (struct gconf_sockaddr) /* gconf_type_sockaddr */,
0 /* gconf_type_section */
};
#define gconf_type_size_count \
diff --git a/gconf/gconf.h b/gconf/gconf.h
index f88e87a..56792a0 100644
--- a/gconf/gconf.h
+++ b/gconf/gconf.h
@@ -97,6 +97,11 @@ struct gconf_keyword {
struct gconf_keyword *kwd;
};
+struct gconf_sockaddr {
+ int len;
+ struct sockaddr *sa;
+};
+
gconf_value_t *gconf_value_dup(gconf_value_t *input);
extern void gconf_print_diag(gconf_locus_t *, int, int, const char*);
diff --git a/src/Makefile.am b/src/Makefile.am
index 7ba9832..903b754 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,8 +25,11 @@ wydawca_SOURCES=\
exec.c\
gpg.c\
interval.c\
+ job.c\
meta.c\
method.c\
+ net.c\
+ pidfile.c\
process.c\
sql.c\
sql.h\
@@ -56,6 +59,7 @@ LDADD=../gconf/libgconf.a ../gnu/libgnu.a @SQLLIB@ @GPGMELIB@ @MAILUTILS_LIBS@
INCLUDES = -I$(top_srcdir)/gconf -I$(top_srcdir)/gnu -I../gnu @MAILUTILS_INCLUDES@
AM_CPPFLAGS= \
-DSYSCONFDIR=\"$(sysconfdir)\"\
+ -DLOCALSTATEDIR=\"$(localstatedir)\"\
-DDEFAULT_VERSION_INCLUDE_DIR=\"$(incdir)\"\
-DDEFAULT_INCLUDE_DIR=\"$(pkgdatadir)/include\"\
-DDEFAULT_PREPROCESSOR="$(DEFAULT_PREPROCESSOR)"
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 53bdd00..b61517b 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -18,6 +18,7 @@ static struct obstack pp_cmd_stack;
static int pp_cmd_stack_init;
static gl_list_t source_list;
+static gl_list_t tag_list;
static bool
source_eq (const void *elt1, const void *elt2)
@@ -28,9 +29,10 @@ source_eq (const void *elt1, const void *elt2)
int
enabled_spool_p (const struct spool *spool)
{
- if (!source_list)
- return 1;
- return !!gl_list_search (source_list, spool->source_dir);
+ if (source_list || tag_list)
+ return (source_list && gl_list_search (source_list, spool->source_dir))
+ || (tag_list && gl_list_search (tag_list, spool->tag));
+ return 1;
}
OPTIONS_BEGIN(gnu, "wydawca",
@@ -61,12 +63,47 @@ BEGIN
dry_run_mode = 1;
END
+OPTION(cron,,,
+ [<force cron mode>])
+BEGIN
+ cron_option = 1;
+ log_to_stderr = 0;
+END
+
+OPTION(force,,,
+ [<force start up even if the pid file already exists>])
+BEGIN
+ force_startup = 1;
+END
+
+OPTION(foreground,,,
+ [<foreground mode>])
+BEGIN
+ foreground_option = 1;
+END
+
+OPTION(single-process,,,
+ [<single process mode>])
+BEGIN
+ single_process_option = 1;
+END
+
OPTION(config-file,c,FILE,
[<use FILE instead of the default configuration>])
BEGIN
conffile = optarg;
END
+OPTION(spool,S,TAG,
+ [<process only spool with the given tag>])
+BEGIN
+ if (!tag_list)
+ tag_list = gl_list_create_empty (&gl_linked_list_implementation,
+ source_eq, NULL,
+ NULL, false);
+ gl_list_add_last (tag_list, optarg);
+END
+
OPTION(source,s,SOURCE-DIR,
[<process only spool with the given source (may be used multiple times)>])
BEGIN
@@ -79,9 +116,8 @@ END
GROUP(Logging)
-OPTION(cron,,,
- [<log to syslog>])
-ALIAS(syslog)
+OPTION(syslog,,,
+ [<log to syslog>])
BEGIN
log_to_stderr = 0;
END
diff --git a/src/config.c b/src/config.c
index dd444fe..94afb20 100644
--- a/src/config.c
+++ b/src/config.c
@@ -263,11 +263,6 @@ cb_mailer (enum gconf_callback_command cmd,
if (assert_string_arg (locus, cmd, value))
return 1;
- if (cmd != gconf_callback_set_value)
- {
- gconf_error (locus, 0, _("Unexpected block statement"));
- return 1;
- }
rc = mu_mailer_create (&mailer, value->v.string);
if (rc)
gconf_error (locus, 0, _("cannot create mailer `%s': %s"),
@@ -1085,22 +1080,17 @@ cb_access_method (enum gconf_callback_command cmd,
}
static int
-cb_destination_url (enum gconf_callback_command cmd,
- gconf_locus_t *locus,
- void *varptr,
- gconf_value_t *value,
- void *cb_data)
+cb_url (enum gconf_callback_command cmd,
+ gconf_locus_t *locus,
+ void *varptr,
+ gconf_value_t *value,
+ void *cb_data)
{
mu_url_t *purl = varptr, url;
int rc;
if (assert_string_arg (locus, cmd, value))
return 1;
- if (cmd != gconf_callback_set_value)
- {
- gconf_error (locus, 0, _("Unexpected block statement"));
- return 1;
- }
rc = mu_url_create (&url, value->v.string);
if (rc)
{
@@ -1122,11 +1112,15 @@ cb_destination_url (enum gconf_callback_command cmd,
static struct gconf_keyword spool_kw[] = {
+ { "url", N_("arg"), N_("URL corresponding to this spool"),
+ gconf_type_string, NULL, offsetof(struct spool, url) },
+ { "alias", N_("arg"), N_("Aliases"),
+ gconf_type_string|GCONF_LIST, NULL, offsetof(struct spool, aliases) },
{ "source", N_("dir"), N_("Source directory"),
gconf_type_string, NULL, offsetof(struct spool, source_dir) },
{ "destination", N_("dir"), N_("Destination directory"),
gconf_type_string, NULL, offsetof(struct spool, dest_url),
- cb_destination_url },
+ cb_url },
{ "file-sweep-time", N_("interval"), N_("Define file sweep time"),
gconf_type_string, NULL, offsetof(struct spool, file_sweep_time),
cb_interval },
@@ -1164,7 +1158,7 @@ cb_spool (enum gconf_callback_command cmd,
return 1;
}
spool = xzalloc (sizeof (*spool));
- spool->url = xstrdup (value->v.string);
+ spool->tag = xstrdup (value->v.string);
spool->file_sweep_time = file_sweep_time;
for (i = 0; i < NITEMS (spool->access_method); i++)
spool->access_method[i] = default_access_method[i];
@@ -1233,6 +1227,18 @@ cb_spool (enum gconf_callback_command cmd,
static struct gconf_keyword wydawca_kw[] = {
+ { "daemon", NULL, N_("Enable daemon mode"),
+ gconf_type_bool, &daemon_mode },
+ { "foreground", NULL, N_("Start in foreground even in daemon mode"),
+ gconf_type_bool, &foreground },
+ { "single-process", NULL, N_("Do not spawn subprocesses"),
+ gconf_type_bool, &single_process },
+ { "wakeup-interval", N_("time"), N_("Set wake-up interval"),
+ gconf_type_string, &wakeup_interval, 0, cb_interval },
+ { "pidfile", N_("file"), N_("Set pid file name"),
+ gconf_type_string, &pidfile },
+ { "listen", N_("socket"), N_("Listen on this address"),
+ gconf_type_sockaddr, &listen_sockaddr, },
{ "mailer", N_("url"), N_("Set mailer URL"),
gconf_type_string, &mailer, 0, cb_mailer },
{ "admin-address", N_("email"), N_("Set admin email address"),
diff --git a/src/directive.c b/src/directive.c
index 46e3196..37ce241 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -302,7 +302,7 @@ verify_directive_format (struct file_triplet *trp)
/* Process the directives from TRP, using given SPOOL */
int
-process_directives (struct file_triplet *trp, struct spool *spool)
+process_directives (struct file_triplet *trp, const struct spool *spool)
{
int rc, n;
const char *key, *val;
diff --git a/src/diskio.c b/src/diskio.c
index 69a3cbe..ccff5c2 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -305,7 +305,7 @@ tar_append_file (const char *archive, const char *file)
Do nothing if dry_run_mode is set. */
int
backup_file (const char *dst_file, const char *dst_dir, const char *file,
- struct archive_descr *archive, uid_t uid, gid_t gid,
+ const struct archive_descr *archive, uid_t uid, gid_t gid,
const char *reldir)
{
int rc = 0;
@@ -380,7 +380,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
for the argument description. */
int
do_archive_file (const char *dst_file, const char *dst_dir, const char *file,
- struct archive_descr *archive, uid_t uid, gid_t gid,
+ const struct archive_descr *archive, uid_t uid, gid_t gid,
const char *reldir)
{
switch (archive->type)
@@ -410,7 +410,7 @@ do_archive_file (const char *dst_file, const char *dst_dir, const char *file,
Do nothing if dry_run_mode is set. */
int
-dir_move_file (struct file_triplet *trp, struct spool *spool,
+dir_move_file (struct file_triplet *trp, const struct spool *spool,
enum file_type file_id, const char *reldir)
{
char *dst_file;
@@ -447,7 +447,7 @@ dir_move_file (struct file_triplet *trp, struct spool *spool,
Do nothing if dry_run_mode is set.
*/
int
-archive_single_file (struct file_triplet *trp, struct spool *spool,
+archive_single_file (struct file_triplet *trp, const struct spool *spool,
const char *file_name, const char *reldir,
int noentok)
{
@@ -517,7 +517,7 @@ make_signame (const char *file_name)
Do nothing if dry_run_mode is set.
*/
int
-dir_archive_file (struct file_triplet *trp, struct spool *spool,
+dir_archive_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name)
{
int rc;
@@ -537,7 +537,7 @@ dir_archive_file (struct file_triplet *trp, struct spool *spool,
Do nothing if dry_run_mode is set. */
int
-dir_symlink_file (struct file_triplet *trp, struct spool *spool,
+dir_symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
const char *wanted_src, const char *wanted_dst)
{
@@ -697,7 +697,7 @@ do_rmsymlink_file (const char *dst_file, int noentok)
Do nothing if dry_run_mode is set. */
int
-dir_rmsymlink_file (struct file_triplet *trp, struct spool *spool,
+dir_rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name)
{
char *dst_file;
diff --git a/src/gpg.c b/src/gpg.c
index d6e2301..6f7dfb6 100644
--- a/src/gpg.c
+++ b/src/gpg.c
@@ -203,7 +203,7 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig)
/* FIXME: spool currently unused */
int
verify_directive_signature (struct file_triplet *trp,
- struct spool *spool, const char *pubkey)
+ const struct spool *spool, const char *pubkey)
{
gpgme_ctx_t ctx;
gpgme_data_t key_data, directive_data, plain;
@@ -261,7 +261,7 @@ verify_directive_signature (struct file_triplet *trp,
a previous call to verify_directive_signature). */
int
verify_detached_signature (struct file_triplet *trp,
- struct spool *spool)
+ const struct spool *spool)
{
gpgme_engine_info_t info;
const char *argv[5];
diff --git a/src/job.c b/src/job.c
new file mode 100644
index 0000000..9678139
--- /dev/null
+++ b/src/job.c
@@ -0,0 +1,278 @@
+/* wydawca - automatic release submission daemon
+ Copyright (C) 2009 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"
+
+#define STATE_FINISHED 0x01
+#define STATE_QUEUED 0x02
+#define STATE_ACTIVE 0x04
+
+struct job
+{
+ struct job *next, *prev;
+ int state;
+ const struct spool *spool;
+ uid_t uid;
+ pid_t pid;
+ time_t timestamp;
+ int exit_status;
+};
+
+struct job *queue;
+size_t jobmax;
+size_t jobcnt;
+
+struct job *
+job_locate (const struct spool *spool, uid_t uid)
+{
+ struct job *p;
+ for (p = queue; p; p = p->next)
+ if (p->spool == spool && p->uid == uid)
+ break;
+ return p;
+}
+
+size_t
+job_active_count ()
+{
+ struct job *job;
+ size_t count = 0;
+ for (job = queue; job; job = job->next)
+ if (job->state & STATE_ACTIVE)
+ count++;
+ return count;
+}
+
+void
+wydawca_scanner (struct job *job)
+{
+ scan_spool (job->spool, 1, &job->uid);
+ mail_finish ();
+}
+
+int
+job_start (struct job *job)
+{
+ pid_t pid;
+
+ if (jobmax && jobcnt == jobmax)
+ {
+ logmsg (LOG_NOTICE, "maximum number of processes active");
+ return 1;
+ }
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, _("starting job: %s, %lu"), job->spool->tag, job->uid);
+
+ if (single_process)
+ {
+ wydawca_scanner (job);
+ return 0;
+ }
+
+ pid = fork ();
+ if (pid == 0)
+ {
+ wydawca_scanner (job);
+ exit (0);
+ }
+ else if (pid == -1)
+ {
+ logmsg (LOG_CRIT, "fork: %s", strerror (errno));
+ return -1;
+ }
+ else
+ {
+ job->state = STATE_ACTIVE;
+ job->pid = pid;
+ jobcnt++;
+ }
+ return 0;
+}
+
+void
+job_remove (struct job *job)
+{
+ struct job *p;
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, _("removing job: %s, %lu"), job->spool->tag, job->uid);
+ p = job->prev;
+ if (p)
+ p->next = job->next;
+ else
+ queue = job->next;
+
+ p = job->next;
+ if (p)
+ p->prev = job->prev;
+}
+
+void
+job_insert (struct job *job, struct job *elt)
+{
+ struct job *p;
+
+ job->prev = elt;
+ if (!elt)
+ {
+ if (queue)
+ queue->prev = job;
+ job->next = queue;
+ queue = job;
+ return;
+ }
+
+ p = elt->next;
+ elt->next = job;
+
+ if (p)
+ p->prev = job;
+}
+
+int
+schedule_job (const struct spool *spool, uid_t uid)
+{
+ struct job *job;
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, _("scheduling job: %s, %lu"), spool->tag, uid);
+
+ job = job_locate (spool, uid);
+ if (!job)
+ {
+ job = xzalloc (sizeof (*job));
+ job->spool = spool;
+ job->uid = uid;
+ job->pid = -1;
+ time (&job->timestamp);
+ job_insert (job, NULL);
+ }
+
+ job->state |= STATE_QUEUED;
+ job_start (job);
+}
+
+static void
+print_status (struct job *job, int expect_term)
+{
+ struct passwd *pw = getpwuid (job->uid);
+ int status = job->exit_status;
+
+ if (WIFEXITED (status))
+ {
+ if (WEXITSTATUS (status) == 0)
+ {
+ if (debug_level)
+ logmsg (LOG_DEBUG,
+ _("%lu (%s, %s) exited successfully"),
+ (unsigned long) job->pid, job->spool->tag, pw->pw_name);
+ }
+ else
+ logmsg (LOG_ERR,
+ _("%lu (%s, %s) failed with status %d"),
+ (unsigned long) job->pid, job->spool->tag, pw->pw_name,
+ WEXITSTATUS (status));
+ }
+ else if (WIFSIGNALED (status))
+ {
+ int prio;
+ if (expect_term && WTERMSIG (status) == SIGTERM)
+ {
+ if (!debug_level)
+ return;
+ prio = LOG_DEBUG;
+ }
+ else
+ prio = LOG_ERR;
+
+ logmsg (prio,
+ _("%lu (%s, %s) terminated on signal %d"),
+ job->pid, job->spool->tag, pw->pw_name, WTERMSIG (status));
+ }
+ else if (WIFSTOPPED (status))
+ logmsg (LOG_NOTICE,
+ _("%lu (%s, %s) stopped on signal %d"),
+ job->pid, job->spool->tag, pw->pw_name, WSTOPSIG (status));
+#ifdef WCOREDUMP
+ else if (WCOREDUMP (status))
+ logmsg (LOG_NOTICE,
+ _("%lu (%s, %s) dumped core"),
+ job->pid, job->spool->tag, pw->pw_name);
+#endif
+ else
+ logmsg (LOG_ERR,
+ _("%lu (%s, %s) terminated with unrecognized status"),
+ job->pid, job->spool->tag, pw->pw_name);
+}
+
+static int wakeup;
+
+RETSIGTYPE
+queue_signal (int sig)
+{
+ wakeup = 1;
+ signal (sig, queue_signal);
+}
+
+void
+job_queue_runner ()
+{
+ int status;
+ struct job *job;
+
+ if (!wakeup)
+ return;
+ wakeup = 0;
+
+ for (;;)
+ {
+ pid_t pid = waitpid ((pid_t)-1, &status, WNOHANG);
+ if (pid <= 0)
+ break;
+ for (job = queue; job; job = job->next)
+ {
+ if ((job->state & STATE_ACTIVE) && job->pid == pid)
+ {
+ job->state &= ~STATE_ACTIVE;
+ job->state |= STATE_FINISHED;
+ job->exit_status = status;
+ jobcnt--;
+ }
+ }
+ }
+
+ for (job = queue; job;)
+ {
+ struct job *next = job->next;
+ if (job->state & STATE_FINISHED)
+ {
+ print_status (job, 0);
+ if ((job->state &= ~STATE_FINISHED) == 0)
+ job_remove (job);
+ }
+ if (job->state == STATE_QUEUED)
+ if (job_start (job))
+ pause ();
+ job = next;
+ }
+}
+
+void
+job_init ()
+{
+ signal (SIGCHLD, queue_signal);
+}
diff --git a/src/mail.c b/src/mail.c
index 7987819..ea74b8c 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -104,7 +104,10 @@ void
mail_finish ()
{
if (mailer_opened)
- mu_mailer_close (mailer);
+ {
+ mu_mailer_close (mailer);
+ mailer_opened = 0;
+ }
}
@@ -269,14 +272,14 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
if (method->type == method_none)
{
- *errp = "access method is not configured";
+ *errp = N_("access method is not configured");
return NULL;
}
md = method_open (method);
if (!md)
{
- *errp = "failed to open access method";
+ *errp = N_("failed to open access method");
return NULL;
}
@@ -289,7 +292,7 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
free (text);
if (rc)
{
- *errp = "cannot obtain recipient emails";
+ *errp = N_("cannot obtain recipient emails");
method_close (method, md);
return NULL;
}
@@ -299,7 +302,7 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
if (nrows == 0)
{
- *errp = "cannot obtain recipient emails";
+ *errp = N_("cannot obtain recipient emails");
return NULL;
}
@@ -350,7 +353,7 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
logmsg (LOG_ERR, _("not notifying %s (project %s) about %s: %s"),
notification_target_str (ntf->tgt),
trp->project,
- notification_event_str (ev), errp);
+ notification_event_str (ev), gettext (errp));
return;
}
diff --git a/src/net.c b/src/net.c
new file mode 100644
index 0000000..efb6225
--- /dev/null
+++ b/src/net.c
@@ -0,0 +1,227 @@
+/* wydawca - automatic release submission daemon
+ Copyright (C) 2007, 2009 Sergey Poznyakoff
+
+ Wydawca 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.
+
+ Wydawca 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 wydawca. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "wydawca.h"
+
+static int
+open_listener ()
+{
+ int fd;
+
+ if (listen_sockaddr.sa == NULL)
+ {
+ logmsg (LOG_CRIT, _("listener address is not configured"));
+ exit (1);
+ }
+
+ fd = socket (listen_sockaddr.sa->sa_family, SOCK_STREAM, 0);
+ if (fd == -1)
+ {
+ logmsg (LOG_CRIT, _("cannot create socket: %s"),
+ strerror(errno));
+ exit (1);
+ }
+ if (listen_sockaddr.sa->sa_family == AF_UNIX)
+ {
+ struct stat st;
+ struct sockaddr_un *s_un = (struct sockaddr_un *) listen_sockaddr.sa;
+ if (stat (s_un->sun_path, &st))
+ {
+ if (errno != ENOENT)
+ {
+ logmsg (LOG_CRIT, _("%s: cannot stat socket: %s"),
+ s_un->sun_path, strerror (errno));
+ exit (1);
+ }
+ }
+ else
+ {
+ /* FIXME: Check permissions? */
+ if (!S_ISSOCK (st.st_mode))
+ {
+ logmsg (LOG_CRIT, _("%s: not a socket"),
+ s_un->sun_path, strerror (errno));
+ exit (1);
+ }
+ unlink (s_un->sun_path);
+ }
+ /* FIXME: Setup umask */
+ }
+ else
+ {
+ int yes = 1;
+ setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof(yes));
+ }
+
+ if (bind (fd, listen_sockaddr.sa, listen_sockaddr.len) < 0)
+ {
+ logmsg (LOG_CRIT, _("cannot bind to local address: %s"),
+ strerror (errno));
+ close (fd);
+ exit (1);
+ }
+ if (listen (fd, 8) == -1)
+ {
+ logmsg (LOG_CRIT, "listen: %s", strerror (errno));
+ close (fd);
+ exit (1);
+ }
+
+ return fd;
+}
+
+static void
+trim_crlf (char *s)
+{
+ size_t len = strlen (s);
+ if (len > 0 && s[len-1] == '\n')
+ {
+ s[--len] = 0;
+ if (len > 0 && s[len-1] == '\r')
+ s[--len] = 0;
+ }
+}
+
+void
+handle_connection (FILE *fp)
+{
+ char *buf = NULL;
+ size_t buflen = 0;
+ const struct spool *spool;
+ char *p;
+ struct passwd *pw;
+
+ if (getline (&buf, &buflen, fp) <= 0)
+ return;
+ trim_crlf (buf);
+ if (debug_level)
+ logmsg (LOG_DEBUG, "recv: %s", buf);
+ spool = wydawca_find_spool (buf);
+ if (!spool)
+ {
+ fprintf (fp, "- Unknown service name\r\n");
+ free (buf);
+ return;
+ }
+ else if (spool->url)
+ fprintf (fp, "+ OK, URL %s\r\n", spool->url);
+ else
+ fprintf (fp, "+ OK, spool %s\r\n", spool->tag);
+
+ if (getline (&buf, &buflen, fp) <= 0)
+ {
+ logmsg (LOG_ERR, "protocol error");
+ free (buf);
+ return;
+ }
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, "recv: %s", buf);
+
+ p = strchr (buf, ' ');
+ if (p)
+ {
+ *p++ = 0;
+ while (*p && (*p == ' ' || *p == '\t'))
+ p++;
+ }
+ else
+ p = "";
+
+ pw = getpwnam (buf);
+ if (pw)
+ schedule_job (spool, pw->pw_uid);
+ else
+ logmsg (LOG_ERR, "no such user: %s", buf);
+ free (buf);
+}
+
+static int reconfigure;
+static int terminate;
+
+RETSIGTYPE
+sig_hup (int sig)
+{
+ reconfigure = 1;
+ terminate = 1;
+}
+
+RETSIGTYPE
+sig_term (int sig)
+{
+ terminate = 1;
+}
+
+void
+wydawca_listener ()
+{
+ int ctlfd = open_listener ();
+
+ job_init ();
+ signal (SIGHUP, sig_hup);
+ signal (SIGTERM, sig_term);
+ signal (SIGQUIT, sig_term);
+ signal (SIGINT, sig_term);
+ while (!terminate)
+ {
+ int fd;
+ FILE *fp;
+ int rc;
+ fd_set rset;
+ struct timeval to, *pto;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in s_in;
+ struct sockaddr_un s_un;
+ } addr;
+ socklen_t len;
+
+ job_queue_runner ();
+ FD_ZERO (&rset);
+ FD_SET (ctlfd, &rset);
+
+ if (wakeup_interval)
+ {
+ to.tv_sec = wakeup_interval;
+ to.tv_usec = 0;
+ *pto = to;
+ }
+ else
+ pto = NULL;
+
+ rc = select (ctlfd + 1, &rset, NULL, NULL, pto);
+ if (rc == 0)
+ continue;
+ else if (rc < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ logmsg (LOG_ERR, "select: %s", strerror (errno));
+ break;
+ }
+
+ len = sizeof (addr);
+ fd = accept (ctlfd, (struct sockaddr*) &addr, &len);
+ if (fd == -1)
+ continue;
+ /* FIXME: Check if the connection is allowed */
+ fp = fdopen (fd, "r+");
+ handle_connection (fp);
+ fclose (fp);
+ }
+}
+
+
diff --git a/src/null.c b/src/null.c
index 7ead150..6a1b0a7 100644
--- a/src/null.c
+++ b/src/null.c
@@ -17,13 +17,13 @@
#include "wydawca.h"
int
-null_move_file (struct file_triplet *trp, struct spool *spool,
+null_move_file (struct file_triplet *trp, const struct spool *spool,
enum file_type file_id, const char *reldir)
{
const char *file_name = trp->file[file_id].name;
if (debug_level)
- logmsg (LOG_DEBUG, _("%s: installing file `%s/%s'"),
- spool->url, reldir, file_name);
+ logmsg (LOG_DEBUG, _("spool %s: installing file `%s/%s'"),
+ spool->tag, reldir, file_name);
UPDATE_STATS (STAT_UPLOADS);
if (unlink (file_name))
{
@@ -35,34 +35,34 @@ null_move_file (struct file_triplet *trp, struct spool *spool,
}
int
-null_archive_file (struct file_triplet *trp, struct spool *spool,
+null_archive_file (struct file_triplet *trp, const struct spool *spool,
const char *file_name, const char *reldir)
{
if (debug_level)
- logmsg (LOG_DEBUG, _("%s: archiving `%s'"), spool->url, file_name);
+ logmsg (LOG_DEBUG, _("spool %s: archiving `%s'"), spool->tag, file_name);
UPDATE_STATS (STAT_ARCHIVES);
return 0;
}
int
-null_symlink_file (st