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