aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-02-24 18:45:51 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-02-24 18:45:51 +0200
commitc9178a6fef0184baed0e8456bb6c6d4091b4997c (patch)
tree0c97d7aeb6235a469cd071d7d0b589f45a9d35f6
parentb1472caae9a1b6905b6bbe42e69539b29febcf5c (diff)
downloadwydawca-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.modules4
-rw-r--r--src/Makefile.am1
-rw-r--r--src/config.c8
-rw-r--r--src/directive.c4
-rw-r--r--src/diskio.c6
-rw-r--r--src/exec.c2
-rw-r--r--src/getopt.m42
-rw-r--r--src/job.c45
-rw-r--r--src/lock.c239
-rw-r--r--src/net.c14
-rw-r--r--src/pidfile.c10
-rw-r--r--src/process.c25
-rw-r--r--src/triplet.c4
-rw-r--r--src/wydawca.c50
-rw-r--r--src/wydawca.h27
-rw-r--r--tests/etc/wydawca.rcin2
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)
diff --git a/src/exec.c b/src/exec.c
index eb4c8c4..7293ca1 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -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)
}
}
}
>])
diff --git a/src/job.c b/src/job.c
index 545d270..2c177cb 100644
--- a/src/job.c
+++ b/src/job.c
@@ -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);
+ }
+}
diff --git a/src/net.c b/src/net.c
index 03f9a5a..3874827 100644
--- a/src/net.c
+++ b/src/net.c
@@ -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");
}

Return to:

Send suggestions and report system problems to the System administrator.