summaryrefslogtreecommitdiffstats
path: root/liblock/lockmail.c
diff options
context:
space:
mode:
Diffstat (limited to 'liblock/lockmail.c')
-rw-r--r--liblock/lockmail.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/liblock/lockmail.c b/liblock/lockmail.c
new file mode 100644
index 0000000..a2c81ee
--- /dev/null
+++ b/liblock/lockmail.c
@@ -0,0 +1,186 @@
+/*
+** Copyright 2002-2006 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+#include "config.h"
+#include "liblock.h"
+#include "mail.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#if HAVE_SYSEXITS_H
+#include <sysexits.h>
+#endif
+
+#ifndef EX_TEMPFAIL
+#define EX_TEMPFAIL 75
+#endif
+
+
+#define NTRIES_DEFAULT 60
+#define DELAY 5
+
+static int sig=0;
+
+static int catch(int signum)
+{
+ sig=1;
+ signal(SIGHUP, (RETSIGTYPE (*)(int))catch);
+ signal(SIGTERM, (RETSIGTYPE (*)(int))catch);
+ signal(SIGINT, (RETSIGTYPE (*)(int))catch);
+ return 0;
+}
+
+static int caught()
+{
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ return sig;
+}
+
+int main(int argc, char **argv)
+{
+ char **argvec;
+ int n;
+ int fd;
+ pid_t pid, pid2;
+ int waitstat;
+ struct ll_mail *p;
+ int ntries=NTRIES_DEFAULT;
+ int readonly=0;
+ int optchar;
+
+ while ((optchar=getopt(argc, argv, "+rt:")) != -1)
+ switch (optchar) {
+ case 'r':
+ readonly=1;
+ break;
+ case 't':
+ ntries=atoi(optarg);
+ if (ntries < 0)
+ {
+ fprintf(stderr, "%s: invalid argument to -t\n",
+ argv[0]);
+ exit(EX_TEMPFAIL);
+ }
+ ntries= (ntries / DELAY) + 1;
+ break;
+ default:
+ exit(1);
+ }
+
+ if (argc - optind < 2)
+ {
+ fprintf(stderr, "Usage: %s [-r] [-t time] mailfile program [args]...\n",
+ argv[0]);
+ exit(1);
+ }
+
+ if ((argvec=malloc(sizeof(char *) * (argc - optind + 1))) == NULL)
+ {
+ perror("malloc");
+ exit (1);
+ }
+
+ for (n=optind+1; n<argc; n++)
+ argvec[n-optind - 1]=argv[n];
+
+ argvec[n-optind-1]=NULL;
+
+ /* Create the mail file, if it doesn't exist */
+
+ if ((n=open(argv[optind], O_RDWR|O_CREAT, 0600)) >= 0)
+ close(n);
+
+ signal(SIGUSR2, SIG_IGN);
+ signal(SIGCHLD, SIG_DFL);
+
+ p=NULL;
+
+ for (n=0; n<ntries; sleep(DELAY), n++)
+ {
+ if (p)
+ ll_mail_free(p);
+
+ if ((p=ll_mail_alloc(argv[optind])) == NULL)
+ {
+ perror("malloc");
+ exit(1);
+ }
+
+ signal(SIGHUP, (RETSIGTYPE (*)(int))catch);
+ signal(SIGTERM, (RETSIGTYPE (*)(int))catch);
+ signal(SIGINT, (RETSIGTYPE (*)(int))catch);
+
+ if (ll_mail_lock(p) < 0)
+ {
+ if (errno == ENOENT)
+ break; /* Mail file gone? */
+ if (caught())
+ break;
+ continue;
+ }
+
+ if ((fd=ll_mail_open(p)) < 0)
+ {
+ if (!readonly || (fd=ll_mail_open_ro(p)) < 0)
+ {
+ if (caught())
+ break;
+ continue;
+ }
+ }
+
+ if ((pid=fork()) < 0)
+ {
+ perror("fork");
+ exit(1);
+ }
+
+ if (pid == 0)
+ {
+ setgid(getgid());
+ setuid(getuid());
+
+ (void)caught();
+ execvp(argvec[0], argvec);
+
+ perror(argvec[0]);
+ exit(1);
+ }
+
+ while ((pid2=wait(&waitstat)) != pid)
+ ;
+
+ ll_mail_free(p);
+
+ if (WIFEXITED(waitstat))
+ exit(WEXITSTATUS(waitstat));
+ exit(EX_TEMPFAIL);
+ }
+ if (p)
+ ll_mail_free(p);
+ exit(EX_TEMPFAIL);
+ return (0);
+}
+