]> git.ipfire.org Git - people/ms/dma.git/blob - util.c
dma-mbox-create: group mail only needs to write to mboxes
[people/ms/dma.git] / util.c
1 /*
2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <sys/file.h>
37
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <netdb.h>
42 #include <pwd.h>
43 #include <setjmp.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <syslog.h>
47 #include <unistd.h>
48
49 #include "dma.h"
50
51 const char *
52 hostname(void)
53 {
54 static char name[HOST_NAME_MAX+1];
55 static int initialized = 0;
56 char *s;
57
58 if (initialized)
59 return (name);
60
61 if (config.mailname == NULL || !*config.mailname)
62 goto local;
63
64 if (config.mailname[0] == '/') {
65 /*
66 * If the mailname looks like an absolute path,
67 * treat it as a file.
68 */
69 FILE *fp;
70
71 fp = fopen(config.mailname, "r");
72 if (fp == NULL)
73 goto local;
74
75 s = fgets(name, sizeof(name), fp);
76 fclose(fp);
77 if (s == NULL)
78 goto local;
79
80 for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
81 /* NOTHING */;
82 *s = 0;
83
84 if (!*name)
85 goto local;
86
87 initialized = 1;
88 return (name);
89 } else {
90 snprintf(name, sizeof(name), "%s", config.mailname);
91 initialized = 1;
92 return (name);
93 }
94
95 local:
96 if (gethostname(name, sizeof(name)) != 0)
97 *name = 0;
98 /*
99 * gethostname() is allowed to truncate name without NUL-termination
100 * and at the same time not return an error.
101 */
102 name[sizeof(name) - 1] = 0;
103
104 for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
105 /* NOTHING */;
106 *s = 0;
107
108 if (!*name)
109 snprintf(name, sizeof(name), "unknown-hostname");
110
111 initialized = 1;
112 return (name);
113 }
114
115 void
116 setlogident(const char *fmt, ...)
117 {
118 static char tag[50];
119
120 snprintf(tag, sizeof(tag), "%s", logident_base);
121 if (fmt != NULL) {
122 va_list ap;
123 char sufx[50];
124
125 va_start(ap, fmt);
126 vsnprintf(sufx, sizeof(sufx), fmt, ap);
127 va_end(ap);
128 snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx);
129 }
130 closelog();
131 openlog(tag, 0, LOG_MAIL);
132 }
133
134 void
135 errlog(int exitcode, const char *fmt, ...)
136 {
137 int oerrno = errno;
138 va_list ap;
139 char outs[ERRMSG_SIZE];
140
141 outs[0] = 0;
142 if (fmt != NULL) {
143 va_start(ap, fmt);
144 vsnprintf(outs, sizeof(outs), fmt, ap);
145 va_end(ap);
146 }
147
148 if (*outs != 0) {
149 syslog(LOG_ERR, "%s: %m", outs);
150 fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno));
151 } else {
152 syslog(LOG_ERR, "%m");
153 fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno));
154 }
155
156 exit(exitcode);
157 }
158
159 void
160 errlogx(int exitcode, const char *fmt, ...)
161 {
162 va_list ap;
163 char outs[ERRMSG_SIZE];
164
165 outs[0] = 0;
166 if (fmt != NULL) {
167 va_start(ap, fmt);
168 vsnprintf(outs, sizeof(outs), fmt, ap);
169 va_end(ap);
170 }
171
172 if (*outs != 0) {
173 syslog(LOG_ERR, "%s", outs);
174 fprintf(stderr, "%s: %s\n", getprogname(), outs);
175 } else {
176 syslog(LOG_ERR, "Unknown error");
177 fprintf(stderr, "%s: Unknown error\n", getprogname());
178 }
179
180 exit(exitcode);
181 }
182
183 static int
184 check_username(const char *name, uid_t ckuid)
185 {
186 struct passwd *pwd;
187
188 if (name == NULL)
189 return (0);
190 pwd = getpwnam(name);
191 if (pwd == NULL || pwd->pw_uid != ckuid)
192 return (0);
193 snprintf(username, sizeof(username), "%s", name);
194 return (1);
195 }
196
197 void
198 set_username(void)
199 {
200 struct passwd *pwd;
201
202 useruid = getuid();
203 if (check_username(getlogin(), useruid))
204 return;
205 if (check_username(getenv("LOGNAME"), useruid))
206 return;
207 if (check_username(getenv("USER"), useruid))
208 return;
209 pwd = getpwuid(useruid);
210 if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') {
211 if (check_username(pwd->pw_name, useruid))
212 return;
213 }
214 snprintf(username, sizeof(username), "uid=%ld", (long)useruid);
215 }
216
217 void
218 deltmp(void)
219 {
220 struct stritem *t;
221
222 SLIST_FOREACH(t, &tmpfs, next) {
223 unlink(t->str);
224 }
225 }
226
227 static sigjmp_buf sigbuf;
228 static int sigbuf_valid;
229
230 static void
231 sigalrm_handler(int signo)
232 {
233 (void)signo; /* so that gcc doesn't complain */
234 if (sigbuf_valid)
235 siglongjmp(sigbuf, 1);
236 }
237
238 int
239 do_timeout(int timeout, int dojmp)
240 {
241 struct sigaction act;
242 int ret = 0;
243
244 sigemptyset(&act.sa_mask);
245 act.sa_flags = 0;
246
247 if (timeout) {
248 act.sa_handler = sigalrm_handler;
249 if (sigaction(SIGALRM, &act, NULL) != 0)
250 syslog(LOG_WARNING, "can not set signal handler: %m");
251 if (dojmp) {
252 ret = sigsetjmp(sigbuf, 1);
253 if (ret)
254 goto disable;
255 /* else just programmed */
256 sigbuf_valid = 1;
257 }
258
259 alarm(timeout);
260 } else {
261 disable:
262 alarm(0);
263
264 act.sa_handler = SIG_IGN;
265 if (sigaction(SIGALRM, &act, NULL) != 0)
266 syslog(LOG_WARNING, "can not remove signal handler: %m");
267 sigbuf_valid = 0;
268 }
269
270 return (ret);
271 }
272
273 int
274 open_locked(const char *fname, int flags, ...)
275 {
276 int mode = 0;
277
278 if (flags & O_CREAT) {
279 va_list ap;
280 va_start(ap, flags);
281 mode = va_arg(ap, int);
282 va_end(ap);
283 }
284
285 #ifndef O_EXLOCK
286 int fd, save_errno;
287
288 fd = open(fname, flags, mode);
289 if (fd < 0)
290 return(fd);
291 if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) {
292 save_errno = errno;
293 close(fd);
294 errno = save_errno;
295 return(-1);
296 }
297 return(fd);
298 #else
299 return(open(fname, flags|O_EXLOCK, mode));
300 #endif
301 }
302
303 char *
304 rfc822date(void)
305 {
306 static char str[50];
307 size_t error;
308 time_t now;
309
310 now = time(NULL);
311 error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z",
312 localtime(&now));
313 if (error == 0)
314 strcpy(str, "(date fail)");
315 return (str);
316 }
317
318 int
319 strprefixcmp(const char *str, const char *prefix)
320 {
321 return (strncasecmp(str, prefix, strlen(prefix)));
322 }
323
324 void
325 init_random(void)
326 {
327 unsigned int seed;
328 int rf;
329
330 rf = open("/dev/urandom", O_RDONLY);
331 if (rf == -1)
332 rf = open("/dev/random", O_RDONLY);
333
334 if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed)))
335 seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed;
336
337 srandom(seed);
338
339 if (rf != -1)
340 close(rf);
341 }