summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDan Theisen <djt@hxx.in>2019-09-22 04:24:21 +0000
committerDan Theisen <djt@hxx.in>2019-09-22 04:40:33 +0000
commitce0e576ac41ee22cf821b640e97e07f263ce44ce (patch)
tree27379636a859876c27be0506c60ab2eb58761b2f /lib
parent8158ef186bf16307b6ed2c329cf008064c6ba868 (diff)
downloaduserland-ce0e576ac41ee22cf821b640e97e07f263ce44ce.tar.gz
userland-ce0e576ac41ee22cf821b640e97e07f263ce44ce.tar.bz2
userland-ce0e576ac41ee22cf821b640e97e07f263ce44ce.tar.xz
userland-ce0e576ac41ee22cf821b640e97e07f263ce44ce.zip
lib/bsdutil: add library for common utility functions
Diffstat (limited to 'lib')
-rw-r--r--lib/bsdutil/bsdutil.gpr19
-rw-r--r--lib/bsdutil/close_fd.h54
-rw-r--r--lib/bsdutil/efun.c150
-rw-r--r--lib/bsdutil/nls.h153
-rw-r--r--lib/bsdutil/ttymsg.c189
5 files changed, 565 insertions, 0 deletions
diff --git a/lib/bsdutil/bsdutil.gpr b/lib/bsdutil/bsdutil.gpr
new file mode 100644
index 0000000..bf60c4a
--- /dev/null
+++ b/lib/bsdutil/bsdutil.gpr
@@ -0,0 +1,19 @@
+library project bsdutil extends "template/base.gpr" is
+
+ BuildRoot := External ("BUILDROOT");
+ IncludeDir := External ("PROJ_INCLUDE");
+ HeaderFile := project'Name & ".h";
+
+ for Library_Name use "bsdutil";
+ for Object_Dir use BuildRoot & "/" & project'Name;
+ for Library_Dir use BuildRoot & "/lib";
+ for Library_Standalone use "no";
+ for Library_Kind use "dynamic";
+ for Library_Version use "libbsdutil.so.1";
+ for Symbolic_Link_Supported use "true";
+ for Library_Partial_Linker use ("");
+
+ for Source_Dirs use ("./**", IncludeDir);
+ for Interfaces use (HeaderFile);
+
+end bsdutil;
diff --git a/lib/bsdutil/close_fd.h b/lib/bsdutil/close_fd.h
new file mode 100644
index 0000000..68ba6c9
--- /dev/null
+++ b/lib/bsdutil/close_fd.h
@@ -0,0 +1,54 @@
+#ifndef _PATH_DEV
+/*
+ * The tailing '/' in _PATH_DEV is there for compatibility with libc.
+ */
+# define _PATH_DEV"/dev/"
+#endif
+
+////////////////////////////////////////////////
+/// Cargo culted from util-linux include/c.h ///
+////////////////////////////////////////////////
+#include <err.h>
+
+/*
+ * Force a compilation error if condition is true, but also produce a
+ * result (of value 0 and type size_t), so the expression can be used
+ * e.g. in a structure initializer (or wherever else comma expressions
+ * aren't permitted).
+ */
+#define UL_BUILD_BUG_ON_ZERO(e) __extension__ (sizeof(struct { int:-!!(e); }))
+#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
+
+#ifdef __GNUC__
+/* &a[0] degrades to a pointer: a different type from an array */
+# define __must_be_array(a) \
+ UL_BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(__typeof__(a), __typeof__(&a[0])))
+
+# define ignore_result(x) __extension__ ({ \
+ __typeof__(x) __dummy __attribute__((__unused__)) = (x); (void) __dummy; \
+ })
+#else /* !__GNUC__ */
+# define __must_be_array(a) 0
+# define __attribute__(_arg_)
+# define ignore_result(x) ((void) (x))
+#endif /* !__GNUC__ */
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+#endif
+
+//////////////////////////////////////////////////////////
+/// Cargo culted from util-linux include/closestream.h ///
+//////////////////////////////////////////////////////////
+static inline int
+close_fd(int fd)
+{
+ const int fsync_fail = (fsync(fd) != 0);
+ const int close_fail = (close(fd) != 0);
+
+ if (fsync_fail || close_fail)
+ return EOF;
+ return 0;
+}
+
+
diff --git a/lib/bsdutil/efun.c b/lib/bsdutil/efun.c
new file mode 100644
index 0000000..cf46124
--- /dev/null
+++ b/lib/bsdutil/efun.c
@@ -0,0 +1,150 @@
+/* $NetBSD: efun.c,v 1.10 2015/07/26 02:20:30 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <bsd/err.h>
+#include <errno.h>
+#include <bsd/inttypes.h>
+#include <bsd/string.h>
+#include <bsd/stdlib.h>
+#include <bsd/stdio.h>
+#include <stdarg.h>
+#include <bsdutil.h>
+
+static void (*efunc)(int, const char *, ...) = err;
+
+void (*
+esetfunc(void (*ef)(int, const char *, ...)))(int, const char *, ...)
+{
+ void (*of)(int, const char *, ...) = efunc;
+ efunc = ef == NULL ? (void (*)(int, const char *, ...))exit : ef;
+ return of;
+}
+
+size_t
+estrlcpy(char *dst, const char *src, size_t len)
+{
+ size_t rv;
+ if ((rv = strlcpy(dst, src, len)) >= len) {
+ errno = ENAMETOOLONG;
+ (*efunc)(1,
+ "Cannot copy string; %zu chars needed %zu provided",
+ rv, len);
+ }
+ return rv;
+}
+
+size_t
+estrlcat(char *dst, const char *src, size_t len)
+{
+ size_t rv;
+ if ((rv = strlcat(dst, src, len)) >= len) {
+ errno = ENAMETOOLONG;
+ (*efunc)(1,
+ "Cannot append to string; %zu chars needed %zu provided",
+ rv, len);
+ }
+ return rv;
+}
+
+char *
+estrdup(const char *s)
+{
+ char *d = strdup(s);
+ if (d == NULL)
+ (*efunc)(1, "Cannot copy string");
+ return d;
+}
+
+char *
+estrndup(const char *s, size_t len)
+{
+ char *d = strndup(s, len);
+ if (d == NULL)
+ (*efunc)(1, "Cannot copy string");
+ return d;
+}
+
+void *
+emalloc(size_t n)
+{
+ void *p = malloc(n);
+ if (p == NULL && n != 0)
+ (*efunc)(1, "Cannot allocate %zu bytes", n);
+ return p;
+}
+
+void *
+ecalloc(size_t n, size_t s)
+{
+ void *p = calloc(n, s);
+ if (p == NULL && n != 0 && s != 0)
+ (*efunc)(1, "Cannot allocate %zu blocks of size %zu", n, s);
+ return p;
+}
+
+void *
+erealloc(void *p, size_t n)
+{
+ void *q = realloc(p, n);
+ if (q == NULL && n != 0)
+ (*efunc)(1, "Cannot re-allocate %zu bytes", n);
+ return q;
+}
+
+FILE *
+efopen(const char *p, const char *m)
+{
+ FILE *fp = fopen(p, m);
+ if (fp == NULL)
+ (*efunc)(1, "Cannot open `%s'", p);
+ return fp;
+}
+
+int
+easprintf(char ** __restrict ret, const char * __restrict format, ...)
+{
+ int rv;
+ va_list ap;
+ va_start(ap, format);
+ if ((rv = vasprintf(ret, format, ap)) == -1)
+ (*efunc)(1, "Cannot format string");
+ va_end(ap);
+ return rv;
+}
+
+int
+evasprintf(char ** __restrict ret, const char * __restrict format, va_list ap)
+{
+ int rv;
+ if ((rv = vasprintf(ret, format, ap)) == -1)
+ (*efunc)(1, "Cannot format string");
+ return rv;
+}
diff --git a/lib/bsdutil/nls.h b/lib/bsdutil/nls.h
new file mode 100644
index 0000000..5566908
--- /dev/null
+++ b/lib/bsdutil/nls.h
@@ -0,0 +1,153 @@
+#ifndef UTIL_LINUX_NLS_H
+#define UTIL_LINUX_NLS_H
+
+#ifndef LOCALEDIR
+#define LOCALEDIR "/usr/share/locale"
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#else
+# undef setlocale
+# define setlocale(Category, Locale) /* empty */
+struct lconv
+{
+ char *decimal_point;
+};
+# undef localeconv
+# define localeconv() NULL
+#endif
+
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+/*
+ * For NLS support in the public shared libraries we have to specify text
+ * domain name to be independent on the main program. For this purpose define
+ * UL_TEXTDOMAIN_EXPLICIT before you include nls.h to your shared library code.
+ */
+# ifdef UL_TEXTDOMAIN_EXPLICIT
+# define _(Text) dgettext (UL_TEXTDOMAIN_EXPLICIT, Text)
+# else
+# define _(Text) gettext (Text)
+# endif
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+# define P_(Singular, Plural, n) ngettext (Singular, Plural, n)
+#else
+# undef bindtextdomain
+# define bindtextdomain(Domain, Directory) /* empty */
+# undef textdomain
+# define textdomain(Domain) /* empty */
+# define _(Text) (Text)
+# define N_(Text) (Text)
+# define P_(Singular, Plural, n) ((n) == 1 ? (Singular) : (Plural))
+#endif /* ENABLE_NLS */
+
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#else
+
+typedef int nl_item;
+extern char *langinfo_fallback(nl_item item);
+
+# define nl_langinfo langinfo_fallback
+
+enum {
+ CODESET = 1,
+ RADIXCHAR,
+ THOUSEP,
+ D_T_FMT,
+ D_FMT,
+ T_FMT,
+ T_FMT_AMPM,
+ AM_STR,
+ PM_STR,
+
+ DAY_1,
+ DAY_2,
+ DAY_3,
+ DAY_4,
+ DAY_5,
+ DAY_6,
+ DAY_7,
+
+ ABDAY_1,
+ ABDAY_2,
+ ABDAY_3,
+ ABDAY_4,
+ ABDAY_5,
+ ABDAY_6,
+ ABDAY_7,
+
+ MON_1,
+ MON_2,
+ MON_3,
+ MON_4,
+ MON_5,
+ MON_6,
+ MON_7,
+ MON_8,
+ MON_9,
+ MON_10,
+ MON_11,
+ MON_12,
+
+ ABMON_1,
+ ABMON_2,
+ ABMON_3,
+ ABMON_4,
+ ABMON_5,
+ ABMON_6,
+ ABMON_7,
+ ABMON_8,
+ ABMON_9,
+ ABMON_10,
+ ABMON_11,
+ ABMON_12,
+
+ ERA_D_FMT,
+ ERA_D_T_FMT,
+ ERA_T_FMT,
+ ALT_DIGITS,
+ CRNCYSTR,
+ YESEXPR,
+ NOEXPR
+};
+
+#endif /* !HAVE_LANGINFO_H */
+
+#ifndef HAVE_LANGINFO_ALTMON
+# define ALTMON_1 MON_1
+# define ALTMON_2 MON_2
+# define ALTMON_3 MON_3
+# define ALTMON_4 MON_4
+# define ALTMON_5 MON_5
+# define ALTMON_6 MON_6
+# define ALTMON_7 MON_7
+# define ALTMON_8 MON_8
+# define ALTMON_9 MON_9
+# define ALTMON_10 MON_10
+# define ALTMON_11 MON_11
+# define ALTMON_12 MON_12
+#endif /* !HAVE_LANGINFO_ALTMON */
+
+#ifndef HAVE_LANGINFO_NL_ABALTMON
+# define _NL_ABALTMON_1 ABMON_1
+# define _NL_ABALTMON_2 ABMON_2
+# define _NL_ABALTMON_3 ABMON_3
+# define _NL_ABALTMON_4 ABMON_4
+# define _NL_ABALTMON_5 ABMON_5
+# define _NL_ABALTMON_6 ABMON_6
+# define _NL_ABALTMON_7 ABMON_7
+# define _NL_ABALTMON_8 ABMON_8
+# define _NL_ABALTMON_9 ABMON_9
+# define _NL_ABALTMON_10 ABMON_10
+# define _NL_ABALTMON_11 ABMON_11
+# define _NL_ABALTMON_12 ABMON_12
+#endif /* !HAVE_LANGINFO_NL_ABALTMON */
+
+#endif /* UTIL_LINUX_NLS_H */
diff --git a/lib/bsdutil/ttymsg.c b/lib/bsdutil/ttymsg.c
new file mode 100644
index 0000000..9afa7ea
--- /dev/null
+++ b/lib/bsdutil/ttymsg.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * Modified Sun Mar 12 10:39:22 1995, faith@cs.unc.edu for Linux
+ *
+ */
+
+ /* 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * - fixed strerr(errno) in gettext calls
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <paths.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <bsdutil.h>
+#include "nls.h"
+#include "close_fd.h"
+
+#define ERR_BUFLEN (MAXNAMLEN + 1024)
+
+/*
+ * Display the contents of a uio structure on a terminal. Used by wall(1),
+ * syslogd(8), and talkd(8). Forks and finishes in child if write would block,
+ * waiting up to tmout seconds. Returns pointer to error string on unexpected
+ * error; string is not newline-terminated. Various "normal" errors are
+ * ignored (exclusive-use, lack of permission, etc.).
+ */
+char *
+ttymsg(struct iovec *iov, size_t iovcnt, const char *line, int tmout) {
+ static char device[MAXNAMLEN];
+ static char errbuf[ERR_BUFLEN];
+ size_t cnt, left;
+ ssize_t wret;
+ struct iovec localiov[6];
+ int fd, forked = 0;
+ ssize_t len = 0;
+
+ if (iovcnt > ARRAY_SIZE(localiov)) {
+ snprintf(errbuf, sizeof(errbuf), _("internal error: too many iov's"));
+ return errbuf;
+ }
+
+ /* The old code here rejected the line argument when it contained a '/',
+ saying: "A slash may be an attempt to break security...".
+ However, if a user can control the line argument here
+ then he can make this routine write to /dev/hda or /dev/sda
+ already. So, this test was worthless, and these days it is
+ also wrong since people use /dev/pts/xxx. */
+
+ len = snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line);
+ if (len < 0 || (size_t)len >= sizeof(device)) {
+ snprintf(errbuf, sizeof(errbuf), _("excessively long line arg"));
+ return errbuf;
+ }
+
+ /*
+ * open will fail on slip lines or exclusive-use lines
+ * if not running as root; not an error.
+ */
+ if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
+ if (errno == EBUSY || errno == EACCES)
+ return NULL;
+
+ len = snprintf(errbuf, sizeof(errbuf), "%s: %m", device);
+ if (len < 0 || (size_t)len >= sizeof(errbuf))
+ snprintf(errbuf, sizeof(errbuf), _("open failed"));
+ return errbuf;
+ }
+
+ for (cnt = left = 0; cnt < iovcnt; ++cnt)
+ left += iov[cnt].iov_len;
+
+ for (;;) {
+ wret = writev(fd, iov, iovcnt);
+ if (wret >= (ssize_t) left)
+ break;
+ if (wret >= 0) {
+ left -= wret;
+ if (iov != localiov) {
+ memmove(localiov, iov,
+ iovcnt * sizeof(struct iovec));
+ iov = localiov;
+ }
+ for (cnt = 0; wret >= (ssize_t) iov->iov_len; ++cnt) {
+ wret -= iov->iov_len;
+ ++iov;
+ --iovcnt;
+ }
+ if (wret) {
+ iov->iov_base = (char *) iov->iov_base + wret;
+ iov->iov_len -= wret;
+ }
+ continue;
+ }
+ if (errno == EWOULDBLOCK) {
+ int cpid, flags;
+ sigset_t sigmask;
+
+ if (forked) {
+ close(fd);
+ _exit(EXIT_FAILURE);
+ }
+ cpid = fork();
+ if (cpid < 0) {
+ len = snprintf(errbuf, sizeof(errbuf), _("fork: %m"));
+ if (len < 0 || (size_t)len >= sizeof(errbuf))
+ snprintf(errbuf, sizeof(errbuf), _("cannot fork"));
+ close(fd);
+ return errbuf;
+ }
+ if (cpid) { /* parent */
+ close(fd);
+ return NULL;
+ }
+ forked++;
+ /* wait at most tmout seconds */
+ signal(SIGALRM, SIG_DFL);
+ signal(SIGTERM, SIG_DFL); /* XXX */
+ sigemptyset(&sigmask);
+ sigprocmask (SIG_SETMASK, &sigmask, NULL);
+ alarm((u_int)tmout);
+ flags = fcntl(fd, F_GETFL);
+ fcntl(flags, F_SETFL, (long) (flags & ~O_NONBLOCK));
+ continue;
+ }
+ /*
+ * We get ENODEV on a slip line if we're running as root,
+ * and EIO if the line just went away.
+ */
+ if (errno == ENODEV || errno == EIO)
+ break;
+ if (close_fd(fd) != 0)
+ warn(_("write failed: %s"), device);
+ if (forked)
+ _exit(EXIT_FAILURE);
+
+ len = snprintf(errbuf, sizeof(errbuf), "%s: %m", device);
+ if (len < 0 || (size_t)len >= sizeof(errbuf))
+ snprintf(errbuf, sizeof(errbuf),
+ _("%s: BAD ERROR, message is "
+ "far too long"), device);
+ return errbuf;
+ }
+
+ if (forked)
+ _exit(EXIT_SUCCESS);
+ return NULL;
+}