Import Upstream version 0.66.4
[hcoop/debian/courier-authlib.git] / libs / 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
39 #define NTRIES_DEFAULT 60
40 #define DELAY 5
41
42 static int sig=0;
43
44 static int catch(int signum)
45 {
46 sig=1;
47 signal(SIGHUP, (RETSIGTYPE (*)(int))catch);
48 signal(SIGTERM, (RETSIGTYPE (*)(int))catch);
49 signal(SIGINT, (RETSIGTYPE (*)(int))catch);
50 return 0;
51 }
52
53 static int caught()
54 {
55 signal(SIGHUP, SIG_DFL);
56 signal(SIGTERM, SIG_DFL);
57 signal(SIGINT, SIG_DFL);
58 return sig;
59 }
60
61 int main(int argc, char **argv)
62 {
63 char **argvec;
64 int n;
65 int fd;
66 pid_t pid, pid2;
67 int waitstat;
68 struct ll_mail *p;
69 int ntries=NTRIES_DEFAULT;
70 int readonly=0;
71 int optchar;
72
73 while ((optchar=getopt(argc, argv, "+rt:")) != -1)
74 switch (optchar) {
75 case 'r':
76 readonly=1;
77 break;
78 case 't':
79 ntries=atoi(optarg);
80 if (ntries < 0)
81 {
82 fprintf(stderr, "%s: invalid argument to -t\n",
83 argv[0]);
84 exit(EX_TEMPFAIL);
85 }
86 ntries= (ntries / DELAY) + 1;
87 break;
88 default:
89 exit(1);
90 }
91
92 if (argc - optind < 2)
93 {
94 fprintf(stderr, "Usage: %s [-r] [-t time] mailfile program [args]...\n",
95 argv[0]);
96 exit(1);
97 }
98
99 if ((argvec=malloc(sizeof(char *) * (argc - optind + 1))) == NULL)
100 {
101 perror("malloc");
102 exit (1);
103 }
104
105 for (n=optind+1; n<argc; n++)
106 argvec[n-optind - 1]=argv[n];
107
108 argvec[n-optind-1]=NULL;
109
110 /* Create the mail file, if it doesn't exist */
111
112 if ((n=open(argv[optind], O_RDWR|O_CREAT, 0600)) >= 0)
113 close(n);
114
115 signal(SIGUSR2, SIG_IGN);
116 signal(SIGCHLD, SIG_DFL);
117
118 p=NULL;
119
120 for (n=0; n<ntries; sleep(DELAY), n++)
121 {
122 if (p)
123 ll_mail_free(p);
124
125 if ((p=ll_mail_alloc(argv[optind])) == NULL)
126 {
127 perror("malloc");
128 exit(1);
129 }
130
131 signal(SIGHUP, (RETSIGTYPE (*)(int))catch);
132 signal(SIGTERM, (RETSIGTYPE (*)(int))catch);
133 signal(SIGINT, (RETSIGTYPE (*)(int))catch);
134
135 if (ll_mail_lock(p) < 0)
136 {
137 if (errno == ENOENT)
138 break; /* Mail file gone? */
139 if (caught())
140 break;
141 continue;
142 }
143
144 if ((fd=ll_mail_open(p)) < 0)
145 {
146 if (!readonly || (fd=ll_mail_open_ro(p)) < 0)
147 {
148 if (caught())
149 break;
150 continue;
151 }
152 }
153
154 if ((pid=fork()) < 0)
155 {
156 perror("fork");
157 exit(1);
158 }
159
160 if (pid == 0)
161 {
162 if (setgid(getgid()) < 0 ||
163 setuid(getuid()) < 0)
164 {
165 perror("setuid/setgid");
166 exit(1);
167 }
168
169 (void)caught();
170 execvp(argvec[0], argvec);
171
172 perror(argvec[0]);
173 exit(1);
174 }
175
176 while ((pid2=wait(&waitstat)) != pid)
177 ;
178
179 ll_mail_free(p);
180
181 if (WIFEXITED(waitstat))
182 exit(WEXITSTATUS(waitstat));
183 exit(EX_TEMPFAIL);
184 }
185 if (p)
186 ll_mail_free(p);
187 exit(EX_TEMPFAIL);
188 return (0);
189 }
190