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