From ce0e576ac41ee22cf821b640e97e07f263ce44ce Mon Sep 17 00:00:00 2001 From: Dan Theisen Date: Sun, 22 Sep 2019 04:24:21 +0000 Subject: lib/bsdutil: add library for common utility functions --- lib/bsdutil/bsdutil.gpr | 19 +++++ lib/bsdutil/close_fd.h | 54 ++++++++++++++ lib/bsdutil/efun.c | 150 ++++++++++++++++++++++++++++++++++++++ lib/bsdutil/nls.h | 153 +++++++++++++++++++++++++++++++++++++++ lib/bsdutil/ttymsg.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 565 insertions(+) create mode 100644 lib/bsdutil/bsdutil.gpr create mode 100644 lib/bsdutil/close_fd.h create mode 100644 lib/bsdutil/efun.c create mode 100644 lib/bsdutil/nls.h create mode 100644 lib/bsdutil/ttymsg.c (limited to 'lib') 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 + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +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 +#else +# undef setlocale +# define setlocale(Category, Locale) /* empty */ +struct lconv +{ + char *decimal_point; +}; +# undef localeconv +# define localeconv() NULL +#endif + + +#ifdef ENABLE_NLS +# include +/* + * 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 +#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 + * - added Native Language Support + * Sun Mar 21 1999 - Arnaldo Carvalho de Melo + * - fixed strerr(errno) in gettext calls + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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; +} -- cgit v1.2.3-70-g09d2