diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-24 18:45:51 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-24 18:45:51 +0200 |
commit | c9178a6fef0184baed0e8456bb6c6d4091b4997c (patch) | |
tree | 0c97d7aeb6235a469cd071d7d0b589f45a9d35f6 | |
parent | b1472caae9a1b6905b6bbe42e69539b29febcf5c (diff) | |
download | wydawca-c9178a6fef0184baed0e8456bb6c6d4091b4997c.tar.gz wydawca-c9178a6fef0184baed0e8456bb6c6d4091b4997c.tar.bz2 |
Implement locking
* src/lock.c: New file.
* gnulib.modules (sysexits, xgethostname): New modules.
* src/lock.c: New file.
* src/Makefile.am: Add lock.c
* src/config.c: Locking keywords.
* src/job.c: Requeue jobs if locking fails.
* src/wydawca.c (wydawca_uid): Rename to wydawca_set_uid
(main): Implement restart.
* src/process.c (scan_spool, scan_all_spools): Use locking, if configured.
* src/directive.c, src/diskio.c, src/triplet.c: Rename
wydawca_uid
* src/exec.c, src/getopt.m4, src/net.c,
src/pidfile.c: Use standard error codes from sysexits.h
* tests/etc/wydawca.rcin: Disable locking.
-rw-r--r-- | gnulib.modules | 4 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/config.c | 8 | ||||
-rw-r--r-- | src/directive.c | 4 | ||||
-rw-r--r-- | src/diskio.c | 6 | ||||
-rw-r--r-- | src/exec.c | 2 | ||||
-rw-r--r-- | src/getopt.m4 | 2 | ||||
-rw-r--r-- | src/job.c | 45 | ||||
-rw-r--r-- | src/lock.c | 239 | ||||
-rw-r--r-- | src/net.c | 14 | ||||
-rw-r--r-- | src/pidfile.c | 10 | ||||
-rw-r--r-- | src/process.c | 25 | ||||
-rw-r--r-- | src/triplet.c | 4 | ||||
-rw-r--r-- | src/wydawca.c | 50 | ||||
-rw-r--r-- | src/wydawca.h | 27 | ||||
-rw-r--r-- | tests/etc/wydawca.rcin | 2 |
16 files changed, 391 insertions, 52 deletions
diff --git a/gnulib.modules b/gnulib.modules index 1c56638..3dbc445 100644 --- a/gnulib.modules +++ b/gnulib.modules @@ -9,10 +9,12 @@ error progname getline mkdtemp save-cwd backupfile strerror +sysexits vasprintf inttostr strftime -version-etc
\ No newline at end of file +version-etc +xgethostname diff --git a/src/Makefile.am b/src/Makefile.am index 903b754..fcfdb78 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,12 +23,13 @@ wydawca_SOURCES=\ directive.c\ diskio.c\ exec.c\ gpg.c\ interval.c\ job.c\ + lock.c\ meta.c\ method.c\ net.c\ pidfile.c\ process.c\ sql.c\ diff --git a/src/config.c b/src/config.c index facfcbc..bab1ed3 100644 --- a/src/config.c +++ b/src/config.c @@ -1234,12 +1234,20 @@ static struct gconf_keyword wydawca_kw[] = { { "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 }, + + { "locking", NULL, N_("Enable or disable locking"), + gconf_type_bool, &enable_locking }, + { "lockdir", N_("dir"), N_("Set directory for lock files"), + gconf_type_string, &lockdir }, + { "lock-expire-time", N_("interval"), N_("Define lock expiration interval"), + gconf_type_string, &lock_expire_time, 0, cb_interval }, + { "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 }, diff --git a/src/directive.c b/src/directive.c index 37ce241..ccea1ef 100644 --- a/src/directive.c +++ b/src/directive.c @@ -334,15 +334,15 @@ process_directives (struct file_triplet *trp, const struct spool *spool) trp->file[file_directive].name, val); return 1; } break; case filename_dir: - wydawca_uid (0); + wydawca_set_uid (0); rc = verify_detached_signature (trp, spool); - wydawca_uid (TRIPLET_UID (trp)); + wydawca_set_uid (TRIPLET_UID (trp)); if (rc == 0) { if (move_file (trp, spool, file_dist, relative_dir) || move_file (trp, spool, file_signature, relative_dir)) return 1; } diff --git a/src/diskio.c b/src/diskio.c index ccff5c2..c068e49 100644 --- a/src/diskio.c +++ b/src/diskio.c @@ -121,15 +121,15 @@ create_directory (const char *base, const char *name, uid_t uid, gid_t gid) size_t baselen; char *dir = concat_dir (base, name, &baselen); if (!dry_run_mode) { int rc; - wydawca_uid (0); + wydawca_set_uid (0); rc = create_hierarchy (dir, baselen, uid, gid); - wydawca_uid (uid); + wydawca_set_uid (uid); if (rc) { free (dir); dir = NULL; } } @@ -644,13 +644,13 @@ dir_symlink_file (struct file_triplet *trp, const struct spool *spool, } if (restore_cwd (&cwd)) { logmsg (LOG_EMERG, _("cannot restore current directory: %s"), strerror (errno)); - exit (1); + exit (EX_SOFTWARE); } free (src); free (dst); free (dst_dir); if (rc == 0) @@ -46,13 +46,13 @@ start_prog (int argc, const char **argv, pid_t *ppid) /* Close unneded descripitors */ for (i = getdtablesize (); i > 2; i--) close (i); execvp (argv[0], (char**) argv); logmsg (LOG_CRIT, _("cannot run %s: %s"), argv[0], strerror (errno)); - exit (1); + exit (EX_UNAVAILABLE); case -1: logmsg (LOG_CRIT, _("cannot run `%s': fork failed: %s"), argv[0], strerror (errno)); return NULL; diff --git a/src/getopt.m4 b/src/getopt.m4 index 83cc45f..2cd9a0f 100644 --- a/src/getopt.m4 +++ b/src/getopt.m4 @@ -176,13 +176,13 @@ ifelse([<$#>],3,opterr = 0;) while ((c = getopt_long($1, $2, "SHORT_OPTS", long_options, NULL)) != EOF) { switch (c) { default: - ifelse([<$#>],3,$3,[<exit(1)>]); + ifelse([<$#>],3,$3,[<exit (EX_USAGE)>]); undivert(4) } } } >]) @@ -35,12 +35,21 @@ struct job struct job *queue; size_t jobmax; size_t jobcnt; static struct spool fake_spool = { "all spools" }; +static int wakeup; + +RETSIGTYPE +queue_signal (int sig) +{ + wakeup = 1; + signal (sig, queue_signal); +} + 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) @@ -56,27 +65,29 @@ job_active_count () for (job = queue; job; job = job->next) if (job->state & STATE_ACTIVE) count++; return count; } -void +int wydawca_scanner (struct job *job) { + int rc; initstats(); timer_start ("wydawca"); if (job->spool == &fake_spool) - scan_all_spools (1, &job->uid); + rc = scan_all_spools (1, &job->uid); else { spool_create_timers (); - scan_spool (job->spool, 1, &job->uid); + rc = scan_spool (job->spool, 1, &job->uid); } timer_stop ("wydawca"); mail_finish (); logstats (); + return rc; } int job_start (struct job *job) { pid_t pid; @@ -89,21 +100,23 @@ job_start (struct job *job) if (debug_level) logmsg (LOG_DEBUG, _("starting job: %s, %lu"), job->spool->tag, job->uid); if (single_process) { - wydawca_scanner (job); - return 0; + if (wydawca_scanner (job)) + job->state = STATE_QUEUED; + else + job->state = STATE_FINISHED; + wakeup = 1; } pid = fork (); if (pid == 0) { - wydawca_scanner (job); - exit (0); + exit (wydawca_scanner (job) ? WYDAWCA_EX_AGAIN : 0); } else if (pid == -1) { logmsg (LOG_CRIT, "fork: %s", strerror (errno)); return -1; } @@ -232,21 +245,12 @@ print_status (struct job *job, int expect_term) 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; @@ -275,13 +279,20 @@ job_queue_runner () { struct job *next = job->next; if (job->state & STATE_FINISHED) { print_status (job, 0); if ((job->state &= ~STATE_FINISHED) == 0) - job_remove (job); + { + if (WIFEXITED (job->exit_status) + && WEXITSTATUS (job->exit_status) == WYDAWCA_EX_AGAIN) + /* Re-queue the job */ + job->state = STATE_QUEUED; + else + job_remove (job); + } } if (job->state == STATE_QUEUED) if (job_start (job)) pause (); job = next; } diff --git a/src/lock.c b/src/lock.c new file mode 100644 index 0000000..d94731c --- /dev/null +++ b/src/lock.c @@ -0,0 +1,239 @@ +/* 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" +#include "c-ctype.h" +#include "xgethostname.h" + +int enable_locking = 1; +char *lockdir; +time_t lock_expire_time; + +#define LOCKFILE_MODE 0644 + +static int +stat_check (const char *file, int fd, int links) +{ + struct stat fn_stat; + struct stat fd_stat; + int err = 0; + int localfd = -1; + + if (fd == -1) + { + localfd = open (file, O_RDONLY); + + if (localfd == -1) + return errno; + fd = localfd; + } + + /* We should always be able to stat a valid fd, so this + is an error condition. */ + if (lstat (file, &fn_stat) || fstat (fd, &fd_stat)) + err = errno; + else + { + /* If the link and stat don't report the same info, or the + file is a symlink, fail the locking. */ +#define CHK(X) if(X) err = EINVAL + + CHK (!S_ISREG (fn_stat.st_mode)); + CHK (!S_ISREG (fd_stat.st_mode)); + CHK (fn_stat.st_nlink != links); + CHK (fn_stat.st_dev != fd_stat.st_dev); + CHK (fn_stat.st_ino != fd_stat.st_ino); + CHK (fn_stat.st_mode != fd_stat.st_mode); + CHK (fn_stat.st_nlink != fd_stat.st_nlink); + CHK (fn_stat.st_uid != fd_stat.st_uid); + CHK (fn_stat.st_gid != fd_stat.st_gid); + CHK (fn_stat.st_rdev != fd_stat.st_rdev); + +#undef CHK + } + if (localfd != -1) + close (localfd); + + return err; +} + +int +_lock_internal (const char *file, const char *fname) +{ + int err = 0; + int fd; + FILE *fp; + + fd = open (fname, O_WRONLY | O_CREAT | O_EXCL, LOCKFILE_MODE); + if (fd == -1) + { + if (errno == EEXIST) + return LOCK_RETRY; + else + { + logmsg (LOG_ERR, _("cannot create lock file %s: %s"), + fname, strerror (errno)); + return LOCK_FAILURE; + } + } + close (fd); + + /* Try to link to the lockfile. */ + if (link (fname, file) == -1) + { + unlink (fname); + if (errno == EEXIST) + return LOCK_RETRY; + else + { + logmsg (LOG_ERR, _("cannot create lock file %s: %s"), + file, strerror (errno)); + return LOCK_FAILURE; + } + } + + if ((fd = open (file, O_RDWR)) == -1) + { + unlink (fname); + logmsg (LOG_ERR, _("cannot open lock file %s: %s"), + fname, strerror (errno)); + return LOCK_FAILURE; + } + + err = stat_check (fname, fd, 2); + if (err) + { + unlink (fname); + logmsg (LOG_ERR, _("lock file check failed: %s"), strerror (errno)); + return (err == EINVAL) ? LOCK_INVALID : LOCK_FAILURE; + } + + unlink (fname); + + fp = fdopen (fd, "w"); + fprintf (fp, "%lu", (unsigned long) getpid ()); + fclose (fp); + + return 0; +} + +static void +expire_stale_lock (const char *file) +{ + int stale = 0; + char buf[80]; + int fd; + int len; + + fd = open (file, O_RDONLY); + if (fd == -1) + return; + + len = read (fd, buf, sizeof (buf) - 1); + if (len > 0) + { + pid_t pid; + + buf[len] = 0; + pid = strtoul (buf, NULL, 10); + if (pid > 0) + { + /* Process is gone so we try to remove the lock. */ + if (kill (pid, 0) == -1) + stale = 1; + } + else + stale = 1; /* Corrupted file, remove the lock. */ + } + + if (!stale) + { + struct stat stbuf; + fstat (fd, &stbuf); + /* The lock has expired. */ + if ((time (NULL) - stbuf.st_mtime) > lock_expire_time) + stale = 1; + } + + close (fd); + if (stale) + unlink (file); +} + +int +wydawca_lock (const char *lockname) +{ + char *tempname = NULL; + int rc; + + if (!enable_locking) + return 0; + expire_stale_lock (lockname); + + /* build the NFS hitching-post to the lock file */ + asprintf (&tempname, "%s.%lu.%lu.%s", + lockname, + (unsigned long) getpid (), + (unsigned long) time (NULL), xgethostname ()); + if (!tempname) + return LOCK_FAILURE; + rc = _lock_internal (lockname, tempname); + free (tempname); + return rc; +} + +void +wydawca_unlock (const char *lockfile) +{ + if (enable_locking) + unlink (lockfile); +} + +static char * +fix_tagname (const char *tag) +{ + char *tagname = xstrdup (tag); + char *p; + + for (p = tagname; *p; p++) + if (!c_isalnum (*p) && *p != '_' && *p != '-') + *p = '_'; + return tagname; +} + +char * +wydawca_lockname (const char *tag) +{ + char *lockname = NULL; + char *tagname = fix_tagname (tag); + asprintf (&lockname, "%s/LCK.%s", lockdir, tagname); + if (!lockname) + xalloc_die (); + free (tagname); + return lockname; +} + +void +wydawca_lock_init () +{ + if (enable_locking) + { + if (!lockdir) + lockdir = xstrdup (LOCALSTATEDIR "/lock/" PACKAGE); + if (create_hierarchy (lockdir, 0, getuid (), getgid ())) + exit (EX_OSFILE); + } +} @@ -21,43 +21,43 @@ open_listener () { int fd; if (listen_sockaddr.sa == NULL) { logmsg (LOG_CRIT, _("listener address is not configured")); - exit (1); + exit (EX_CONFIG); } fd = socket (listen_sockaddr.sa->sa_family, SOCK_STREAM, 0); if (fd == -1) { logmsg (LOG_CRIT, _("cannot create socket: %s"), strerror(errno)); - exit (1); + exit (EX_OSERR); } 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); + exit (errno == EACCES ? EX_NOPERM : EX_OSERR); } } 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); + exit (EX_OSFILE); } unlink (s_un->sun_path); } /* FIXME: Setup umask */ } else @@ -68,19 +68,19 @@ open_listener () 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); + exit (EX_OSERR); } if (listen (fd, 8) == -1) { logmsg (LOG_CRIT, "listen: %s", strerror (errno)); close (fd); - exit (1); + exit (EX_OSERR); } return fd; } static void @@ -152,13 +152,13 @@ handle_connection (FILE *fp) schedule_job (spool, pw->pw_uid); else logmsg (LOG_ERR, "no such user: %s", buf); free (buf); } -static int reconfigure; +int reconfigure; static int terminate; RETSIGTYPE sig_hup (int sig) { reconfigure = 1; diff --git a/src/pidfile.c b/src/pidfile.c index 484cabd..6da84f1 100644 --- a/src/pidfile.c +++ b/src/pidfile.c @@ -35,54 +35,54 @@ check_pidfile () { unsigned long pid; if (fscanf (fp, "%ul\n", &pid) != 1) { logmsg (LOG_ERR, _("malformed pidfile %s"), pidfile); if (!force_startup) - exit (1); + exit (EX_UNAVAILABLE); } 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); + exit (EX_UNAVAILABLE); } } else if (!force_startup) { logmsg (LOG_ERR, _("another wydawca instance may be running (PID %lu)"), pid); - exit (1); + exit (EX_UNAVAILABLE); } } 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); + exit (EX_UNAVAILABLE); } else { fp = fopen (pidfile, "w"); if (!fp) { logmsg (LOG_ERR, _("cannot open pidfile %s for writing: %s"), pidfile, strerror (errno)); - exit (1); + exit (EX_UNAVAILABLE); } } fprintf (fp, "%lu\n", getpid ()); fclose (fp); atexit (remove_pidfile); } diff --git a/src/process.c b/src/process.c index 1a6b01d..d04121c 100644 --- a/src/process.c +++ b/src/process.c @@ -134,13 +134,13 @@ match_uid_p (uid_t uid, int uc, uid_t *uv) return 0; } /* Scan upload directory from the DPAIR and register all files found there, forming triplets when possible */ void -scan_spool (const struct spool *spool, int uc, uid_t *uv) +scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv) { DIR *dir; struct dirent *ent; if (debug_level) logmsg (LOG_DEBUG, "%s -> %s", spool->source_dir, @@ -222,34 +222,51 @@ scan_spool (const struct spool *spool, int uc, uid_t *uv) enumerate_triplets (spool); } timer_stop (spool->tag); timer_stop ("spool"); } +int +scan_spool (const struct spool *spool, int uc, uid_t *uv) +{ + char *lockfile = wydawca_lockname (spool->tag); + int rc = wydawca_lock (lockfile); + if (rc == LOCK_OK) + { + scan_spool_unlocked (spool, uc, uv); + wydawca_unlock (lockfile); + } + free (lockfile); + return rc; +} + static void close_methods (struct spool *spool) { int i; for (i = 0; i < NITEMS (spool->access_method); i++) method_done (spool->access_method[i]); } /* Scan all configured update directories */ -void +int scan_all_spools (int uidc, uid_t *uidv) { struct spool_list *sp; - + int rc = 0; + timer_start ("wydawca"); for (sp = spool_list; sp; sp = sp->next) if (enabled_spool_p (&sp->spool)) - scan_spool (&sp->spool, uidc, uidv); + if (scan_spool (&sp->spool, uidc, uidv)) + rc++; for (sp = spool_list; sp; sp = sp->next) close_methods (&sp->spool); timer_stop ("wydawca"); + return rc; } void spool_create_timers () { struct spool_list *sp; diff --git a/src/triplet.c b/src/triplet.c index 717fd2a..285c831 100644 --- a/src/triplet.c +++ b/src/triplet.c @@ -196,16 +196,16 @@ triplet_processor (void *data, void *proc_data) switch (check_triplet_state (trp)) { case triplet_directive: case triplet_complete: if (debug_level) logmsg (LOG_DEBUG, _("processing triplet `%s'"), trp->name); - if (wydawca_uid (TRIPLET_UID (trp)) == 0) + if (wydawca_set_uid (TRIPLET_UID (trp)) == 0) { process_directives (trp, spool); - wydawca_uid (0); + wydawca_set_uid (0); } return true; case triplet_incomplete: if (debug_level) logmsg (LOG_DEBUG, _("%s: incomplete triplet"), trp->name); diff --git a/src/wydawca.c b/src/wydawca.c index f9818ed..b121959 100644 --- a/src/wydawca.c +++ b/src/wydawca.c @@ -252,24 +252,24 @@ collect_uids (int argc, char **argv) { char *p; unsigned n = strtoul (argv[i], &p, 10); if (*p) { logmsg (LOG_ERR, _("no such user: %s"), argv[i]); - exit (1); + exit (EX_NOUSER); } uidv[i] = n; } else uidv[i] = pw->pw_uid; } } int -wydawca_uid (uid_t uid) +wydawca_set_uid (uid_t uid) { int rc; if (getuid () != 0) return 0; #if defined(HAVE_SETREUID) @@ -284,22 +284,47 @@ wydawca_uid (uid_t uid) if (rc < 0) logmsg (LOG_ERR, _("cannot switch to UID %d: %s (r=%d, e=%d)"), uid, strerror (errno), getuid (), geteuid ()); return rc; } +int +wydawca_set_gid (gid_t gid) +{ + int rc; + + if (getuid () != 0) + return 0; +#if defined(HAVE_SETREGID) + rc = setregid (0, gid); +#elif defined(HAVE_SETRESGID) + rc = setresgid (-1, gid, -1); +#elif defined(HAVE_SETEGID) + rc = setegid (gid); +#else +# error "No way to reset user privileges?" +#endif + if (rc < 0) + logmsg (LOG_ERR, _("cannot switch to GID %d: %s (r=%d, e=%d)"), + gid, strerror (errno), getgid (), getegid ()); + return rc; +} + +char **x_argv; +extern int reconfigure; + void wydawca_daemon () { check_pidfile (); if (!foreground && daemon (0, 0)) { logmsg (LOG_ERR, "%s", strerror (errno)); - exit (1); + exit (EX_OSERR); } wydawca_listener (); } @@ -309,24 +334,26 @@ int main (int argc, char **argv) { program_name = argv[0]; mu_register_all_mailer_formats (); config_init (); + x_argv = argv; parse_options (argc, argv); argv += optind; argc -= optind; if (argc) collect_uids (argc, argv); if (preprocess_only) - exit (gconf_preproc_run (conffile, gconf_preprocessor)); + exit (gconf_preproc_run (conffile, gconf_preprocessor) ? EX_CONFIG : 0); - gconf_parse (conffile); + if (gconf_parse (conffile)) + exit (EX_CONFIG); if (lint_mode) exit (0); if (cron_option) daemon_mode = 0; @@ -343,13 +370,14 @@ main (int argc, char **argv) { openlog (syslog_tag, LOG_PID, log_facility); log_printer = syslog_printer; } mail_init (); - + wydawca_lock_init (); + logmsg (LOG_NOTICE, _("wydawca (%s) started"), PACKAGE_STRING); if (!daemon_mode) { scan_all_spools (uidc, uidv); logstats (); @@ -358,8 +386,18 @@ main (int argc, char **argv) wydawca_daemon (); logmsg (LOG_NOTICE, _("wydawca (%s) finished"), PACKAGE_STRING); mail_finish (); + if (reconfigure) + { + int i; + wydawca_set_uid (0); + for (i = getdtablesize (); i > 2; i--) + close (i); + remove_pidfile (); + execv (x_argv[0], x_argv); + } + exit (0); } diff --git a/src/wydawca.h b/src/wydawca.h index 6384738..f093504 100644 --- a/src/wydawca.h +++ b/src/wydawca.h @@ -37,12 +37,13 @@ #include <sys/un.h> #include <sys/wait.h> #include <netdb.h> #include <arpa/inet.h> #include <fcntl.h> #include <time.h> +#include <sysexits.h> #include <mailutils/types.h> #include <mailutils/url.h> #include <mailutils/errno.h> #define obstack_chunk_alloc malloc @@ -60,12 +61,14 @@ #define gettext(s) s #define _(s) s #define N_(s) s #define SP(s) ((s) ? (s) : "NONE") +#define WYDAWCA_EX_AGAIN 1 + /* The range of directive versions we accept (major * 100 + minor) */ #define MIN_DIRECTIVE_VERSION 101 #define MAX_DIRECTIVE_VERSION 101 /* Default modes for mkdir and creat commands: rely on the umask value */ #define MKDIR_PERMISSIONS 0777 @@ -316,12 +319,16 @@ extern int archive_signatures; extern char *admin_stat_message; extern char *pidfile; extern int force_startup; +extern char *lockdir; +extern time_t lock_expire_time; +extern int enable_locking; + extern int daemon_mode; extern time_t wakeup_interval; extern int foreground; extern int single_process; extern struct gconf_sockaddr listen_sockaddr; @@ -361,14 +368,15 @@ enum exec_result }; enum exec_result wydawca_exec (int argc, const char **argv, int *retcode); /* Directory scanning and registering */ -void scan_spool (const struct spool *spool, int uc, uid_t *uv); -void scan_all_spools (int, uid_t *); +int scan_spool (const struct spool *spool, int uc, uid_t *uv); +int scan_all_spools (int, uid_t *); +void spool_create_timers (void); void register_spool (struct spool *spool); struct spool *wydawca_find_spool (const char *name); void register_file (struct file_info *finfo); void enumerate_triplets (const struct spool *); size_t count_collected_triplets (void); @@ -417,13 +425,13 @@ int directive_next (struct file_triplet *trp, int n, const char **pkey, const char **pval); int process_directives (struct file_triplet *trp, const struct spool *spool); int enabled_spool_p (const struct spool *spool); -int wydawca_uid (uid_t uid); +int wydawca_set_uid (uid_t uid); int parse_time_interval (const char *str, time_t *pint, const char **endp); /* config.c */ @@ -501,10 +509,23 @@ 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); +void remove_pidfile (void); /* net.c */ void wydawca_listener (void); + + +#define LOCK_OK 0 +#define LOCK_CONFLICT 1 +#define LOCK_RETRY 2 +#define LOCK_INVALID 3 +#define LOCK_FAILURE 4 + +char *wydawca_lockname (const char *tag); +int wydawca_lock (const char *lockname); +void wydawca_unlock (const char *lockname); +void wydawca_lock_init (void); diff --git a/tests/etc/wydawca.rcin b/tests/etc/wydawca.rcin index 36ef7a2..bc6aaa4 100644 --- a/tests/etc/wydawca.rcin +++ b/tests/etc/wydawca.rcin @@ -15,12 +15,14 @@ # along with Wydawca. If not, see <http://www.gnu.org/licenses/>. statistics all; umask 022; +locking no; + access-method project-owner { type builtin; query "${project}"; params ("/exact", "proj", "proj-owner@localhost", "Project Admin"); } |