summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org.ua>2009-02-23 22:49:40 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2009-02-23 22:57:16 (GMT)
commit4213ec5ef9695aa504938c0e764ba9a4f08921b2 (patch) (side-by-side diff)
tree88ac2b2eb01337f0924d687df38b2a163bc94e11 /src
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.
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-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
@@ -27,4 +27,7 @@ wydawca_SOURCES=\
interval.c\
+ job.c\
meta.c\
method.c\
+ net.c\
+ pidfile.c\
process.c\
@@ -58,2 +61,3 @@ AM_CPPFLAGS= \
-DSYSCONFDIR=\"$(sysconfdir)\"\
+ -DLOCALSTATEDIR=\"$(localstatedir)\"\
-DDEFAULT_VERSION_INCLUDE_DIR=\"$(incdir)\"\
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 53bdd00..b61517b 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -20,2 +20,3 @@ static int pp_cmd_stack_init;
static gl_list_t source_list;
+static gl_list_t tag_list;
@@ -30,5 +31,6 @@ 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;
}
@@ -63,2 +65,27 @@ 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,
@@ -69,2 +96,12 @@ 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,
@@ -81,5 +118,4 @@ GROUP(Logging)
-OPTION(cron,,,
- [<log to syslog>])
-ALIAS(syslog)
+OPTION(syslog,,,
+ [<log to syslog>])
BEGIN
diff --git a/src/config.c b/src/config.c
index dd444fe..94afb20 100644
--- a/src/config.c
+++ b/src/config.c
@@ -265,7 +265,2 @@ cb_mailer (enum gconf_callback_command cmd,
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);
@@ -1087,7 +1082,7 @@ 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)
{
@@ -1098,7 +1093,2 @@ cb_destination_url (enum gconf_callback_command cmd,
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);
@@ -1124,2 +1114,6 @@ 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"),
@@ -1128,3 +1122,3 @@ static struct gconf_keyword spool_kw[] = {
gconf_type_string, NULL, offsetof(struct spool, dest_url),
- cb_destination_url },
+ cb_url },
{ "file-sweep-time", N_("interval"), N_("Define file sweep time"),
@@ -1166,3 +1160,3 @@ cb_spool (enum gconf_callback_command cmd,
spool = xzalloc (sizeof (*spool));
- spool->url = xstrdup (value->v.string);
+ spool->tag = xstrdup (value->v.string);
spool->file_sweep_time = file_sweep_time;
@@ -1235,2 +1229,14 @@ 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"),
diff --git a/src/directive.c b/src/directive.c
index 46e3196..37ce241 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -304,3 +304,3 @@ verify_directive_format (struct file_triplet *trp)
int
-process_directives (struct file_triplet *trp, struct spool *spool)
+process_directives (struct file_triplet *trp, const struct spool *spool)
{
diff --git a/src/diskio.c b/src/diskio.c
index 69a3cbe..ccff5c2 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -307,3 +307,3 @@ 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)
@@ -382,3 +382,3 @@ 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)
@@ -412,3 +412,3 @@ do_archive_file (const char *dst_file, const char *dst_dir, const char *file,
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)
@@ -449,3 +449,3 @@ dir_move_file (struct file_triplet *trp, struct spool *spool,
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,
@@ -519,3 +519,3 @@ make_signame (const char *file_name)
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)
@@ -539,3 +539,3 @@ dir_archive_file (struct file_triplet *trp, struct spool *spool,
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,
@@ -699,3 +699,3 @@ do_rmsymlink_file (const char *dst_file, int noentok)
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)
diff --git a/src/gpg.c b/src/gpg.c
index d6e2301..6f7dfb6 100644
--- a/src/gpg.c
+++ b/src/gpg.c
@@ -205,3 +205,3 @@ int
verify_directive_signature (struct file_triplet *trp,
- struct spool *spool, const char *pubkey)
+ const struct spool *spool, const char *pubkey)
{
@@ -263,3 +263,3 @@ int
verify_detached_signature (struct file_triplet *trp,
- struct spool *spool)
+ const struct spool *spool)
{
diff --git a/src/job.c b/src/job.c
new file mode 100644
index 0000000..9678139
--- a/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
@@ -106,3 +106,6 @@ mail_finish ()
if (mailer_opened)
- mu_mailer_close (mailer);
+ {
+ mu_mailer_close (mailer);
+ mailer_opened = 0;
+ }
}
@@ -271,3 +274,3 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
{
- *errp = "access method is not configured";
+ *errp = N_("access method is not configured");
return NULL;
@@ -278,3 +281,3 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
{
- *errp = "failed to open access method";
+ *errp = N_("failed to open access method");
return NULL;
@@ -291,3 +294,3 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
{
- *errp = "cannot obtain recipient emails";
+ *errp = N_("cannot obtain recipient emails");
method_close (method, md);
@@ -301,3 +304,3 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
{
- *errp = "cannot obtain recipient emails";
+ *errp = N_("cannot obtain recipient emails");
return NULL;
@@ -352,3 +355,3 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
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
--- a/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
@@ -19,3 +19,3 @@
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)
@@ -24,4 +24,4 @@ null_move_file (struct file_triplet *trp, struct spool *spool,
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);
@@ -37,3 +37,3 @@ 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)
@@ -41,3 +41,3 @@ null_archive_file (struct file_triplet *trp, struct spool *spool,
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);
@@ -47,3 +47,3 @@ null_archive_file (struct file_triplet *trp, struct spool *spool,
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,
@@ -52,4 +52,4 @@ null_symlink_file (struct file_triplet *trp, struct spool *spool,
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);
@@ -59,3 +59,3 @@ null_symlink_file (struct file_triplet *trp, struct spool *spool,
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)
@@ -63,4 +63,4 @@ null_rmsymlink_file (struct file_triplet *trp, struct spool *spool,
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);
diff --git a/src/pidfile.c b/src/pidfile.c
new file mode 100644
index 0000000..484cabd
--- a/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
@@ -35,2 +35,37 @@ register_spool (struct spool *spool)
+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
@@ -102,2 +137,14 @@ parse_file_name (const char *name, struct file_info *finfo)
+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
@@ -105,3 +152,3 @@ parse_file_name (const char *name, struct file_info *finfo)
void
-scan_spool (struct spool *spool)
+scan_spool (const struct spool *spool, int uc, uid_t *uv)
{
@@ -129,4 +176,5 @@ scan_spool (struct spool *spool)
- timer_start ("directory");
- timer_start (spool->url);
+ timer_start ("spool");
+ /* FIXME: prefix spool tag with something */
+ timer_start (spool->tag);
while ((ent = readdir (dir)))
@@ -154,3 +202,3 @@ scan_spool (struct spool *spool)
- if (!match_uid_p (st.st_uid))
+ if (!match_uid_p (st.st_uid, uc, uv))
{
@@ -166,3 +214,3 @@ scan_spool (struct spool *spool)
if (debug_level)
- logmsg (LOG_DEBUG, _("file %s: %s, root %.*s"), ent->d_name,
+ logmsg (LOG_DEBUG, _("found file %s: %s, stem: %.*s"), ent->d_name,
file_type_str (finfo.type), finfo.root_len, finfo.name);
@@ -188,4 +236,4 @@ scan_spool (struct spool *spool)
}
- timer_stop (spool->url);
- timer_stop ("directory");
+ timer_stop (spool->tag);
+ timer_stop ("spool");
}
@@ -202,3 +250,3 @@ close_methods (struct spool *spool)
void
-scan_directories ()
+scan_directories (int uidc, uid_t *uidv)
{
@@ -210,3 +258,3 @@ scan_directories ()
if (enabled_spool_p (&sp->spool))
- scan_spool (&sp->spool);
+ scan_spool (&sp->spool, uidc, uidv);
diff --git a/src/triplet.c b/src/triplet.c
index 6641211..717fd2a 100644
--- a/src/triplet.c
+++ b/src/triplet.c
@@ -184,3 +184,3 @@ triplet_processor (void *data, void *proc_data)
struct file_triplet *trp = data;
- struct spool *spool = proc_data;
+ const struct spool *spool = proc_data;
@@ -232,10 +232,10 @@ triplet_processor (void *data, void *proc_data)
void
-enumerate_triplets (struct spool *spool)
+enumerate_triplets (const struct spool *spool)
{
if (debug_level)
- logmsg (LOG_DEBUG, _("processing files for %s (%s)"),
- spool->url, mu_url_to_string (spool->dest_url));
+ logmsg (LOG_DEBUG, _("processing spool %s (%s)"),
+ spool->tag, mu_url_to_string (spool->dest_url));
if (triplet_table)
{
- hash_do_for_each (triplet_table, triplet_processor, spool);
+ hash_do_for_each (triplet_table, triplet_processor, (void*) spool);
hash_clear (triplet_table);
@@ -259,2 +259,9 @@ expand_project_base (struct metadef *def, void *data)
static const char *
+expand_tag (struct metadef *def, void *data)
+{
+ struct file_triplet *trp = data;
+ return trp->spool->tag;
+}
+
+static const char *
expand_url (struct metadef *def, void *data)
@@ -578,2 +585,3 @@ struct metadef triplet_meta[] = {
{ "url", NULL, expand_url, NULL },
+ { "spool", NULL, expand_tag, NULL },
{ "dir", NULL, expand_relative_dir, NULL },
diff --git a/src/verify.c b/src/verify.c
index 14651d2..522b865 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -94,3 +94,3 @@ make_default_meta (struct metadef def[5], const char *user,
int
-check_access_rights (struct file_triplet *trp, struct spool *spool,
+check_access_rights (struct file_triplet *trp, const struct spool *spool,
const char *user)
@@ -145,3 +145,3 @@ check_access_rights (struct file_triplet *trp, struct spool *spool,
int
-verify_directive_file (struct file_triplet *trp, struct spool *spool)
+verify_directive_file (struct file_triplet *trp, const struct spool *spool)
{
diff --git a/src/vtab.c b/src/vtab.c
index c34896c..36d8af8 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -53,3 +53,3 @@ url_to_vtab (mu_url_t url, struct virt_tab *vtab)
int
-move_file (struct file_triplet *trp, struct spool *spool,
+move_file (struct file_triplet *trp, const const struct spool *spool,
enum file_type file_id, const char *reldir)
@@ -63,3 +63,3 @@ move_file (struct file_triplet *trp, struct spool *spool,
int
-archive_file (struct file_triplet *trp, struct spool *spool,
+archive_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name)
@@ -73,3 +73,3 @@ archive_file (struct file_triplet *trp, struct spool *spool,
int
-symlink_file (struct file_triplet *trp, struct spool *spool,
+symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
@@ -86,3 +86,3 @@ symlink_file (struct file_triplet *trp, struct spool *spool,
int
-rmsymlink_file (struct file_triplet *trp, struct spool *spool,
+rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name)
diff --git a/src/wydawca.c b/src/wydawca.c
index ce78fc1..cc6c8f0 100644
--- a/src/wydawca.c
+++ b/src/wydawca.c
@@ -34,2 +34,12 @@ int lint_mode = 0;
int preprocess_only = 0;
+int cron_option = 0;
+int foreground_option = -1;
+int single_process_option = -1;
+
+int daemon_mode = 0;
+int foreground;
+int single_process;
+time_t wakeup_interval;
+
+struct gconf_sockaddr listen_sockaddr;
@@ -108,42 +118,16 @@ logmsg (int prio, char *fmt, ...)
-
-enum {
- SYSLOG_OPTION = 256,
- CONFIG_HELP_OPTION,
- DUMP_GRAMMAR_TRACE_OPTION,
- DUMP_LEX_TRACE_OPTION
-};
-
-struct option options[] = {
- { "config-file", required_argument, NULL, 'c' },
- { "config-help", no_argument, NULL, CONFIG_HELP_OPTION },
- { "dump-grammar-trace", no_argument, NULL, DUMP_GRAMMAR_TRACE_OPTION },
- { "dump-lex-trace", no_argument, NULL, DUMP_LEX_TRACE_OPTION },
- { "debug", no_argument, NULL, 'd' },
- { "stderr", no_argument, NULL, 'e' },
- { "syslog", no_argument, NULL, SYSLOG_OPTION },
- { "cron", no_argument, NULL, SYSLOG_OPTION },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, 'v' },
- { "dry-run", no_argument, NULL, 'n' },
- { "lint", no_argument, NULL, 't' },
- { "include-directory", optional_argument, NULL, 'I' },
- { NULL }
-};
-
-
static char *stat_name[MAX_STAT] = {
- "errors",
- "warnings",
- "bad signatures",
- "access violation attempts",
- "complete triplets",
- "incomplete triplets",
- "bad triplets",
- "expired triplets",
- "triplet successes",
- "files uploaded",
- "files archived",
- "symlinks created",
- "symlinks removed",
+ N_("errors"),
+ N_("warnings"),
+ N_("bad signatures"),
+ N_("access violation attempts"),
+ N_("complete triplets"),
+ N_("incomplete triplets"),
+ N_("bad triplets"),
+ N_("expired triplets"),
+ N_("triplet successes"),
+ N_("files uploaded"),
+ N_("files archived"),
+ N_("symlinks created"),
+ N_("symlinks removed"),
};
@@ -214,3 +198,3 @@ logstats ()
if (print_stats & STAT_MASK (i))
- logmsg (LOG_INFO, "%s: %u", stat_name[i], wydawca_stat[i]);
+ logmsg (LOG_INFO, "%s: %u", gettext (stat_name[i]), wydawca_stat[i]);
}
@@ -246,3 +230,3 @@ gconf_print_diag (gconf_locus_t *locus, int err, int errcode, const char *msg)
static int uidc;
-static char *uidv;
+static uid_t *uidv;
@@ -274,14 +258,2 @@ collect_uids (int argc, char **argv)
-int
-match_uid_p (uid_t uid)
-{
- int i;
- if (!uidv)
- return 1;
- for (i = 0; i < uidc; i++)
- if (uidv[i] == uid)
- return 1;
- return 0;
-}
-
@@ -310,2 +282,17 @@ wydawca_uid (uid_t uid)
+void
+wydawca_daemon ()
+{
+ check_pidfile ();
+
+ if (!foreground && daemon (0, 0))
+ {
+ logmsg (LOG_ERR, "%s", strerror (errno));
+ exit (1);
+ }
+
+ wydawca_listener ();
+}
+
+
#include "cmdline.h"
@@ -335,4 +322,11 @@ main (int argc, char **argv)
+ if (cron_option)
+ daemon_mode = 0;
+ if (foreground_option >= 0)
+ foreground = foreground_option;
+ if (single_process_option >= 0)
+ single_process = single_process_option;
+
if (log_to_stderr == -1)
- log_to_stderr = isatty (0);
+ log_to_stderr = (!daemon_mode || foreground) && isatty (0);
@@ -348,6 +342,12 @@ main (int argc, char **argv)
logmsg (LOG_NOTICE, _("wydawca (%s) started"), PACKAGE_STRING);
- scan_directories ();
+ if (!daemon_mode)
+ {
+ scan_directories (uidc, uidv);
+ logstats ();
+ }
+ else
+ wydawca_daemon ();
+
logmsg (LOG_NOTICE, _("wydawca (%s) finished"), PACKAGE_STRING);
- logstats ();
diff --git a/src/wydawca.h b/src/wydawca.h
index 3f28919..8a716e4 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -34,3 +34,10 @@
#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <netdb.h>
+#include <arpa/inet.h>
#include <fcntl.h>
+#include <time.h>
@@ -49,2 +56,3 @@
#include "gconf.h"
+#include "gl_list.h"
#include "argcv.h"
@@ -158,3 +166,3 @@ struct file_triplet
struct file_info file[FILE_TYPE_COUNT]; /* Components */
- struct spool *spool; /* Owning spool */
+ const struct spool *spool; /* Owning spool */
char **directive; /* Decoded directive pairs (key: value\0) */
@@ -181,3 +189,3 @@ struct virt_tab
int (*move_file) (struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
enum file_type file_id,
@@ -185,3 +193,3 @@ struct virt_tab
int (*archive_file) (struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
const char *reldir,
@@ -189,3 +197,3 @@ struct virt_tab
int (*symlink_file) (struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
const char *reldir,
@@ -194,3 +202,3 @@ struct virt_tab
int (*rmsymlink_file)(struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
const char *reldir,
@@ -203,2 +211,4 @@ struct spool
{
+ char *tag;
+ gl_list_t aliases;
char *url; /* Download URL */
@@ -308,2 +318,11 @@ extern char *admin_stat_message;
+extern char *pidfile;
+extern int force_startup;
+
+extern int daemon_mode;
+extern time_t wakeup_interval;
+extern int foreground;
+extern int single_process;
+extern struct gconf_sockaddr listen_sockaddr;
+
#define UPDATE_STATS(what) \
@@ -343,6 +362,9 @@ enum exec_result wydawca_exec (int argc, const char **argv, int *retcode);
/* Directory scanning and registering */
-void scan_directories (void);
+void scan_spool (const struct spool *spool, int uc, uid_t *uv);
+void scan_directories (int, uid_t *);
+
void register_spool (struct spool *spool);
+struct spool *wydawca_find_spool (const char *name);
void register_file (struct file_info *finfo);
-void enumerate_triplets (struct spool *);
+void enumerate_triplets (const struct spool *);
size_t count_collected_triplets (void);
@@ -371,8 +393,8 @@ unsigned method_num_cols (struct access_method *method);
int verify_directive_file (struct file_triplet *trp,
- struct spool *spool);
+ const struct spool *spool);
int verify_directive_signature (struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
const char *pubkey);
int verify_detached_signature (struct file_triplet *trp,
- struct spool *spool);
+ const struct spool *spool);
int fill_project_name (struct file_triplet *trp);
@@ -392,5 +414,4 @@ int directive_next (struct file_triplet *trp, int n,
int process_directives (struct file_triplet *trp,
- struct spool *spool);
+ const struct spool *spool);
-int match_uid_p (uid_t uid);
int enabled_spool_p (const struct spool *spool);
@@ -412,9 +433,9 @@ int url_to_vtab (mu_url_t url, struct virt_tab *vtab);
int
-move_file (struct file_triplet *trp, struct spool *spool,
+move_file (struct file_triplet *trp, const struct spool *spool,
enum file_type file_id, const char *reldir);
int
-archive_file (struct file_triplet *trp, struct spool *spool,
+archive_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name);
int
-symlink_file (struct file_triplet *trp, struct spool *spool,
+symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
@@ -422,3 +443,3 @@ symlink_file (struct file_triplet *trp, struct spool *spool,
int
-rmsymlink_file (struct file_triplet *trp, struct spool *spool,
+rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name);
@@ -429,10 +450,10 @@ rmsymlink_file (struct file_triplet *trp, struct spool *spool,
int dir_test_url (mu_url_t url, gconf_locus_t *locus);
-int dir_move_file (struct file_triplet *trp, struct spool *spool,
+int dir_move_file (struct file_triplet *trp, const struct spool *spool,
enum file_type file_id, const char *reldir);
-int dir_archive_file (struct file_triplet *trp, struct spool *spool,
+int dir_archive_file (struct file_triplet *trp, const struct spool *spool,
const char *file_name, const char *reldir);
-int dir_symlink_file (struct file_triplet *trp, struct spool *spool,
+int dir_symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
const char *wanted_src, const char *wanted_dst);
-int dir_rmsymlink_file (struct file_triplet *trp, struct spool *spool,
+int dir_rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name);
@@ -440,10 +461,10 @@ int dir_rmsymlink_file (struct file_triplet *trp, struct spool *spool,
/* null.c */
-int null_move_file (struct file_triplet *trp, struct spool *spool,
+int null_move_file (struct file_triplet *trp, const struct spool *spool,
enum file_type file_id, const char *reldir);
-int null_archive_file (struct file_triplet *trp, struct spool *spool,
+int null_archive_file (struct file_triplet *trp, const struct spool *spool,
const char *file_name, const char *reldir);
-int null_symlink_file (struct file_triplet *trp, struct spool *spool,
+int null_symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
const char *wanted_src, const char *wanted_dst);
-int null_rmsymlink_file (struct file_triplet *trp, struct spool *spool,
+int null_rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name);
@@ -471 +492,15 @@ void report_finish (void);
extern char *report_string;
+
+
+/* job.c */
+int schedule_job (const struct spool *spool, uid_t uid);
+void job_init (void);
+void job_queue_runner (void);
+
+
+/* profile.c */
+void check_pidfile (void);
+
+
+/* net.c */
+void wydawca_listener (void);

Return to:

Send suggestions and report system problems to the System administrator.