#include "config.h" #if !HAVE_ERR /* * Copyright (c) 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. 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. */ #include #include #include #include #include void vwarnx(const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); if (fmt != NULL) vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } void vwarnc(int code, const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); if (fmt != NULL) { vfprintf(stderr, fmt, ap); fprintf(stderr, ": "); } fprintf(stderr, "%s\n", strerror(code)); } void vwarn(const char *fmt, va_list ap) { int sverrno; sverrno = errno; fprintf(stderr, "%s: ", getprogname()); if (fmt != NULL) { vfprintf(stderr, fmt, ap); fprintf(stderr, ": "); } fprintf(stderr, "%s\n", strerror(sverrno)); } void verrc(int eval, int code, const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); if (fmt != NULL) { vfprintf(stderr, fmt, ap); fprintf(stderr, ": "); } fprintf(stderr, "%s\n", strerror(code)); exit(eval); } void verrx(int eval, const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); if (fmt != NULL) vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); exit(eval); } void verr(int eval, const char *fmt, va_list ap) { int sverrno; sverrno = errno; fprintf(stderr, "%s: ", getprogname()); if (fmt != NULL) { vfprintf(stderr, fmt, ap); fprintf(stderr, ": "); } fprintf(stderr, "%s\n", strerror(sverrno)); exit(eval); } void err(int eval, const char *fmt, ...) { va_list ap; va_start(ap, fmt); verr(eval, fmt, ap); va_end(ap); } void errc(int eval, int code, const char *fmt, ...) { va_list ap; va_start(ap, fmt); verrc(eval, code, fmt, ap); va_end(ap); } void errx(int eval, const char *fmt, ...) { va_list ap; va_start(ap, fmt); verrx(eval, fmt, ap); va_end(ap); } void warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarn(fmt, ap); va_end(ap); } void warnc(int code, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarnc(code, fmt, ap); va_end(ap); } void warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarnx(fmt, ap); va_end(ap); } #endif /* !HAVE_ERR */ #if !HAVE_FLOCK #include #include #include /* * flock(2) emulation on top of fcntl advisory locks. This is "good * enough" for amused, not a _real_ emulation. flock and fcntl locks * have subtly different behaviours! */ int flock(int fd, int op) { struct flock l; int cmd; memset(&l, 0, sizeof(l)); l.l_whence = SEEK_SET; if (op & LOCK_SH) l.l_type = F_RDLCK; else if (op & LOCK_EX) l.l_type = F_WRLCK; else { errno = EINVAL; return -1; } cmd = F_SETLKW; if (op & LOCK_NB) cmd = F_SETLK; return fcntl(fd, cmd, &l); } #endif /* HAVE_FLOCK */ #if !HAVE_FREEZERO #include #include void freezero(void *ptr, size_t len) { if (ptr == NULL) return; memset(ptr, 0, len); free(ptr); } #endif /* HAVE_FREEZERO */ #if !HAVE_EXPLICIT_BZERO /* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */ /* * Public domain. * Written by Ted Unangst */ #include /* * explicit_bzero - don't let the compiler optimize away bzero */ #if HAVE_MEMSET_S void explicit_bzero(void *p, size_t n) { if (n == 0) return; (void)memset_s(p, n, 0, n); } #else /* HAVE_MEMSET_S */ #include /* * Indirect memset through a volatile pointer to hopefully avoid * dead-store optimisation eliminating the call. */ static void (* volatile ssh_memset)(void *, int, size_t) = memset; void explicit_bzero(void *p, size_t n) { if (n == 0) return; /* * clang -fsanitize=memory needs to intercept memset-like functions * to correctly detect memory initialisation. Make sure one is called * directly since our indirection trick above sucessfully confuses it. */ #if defined(__has_feature) # if __has_feature(memory_sanitizer) memset(p, 0, n); # endif #endif ssh_memset(p, 0, n); } #endif /* HAVE_MEMSET_S */ #endif /* !HAVE_EXPLICIT_BZERO */ #if !HAVE_GETPROGNAME /* * Copyright (c) 2016 Nicholas Marriott * Copyright (c) 2017 Kristaps Dzonsons * Copyright (c) 2020 Stephen Gregoratto * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #if HAVE_GETEXECNAME #include const char * getprogname(void) { return getexecname(); } #elif HAVE_PROGRAM_INVOCATION_SHORT_NAME const char * getprogname(void) { return (program_invocation_short_name); } #elif HAVE___PROGNAME const char * getprogname(void) { extern char *__progname; return (__progname); } #else #warning No getprogname available. const char * getprogname(void) { return ("amused"); } #endif #endif /* !HAVE_GETPROGNAME */ #if !HAVE_IMSG /* $OpenBSD: imsg-buffer.c,v 1.13 2021/03/31 17:42:24 eric Exp $ */ /* $OpenBSD: imsg.c,v 1.17 2022/01/28 10:41:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" #include #include #include #include #include #include #include #include #include "imsg.h" static int ibuf_realloc(struct ibuf *, size_t); static void ibuf_enqueue(struct msgbuf *, struct ibuf *); static void ibuf_dequeue(struct msgbuf *, struct ibuf *); struct ibuf * ibuf_open(size_t len) { struct ibuf *buf; if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) return (NULL); if ((buf->buf = malloc(len)) == NULL) { free(buf); return (NULL); } buf->size = buf->max = len; buf->fd = -1; return (buf); } struct ibuf * ibuf_dynamic(size_t len, size_t max) { struct ibuf *buf; if (max < len) return (NULL); if ((buf = ibuf_open(len)) == NULL) return (NULL); if (max > 0) buf->max = max; return (buf); } static int ibuf_realloc(struct ibuf *buf, size_t len) { unsigned char *b; /* on static buffers max is eq size and so the following fails */ if (buf->wpos + len > buf->max) { errno = ERANGE; return (-1); } b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1); if (b == NULL) return (-1); buf->buf = b; buf->size = buf->wpos + len; return (0); } int ibuf_add(struct ibuf *buf, const void *data, size_t len) { if (buf->wpos + len > buf->size) if (ibuf_realloc(buf, len) == -1) return (-1); memcpy(buf->buf + buf->wpos, data, len); buf->wpos += len; return (0); } void * ibuf_reserve(struct ibuf *buf, size_t len) { void *b; if (buf->wpos + len > buf->size) if (ibuf_realloc(buf, len) == -1) return (NULL); b = buf->buf + buf->wpos; buf->wpos += len; return (b); } void * ibuf_seek(struct ibuf *buf, size_t pos, size_t len) { /* only allowed to seek in already written parts */ if (pos + len > buf->wpos) return (NULL); return (buf->buf + pos); } size_t ibuf_size(struct ibuf *buf) { return (buf->wpos); } size_t ibuf_left(struct ibuf *buf) { return (buf->max - buf->wpos); } void ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) { ibuf_enqueue(msgbuf, buf); } int ibuf_write(struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; struct ibuf *buf; unsigned int i = 0; ssize_t n; memset(&iov, 0, sizeof(iov)); TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { if (i >= IOV_MAX) break; iov[i].iov_base = buf->buf + buf->rpos; iov[i].iov_len = buf->wpos - buf->rpos; i++; } again: if ((n = writev(msgbuf->fd, iov, i)) == -1) { if (errno == EINTR) goto again; if (errno == ENOBUFS) errno = EAGAIN; return (-1); } if (n == 0) { /* connection closed */ errno = 0; return (0); } msgbuf_drain(msgbuf, n); return (1); } void ibuf_free(struct ibuf *buf) { if (buf == NULL) return; freezero(buf->buf, buf->size); free(buf); } void msgbuf_init(struct msgbuf *msgbuf) { msgbuf->queued = 0; msgbuf->fd = -1; TAILQ_INIT(&msgbuf->bufs); } void msgbuf_drain(struct msgbuf *msgbuf, size_t n) { struct ibuf *buf, *next; for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; buf = next) { next = TAILQ_NEXT(buf, entry); if (buf->rpos + n >= buf->wpos) { n -= buf->wpos - buf->rpos; ibuf_dequeue(msgbuf, buf); } else { buf->rpos += n; n = 0; } } } void msgbuf_clear(struct msgbuf *msgbuf) { struct ibuf *buf; while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) ibuf_dequeue(msgbuf, buf); } int msgbuf_write(struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; struct ibuf *buf, *buf0 = NULL; unsigned int i = 0; ssize_t n; struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(int))]; } cmsgbuf; memset(&iov, 0, sizeof(iov)); memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { if (i >= IOV_MAX) break; if (i > 0 && buf->fd != -1) break; iov[i].iov_base = buf->buf + buf->rpos; iov[i].iov_len = buf->wpos - buf->rpos; i++; if (buf->fd != -1) buf0 = buf; } msg.msg_iov = iov; msg.msg_iovlen = i; if (buf0 != NULL) { msg.msg_control = (caddr_t)&cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = buf0->fd; } again: if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; if (errno == ENOBUFS) errno = EAGAIN; return (-1); } if (n == 0) { /* connection closed */ errno = 0; return (0); } /* * assumption: fd got sent if sendmsg sent anything * this works because fds are passed one at a time */ if (buf0 != NULL) { close(buf0->fd); buf0->fd = -1; } msgbuf_drain(msgbuf, n); return (1); } static void ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) { TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); msgbuf->queued++; } static void ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) { TAILQ_REMOVE(&msgbuf->bufs, buf, entry); if (buf->fd != -1) close(buf->fd); msgbuf->queued--; ibuf_free(buf); } /* imsg.c */ int imsg_fd_overhead = 0; static int imsg_get_fd(struct imsgbuf *); void imsg_init(struct imsgbuf *ibuf, int fd) { msgbuf_init(&ibuf->w); memset(&ibuf->r, 0, sizeof(ibuf->r)); ibuf->fd = fd; ibuf->w.fd = fd; ibuf->pid = getpid(); TAILQ_INIT(&ibuf->fds); } ssize_t imsg_read(struct imsgbuf *ibuf) { struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(int) * 1)]; } cmsgbuf; struct iovec iov; ssize_t n = -1; int fd; struct imsg_fd *ifd; memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); iov.iov_base = ibuf->r.buf + ibuf->r.wpos; iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) return (-1); again: if (getdtablecount() + imsg_fd_overhead + (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int)) >= getdtablesize()) { errno = EAGAIN; free(ifd); return (-1); } if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; goto fail; } ibuf->r.wpos += n; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int i; int j; /* * We only accept one file descriptor. Due to C * padding rules, our control buffer might contain * more than one fd, and we must close them. */ j = ((char *)cmsg + cmsg->cmsg_len - (char *)CMSG_DATA(cmsg)) / sizeof(int); for (i = 0; i < j; i++) { fd = ((int *)CMSG_DATA(cmsg))[i]; if (ifd != NULL) { ifd->fd = fd; TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry); ifd = NULL; } else close(fd); } } /* we do not handle other ctl data level */ } fail: free(ifd); return (n); } ssize_t imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) { size_t av, left, datalen; av = ibuf->r.wpos; if (IMSG_HEADER_SIZE > av) return (0); memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); if (imsg->hdr.len < IMSG_HEADER_SIZE || imsg->hdr.len > MAX_IMSGSIZE) { errno = ERANGE; return (-1); } if (imsg->hdr.len > av) return (0); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; if (datalen == 0) imsg->data = NULL; else if ((imsg->data = malloc(datalen)) == NULL) return (-1); if (imsg->hdr.flags & IMSGF_HASFD) imsg->fd = imsg_get_fd(ibuf); else imsg->fd = -1; if (datalen != 0) memcpy(imsg->data, ibuf->r.rptr, datalen); if (imsg->hdr.len < av) { left = av - imsg->hdr.len; memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); ibuf->r.wpos = left; } else ibuf->r.wpos = 0; return (datalen + IMSG_HEADER_SIZE); } int imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, int fd, const void *data, uint16_t datalen) { struct ibuf *wbuf; if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) return (-1); if (imsg_add(wbuf, data, datalen) == -1) return (-1); wbuf->fd = fd; imsg_close(ibuf, wbuf); return (1); } int imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, int fd, const struct iovec *iov, int iovcnt) { struct ibuf *wbuf; int i, datalen = 0; for (i = 0; i < iovcnt; i++) datalen += iov[i].iov_len; if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) return (-1); for (i = 0; i < iovcnt; i++) if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) return (-1); wbuf->fd = fd; imsg_close(ibuf, wbuf); return (1); } /* ARGSUSED */ struct ibuf * imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid, uint16_t datalen) { struct ibuf *wbuf; struct imsg_hdr hdr; datalen += IMSG_HEADER_SIZE; if (datalen > MAX_IMSGSIZE) { errno = ERANGE; return (NULL); } hdr.type = type; hdr.flags = 0; hdr.peerid = peerid; if ((hdr.pid = pid) == 0) hdr.pid = ibuf->pid; if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { return (NULL); } if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) return (NULL); return (wbuf); } int imsg_add(struct ibuf *msg, const void *data, uint16_t datalen) { if (datalen) if (ibuf_add(msg, data, datalen) == -1) { ibuf_free(msg); return (-1); } return (datalen); } void imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) { struct imsg_hdr *hdr; hdr = (struct imsg_hdr *)msg->buf; hdr->flags &= ~IMSGF_HASFD; if (msg->fd != -1) hdr->flags |= IMSGF_HASFD; hdr->len = (uint16_t)msg->wpos; ibuf_close(&ibuf->w, msg); } void imsg_free(struct imsg *imsg) { freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); } static int imsg_get_fd(struct imsgbuf *ibuf) { int fd; struct imsg_fd *ifd; if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) return (-1); fd = ifd->fd; TAILQ_REMOVE(&ibuf->fds, ifd, entry); free(ifd); return (fd); } int imsg_flush(struct imsgbuf *ibuf) { while (ibuf->w.queued) if (msgbuf_write(&ibuf->w) <= 0) return (-1); return (0); } void imsg_clear(struct imsgbuf *ibuf) { int fd; msgbuf_clear(&ibuf->w); while ((fd = imsg_get_fd(ibuf)) != -1) close(fd); } #endif /* HAVE_IMSG */ #if !HAVE_MEMMEM /*- * Copyright (c) 2005 Pascal Gloor * * 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. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /* * Find the first occurrence of the byte string s in byte string l. */ void * memmem(const void *l, size_t l_len, const void *s, size_t s_len) { const char *cur, *last; const char *cl = l; const char *cs = s; /* a zero length needle should just return the haystack */ if (l_len == 0) return (void *)cl; /* "s" must be smaller or equal to "l" */ if (l_len < s_len) return NULL; /* special case where s_len == 1 */ if (s_len == 1) return memchr(l, *cs, l_len); /* the last position where its possible to find "s" in "l" */ last = cl + l_len - s_len; for (cur = cl; cur <= last; cur++) if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) return (void *)cur; return NULL; } #endif /* !HAVE_MEMMEM */ #if !HAVE_MEMRCHR /* * Copyright (c) 2007 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include /* * Reverse memchr() * Find the last occurrence of 'c' in the buffer 's' of size 'n'. */ void * memrchr(const void *s, int c, size_t n) { const unsigned char *cp; if (n != 0) { cp = (unsigned char *)s + n; do { if (*(--cp) == (unsigned char)c) return((void *)cp); } while (--n != 0); } return(NULL); } #endif /* !HAVE_MEMRCHR */ #if !HAVE_OPTRESET /* * Copyright (c) 1987, 1993, 1994 * 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. 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. */ /* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ #include #include #include int BSDopterr = 1, /* if error message should be printed */ BSDoptind = 1, /* index into parent argv vector */ BSDoptopt, /* character checked for validity */ BSDoptreset; /* reset getopt */ char *BSDoptarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int BSDgetopt(int nargc, char *const *nargv, const char *ostr) { static const char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (ostr == NULL) return (-1); if (BSDoptreset || !*place) { /* update scanning pointer */ BSDoptreset = 0; if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-') { /* found "--" */ if (place[1]) return (BADCH); ++BSDoptind; place = EMSG; return (-1); } } /* option letter okay? */ if ((BSDoptopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, BSDoptopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (BSDoptopt == (int)'-') return (-1); if (!*place) ++BSDoptind; if (BSDopterr && *ostr != ':') (void)fprintf(stderr, "%s: unknown option -- %c\n", getprogname(), BSDoptopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ BSDoptarg = NULL; if (!*place) ++BSDoptind; } else { /* need an argument */ if (*place) /* no white space */ BSDoptarg = (char *)place; else if (nargc <= ++BSDoptind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (BSDopterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", getprogname(), BSDoptopt); return (BADCH); } else /* white space */ BSDoptarg = nargv[BSDoptind]; place = EMSG; ++BSDoptind; } return (BSDoptopt); /* dump back option letter */ } #endif #if !HAVE_REALLOCARRAY /* * Copyright (c) 2008 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * reallocarray(void *optr, size_t nmemb, size_t size) { if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { errno = ENOMEM; return NULL; } return realloc(optr, size * nmemb); } #endif /* !HAVE_REALLOCARRAY */ #if !HAVE_RECALLOCARRAY /* * Copyright (c) 2008, 2017 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */ #include #include #include #include #include /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) { size_t oldsize, newsize; void *newptr; if (ptr == NULL) return calloc(newnmemb, size); if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && newnmemb > 0 && SIZE_MAX / newnmemb < size) { errno = ENOMEM; return NULL; } newsize = newnmemb * size; if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { errno = EINVAL; return NULL; } oldsize = oldnmemb * size; /* * Don't bother too much if we're shrinking just a bit, * we do not shrink for series of small steps, oh well. */ if (newsize <= oldsize) { size_t d = oldsize - newsize; if (d < oldsize / 2 && d < (size_t)getpagesize()) { memset((char *)ptr + newsize, 0, d); return ptr; } } newptr = malloc(newsize); if (newptr == NULL) return NULL; if (newsize > oldsize) { memcpy(newptr, ptr, oldsize); memset((char *)newptr + oldsize, 0, newsize - oldsize); } else memcpy(newptr, ptr, newsize); explicit_bzero(ptr, oldsize); free(ptr); return newptr; } #endif /* !HAVE_RECALLOCARRAY */ #if !HAVE_SETPROCTITLE /* * Copyright (c) 2016 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ # if HAVE_PR_SET_NAME #include #include #include #include #include void setproctitle(const char *fmt, ...) { char title[16], name[16], *cp; va_list ap; int used; va_start(ap, fmt); vsnprintf(title, sizeof(title), fmt, ap); va_end(ap); used = snprintf(name, sizeof(name), "%s: %s", getprogname(), title); if (used >= (int)sizeof(name)) { cp = strrchr(name, ' '); if (cp != NULL) *cp = '\0'; } prctl(PR_SET_NAME, name); } # else void setproctitle(const char *fmt, ...) { return; } # endif #endif /* !HAVE_SETPROCTITLE */ #if !HAVE_STRLCAT /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif /* !HAVE_STRLCAT */ #if !HAVE_STRLCPY /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif /* !HAVE_STRLCPY */ #if !HAVE_STRNDUP /* $OpenBSD$ */ /* * Copyright (c) 2010 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include char * strndup(const char *str, size_t maxlen) { char *copy; size_t len; len = strnlen(str, maxlen); copy = malloc(len + 1); if (copy != NULL) { (void)memcpy(copy, str, len); copy[len] = '\0'; } return copy; } #endif /* !HAVE_STRNDUP */ #if !HAVE_STRNLEN /* $OpenBSD$ */ /* * Copyright (c) 2010 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include size_t strnlen(const char *str, size_t maxlen) { const char *cp; for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--) ; return (size_t)(cp - str); } #endif /* !HAVE_STRNLEN */ #if !HAVE_STRTONUM /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; int error = 0; char *ep; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) { error = INVALID; } else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } #endif /* !HAVE_STRTONUM */