Imported upstream version 0.59.3
[hcoop/debian/courier-authlib.git] / liblock / lockmail.c
1 /*
2 ** Copyright 2002-2006 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6 #include "config.h"
7 #include "liblock.h"
8 #include "mail.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #include <signal.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #if HAVE_SYS_WAIT_H
18 #include <sys/wait.h>
19 #endif
20 #ifdef HAVE_FCNTL_H
21 #include <fcntl.h>
22 #endif
23 #ifndef WEXITSTATUS
24 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
25 #endif
26 #ifndef WIFEXITED
27 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
28 #endif
29
30 #if HAVE_SYSEXITS_H
31 #include <sysexits.h>
32 #endif
33
34 #ifndef EX_TEMPFAIL
35 #define EX_TEMPFAIL 75
36 #endif
37
38 static const char rcsid[]="$Id: lockmail.c,v 1.6 2006/09/20 01:41:27 mrsam Exp $";
39
40 #define NTRIES_DEFAULT 60
41 #define DELAY 5
42
43 static int sig=0;
44
45 static int catch(int signum)
46 {
47 sig=1;
48 signal(SIGHUP, (RETSIGTYPE (*)(int))catch);
49 signal(SIGTERM, (RETSIGTYPE (*)(int))catch);
50 signal(SIGINT, (RETSIGTYPE (*)(int))catch);
51 return 0;
52 }
53
54 static int caught()
55 {
56 signal(SIGHUP, SIG_DFL);
57 signal(SIGTERM, SIG_DFL);
58 signal(SIGINT, SIG_DFL);
59 return sig;
60 }
61
62 int main(int argc, char **argv)
63 {
64 char **argvec;
65 int n;
66 int fd;
67 pid_t pid, pid2;
68 int waitstat;
69 struct ll_mail *p;
70 int ntries=NTRIES_DEFAULT;
71 int readonly=0;
72 int optchar;
73
74 while ((optchar=getopt(argc, argv, "+rt:")) != -1)
75 switch (optchar) {
76 case 'r':
77 readonly=1;
78 break;
79 case 't':
80 ntries=atoi(optarg);
81 if (ntries < 0)
82 {
83 fprintf(stderr, "%s: invalid argument to -t\n",
84 argv[0]);
85 exit(EX_TEMPFAIL);
86 }
87 ntries= (ntries / DELAY) + 1;
88 break;
89 default:
90 exit(1);
91 }
92
93 if (argc - optind < 2)
94 {
95 fprintf(stderr, "Usage: %s [-r] [-t time] mailfile program [args]...\n",
96 argv[0]);
97 exit(1);
98 }
99
100 if ((argvec=malloc(sizeof(char *) * (argc - optind + 1))) == NULL)
101 {
102 perror("malloc");
103 exit (1);
104 }
105
106 for (n=optind+1; n<argc; n++)
107 argvec[n-optind - 1]=argv[n];
108
109 argvec[n-optind-1]=NULL;
110
111 /* Create the mail file, if it doesn't exist */
112
113 if ((n=open(argv[optind], O_RDWR|O_CREAT, 0600)) >= 0)
114 close(n);
115
116 signal(SIGUSR2, SIG_IGN);
117 signal(SIGCHLD, SIG_DFL);
118
119 p=NULL;
120
121 for (n=0; n<ntries; sleep(DELAY), n++)
122 {
123 if (p)
124 ll_mail_free(p);
125
126 if ((p=ll_mail_alloc(argv[optind])) == NULL)
127 {
128 perror("malloc");
129 exit(1);
130 }
131
132 signal(SIGHUP, (RETSIGTYPE (*)(int))catch);
133 signal(SIGTERM, (RETSIGTYPE (*)(int))catch);
134 signal(SIGINT, (RETSIGTYPE (*)(int))catch);
135
136 if (ll_mail_lock(p) < 0)
137 {
138 if (errno == ENOENT)
139 break; /* Mail file gone? */
140 if (caught())
141 break;
142 continue;
143 }
144
145 if ((fd=ll_mail_open(p)) < 0)
146 {
147 if (!readonly || (fd=ll_mail_open_ro(p)) < 0)
148 {
149 if (caught())
150 break;
151 continue;
152 }
153 }
154
155 if ((pid=fork()) < 0)
156 {
157 perror("fork");
158 exit(1);
159 }
160
161 if (pid == 0)
162 {
163 setgid(getgid());
164 setuid(getuid());
165
166 (void)caught();
167 execvp(argvec[0], argvec);
168
169 perror(argvec[0]);
170 exit(1);
171 }
172
173 while ((pid2=wait(&waitstat)) != pid)
174 ;
175
176 ll_mail_free(p);
177
178 if (WIFEXITED(waitstat))
179 exit(WEXITSTATUS(waitstat));
180 exit(EX_TEMPFAIL);
181 }
182 if (p)
183 ll_mail_free(p);
184 exit(EX_TEMPFAIL);
185 return (0);
186 }
187