dma(8): Upgrade to v0.7.
[dragonfly.git] / libexec / dma / 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 #ifndef HOST_NAME_MAX
55 #define HOST_NAME_MAX   255
56 #endif
57         static char name[HOST_NAME_MAX+1];
58         static int initialized = 0;
59         char *s;
60
61         if (initialized)
62                 return (name);
63
64         if (config.mailname == NULL || !*config.mailname)
65                 goto local;
66
67         if (config.mailname[0] == '/') {
68                 /*
69                  * If the mailname looks like an absolute path,
70                  * treat it as a file.
71                  */
72                 FILE *fp;
73
74                 fp = fopen(config.mailname, "r");
75                 if (fp == NULL)
76                         goto local;
77
78                 s = fgets(name, sizeof(name), fp);
79                 fclose(fp);
80                 if (s == NULL)
81                         goto local;
82
83                 for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
84                         /* NOTHING */;
85                 *s = 0;
86
87                 if (!*name)
88                         goto local;
89
90                 initialized = 1;
91                 return (name);
92         } else {
93                 snprintf(name, sizeof(name), "%s", config.mailname);
94                 initialized = 1;
95                 return (name);
96         }
97
98 local:
99         if (gethostname(name, sizeof(name)) != 0)
100                 *name = 0;
101         /*
102          * gethostname() is allowed to truncate name without NUL-termination
103          * and at the same time not return an error.
104          */
105         name[sizeof(name) - 1] = 0;
106
107         for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
108                 /* NOTHING */;
109         *s = 0;
110
111         if (!*name)
112                 snprintf(name, sizeof(name), "unknown-hostname");
113
114         initialized = 1;
115         return (name);
116 }
117
118 void
119 setlogident(const char *fmt, ...)
120 {
121         static char tag[50];
122
123         snprintf(tag, sizeof(tag), "%s", logident_base);
124         if (fmt != NULL) {
125                 va_list ap;
126                 char sufx[50];
127
128                 va_start(ap, fmt);
129                 vsnprintf(sufx, sizeof(sufx), fmt, ap);
130                 va_end(ap);
131                 snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx);
132         }
133         closelog();
134         openlog(tag, 0, LOG_MAIL);
135 }
136
137 void
138 errlog(int exitcode, const char *fmt, ...)
139 {
140         int oerrno = errno;
141         va_list ap;
142         char outs[ERRMSG_SIZE];
143
144         outs[0] = 0;
145         if (fmt != NULL) {
146                 va_start(ap, fmt);
147                 vsnprintf(outs, sizeof(outs), fmt, ap);
148                 va_end(ap);
149         }
150
151         errno = oerrno;
152         if (*outs != 0) {
153                 syslog(LOG_ERR, "%s: %m", outs);
154                 fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno));
155         } else {
156                 syslog(LOG_ERR, "%m");
157                 fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno));
158         }
159
160         exit(exitcode);
161 }
162
163 void
164 errlogx(int exitcode, const char *fmt, ...)
165 {
166         va_list ap;
167         char outs[ERRMSG_SIZE];
168
169         outs[0] = 0;
170         if (fmt != NULL) {
171                 va_start(ap, fmt);
172                 vsnprintf(outs, sizeof(outs), fmt, ap);
173                 va_end(ap);
174         }
175
176         if (*outs != 0) {
177                 syslog(LOG_ERR, "%s", outs);
178                 fprintf(stderr, "%s: %s\n", getprogname(), outs);
179         } else {
180                 syslog(LOG_ERR, "Unknown error");
181                 fprintf(stderr, "%s: Unknown error\n", getprogname());
182         }
183
184         exit(exitcode);
185 }
186
187 static int
188 check_username(const char *name, uid_t ckuid)
189 {
190         struct passwd *pwd;
191
192         if (name == NULL)
193                 return (0);
194         pwd = getpwnam(name);
195         if (pwd == NULL || pwd->pw_uid != ckuid)
196                 return (0);
197         snprintf(username, sizeof(username), "%s", name);
198         return (1);
199 }
200
201 void
202 set_username(void)
203 {
204         struct passwd *pwd;
205
206         useruid = getuid();
207         if (check_username(getlogin(), useruid))
208                 return;
209         if (check_username(getenv("LOGNAME"), useruid))
210                 return;
211         if (check_username(getenv("USER"), useruid))
212                 return;
213         pwd = getpwuid(useruid);
214         if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') {
215                 if (check_username(pwd->pw_name, useruid))
216                         return;
217         }
218         snprintf(username, sizeof(username), "uid=%ld", (long)useruid);
219 }
220
221 void
222 deltmp(void)
223 {
224         struct stritem *t;
225
226         SLIST_FOREACH(t, &tmpfs, next) {
227                 unlink(t->str);
228         }
229 }
230
231 static sigjmp_buf sigbuf;
232 static int sigbuf_valid;
233
234 static void
235 sigalrm_handler(int signo)
236 {
237         (void)signo;    /* so that gcc doesn't complain */
238         if (sigbuf_valid)
239                 siglongjmp(sigbuf, 1);
240 }
241
242 int
243 do_timeout(int timeout, int dojmp)
244 {
245         struct sigaction act;
246         int ret = 0;
247
248         sigemptyset(&act.sa_mask);
249         act.sa_flags = 0;
250
251         if (timeout) {
252                 act.sa_handler = sigalrm_handler;
253                 if (sigaction(SIGALRM, &act, NULL) != 0)
254                         syslog(LOG_WARNING, "can not set signal handler: %m");
255                 if (dojmp) {
256                         ret = sigsetjmp(sigbuf, 1);
257                         if (ret)
258                                 goto disable;
259                         /* else just programmed */
260                         sigbuf_valid = 1;
261                 }
262
263                 alarm(timeout);
264         } else {
265 disable:
266                 alarm(0);
267
268                 act.sa_handler = SIG_IGN;
269                 if (sigaction(SIGALRM, &act, NULL) != 0)
270                         syslog(LOG_WARNING, "can not remove signal handler: %m");
271                 sigbuf_valid = 0;
272         }
273
274         return (ret);
275 }
276
277 int
278 open_locked(const char *fname, int flags, ...)
279 {
280         int mode = 0;
281
282         if (flags & O_CREAT) {
283                 va_list ap;
284                 va_start(ap, flags);
285                 mode = va_arg(ap, int);
286                 va_end(ap);
287         }
288
289 #ifndef O_EXLOCK
290         int fd, save_errno;
291
292         fd = open(fname, flags, mode);
293         if (fd < 0)
294                 return(fd);
295         if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) {
296                 save_errno = errno;
297                 close(fd);
298                 errno = save_errno;
299                 return(-1);
300         }
301         return(fd);
302 #else
303         return(open(fname, flags|O_EXLOCK, mode));
304 #endif
305 }
306
307 char *
308 rfc822date(void)
309 {
310         static char str[50];
311         size_t error;
312         time_t now;
313
314         now = time(NULL);
315         error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z",
316                        localtime(&now));
317         if (error == 0)
318                 strcpy(str, "(date fail)");
319         return (str);
320 }
321
322 int
323 strprefixcmp(const char *str, const char *prefix)
324 {
325         return (strncasecmp(str, prefix, strlen(prefix)));
326 }
327
328 void
329 init_random(void)
330 {
331         unsigned int seed;
332         int rf;
333
334         rf = open("/dev/urandom", O_RDONLY);
335         if (rf == -1)
336                 rf = open("/dev/random", O_RDONLY);
337
338         if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed)))
339                 seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed;
340
341         srandom(seed);
342
343         if (rf != -1)
344                 close(rf);
345 }