aboutsummaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'util.c')
-rw-r--r--util.c345
1 files changed, 345 insertions, 0 deletions
diff --git a/util.c b/util.c
new file mode 100644
index 000000000000..a139b20d3831
--- /dev/null
+++ b/util.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project. All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "dma.h"
+
+const char *
+hostname(void)
+{
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+ static char name[HOST_NAME_MAX+1];
+ static int initialized = 0;
+ char *s;
+
+ if (initialized)
+ return (name);
+
+ if (config.mailname == NULL || !*config.mailname)
+ goto local;
+
+ if (config.mailname[0] == '/') {
+ /*
+ * If the mailname looks like an absolute path,
+ * treat it as a file.
+ */
+ FILE *fp;
+
+ fp = fopen(config.mailname, "r");
+ if (fp == NULL)
+ goto local;
+
+ s = fgets(name, sizeof(name), fp);
+ fclose(fp);
+ if (s == NULL)
+ goto local;
+
+ for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
+ /* NOTHING */;
+ *s = 0;
+
+ if (!*name)
+ goto local;
+
+ initialized = 1;
+ return (name);
+ } else {
+ snprintf(name, sizeof(name), "%s", config.mailname);
+ initialized = 1;
+ return (name);
+ }
+
+local:
+ if (gethostname(name, sizeof(name)) != 0)
+ *name = 0;
+ /*
+ * gethostname() is allowed to truncate name without NUL-termination
+ * and at the same time not return an error.
+ */
+ name[sizeof(name) - 1] = 0;
+
+ for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s)
+ /* NOTHING */;
+ *s = 0;
+
+ if (!*name)
+ snprintf(name, sizeof(name), "unknown-hostname");
+
+ initialized = 1;
+ return (name);
+}
+
+void
+setlogident(const char *fmt, ...)
+{
+ static char tag[50];
+
+ snprintf(tag, sizeof(tag), "%s", logident_base);
+ if (fmt != NULL) {
+ va_list ap;
+ char sufx[50];
+
+ va_start(ap, fmt);
+ vsnprintf(sufx, sizeof(sufx), fmt, ap);
+ va_end(ap);
+ snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx);
+ }
+ closelog();
+ openlog(tag, 0, LOG_MAIL);
+}
+
+void
+errlog(int exitcode, const char *fmt, ...)
+{
+ int oerrno = errno;
+ va_list ap;
+ char outs[ERRMSG_SIZE];
+
+ outs[0] = 0;
+ if (fmt != NULL) {
+ va_start(ap, fmt);
+ vsnprintf(outs, sizeof(outs), fmt, ap);
+ va_end(ap);
+ }
+
+ errno = oerrno;
+ if (*outs != 0) {
+ syslog(LOG_ERR, "%s: %m", outs);
+ fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno));
+ } else {
+ syslog(LOG_ERR, "%m");
+ fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno));
+ }
+
+ exit(exitcode);
+}
+
+void
+errlogx(int exitcode, const char *fmt, ...)
+{
+ va_list ap;
+ char outs[ERRMSG_SIZE];
+
+ outs[0] = 0;
+ if (fmt != NULL) {
+ va_start(ap, fmt);
+ vsnprintf(outs, sizeof(outs), fmt, ap);
+ va_end(ap);
+ }
+
+ if (*outs != 0) {
+ syslog(LOG_ERR, "%s", outs);
+ fprintf(stderr, "%s: %s\n", getprogname(), outs);
+ } else {
+ syslog(LOG_ERR, "Unknown error");
+ fprintf(stderr, "%s: Unknown error\n", getprogname());
+ }
+
+ exit(exitcode);
+}
+
+static int
+check_username(const char *name, uid_t ckuid)
+{
+ struct passwd *pwd;
+
+ if (name == NULL)
+ return (0);
+ pwd = getpwnam(name);
+ if (pwd == NULL || pwd->pw_uid != ckuid)
+ return (0);
+ snprintf(username, sizeof(username), "%s", name);
+ return (1);
+}
+
+void
+set_username(void)
+{
+ struct passwd *pwd;
+
+ useruid = getuid();
+ if (check_username(getlogin(), useruid))
+ return;
+ if (check_username(getenv("LOGNAME"), useruid))
+ return;
+ if (check_username(getenv("USER"), useruid))
+ return;
+ pwd = getpwuid(useruid);
+ if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') {
+ if (check_username(pwd->pw_name, useruid))
+ return;
+ }
+ snprintf(username, sizeof(username), "uid=%ld", (long)useruid);
+}
+
+void
+deltmp(void)
+{
+ struct stritem *t;
+
+ SLIST_FOREACH(t, &tmpfs, next) {
+ unlink(t->str);
+ }
+}
+
+static sigjmp_buf sigbuf;
+static int sigbuf_valid;
+
+static void
+sigalrm_handler(int signo)
+{
+ (void)signo; /* so that gcc doesn't complain */
+ if (sigbuf_valid)
+ siglongjmp(sigbuf, 1);
+}
+
+int
+do_timeout(int timeout, int dojmp)
+{
+ struct sigaction act;
+ int ret = 0;
+
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ if (timeout) {
+ act.sa_handler = sigalrm_handler;
+ if (sigaction(SIGALRM, &act, NULL) != 0)
+ syslog(LOG_WARNING, "can not set signal handler: %m");
+ if (dojmp) {
+ ret = sigsetjmp(sigbuf, 1);
+ if (ret)
+ goto disable;
+ /* else just programmed */
+ sigbuf_valid = 1;
+ }
+
+ alarm(timeout);
+ } else {
+disable:
+ alarm(0);
+
+ act.sa_handler = SIG_IGN;
+ if (sigaction(SIGALRM, &act, NULL) != 0)
+ syslog(LOG_WARNING, "can not remove signal handler: %m");
+ sigbuf_valid = 0;
+ }
+
+ return (ret);
+}
+
+int
+open_locked(const char *fname, int flags, ...)
+{
+ int mode = 0;
+
+ if (flags & O_CREAT) {
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+#ifndef O_EXLOCK
+ int fd, save_errno;
+
+ fd = open(fname, flags, mode);
+ if (fd < 0)
+ return(fd);
+ if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) {
+ save_errno = errno;
+ close(fd);
+ errno = save_errno;
+ return(-1);
+ }
+ return(fd);
+#else
+ return(open(fname, flags|O_EXLOCK, mode));
+#endif
+}
+
+char *
+rfc822date(void)
+{
+ static char str[50];
+ size_t error;
+ time_t now;
+
+ now = time(NULL);
+ error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z",
+ localtime(&now));
+ if (error == 0)
+ strcpy(str, "(date fail)");
+ return (str);
+}
+
+int
+strprefixcmp(const char *str, const char *prefix)
+{
+ return (strncasecmp(str, prefix, strlen(prefix)));
+}
+
+void
+init_random(void)
+{
+ unsigned int seed;
+ int rf;
+
+ rf = open("/dev/urandom", O_RDONLY);
+ if (rf == -1)
+ rf = open("/dev/random", O_RDONLY);
+
+ if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed)))
+ seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed;
+
+ srandom(seed);
+
+ if (rf != -1)
+ close(rf);
+}