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