diff options
-rw-r--r-- | gconf/gconf-gram.y | 20 | ||||
-rw-r--r-- | gconf/gconf.h | 5 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/cmdline.opt | 48 | ||||
-rw-r--r-- | src/config.c | 40 | ||||
-rw-r--r-- | src/directive.c | 2 | ||||
-rw-r--r-- | src/diskio.c | 14 | ||||
-rw-r--r-- | src/gpg.c | 4 | ||||
-rw-r--r-- | src/job.c | 278 | ||||
-rw-r--r-- | src/mail.c | 15 | ||||
-rw-r--r-- | src/net.c | 227 | ||||
-rw-r--r-- | src/null.c | 22 | ||||
-rw-r--r-- | src/pidfile.c | 90 | ||||
-rw-r--r-- | src/process.c | 66 | ||||
-rw-r--r-- | src/triplet.c | 18 | ||||
-rw-r--r-- | src/verify.c | 4 | ||||
-rw-r--r-- | src/vtab.c | 8 | ||||
-rw-r--r-- | src/wydawca.c | 112 | ||||
-rw-r--r-- | src/wydawca.h | 83 | ||||
-rw-r--r-- | tests/etc/wydawca.rcin | 3 | ||||
-rw-r--r-- | tests/mailstats.at | 2 | ||||
-rw-r--r-- | tests/notify-upl.at | 2 | ||||
-rw-r--r-- | tests/upload-dry.at | 10 | ||||
-rw-r--r-- | tests/upload.at | 2 |
24 files changed, 913 insertions, 166 deletions
diff --git a/gconf/gconf-gram.y b/gconf/gconf-gram.y index a1d9f2a..f7ee710 100644 --- a/gconf/gconf-gram.y +++ b/gconf/gconf-gram.y @@ -503,25 +503,29 @@ string_to_host (struct in_addr *in, const char *string) memcpy (in, hp->h_addr, sizeof (struct in_addr)); } return 0; } static int -string_to_sockaddr (sockaddr_union_t *s, const char *string) +string_to_sockaddr (struct gconf_sockaddr *sp, const char *string) { if (string[0] == '/') { - if (strlen (string) >= sizeof (s->s_un.sun_path)) + struct sockaddr_un s_un; + if (strlen (string) >= sizeof (s_un.sun_path)) { gconf_error (&gconf_current_locus, 0, _("%s: UNIX socket name too long"), string); return 1; } - s->s_un.sun_family = AF_UNIX; - strcpy (s->s_un.sun_path, string); + s_un.sun_family = AF_UNIX; + strcpy (s_un.sun_path, string); + sp->len = sizeof (s_un); + sp->sa = xmalloc (sp->len); + memcpy (sp->sa, &s_un, sp->len); } else { char *p = strchr (string, ':'); size_t len; struct sockaddr_in sa; @@ -580,13 +584,15 @@ string_to_sockaddr (sockaddr_union_t *s, const char *string) sa.sin_port = gconf_default_port; else { gconf_error (&gconf_current_locus, 0, _("missing port number")); return 1; } - s->s_in = sa; + sp->len = sizeof (sa); + sp->sa = xmalloc (sp->len); + memcpy (sp->sa, &sa, sp->len); } return 0; } static int string_convert (void *target, enum gconf_data_type type, const char *string) @@ -686,13 +692,13 @@ string_convert (void *target, enum gconf_data_type type, const char *string) _("%s: not a valid IP address or hostname"), string); return 1; } break; case gconf_type_sockaddr: - return string_to_sockaddr ((sockaddr_union_t*)target, string); + return string_to_sockaddr ((struct gconf_sockaddr *)target, string); /* FIXME: */ case gconf_type_cidr: case gconf_type_section: gconf_error (&gconf_current_locus, 0, _("INTERNAL ERROR at %s:%d"), __FILE__, @@ -717,13 +723,13 @@ size_t gconf_type_size_tab[] = { sizeof (intmax_t) /* gconf_type_intmax */, sizeof (time_t) /* gconf_type_time */, sizeof (int) /* gconf_type_bool */, sizeof (struct in_addr) /* gconf_type_ipv4 */, 0 /* FIXME: gconf_type_cidr */, sizeof (struct in_addr) /* gconf_type_host */, - sizeof (sockaddr_union_t) /* gconf_type_sockaddr */, + sizeof (struct gconf_sockaddr) /* gconf_type_sockaddr */, 0 /* gconf_type_section */ }; #define gconf_type_size_count \ (sizeof (gconf_type_size_tab) / sizeof (gconf_type_size_tab[0])) static void diff --git a/gconf/gconf.h b/gconf/gconf.h index f88e87a..56792a0 100644 --- a/gconf/gconf.h +++ b/gconf/gconf.h @@ -94,12 +94,17 @@ struct gconf_keyword { size_t offset; gconf_callback_fn callback; void *callback_data; struct gconf_keyword *kwd; }; +struct gconf_sockaddr { + int len; + struct sockaddr *sa; +}; + gconf_value_t *gconf_value_dup(gconf_value_t *input); extern void gconf_print_diag(gconf_locus_t *, int, int, const char*); void gconf_warning(gconf_locus_t *locus, int errcode, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); diff --git a/src/Makefile.am b/src/Makefile.am index 7ba9832..903b754 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,14 +22,17 @@ wydawca_SOURCES=\ config.c\ directive.c\ diskio.c\ exec.c\ gpg.c\ interval.c\ + job.c\ meta.c\ method.c\ + net.c\ + pidfile.c\ process.c\ sql.c\ sql.h\ triplet.c\ verify.c\ wydawca.c\ @@ -53,10 +56,11 @@ incdir=$(pkgdatadir)/$(VERSION)/include inc_DATA = $(PP_SETUP_FILE) LDADD=../gconf/libgconf.a ../gnu/libgnu.a @SQLLIB@ @GPGMELIB@ @MAILUTILS_LIBS@ INCLUDES = -I$(top_srcdir)/gconf -I$(top_srcdir)/gnu -I../gnu @MAILUTILS_INCLUDES@ AM_CPPFLAGS= \ -DSYSCONFDIR=\"$(sysconfdir)\"\ + -DLOCALSTATEDIR=\"$(localstatedir)\"\ -DDEFAULT_VERSION_INCLUDE_DIR=\"$(incdir)\"\ -DDEFAULT_INCLUDE_DIR=\"$(pkgdatadir)/include\"\ -DDEFAULT_PREPROCESSOR="$(DEFAULT_PREPROCESSOR)" diff --git a/src/cmdline.opt b/src/cmdline.opt index 53bdd00..b61517b 100644 --- a/src/cmdline.opt +++ b/src/cmdline.opt @@ -15,25 +15,27 @@ with wydawca. If not, see <http://www.gnu.org/licenses/>. */ static struct obstack pp_cmd_stack; static int pp_cmd_stack_init; static gl_list_t source_list; +static gl_list_t tag_list; static bool source_eq (const void *elt1, const void *elt2) { return strcmp ((const char *)elt1, (const char *)elt2) == 0; } int enabled_spool_p (const struct spool *spool) { - if (!source_list) - return 1; - return !!gl_list_search (source_list, spool->source_dir); + if (source_list || tag_list) + return (source_list && gl_list_search (source_list, spool->source_dir)) + || (tag_list && gl_list_search (tag_list, spool->tag)); + return 1; } OPTIONS_BEGIN(gnu, "wydawca", [<wydawca synchronizes files from a set of upload directories with the corresponding distribution sites>], [<UID [UID...]>]) @@ -58,33 +60,67 @@ OPTION(dry-run,n,, BEGIN log_to_stderr = 1; debug_level++; dry_run_mode = 1; END +OPTION(cron,,, + [<force cron mode>]) +BEGIN + cron_option = 1; + log_to_stderr = 0; +END + +OPTION(force,,, + [<force start up even if the pid file already exists>]) +BEGIN + force_startup = 1; +END + +OPTION(foreground,,, + [<foreground mode>]) +BEGIN + foreground_option = 1; +END + +OPTION(single-process,,, + [<single process mode>]) +BEGIN + single_process_option = 1; +END + OPTION(config-file,c,FILE, [<use FILE instead of the default configuration>]) BEGIN conffile = optarg; END +OPTION(spool,S,TAG, + [<process only spool with the given tag>]) +BEGIN + if (!tag_list) + tag_list = gl_list_create_empty (&gl_linked_list_implementation, + source_eq, NULL, + NULL, false); + gl_list_add_last (tag_list, optarg); +END + OPTION(source,s,SOURCE-DIR, [<process only spool with the given source (may be used multiple times)>]) BEGIN if (!source_list) source_list = gl_list_create_empty (&gl_linked_list_implementation, source_eq, NULL, NULL, false); gl_list_add_last (source_list, optarg); END GROUP(Logging) -OPTION(cron,,, - [<log to syslog>]) -ALIAS(syslog) +OPTION(syslog,,, + [<log to syslog>]) BEGIN log_to_stderr = 0; END OPTION(stderr,e,, [<log to stderr>]) diff --git a/src/config.c b/src/config.c index dd444fe..94afb20 100644 --- a/src/config.c +++ b/src/config.c @@ -260,17 +260,12 @@ cb_mailer (enum gconf_callback_command cmd, void *cb_data) { int rc; if (assert_string_arg (locus, cmd, value)) return 1; - if (cmd != gconf_callback_set_value) - { - gconf_error (locus, 0, _("Unexpected block statement")); - return 1; - } rc = mu_mailer_create (&mailer, value->v.string); if (rc) gconf_error (locus, 0, _("cannot create mailer `%s': %s"), value->v.string, mu_strerror (rc)); return rc; } @@ -1082,28 +1077,23 @@ cb_access_method (enum gconf_callback_command cmd, gconf_error (locus, 0, _("invalid use of block statement")); } return 0; } static int -cb_destination_url (enum gconf_callback_command cmd, - gconf_locus_t *locus, - void *varptr, - gconf_value_t *value, - void *cb_data) +cb_url (enum gconf_callback_command cmd, + gconf_locus_t *locus, + void *varptr, + gconf_value_t *value, + void *cb_data) { mu_url_t *purl = varptr, url; int rc; if (assert_string_arg (locus, cmd, value)) return 1; - if (cmd != gconf_callback_set_value) - { - gconf_error (locus, 0, _("Unexpected block statement")); - return 1; - } rc = mu_url_create (&url, value->v.string); if (rc) { gconf_error (locus, 0, _("cannot create URL `%s': %s"), value->v.string, mu_strerror (rc)); return rc; @@ -1119,17 +1109,21 @@ cb_destination_url (enum gconf_callback_command cmd, *purl = url; return 0; } static struct gconf_keyword spool_kw[] = { + { "url", N_("arg"), N_("URL corresponding to this spool"), + gconf_type_string, NULL, offsetof(struct spool, url) }, + { "alias", N_("arg"), N_("Aliases"), + gconf_type_string|GCONF_LIST, NULL, offsetof(struct spool, aliases) }, { "source", N_("dir"), N_("Source directory"), gconf_type_string, NULL, offsetof(struct spool, source_dir) }, { "destination", N_("dir"), N_("Destination directory"), gconf_type_string, NULL, offsetof(struct spool, dest_url), - cb_destination_url }, + cb_url }, { "file-sweep-time", N_("interval"), N_("Define file sweep time"), gconf_type_string, NULL, offsetof(struct spool, file_sweep_time), cb_interval }, { "access-method", N_("ident"), N_("Define access method"), gconf_type_section, NULL, offsetof(struct spool, access_method), cb_access_method, NULL, access_method_kw }, @@ -1161,13 +1155,13 @@ cb_spool (enum gconf_callback_command cmd, if (!value || value->type != GCONF_TYPE_STRING) { gconf_error (locus, 0, _("tag must be a string")); return 1; } spool = xzalloc (sizeof (*spool)); - spool->url = xstrdup (value->v.string); + spool->tag = xstrdup (value->v.string); spool->file_sweep_time = file_sweep_time; for (i = 0; i < NITEMS (spool->access_method); i++) spool->access_method[i] = default_access_method[i]; spool->archive = default_archive_descr; *pdata = spool; break; @@ -1230,12 +1224,24 @@ cb_spool (enum gconf_callback_command cmd, return 0; } static struct gconf_keyword wydawca_kw[] = { + { "daemon", NULL, N_("Enable daemon mode"), + gconf_type_bool, &daemon_mode }, + { "foreground", NULL, N_("Start in foreground even in daemon mode"), + gconf_type_bool, &foreground }, + { "single-process", NULL, N_("Do not spawn subprocesses"), + gconf_type_bool, &single_process }, + { "wakeup-interval", N_("time"), N_("Set wake-up interval"), + gconf_type_string, &wakeup_interval, 0, cb_interval }, + { "pidfile", N_("file"), N_("Set pid file name"), + gconf_type_string, &pidfile }, + { "listen", N_("socket"), N_("Listen on this address"), + gconf_type_sockaddr, &listen_sockaddr, }, { "mailer", N_("url"), N_("Set mailer URL"), gconf_type_string, &mailer, 0, cb_mailer }, { "admin-address", N_("email"), N_("Set admin email address"), gconf_type_string, &admin_address, 0, cb_email_address }, { "from-address", N_("email"), N_("Set sender email address"), gconf_type_string, &from_address, 0, cb_email_address }, diff --git a/src/directive.c b/src/directive.c index 46e3196..37ce241 100644 --- a/src/directive.c +++ b/src/directive.c @@ -299,13 +299,13 @@ verify_directive_format (struct file_triplet *trp) } return 0; } /* Process the directives from TRP, using given SPOOL */ int -process_directives (struct file_triplet *trp, struct spool *spool) +process_directives (struct file_triplet *trp, const struct spool *spool) { int rc, n; const char *key, *val; char *relative_dir; UPDATE_STATS (STAT_COMPLETE_TRIPLETS); diff --git a/src/diskio.c b/src/diskio.c index 69a3cbe..ccff5c2 100644 --- a/src/diskio.c +++ b/src/diskio.c @@ -302,13 +302,13 @@ tar_append_file (const char *archive, const char *file) UID, GID - Ownership RELDIR - Directory part of FILE Do nothing if dry_run_mode is set. */ int backup_file (const char *dst_file, const char *dst_dir, const char *file, - struct archive_descr *archive, uid_t uid, gid_t gid, + const struct archive_descr *archive, uid_t uid, gid_t gid, const char *reldir) { int rc = 0; char *adir; char *file_name; @@ -377,13 +377,13 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file, } /* Select the appropriate backup type and backup a file. See backup_file for the argument description. */ int do_archive_file (const char *dst_file, const char *dst_dir, const char *file, - struct archive_descr *archive, uid_t uid, gid_t gid, + const struct archive_descr *archive, uid_t uid, gid_t gid, const char *reldir) { switch (archive->type) { case archive_none: break; @@ -407,13 +407,13 @@ do_archive_file (const char *dst_file, const char *dst_dir, const char *file, /* Move the part FILE_ID of the triplet TRP between the directories in DPAIR. RELDIR gives relative directory (i.e. the directory part of the file name) for backup purposes. Do nothing if dry_run_mode is set. */ int -dir_move_file (struct file_triplet *trp, struct spool *spool, +dir_move_file (struct file_triplet *trp, const struct spool *spool, enum file_type file_id, const char *reldir) { char *dst_file; int rc = 0; char *dst_dir = create_directory (spool->dest_dir, reldir, TRIPLET_UID (trp), TRIPLET_GID (trp)); @@ -444,13 +444,13 @@ dir_move_file (struct file_triplet *trp, struct spool *spool, /* Archive the file FILE_NAME, located in DPAIR->dest_dir, and remove the file. Get user IDs from the triplet TRP. Do nothing if dry_run_mode is set. */ int -archive_single_file (struct file_triplet *trp, struct spool *spool, +archive_single_file (struct file_triplet *trp, const struct spool *spool, const char *file_name, const char *reldir, int noentok) { char *dst_file; int rc = 0; char *dst_dir = create_directory (spool->dest_dir, reldir, @@ -514,13 +514,13 @@ make_signame (const char *file_name) /* Archive the file FILE_NAME, located in DPAIR->dest_dir, and remove the file. Get user IDs from the triplet TRP. Unless FILE_NAME ends in ".sig", do the same with FILE_NAME.sig, if such a file exists. Do nothing if dry_run_mode is set. */ int -dir_archive_file (struct file_triplet *trp, struct spool *spool, +dir_archive_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *file_name) { int rc; char *signame; rc = archive_single_file (trp, spool, file_name, reldir, 0); @@ -534,13 +534,13 @@ dir_archive_file (struct file_triplet *trp, struct spool *spool, /* Create a symbolic link from WANTED_SRC to WANTED_DST in the subdirectory RELDIR of DPAIR->dest_dir. Get ownership information from TRP. Do nothing if dry_run_mode is set. */ int -dir_symlink_file (struct file_triplet *trp, struct spool *spool, +dir_symlink_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *wanted_src, const char *wanted_dst) { int rc = 0; struct saved_cwd cwd; char *dst_dir = create_directory (spool->dest_dir, reldir, @@ -694,13 +694,13 @@ do_rmsymlink_file (const char *dst_file, int noentok) /* Remove the symbolic link DPAIR->dest_dir/RELDIR/FILE_NAME Get ownership information from TRP. Do nothing if dry_run_mode is set. */ int -dir_rmsymlink_file (struct file_triplet *trp, struct spool *spool, +dir_rmsymlink_file (struct file_triplet *trp, const struct spool *spool, const char *reldir, const char *file_name) { char *dst_file; int rc = 0; char *signame; char *dst_dir = create_directory (spool->dest_dir, reldir, @@ -200,13 +200,13 @@ gpg_sig_ok_p (gpgme_ctx_t ctx, gpgme_signature_t sig) } /* Verify the directive file from TRP using public key PUBKEY */ /* FIXME: spool currently unused */ int verify_directive_signature (struct file_triplet *trp, - struct spool *spool, const char *pubkey) + const struct spool *spool, const char *pubkey) { gpgme_ctx_t ctx; gpgme_data_t key_data, directive_data, plain; off_t size; gpgme_error_t ec; int rc; @@ -258,13 +258,13 @@ verify_directive_signature (struct file_triplet *trp, /* Verify the detached signature of TRP. NOTE: It is assumed that the public key is already registered (by a previous call to verify_directive_signature). */ int verify_detached_signature (struct file_triplet *trp, - struct spool *spool) + const struct spool *spool) { gpgme_engine_info_t info; const char *argv[5]; fail_if_err (gpgme_get_engine_info (&info)); while (info && info->protocol != GPGME_PROTOCOL_OpenPGP) diff --git a/src/job.c b/src/job.c new file mode 100644 index 0000000..9678139 --- /dev/null +++ b/src/job.c @@ -0,0 +1,278 @@ +/* wydawca - automatic release submission daemon + Copyright (C) 2009 Sergey Poznyakoff + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" + +#define STATE_FINISHED 0x01 +#define STATE_QUEUED 0x02 +#define STATE_ACTIVE 0x04 + +struct job +{ + struct job *next, *prev; + int state; + const struct spool *spool; + uid_t uid; + pid_t pid; + time_t timestamp; + int exit_status; +}; + +struct job *queue; +size_t jobmax; +size_t jobcnt; + +struct job * +job_locate (const struct spool *spool, uid_t uid) +{ + struct job *p; + for (p = queue; p; p = p->next) + if (p->spool == spool && p->uid == uid) + break; + return p; +} + +size_t +job_active_count () +{ + struct job *job; + size_t count = 0; + for (job = queue; job; job = job->next) + if (job->state & STATE_ACTIVE) + count++; + return count; +} + +void +wydawca_scanner (struct job *job) +{ + scan_spool (job->spool, 1, &job->uid); + mail_finish (); +} + +int +job_start (struct job *job) +{ + pid_t pid; + + if (jobmax && jobcnt == jobmax) + { + logmsg (LOG_NOTICE, "maximum number of processes active"); + return 1; + } + + if (debug_level) + logmsg (LOG_DEBUG, _("starting job: %s, %lu"), job->spool->tag, job->uid); + + if (single_process) + { + wydawca_scanner (job); + return 0; + } + + pid = fork (); + if (pid == 0) + { + wydawca_scanner (job); + exit (0); + } + else if (pid == -1) + { + logmsg (LOG_CRIT, "fork: %s", strerror (errno)); + return -1; + } + else + { + job->state = STATE_ACTIVE; + job->pid = pid; + jobcnt++; + } + return 0; +} + +void +job_remove (struct job *job) +{ + struct job *p; + + if (debug_level) + logmsg (LOG_DEBUG, _("removing job: %s, %lu"), job->spool->tag, job->uid); + p = job->prev; + if (p) + p->next = job->next; + else + queue = job->next; + + p = job->next; + if (p) + p->prev = job->prev; +} + +void +job_insert (struct job *job, struct job *elt) +{ + struct job *p; + + job->prev = elt; + if (!elt) + { + if (queue) + queue->prev = job; + job->next = queue; + queue = job; + return; + } + + p = elt->next; + elt->next = job; + + if (p) + p->prev = job; +} + +int +schedule_job (const struct spool *spool, uid_t uid) +{ + struct job *job; + + if (debug_level) + logmsg (LOG_DEBUG, _("scheduling job: %s, %lu"), spool->tag, uid); + + job = job_locate (spool, uid); + if (!job) + { + job = xzalloc (sizeof (*job)); + job->spool = spool; + job->uid = uid; + job->pid = -1; + time (&job->timestamp); + job_insert (job, NULL); + } + + job->state |= STATE_QUEUED; + job_start (job); +} + +static void +print_status (struct job *job, int expect_term) +{ + struct passwd *pw = getpwuid (job->uid); + int status = job->exit_status; + + if (WIFEXITED (status)) + { + if (WEXITSTATUS (status) == 0) + { + if (debug_level) + logmsg (LOG_DEBUG, + _("%lu (%s, %s) exited successfully"), + (unsigned long) job->pid, job->spool->tag, pw->pw_name); + } + else + logmsg (LOG_ERR, + _("%lu (%s, %s) failed with status %d"), + (unsigned long) job->pid, job->spool->tag, pw->pw_name, + WEXITSTATUS (status)); + } + else if (WIFSIGNALED (status)) + { + int prio; + if (expect_term && WTERMSIG (status) == SIGTERM) + { + if (!debug_level) + return; + prio = LOG_DEBUG; + } + else + prio = LOG_ERR; + + logmsg (prio, + _("%lu (%s, %s) terminated on signal %d"), + job->pid, job->spool->tag, pw->pw_name, WTERMSIG (status)); + } + else if (WIFSTOPPED (status)) + logmsg (LOG_NOTICE, + _("%lu (%s, %s) stopped on signal %d"), + job->pid, job->spool->tag, pw->pw_name, WSTOPSIG (status)); +#ifdef WCOREDUMP + else if (WCOREDUMP (status)) + logmsg (LOG_NOTICE, + _("%lu (%s, %s) dumped core"), + job->pid, job->spool->tag, pw->pw_name); +#endif + else + logmsg (LOG_ERR, + _("%lu (%s, %s) terminated with unrecognized status"), + job->pid, job->spool->tag, pw->pw_name); +} + +static int wakeup; + +RETSIGTYPE +queue_signal (int sig) +{ + wakeup = 1; + signal (sig, queue_signal); +} + +void +job_queue_runner () +{ + int status; + struct job *job; + + if (!wakeup) + return; + wakeup = 0; + + for (;;) + { + pid_t pid = waitpid ((pid_t)-1, &status, WNOHANG); + if (pid <= 0) + break; + for (job = queue; job; job = job->next) + { + if ((job->state & STATE_ACTIVE) && job->pid == pid) + { + job->state &= ~STATE_ACTIVE; + job->state |= STATE_FINISHED; + job->exit_status = status; + jobcnt--; + } + } + } + + for (job = queue; job;) + { + struct job *next = job->next; + if (job->state & STATE_FINISHED) + { + print_status (job, 0); + if ((job->state &= ~STATE_FINISHED) == 0) + job_remove (job); + } + if (job->state == STATE_QUEUED) + if (job_start (job)) + pause (); + job = next; + } +} + +void +job_init () +{ + signal (SIGCHLD, queue_signal); +} @@ -101,13 +101,16 @@ mail_send_message (mu_address_t rcpt, const char *text) } void mail_finish () { if (mailer_opened) - mu_mailer_close (mailer); + { + mu_mailer_close (mailer); + mailer_opened = 0; + } } struct message_template { char *name; @@ -266,43 +269,43 @@ get_recipient (struct access_method *method, struct file_triplet *trp, char *text; int rc; void *md; if (method->type == method_none) { - *errp = "access method is not configured"; + *errp = N_("access method is not configured"); return NULL; } md = method_open (method); if (!md) { - *errp = "failed to open access method"; + *errp = N_("failed to open access method"); return NULL; } make_default_meta (def, trp->user, trp->project); meta_escape (method, md, def); text = meta_expand_string (method->query, def, NULL); meta_free (def); rc = method_run (method, md, text); free (text); if (rc) { - *errp = "cannot obtain recipient emails"; + *errp = N_("cannot obtain recipient emails"); method_close (method, md); return NULL; } nrows = method_num_rows (method); ncols = method_num_cols (method); if (nrows == 0) { - *errp = "cannot obtain recipient emails"; + *errp = N_("cannot obtain recipient emails"); return NULL; } for (i = 0; i < nrows; i++) { mu_address_t addr; @@ -347,13 +350,13 @@ do_notify (struct file_triplet *trp, enum notification_event ev, if (!rcpt) { logmsg (LOG_ERR, _("not notifying %s (project %s) about %s: %s"), notification_target_str (ntf->tgt), trp->project, - notification_event_str (ev), errp); + notification_event_str (ev), gettext (errp)); return; } if (debug_level) { size_t size; diff --git a/src/net.c b/src/net.c new file mode 100644 index 0000000..efb6225 --- /dev/null +++ b/src/net.c @@ -0,0 +1,227 @@ +/* wydawca - automatic release submission daemon + Copyright (C) 2007, 2009 Sergey Poznyakoff + + Wydawca is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Wydawca is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with wydawca. If not, see <http://www.gnu.org/licenses/>. */ + +#include "wydawca.h" + +static int +open_listener () +{ + int fd; + + if (listen_sockaddr.sa == NULL) + { + logmsg (LOG_CRIT, _("listener address is not configured")); + exit (1); + } + + fd = socket (listen_sockaddr.sa->sa_family, SOCK_STREAM, 0); + if (fd == -1) + { + logmsg (LOG_CRIT, _("cannot create socket: %s"), + strerror(errno)); + exit (1); + } + if (listen_sockaddr.sa->sa_family == AF_UNIX) + { + struct stat st; + struct sockaddr_un *s_un = (struct sockaddr_un *) listen_sockaddr.sa; + if (stat (s_un->sun_path, &st)) + { + if (errno != ENOENT) + { + logmsg (LOG_CRIT, _("%s: cannot stat socket: %s"), + s_un->sun_path, strerror (errno)); + exit (1); + } + } + else + { + /* FIXME: Check permissions? */ + if (!S_ISSOCK (st.st_mode)) + { + logmsg (LOG_CRIT, _("%s: not a socket"), + s_un->sun_path, strerror (errno)); + exit (1); + } + unlink (s_un->sun_path); + } + /* FIXME: Setup umask */ + } + else + { + int yes = 1; + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof(yes)); + } + + if (bind (fd, listen_sockaddr.sa, listen_sockaddr.len) < 0) + { + logmsg (LOG_CRIT, _("cannot bind to local address: %s"), + strerror (errno)); + close (fd); + exit (1); + } + if (listen (fd, 8) == -1) + { + logmsg (LOG_CRIT, "listen: %s", strerror (errno)); + close (fd); + exit (1); + } + + return fd; +} + +static void +trim_crlf (char *s) +{ + size_t len = strlen (s); + if (len > 0 && s[len-1] == '\n') + { + s[--len] = 0; + if (len > 0 && s[len-1] == '\r') + s[--len] = 0; + } +} + +void +handle_connection (FILE *fp) +{ + char *buf = NULL; + size_t buflen = 0; + const struct spool *spool; + char *p; + struct passwd *pw; + + if (getline (&buf, &buflen, fp) <= 0) + return; + trim_crlf (buf); + if (debug_level) + logmsg (LOG_DEBUG, "recv: %s", buf); |