aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
17 files changed, 885 insertions, 150 deletions
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 (struct file_triplet *trp, struct spool *spool,
+null_symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
const char *wanted_src, const char *wanted_dst)
{
if (debug_level)
- logmsg (LOG_DEBUG, _("%s: symlinking `%s' to `%s'"),
- spool->url, wanted_src, wanted_dst);
+ logmsg (LOG_DEBUG, _("spool %s: symlinking `%s' to `%s'"),
+ spool->tag, wanted_src, wanted_dst);
UPDATE_STATS (STAT_SYMLINKS);
return 0;
}
int
-null_rmsymlink_file (struct file_triplet *trp, struct spool *spool,
+null_rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name)
{
if (debug_level)
- logmsg (LOG_DEBUG, _("%s: removing symlink `%s/%s'"),
- spool->url, reldir, file_name);
+ logmsg (LOG_DEBUG, _("spool %s: removing symlink `%s/%s'"),
+ spool->tag, reldir, file_name);
UPDATE_STATS (STAT_RMSYMLINKS);
return 0;
}
diff --git a/src/pidfile.c b/src/pidfile.c
new file mode 100644
index 0000000..484cabd
--- /dev/null
+++ b/src/pidfile.c
@@ -0,0 +1,90 @@
+/* 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"
+
+char *pidfile = LOCALSTATEDIR "/run/wydawca.pid";
+int force_startup;
+
+
+void
+remove_pidfile (void)
+{
+ unlink (pidfile);
+}
+
+void
+check_pidfile ()
+{
+ FILE *fp = fopen (pidfile, "r+");
+
+ if (fp)
+ {
+ unsigned long pid;
+ if (fscanf (fp, "%ul\n", &pid) != 1)
+ {
+ logmsg (LOG_ERR, _("malformed pidfile %s"), pidfile);
+ if (!force_startup)
+ exit (1);
+ }
+ else
+ {
+ if (kill (pid, 0))
+ {
+ if (errno != ESRCH)
+ {
+ logmsg (LOG_ERR,
+ _("cannot verify if PID %lu is running: %s"),
+ pid, strerror (errno));
+ if (!force_startup)
+ exit (1);
+ }
+ }
+ else if (!force_startup)
+ {
+ logmsg (LOG_ERR,
+ _("another wydawca instance may be running (PID %lu)"),
+ pid);
+ exit (1);
+ }
+ }
+ logmsg (LOG_NOTICE, _("replacing pidfile %s (PID %lu)"),
+ pidfile, pid);
+ fseek (fp, 0, SEEK_SET);
+ }
+ else if (errno != ENOENT)
+ {
+ logmsg (LOG_ERR, _("cannot open pidfile %s: %s"), pidfile,
+ strerror (errno));
+ exit (1);
+ }
+ else
+ {
+ fp = fopen (pidfile, "w");
+ if (!fp)
+ {
+ logmsg (LOG_ERR,
+ _("cannot open pidfile %s for writing: %s"),
+ pidfile, strerror (errno));
+ exit (1);
+ }
+ }
+ fprintf (fp, "%lu\n", getpid ());
+ fclose (fp);
+ atexit (remove_pidfile);
+}
+
+
diff --git a/src/process.c b/src/process.c
index 0d2bf5e..20bfd38 100644
--- a/src/process.c
+++ b/src/process.c
@@ -33,6 +33,41 @@ register_spool (struct spool *spool)
spool_list = sp;
}
+static int
+spool_check_alias (struct spool *spool, const char *name)
+{
+ int rc = 0;
+
+ if (spool->aliases)
+ {
+ gl_list_iterator_t itr = gl_list_iterator (spool->aliases);
+ const void *p;
+
+ while (gl_list_iterator_next (&itr, &p, NULL))
+ if (strcmp (name, p) == 0)
+ {
+ rc = 1;
+ break;
+ }
+ gl_list_iterator_free (&itr);
+ }
+ return rc;
+}
+
+struct spool *
+wydawca_find_spool (const char *name)
+{
+ struct spool_list *sp;
+
+ for (sp = spool_list; sp; sp = sp->next)
+ {
+ if (strcmp (sp->spool.tag, name) == 0
+ || spool_check_alias (&sp->spool, name))
+ return &sp->spool;
+ }
+ return NULL;
+}
+
/* Return true if NAME is a directory. If stat fails, return the error
code in EC */
int
@@ -100,10 +135,22 @@ parse_file_name (const char *name, struct file_info *finfo)
abort (); /* should not happen */
}
+int
+match_uid_p (uid_t uid, int uc, uid_t *uv)
+{
+ int i;
+ if (!uv)
+ return 1;
+ for (i = 0; i < uc; i++)
+ if (uv[i] == uid)
+ return 1;
+ return 0;
+}
+
/* Scan upload directory from the DPAIR and register all files found
there, forming triplets when possible */
void
-scan_spool (struct spool *spool)
+scan_spool (const struct spool *spool, int uc, uid_t *uv)
{
DIR *dir;
struct dirent *ent;
@@ -127,8 +174,9 @@ scan_spool (struct spool *spool)
return;
}