xref: /freebsd/contrib/dma/util.c (revision 41059135ce931c0f1014a999ffabc6bc470ce856)
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 }
347