summaryrefslogtreecommitdiffabout
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
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 (more/less context) (ignore whitespace changes)
-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
--- 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
@@ -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
--- 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
@@ -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
--- 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
@@ -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;
}
- timer_start ("directory");
- timer_start (spool->url);
+ timer_start ("spool");
+ /* FIXME: prefix spool tag with something */
+ timer_start (spool->tag);
while ((ent = readdir (dir)))
{
struct stat st;
@@ -152,7 +200,7 @@ scan_spool (struct spool *spool)
continue;
}
- if (!match_uid_p (st.st_uid))
+ if (!match_uid_p (st.st_uid, uc, uv))
{
if (debug_level)
logmsg (LOG_DEBUG, _("ignoring file: %s/%s"),
@@ -164,7 +212,7 @@ scan_spool (struct spool *spool)
parse_file_name (ent->d_name, &finfo);
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);
register_file (&finfo);
@@ -186,8 +234,8 @@ scan_spool (struct spool *spool)
}
enumerate_triplets (spool);
}
- timer_stop (spool->url);
- timer_stop ("directory");
+ timer_stop (spool->tag);
+ timer_stop ("spool");
}
static void
@@ -200,7 +248,7 @@ close_methods (struct spool *spool)
/* Scan all configured update directories */
void
-scan_directories ()
+scan_directories (int uidc, uid_t *uidv)
{
struct spool_list *sp;
@@ -208,7 +256,7 @@ scan_directories ()
for (sp = spool_list; sp; sp = sp->next)
if (enabled_spool_p (&sp->spool))
- scan_spool (&sp->spool);
+ scan_spool (&sp->spool, uidc, uidv);
for (sp = spool_list; sp; sp = sp->next)
close_methods (&sp->spool);
diff --git a/src/triplet.c b/src/triplet.c
index 6641211..717fd2a 100644
--- a/src/triplet.c
+++ b/src/triplet.c
@@ -182,7 +182,7 @@ static bool
triplet_processor (void *data, void *proc_data)
{
struct file_triplet *trp = data;
- struct spool *spool = proc_data;
+ const struct spool *spool = proc_data;
trp->spool = spool;
@@ -230,14 +230,14 @@ triplet_processor (void *data, void *proc_data)
/* Process all triplets from the table according to the SPOOL */
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);
}
}
@@ -257,6 +257,13 @@ 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)
{
struct file_triplet *trp = data;
@@ -576,6 +583,7 @@ DECL_EXPAND_TIMER(system)
struct metadef triplet_meta[] = {
{ "project", NULL, expand_project_base, NULL },
{ "url", NULL, expand_url, NULL },
+ { "spool", NULL, expand_tag, NULL },
{ "dir", NULL, expand_relative_dir, NULL },
{ "dest-dir", NULL, expand_dest_dir, NULL },
{ "source-dir", NULL, expand_source_dir, NULL },
diff --git a/src/verify.c b/src/verify.c
index 14651d2..522b865 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -92,7 +92,7 @@ make_default_meta (struct metadef def[5], const char *user,
/* Verify if USER has upload rights on the directory (project) requested
by TRP */
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)
{
struct access_method *method = spool->access_method[verify_method];
@@ -143,7 +143,7 @@ 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)
{
struct passwd *pw;
char *command;
diff --git a/src/vtab.c b/src/vtab.c
index c34896c..36d8af8 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -51,7 +51,7 @@ 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)
{
int rc = spool->vtab.move_file (trp, spool, file_id, reldir);
@@ -61,7 +61,7 @@ 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)
{
int rc = spool->vtab.archive_file (trp, spool, reldir, file_name);
@@ -71,7 +71,7 @@ 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,
const char *wanted_src, const char *wanted_dst)
{
@@ -84,7 +84,7 @@ 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)
{
int rc = spool->vtab.rmsymlink_file (trp, spool, reldir, file_name);
diff --git a/src/wydawca.c b/src/wydawca.c
index ce78fc1..cc6c8f0 100644
--- a/src/wydawca.c
+++ b/src/wydawca.c
@@ -32,6 +32,16 @@ char *tar_command_name = "tar";
int archive_signatures = 1; /* Archive sig files by default */
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;
unsigned wydawca_stat[MAX_STAT];
@@ -106,46 +116,20 @@ 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"),
};
static char *stat_kwname[MAX_STAT] = {
@@ -212,7 +196,7 @@ logstats ()
{
for (i = 0; i < MAX_STAT; i++)
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]);
}
mail_stats ();
@@ -244,7 +228,7 @@ gconf_print_diag (gconf_locus_t *locus, int err, int errcode, const char *msg)
static int uidc;
-static char *uidv;
+static uid_t *uidv;
static int
collect_uids (int argc, char **argv)
@@ -272,18 +256,6 @@ 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;
-}
-
int
wydawca_uid (uid_t uid)
@@ -308,6 +280,21 @@ 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"
int
@@ -333,8 +320,15 @@ main (int argc, char **argv)
if (lint_mode)
exit (0);
+ 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);
gconf_log_to_stderr = log_to_stderr;
if (!log_to_stderr)
@@ -346,10 +340,16 @@ main (int argc, char **argv)
mail_init ();
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 ();
mail_finish ();
diff --git a/src/wydawca.h b/src/wydawca.h
index 3f28919..8a716e4 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -32,7 +32,14 @@
#include <limits.h>
#include <dirent.h>
#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>
#include <mailutils/types.h>
#include <mailutils/url.h>
@@ -47,6 +54,7 @@
#include "backupfile.h"
#include "inttostr.h"
#include "gconf.h"
+#include "gl_list.h"
#include "argcv.h"
#define gettext(s) s
@@ -156,7 +164,7 @@ struct file_triplet
char *name; /* Triplet base name */
gid_t gid; /* Owner GID */
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) */
char *blurb; /* Block of directives: directive[i] points here */
char *tmp; /* Temporary storage */
@@ -179,20 +187,20 @@ struct virt_tab
{
int (*test_url) (mu_url_t url, gconf_locus_t *loc);
int (*move_file) (struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
enum file_type file_id,
const char *reldir);
int (*archive_file) (struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
const char *reldir,
const char *file_name);
int (*symlink_file) (struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
const char *reldir,
const char *wanted_src,
const char *wanted_dst);
int (*rmsymlink_file)(struct file_triplet *trp,
- struct spool *spool,
+ const struct spool *spool,
const char *reldir,
const char *file_name);
};
@@ -201,6 +209,8 @@ struct virt_tab
files from source to destination */
struct spool
{
+ char *tag;
+ gl_list_t aliases;
char *url; /* Download URL */
char *source_dir; /* Source directory */
mu_url_t dest_url; /* Destination URL */
@@ -306,6 +316,15 @@ extern int archive_signatures;
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) \
do \
{ \
@@ -341,10 +360,13 @@ 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);
char *triplet_expand_param (const char *tmpl, struct file_triplet *trp);
@@ -369,12 +391,12 @@ unsigned method_num_cols (struct access_method *method);
/* Verification functions */
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);
/* Directive file support */
@@ -390,9 +412,8 @@ int directive_first (struct file_triplet *trp,
int directive_next (struct file_triplet *trp, int n,
const char **pkey, const char **pval);
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);
int wydawca_uid (uid_t uid);
@@ -410,42 +431,42 @@ void config_help (void);
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,
const char *wanted_src, const char *wanted_dst);
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);
/* diskio.c */
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);
/* 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);
@@ -469,3 +490,17 @@ void report_init (void);
void report_add (const char *fmt, ...);
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);
diff --git a/tests/etc/wydawca.rcin b/tests/etc/wydawca.rcin
index f897cf9..36ef7a2 100644
--- a/tests/etc/wydawca.rcin
+++ b/tests/etc/wydawca.rcin
@@ -76,7 +76,8 @@ access-method gpg-key {
"-----END PGP PUBLIC KEY BLOCK-----\n");
}
-spool ftp://wydawca.test {
+spool test {
+ url ftp://wydawca.test;
source "@WD_SRC@";
destination "@WD_DST@";
archive none;
diff --git a/tests/mailstats.at b/tests/mailstats.at
index b26c832..ff16f2a 100644
--- a/tests/mailstats.at
+++ b/tests/mailstats.at
@@ -19,7 +19,6 @@ AT_SETUP([Simple upload statistics])
AT_DATA([errtmpl],
[wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) started
wydawca: [[NOTICE]] file.directive.asc: COMMENT: Gnupload for Wydawca testsuite
-wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished
wydawca: [[INFO]] errors: 0
wydawca: [[INFO]] warnings: 0
wydawca: [[INFO]] bad signatures: 0
@@ -33,6 +32,7 @@ wydawca: [[INFO]] files uploaded: 2
wydawca: [[INFO]] files archived: 0
wydawca: [[INFO]] symlinks created: 0
wydawca: [[INFO]] symlinks removed: 0
+wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished
])
AT_DATA([expout],
diff --git a/tests/notify-upl.at b/tests/notify-upl.at
index ca57846..9efe1d9 100644
--- a/tests/notify-upl.at
+++ b/tests/notify-upl.at
@@ -19,7 +19,6 @@ AT_SETUP([Simple upload and notification])
AT_DATA([errtmpl],
[wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) started
wydawca: [[NOTICE]] file.directive.asc: COMMENT: Gnupload for Wydawca testsuite
-wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished
wydawca: [[INFO]] errors: 0
wydawca: [[INFO]] warnings: 0
wydawca: [[INFO]] bad signatures: 0
@@ -33,6 +32,7 @@ wydawca: [[INFO]] files uploaded: 2
wydawca: [[INFO]] files archived: 0
wydawca: [[INFO]] symlinks created: 0
wydawca: [[INFO]] symlinks removed: 0
+wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished
])
AT_DATA([outtmpl],
diff --git a/tests/upload-dry.at b/tests/upload-dry.at
index 306f6f3..6ea1f2d 100644
--- a/tests/upload-dry.at
+++ b/tests/upload-dry.at
@@ -19,10 +19,10 @@ AT_SETUP([Dry-run upload])
AT_DATA([template],
[wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) started
wydawca: [[DEBUG]] @WD_SRC@ -> @WD_DST@
-wydawca: [[DEBUG]] file file is a distributive, root file
-wydawca: [[DEBUG]] file file.directive.asc is a signed upload directive, root file
-wydawca: [[DEBUG]] file file.sig is a detached signature, root file
-wydawca: [[DEBUG]] processing files for ftp://wydawca.test (@WD_DST@)
+wydawca: [[DEBUG]] found file file: distributive, stem: file
+wydawca: [[DEBUG]] found file file.directive.asc: signed upload directive, stem: file
+wydawca: [[DEBUG]] found file file.sig: detached signature, stem: file
+wydawca: [[DEBUG]] processing spool test (@WD_DST@)
wydawca: [[DEBUG]] FILE file, DIST=file, SIG=file.sig, DIRECTIVE=file.directive.asc
wydawca: [[NOTICE]] Good signature from Wydawca (Testsuite) <bug-wydawca@gnu.org.ua>
wydawca: [[DEBUG]] file: directive file signature OK
@@ -32,7 +32,6 @@ wydawca: [[NOTICE]] file.directive.asc: COMMENT: Gnupload for Wydawca testsuite
wydawca: [[DEBUG]] good detached signature for file
wydawca: [[DEBUG]] installing file to @WD_DST@/proj
wydawca: [[DEBUG]] installing file.sig to @WD_DST@/proj
-wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished
wydawca: [[INFO]] errors: 0
wydawca: [[INFO]] warnings: 0
wydawca: [[INFO]] bad signatures: 0
@@ -46,6 +45,7 @@ wydawca: [[INFO]] files uploaded: 2
wydawca: [[INFO]] files archived: 0
wydawca: [[INFO]] symlinks created: 0
wydawca: [[INFO]] symlinks removed: 0
+wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished
])
AT_CHECK([
diff --git a/tests/upload.at b/tests/upload.at
index 1f3696c..1968658 100644
--- a/tests/upload.at
+++ b/tests/upload.at
@@ -19,7 +19,6 @@ AT_SETUP([Simple upload])
AT_DATA([template],
[wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) started
wydawca: [[NOTICE]] file.directive.asc: COMMENT: Gnupload for Wydawca testsuite
-wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished
wydawca: [[INFO]] errors: 0
wydawca: [[INFO]] warnings: 0
wydawca: [[INFO]] bad signatures: 0
@@ -33,6 +32,7 @@ wydawca: [[INFO]] files uploaded: 2
wydawca: [[INFO]] files archived: 0
wydawca: [[INFO]] symlinks created: 0
wydawca: [[INFO]] symlinks removed: 0
+wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished
])
AT_CHECK([

Return to:

Send suggestions and report system problems to the System administrator.