aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
@@ -503,25 +503,29 @@ string_to_host (struct in_addr *in, const char *string)
memcpy (in, hp->h_addr, sizeof (struct in_addr));
}
return 0;
}
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
{
char *p = strchr (string, ':');
size_t len;
struct sockaddr_in sa;
@@ -580,13 +584,15 @@ string_to_sockaddr (sockaddr_union_t *s, const char *string)
sa.sin_port = gconf_default_port;
else
{
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;
}
static int
string_convert (void *target, enum gconf_data_type type, const char *string)
@@ -686,13 +692,13 @@ string_convert (void *target, enum gconf_data_type type, const char *string)
_("%s: not a valid IP address or hostname"), string);
return 1;
}
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:
case gconf_type_section:
gconf_error (&gconf_current_locus, 0, _("INTERNAL ERROR at %s:%d"), __FILE__,
@@ -717,13 +723,13 @@ size_t gconf_type_size_tab[] = {
sizeof (intmax_t) /* gconf_type_intmax */,
sizeof (time_t) /* gconf_type_time */,
sizeof (int) /* gconf_type_bool */,
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 \
(sizeof (gconf_type_size_tab) / sizeof (gconf_type_size_tab[0]))
static void
diff --git a/gconf/gconf.h b/gconf/gconf.h
index f88e87a..56792a0 100644
--- a/gconf/gconf.h
+++ b/gconf/gconf.h
@@ -94,12 +94,17 @@ struct gconf_keyword {
size_t offset;
gconf_callback_fn callback;
void *callback_data;
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*);
void gconf_warning(gconf_locus_t *locus, int errcode, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 3, 4)));
diff --git a/src/Makefile.am b/src/Makefile.am
index 7ba9832..903b754 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,14 +22,17 @@ wydawca_SOURCES=\
config.c\
directive.c\
diskio.c\
exec.c\
gpg.c\
interval.c\
+ job.c\
meta.c\
method.c\
+ net.c\
+ pidfile.c\
process.c\
sql.c\
sql.h\
triplet.c\
verify.c\
wydawca.c\
@@ -53,10 +56,11 @@ incdir=$(pkgdatadir)/$(VERSION)/include
inc_DATA = $(PP_SETUP_FILE)
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
@@ -15,25 +15,27 @@
with wydawca. If not, see <http://www.gnu.org/licenses/>. */
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)
{
return strcmp ((const char *)elt1, (const char *)elt2) == 0;
}
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",
[<wydawca synchronizes files from a set of upload directories with the corresponding distribution sites>],
[<UID [UID...]>])
@@ -58,33 +60,67 @@ OPTION(dry-run,n,,
BEGIN
log_to_stderr = 1;
debug_level++;
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
if (!source_list)
source_list = gl_list_create_empty (&gl_linked_list_implementation,
source_eq, NULL,
NULL, false);
gl_list_add_last (source_list, optarg);
END
GROUP(Logging)
-OPTION(cron,,,
- [<log to syslog>])
-ALIAS(syslog)
+OPTION(syslog,,,
+ [<log to syslog>])
BEGIN
log_to_stderr = 0;
END
OPTION(stderr,e,,
[<log to stderr>])
diff --git a/src/config.c b/src/config.c
index dd444fe..94afb20 100644
--- a/src/config.c
+++ b/src/config.c
@@ -260,17 +260,12 @@ cb_mailer (enum gconf_callback_command cmd,
void *cb_data)
{
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_mailer_create (&mailer, value->v.string);
if (rc)
gconf_error (locus, 0, _("cannot create mailer `%s': %s"),
value->v.string, mu_strerror (rc));
return rc;
}
@@ -1082,28 +1077,23 @@ cb_access_method (enum gconf_callback_command cmd,
gconf_error (locus, 0, _("invalid use of block statement"));
}
return 0;
}
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)
{
gconf_error (locus, 0, _("cannot create URL `%s': %s"),
value->v.string, mu_strerror (rc));
return rc;
@@ -1119,17 +1109,21 @@ cb_destination_url (enum gconf_callback_command cmd,
*purl = url;
return 0;
}
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 },
{ "access-method", N_("ident"), N_("Define access method"),
gconf_type_section, NULL, offsetof(struct spool, access_method),
cb_access_method, NULL, access_method_kw },
@@ -1161,13 +1155,13 @@ cb_spool (enum gconf_callback_command cmd,
if (!value || value->type != GCONF_TYPE_STRING)
{
gconf_error (locus, 0, _("tag must be a string"));
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];
spool->archive = default_archive_descr;
*pdata = spool;
break;
@@ -1230,12 +1224,24 @@ cb_spool (enum gconf_callback_command cmd,
return 0;
}
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"),
gconf_type_string, &admin_address, 0, cb_email_address },
{ "from-address", N_("email"), N_("Set sender email address"),
gconf_type_string, &from_address, 0, cb_email_address },
diff --git a/src/directive.c b/src/directive.c
index 46e3196..37ce241 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -299,13 +299,13 @@ verify_directive_format (struct file_triplet *trp)
}
return 0;
}
/* 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;
char *relative_dir;
UPDATE_STATS (STAT_COMPLETE_TRIPLETS);
diff --git a/src/diskio.c b/src/diskio.c
index 69a3cbe..ccff5c2 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -302,13 +302,13 @@ tar_append_file (const char *archive, const char *file)
UID, GID - Ownership
RELDIR - Directory part of 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;
char *adir;
char *file_name;
@@ -377,13 +377,13 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
}
/* Select the appropriate backup type and backup a file. See backup_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)
{
case archive_none:
break;
@@ -407,13 +407,13 @@ do_archive_file (const char *dst_file, const char *dst_dir, const char *file,
/* Move the part FILE_ID of the triplet TRP between the directories in
DPAIR. RELDIR gives relative directory (i.e. the directory part of
the file name) for backup purposes.
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;
int rc = 0;
char *dst_dir = create_directory (spool->dest_dir, reldir,
TRIPLET_UID (trp), TRIPLET_GID (trp));
@@ -444,13 +444,13 @@ dir_move_file (struct file_triplet *trp, struct spool *spool,
/* Archive the file FILE_NAME, located in DPAIR->dest_dir, and remove the
file. Get user IDs from the triplet TRP.
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)
{
char *dst_file;
int rc = 0;
char *dst_dir = create_directory (spool->dest_dir, reldir,
@@ -514,13 +514,13 @@ make_signame (const char *file_name)
/* Archive the file FILE_NAME, located in DPAIR->dest_dir, and remove the
file. Get user IDs from the triplet TRP. Unless FILE_NAME ends in
".sig", do the same with FILE_NAME.sig, if such a file exists.
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;
char *signame;
rc = archive_single_file (trp, spool, file_name, reldir, 0);
@@ -534,13 +534,13 @@ dir_archive_file (struct file_triplet *trp, struct spool *spool,
/* Create a symbolic link from WANTED_SRC to WANTED_DST in the subdirectory
RELDIR of DPAIR->dest_dir. Get ownership information from TRP.
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)
{
int rc = 0;
struct saved_cwd cwd;
char *dst_dir = create_directory (spool->dest_dir, reldir,
@@ -694,13 +694,13 @@ do_rmsymlink_file (const char *dst_file, int noentok)
/* Remove the symbolic link DPAIR->dest_dir/RELDIR/FILE_NAME
Get ownership information from TRP.
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;
int rc = 0;
char *signame;
char *dst_dir = create_directory (spool->dest_dir, reldir,
diff --git a/src/gpg.c b/src/gpg.c
index d6e2301..6f7dfb6 100644
--- a/src/gpg.c
+++ b/src/gpg.c
@@ -200,13 +200,13 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig)
}
/* Verify the directive file from TRP using public key PUBKEY */
/* 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;
off_t size;
gpgme_error_t ec;
int rc;
@@ -258,13 +258,13 @@ verify_directive_signature (struct file_triplet *trp,
/* Verify the detached signature of TRP.
NOTE: It is assumed that the public key is already registered (by
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];
fail_if_err (gpgme_get_engine_info (&info));
while (info && info->protocol != GPGME_PROTOCOL_OpenPGP)
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
@@ -101,13 +101,16 @@ mail_send_message (mu_address_t rcpt, const char *text)
}
void
mail_finish ()
{
if (mailer_opened)
- mu_mailer_close (mailer);
+ {
+ mu_mailer_close (mailer);
+ mailer_opened = 0;
+ }
}
struct message_template
{
char *name;
@@ -266,43 +269,43 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
char *text;
int rc;
void *md;
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;
}
make_default_meta (def, trp->user, trp->project);
meta_escape (method, md, def);
text = meta_expand_string (method->query, def, NULL);
meta_free (def);
rc = method_run (method, md, text);
free (text);
if (rc)
{
- *errp = "cannot obtain recipient emails";
+ *errp = N_("cannot obtain recipient emails");
method_close (method, md);
return NULL;
}
nrows = method_num_rows (method);
ncols = method_num_cols (method);
if (nrows == 0)
{
- *errp = "cannot obtain recipient emails";
+ *errp = N_("cannot obtain recipient emails");
return NULL;
}
for (i = 0; i < nrows; i++)
{
mu_address_t addr;
@@ -347,13 +350,13 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
if (!rcpt)
{
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;
}
if (debug_level)
{
size_t size;
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);